Updated C bit on TLB cache hits.

Added TLB state to the save state file.
This commit is contained in:
skidau 2014-12-05 14:29:13 +11:00
parent 6d5e9cb5b1
commit 693f413364
5 changed files with 69 additions and 53 deletions

View File

@ -28,7 +28,7 @@ std::string PPCDebugInterface::Disassemble(unsigned int address)
if (!Memory::IsRAMAddress(address, true, true)) if (!Memory::IsRAMAddress(address, true, true))
{ {
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bMMU || !((address & JIT_ICACHE_VMEM_BIT) && if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bMMU || !((address & JIT_ICACHE_VMEM_BIT) &&
Memory::TranslateAddress(address, Memory::FLAG_OPCODE))) Memory::TranslateAddress(address, Memory::FLAG_NO_EXCEPTION)))
{ {
return "(No RAM here)"; return "(No RAM here)";
} }

View File

@ -704,31 +704,9 @@ void SDRUpdated()
} }
// TLB cache
#define TLB_SIZE 128
#define TLB_WAYS 2
#define NUM_TLBS 2
#define HW_PAGE_INDEX_SHIFT 12
#define HW_PAGE_INDEX_MASK 0x3f
#define HW_PAGE_TAG_SHIFT 18
#define TLB_FLAG_MOST_RECENT 0x01
#define TLB_FLAG_INVALID 0x02
struct tlb_entry
{
u32 tag;
u32 paddr;
u8 flags;
};
// TODO: tlb needs to be in ppcState for save-state purposes.
static tlb_entry tlb[NUM_TLBS][TLB_SIZE/TLB_WAYS][TLB_WAYS];
static u32 LookupTLBPageAddress(const XCheckTLBFlag _Flag, const u32 vpa, u32 *paddr) static u32 LookupTLBPageAddress(const XCheckTLBFlag _Flag, const u32 vpa, u32 *paddr)
{ {
tlb_entry *tlbe = tlb[_Flag == FLAG_OPCODE][(vpa>>HW_PAGE_INDEX_SHIFT)&HW_PAGE_INDEX_MASK]; PowerPC::tlb_entry *tlbe = PowerPC::ppcState.tlb[_Flag == FLAG_OPCODE][(vpa >> HW_PAGE_INDEX_SHIFT) & HW_PAGE_INDEX_MASK];
if (tlbe[0].tag == (vpa & ~0xfff) && !(tlbe[0].flags & TLB_FLAG_INVALID)) if (tlbe[0].tag == (vpa & ~0xfff) && !(tlbe[0].flags & TLB_FLAG_INVALID))
{ {
if (_Flag != FLAG_NO_EXCEPTION) if (_Flag != FLAG_NO_EXCEPTION)
@ -736,7 +714,19 @@ static u32 LookupTLBPageAddress(const XCheckTLBFlag _Flag, const u32 vpa, u32 *p
tlbe[0].flags |= TLB_FLAG_MOST_RECENT; tlbe[0].flags |= TLB_FLAG_MOST_RECENT;
tlbe[1].flags &= ~TLB_FLAG_MOST_RECENT; tlbe[1].flags &= ~TLB_FLAG_MOST_RECENT;
} }
*paddr = tlbe[0].paddr | (vpa & 0xfff); *paddr = tlbe[0].paddr | (vpa & 0xfff);
// Check if C bit requires updating
if (_Flag == FLAG_WRITE)
{
u8* pRAM = Memory::base;
UPTE2 PTE2;
PTE2.Hex = bswap((*(u32*)&pRAM[tlbe[0].pteg]));
if (PTE2.C == 0)
return 0;
}
return 1; return 1;
} }
if (tlbe[1].tag == (vpa & ~0xfff) && !(tlbe[1].flags & TLB_FLAG_INVALID)) if (tlbe[1].tag == (vpa & ~0xfff) && !(tlbe[1].flags & TLB_FLAG_INVALID))
@ -746,23 +736,36 @@ static u32 LookupTLBPageAddress(const XCheckTLBFlag _Flag, const u32 vpa, u32 *p
tlbe[1].flags |= TLB_FLAG_MOST_RECENT; tlbe[1].flags |= TLB_FLAG_MOST_RECENT;
tlbe[0].flags &= ~TLB_FLAG_MOST_RECENT; tlbe[0].flags &= ~TLB_FLAG_MOST_RECENT;
} }
*paddr = tlbe[1].paddr | (vpa & 0xfff); *paddr = tlbe[1].paddr | (vpa & 0xfff);
// Check if C bit requires updating
if (_Flag == FLAG_WRITE)
{
u8* pRAM = Memory::base;
UPTE2 PTE2;
PTE2.Hex = bswap((*(u32*)&pRAM[tlbe[1].pteg]));
if (PTE2.C == 0)
return 0;
}
return 1; return 1;
} }
return 0; return 0;
} }
static void UpdateTLBEntry(const XCheckTLBFlag _Flag, UPTE2 PTE2, const u32 vpa) static void UpdateTLBEntry(const XCheckTLBFlag _Flag, UPTE2 PTE2, const u32 vpa, const u32 pteg)
{ {
if (_Flag == FLAG_NO_EXCEPTION) if (_Flag == FLAG_NO_EXCEPTION)
return; return;
tlb_entry *tlbe = tlb[_Flag == FLAG_OPCODE][(vpa>>HW_PAGE_INDEX_SHIFT)&HW_PAGE_INDEX_MASK]; PowerPC::tlb_entry *tlbe = PowerPC::ppcState.tlb[_Flag == FLAG_OPCODE][(vpa >> HW_PAGE_INDEX_SHIFT) & HW_PAGE_INDEX_MASK];
if ((tlbe[0].flags & TLB_FLAG_MOST_RECENT) == 0) if ((tlbe[0].flags & TLB_FLAG_MOST_RECENT) == 0 || (tlbe[0].flags & TLB_FLAG_INVALID))
{ {
tlbe[0].flags = TLB_FLAG_MOST_RECENT; tlbe[0].flags = TLB_FLAG_MOST_RECENT;
tlbe[1].flags &= ~TLB_FLAG_MOST_RECENT; tlbe[1].flags &= ~TLB_FLAG_MOST_RECENT;
tlbe[0].paddr = PTE2.RPN << HW_PAGE_INDEX_SHIFT; tlbe[0].paddr = PTE2.RPN << HW_PAGE_INDEX_SHIFT;
tlbe[0].pteg = pteg;
tlbe[0].tag = vpa & ~0xfff; tlbe[0].tag = vpa & ~0xfff;
} }
else else
@ -770,13 +773,14 @@ static void UpdateTLBEntry(const XCheckTLBFlag _Flag, UPTE2 PTE2, const u32 vpa)
tlbe[1].flags = TLB_FLAG_MOST_RECENT; tlbe[1].flags = TLB_FLAG_MOST_RECENT;
tlbe[0].flags &= ~TLB_FLAG_MOST_RECENT; tlbe[0].flags &= ~TLB_FLAG_MOST_RECENT;
tlbe[1].paddr = PTE2.RPN << HW_PAGE_INDEX_SHIFT; tlbe[1].paddr = PTE2.RPN << HW_PAGE_INDEX_SHIFT;
tlbe[1].pteg = pteg;
tlbe[1].tag = vpa & ~0xfff; tlbe[1].tag = vpa & ~0xfff;
} }
} }
void InvalidateTLBEntry(u32 vpa) void InvalidateTLBEntry(u32 vpa)
{ {
tlb_entry *tlbe = tlb[0][(vpa>>HW_PAGE_INDEX_SHIFT)&HW_PAGE_INDEX_MASK]; PowerPC::tlb_entry *tlbe = PowerPC::ppcState.tlb[0][(vpa >> HW_PAGE_INDEX_SHIFT) & HW_PAGE_INDEX_MASK];
if (tlbe[0].tag == (vpa & ~0xfff)) if (tlbe[0].tag == (vpa & ~0xfff))
{ {
tlbe[0].flags |= TLB_FLAG_INVALID; tlbe[0].flags |= TLB_FLAG_INVALID;
@ -785,7 +789,7 @@ void InvalidateTLBEntry(u32 vpa)
{ {
tlbe[1].flags |= TLB_FLAG_INVALID; tlbe[1].flags |= TLB_FLAG_INVALID;
} }
tlb_entry *tlbe_i = tlb[1][(vpa>>HW_PAGE_INDEX_SHIFT)&HW_PAGE_INDEX_MASK]; PowerPC::tlb_entry *tlbe_i = PowerPC::ppcState.tlb[1][(vpa >> HW_PAGE_INDEX_SHIFT) & HW_PAGE_INDEX_MASK];
if (tlbe_i[0].tag == (vpa & ~0xfff)) if (tlbe_i[0].tag == (vpa & ~0xfff))
{ {
tlbe_i[0].flags |= TLB_FLAG_INVALID; tlbe_i[0].flags |= TLB_FLAG_INVALID;
@ -832,8 +836,6 @@ static u32 TranslatePageAddress(const u32 _Address, const XCheckTLBFlag _Flag)
UPTE2 PTE2; UPTE2 PTE2;
PTE2.Hex = bswap((*(u32*)&pRAM[(pteg_addr + 4)])); PTE2.Hex = bswap((*(u32*)&pRAM[(pteg_addr + 4)]));
UpdateTLBEntry(_Flag, PTE2, _Address);
// set the access bits // set the access bits
switch (_Flag) switch (_Flag)
{ {
@ -842,12 +844,16 @@ static u32 TranslatePageAddress(const u32 _Address, const XCheckTLBFlag _Flag)
case FLAG_NO_EXCEPTION: break; case FLAG_NO_EXCEPTION: break;
case FLAG_OPCODE: break; case FLAG_OPCODE: break;
} }
if (_Flag != FLAG_NO_EXCEPTION)
*(u32*)&pRAM[(pteg_addr + 4)] = bswap(PTE2.Hex); *(u32*)&pRAM[(pteg_addr + 4)] = bswap(PTE2.Hex);
return ((PTE2.RPN << 12) | offset); UpdateTLBEntry(_Flag, PTE2, _Address, pteg_addr + 4);
return (PTE2.RPN << 12) | offset;
} }
} }
pteg_addr+=8; pteg_addr += 8;
} }
// hash function no 2 "not" .360 // hash function no 2 "not" .360
@ -863,8 +869,6 @@ static u32 TranslatePageAddress(const u32 _Address, const XCheckTLBFlag _Flag)
UPTE2 PTE2; UPTE2 PTE2;
PTE2.Hex = bswap((*(u32*)&pRAM[(pteg_addr + 4)])); PTE2.Hex = bswap((*(u32*)&pRAM[(pteg_addr + 4)]));
UpdateTLBEntry(_Flag, PTE2, _Address);
switch (_Flag) switch (_Flag)
{ {
case FLAG_READ: PTE2.R = 1; break; case FLAG_READ: PTE2.R = 1; break;
@ -872,12 +876,16 @@ static u32 TranslatePageAddress(const u32 _Address, const XCheckTLBFlag _Flag)
case FLAG_NO_EXCEPTION: break; case FLAG_NO_EXCEPTION: break;
case FLAG_OPCODE: break; case FLAG_OPCODE: break;
} }
if (_Flag != FLAG_NO_EXCEPTION)
*(u32*)&pRAM[(pteg_addr + 4)] = bswap(PTE2.Hex); *(u32*)&pRAM[(pteg_addr + 4)] = bswap(PTE2.Hex);
return ((PTE2.RPN << 12) | offset); UpdateTLBEntry(_Flag, PTE2, _Address, pteg_addr + 4);
return (PTE2.RPN << 12) | offset;
} }
} }
pteg_addr+=8; pteg_addr += 8;
} }
return 0; return 0;
} }

View File

@ -648,7 +648,7 @@ u32 PPCAnalyzer::Analyze(u32 address, CodeBlock *block, CodeBuffer *buffer, u32
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bMMU && (address & JIT_ICACHE_VMEM_BIT)) if (SConfig::GetInstance().m_LocalCoreStartupParameter.bMMU && (address & JIT_ICACHE_VMEM_BIT))
{ {
if (!Memory::TranslateAddress(address, Memory::FLAG_OPCODE)) if (!Memory::TranslateAddress(address, Memory::FLAG_NO_EXCEPTION))
{ {
// Memory exception occurred during instruction fetch // Memory exception occurred during instruction fetch
block->m_memory_exception = true; block->m_memory_exception = true;

View File

@ -118,12 +118,6 @@ void Init(int cpu_core)
FPURoundMode::SetPrecisionMode(FPURoundMode::PREC_53); FPURoundMode::SetPrecisionMode(FPURoundMode::PREC_53);
memset(ppcState.sr, 0, sizeof(ppcState.sr)); memset(ppcState.sr, 0, sizeof(ppcState.sr));
ppcState.dtlb_last = 0;
memset(ppcState.dtlb_va, 0, sizeof(ppcState.dtlb_va));
memset(ppcState.dtlb_pa, 0, sizeof(ppcState.dtlb_pa));
ppcState.itlb_last = 0;
memset(ppcState.itlb_va, 0, sizeof(ppcState.itlb_va));
memset(ppcState.itlb_pa, 0, sizeof(ppcState.itlb_pa));
ppcState.pagetable_base = 0; ppcState.pagetable_base = 0;
ppcState.pagetable_hashmask = 0; ppcState.pagetable_hashmask = 0;

View File

@ -27,6 +27,26 @@ enum CoreMode
MODE_JIT, MODE_JIT,
}; };
// TLB cache
#define TLB_SIZE 128
#define TLB_WAYS 2
#define NUM_TLBS 2
#define HW_PAGE_INDEX_SHIFT 12
#define HW_PAGE_INDEX_MASK 0x3f
#define HW_PAGE_TAG_SHIFT 18
#define TLB_FLAG_MOST_RECENT 0x01
#define TLB_FLAG_INVALID 0x02
struct tlb_entry
{
u32 tag;
u32 paddr;
u32 pteg;
u8 flags;
};
// This contains the entire state of the emulated PowerPC "Gekko" CPU. // This contains the entire state of the emulated PowerPC "Gekko" CPU.
struct GC_ALIGNED64(PowerPCState) struct GC_ALIGNED64(PowerPCState)
{ {
@ -87,13 +107,7 @@ struct GC_ALIGNED64(PowerPCState)
// also for power management, but we don't care about that. // also for power management, but we don't care about that.
u32 spr[1024]; u32 spr[1024];
u32 dtlb_last; tlb_entry tlb[NUM_TLBS][TLB_SIZE / TLB_WAYS][TLB_WAYS];
u32 dtlb_va[128];
u32 dtlb_pa[128];
u32 itlb_last;
u32 itlb_va[128];
u32 itlb_pa[128];
u32 pagetable_base; u32 pagetable_base;
u32 pagetable_hashmask; u32 pagetable_hashmask;