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
This commit is contained in:
parent
42cd2838a3
commit
2d0f714546
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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_
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
// 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))
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue