Skip to content
Permalink
Browse files

Merge pull request #1804 from FioraAeterna/fastermmu2_master

MMU: various improvements, bugfixes, optimizations
  • Loading branch information...
dolphin-emu-bot committed Jan 6, 2015
2 parents a2ec4d5 + e85f0ff commit 89b7f1057fd46cc77c8a93bba961d2d7f98f1959
Showing with 726 additions and 792 deletions.
  1. +14 −4 Source/Core/Common/x64ABI.cpp
  2. +1 −1 Source/Core/Common/x64Emitter.h
  3. +1 −1 Source/Core/Core/Debugger/PPCDebugInterface.cpp
  4. +39 −39 Source/Core/Core/HW/Memmap.cpp
  5. +30 −37 Source/Core/Core/HW/Memmap.h
  6. +308 −451 Source/Core/Core/HW/MemmapFunctions.cpp
  7. +42 −15 Source/Core/Core/PowerPC/Jit64/Jit.cpp
  8. +1 −0 Source/Core/Core/PowerPC/Jit64/Jit.h
  9. +2 −0 Source/Core/Core/PowerPC/Jit64/JitAsm.cpp
  10. +2 −2 Source/Core/Core/PowerPC/Jit64/JitRegCache.cpp
  11. +1 −1 Source/Core/Core/PowerPC/Jit64/JitRegCache.h
  12. +36 −25 Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp
  13. +29 −31 Source/Core/Core/PowerPC/Jit64/Jit_LoadStoreFloating.cpp
  14. +2 −4 Source/Core/Core/PowerPC/Jit64/Jit_LoadStorePaired.cpp
  15. +46 −31 Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp
  16. +1 −1 Source/Core/Core/PowerPC/Jit64IL/JitIL.cpp
  17. +38 −0 Source/Core/Core/PowerPC/JitCommon/JitAsmCommon.cpp
  18. +2 −0 Source/Core/Core/PowerPC/JitCommon/JitAsmCommon.h
  19. +19 −9 Source/Core/Core/PowerPC/JitCommon/JitBackpatch.cpp
  20. +10 −0 Source/Core/Core/PowerPC/JitCommon/JitBase.h
  21. +16 −10 Source/Core/Core/PowerPC/JitCommon/Jit_Util.cpp
  22. +7 −12 Source/Core/Core/PowerPC/JitCommon/Jit_Util.h
  23. +53 −80 Source/Core/Core/PowerPC/JitCommon/TrampolineCache.cpp
  24. +3 −23 Source/Core/Core/PowerPC/JitCommon/TrampolineCache.h
  25. +1 −1 Source/Core/Core/PowerPC/JitInterface.cpp
  26. +10 −1 Source/Core/Core/PowerPC/PPCAnalyst.cpp
  27. +4 −4 Source/Core/Core/PowerPC/PowerPC.cpp
  28. +7 −8 Source/Core/Core/PowerPC/PowerPC.h
  29. +1 −1 Source/Core/Core/State.cpp
@@ -181,29 +181,39 @@ void XEmitter::ABI_CallFunctionR(const void *func, X64Reg reg1)
// Pass two registers as parameters.
void XEmitter::ABI_CallFunctionRR(const void *func, X64Reg reg1, X64Reg reg2)
{
MOVTwo(64, ABI_PARAM1, reg1, ABI_PARAM2, reg2);
MOVTwo(64, ABI_PARAM1, reg1, 0, ABI_PARAM2, reg2);
ABI_CallFunction(func);
}

void XEmitter::MOVTwo(int bits, Gen::X64Reg dst1, Gen::X64Reg src1, Gen::X64Reg dst2, Gen::X64Reg src2)
void XEmitter::MOVTwo(int bits, Gen::X64Reg dst1, Gen::X64Reg src1, s32 offset1, Gen::X64Reg dst2, Gen::X64Reg src2)
{
if (dst1 == src2 && dst2 == src1)
{
XCHG(bits, R(src1), R(src2));
if (offset1)
ADD(bits, R(dst1), Imm32(offset1));
}
else if (src2 != dst1)
{
if (dst1 != src1)
if (dst1 != src1 && offset1)
LEA(bits, dst1, MDisp(src1, offset1));
else if (dst1 != src1)
MOV(bits, R(dst1), R(src1));
else if (offset1)
ADD(bits, R(dst1), Imm32(offset1));
if (dst2 != src2)
MOV(bits, R(dst2), R(src2));
}
else
{
if (dst2 != src2)
MOV(bits, R(dst2), R(src2));
if (dst1 != src1)
if (dst1 != src1 && offset1)
LEA(bits, dst1, MDisp(src1, offset1));
else if (dst1 != src1)
MOV(bits, R(dst1), R(src1));
else if (offset1)
ADD(bits, R(dst1), Imm32(offset1));
}
}

@@ -888,7 +888,7 @@ class XEmitter
void ABI_CallFunctionRR(const void *func, X64Reg reg1, X64Reg reg2);

// Helper method for the above, or can be used separately.
void MOVTwo(int bits, Gen::X64Reg dst1, Gen::X64Reg src1, Gen::X64Reg dst2, Gen::X64Reg src2);
void MOVTwo(int bits, Gen::X64Reg dst1, Gen::X64Reg src1, s32 offset, Gen::X64Reg dst2, Gen::X64Reg src2);

// Saves/restores the registers and adjusts the stack to be aligned as
// required by the ABI, where the previous alignment was as specified.
@@ -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)";
}
@@ -188,9 +188,9 @@ bool AreMemoryBreakpointsActivated()
#endif
}

u32 Read_Instruction(const u32 em_address)
u32 Read_Instruction(const u32 address)
{
UGeckoInstruction inst = ReadUnchecked_U32(em_address);
UGeckoInstruction inst = ReadUnchecked_U32(address);
return inst.hex;
}

@@ -235,48 +235,48 @@ void Memset(const u32 _Address, const u8 _iValue, const u32 _iLength)
}
}

void ClearCacheLine(const u32 _Address)
void ClearCacheLine(const u32 address)
{
// FIXME: does this do the right thing if dcbz is run on hardware memory, e.g.
// the FIFO? Do games even do that? Probably not, but we should try to be correct...
for (u32 i = 0; i < 32; i += 8)
Write_U64(0, _Address + i);
Write_U64(0, address + i);
}

void DMA_LCToMemory(const u32 _MemAddr, const u32 _CacheAddr, const u32 _iNumBlocks)
void DMA_LCToMemory(const u32 memAddr, const u32 cacheAddr, const u32 numBlocks)
{
const u8* src = m_pL1Cache + (_CacheAddr & 0x3FFFF);
u8* dst = GetPointer(_MemAddr);
const u8* src = m_pL1Cache + (cacheAddr & 0x3FFFF);
u8* dst = GetPointer(memAddr);

if ((dst != nullptr) && (src != nullptr) && (_MemAddr & 3) == 0 && (_CacheAddr & 3) == 0)
if ((dst != nullptr) && (src != nullptr) && (memAddr & 3) == 0 && (cacheAddr & 3) == 0)
{
memcpy(dst, src, 32 * _iNumBlocks);
memcpy(dst, src, 32 * numBlocks);
}
else
{
for (u32 i = 0; i < 32 * _iNumBlocks; i++)
for (u32 i = 0; i < 32 * numBlocks; i++)
{
u8 Temp = Read_U8(_CacheAddr + i);
Write_U8(Temp, _MemAddr + i);
u8 Temp = Read_U8(cacheAddr + i);
Write_U8(Temp, memAddr + i);
}
}
}

void DMA_MemoryToLC(const u32 _CacheAddr, const u32 _MemAddr, const u32 _iNumBlocks)
void DMA_MemoryToLC(const u32 cacheAddr, const u32 memAddr, const u32 numBlocks)
{
const u8* src = GetPointer(_MemAddr);
u8* dst = m_pL1Cache + (_CacheAddr & 0x3FFFF);
const u8* src = GetPointer(memAddr);
u8* dst = m_pL1Cache + (cacheAddr & 0x3FFFF);

if ((dst != nullptr) && (src != nullptr) && (_MemAddr & 3) == 0 && (_CacheAddr & 3) == 0)
if ((dst != nullptr) && (src != nullptr) && (memAddr & 3) == 0 && (cacheAddr & 3) == 0)
{
memcpy(dst, src, 32 * _iNumBlocks);
memcpy(dst, src, 32 * numBlocks);
}
else
{
for (u32 i = 0; i < 32 * _iNumBlocks; i++)
for (u32 i = 0; i < 32 * numBlocks; i++)
{
u8 Temp = Read_U8(_MemAddr + i);
Write_U8(Temp, _CacheAddr + i);
u8 Temp = Read_U8(memAddr + i);
Write_U8(Temp, cacheAddr + i);
}
}
}
@@ -301,16 +301,16 @@ std::string GetString(u32 em_address, size_t size)
// GetPointer must always return an address in the bottom 32 bits of address space, so that 64-bit
// programs don't have problems directly addressing any part of memory.
// TODO re-think with respect to other BAT setups...
u8* GetPointer(const u32 _Address)
u8* GetPointer(const u32 address)
{
switch (_Address >> 28)
switch (address >> 28)
{
case 0x0:
case 0x8:
if ((_Address & 0xfffffff) < REALRAM_SIZE)
return m_pRAM + (_Address & RAM_MASK);
if ((address & 0xfffffff) < REALRAM_SIZE)
return m_pRAM + (address & RAM_MASK);
case 0xc:
switch (_Address >> 24)
switch (address >> 24)
{
case 0xcc:
case 0xcd:
@@ -320,62 +320,62 @@ u8* GetPointer(const u32 _Address)
break;

default:
if ((_Address & 0xfffffff) < REALRAM_SIZE)
return m_pRAM + (_Address & RAM_MASK);
if ((address & 0xfffffff) < REALRAM_SIZE)
return m_pRAM + (address & RAM_MASK);
}

case 0x1:
case 0x9:
case 0xd:
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii)
{
if ((_Address & 0xfffffff) < EXRAM_SIZE)
return m_pEXRAM + (_Address & EXRAM_MASK);
if ((address & 0xfffffff) < EXRAM_SIZE)
return m_pEXRAM + (address & EXRAM_MASK);
}
else
break;

case 0xe:
if (_Address < (0xE0000000 + L1_CACHE_SIZE))
return m_pL1Cache + (_Address & L1_CACHE_MASK);
if (address < (0xE0000000 + L1_CACHE_SIZE))
return m_pL1Cache + (address & L1_CACHE_MASK);
else
break;

default:
if (bFakeVMEM)
return m_pFakeVMEM + (_Address & FAKEVMEM_MASK);
return m_pFakeVMEM + (address & FAKEVMEM_MASK);
}

ERROR_LOG(MEMMAP, "Unknown Pointer %#8x PC %#8x LR %#8x", _Address, PC, LR);
ERROR_LOG(MEMMAP, "Unknown Pointer %#8x PC %#8x LR %#8x", address, PC, LR);

return nullptr;
}

bool IsRAMAddress(const u32 addr, bool allow_locked_cache, bool allow_fake_vmem)
bool IsRAMAddress(const u32 address, bool allow_locked_cache, bool allow_fake_vmem)
{
switch ((addr >> 24) & 0xFC)
switch ((address >> 24) & 0xFC)
{
case 0x00:
case 0x80:
case 0xC0:
if ((addr & 0x1FFFFFFF) < RAM_SIZE)
if ((address & 0x1FFFFFFF) < RAM_SIZE)
return true;
else
return false;
case 0x10:
case 0x90:
case 0xD0:
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii && (addr & 0x0FFFFFFF) < EXRAM_SIZE)
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii && (address & 0x0FFFFFFF) < EXRAM_SIZE)
return true;
else
return false;
case 0xE0:
if (allow_locked_cache && addr - 0xE0000000 < L1_CACHE_SIZE)
if (allow_locked_cache && address - 0xE0000000 < L1_CACHE_SIZE)
return true;
else
return false;
case 0x7C:
if (allow_fake_vmem && bFakeVMEM && addr >= 0x7E000000)
if (allow_fake_vmem && bFakeVMEM && address >= 0x7E000000)
return true;
else
return false;
@@ -74,64 +74,57 @@ void Clear();
bool AreMemoryBreakpointsActivated();

// ONLY for use by GUI
u8 ReadUnchecked_U8(const u32 _Address);
u32 ReadUnchecked_U32(const u32 _Address);
u8 ReadUnchecked_U8(const u32 address);
u32 ReadUnchecked_U32(const u32 address);

void WriteUnchecked_U8(const u8 _Data, const u32 _Address);
void WriteUnchecked_U32(const u32 _Data, const u32 _Address);
void WriteUnchecked_U8(const u8 var, const u32 address);
void WriteUnchecked_U32(const u32 var, const u32 address);

bool IsRAMAddress(const u32 addr, bool allow_locked_cache = false, bool allow_fake_vmem = false);
bool IsRAMAddress(const u32 address, bool allow_locked_cache = false, bool allow_fake_vmem = false);

// used by interpreter to read instructions, uses iCache
u32 Read_Opcode(const u32 _Address);
u32 Read_Opcode(const u32 address);
// this is used by Debugger a lot.
// For now, just reads from memory!
u32 Read_Instruction(const u32 _Address);
u32 Read_Instruction(const u32 address);


// For use by emulator

u8 Read_U8(const u32 _Address);
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);
u8 Read_U8(const u32 address);
u16 Read_U16(const u32 address);
u32 Read_U32(const u32 address);
u64 Read_U64(const u32 address);

// Useful helper functions, used by ARM JIT
float Read_F32(const u32 _Address);
double Read_F64(const u32 _Address);
float Read_F32(const u32 address);
double Read_F64(const u32 address);

// used by JIT. Return zero-extended 32bit values
u32 Read_U8_ZX(const u32 _Address);
u32 Read_U16_ZX(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);

u8* GetPointer(const u32 _Address);
void DMA_LCToMemory(const u32 _iMemAddr, const u32 _iCacheAddr, const u32 _iNumBlocks);
void DMA_MemoryToLC(const u32 _iCacheAddr, const u32 _iMemAddr, const u32 _iNumBlocks);
u8* GetPointer(const u32 address);
void DMA_LCToMemory(const u32 memAddr, const u32 cacheAddr, const u32 numBlocks);
void DMA_MemoryToLC(const u32 cacheAddr, const u32 memAddr, const u32 numBlocks);
void CopyFromEmu(void* data, u32 address, size_t size);
void CopyToEmu(u32 address, const void* data, size_t size);
void Memset(const u32 _Address, const u8 _Data, const u32 _iLength);
void ClearCacheLine(const u32 _Address); // Zeroes 32 bytes; address should be 32-byte-aligned
void Memset(const u32 address, const u8 var, const u32 length);
void ClearCacheLine(const u32 address); // Zeroes 32 bytes; address should be 32-byte-aligned

// TLB functions
void SDRUpdated();
@@ -142,8 +135,8 @@ enum XCheckTLBFlag
FLAG_WRITE,
FLAG_OPCODE,
};
u32 TranslateAddress(u32 _Address, XCheckTLBFlag _Flag);
void InvalidateTLBEntry(u32 _Address);
template <const XCheckTLBFlag flag> u32 TranslateAddress(const u32 address);
void InvalidateTLBEntry(u32 address);
extern u32 pagetable_base;
extern u32 pagetable_hashmask;
}
Oops, something went wrong.

2 comments on commit 89b7f10

@Mullin

This comment has been minimized.

Copy link
Contributor

Mullin replied Jan 7, 2015

Break emulation on Android + warning

@heinermann

This comment has been minimized.

Copy link

heinermann replied Mar 6, 2015

Confirmed caused Android builds to fail on Nexus 5 and Kindle Fire HDX devices.
https://buildbot.dolphin-emu.org/builders/release-android/builds/156

Is there a followup commit anywhere? I can't find a working build after this point.

Please sign in to comment.
You can’t perform that action at this time.