diff --git a/Source/Core/Core/Debugger/PPCDebugInterface.cpp b/Source/Core/Core/Debugger/PPCDebugInterface.cpp index 988d0de20d..ddc2fec12e 100644 --- a/Source/Core/Core/Debugger/PPCDebugInterface.cpp +++ b/Source/Core/Core/Debugger/PPCDebugInterface.cpp @@ -28,7 +28,7 @@ std::string PPCDebugInterface::Disassemble(unsigned int address) if (!Memory::IsRAMAddress(address, true, true)) { 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)"; } diff --git a/Source/Core/Core/HW/MemmapFunctions.cpp b/Source/Core/Core/HW/MemmapFunctions.cpp index e3aea97418..4e87406efa 100644 --- a/Source/Core/Core/HW/MemmapFunctions.cpp +++ b/Source/Core/Core/HW/MemmapFunctions.cpp @@ -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) { - 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 (_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[1].flags &= ~TLB_FLAG_MOST_RECENT; } + *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; } 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[0].flags &= ~TLB_FLAG_MOST_RECENT; } + *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 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) return; - tlb_entry *tlbe = tlb[_Flag == FLAG_OPCODE][(vpa>>HW_PAGE_INDEX_SHIFT)&HW_PAGE_INDEX_MASK]; - if ((tlbe[0].flags & TLB_FLAG_MOST_RECENT) == 0) + 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 || (tlbe[0].flags & TLB_FLAG_INVALID)) { 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].tag = vpa & ~0xfff; } else @@ -770,13 +773,14 @@ 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].tag = vpa & ~0xfff; } } 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)) { tlbe[0].flags |= TLB_FLAG_INVALID; @@ -785,7 +789,7 @@ void InvalidateTLBEntry(u32 vpa) { 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)) { tlbe_i[0].flags |= TLB_FLAG_INVALID; @@ -832,8 +836,6 @@ static u32 TranslatePageAddress(const u32 _Address, const XCheckTLBFlag _Flag) UPTE2 PTE2; PTE2.Hex = bswap((*(u32*)&pRAM[(pteg_addr + 4)])); - UpdateTLBEntry(_Flag, PTE2, _Address); - // set the access bits switch (_Flag) { @@ -842,12 +844,16 @@ static u32 TranslatePageAddress(const u32 _Address, const XCheckTLBFlag _Flag) case FLAG_NO_EXCEPTION: break; case FLAG_OPCODE: break; } - *(u32*)&pRAM[(pteg_addr + 4)] = bswap(PTE2.Hex); - 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; } // hash function no 2 "not" .360 @@ -863,8 +869,6 @@ static u32 TranslatePageAddress(const u32 _Address, const XCheckTLBFlag _Flag) UPTE2 PTE2; PTE2.Hex = bswap((*(u32*)&pRAM[(pteg_addr + 4)])); - UpdateTLBEntry(_Flag, PTE2, _Address); - switch (_Flag) { 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_OPCODE: break; } - *(u32*)&pRAM[(pteg_addr + 4)] = bswap(PTE2.Hex); - 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; } diff --git a/Source/Core/Core/PowerPC/PPCAnalyst.cpp b/Source/Core/Core/PowerPC/PPCAnalyst.cpp index 13b4b3d49d..5827b99845 100644 --- a/Source/Core/Core/PowerPC/PPCAnalyst.cpp +++ b/Source/Core/Core/PowerPC/PPCAnalyst.cpp @@ -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 (!Memory::TranslateAddress(address, Memory::FLAG_OPCODE)) + if (!Memory::TranslateAddress(address, Memory::FLAG_NO_EXCEPTION)) { // Memory exception occurred during instruction fetch block->m_memory_exception = true; diff --git a/Source/Core/Core/PowerPC/PowerPC.cpp b/Source/Core/Core/PowerPC/PowerPC.cpp index f75cd9f7be..ad2fb808f0 100644 --- a/Source/Core/Core/PowerPC/PowerPC.cpp +++ b/Source/Core/Core/PowerPC/PowerPC.cpp @@ -118,12 +118,6 @@ void Init(int cpu_core) FPURoundMode::SetPrecisionMode(FPURoundMode::PREC_53); 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_hashmask = 0; diff --git a/Source/Core/Core/PowerPC/PowerPC.h b/Source/Core/Core/PowerPC/PowerPC.h index e9f3aee367..b93b79f4d3 100644 --- a/Source/Core/Core/PowerPC/PowerPC.h +++ b/Source/Core/Core/PowerPC/PowerPC.h @@ -27,6 +27,26 @@ enum CoreMode 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. struct GC_ALIGNED64(PowerPCState) { @@ -87,13 +107,7 @@ struct GC_ALIGNED64(PowerPCState) // also for power management, but we don't care about that. u32 spr[1024]; - u32 dtlb_last; - u32 dtlb_va[128]; - u32 dtlb_pa[128]; - - u32 itlb_last; - u32 itlb_va[128]; - u32 itlb_pa[128]; + tlb_entry tlb[NUM_TLBS][TLB_SIZE / TLB_WAYS][TLB_WAYS]; u32 pagetable_base; u32 pagetable_hashmask;