mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-10 16:19:28 +01:00
Merge pull request #10074 from lioncash/pte
MMU: Tidy up PTE-related code
This commit is contained in:
commit
c3dadd140b
@ -611,11 +611,14 @@ union UReg_HID4
|
|||||||
// SDR1 - Page Table format
|
// SDR1 - Page Table format
|
||||||
union UReg_SDR1
|
union UReg_SDR1
|
||||||
{
|
{
|
||||||
BitField<0, 16, u32> htaborg;
|
BitField<0, 9, u32> htabmask;
|
||||||
BitField<16, 7, u32> reserved;
|
BitField<9, 7, u32> reserved;
|
||||||
BitField<23, 9, u32> htabmask;
|
BitField<16, 16, u32> htaborg;
|
||||||
|
|
||||||
u32 Hex = 0;
|
u32 Hex = 0;
|
||||||
|
|
||||||
|
UReg_SDR1() = default;
|
||||||
|
explicit UReg_SDR1(u32 hex_) : Hex{hex_} {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// MMCR0 - Monitor Mode Control Register 0 format
|
// MMCR0 - Monitor Mode Control Register 0 format
|
||||||
@ -718,6 +721,27 @@ union UReg_BAT_Lo
|
|||||||
explicit UReg_BAT_Lo(u32 hex_) : Hex{hex_} {}
|
explicit UReg_BAT_Lo(u32 hex_) : Hex{hex_} {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Segment register
|
||||||
|
union UReg_SR
|
||||||
|
{
|
||||||
|
BitField<0, 24, u32> VSID; // Virtual segment ID
|
||||||
|
BitField<24, 4, u32> reserved; // Reserved
|
||||||
|
BitField<28, 1, u32> N; // No-execute protection
|
||||||
|
BitField<29, 1, u32> Kp; // User-state protection
|
||||||
|
BitField<30, 1, u32> Ks; // Supervisor-state protection
|
||||||
|
BitField<31, 1, u32> T; // Segment register format selector
|
||||||
|
|
||||||
|
// These override other fields if T = 1
|
||||||
|
|
||||||
|
BitField<0, 20, u32> CNTLR_SPEC; // Device-specific data for I/O controller
|
||||||
|
BitField<20, 9, u32> BUID; // Bus unit ID
|
||||||
|
|
||||||
|
u32 Hex = 0;
|
||||||
|
|
||||||
|
UReg_SR() = default;
|
||||||
|
explicit UReg_SR(u32 hex_) : Hex{hex_} {}
|
||||||
|
};
|
||||||
|
|
||||||
union UReg_THRM12
|
union UReg_THRM12
|
||||||
{
|
{
|
||||||
BitField<0, 1, u32> V; // Valid
|
BitField<0, 1, u32> V; // Valid
|
||||||
@ -746,22 +770,33 @@ union UReg_THRM3
|
|||||||
explicit UReg_THRM3(u32 hex_) : Hex{hex_} {}
|
explicit UReg_THRM3(u32 hex_) : Hex{hex_} {}
|
||||||
};
|
};
|
||||||
|
|
||||||
union UReg_PTE
|
union UPTE_Lo
|
||||||
{
|
{
|
||||||
BitField<0, 6, u64> API;
|
BitField<0, 6, u32> API;
|
||||||
BitField<6, 1, u64> H;
|
BitField<6, 1, u32> H;
|
||||||
BitField<7, 24, u64> VSID;
|
BitField<7, 24, u32> VSID;
|
||||||
BitField<31, 1, u64> V;
|
BitField<31, 1, u32> V;
|
||||||
BitField<32, 2, u64> PP;
|
|
||||||
BitField<34, 1, u64> reserved_1;
|
|
||||||
BitField<35, 4, u64> WIMG;
|
|
||||||
BitField<39, 1, u64> C;
|
|
||||||
BitField<40, 1, u64> R;
|
|
||||||
BitField<41, 3, u64> reserved_2;
|
|
||||||
BitField<44, 20, u64> RPN;
|
|
||||||
|
|
||||||
u64 Hex = 0;
|
u32 Hex = 0;
|
||||||
u32 Hex32[2];
|
|
||||||
|
UPTE_Lo() = default;
|
||||||
|
explicit UPTE_Lo(u32 hex_) : Hex{hex_} {}
|
||||||
|
};
|
||||||
|
|
||||||
|
union UPTE_Hi
|
||||||
|
{
|
||||||
|
BitField<0, 2, u32> PP;
|
||||||
|
BitField<2, 1, u32> reserved_1;
|
||||||
|
BitField<3, 4, u32> WIMG;
|
||||||
|
BitField<7, 1, u32> C;
|
||||||
|
BitField<8, 1, u32> R;
|
||||||
|
BitField<9, 3, u32> reserved_2;
|
||||||
|
BitField<12, 20, u32> RPN;
|
||||||
|
|
||||||
|
u32 Hex = 0;
|
||||||
|
|
||||||
|
UPTE_Hi() = default;
|
||||||
|
explicit UPTE_Hi(u32 hex_) : Hex{hex_} {}
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -1137,68 +1137,6 @@ TranslateResult JitCache_TranslateAddress(u32 address)
|
|||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define PPC_EXC_DSISR_PAGE (1 << 30)
|
|
||||||
#define PPC_EXC_DSISR_PROT (1 << 27)
|
|
||||||
#define PPC_EXC_DSISR_STORE (1 << 25)
|
|
||||||
|
|
||||||
#define SDR1_HTABORG(v) (((v) >> 16) & 0xffff)
|
|
||||||
#define SDR1_HTABMASK(v) ((v)&0x1ff)
|
|
||||||
#define SDR1_PAGETABLE_BASE(v) ((v)&0xffff)
|
|
||||||
#define SR_T (1 << 31)
|
|
||||||
#define SR_Ks (1 << 30)
|
|
||||||
#define SR_Kp (1 << 29)
|
|
||||||
#define SR_N (1 << 28)
|
|
||||||
#define SR_VSID(v) ((v)&0xffffff)
|
|
||||||
#define SR_BUID(v) (((v) >> 20) & 0x1ff)
|
|
||||||
#define SR_CNTRL_SPEC(v) ((v)&0xfffff)
|
|
||||||
|
|
||||||
#define EA_SR(v) (((v) >> 28) & 0xf)
|
|
||||||
#define EA_PageIndex(v) (((v) >> 12) & 0xffff)
|
|
||||||
#define EA_Offset(v) ((v)&0xfff)
|
|
||||||
#define EA_API(v) (((v) >> 22) & 0x3f)
|
|
||||||
|
|
||||||
#define PA_RPN(v) (((v) >> 12) & 0xfffff)
|
|
||||||
#define PA_Offset(v) ((v)&0xfff)
|
|
||||||
|
|
||||||
#define PTE1_V (1 << 31)
|
|
||||||
#define PTE1_VSID(v) (((v) >> 7) & 0xffffff)
|
|
||||||
#define PTE1_H (1 << 6)
|
|
||||||
#define PTE1_API(v) ((v)&0x3f)
|
|
||||||
|
|
||||||
#define PTE2_RPN(v) ((v)&0xfffff000)
|
|
||||||
#define PTE2_R (1 << 8)
|
|
||||||
#define PTE2_C (1 << 7)
|
|
||||||
#define PTE2_WIMG(v) (((v) >> 3) & 0xf)
|
|
||||||
#define PTE2_PP(v) ((v)&3)
|
|
||||||
|
|
||||||
// Hey! these duplicate a structure in Gekko.h
|
|
||||||
union UPTE1
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
u32 API : 6;
|
|
||||||
u32 H : 1;
|
|
||||||
u32 VSID : 24;
|
|
||||||
u32 V : 1;
|
|
||||||
};
|
|
||||||
u32 Hex;
|
|
||||||
};
|
|
||||||
|
|
||||||
union UPTE2
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
u32 PP : 2;
|
|
||||||
u32 : 1;
|
|
||||||
u32 WIMG : 4;
|
|
||||||
u32 C : 1;
|
|
||||||
u32 R : 1;
|
|
||||||
u32 : 3;
|
|
||||||
u32 RPN : 20;
|
|
||||||
};
|
|
||||||
u32 Hex;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void GenerateDSIException(u32 effective_address, bool write)
|
static void GenerateDSIException(u32 effective_address, bool write)
|
||||||
{
|
{
|
||||||
// DSI exceptions are only supported in MMU mode.
|
// DSI exceptions are only supported in MMU mode.
|
||||||
@ -1209,14 +1147,17 @@ static void GenerateDSIException(u32 effective_address, bool write)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (effective_address)
|
constexpr u32 dsisr_page = 1U << 30;
|
||||||
PowerPC::ppcState.spr[SPR_DSISR] = PPC_EXC_DSISR_PAGE | PPC_EXC_DSISR_STORE;
|
constexpr u32 dsisr_store = 1U << 25;
|
||||||
|
|
||||||
|
if (effective_address != 0)
|
||||||
|
ppcState.spr[SPR_DSISR] = dsisr_page | dsisr_store;
|
||||||
else
|
else
|
||||||
PowerPC::ppcState.spr[SPR_DSISR] = PPC_EXC_DSISR_PAGE;
|
ppcState.spr[SPR_DSISR] = dsisr_page;
|
||||||
|
|
||||||
PowerPC::ppcState.spr[SPR_DAR] = effective_address;
|
ppcState.spr[SPR_DAR] = effective_address;
|
||||||
|
|
||||||
PowerPC::ppcState.Exceptions |= EXCEPTION_DSI;
|
ppcState.Exceptions |= EXCEPTION_DSI;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void GenerateISIException(u32 effective_address)
|
static void GenerateISIException(u32 effective_address)
|
||||||
@ -1230,7 +1171,9 @@ static void GenerateISIException(u32 effective_address)
|
|||||||
|
|
||||||
void SDRUpdated()
|
void SDRUpdated()
|
||||||
{
|
{
|
||||||
u32 htabmask = SDR1_HTABMASK(PowerPC::ppcState.spr[SPR_SDR]);
|
const auto sdr = UReg_SDR1{ppcState.spr[SPR_SDR]};
|
||||||
|
const u32 htabmask = sdr.htabmask;
|
||||||
|
|
||||||
if (!Common::IsValidLowMask(htabmask))
|
if (!Common::IsValidLowMask(htabmask))
|
||||||
WARN_LOG_FMT(POWERPC, "Invalid HTABMASK: 0b{:032b}", htabmask);
|
WARN_LOG_FMT(POWERPC, "Invalid HTABMASK: 0b{:032b}", htabmask);
|
||||||
|
|
||||||
@ -1238,12 +1181,12 @@ void SDRUpdated()
|
|||||||
// must be equal to the number of trailing ones in the mask (i.e. HTABORG must be
|
// must be equal to the number of trailing ones in the mask (i.e. HTABORG must be
|
||||||
// properly aligned), this is actually not a hard requirement. Real hardware will just OR
|
// properly aligned), this is actually not a hard requirement. Real hardware will just OR
|
||||||
// the base address anyway. Ignoring SDR changes would lead to incorrect emulation.
|
// the base address anyway. Ignoring SDR changes would lead to incorrect emulation.
|
||||||
u32 htaborg = SDR1_HTABORG(PowerPC::ppcState.spr[SPR_SDR]);
|
const u32 htaborg = sdr.htaborg;
|
||||||
if (htaborg & htabmask)
|
if ((htaborg & htabmask) != 0)
|
||||||
WARN_LOG_FMT(POWERPC, "Invalid HTABORG: htaborg=0x{:08x} htabmask=0x{:08x}", htaborg, htabmask);
|
WARN_LOG_FMT(POWERPC, "Invalid HTABORG: htaborg=0x{:08x} htabmask=0x{:08x}", htaborg, htabmask);
|
||||||
|
|
||||||
PowerPC::ppcState.pagetable_base = htaborg << 16;
|
ppcState.pagetable_base = htaborg << 16;
|
||||||
PowerPC::ppcState.pagetable_hashmask = ((htabmask << 10) | 0x3ff);
|
ppcState.pagetable_hashmask = ((htabmask << 10) | 0x3ff);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class TLBLookupResult
|
enum class TLBLookupResult
|
||||||
@ -1261,16 +1204,15 @@ static TLBLookupResult LookupTLBPageAddress(const XCheckTLBFlag flag, const u32
|
|||||||
|
|
||||||
if (tlbe.tag[0] == tag)
|
if (tlbe.tag[0] == tag)
|
||||||
{
|
{
|
||||||
UPTE2 PTE2;
|
UPTE_Hi pte2(tlbe.pte[0]);
|
||||||
PTE2.Hex = tlbe.pte[0];
|
|
||||||
|
|
||||||
// Check if C bit requires updating
|
// Check if C bit requires updating
|
||||||
if (flag == XCheckTLBFlag::Write)
|
if (flag == XCheckTLBFlag::Write)
|
||||||
{
|
{
|
||||||
if (PTE2.C == 0)
|
if (pte2.C == 0)
|
||||||
{
|
{
|
||||||
PTE2.C = 1;
|
pte2.C = 1;
|
||||||
tlbe.pte[0] = PTE2.Hex;
|
tlbe.pte[0] = pte2.Hex;
|
||||||
return TLBLookupResult::UpdateC;
|
return TLBLookupResult::UpdateC;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1279,22 +1221,21 @@ static TLBLookupResult LookupTLBPageAddress(const XCheckTLBFlag flag, const u32
|
|||||||
tlbe.recent = 0;
|
tlbe.recent = 0;
|
||||||
|
|
||||||
*paddr = tlbe.paddr[0] | (vpa & 0xfff);
|
*paddr = tlbe.paddr[0] | (vpa & 0xfff);
|
||||||
*wi = (PTE2.WIMG & 0b1100) != 0;
|
*wi = (pte2.WIMG & 0b1100) != 0;
|
||||||
|
|
||||||
return TLBLookupResult::Found;
|
return TLBLookupResult::Found;
|
||||||
}
|
}
|
||||||
if (tlbe.tag[1] == tag)
|
if (tlbe.tag[1] == tag)
|
||||||
{
|
{
|
||||||
UPTE2 PTE2;
|
UPTE_Hi pte2(tlbe.pte[1]);
|
||||||
PTE2.Hex = tlbe.pte[1];
|
|
||||||
|
|
||||||
// Check if C bit requires updating
|
// Check if C bit requires updating
|
||||||
if (flag == XCheckTLBFlag::Write)
|
if (flag == XCheckTLBFlag::Write)
|
||||||
{
|
{
|
||||||
if (PTE2.C == 0)
|
if (pte2.C == 0)
|
||||||
{
|
{
|
||||||
PTE2.C = 1;
|
pte2.C = 1;
|
||||||
tlbe.pte[1] = PTE2.Hex;
|
tlbe.pte[1] = pte2.Hex;
|
||||||
return TLBLookupResult::UpdateC;
|
return TLBLookupResult::UpdateC;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1303,24 +1244,24 @@ static TLBLookupResult LookupTLBPageAddress(const XCheckTLBFlag flag, const u32
|
|||||||
tlbe.recent = 1;
|
tlbe.recent = 1;
|
||||||
|
|
||||||
*paddr = tlbe.paddr[1] | (vpa & 0xfff);
|
*paddr = tlbe.paddr[1] | (vpa & 0xfff);
|
||||||
*wi = (PTE2.WIMG & 0b1100) != 0;
|
*wi = (pte2.WIMG & 0b1100) != 0;
|
||||||
|
|
||||||
return TLBLookupResult::Found;
|
return TLBLookupResult::Found;
|
||||||
}
|
}
|
||||||
return TLBLookupResult::NotFound;
|
return TLBLookupResult::NotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void UpdateTLBEntry(const XCheckTLBFlag flag, UPTE2 PTE2, const u32 address)
|
static void UpdateTLBEntry(const XCheckTLBFlag flag, UPTE_Hi pte2, const u32 address)
|
||||||
{
|
{
|
||||||
if (IsNoExceptionFlag(flag))
|
if (IsNoExceptionFlag(flag))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const int tag = address >> HW_PAGE_INDEX_SHIFT;
|
const u32 tag = address >> HW_PAGE_INDEX_SHIFT;
|
||||||
TLBEntry& tlbe = ppcState.tlb[IsOpcodeFlag(flag)][tag & HW_PAGE_INDEX_MASK];
|
TLBEntry& tlbe = ppcState.tlb[IsOpcodeFlag(flag)][tag & HW_PAGE_INDEX_MASK];
|
||||||
const int index = tlbe.recent == 0 && tlbe.tag[0] != TLBEntry::INVALID_TAG;
|
const u32 index = tlbe.recent == 0 && tlbe.tag[0] != TLBEntry::INVALID_TAG;
|
||||||
tlbe.recent = index;
|
tlbe.recent = index;
|
||||||
tlbe.paddr[index] = PTE2.RPN << HW_PAGE_INDEX_SHIFT;
|
tlbe.paddr[index] = pte2.RPN << HW_PAGE_INDEX_SHIFT;
|
||||||
tlbe.pte[index] = PTE2.Hex;
|
tlbe.pte[index] = pte2.Hex;
|
||||||
tlbe.tag[index] = tag;
|
tlbe.tag[index] = tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1328,50 +1269,63 @@ void InvalidateTLBEntry(u32 address)
|
|||||||
{
|
{
|
||||||
const u32 entry_index = (address >> HW_PAGE_INDEX_SHIFT) & HW_PAGE_INDEX_MASK;
|
const u32 entry_index = (address >> HW_PAGE_INDEX_SHIFT) & HW_PAGE_INDEX_MASK;
|
||||||
|
|
||||||
TLBEntry& tlbe = ppcState.tlb[0][entry_index];
|
ppcState.tlb[0][entry_index].Invalidate();
|
||||||
tlbe.tag[0] = TLBEntry::INVALID_TAG;
|
ppcState.tlb[1][entry_index].Invalidate();
|
||||||
tlbe.tag[1] = TLBEntry::INVALID_TAG;
|
|
||||||
|
|
||||||
TLBEntry& tlbe_i = ppcState.tlb[1][entry_index];
|
|
||||||
tlbe_i.tag[0] = TLBEntry::INVALID_TAG;
|
|
||||||
tlbe_i.tag[1] = TLBEntry::INVALID_TAG;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
union EffectiveAddress
|
||||||
|
{
|
||||||
|
BitField<0, 12, u32> offset;
|
||||||
|
BitField<12, 16, u32> page_index;
|
||||||
|
BitField<22, 6, u32> API;
|
||||||
|
BitField<28, 4, u32> SR;
|
||||||
|
|
||||||
|
u32 Hex = 0;
|
||||||
|
|
||||||
|
EffectiveAddress() = default;
|
||||||
|
explicit EffectiveAddress(u32 address) : Hex{address} {}
|
||||||
|
};
|
||||||
|
|
||||||
// Page Address Translation
|
// Page Address Translation
|
||||||
static TranslateAddressResult TranslatePageAddress(const u32 address, const XCheckTLBFlag flag,
|
static TranslateAddressResult TranslatePageAddress(const EffectiveAddress address,
|
||||||
bool* wi)
|
const XCheckTLBFlag flag, bool* wi)
|
||||||
{
|
{
|
||||||
// TLB cache
|
// TLB cache
|
||||||
// This catches 99%+ of lookups in practice, so the actual page table entry code below doesn't
|
// This catches 99%+ of lookups in practice, so the actual page table entry code below doesn't
|
||||||
// benefit much from optimization.
|
// benefit much from optimization.
|
||||||
u32 translatedAddress = 0;
|
u32 translated_address = 0;
|
||||||
TLBLookupResult res = LookupTLBPageAddress(flag, address, &translatedAddress, wi);
|
const TLBLookupResult res = LookupTLBPageAddress(flag, address.Hex, &translated_address, wi);
|
||||||
if (res == TLBLookupResult::Found)
|
if (res == TLBLookupResult::Found)
|
||||||
|
{
|
||||||
return TranslateAddressResult{TranslateAddressResultEnum::PAGE_TABLE_TRANSLATED,
|
return TranslateAddressResult{TranslateAddressResultEnum::PAGE_TABLE_TRANSLATED,
|
||||||
translatedAddress};
|
translated_address};
|
||||||
|
}
|
||||||
|
|
||||||
u32 sr = PowerPC::ppcState.sr[EA_SR(address)];
|
const auto sr = UReg_SR{ppcState.sr[address.SR]};
|
||||||
|
|
||||||
if (sr & 0x80000000)
|
if (sr.T != 0)
|
||||||
return TranslateAddressResult{TranslateAddressResultEnum::DIRECT_STORE_SEGMENT, 0};
|
return TranslateAddressResult{TranslateAddressResultEnum::DIRECT_STORE_SEGMENT, 0};
|
||||||
|
|
||||||
// TODO: Handle KS/KP segment register flags.
|
// TODO: Handle KS/KP segment register flags.
|
||||||
|
|
||||||
// No-execute segment register flag.
|
// No-execute segment register flag.
|
||||||
if ((flag == XCheckTLBFlag::Opcode || flag == XCheckTLBFlag::OpcodeNoException) &&
|
if ((flag == XCheckTLBFlag::Opcode || flag == XCheckTLBFlag::OpcodeNoException) && sr.N != 0)
|
||||||
(sr & 0x10000000))
|
|
||||||
{
|
{
|
||||||
return TranslateAddressResult{TranslateAddressResultEnum::PAGE_FAULT, 0};
|
return TranslateAddressResult{TranslateAddressResultEnum::PAGE_FAULT, 0};
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 offset = EA_Offset(address); // 12 bit
|
const u32 offset = address.offset; // 12 bit
|
||||||
u32 page_index = EA_PageIndex(address); // 16 bit
|
const u32 page_index = address.page_index; // 16 bit
|
||||||
u32 VSID = SR_VSID(sr); // 24 bit
|
const u32 VSID = sr.VSID; // 24 bit
|
||||||
u32 api = EA_API(address); // 6 bit (part of page_index)
|
const u32 api = address.API; // 6 bit (part of page_index)
|
||||||
|
|
||||||
// hash function no 1 "xor" .360
|
// hash function no 1 "xor" .360
|
||||||
u32 hash = (VSID ^ page_index);
|
u32 hash = (VSID ^ page_index);
|
||||||
u32 pte1 = (VSID << 7) | api | PTE1_V;
|
|
||||||
|
UPTE_Lo pte1;
|
||||||
|
pte1.VSID = VSID;
|
||||||
|
pte1.API = api;
|
||||||
|
pte1.V = 1;
|
||||||
|
|
||||||
for (int hash_func = 0; hash_func < 2; hash_func++)
|
for (int hash_func = 0; hash_func < 2; hash_func++)
|
||||||
{
|
{
|
||||||
@ -1379,7 +1333,7 @@ static TranslateAddressResult TranslatePageAddress(const u32 address, const XChe
|
|||||||
if (hash_func == 1)
|
if (hash_func == 1)
|
||||||
{
|
{
|
||||||
hash = ~hash;
|
hash = ~hash;
|
||||||
pte1 |= PTE1_H;
|
pte1.H = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 pteg_addr =
|
u32 pteg_addr =
|
||||||
@ -1389,10 +1343,9 @@ static TranslateAddressResult TranslatePageAddress(const u32 address, const XChe
|
|||||||
{
|
{
|
||||||
const u32 pteg = Memory::Read_U32(pteg_addr);
|
const u32 pteg = Memory::Read_U32(pteg_addr);
|
||||||
|
|
||||||
if (pte1 == pteg)
|
if (pte1.Hex == pteg)
|
||||||
{
|
{
|
||||||
UPTE2 PTE2;
|
UPTE_Hi pte2(Memory::Read_U32(pteg_addr + 4));
|
||||||
PTE2.Hex = Memory::Read_U32(pteg_addr + 4);
|
|
||||||
|
|
||||||
// set the access bits
|
// set the access bits
|
||||||
switch (flag)
|
switch (flag)
|
||||||
@ -1401,30 +1354,30 @@ static TranslateAddressResult TranslatePageAddress(const u32 address, const XChe
|
|||||||
case XCheckTLBFlag::OpcodeNoException:
|
case XCheckTLBFlag::OpcodeNoException:
|
||||||
break;
|
break;
|
||||||
case XCheckTLBFlag::Read:
|
case XCheckTLBFlag::Read:
|
||||||
PTE2.R = 1;
|
pte2.R = 1;
|
||||||
break;
|
break;
|
||||||
case XCheckTLBFlag::Write:
|
case XCheckTLBFlag::Write:
|
||||||
PTE2.R = 1;
|
pte2.R = 1;
|
||||||
PTE2.C = 1;
|
pte2.C = 1;
|
||||||
break;
|
break;
|
||||||
case XCheckTLBFlag::Opcode:
|
case XCheckTLBFlag::Opcode:
|
||||||
PTE2.R = 1;
|
pte2.R = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsNoExceptionFlag(flag))
|
if (!IsNoExceptionFlag(flag))
|
||||||
{
|
{
|
||||||
Memory::Write_U32(PTE2.Hex, pteg_addr + 4);
|
Memory::Write_U32(pte2.Hex, pteg_addr + 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We already updated the TLB entry if this was caused by a C bit.
|
// We already updated the TLB entry if this was caused by a C bit.
|
||||||
if (res != TLBLookupResult::UpdateC)
|
if (res != TLBLookupResult::UpdateC)
|
||||||
UpdateTLBEntry(flag, PTE2, address);
|
UpdateTLBEntry(flag, pte2, address.Hex);
|
||||||
|
|
||||||
*wi = (PTE2.WIMG & 0b1100) != 0;
|
*wi = (pte2.WIMG & 0b1100) != 0;
|
||||||
|
|
||||||
return TranslateAddressResult{TranslateAddressResultEnum::PAGE_TABLE_TRANSLATED,
|
return TranslateAddressResult{TranslateAddressResultEnum::PAGE_TABLE_TRANSLATED,
|
||||||
(PTE2.RPN << 12) | offset};
|
(pte2.RPN << 12) | offset};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1590,7 +1543,7 @@ static TranslateAddressResult TranslateAddress(u32 address)
|
|||||||
if (TranslateBatAddess(IsOpcodeFlag(flag) ? ibat_table : dbat_table, &address, &wi))
|
if (TranslateBatAddess(IsOpcodeFlag(flag) ? ibat_table : dbat_table, &address, &wi))
|
||||||
return TranslateAddressResult{TranslateAddressResultEnum::BAT_TRANSLATED, address, wi};
|
return TranslateAddressResult{TranslateAddressResultEnum::BAT_TRANSLATED, address, wi};
|
||||||
|
|
||||||
return TranslatePageAddress(address, flag, &wi);
|
return TranslatePageAddress(EffectiveAddress{address}, flag, &wi);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<u32> GetTranslatedAddress(u32 address)
|
std::optional<u32> GetTranslatedAddress(u32 address)
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
@ -49,12 +50,16 @@ constexpr size_t TLB_WAYS = 2;
|
|||||||
|
|
||||||
struct TLBEntry
|
struct TLBEntry
|
||||||
{
|
{
|
||||||
|
using WayArray = std::array<u32, TLB_WAYS>;
|
||||||
|
|
||||||
static constexpr u32 INVALID_TAG = 0xffffffff;
|
static constexpr u32 INVALID_TAG = 0xffffffff;
|
||||||
|
|
||||||
u32 tag[TLB_WAYS] = {INVALID_TAG, INVALID_TAG};
|
WayArray tag{INVALID_TAG, INVALID_TAG};
|
||||||
u32 paddr[TLB_WAYS] = {};
|
WayArray paddr{};
|
||||||
u32 pte[TLB_WAYS] = {};
|
WayArray pte{};
|
||||||
u8 recent = 0;
|
u32 recent = 0;
|
||||||
|
|
||||||
|
void Invalidate() { tag.fill(INVALID_TAG); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PairedSingle
|
struct PairedSingle
|
||||||
|
Loading…
x
Reference in New Issue
Block a user