From 2d0f714546cba64ec9191c4e3e0b60351ad3e539 Mon Sep 17 00:00:00 2001 From: hrydgard Date: Sat, 7 Nov 2009 18:53:10 +0000 Subject: [PATCH] Rewrite memory management, _hopefully_ banishing "failed to map 1 gb contiguous memory" 32-bit Dolphin errors to history. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@4505 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/Common/Src/MemArena.cpp | 161 +++++++++++++++- Source/Core/Common/Src/MemArena.h | 20 ++ Source/Core/Core/Src/HW/Memmap.cpp | 273 ++++++++-------------------- Source/Core/Core/Src/HW/Memmap.h | 211 ++++++++++----------- 4 files changed, 354 insertions(+), 311 deletions(-) diff --git a/Source/Core/Common/Src/MemArena.cpp b/Source/Core/Common/Src/MemArena.cpp index fb9e6e03af..064863e15e 100644 --- a/Source/Core/Common/Src/MemArena.cpp +++ b/Source/Core/Common/Src/MemArena.cpp @@ -66,7 +66,6 @@ void* MemArena::CreateView(s64 offset, size_t size, bool ensure_low_mem) { #ifdef _WIN32 return MapViewOfFile(hMemoryMapping, FILE_MAP_ALL_ACCESS, 0, (DWORD)((u64)offset), size); - #else void* ptr = mmap(0, size, PROT_READ | PROT_WRITE, @@ -75,15 +74,8 @@ void* MemArena::CreateView(s64 offset, size_t size, bool ensure_low_mem) | (ensure_low_mem ? MAP_32BIT : 0) #endif , fd, offset); - - if (!ptr) - { - PanicAlert("Failed to create view"); - } - - return(ptr); + return ptr; #endif - } @@ -141,3 +133,154 @@ u8* MemArena::Find4GBBase() #endif #endif } + + +// yeah, this could also be done in like two bitwise ops... +#define SKIP(a_flags, b_flags) \ + if (!(a_flags & MV_WII_ONLY) && (b_flags & MV_WII_ONLY)) \ + continue; \ + if (!(a_flags & MV_FAKE_VMEM) && (b_flags & MV_FAKE_VMEM)) \ + continue; \ + + +static bool Memory_TryBase(u8 *base, const MemoryView *views, int num_views, u32 flags, MemArena *arena) { + // OK, we know where to find free space. Now grab it! + // We just mimic the popular BAT setup. + u32 position = 0; + u32 last_position = 0; + + // Zero all the pointers to be sure. + for (int i = 0; i < num_views; i++) + { + if (views[i].out_ptr_low) + *views[i].out_ptr_low = 0; + if (views[i].out_ptr) + *views[i].out_ptr = 0; + } + + int i; + for (i = 0; i < num_views; i++) + { + SKIP(flags, views[i].flags); + if (views[i].flags & MV_MIRROR_PREVIOUS) { + position = last_position; + } else { + *(views[i].out_ptr_low) = (u8*)arena->CreateView(position, views[i].size); + if (!*views[i].out_ptr_low) + goto bail; + } +#ifdef _M_X64 + *views[i].out_ptr = (u8*)arena->CreateViewAt( + position, views[i].size, base + views[i].virtual_address); +#else + if (views[i].flags & MV_MIRROR_PREVIOUS) { + // No need to create multiple identical views. + *views[i].out_ptr = *views[i - 1].out_ptr; + } else { + *views[i].out_ptr = (u8*)arena->CreateViewAt( + position, views[i].size, base + (views[i].virtual_address & 0x3FFFFFFF)); + if (!*views[i].out_ptr) + goto bail; + } +#endif + last_position = position; + position += views[i].size; + } + + return true; + +bail: + // Argh! ERROR! Free what we grabbed so far so we can try again. + for (int j = 0; j <= i; j++) + { + if (views[j].out_ptr_low && *views[j].out_ptr_low) + { + arena->ReleaseView(*views[j].out_ptr_low, views[j].size); + *views[j].out_ptr_low = NULL; + } + if (*views[j].out_ptr) + { +#ifdef _M_X64 + arena->ReleaseView(*views[j].out_ptr, views[j].size); +#else + if (!(views[j].flags & MV_MIRROR_PREVIOUS)) + { + arena->ReleaseView(*views[j].out_ptr, views[j].size); + } +#endif + *views[j].out_ptr = NULL; + } + } + return false; +} + +u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena *arena) +{ + u32 total_mem = 0; + for (int i = 0; i < num_views; i++) + { + SKIP(flags, views[i].flags); + if ((views[i].flags & MV_MIRROR_PREVIOUS) == 0) + total_mem += views[i].size; + } + // Grab some pagefile backed memory out of the void ... + arena->GrabLowMemSpace(total_mem); + + // Now, create views in high memory where there's plenty of space. +#ifdef _M_X64 + u8 *base = MemArena::Find4GBBase(); + // This really shouldn't fail - in 64-bit, there will always be enough + // address space. + if (!Memory_TryBase(base, views, num_views, flags, arena)) + { + PanicAlert("MemoryMap_Setup: Failed finding a memory base."); + exit(0); + return 0; + } +#else +#ifdef _WIN32 + // Try a whole range of possible bases. Return once we got a valid one. + u32 max_base_addr = 0x7FFF0000 - 0x31000000; + u8 *base = NULL; + int base_attempts = 1; + for (u32 base_addr = 0; base_addr < max_base_addr; base_addr += 0x40000) + { + base = (u8 *)base_addr; + if (Memory_TryBase(base, views, num_views, flags, arena)) + { + INFO_LOG(MEMMAP, "Found valid memory base at %p after %i tries.", base, base_attempts); + break; + } + base_attempts++; + } +#else + // Linux32 is fine with the x64 method, although limited to 32-bit with no automirrors. + u8 *base = MemArena::Find4GBBase(); + if (!Memory_TryBase(base, views, num_views, flags, arena)) + { + PanicAlert("MemoryMap_Setup: Failed finding a memory base."); + exit(0); + return 0; + } +#endif + +#endif + if (!base) + PanicAlert("No possible memory base pointer found!"); + return base; +} + +void MemoryMap_Shutdown(const MemoryView *views, int num_views, u32 flags, MemArena *arena) +{ + for (int i = 0; i < num_views; i++) + { + SKIP(flags, views[i].flags); + if (views[i].out_ptr_low && *views[i].out_ptr_low) + arena->ReleaseView(*views[i].out_ptr_low, views[i].size); + if (*views[i].out_ptr && (views[i].out_ptr_low && *views[i].out_ptr != *views[i].out_ptr_low)) + arena->ReleaseView(*views[i].out_ptr, views[i].size); + *views[i].out_ptr = NULL; + if (views[i].out_ptr_low) + *views[i].out_ptr_low = NULL; + } +} \ No newline at end of file diff --git a/Source/Core/Common/Src/MemArena.h b/Source/Core/Common/Src/MemArena.h index bdc3b9bc4c..be0f86de75 100644 --- a/Source/Core/Common/Src/MemArena.h +++ b/Source/Core/Common/Src/MemArena.h @@ -49,4 +49,24 @@ private: #endif }; +enum { + MV_MIRROR_PREVIOUS = 1, + MV_FAKE_VMEM = 2, + MV_WII_ONLY = 4, +}; + +struct MemoryView +{ + u8 **out_ptr_low; + u8 **out_ptr; + u32 virtual_address; + u32 size; + u32 flags; +}; + +// Uses a memory arena to set up an emulator-friendly memory map according to +// a passed-in list of MemoryView structures. +u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena *arena); +void MemoryMap_Shutdown(const MemoryView *views, int num_views, u32 flags, MemArena *arena); + #endif // _MEMARENA_H_ diff --git a/Source/Core/Core/Src/HW/Memmap.cpp b/Source/Core/Core/Src/HW/Memmap.cpp index f1b063d556..5114d315d0 100644 --- a/Source/Core/Core/Src/HW/Memmap.cpp +++ b/Source/Core/Core/Src/HW/Memmap.cpp @@ -78,24 +78,27 @@ MemArena g_arena; // STATE_TO_SAVE (applies to a lot of things in this file) -// Pointers to low memory -u8* m_pRAM = NULL; -u8* m_pFakeVMEM = NULL; -u8* m_pEXRAM = NULL; //wii -u8* m_pEFB = NULL; -u8* m_pL1Cache = NULL; bool m_IsInitialized = false; // Save the Init(), Shutdown() state -// Pointers into the "View" (rarely used) -u8* m_pPhysicalFakeVMEM; -u8* m_pPhysicalRAM; -u8* m_pPhysicalEXRAM; //wii -u8* m_pVirtualCachedRAM; -u8* m_pVirtualUncachedRAM; -u8* m_pVirtualCachedEXRAM; -u8* m_pVirtualUncachedEXRAM; -u8* m_pVirtualEFB; -u8* m_pVirtualL1Cache; +// 64-bit: Pointers to low-mem (sub-0x10000000) mirror +// 32-bit: Same as the corresponding physical/virtual pointers. +u8 *m_pRAM; +u8 *m_pEFB; +u8 *m_pL1Cache; +u8 *m_pEXRAM; +u8 *m_pFakeVMEM; + +// 64-bit: Pointers to high-mem mirrors +// 32-bit: Same as above +u8 *m_pPhysicalRAM; +u8 *m_pVirtualCachedRAM; +u8 *m_pVirtualUncachedRAM; +u8 *m_pPhysicalEXRAM; // wii only +u8 *m_pVirtualCachedEXRAM; // wii only +u8 *m_pVirtualUncachedEXRAM; // wii only +u8 *m_pVirtualEFB; +u8 *m_pVirtualL1Cache; +u8 *m_pVirtualFakeVMEM; // ================================= // Read and write shortcuts @@ -119,36 +122,29 @@ readFn8 hwReadWii8 [NUMHWMEMFUN]; readFn16 hwReadWii16[NUMHWMEMFUN]; readFn32 hwReadWii32[NUMHWMEMFUN]; readFn64 hwReadWii64[NUMHWMEMFUN]; -// =============== - - - - // Default read and write functions -// ---------------- -u32 CheckDTLB(u32 _Address, XCheckTLBFlag _Flag); - template void HW_Default_Write(const T _Data, const u32 _Address){ ERROR_LOG(MASTER_LOG, "Illegal HW Write%i %08x", sizeof(T)*8, _Address);_dbg_assert_(MEMMAP, 0);} template void HW_Default_Read(T _Data, const u32 _Address){ ERROR_LOG(MASTER_LOG, "Illegal HW Read%i %08x", sizeof(T)*8, _Address); _dbg_assert_(MEMMAP, 0);} +u32 CheckDTLB(u32 _Address, XCheckTLBFlag _Flag); #define PAGE_SHIFT 10 #define PAGE_SIZE (1 << PAGE_SHIFT) #define PAGE_MASK (PAGE_SHIFT - 1) -template void HW_Read_Memory(T &_Data, const u32 _Address) { _Data = *(T*)&P[_Address & PAGE_MASK]; } -template void HW_Write_Memory(T _Data, const u32 _Address) { *(T*)&P[_Address & PAGE_MASK] = _Data; } +template void HW_Read_Memory(T &_Data, const u32 _Address) { + _Data = *(T *)&P[_Address & PAGE_MASK]; +} +template void HW_Write_Memory(T _Data, const u32 _Address) { + *(T *)&P[_Address & PAGE_MASK] = _Data; +} - - - -/* Create shortcuts to the hardware devices' read and write functions. This can be seen - as an alternative to a switch() or if() table. */ -// ---------------- +// Create shortcuts to the hardware devices' read and write functions. +// This can be seen as an alternative to a switch() or if() table. #define BLOCKSIZE 4 #define CP_START 0x00 //0x0000 >> 10 #define WII_IPC_START 0x00 //0x0000 >> 10 @@ -163,7 +159,6 @@ template void HW_Write_Memory(T _Data, const u32 _Address) { *( #define AUDIO_START 0x1B //0x6C00 >> 10 #define GP_START 0x20 //0x8000 >> 10 - void InitHWMemFuncs() { for (int i = 0; i < NUMHWMEMFUN; i++) @@ -177,7 +172,8 @@ void InitHWMemFuncs() hwRead32 [i] = HW_Default_Read; hwRead64 [i] = HW_Default_Read; - // To prevent Dolphin from crashing when running Wii executables in Gc mode. + // To prevent Dolphin from crashing when accidentally running Wii + // executables in GC mode (or running malicious GC executables...) hwWriteWii8 [i] = HW_Default_Write; hwWriteWii16[i] = HW_Default_Write; hwWriteWii32[i] = HW_Default_Write; @@ -327,114 +323,39 @@ writeFn32 GetHWWriteFun32(const u32 _Address) return hwWrite32[(_Address >> HWSHIFT) & (NUMHWMEMFUN-1)]; } - - - - -// Init and Shutdown -// ---------------- bool IsInitialized() { return m_IsInitialized; } +// We don't declare the IO region in here since its handled by other means. +static const MemoryView views[] = +{ + {&m_pRAM, &m_pPhysicalRAM, 0x00000000, RAM_SIZE, 0}, + {NULL, &m_pVirtualCachedRAM, 0x80000000, RAM_SIZE, MV_MIRROR_PREVIOUS}, + {NULL, &m_pVirtualUncachedRAM, 0xC0000000, RAM_SIZE, MV_MIRROR_PREVIOUS}, + + {&m_pEFB, &m_pVirtualEFB, 0xC8000000, EFB_SIZE, 0}, + {&m_pL1Cache, &m_pVirtualL1Cache, 0xE0000000, L1_CACHE_SIZE, 0}, + + {&m_pFakeVMEM, &m_pVirtualFakeVMEM, 0x7E000000, FAKEVMEM_SIZE, MV_FAKE_VMEM}, + + {&m_pEXRAM, &m_pPhysicalEXRAM, 0x10000000, EXRAM_SIZE, MV_WII_ONLY}, + {NULL, &m_pVirtualCachedEXRAM, 0x90000000, EXRAM_SIZE, MV_WII_ONLY | MV_MIRROR_PREVIOUS}, + {NULL, &m_pVirtualUncachedEXRAM, 0xD0000000, EXRAM_SIZE, MV_WII_ONLY | MV_MIRROR_PREVIOUS}, +}; +static const int num_views = sizeof(views) / sizeof(MemoryView); + bool Init() { bool wii = Core::GetStartupParameter().bWii; bFakeVMEM = Core::GetStartupParameter().iTLBHack == 1; - int totalMemSize = RAM_SIZE + EFB_SIZE + L1_CACHE_SIZE + IO_SIZE; - if (bFakeVMEM) - totalMemSize += FAKEVMEM_SIZE; - if (wii) - totalMemSize += EXRAM_SIZE; - - //Grab some pagefile backed memory out of the void ... - g_arena.GrabLowMemSpace(totalMemSize); - - //First, map in our regular pointers - int position = 0; - m_pRAM = (u8*)g_arena.CreateView(position, RAM_SIZE); - position += RAM_SIZE; - m_pEFB = (u8*)g_arena.CreateView(position, EFB_SIZE); - position += EFB_SIZE; - m_pL1Cache = (u8*)g_arena.CreateView(position, L1_CACHE_SIZE); - position += L1_CACHE_SIZE; - if (bFakeVMEM) - { - m_pFakeVMEM = (u8*)g_arena.CreateView(position, FAKEVMEM_SIZE); - position += FAKEVMEM_SIZE; - } - - if (wii) - m_pEXRAM = (u8*)g_arena.CreateView(position, EXRAM_SIZE); - -#ifdef _M_X64 - //Then, in x64 mode where we have space, grab a 4GB virtual address space - base = MemArena::Find4GBBase(); - //OK, we know where to find free space. Now grab it! - - //Physical should be unmapped when not in "real mode" - //All in all, we should obey IBAT and DBAT. Maybe IBAT and DBAT should have a 4GB space each? - //It's not like 4GB is anything these days... - position = 0; - m_pPhysicalRAM = (u8*)g_arena.CreateViewAt(position, RAM_SIZE, base + 0x00000000); - m_pVirtualCachedRAM = (u8*)g_arena.CreateViewAt(position, RAM_SIZE, base + 0x80000000); - m_pVirtualUncachedRAM = (u8*)g_arena.CreateViewAt(position, RAM_SIZE, base + 0xC0000000); - position += RAM_SIZE; - m_pVirtualEFB = (u8*)g_arena.CreateViewAt(position, EFB_SIZE, base + 0xC8000000); - position += EFB_SIZE; - m_pVirtualL1Cache = (u8*)g_arena.CreateViewAt(position, L1_CACHE_SIZE, base + 0xE0000000); - position += L1_CACHE_SIZE; - if (bFakeVMEM) { - m_pPhysicalFakeVMEM = (u8*)g_arena.CreateViewAt(position, FAKEVMEM_SIZE, base + 0x7E000000); - position += FAKEVMEM_SIZE; - } - - if (wii) - { - m_pPhysicalEXRAM = (u8*)g_arena.CreateViewAt(position, EXRAM_SIZE, base + 0x10000000); - m_pVirtualCachedEXRAM = (u8*)g_arena.CreateViewAt(position, EXRAM_SIZE, base + 0x90000000); - m_pVirtualUncachedEXRAM = (u8*)g_arena.CreateViewAt(position, EXRAM_SIZE, base + 0xD0000000); - } -#else - // Do a poor mans version - just grab 1GB, possibly discontiguous, and use &0x3FFFFFFF as the mask whenever it is accessed. - base = MemArena::Find4GBBase(); - if (!base) { - PanicAlert("Failed to grab 1 GB of contiguous memory!\nDo you have an antivirus program or any other program\n" - "that injects itself into every process, consuming address space?\nOr simply a bad graphics driver?\n\n" - "Dolphin will handle this better in the future by falling back to slow memory emulation.\n" - "For now, sorry, but it won't work. Try the 64-bit build if you can."); - } - position = 0; - m_pPhysicalRAM = (u8*)g_arena.CreateViewAt(position, RAM_SIZE, base + (0x00000000 & MEMVIEW32_MASK)); - m_pVirtualCachedRAM = m_pPhysicalRAM; - m_pVirtualUncachedRAM = m_pPhysicalRAM; - position += RAM_SIZE; - m_pVirtualEFB = (u8*)g_arena.CreateViewAt(position, EFB_SIZE, base + (0xC8000000 & MEMVIEW32_MASK)); - position += EFB_SIZE; - m_pVirtualL1Cache = (u8*)g_arena.CreateViewAt(position, L1_CACHE_SIZE, base + (0xE0000000 & MEMVIEW32_MASK)); - position += L1_CACHE_SIZE; - if (bFakeVMEM) { - m_pPhysicalFakeVMEM = (u8*)g_arena.CreateViewAt(position, FAKEVMEM_SIZE, base + (0x7E000000 & MEMVIEW32_MASK)); - position += FAKEVMEM_SIZE; - } - //WriteProtectMemory(base + 24*1024*1024, 8*1024*1024); - if (wii) - { - m_pPhysicalEXRAM = (u8*)g_arena.CreateViewAt(position, EXRAM_SIZE, base + (0x10000000 & MEMVIEW32_MASK)); - m_pVirtualCachedEXRAM = m_pPhysicalEXRAM; - m_pVirtualUncachedEXRAM = m_pPhysicalEXRAM; - } -#endif - - memset(m_pRAM, 0, RAM_SIZE); - if (wii) { - memset(m_pPhysicalEXRAM, 0, EXRAM_SIZE); - } - memset(m_pEFB, 0, EFB_SIZE); - memset(m_pL1Cache, 0, L1_CACHE_SIZE); + u32 flags = 0; + if (wii) flags |= MV_WII_ONLY; + if (bFakeVMEM) flags |= MV_FAKE_VMEM; + base = MemoryMap_Setup(views, num_views, flags, &g_arena); if (wii) InitHWMemFuncsWii(); @@ -450,9 +371,9 @@ bool Init() void DoState(PointerWrap &p) { bool wii = Core::GetStartupParameter().bWii; - p.DoArray(m_pRAM, RAM_SIZE); - p.DoArray(m_pEFB, EFB_SIZE); - p.DoArray(m_pL1Cache, L1_CACHE_SIZE); + p.DoArray(m_pPhysicalRAM, RAM_SIZE); + p.DoArray(m_pVirtualEFB, EFB_SIZE); + p.DoArray(m_pVirtualL1Cache, L1_CACHE_SIZE); if (wii) p.DoArray(m_pEXRAM, EXRAM_SIZE); } @@ -460,48 +381,16 @@ void DoState(PointerWrap &p) bool Shutdown() { m_IsInitialized = false; - bool wii = Core::GetStartupParameter().bWii; - - g_arena.ReleaseView(m_pRAM, RAM_SIZE); - g_arena.ReleaseView(m_pEFB, EFB_SIZE); - g_arena.ReleaseView(m_pL1Cache, L1_CACHE_SIZE); - if (wii) { - g_arena.ReleaseView(m_pEXRAM, EXRAM_SIZE); - } - if (bFakeVMEM) { - g_arena.ReleaseView(m_pFakeVMEM, FAKEVMEM_SIZE); - } - -#ifdef _M_X64 - g_arena.ReleaseView(m_pPhysicalRAM, RAM_SIZE); - g_arena.ReleaseView(m_pVirtualCachedRAM, RAM_SIZE); - g_arena.ReleaseView(m_pVirtualUncachedRAM, RAM_SIZE); - g_arena.ReleaseView(m_pVirtualEFB, EFB_SIZE); - g_arena.ReleaseView(m_pVirtualL1Cache, L1_CACHE_SIZE); - if (wii) - { - g_arena.ReleaseView(m_pPhysicalEXRAM, EXRAM_SIZE); - g_arena.ReleaseView(m_pVirtualCachedEXRAM, EXRAM_SIZE); - g_arena.ReleaseView(m_pVirtualUncachedEXRAM, EXRAM_SIZE); - } - if (bFakeVMEM) { - g_arena.ReleaseView(m_pPhysicalFakeVMEM, FAKEVMEM_SIZE); - } -#else - g_arena.ReleaseView(m_pPhysicalRAM, RAM_SIZE); - g_arena.ReleaseView(m_pVirtualEFB, EFB_SIZE); - g_arena.ReleaseView(m_pVirtualL1Cache, L1_CACHE_SIZE); - if (wii) - g_arena.ReleaseView(m_pPhysicalEXRAM, EXRAM_SIZE); - if (bFakeVMEM) - g_arena.ReleaseView(m_pPhysicalFakeVMEM, FAKEVMEM_SIZE); -#endif + u32 flags = 0; + if (Core::GetStartupParameter().bWii) flags |= MV_WII_ONLY; + if (bFakeVMEM) flags |= MV_FAKE_VMEM; + MemoryMap_Shutdown(views, num_views, flags, &g_arena); g_arena.ReleaseSpace(); + base = NULL; INFO_LOG(MEMMAP, "Memory system shut down."); return true; } - void Clear() { if (m_pRAM) @@ -514,7 +403,6 @@ void Clear() memset(m_pEXRAM, 0, EXRAM_SIZE); } - bool AreMemoryBreakpointsActivated() { #ifndef ENABLE_MEM_CHECK @@ -524,7 +412,6 @@ bool AreMemoryBreakpointsActivated() #endif } - u32 Read_Instruction(const u32 em_address) { UGeckoInstruction inst = ReadUnchecked_U32(em_address); @@ -781,21 +668,12 @@ void CheckForBadAddresses32(u32 Address, u32 Data, bool Read) void CheckForBadAddresses64(u32 Address, u64 Data, bool Read) {CheckForBadAddresses(Address, (u32)Data, Read, 64);} -// ============= - - - - - -// Other functions -// ---------------- void WriteBigEData(const u8 *_pData, const u32 _Address, const u32 _iSize) { memcpy(GetPointer(_Address), _pData, _iSize); } - void Memset(const u32 _Address, const u8 _iValue, const u32 _iLength) { u8 *ptr = GetPointer(_Address); @@ -813,13 +691,12 @@ void Memset(const u32 _Address, const u8 _iValue, const u32 _iLength) } } - void DMA_LCToMemory(const u32 _MemAddr, const u32 _CacheAddr, const u32 _iNumBlocks) { - u8 *src = GetCachePtr() + (_CacheAddr & 0x3FFFF); + const u8 *src = GetCachePtr() + (_CacheAddr & 0x3FFFF); u8 *dst = GetPointer(_MemAddr); - if ((dst != NULL) && (src != NULL)) + if ((dst != NULL) && (src != NULL) && (_MemAddr & 3) == 0 && (_CacheAddr & 3) == 0) { memcpy(dst, src, 32 * _iNumBlocks); } @@ -833,13 +710,12 @@ void DMA_LCToMemory(const u32 _MemAddr, const u32 _CacheAddr, const u32 _iNumBlo } } - void DMA_MemoryToLC(const u32 _CacheAddr, const u32 _MemAddr, const u32 _iNumBlocks) { - u8 *src = GetPointer(_MemAddr); + const u8 *src = GetPointer(_MemAddr); u8 *dst = GetCachePtr() + (_CacheAddr & 0x3FFFF); - if ((dst != NULL) && (src != NULL)) + if ((dst != NULL) && (src != NULL) && (_MemAddr & 3) == 0 && (_CacheAddr & 3) == 0) { memcpy(dst, src, 32 * _iNumBlocks); } @@ -853,27 +729,24 @@ void DMA_MemoryToLC(const u32 _CacheAddr, const u32 _MemAddr, const u32 _iNumBlo } } - -void ReadBigEData( u8 *_pData, const u32 _Address, const u32 size) +void ReadBigEData(u8 *data, const u32 em_address, const u32 size) { - u8 *src = GetPointer(_Address); - memcpy(_pData, src, size); + u8 *src = GetPointer(em_address); + memcpy(data, src, size); } - -void GetString(std::string& _string, const u32 _Address) +void GetString(std::string& _string, const u32 em_address) { char stringBuffer[2048]; char *string = stringBuffer; char c; - int addr = _Address; + u32 addr = em_address; while ((c = Read_U8(addr))) { *string++ = c; addr++; } - *string++=0; - + *string++ = '\0'; _string = stringBuffer; } @@ -890,7 +763,7 @@ u8 *GetPointer(const u32 _Address) case 0x81: case 0xC0: case 0xC1: - return (u8*)(((char*)m_pRAM) + (_Address & RAM_MASK)); + return (u8*)(((char*)m_pPhysicalRAM) + (_Address & RAM_MASK)); case 0x10: case 0x11: @@ -905,13 +778,13 @@ u8 *GetPointer(const u32 _Address) case 0xD2: case 0xD3: if (Core::GetStartupParameter().bWii) - return (u8*)(((char*)m_pEXRAM) + (_Address & EXRAM_MASK)); + return (u8*)(((char*)m_pPhysicalEXRAM) + (_Address & EXRAM_MASK)); else return 0; case 0x7E: case 0x7F: - return (u8*)(((char*)m_pFakeVMEM) + (_Address & RAM_MASK)); + return (u8*)(((char*)m_pVirtualFakeVMEM) + (_Address & RAM_MASK)); case 0xE0: if (_Address < (0xE0000000 + L1_CACHE_SIZE)) diff --git a/Source/Core/Core/Src/HW/Memmap.h b/Source/Core/Core/Src/HW/Memmap.h index 703fd6c399..bed6602104 100644 --- a/Source/Core/Core/Src/HW/Memmap.h +++ b/Source/Core/Core/Src/HW/Memmap.h @@ -42,122 +42,129 @@ typedef void (*readFn64)(u64&, const u32); namespace Memory { - /* Base is a pointer to the base of the memory map. Yes, some MMU tricks - are used to set up a full GC or Wii memory map in process memory. on - 32-bit, you have to mask your offsets with 0x3FFFFFFF. This means that - some things are mirrored, but eh... it works. */ +// Base is a pointer to the base of the memory map. Yes, some MMU tricks +// are used to set up a full GC or Wii memory map in process memory. on +// 32-bit, you have to mask your offsets with 0x3FFFFFFF. This means that +// some things are mirrored too many times, but eh... it works. - extern u8 *base; - extern u8* m_pRAM; - extern u8* m_pL1Cache; +// In 64-bit, this might point to "high memory" (above the 32-bit limit), +// so be sure to load it into a 64-bit register. +extern u8 *base; - // The size should be 24mb only, but the RAM_MASK wouldn't work anymore - enum - { - RAM_SIZE = 0x2000000, - RAM_MASK = 0x1FFFFFF, - FAKEVMEM_SIZE = 0x2000000, - FAKEVMEM_MASK = 0x1FFFFFF, - REALRAM_SIZE = 0x1800000, - L1_CACHE_SIZE = 0x40000, - L1_CACHE_MASK = 0x3FFFF, - EFB_SIZE = 0x200000, - EFB_MASK = 0x1FFFFF, - IO_SIZE = 0x10000, - EXRAM_SIZE = 0x4000000, - EXRAM_MASK = 0x3FFFFFF, - #ifdef _M_IX86 - MEMVIEW32_MASK = 0x3FFFFFFF, - #endif - }; +// These are guarenteed to point to "low memory" addresses (sub-32-bit). +extern u8 *m_pRAM; +extern u8 *m_pL1Cache; - // Init and Shutdown - bool IsInitialized(); - bool Init(); - bool Shutdown(); - void DoState(PointerWrap &p); - - void Clear(); - bool AreMemoryBreakpointsActivated(); - - // ONLY for use by GUI - 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 InitHWMemFuncs(); - void InitHWMemFuncsWii(); - - bool IsRAMAddress(const u32 addr, bool allow_locked_cache = false); - writeFn32 GetHWWriteFun32(const u32 _Address); - - inline u8* GetCachePtr() {return m_pL1Cache;} - inline u8* GetMainRAMPtr() {return m_pRAM;} - inline u32 ReadFast32(const u32 _Address) - { +enum +{ + // The size should be just 24MB instead of 32, but the RAM_MASK wouldn't + // work. + RAM_SIZE = 0x2000000, + RAM_MASK = 0x1FFFFFF, + FAKEVMEM_SIZE = 0x2000000, + FAKEVMEM_MASK = 0x1FFFFFF, + REALRAM_SIZE = 0x1800000, + L1_CACHE_SIZE = 0x40000, + L1_CACHE_MASK = 0x3FFFF, + EFB_SIZE = 0x200000, + EFB_MASK = 0x1FFFFF, + IO_SIZE = 0x10000, + EXRAM_SIZE = 0x4000000, + EXRAM_MASK = 0x3FFFFFF, #ifdef _M_IX86 - return Common::swap32(*(u32 *)(base + (_Address & MEMVIEW32_MASK))); // ReadUnchecked_U32(_Address); - #elif defined(_M_X64) - return Common::swap32(*(u32 *)(base + _Address)); + MEMVIEW32_MASK = 0x3FFFFFFF, #endif - } +}; - // used by interpreter to read instructions, uses iCache - u32 Read_Opcode(const u32 _Address); - // used by JIT to read instructions, uses iCacheJIT - u32 Read_Opcode_JIT(const u32 _Address); - // used by JIT. uses iCacheJIT. Reads in the "Locked cache" mode - u32 Read_Opcode_JIT_LC(const u32 _Address); - void Write_Opcode_JIT(const u32 _Address, const u32 _Value); - // this is used by Debugger a lot. - // For now, just reads from memory! - u32 Read_Instruction(const u32 _Address); +// Init and Shutdown +bool IsInitialized(); +bool Init(); +bool Shutdown(); +void DoState(PointerWrap &p); + +void Clear(); +bool AreMemoryBreakpointsActivated(); + +// ONLY for use by GUI +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 InitHWMemFuncs(); +void InitHWMemFuncsWii(); + +bool IsRAMAddress(const u32 addr, bool allow_locked_cache = false); +writeFn32 GetHWWriteFun32(const u32 _Address); + +inline u8* GetCachePtr() {return m_pL1Cache;} +inline u8* GetMainRAMPtr() {return m_pRAM;} +inline u32 ReadFast32(const u32 _Address) +{ +#ifdef _M_IX86 + return Common::swap32(*(u32 *)(base + (_Address & MEMVIEW32_MASK))); // ReadUnchecked_U32(_Address); +#elif defined(_M_X64) + return Common::swap32(*(u32 *)(base + _Address)); +#endif +} + +// used by interpreter to read instructions, uses iCache +u32 Read_Opcode(const u32 _Address); +// used by JIT to read instructions, uses iCacheJIT +u32 Read_Opcode_JIT(const u32 _Address); +// used by JIT. uses iCacheJIT. Reads in the "Locked cache" mode +u32 Read_Opcode_JIT_LC(const u32 _Address); +void Write_Opcode_JIT(const u32 _Address, const u32 _Value); +// this is used by Debugger a lot. +// For now, just reads from memory! +u32 Read_Instruction(const u32 _Address); - // For use by emulator +// For use by emulator - // Read and write functions - #define NUMHWMEMFUN 64 - #define HWSHIFT 10 - #define HW_MASK 0x3FF +// Read and write functions +#define NUMHWMEMFUN 64 +#define HWSHIFT 10 +#define HW_MASK 0x3FF - u8 Read_U8(const u32 _Address); - u16 Read_U16(const u32 _Address); - u32 Read_U32(const u32 _Address); - u64 Read_U64(const u32 _Address); +u8 Read_U8(const u32 _Address); +u16 Read_U16(const u32 _Address); +u32 Read_U32(const u32 _Address); +u64 Read_U64(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); +// used by JIT. Return zero-extended 32bit values +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 _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 WriteHW_U32(const u32 _Data, const u32 _Address); - void GetString(std::string& _string, const u32 _Address); - void WriteBigEData(const u8 *_pData, const u32 _Address, const u32 size); - void ReadBigEData(u8 *_pDest, const u32 _Address, const u32 size); - 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); - void Memset(const u32 _Address, const u8 _Data, const u32 _iLength); +void WriteHW_U32(const u32 _Data, const u32 _Address); +void GetString(std::string& _string, const u32 _Address); + +void WriteBigEData(const u8 *_pData, const u32 _Address, const u32 size); +void ReadBigEData(u8 *_pDest, const u32 _Address, const u32 size); +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); +void Memset(const u32 _Address, const u8 _Data, const u32 _iLength); + +// TLB functions +void SDRUpdated(); +enum XCheckTLBFlag +{ + FLAG_NO_EXCEPTION, + FLAG_READ, + FLAG_WRITE, + FLAG_OPCODE, +}; +u32 CheckDTLB(u32 _Address, XCheckTLBFlag _Flag); +extern u32 pagetable_base; +extern u32 pagetable_hashmask; - // TLB functions - void SDRUpdated(); - enum XCheckTLBFlag - { - FLAG_NO_EXCEPTION, - FLAG_READ, - FLAG_WRITE, - FLAG_OPCODE, - }; - u32 CheckDTLB(u32 _Address, XCheckTLBFlag _Flag); - extern u32 pagetable_base; - extern u32 pagetable_hashmask; }; #endif