MemmapFunctions: various MMU optimizations

Small TLB lookup optimizations: this is the hot path for MMU code, so try to
make it better.

Template the TLB lookup functions based on the lookup type (opcode, data,
no exception).

Clean up the Read/Write functions and make them more consistent.

Add an early-exit path for MMU accesses to ReadFromHardware/WriteToHardware.
This commit is contained in:
Fiora 2014-12-30 18:12:47 -08:00
parent ea23ce2726
commit c2ed29fe0d
5 changed files with 155 additions and 177 deletions

View File

@ -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_NO_EXCEPTION)))
Memory::TranslateAddress<Memory::FLAG_NO_EXCEPTION>(address)))
{
return "(No RAM here)";
}

View File

@ -96,12 +96,12 @@ u16 Read_U16(const u32 _Address);
u32 Read_U32(const u32 _Address);
u64 Read_U64(const u32 _Address);
u32 Read_S8_Val(u32 address, u32 val);
u32 Read_U8_Val(u32 address, u32 val);
u32 Read_S16_Val(u32 address, u32 val);
u32 Read_U16_Val(u32 address, u32 val);
u32 Read_U32_Val(u32 address, u32 val);
u64 Read_U64_Val(u32 address, u64 val);
u32 Read_S8_Val(const u32 _Address, u32 _var);
u32 Read_U8_Val(const u32 _Address, u32 _var);
u32 Read_S16_Val(const u32 _Address, u32 _var);
u32 Read_U16_Val(const u32 _Address, u32 _var);
u32 Read_U32_Val(const u32 _Address, u32 _var);
u64 Read_U64_Val(const u32 _Address, u64 _var);
// Useful helper functions, used by ARM JIT
float Read_F32(const u32 _Address);
@ -111,17 +111,17 @@ double Read_F64(const u32 _Address);
u32 Read_U8_ZX(const u32 _Address);
u32 Read_U16_ZX(const u32 _Address);
void Write_U8(const u8 _Data, const u32 _Address);
void Write_U16(const u16 _Data, const u32 _Address);
void Write_U32(const u32 _Data, const u32 _Address);
void Write_U64(const u64 _Data, const u32 _Address);
void Write_U8(const u8 _var, const u32 _Address);
void Write_U16(const u16 _var, const u32 _Address);
void Write_U32(const u32 _var, const u32 _Address);
void Write_U64(const u64 _var, const u32 _Address);
void Write_U16_Swap(const u16 _Data, const u32 _Address);
void Write_U32_Swap(const u32 _Data, const u32 _Address);
void Write_U64_Swap(const u64 _Data, const u32 _Address);
void Write_U16_Swap(const u16 _var, const u32 _Address);
void Write_U32_Swap(const u32 _var, const u32 _Address);
void Write_U64_Swap(const u64 _var, const u32 _Address);
// Useful helper functions, used by ARM JIT
void Write_F64(const double _Data, const u32 _Address);
void Write_F64(const double _var, const u32 _Address);
std::string GetString(u32 em_address, size_t size = 0);
@ -142,7 +142,7 @@ enum XCheckTLBFlag
FLAG_WRITE,
FLAG_OPCODE,
};
u32 TranslateAddress(u32 _Address, XCheckTLBFlag _Flag);
template <const XCheckTLBFlag _Flag> u32 TranslateAddress(const u32 _Address);
void InvalidateTLBEntry(u32 _Address);
extern u32 pagetable_base;
extern u32 pagetable_hashmask;

View File

@ -16,6 +16,7 @@
// https://github.com/dolphin-emu/dolphin
#include "Common/Atomic.h"
#include "Common/BitSet.h"
#include "Common/CommonTypes.h"
#include "Core/ConfigManager.h"
@ -91,9 +92,14 @@ static u32 EFB_Read(const u32 addr)
static void GenerateDSIException(u32 _EffectiveAddress, bool _bWrite);
template <typename T, typename U>
__forceinline void ReadFromHardware(U &_var, const u32 em_address, Memory::XCheckTLBFlag flag)
template <XCheckTLBFlag flag, typename T, typename U>
__forceinline void ReadFromHardware(U &_var, const u32 em_address)
{
int segment = em_address >> 28;
// Quick check for an address that can't meet any of the following conditions,
// to speed up the MMU path.
if (BitSet32(0xCFC)[segment])
goto translateaddress;
// TODO: Figure out the fastest order of tests for both read and write (they are probably different).
if ((em_address & 0xC8000000) == 0xC8000000)
{
@ -102,30 +108,28 @@ __forceinline void ReadFromHardware(U &_var, const u32 em_address, Memory::XChec
else
_var = (T)mmio_mapping->Read<typename std::make_unsigned<T>::type>(em_address);
}
else if (((em_address & 0xF0000000) == 0x80000000) ||
((em_address & 0xF0000000) == 0xC0000000) ||
((em_address & 0xF0000000) == 0x00000000))
else if (segment == 0x8 || segment == 0xC || segment == 0x0)
{
_var = bswap((*(const T*)&m_pRAM[em_address & RAM_MASK]));
}
else if (m_pEXRAM && (((em_address & 0xF0000000) == 0x90000000) ||
((em_address & 0xF0000000) == 0xD0000000) ||
((em_address & 0xF0000000) == 0x10000000)))
else if (m_pEXRAM && (segment == 0x9 || segment == 0xD || segment == 0x1))
{
_var = bswap((*(const T*)&m_pEXRAM[em_address & EXRAM_MASK]));
}
else if ((em_address >= 0xE0000000) && (em_address < (0xE0000000+L1_CACHE_SIZE)))
else if (segment == 0xE && (em_address < (0xE0000000+L1_CACHE_SIZE)))
{
_var = bswap((*(const T*)&m_pL1Cache[em_address & L1_CACHE_MASK]));
}
else if ((bFakeVMEM && ((em_address &0xF0000000) == 0x70000000)) ||
(bFakeVMEM && ((em_address &0xF0000000) == 0x40000000)))
{
// fake VMEM
_var = bswap((*(const T*)&m_pFakeVMEM[em_address & FAKEVMEM_MASK]));
}
else
{
translateaddress:
if (bFakeVMEM && (segment == 0x7 || segment == 0x4))
{
// fake VMEM
_var = bswap((*(const T*)&m_pFakeVMEM[em_address & FAKEVMEM_MASK]));
return;
}
// MMU
// Handle loads that cross page boundaries (ewwww)
if (sizeof(T) > 1 && (em_address & (HW_PAGE_SIZE - 1)) > HW_PAGE_SIZE - sizeof(T))
@ -134,9 +138,9 @@ __forceinline void ReadFromHardware(U &_var, const u32 em_address, Memory::XChec
// way isn't too terrible.
// TODO: floats on non-word-aligned boundaries should technically cause alignment exceptions.
// Note that "word" means 32-bit, so paired singles or doubles might still be 32-bit aligned!
u32 tlb_addr = TranslateAddress(em_address, flag);
u32 tlb_addr = TranslateAddress<flag>(em_address);
u32 em_address_next_page = (em_address + sizeof(T) - 1) & ~(HW_PAGE_SIZE - 1);
u32 tlb_addr_next_page = TranslateAddress(em_address_next_page, flag);
u32 tlb_addr_next_page = TranslateAddress<flag>(em_address_next_page);
if (tlb_addr == 0 || tlb_addr_next_page == 0)
{
if (flag == FLAG_READ)
@ -163,7 +167,7 @@ __forceinline void ReadFromHardware(U &_var, const u32 em_address, Memory::XChec
}
else
{
u32 tlb_addr = TranslateAddress(em_address, flag);
u32 tlb_addr = TranslateAddress<flag>(em_address);
if (tlb_addr == 0)
{
if (flag == FLAG_READ)
@ -190,9 +194,14 @@ __forceinline void ReadFromHardware(U &_var, const u32 em_address, Memory::XChec
}
template <typename T>
__forceinline void WriteToHardware(u32 em_address, const T data, Memory::XCheckTLBFlag flag)
template <XCheckTLBFlag flag, typename T>
__forceinline void WriteToHardware(u32 em_address, const T data)
{
int segment = em_address >> 28;
// Quick check for an address that can't meet any of the following conditions,
// to speed up the MMU path.
if (BitSet32(0xCFC)[segment])
goto translateaddress;
// First, let's check for FIFO writes, since they are probably the most common
// reason we end up in this function:
if ((em_address & 0xFFFFF000) == 0xCC008000)
@ -231,42 +240,40 @@ __forceinline void WriteToHardware(u32 em_address, const T data, Memory::XCheckT
return;
}
}
else if (((em_address & 0xF0000000) == 0x80000000) ||
((em_address & 0xF0000000) == 0xC0000000) ||
((em_address & 0xF0000000) == 0x00000000))
else if (segment == 0x8 || segment == 0xC || segment == 0x0)
{
*(T*)&m_pRAM[em_address & RAM_MASK] = bswap(data);
return;
}
else if (m_pEXRAM && (((em_address & 0xF0000000) == 0x90000000) ||
((em_address & 0xF0000000) == 0xD0000000) ||
((em_address & 0xF0000000) == 0x10000000)))
else if (m_pEXRAM && (segment == 0x9 || segment == 0xD || segment == 0x1))
{
*(T*)&m_pEXRAM[em_address & EXRAM_MASK] = bswap(data);
return;
}
else if ((em_address >= 0xE0000000) && (em_address < (0xE0000000+L1_CACHE_SIZE)))
else if (segment == 0xE && (em_address < (0xE0000000+L1_CACHE_SIZE)))
{
*(T*)&m_pL1Cache[em_address & L1_CACHE_MASK] = bswap(data);
return;
}
else if ((bFakeVMEM && ((em_address &0xF0000000) == 0x70000000)) ||
(bFakeVMEM && ((em_address &0xF0000000) == 0x40000000)))
{
// fake VMEM
*(T*)&m_pFakeVMEM[em_address & FAKEVMEM_MASK] = bswap(data);
}
else
{
translateaddress:
if (bFakeVMEM && (segment == 0x7 || segment == 0x4))
{
// fake VMEM
*(T*)&m_pFakeVMEM[em_address & FAKEVMEM_MASK] = bswap(data);
return;
}
// MMU
// Handle stores that cross page boundaries (ewwww)
if (sizeof(T) > 1 && (em_address & (HW_PAGE_SIZE-1)) > HW_PAGE_SIZE - sizeof(T))
if (sizeof(T) > 1 && (em_address & (HW_PAGE_SIZE - 1)) > HW_PAGE_SIZE - sizeof(T))
{
T val = bswap(data);
// We need to check both addresses before writing in case there's a DSI.
u32 tlb_addr = TranslateAddress(em_address, flag);
u32 tlb_addr = TranslateAddress<flag>(em_address);
u32 em_address_next_page = (em_address + sizeof(T) - 1) & ~(HW_PAGE_SIZE - 1);
u32 tlb_addr_next_page = TranslateAddress(em_address_next_page, flag);
u32 tlb_addr_next_page = TranslateAddress<flag>(em_address_next_page);
if (tlb_addr == 0 || tlb_addr_next_page == 0)
{
if (flag == FLAG_WRITE)
@ -291,7 +298,7 @@ __forceinline void WriteToHardware(u32 em_address, const T data, Memory::XCheckT
}
else
{
u32 tlb_addr = TranslateAddress(em_address, flag);
u32 tlb_addr = TranslateAddress<flag>(em_address);
if (tlb_addr == 0)
{
if (flag == FLAG_WRITE)
@ -339,7 +346,7 @@ u32 Read_Opcode(u32 _Address)
(_Address & ADDR_MASK_MEM1))
{
// TODO: Check for MSR instruction address translation flag before translating
u32 tlb_addr = Memory::TranslateAddress(_Address, FLAG_OPCODE);
u32 tlb_addr = TranslateAddress<FLAG_OPCODE>(_Address);
if (tlb_addr == 0)
{
GenerateISIException(_Address);
@ -354,63 +361,49 @@ u32 Read_Opcode(u32 _Address)
return PowerPC::ppcState.iCache.ReadInstruction(_Address);
}
#ifdef ENABLE_MEM_CHECK
#define MEMCHECK(write, size)\
{\
TMemCheck *mc = PowerPC::memchecks.GetMemCheck(_Address);\
if (mc)\
{\
mc->numHits++;\
mc->Action(&PowerPC::debug_interface, (u32)_var, _Address, write, size, PC);\
}\
}
#else
#define MEMCHECK(write, size)
#endif
u8 Read_U8(const u32 _Address)
{
u8 _var = 0;
ReadFromHardware<u8>(_var, _Address, FLAG_READ);
#ifdef ENABLE_MEM_CHECK
TMemCheck *mc = PowerPC::memchecks.GetMemCheck(_Address);
if (mc)
{
mc->numHits++;
mc->Action(&PowerPC::debug_interface, _var, _Address, false, 1, PC);
}
#endif
ReadFromHardware<FLAG_READ, u8>(_var, _Address);
MEMCHECK(false, 1);
return (u8)_var;
}
u16 Read_U16(const u32 _Address)
{
u16 _var = 0;
ReadFromHardware<u16>(_var, _Address, FLAG_READ);
#ifdef ENABLE_MEM_CHECK
TMemCheck *mc = PowerPC::memchecks.GetMemCheck(_Address);
if (mc)
{
mc->numHits++;
mc->Action(&PowerPC::debug_interface, _var, _Address, false, 2, PC);
}
#endif
ReadFromHardware<FLAG_READ, u16>(_var, _Address);
MEMCHECK(false, 2);
return (u16)_var;
}
u32 Read_U32(const u32 _Address)
{
u32 _var = 0;
ReadFromHardware<u32>(_var, _Address, FLAG_READ);
#ifdef ENABLE_MEM_CHECK
TMemCheck *mc = PowerPC::memchecks.GetMemCheck(_Address);
if (mc)
{
mc->numHits++;
mc->Action(&PowerPC::debug_interface, _var, _Address, false, 4, PC);
}
#endif
ReadFromHardware<FLAG_READ, u32>(_var, _Address);
MEMCHECK(false, 4);
return _var;
}
u64 Read_U64(const u32 _Address)
{
u64 _var = 0;
ReadFromHardware<u64>(_var, _Address, FLAG_READ);
#ifdef ENABLE_MEM_CHECK
TMemCheck *mc = PowerPC::memchecks.GetMemCheck(_Address);
if (mc)
{
mc->numHits++;
mc->Action(&PowerPC::debug_interface, (u32)_var, _Address, false, 8, PC);
}
#endif
ReadFromHardware<FLAG_READ, u64>(_var, _Address);
MEMCHECK(false, 8);
return _var;
}
@ -438,40 +431,46 @@ float Read_F32(const u32 _Address)
return cvt.d;
}
u32 Read_U8_Val(u32 address, u32 val)
u32 Read_U8_Val(const u32 _Address, u32 _var)
{
ReadFromHardware<u8>(val, address, FLAG_READ);
return val;
ReadFromHardware<FLAG_READ, u8>(_var, _Address);
MEMCHECK(false, 1);
return _var;
}
u32 Read_S8_Val(u32 address, u32 val)
u32 Read_S8_Val(const u32 _Address, u32 _var)
{
ReadFromHardware<s8>(val, address, FLAG_READ);
return val;
ReadFromHardware<FLAG_READ, s8>(_var, _Address);
MEMCHECK(false, 1);
return _var;
}
u32 Read_U16_Val(u32 address, u32 val)
u32 Read_U16_Val(const u32 _Address, u32 _var)
{
ReadFromHardware<u16>(val, address, FLAG_READ);
return val;
ReadFromHardware<FLAG_READ, u16>(_var, _Address);
MEMCHECK(false, 2);
return _var;
}
u32 Read_S16_Val(u32 address, u32 val)
u32 Read_S16_Val(const u32 _Address, u32 _var)
{
ReadFromHardware<s16>(val, address, FLAG_READ);
return val;
ReadFromHardware<FLAG_READ, s16>(_var, _Address);
MEMCHECK(false, 2);
return _var;
}
u32 Read_U32_Val(u32 address, u32 val)
u32 Read_U32_Val(const u32 _Address, u32 _var)
{
ReadFromHardware<u32>(val, address, FLAG_READ);
return val;
ReadFromHardware<FLAG_READ, u32>(_var, _Address);
MEMCHECK(false, 4);
return _var;
}
u64 Read_U64_Val(u32 address, u64 val)
u64 Read_U64_Val(const u32 _Address, u64 _var)
{
ReadFromHardware<u64>(val, address, FLAG_READ);
return val;
ReadFromHardware<FLAG_READ, u64>(_var, _Address);
MEMCHECK(false, 8);
return _var;
}
u32 Read_U8_ZX(const u32 _Address)
@ -484,88 +483,60 @@ u32 Read_U16_ZX(const u32 _Address)
return (u32)Read_U16(_Address);
}
void Write_U8(const u8 _Data, const u32 _Address)
void Write_U8(const u8 _var, const u32 _Address)
{
#ifdef ENABLE_MEM_CHECK
TMemCheck *mc = PowerPC::memchecks.GetMemCheck(_Address);
if (mc)
{
mc->numHits++;
mc->Action(&PowerPC::debug_interface, _Data,_Address,true,1,PC);
}
#endif
WriteToHardware<u8>(_Address, _Data, FLAG_WRITE);
MEMCHECK(true, 1);
WriteToHardware<FLAG_WRITE, u8>(_Address, _var);
}
void Write_U16(const u16 _var, const u32 _Address)
{
MEMCHECK(true, 2);
WriteToHardware<FLAG_WRITE, u16>(_Address, _var);
}
void Write_U16_Swap(const u16 _var, const u32 _Address)
{
MEMCHECK(true, 2);
Write_U16(Common::swap16(_var), _Address);
}
void Write_U16(const u16 _Data, const u32 _Address)
void Write_U32(const u32 _var, const u32 _Address)
{
#ifdef ENABLE_MEM_CHECK
TMemCheck *mc = PowerPC::memchecks.GetMemCheck(_Address);
if (mc)
{
mc->numHits++;
mc->Action(&PowerPC::debug_interface, _Data,_Address,true,2,PC);
}
#endif
WriteToHardware<u16>(_Address, _Data, FLAG_WRITE);
MEMCHECK(true, 4);
WriteToHardware<FLAG_WRITE, u32>(_Address, _var);
}
void Write_U16_Swap(const u16 _Data, const u32 _Address)
void Write_U32_Swap(const u32 _var, const u32 _Address)
{
Write_U16(Common::swap16(_Data), _Address);
MEMCHECK(true, 4);
Write_U32(Common::swap32(_var), _Address);
}
void Write_U32(const u32 _Data, const u32 _Address)
void Write_U64(const u64 _var, const u32 _Address)
{
#ifdef ENABLE_MEM_CHECK
TMemCheck *mc = PowerPC::memchecks.GetMemCheck(_Address);
if (mc)
{
mc->numHits++;
mc->Action(&PowerPC::debug_interface, _Data,_Address,true,4,PC);
}
#endif
WriteToHardware<u32>(_Address, _Data, FLAG_WRITE);
MEMCHECK(true, 8);
WriteToHardware<FLAG_WRITE, u64>(_Address, _var);
}
void Write_U32_Swap(const u32 _Data, const u32 _Address)
void Write_U64_Swap(const u64 _var, const u32 _Address)
{
Write_U32(Common::swap32(_Data), _Address);
MEMCHECK(true, 8);
Write_U64(Common::swap64(_var), _Address);
}
void Write_U64(const u64 _Data, const u32 _Address)
{
#ifdef ENABLE_MEM_CHECK
TMemCheck *mc = PowerPC::memchecks.GetMemCheck(_Address);
if (mc)
{
mc->numHits++;
mc->Action(&PowerPC::debug_interface, (u32)_Data,_Address,true,8,PC);
}
#endif
WriteToHardware<u64>(_Address, _Data, FLAG_WRITE);
}
void Write_U64_Swap(const u64 _Data, const u32 _Address)
{
Write_U64(Common::swap64(_Data), _Address);
}
void Write_F64(const double _Data, const u32 _Address)
void Write_F64(const double _var, const u32 _Address)
{
union
{
u64 i;
double d;
} cvt;
cvt.d = _Data;
cvt.d = _var;
Write_U64(cvt.i, _Address);
}
u8 ReadUnchecked_U8(const u32 _Address)
{
u8 _var = 0;
ReadFromHardware<u8>(_var, _Address, FLAG_NO_EXCEPTION);
ReadFromHardware<FLAG_NO_EXCEPTION, u8>(_var, _Address);
return _var;
}
@ -573,19 +544,19 @@ u8 ReadUnchecked_U8(const u32 _Address)
u32 ReadUnchecked_U32(const u32 _Address)
{
u32 _var = 0;
ReadFromHardware<u32>(_var, _Address, FLAG_NO_EXCEPTION);
ReadFromHardware<FLAG_NO_EXCEPTION, u32>(_var, _Address);
return _var;
}
void WriteUnchecked_U8(const u8 _iValue, const u32 _Address)
{
WriteToHardware<u8>(_Address, _iValue, FLAG_NO_EXCEPTION);
WriteToHardware<FLAG_NO_EXCEPTION, u8>(_Address, _iValue);
}
void WriteUnchecked_U32(const u32 _iValue, const u32 _Address)
{
WriteToHardware<u32>(_Address, _iValue, FLAG_NO_EXCEPTION);
WriteToHardware<FLAG_NO_EXCEPTION, u32>(_Address, _iValue);
}
// *********************************************************************************
@ -731,8 +702,9 @@ void SDRUpdated()
static __forceinline u32 LookupTLBPageAddress(const XCheckTLBFlag _Flag, const u32 vpa, u32 *paddr)
{
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))
int tag = vpa >> HW_PAGE_INDEX_SHIFT;
PowerPC::tlb_entry *tlbe = PowerPC::ppcState.tlb[_Flag == FLAG_OPCODE][tag & HW_PAGE_INDEX_MASK];
if (tlbe[0].tag == tag && !(tlbe[0].flags & TLB_FLAG_INVALID))
{
// Check if C bit requires updating
if (_Flag == FLAG_WRITE)
@ -757,7 +729,7 @@ static __forceinline u32 LookupTLBPageAddress(const XCheckTLBFlag _Flag, const u
return 1;
}
if (tlbe[1].tag == (vpa & ~0xfff) && !(tlbe[1].flags & TLB_FLAG_INVALID))
if (tlbe[1].tag == tag && !(tlbe[1].flags & TLB_FLAG_INVALID))
{
// Check if C bit requires updating
if (_Flag == FLAG_WRITE)
@ -797,7 +769,7 @@ static __forceinline void UpdateTLBEntry(const XCheckTLBFlag _Flag, UPTE2 PTE2,
tlbe[1].flags &= ~TLB_FLAG_MOST_RECENT;
tlbe[0].paddr = PTE2.RPN << HW_PAGE_INDEX_SHIFT;
tlbe[0].pte = PTE2.Hex;
tlbe[0].tag = vpa & ~0xfff;
tlbe[0].tag = vpa >> HW_PAGE_INDEX_SHIFT;
}
else
{
@ -805,7 +777,7 @@ static __forceinline void UpdateTLBEntry(const XCheckTLBFlag _Flag, UPTE2 PTE2,
tlbe[0].flags &= ~TLB_FLAG_MOST_RECENT;
tlbe[1].paddr = PTE2.RPN << HW_PAGE_INDEX_SHIFT;
tlbe[1].pte = PTE2.Hex;
tlbe[1].tag = vpa & ~0xfff;
tlbe[1].tag = vpa >> HW_PAGE_INDEX_SHIFT;
}
}
@ -952,7 +924,8 @@ static u32 TranslateBlockAddress(const u32 addr, const XCheckTLBFlag _Flag)
}
// Translate effective address using BAT or PAT. Returns 0 if the address cannot be translated.
u32 TranslateAddress(const u32 _Address, const XCheckTLBFlag _Flag)
template <const XCheckTLBFlag _Flag>
u32 TranslateAddress(const u32 _Address)
{
// Check MSR[IR] bit before translating instruction addresses. Rogue Leader clears IR and DR??
//if ((_Flag == FLAG_OPCODE) && !(MSR & (1 << (31 - 26)))) return _Address;
@ -970,4 +943,9 @@ u32 TranslateAddress(const u32 _Address, const XCheckTLBFlag _Flag)
}
return TranslatePageAddress(_Address, _Flag);
}
template u32 TranslateAddress<Memory::FLAG_NO_EXCEPTION>(const u32 _Address);
template u32 TranslateAddress<Memory::FLAG_READ>(const u32 _Address);
template u32 TranslateAddress<Memory::FLAG_WRITE>(const u32 _Address);
template u32 TranslateAddress<Memory::FLAG_OPCODE>(const u32 _Address);
} // namespace

View File

@ -211,7 +211,7 @@ namespace JitInterface
{
if (bMMU && !bFakeVMEM && (_Address & Memory::ADDR_MASK_MEM1))
{
_Address = Memory::TranslateAddress(_Address, Memory::FLAG_OPCODE);
_Address = Memory::TranslateAddress<Memory::FLAG_OPCODE>(_Address);
if (_Address == 0)
{
return 0;

View File

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