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
|
#ifdef _WIN32
|
||||||
return MapViewOfFile(hMemoryMapping, FILE_MAP_ALL_ACCESS, 0, (DWORD)((u64)offset), size);
|
return MapViewOfFile(hMemoryMapping, FILE_MAP_ALL_ACCESS, 0, (DWORD)((u64)offset), size);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
void* ptr = mmap(0, size,
|
void* ptr = mmap(0, size,
|
||||||
PROT_READ | PROT_WRITE,
|
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)
|
| (ensure_low_mem ? MAP_32BIT : 0)
|
||||||
#endif
|
#endif
|
||||||
, fd, offset);
|
, fd, offset);
|
||||||
|
return ptr;
|
||||||
if (!ptr)
|
|
||||||
{
|
|
||||||
PanicAlert("Failed to create view");
|
|
||||||
}
|
|
||||||
|
|
||||||
return(ptr);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -141,3 +133,154 @@ u8* MemArena::Find4GBBase()
|
||||||
#endif
|
#endif
|
||||||
#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
|
#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_
|
#endif // _MEMARENA_H_
|
||||||
|
|
|
@ -78,24 +78,27 @@ MemArena g_arena;
|
||||||
|
|
||||||
// STATE_TO_SAVE (applies to a lot of things in this file)
|
// 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
|
bool m_IsInitialized = false; // Save the Init(), Shutdown() state
|
||||||
|
|
||||||
// Pointers into the "View" (rarely used)
|
// 64-bit: Pointers to low-mem (sub-0x10000000) mirror
|
||||||
u8* m_pPhysicalFakeVMEM;
|
// 32-bit: Same as the corresponding physical/virtual pointers.
|
||||||
u8* m_pPhysicalRAM;
|
u8 *m_pRAM;
|
||||||
u8* m_pPhysicalEXRAM; //wii
|
u8 *m_pEFB;
|
||||||
u8* m_pVirtualCachedRAM;
|
u8 *m_pL1Cache;
|
||||||
u8* m_pVirtualUncachedRAM;
|
u8 *m_pEXRAM;
|
||||||
u8* m_pVirtualCachedEXRAM;
|
u8 *m_pFakeVMEM;
|
||||||
u8* m_pVirtualUncachedEXRAM;
|
|
||||||
u8* m_pVirtualEFB;
|
// 64-bit: Pointers to high-mem mirrors
|
||||||
u8* m_pVirtualL1Cache;
|
// 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
|
// Read and write shortcuts
|
||||||
|
@ -119,36 +122,29 @@ readFn8 hwReadWii8 [NUMHWMEMFUN];
|
||||||
readFn16 hwReadWii16[NUMHWMEMFUN];
|
readFn16 hwReadWii16[NUMHWMEMFUN];
|
||||||
readFn32 hwReadWii32[NUMHWMEMFUN];
|
readFn32 hwReadWii32[NUMHWMEMFUN];
|
||||||
readFn64 hwReadWii64[NUMHWMEMFUN];
|
readFn64 hwReadWii64[NUMHWMEMFUN];
|
||||||
// ===============
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Default read and write functions
|
// Default read and write functions
|
||||||
// ----------------
|
|
||||||
u32 CheckDTLB(u32 _Address, XCheckTLBFlag _Flag);
|
|
||||||
|
|
||||||
template <class T>
|
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);}
|
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>
|
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);}
|
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_SHIFT 10
|
||||||
#define PAGE_SIZE (1 << PAGE_SHIFT)
|
#define PAGE_SIZE (1 << PAGE_SHIFT)
|
||||||
#define PAGE_MASK (PAGE_SHIFT - 1)
|
#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_Read_Memory(T &_Data, const u32 _Address) {
|
||||||
template <class T, u8* P> void HW_Write_Memory(T _Data, const u32 _Address) { *(T*)&P[_Address & PAGE_MASK] = _Data; }
|
_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 BLOCKSIZE 4
|
||||||
#define CP_START 0x00 //0x0000 >> 10
|
#define CP_START 0x00 //0x0000 >> 10
|
||||||
#define WII_IPC_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 AUDIO_START 0x1B //0x6C00 >> 10
|
||||||
#define GP_START 0x20 //0x8000 >> 10
|
#define GP_START 0x20 //0x8000 >> 10
|
||||||
|
|
||||||
|
|
||||||
void InitHWMemFuncs()
|
void InitHWMemFuncs()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < NUMHWMEMFUN; i++)
|
for (int i = 0; i < NUMHWMEMFUN; i++)
|
||||||
|
@ -177,7 +172,8 @@ void InitHWMemFuncs()
|
||||||
hwRead32 [i] = HW_Default_Read<u32&>;
|
hwRead32 [i] = HW_Default_Read<u32&>;
|
||||||
hwRead64 [i] = HW_Default_Read<u64&>;
|
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>;
|
hwWriteWii8 [i] = HW_Default_Write<u8>;
|
||||||
hwWriteWii16[i] = HW_Default_Write<u16>;
|
hwWriteWii16[i] = HW_Default_Write<u16>;
|
||||||
hwWriteWii32[i] = HW_Default_Write<u32>;
|
hwWriteWii32[i] = HW_Default_Write<u32>;
|
||||||
|
@ -327,114 +323,39 @@ writeFn32 GetHWWriteFun32(const u32 _Address)
|
||||||
return hwWrite32[(_Address >> HWSHIFT) & (NUMHWMEMFUN-1)];
|
return hwWrite32[(_Address >> HWSHIFT) & (NUMHWMEMFUN-1)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Init and Shutdown
|
|
||||||
// ----------------
|
|
||||||
bool IsInitialized()
|
bool IsInitialized()
|
||||||
{
|
{
|
||||||
return m_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 Init()
|
||||||
{
|
{
|
||||||
bool wii = Core::GetStartupParameter().bWii;
|
bool wii = Core::GetStartupParameter().bWii;
|
||||||
bFakeVMEM = Core::GetStartupParameter().iTLBHack == 1;
|
bFakeVMEM = Core::GetStartupParameter().iTLBHack == 1;
|
||||||
|
|
||||||
int totalMemSize = RAM_SIZE + EFB_SIZE + L1_CACHE_SIZE + IO_SIZE;
|
u32 flags = 0;
|
||||||
if (bFakeVMEM)
|
if (wii) flags |= MV_WII_ONLY;
|
||||||
totalMemSize += FAKEVMEM_SIZE;
|
if (bFakeVMEM) flags |= MV_FAKE_VMEM;
|
||||||
if (wii)
|
base = MemoryMap_Setup(views, num_views, flags, &g_arena);
|
||||||
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);
|
|
||||||
|
|
||||||
if (wii)
|
if (wii)
|
||||||
InitHWMemFuncsWii();
|
InitHWMemFuncsWii();
|
||||||
|
@ -450,9 +371,9 @@ bool Init()
|
||||||
void DoState(PointerWrap &p)
|
void DoState(PointerWrap &p)
|
||||||
{
|
{
|
||||||
bool wii = Core::GetStartupParameter().bWii;
|
bool wii = Core::GetStartupParameter().bWii;
|
||||||
p.DoArray(m_pRAM, RAM_SIZE);
|
p.DoArray(m_pPhysicalRAM, RAM_SIZE);
|
||||||
p.DoArray(m_pEFB, EFB_SIZE);
|
p.DoArray(m_pVirtualEFB, EFB_SIZE);
|
||||||
p.DoArray(m_pL1Cache, L1_CACHE_SIZE);
|
p.DoArray(m_pVirtualL1Cache, L1_CACHE_SIZE);
|
||||||
if (wii)
|
if (wii)
|
||||||
p.DoArray(m_pEXRAM, EXRAM_SIZE);
|
p.DoArray(m_pEXRAM, EXRAM_SIZE);
|
||||||
}
|
}
|
||||||
|
@ -460,48 +381,16 @@ void DoState(PointerWrap &p)
|
||||||
bool Shutdown()
|
bool Shutdown()
|
||||||
{
|
{
|
||||||
m_IsInitialized = false;
|
m_IsInitialized = false;
|
||||||
bool wii = Core::GetStartupParameter().bWii;
|
u32 flags = 0;
|
||||||
|
if (Core::GetStartupParameter().bWii) flags |= MV_WII_ONLY;
|
||||||
g_arena.ReleaseView(m_pRAM, RAM_SIZE);
|
if (bFakeVMEM) flags |= MV_FAKE_VMEM;
|
||||||
g_arena.ReleaseView(m_pEFB, EFB_SIZE);
|
MemoryMap_Shutdown(views, num_views, flags, &g_arena);
|
||||||
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
|
|
||||||
g_arena.ReleaseSpace();
|
g_arena.ReleaseSpace();
|
||||||
|
base = NULL;
|
||||||
INFO_LOG(MEMMAP, "Memory system shut down.");
|
INFO_LOG(MEMMAP, "Memory system shut down.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Clear()
|
void Clear()
|
||||||
{
|
{
|
||||||
if (m_pRAM)
|
if (m_pRAM)
|
||||||
|
@ -514,7 +403,6 @@ void Clear()
|
||||||
memset(m_pEXRAM, 0, EXRAM_SIZE);
|
memset(m_pEXRAM, 0, EXRAM_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool AreMemoryBreakpointsActivated()
|
bool AreMemoryBreakpointsActivated()
|
||||||
{
|
{
|
||||||
#ifndef ENABLE_MEM_CHECK
|
#ifndef ENABLE_MEM_CHECK
|
||||||
|
@ -524,7 +412,6 @@ bool AreMemoryBreakpointsActivated()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
u32 Read_Instruction(const u32 em_address)
|
u32 Read_Instruction(const u32 em_address)
|
||||||
{
|
{
|
||||||
UGeckoInstruction inst = ReadUnchecked_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)
|
void CheckForBadAddresses64(u32 Address, u64 Data, bool Read)
|
||||||
{CheckForBadAddresses(Address, (u32)Data, Read, 64);}
|
{CheckForBadAddresses(Address, (u32)Data, Read, 64);}
|
||||||
// =============
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Other functions
|
|
||||||
// ----------------
|
|
||||||
void WriteBigEData(const u8 *_pData, const u32 _Address, const u32 _iSize)
|
void WriteBigEData(const u8 *_pData, const u32 _Address, const u32 _iSize)
|
||||||
{
|
{
|
||||||
memcpy(GetPointer(_Address), _pData, _iSize);
|
memcpy(GetPointer(_Address), _pData, _iSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Memset(const u32 _Address, const u8 _iValue, const u32 _iLength)
|
void Memset(const u32 _Address, const u8 _iValue, const u32 _iLength)
|
||||||
{
|
{
|
||||||
u8 *ptr = GetPointer(_Address);
|
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)
|
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);
|
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);
|
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)
|
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);
|
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);
|
memcpy(dst, src, 32 * _iNumBlocks);
|
||||||
}
|
}
|
||||||
|
@ -853,27 +729,24 @@ void DMA_MemoryToLC(const u32 _CacheAddr, const u32 _MemAddr, const u32 _iNumBlo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ReadBigEData(u8 *data, const u32 em_address, const u32 size)
|
||||||
void ReadBigEData( u8 *_pData, const u32 _Address, const u32 size)
|
|
||||||
{
|
{
|
||||||
u8 *src = GetPointer(_Address);
|
u8 *src = GetPointer(em_address);
|
||||||
memcpy(_pData, src, size);
|
memcpy(data, src, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GetString(std::string& _string, const u32 em_address)
|
||||||
void GetString(std::string& _string, const u32 _Address)
|
|
||||||
{
|
{
|
||||||
char stringBuffer[2048];
|
char stringBuffer[2048];
|
||||||
char *string = stringBuffer;
|
char *string = stringBuffer;
|
||||||
char c;
|
char c;
|
||||||
int addr = _Address;
|
u32 addr = em_address;
|
||||||
while ((c = Read_U8(addr)))
|
while ((c = Read_U8(addr)))
|
||||||
{
|
{
|
||||||
*string++ = c;
|
*string++ = c;
|
||||||
addr++;
|
addr++;
|
||||||
}
|
}
|
||||||
*string++=0;
|
*string++ = '\0';
|
||||||
|
|
||||||
_string = stringBuffer;
|
_string = stringBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -890,7 +763,7 @@ u8 *GetPointer(const u32 _Address)
|
||||||
case 0x81:
|
case 0x81:
|
||||||
case 0xC0:
|
case 0xC0:
|
||||||
case 0xC1:
|
case 0xC1:
|
||||||
return (u8*)(((char*)m_pRAM) + (_Address & RAM_MASK));
|
return (u8*)(((char*)m_pPhysicalRAM) + (_Address & RAM_MASK));
|
||||||
|
|
||||||
case 0x10:
|
case 0x10:
|
||||||
case 0x11:
|
case 0x11:
|
||||||
|
@ -905,13 +778,13 @@ u8 *GetPointer(const u32 _Address)
|
||||||
case 0xD2:
|
case 0xD2:
|
||||||
case 0xD3:
|
case 0xD3:
|
||||||
if (Core::GetStartupParameter().bWii)
|
if (Core::GetStartupParameter().bWii)
|
||||||
return (u8*)(((char*)m_pEXRAM) + (_Address & EXRAM_MASK));
|
return (u8*)(((char*)m_pPhysicalEXRAM) + (_Address & EXRAM_MASK));
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case 0x7E:
|
case 0x7E:
|
||||||
case 0x7F:
|
case 0x7F:
|
||||||
return (u8*)(((char*)m_pFakeVMEM) + (_Address & RAM_MASK));
|
return (u8*)(((char*)m_pVirtualFakeVMEM) + (_Address & RAM_MASK));
|
||||||
|
|
||||||
case 0xE0:
|
case 0xE0:
|
||||||
if (_Address < (0xE0000000 + L1_CACHE_SIZE))
|
if (_Address < (0xE0000000 + L1_CACHE_SIZE))
|
||||||
|
|
|
@ -42,122 +42,129 @@ typedef void (*readFn64)(u64&, const u32);
|
||||||
|
|
||||||
namespace Memory
|
namespace Memory
|
||||||
{
|
{
|
||||||
/* Base is a pointer to the base of the memory map. Yes, some MMU tricks
|
// 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
|
// 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
|
// 32-bit, you have to mask your offsets with 0x3FFFFFFF. This means that
|
||||||
some things are mirrored, but eh... it works. */
|
// some things are mirrored too many times, but eh... it works.
|
||||||
|
|
||||||
extern u8 *base;
|
// In 64-bit, this might point to "high memory" (above the 32-bit limit),
|
||||||
extern u8* m_pRAM;
|
// so be sure to load it into a 64-bit register.
|
||||||
extern u8* m_pL1Cache;
|
extern u8 *base;
|
||||||
|
|
||||||
// The size should be 24mb only, but the RAM_MASK wouldn't work anymore
|
// These are guarenteed to point to "low memory" addresses (sub-32-bit).
|
||||||
enum
|
extern u8 *m_pRAM;
|
||||||
{
|
extern u8 *m_pL1Cache;
|
||||||
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
|
enum
|
||||||
bool IsInitialized();
|
{
|
||||||
bool Init();
|
// The size should be just 24MB instead of 32, but the RAM_MASK wouldn't
|
||||||
bool Shutdown();
|
// work.
|
||||||
void DoState(PointerWrap &p);
|
RAM_SIZE = 0x2000000,
|
||||||
|
RAM_MASK = 0x1FFFFFF,
|
||||||
void Clear();
|
FAKEVMEM_SIZE = 0x2000000,
|
||||||
bool AreMemoryBreakpointsActivated();
|
FAKEVMEM_MASK = 0x1FFFFFF,
|
||||||
|
REALRAM_SIZE = 0x1800000,
|
||||||
// ONLY for use by GUI
|
L1_CACHE_SIZE = 0x40000,
|
||||||
u8 ReadUnchecked_U8(const u32 _Address);
|
L1_CACHE_MASK = 0x3FFFF,
|
||||||
u32 ReadUnchecked_U32(const u32 _Address);
|
EFB_SIZE = 0x200000,
|
||||||
|
EFB_MASK = 0x1FFFFF,
|
||||||
void WriteUnchecked_U8(const u8 _Data, const u32 _Address);
|
IO_SIZE = 0x10000,
|
||||||
void WriteUnchecked_U32(const u32 _Data, const u32 _Address);
|
EXRAM_SIZE = 0x4000000,
|
||||||
|
EXRAM_MASK = 0x3FFFFFF,
|
||||||
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
|
#ifdef _M_IX86
|
||||||
return Common::swap32(*(u32 *)(base + (_Address & MEMVIEW32_MASK))); // ReadUnchecked_U32(_Address);
|
MEMVIEW32_MASK = 0x3FFFFFFF,
|
||||||
#elif defined(_M_X64)
|
|
||||||
return Common::swap32(*(u32 *)(base + _Address));
|
|
||||||
#endif
|
#endif
|
||||||
}
|
};
|
||||||
|
|
||||||
// used by interpreter to read instructions, uses iCache
|
// Init and Shutdown
|
||||||
u32 Read_Opcode(const u32 _Address);
|
bool IsInitialized();
|
||||||
// used by JIT to read instructions, uses iCacheJIT
|
bool Init();
|
||||||
u32 Read_Opcode_JIT(const u32 _Address);
|
bool Shutdown();
|
||||||
// used by JIT. uses iCacheJIT. Reads in the "Locked cache" mode
|
void DoState(PointerWrap &p);
|
||||||
u32 Read_Opcode_JIT_LC(const u32 _Address);
|
|
||||||
void Write_Opcode_JIT(const u32 _Address, const u32 _Value);
|
void Clear();
|
||||||
// this is used by Debugger a lot.
|
bool AreMemoryBreakpointsActivated();
|
||||||
// For now, just reads from memory!
|
|
||||||
u32 Read_Instruction(const u32 _Address);
|
// 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
|
// Read and write functions
|
||||||
#define NUMHWMEMFUN 64
|
#define NUMHWMEMFUN 64
|
||||||
#define HWSHIFT 10
|
#define HWSHIFT 10
|
||||||
#define HW_MASK 0x3FF
|
#define HW_MASK 0x3FF
|
||||||
|
|
||||||
u8 Read_U8(const u32 _Address);
|
u8 Read_U8(const u32 _Address);
|
||||||
u16 Read_U16(const u32 _Address);
|
u16 Read_U16(const u32 _Address);
|
||||||
u32 Read_U32(const u32 _Address);
|
u32 Read_U32(const u32 _Address);
|
||||||
u64 Read_U64(const u32 _Address);
|
u64 Read_U64(const u32 _Address);
|
||||||
|
|
||||||
// used by JIT. Return zero-extended 32bit values
|
// used by JIT. Return zero-extended 32bit values
|
||||||
u32 Read_U8_ZX(const u32 _Address);
|
u32 Read_U8_ZX(const u32 _Address);
|
||||||
u32 Read_U16_ZX(const u32 _Address);
|
u32 Read_U16_ZX(const u32 _Address);
|
||||||
|
|
||||||
void Write_U8(const u8 _Data, const u32 _Address);
|
void Write_U8(const u8 _Data, const u32 _Address);
|
||||||
void Write_U16(const u16 _Data, const u32 _Address);
|
void Write_U16(const u16 _Data, const u32 _Address);
|
||||||
void Write_U32(const u32 _Data, const u32 _Address);
|
void Write_U32(const u32 _Data, const u32 _Address);
|
||||||
void Write_U64(const u64 _Data, const u32 _Address);
|
void Write_U64(const u64 _Data, const u32 _Address);
|
||||||
|
|
||||||
void WriteHW_U32(const u32 _Data, const u32 _Address);
|
void WriteHW_U32(const u32 _Data, const u32 _Address);
|
||||||
void GetString(std::string& _string, 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);
|
void WriteBigEData(const u8 *_pData, const u32 _Address, const u32 size);
|
||||||
u8* GetPointer(const u32 _Address);
|
void ReadBigEData(u8 *_pDest, const u32 _Address, const u32 size);
|
||||||
void DMA_LCToMemory(const u32 _iMemAddr, const u32 _iCacheAddr, const u32 _iNumBlocks);
|
u8* GetPointer(const u32 _Address);
|
||||||
void DMA_MemoryToLC(const u32 _iCacheAddr, const u32 _iMemAddr, const u32 _iNumBlocks);
|
void DMA_LCToMemory(const u32 _iMemAddr, const u32 _iCacheAddr, const u32 _iNumBlocks);
|
||||||
void Memset(const u32 _Address, const u8 _Data, const u32 _iLength);
|
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
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue