Stored a copy of the PTE in the TLB like the real hardware does.

Updated PTE.R bit on Write and Instruction fetch.
Added code to read the PTE from MEM2 if the PTE is stored there.
Refactored the two hash functions to reduce code duplication.
Updated save state version.
This commit is contained in:
skidau 2014-12-06 10:28:34 +11:00
parent 997681b65a
commit d485acdb51
4 changed files with 55 additions and 67 deletions

View File

@ -712,11 +712,14 @@ static u32 LookupTLBPageAddress(const XCheckTLBFlag _Flag, const u32 vpa, u32 *p
// Check if C bit requires updating
if (_Flag == FLAG_WRITE)
{
u8* pRAM = Memory::base;
UPTE2 PTE2;
PTE2.Hex = bswap((*(u32*)&pRAM[tlbe[0].pteg]));
PTE2.Hex = tlbe[0].pte;
if (PTE2.C == 0)
{
PTE2.C = 1;
tlbe[0].pte = PTE2.Hex;
return 0;
}
}
if (_Flag != FLAG_NO_EXCEPTION)
@ -734,11 +737,14 @@ static u32 LookupTLBPageAddress(const XCheckTLBFlag _Flag, const u32 vpa, u32 *p
// Check if C bit requires updating
if (_Flag == FLAG_WRITE)
{
u8* pRAM = Memory::base;
UPTE2 PTE2;
PTE2.Hex = bswap((*(u32*)&pRAM[tlbe[1].pteg]));
PTE2.Hex = tlbe[1].pte;
if (PTE2.C == 0)
{
PTE2.C = 1;
tlbe[1].pte = PTE2.Hex;
return 0;
}
}
if (_Flag != FLAG_NO_EXCEPTION)
@ -754,7 +760,7 @@ static u32 LookupTLBPageAddress(const XCheckTLBFlag _Flag, const u32 vpa, u32 *p
return 0;
}
static void UpdateTLBEntry(const XCheckTLBFlag _Flag, UPTE2 PTE2, const u32 vpa, const u32 pteg)
static void UpdateTLBEntry(const XCheckTLBFlag _Flag, UPTE2 PTE2, const u32 vpa)
{
if (_Flag == FLAG_NO_EXCEPTION)
return;
@ -765,7 +771,7 @@ static void UpdateTLBEntry(const XCheckTLBFlag _Flag, UPTE2 PTE2, const u32 vpa,
tlbe[0].flags = TLB_FLAG_MOST_RECENT;
tlbe[1].flags &= ~TLB_FLAG_MOST_RECENT;
tlbe[0].paddr = PTE2.RPN << HW_PAGE_INDEX_SHIFT;
tlbe[0].pteg = pteg;
tlbe[0].pte = PTE2.Hex;
tlbe[0].tag = vpa & ~0xfff;
}
else
@ -773,7 +779,7 @@ static void UpdateTLBEntry(const XCheckTLBFlag _Flag, UPTE2 PTE2, const u32 vpa,
tlbe[1].flags = TLB_FLAG_MOST_RECENT;
tlbe[0].flags &= ~TLB_FLAG_MOST_RECENT;
tlbe[1].paddr = PTE2.RPN << HW_PAGE_INDEX_SHIFT;
tlbe[1].pteg = pteg;
tlbe[1].pte = PTE2.Hex;
tlbe[1].tag = vpa & ~0xfff;
}
}
@ -805,76 +811,58 @@ static u32 TranslatePageAddress(const u32 _Address, const XCheckTLBFlag _Flag)
// Direct access to the fastmem Arena
// FIXME: is this the best idea for clean code?
u8* pRAM = Memory::base;
u8* base = Memory::base;
// hash function no 1 "xor" .360
u32 hash1 = (VSID ^ page_index);
u32 pteg_addr = ((hash1 & PowerPC::ppcState.pagetable_hashmask) << 6) | PowerPC::ppcState.pagetable_base;
u32 hash = (VSID ^ page_index);
// hash1
for (int i = 0; i < 8; i++)
for (int hash_func = 0; hash_func < 2; hash_func++)
{
UPTE1 PTE1;
PTE1.Hex = bswap(*(u32*)&pRAM[pteg_addr]);
if (PTE1.V && !PTE1.H)
if (hash_func == 1)
{
if (VSID == PTE1.VSID && (api == PTE1.API))
{
UPTE2 PTE2;
PTE2.Hex = bswap((*(u32*)&pRAM[(pteg_addr + 4)]));
// set the access bits
switch (_Flag)
{
case FLAG_READ: PTE2.R = 1; break;
case FLAG_WRITE: PTE2.C = 1; break;
case FLAG_NO_EXCEPTION: break;
case FLAG_OPCODE: break;
}
if (_Flag != FLAG_NO_EXCEPTION)
*(u32*)&pRAM[(pteg_addr + 4)] = bswap(PTE2.Hex);
UpdateTLBEntry(_Flag, PTE2, _Address, pteg_addr + 4);
return (PTE2.RPN << 12) | offset;
}
// hash function no 2 "not" .360
hash = ~hash;
}
pteg_addr += 8;
}
// hash function no 2 "not" .360
hash1 = ~hash1;
pteg_addr = ((hash1 & PowerPC::ppcState.pagetable_hashmask) << 6) | PowerPC::ppcState.pagetable_base;
for (int i = 0; i < 8; i++)
{
u32 pte = bswap(*(u32*)&pRAM[pteg_addr]);
if ((pte & PTE1_V) && (pte & PTE1_H))
u32 pteg_addr = ((hash & PowerPC::ppcState.pagetable_hashmask) << 6) | PowerPC::ppcState.pagetable_base;
if ((pteg_addr >> 28) == 1)
base = Memory::m_pEXRAM;
for (int i = 0; i < 8; i++)
{
if (VSID == PTE1_VSID(pte) && (api == PTE1_API(pte)))
u32 pte = bswap(*(u32*)&base[pteg_addr]);
bool pteh = (pte & PTE1_H) == 0;
if (hash_func == 1)
pteh = !pteh;
if ((pte & PTE1_V) && pteh)
{
UPTE2 PTE2;
PTE2.Hex = bswap((*(u32*)&pRAM[(pteg_addr + 4)]));
// set the access bits
switch (_Flag)
if (VSID == PTE1_VSID(pte) && (api == PTE1_API(pte)))
{
case FLAG_READ: PTE2.R = 1; break;
case FLAG_WRITE: PTE2.C = 1; break;
case FLAG_NO_EXCEPTION: break;
case FLAG_OPCODE: break;
UPTE2 PTE2;
PTE2.Hex = bswap((*(u32*)&base[(pteg_addr + 4)]));
// set the access bits
switch (_Flag)
{
case FLAG_NO_EXCEPTION: break;
case FLAG_READ: PTE2.R = 1; break;
case FLAG_WRITE: PTE2.R = 1; PTE2.C = 1; break;
case FLAG_OPCODE: PTE2.R = 1; break;
}
if (_Flag != FLAG_NO_EXCEPTION)
*(u32*)&base[(pteg_addr + 4)] = bswap(PTE2.Hex);
UpdateTLBEntry(_Flag, PTE2, _Address);
return (PTE2.RPN << 12) | offset;
}
if (_Flag != FLAG_NO_EXCEPTION)
*(u32*)&pRAM[(pteg_addr + 4)] = bswap(PTE2.Hex);
UpdateTLBEntry(_Flag, PTE2, _Address, pteg_addr + 4);
return (PTE2.RPN << 12) | offset;
}
pteg_addr += 8;
}
pteg_addr += 8;
}
return 0;
}

View File

@ -129,7 +129,7 @@ void Init(int cpu_core)
{
ppcState.tlb[tlb][set][way].flags = TLB_FLAG_INVALID;
ppcState.tlb[tlb][set][way].paddr = 0;
ppcState.tlb[tlb][set][way].pteg = 0;
ppcState.tlb[tlb][set][way].pte = 0;
ppcState.tlb[tlb][set][way].tag = 0;
}
}

View File

@ -43,7 +43,7 @@ struct tlb_entry
{
u32 tag;
u32 paddr;
u32 pteg;
u32 pte;
u8 flags;
};

View File

@ -64,7 +64,7 @@ static Common::Event g_compressAndDumpStateSyncEvent;
static std::thread g_save_thread;
// Don't forget to increase this after doing changes on the savestate system
static const u32 STATE_VERSION = 36;
static const u32 STATE_VERSION = 37;
enum
{