Memmapfunctions: more refactoring and optimizations

Try to clean up some redundant code, simplify a few checks, and simplify
page accesses.
This commit is contained in:
Fiora
2015-01-01 13:02:33 -08:00
parent c2ed29fe0d
commit a0e5c76a1f
2 changed files with 163 additions and 199 deletions

View File

@ -91,37 +91,37 @@ u32 Read_Instruction(const u32 _Address);
// For use by emulator // For use by emulator
u8 Read_U8(const u32 _Address); u8 Read_U8(const u32 address);
u16 Read_U16(const u32 _Address); u16 Read_U16(const u32 address);
u32 Read_U32(const u32 _Address); u32 Read_U32(const u32 address);
u64 Read_U64(const u32 _Address); u64 Read_U64(const u32 address);
u32 Read_S8_Val(const u32 _Address, u32 _var); u32 Read_S8_Val(const u32 address, u32 var);
u32 Read_U8_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_S16_Val(const u32 address, u32 var);
u32 Read_U16_Val(const u32 _Address, u32 _var); u32 Read_U16_Val(const u32 address, u32 var);
u32 Read_U32_Val(const u32 _Address, u32 _var); u32 Read_U32_Val(const u32 address, u32 var);
u64 Read_U64_Val(const u32 _Address, u64 _var); u64 Read_U64_Val(const u32 address, u64 var);
// Useful helper functions, used by ARM JIT // Useful helper functions, used by ARM JIT
float Read_F32(const u32 _Address); float Read_F32(const u32 address);
double Read_F64(const u32 _Address); double Read_F64(const u32 address);
// used by JIT. Return zero-extended 32bit values // used by JIT. Return zero-extended 32bit values
u32 Read_U8_ZX(const u32 _Address); u32 Read_U8_ZX(const u32 address);
u32 Read_U16_ZX(const u32 _Address); u32 Read_U16_ZX(const u32 address);
void Write_U8(const u8 _var, const u32 _Address); void Write_U8(const u8 var, const u32 address);
void Write_U16(const u16 _var, const u32 _Address); void Write_U16(const u16 var, const u32 address);
void Write_U32(const u32 _var, const u32 _Address); void Write_U32(const u32 var, const u32 address);
void Write_U64(const u64 _var, const u32 _Address); void Write_U64(const u64 var, const u32 address);
void Write_U16_Swap(const u16 _var, 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_U32_Swap(const u32 var, const u32 address);
void Write_U64_Swap(const u64 _var, const u32 _Address); void Write_U64_Swap(const u64 var, const u32 address);
// Useful helper functions, used by ARM JIT // Useful helper functions, used by ARM JIT
void Write_F64(const double _var, const u32 _Address); void Write_F64(const double var, const u32 address);
std::string GetString(u32 em_address, size_t size = 0); std::string GetString(u32 em_address, size_t size = 0);

View File

@ -129,28 +129,31 @@ translateaddress:
_var = bswap((*(const T*)&m_pFakeVMEM[em_address & FAKEVMEM_MASK])); _var = bswap((*(const T*)&m_pFakeVMEM[em_address & FAKEVMEM_MASK]));
return; return;
} }
// MMU // MMU: Do page table translation
u32 tlb_addr = TranslateAddress<flag>(em_address);
if (tlb_addr == 0)
{
if (flag == FLAG_READ)
GenerateDSIException(em_address, false);
return;
}
// Handle loads that cross page boundaries (ewwww) // Handle loads that cross page boundaries (ewwww)
if (sizeof(T) > 1 && (em_address & (HW_PAGE_SIZE - 1)) > HW_PAGE_SIZE - sizeof(T)) // The alignment check isn't strictly necessary, but since this is a rare slow path, it provides a faster
// (1 instruction on x86) bailout.
if (sizeof(T) > 1 && (em_address & (sizeof(T) - 1)) && (em_address & (HW_PAGE_SIZE - 1)) > HW_PAGE_SIZE - sizeof(T))
{ {
// This could be unaligned down to the byte level... hopefully this is rare, so doing it this // This could be unaligned down to the byte level... hopefully this is rare, so doing it this
// way isn't too terrible. // way isn't too terrible.
// TODO: floats on non-word-aligned boundaries should technically cause alignment exceptions. // 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! // Note that "word" means 32-bit, so paired singles or doubles might still be 32-bit aligned!
u32 tlb_addr = TranslateAddress<flag>(em_address);
u32 em_address_next_page = (em_address + sizeof(T) - 1) & ~(HW_PAGE_SIZE - 1); u32 em_address_next_page = (em_address + sizeof(T) - 1) & ~(HW_PAGE_SIZE - 1);
u32 tlb_addr_next_page = TranslateAddress<flag>(em_address_next_page); u32 tlb_addr_next_page = TranslateAddress<flag>(em_address_next_page);
if (tlb_addr == 0 || tlb_addr_next_page == 0) if (tlb_addr == 0 || tlb_addr_next_page == 0)
{ {
if (flag == FLAG_READ) if (flag == FLAG_READ)
{ GenerateDSIException(em_address_next_page, false);
u32 exception_addr = tlb_addr == 0 ? em_address : em_address_next_page;
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bMMU)
PanicAlertT("Invalid Read at 0x%08x, PC = 0x%08x ", exception_addr, PC);
else
GenerateDSIException(exception_addr, false);
}
return; return;
} }
_var = 0; _var = 0;
@ -158,37 +161,14 @@ translateaddress:
{ {
if (addr == em_address_next_page) if (addr == em_address_next_page)
tlb_addr = tlb_addr_next_page; tlb_addr = tlb_addr_next_page;
_var <<= 8; _var = (_var << 8) | Memory::base[tlb_addr];
if (m_pEXRAM && (tlb_addr & 0xF0000000) == 0x10000000)
_var |= m_pEXRAM[tlb_addr & EXRAM_MASK];
else
_var |= m_pRAM[tlb_addr & RAM_MASK];
} }
return;
} }
else else
{ {
u32 tlb_addr = TranslateAddress<flag>(em_address); // The easy case!
if (tlb_addr == 0) _var = bswap(*(const T*)&Memory::base[tlb_addr]);
{
if (flag == FLAG_READ)
{
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bMMU)
PanicAlertT("Invalid Read at 0x%08x, PC = 0x%08x ", em_address, PC);
else
GenerateDSIException(em_address, false);
}
}
else
{
if (m_pEXRAM && (tlb_addr & 0xF0000000) == 0x10000000)
{
_var = bswap((*(const T*)&m_pEXRAM[tlb_addr & EXRAM_MASK]));
}
else
{
_var = bswap((*(const T*)&m_pRAM[tlb_addr & RAM_MASK]));
}
}
} }
} }
} }
@ -255,7 +235,7 @@ __forceinline void WriteToHardware(u32 em_address, const T data)
*(T*)&m_pL1Cache[em_address & L1_CACHE_MASK] = bswap(data); *(T*)&m_pL1Cache[em_address & L1_CACHE_MASK] = bswap(data);
return; return;
} }
else else
{ {
translateaddress: translateaddress:
if (bFakeVMEM && (segment == 0x7 || segment == 0x4)) if (bFakeVMEM && (segment == 0x7 || segment == 0x4))
@ -265,61 +245,40 @@ translateaddress:
return; return;
} }
// MMU // MMU: Do page table translation
u32 tlb_addr = TranslateAddress<flag>(em_address);
if (tlb_addr == 0)
{
if (flag == FLAG_WRITE)
GenerateDSIException(em_address, true);
return;
}
// Handle stores that cross page boundaries (ewwww) // 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 & (sizeof(T) - 1)) && (em_address & (HW_PAGE_SIZE - 1)) > HW_PAGE_SIZE - sizeof(T))
{ {
T val = bswap(data); T val = bswap(data);
// We need to check both addresses before writing in case there's a DSI. // We need to check both addresses before writing in case there's a DSI.
u32 tlb_addr = TranslateAddress<flag>(em_address);
u32 em_address_next_page = (em_address + sizeof(T) - 1) & ~(HW_PAGE_SIZE - 1); u32 em_address_next_page = (em_address + sizeof(T) - 1) & ~(HW_PAGE_SIZE - 1);
u32 tlb_addr_next_page = TranslateAddress<flag>(em_address_next_page); u32 tlb_addr_next_page = TranslateAddress<flag>(em_address_next_page);
if (tlb_addr == 0 || tlb_addr_next_page == 0) if (tlb_addr_next_page == 0)
{ {
if (flag == FLAG_WRITE) if (flag == FLAG_WRITE)
{ GenerateDSIException(em_address_next_page, true);
u32 exception_addr = tlb_addr == 0 ? em_address : em_address_next_page;
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bMMU)
PanicAlertT("Invalid Write to 0x%08x, PC = 0x%08x ", exception_addr, PC);
else
GenerateDSIException(exception_addr, true);
}
return; return;
} }
for (u32 addr = em_address; addr < em_address + sizeof(T); addr++, tlb_addr++, val >>= 8) for (u32 addr = em_address; addr < em_address + sizeof(T); addr++, tlb_addr++, val >>= 8)
{ {
if (addr == em_address_next_page) if (addr == em_address_next_page)
tlb_addr = tlb_addr_next_page; tlb_addr = tlb_addr_next_page;
if (m_pEXRAM && (tlb_addr & 0xF0000000) == 0x10000000) Memory::base[tlb_addr] = (u8)val;
m_pEXRAM[tlb_addr & EXRAM_MASK] = (u8)val;
else
m_pRAM[tlb_addr & RAM_MASK] = (u8)val;
} }
} }
else else
{ {
u32 tlb_addr = TranslateAddress<flag>(em_address); // The easy case!
if (tlb_addr == 0) *(T*)&Memory::base[tlb_addr] = bswap(data);
{
if (flag == FLAG_WRITE)
{
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bMMU)
PanicAlertT("Invalid Write to 0x%08x, PC = 0x%08x ", em_address, PC);
else
GenerateDSIException(em_address, true);
}
}
else
{
if (m_pEXRAM && (tlb_addr & 0xF0000000) == 0x10000000)
{
*(T*)&m_pEXRAM[tlb_addr & EXRAM_MASK] = bswap(data);
}
else
{
*(T*)&m_pRAM[tlb_addr & RAM_MASK] = bswap(data);
}
}
} }
} }
} }
@ -361,53 +320,51 @@ u32 Read_Opcode(u32 _Address)
return PowerPC::ppcState.iCache.ReadInstruction(_Address); return PowerPC::ppcState.iCache.ReadInstruction(_Address);
} }
static __forceinline void Memcheck(u32 address, u32 var, bool write, int size)
{
#ifdef ENABLE_MEM_CHECK #ifdef ENABLE_MEM_CHECK
#define MEMCHECK(write, size)\ TMemCheck *mc = PowerPC::memchecks.GetMemCheck(address);
{\ if (mc)
TMemCheck *mc = PowerPC::memchecks.GetMemCheck(_Address);\ {
if (mc)\ mc->numHits++;
{\ mc->Action(&PowerPC::debug_interface, var, address, write, size, PC);
mc->numHits++;\ }
mc->Action(&PowerPC::debug_interface, (u32)_var, _Address, write, size, PC);\
}\
}
#else
#define MEMCHECK(write, size)
#endif #endif
u8 Read_U8(const u32 _Address)
{
u8 _var = 0;
ReadFromHardware<FLAG_READ, u8>(_var, _Address);
MEMCHECK(false, 1);
return (u8)_var;
} }
u16 Read_U16(const u32 _Address) u8 Read_U8(const u32 address)
{ {
u16 _var = 0; u8 var = 0;
ReadFromHardware<FLAG_READ, u16>(_var, _Address); ReadFromHardware<FLAG_READ, u8>(var, address);
MEMCHECK(false, 2); Memcheck(address, var, false, 1);
return (u16)_var; return (u8)var;
} }
u32 Read_U32(const u32 _Address) u16 Read_U16(const u32 address)
{ {
u32 _var = 0; u16 var = 0;
ReadFromHardware<FLAG_READ, u32>(_var, _Address); ReadFromHardware<FLAG_READ, u16>(var, address);
MEMCHECK(false, 4); Memcheck(address, var, false, 2);
return _var; return (u16)var;
} }
u64 Read_U64(const u32 _Address) u32 Read_U32(const u32 address)
{ {
u64 _var = 0; u32 var = 0;
ReadFromHardware<FLAG_READ, u64>(_var, _Address); ReadFromHardware<FLAG_READ, u32>(var, address);
MEMCHECK(false, 8); Memcheck(address, var, false, 4);
return _var; return var;
} }
double Read_F64(const u32 _Address) u64 Read_U64(const u32 address)
{
u64 var = 0;
ReadFromHardware<FLAG_READ, u64>(var, address);
Memcheck(address, (u32)var, false, 8);
return var;
}
double Read_F64(const u32 address)
{ {
union union
{ {
@ -415,11 +372,11 @@ double Read_F64(const u32 _Address)
double d; double d;
} cvt; } cvt;
cvt.i = Read_U64(_Address); cvt.i = Read_U64(address);
return cvt.d; return cvt.d;
} }
float Read_F32(const u32 _Address) float Read_F32(const u32 address)
{ {
union union
{ {
@ -427,136 +384,136 @@ float Read_F32(const u32 _Address)
float d; float d;
} cvt; } cvt;
cvt.i = Read_U32(_Address); cvt.i = Read_U32(address);
return cvt.d; return cvt.d;
} }
u32 Read_U8_Val(const u32 _Address, u32 _var) u32 Read_U8_Val(const u32 address, u32 var)
{ {
ReadFromHardware<FLAG_READ, u8>(_var, _Address); ReadFromHardware<FLAG_READ, u8>(var, address);
MEMCHECK(false, 1); Memcheck(address, var, false, 1);
return _var; return var;
} }
u32 Read_S8_Val(const u32 _Address, u32 _var) u32 Read_S8_Val(const u32 address, u32 var)
{ {
ReadFromHardware<FLAG_READ, s8>(_var, _Address); ReadFromHardware<FLAG_READ, s8>(var, address);
MEMCHECK(false, 1); Memcheck(address, var, false, 1);
return _var; return var;
} }
u32 Read_U16_Val(const u32 _Address, u32 _var) u32 Read_U16_Val(const u32 address, u32 var)
{ {
ReadFromHardware<FLAG_READ, u16>(_var, _Address); ReadFromHardware<FLAG_READ, u16>(var, address);
MEMCHECK(false, 2); Memcheck(address, var, false, 2);
return _var; return var;
} }
u32 Read_S16_Val(const u32 _Address, u32 _var) u32 Read_S16_Val(const u32 address, u32 var)
{ {
ReadFromHardware<FLAG_READ, s16>(_var, _Address); ReadFromHardware<FLAG_READ, s16>(var, address);
MEMCHECK(false, 2); Memcheck(address, var, false, 2);
return _var; return var;
} }
u32 Read_U32_Val(const u32 _Address, u32 _var) u32 Read_U32_Val(const u32 address, u32 var)
{ {
ReadFromHardware<FLAG_READ, u32>(_var, _Address); ReadFromHardware<FLAG_READ, u32>(var, address);
MEMCHECK(false, 4); Memcheck(address, var, false, 4);
return _var; return var;
} }
u64 Read_U64_Val(const u32 _Address, u64 _var) u64 Read_U64_Val(const u32 address, u64 var)
{ {
ReadFromHardware<FLAG_READ, u64>(_var, _Address); ReadFromHardware<FLAG_READ, u64>(var, address);
MEMCHECK(false, 8); Memcheck(address, (u32)var, false, 8);
return _var; return var;
} }
u32 Read_U8_ZX(const u32 _Address) u32 Read_U8_ZX(const u32 address)
{ {
return (u32)Read_U8(_Address); return (u32)Read_U8(address);
} }
u32 Read_U16_ZX(const u32 _Address) u32 Read_U16_ZX(const u32 address)
{ {
return (u32)Read_U16(_Address); return (u32)Read_U16(address);
} }
void Write_U8(const u8 _var, const u32 _Address) void Write_U8(const u8 var, const u32 address)
{ {
MEMCHECK(true, 1); Memcheck(address, var, true, 1);
WriteToHardware<FLAG_WRITE, u8>(_Address, _var); WriteToHardware<FLAG_WRITE, u8>(address, var);
} }
void Write_U16(const u16 _var, const u32 _Address) void Write_U16(const u16 var, const u32 address)
{ {
MEMCHECK(true, 2); Memcheck(address, var, true, 2);
WriteToHardware<FLAG_WRITE, u16>(_Address, _var); WriteToHardware<FLAG_WRITE, u16>(address, var);
} }
void Write_U16_Swap(const u16 _var, const u32 _Address) void Write_U16_Swap(const u16 var, const u32 address)
{ {
MEMCHECK(true, 2); Memcheck(address, var, true, 2);
Write_U16(Common::swap16(_var), _Address); Write_U16(Common::swap16(var), address);
} }
void Write_U32(const u32 _var, const u32 _Address) void Write_U32(const u32 var, const u32 address)
{ {
MEMCHECK(true, 4); Memcheck(address, var, true, 4);
WriteToHardware<FLAG_WRITE, u32>(_Address, _var); WriteToHardware<FLAG_WRITE, u32>(address, var);
} }
void Write_U32_Swap(const u32 _var, const u32 _Address) void Write_U32_Swap(const u32 var, const u32 address)
{ {
MEMCHECK(true, 4); Memcheck(address, var, true, 4);
Write_U32(Common::swap32(_var), _Address); Write_U32(Common::swap32(var), address);
} }
void Write_U64(const u64 _var, const u32 _Address) void Write_U64(const u64 var, const u32 address)
{ {
MEMCHECK(true, 8); Memcheck(address, (u32)var, true, 8);
WriteToHardware<FLAG_WRITE, u64>(_Address, _var); WriteToHardware<FLAG_WRITE, u64>(address, var);
} }
void Write_U64_Swap(const u64 _var, const u32 _Address) void Write_U64_Swap(const u64 var, const u32 address)
{ {
MEMCHECK(true, 8); Memcheck(address, (u32)var, true, 8);
Write_U64(Common::swap64(_var), _Address); Write_U64(Common::swap64(var), address);
} }
void Write_F64(const double _var, const u32 _Address) void Write_F64(const double var, const u32 address)
{ {
union union
{ {
u64 i; u64 i;
double d; double d;
} cvt; } cvt;
cvt.d = _var; cvt.d = var;
Write_U64(cvt.i, _Address); Write_U64(cvt.i, address);
} }
u8 ReadUnchecked_U8(const u32 _Address) u8 ReadUnchecked_U8(const u32 address)
{ {
u8 _var = 0; u8 var = 0;
ReadFromHardware<FLAG_NO_EXCEPTION, u8>(_var, _Address); ReadFromHardware<FLAG_NO_EXCEPTION, u8>(var, address);
return _var; return var;
} }
u32 ReadUnchecked_U32(const u32 _Address) u32 ReadUnchecked_U32(const u32 address)
{ {
u32 _var = 0; u32 var = 0;
ReadFromHardware<FLAG_NO_EXCEPTION, u32>(_var, _Address); ReadFromHardware<FLAG_NO_EXCEPTION, u32>(var, address);
return _var; return var;
} }
void WriteUnchecked_U8(const u8 _iValue, const u32 _Address) void WriteUnchecked_U8(const u8 var, const u32 address)
{ {
WriteToHardware<FLAG_NO_EXCEPTION, u8>(_Address, _iValue); WriteToHardware<FLAG_NO_EXCEPTION, u8>(address, var);
} }
void WriteUnchecked_U32(const u32 _iValue, const u32 _Address) void WriteUnchecked_U32(const u32 var, const u32 address)
{ {
WriteToHardware<FLAG_NO_EXCEPTION, u32>(_Address, _iValue); WriteToHardware<FLAG_NO_EXCEPTION, u32>(address, var);
} }
// ********************************************************************************* // *********************************************************************************
@ -654,6 +611,13 @@ union UPTE2
static void GenerateDSIException(u32 _EffectiveAddress, bool _bWrite) static void GenerateDSIException(u32 _EffectiveAddress, bool _bWrite)
{ {
// DSI exceptions are only supported in MMU mode.
if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bMMU)
{
PanicAlertT("Invalid %s to 0x%08x, PC = 0x%08x ", _bWrite ? "Write to" : "Read from", _EffectiveAddress, PC);
return;
}
if (_bWrite) if (_bWrite)
PowerPC::ppcState.spr[SPR_DSISR] = PPC_EXC_DSISR_PAGE | PPC_EXC_DSISR_STORE; PowerPC::ppcState.spr[SPR_DSISR] = PPC_EXC_DSISR_PAGE | PPC_EXC_DSISR_STORE;
else else