summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorhrydgard <hrydgard@gmail.com>2009-11-07 18:53:10 +0000
committerhrydgard <hrydgard@gmail.com>2009-11-07 18:53:10 +0000
commit2d0f714546cba64ec9191c4e3e0b60351ad3e539 (patch)
tree6bb1aa589f704549656f7b1f7df1b924a9d52d7c /Source/Core
parent42cd2838a3064f6e9b597fec0a8be4cea6f008c4 (diff)
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
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Common/Src/MemArena.cpp161
-rw-r--r--Source/Core/Common/Src/MemArena.h20
-rw-r--r--Source/Core/Core/Src/HW/Memmap.cpp273
-rw-r--r--Source/Core/Core/Src/HW/Memmap.h235
4 files changed, 366 insertions, 323 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 <class T>
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 <class T>
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 <class T, u8* P> void HW_Read_Memory(T &_Data, const u32 _Address) { _Data = *(T*)&P[_Address & PAGE_MASK]; }
-template <class T, u8* P> void HW_Write_Memory(T _Data, const u32 _Address) { *(T*)&P[_Address & PAGE_MASK] = _Data; }
-
-
-
+template <class T, u8 *P> void HW_Read_Memory(T &_Data, const u32 _Address) {
+ _Data = *(T *)&P[_Address & PAGE_MASK];
+}
+template <class T, u8 *P> 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 <class T, u8* P> 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<u32&>;
hwRead64 [i] = HW_Default_Read<u64&>;
- // 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<u8>;
hwWriteWii16[i] = HW_Default_Write<u16>;
hwWriteWii32[i] = HW_Default_Write<u32>;
@@ -327,114 +323,39 @@ writeFn32 GetHWWriteFun32(const u32 _Address)
return hwWrite32[(_Address >> HWSHIFT) & (NUMHWMEMFUN-1)];
}
-
-
-
-
-// Init and Shutdown
-// ----------------
bool IsInitialized()
{
return m_IsInitialized;
}
-bool Init()
+// We don't declare the IO region in here since its handled by other means.
+static const MemoryView views[] =
{
- bool wii = Core::GetStartupParameter().bWii;
- bFakeVMEM = Core::GetStartupParameter().iTLBHack == 1;
+ {&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},
- 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;
- }
+ {&m_pEFB, &m_pVirtualEFB, 0xC8000000, EFB_SIZE, 0},
+ {&m_pL1Cache, &m_pVirtualL1Cache, 0xE0000000, L1_CACHE_SIZE, 0},
- if (wii)
- m_pEXRAM = (u8*)g_arena.CreateView(position, EXRAM_SIZE);
+ {&m_pFakeVMEM, &m_pVirtualFakeVMEM, 0x7E000000, FAKEVMEM_SIZE, MV_FAKE_VMEM},
-#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
+ {&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);
- 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);
+bool Init()
+{
+ bool wii = Core::GetStartupParameter().bWii;
+ bFakeVMEM = Core::GetStartupParameter().iTLBHack == 1;
+
+ 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. */
-
- extern u8 *base;
- extern u8* m_pRAM;
- extern u8* m_pL1Cache;
-
- // 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
- };
-
- // 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)
- {
+// 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.
+
+// 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;
+
+// These are guarenteed to point to "low memory" addresses (sub-32-bit).
+extern u8 *m_pRAM;
+extern u8 *m_pL1Cache;
+
+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);
-
-
- // For use by emulator
-
- // 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);
-
- // 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 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;
+};
+
+// 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
+
+// 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);
+
+// 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 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;
+
};
#endif