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:
parent
ea23ce2726
commit
c2ed29fe0d
|
@ -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)";
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue