mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-02 11:02:28 +02:00
MemMap: Divided into two files
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@1918 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
f9ffbd8c32
commit
7bd15a8560
@ -527,6 +527,10 @@
|
||||
RelativePath=".\Src\Hw\Memmap.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\HW\MemmapFunctions.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\HW\SystemTimers.cpp"
|
||||
>
|
||||
|
@ -15,6 +15,21 @@
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// File description:
|
||||
/* -------------
|
||||
|
||||
These functions are primarily used by the interpreter versions of the LoadStore instructions.
|
||||
However, if a JITed instruction (for example lwz) wants to access a bad memory area that call
|
||||
may be redirected here (for example to Read_U32()).
|
||||
|
||||
//////////////////////////*/
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Includes
|
||||
// ----------------
|
||||
#include "Common.h"
|
||||
#include "MemoryUtil.h"
|
||||
#include "MemArena.h"
|
||||
@ -42,26 +57,44 @@
|
||||
#include "../ConfigManager.h"
|
||||
#include "../Debugger/Debugger_BreakPoints.h"
|
||||
#include "../Debugger/Debugger_SymbolMap.h"
|
||||
/////////////////////////////
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Declarations and definitions
|
||||
// ----------------
|
||||
namespace Memory
|
||||
{
|
||||
|
||||
// GLOBAL DEFINES
|
||||
// =================================
|
||||
// LOCAL SETTINGS
|
||||
// ----------------
|
||||
|
||||
// Disable Memory Checks
|
||||
// #define NOCHECK
|
||||
|
||||
// TLBHack = 1 in a patch ini will set this to true.
|
||||
static bool bFakeVMEM = false;
|
||||
|
||||
// Always disable memory checks if the Release build
|
||||
#ifndef LOGGING
|
||||
#define NOCHECK
|
||||
#endif
|
||||
|
||||
// END: GLOBAL DEFINES
|
||||
/* Enable the Translation Lookaside Buffer functions. TLBHack = 1 in Dolphin.ini or a
|
||||
<GameID>.ini file will set this to true */
|
||||
bool bFakeVMEM = false;
|
||||
// ==============
|
||||
|
||||
|
||||
// =================================
|
||||
// Init() declarations
|
||||
// ----------------
|
||||
// Store the MemArena here
|
||||
u8* base = NULL;
|
||||
|
||||
// The MemArena class
|
||||
MemArena g_arena;
|
||||
// ==============
|
||||
|
||||
|
||||
// STATE_TO_SAVE (applies to a lot of things in this file)
|
||||
|
||||
// Pointers to low memory
|
||||
@ -70,9 +103,7 @@ u8* m_pFakeVMEM = NULL;
|
||||
u8* m_pEXRAM = NULL; //wii
|
||||
u8* m_pEFB = NULL;
|
||||
u8* m_pL1Cache = NULL;
|
||||
bool m_IsInitialized = false;
|
||||
|
||||
MemArena g_arena;
|
||||
bool m_IsInitialized = false; // Save the Init(), Shutdown() state
|
||||
|
||||
// Pointers into the "View" (rarely used)
|
||||
u8* m_pPhysicalFakeVMEM;
|
||||
@ -85,10 +116,9 @@ u8* m_pVirtualUncachedEXRAM;
|
||||
u8* m_pVirtualEFB;
|
||||
u8* m_pVirtualL1Cache;
|
||||
|
||||
#define NUMHWMEMFUN 64
|
||||
#define HWSHIFT 10
|
||||
#define HW_MASK 0x3FF
|
||||
|
||||
// =================================
|
||||
// Read and write shortcuts
|
||||
// ----------------
|
||||
writeFn8 hwWrite8 [NUMHWMEMFUN];
|
||||
writeFn16 hwWrite16[NUMHWMEMFUN];
|
||||
writeFn32 hwWrite32[NUMHWMEMFUN];
|
||||
@ -108,13 +138,14 @@ readFn8 hwReadWii8 [NUMHWMEMFUN];
|
||||
readFn16 hwReadWii16[NUMHWMEMFUN];
|
||||
readFn32 hwReadWii32[NUMHWMEMFUN];
|
||||
readFn64 hwReadWii64[NUMHWMEMFUN];
|
||||
// ===============
|
||||
|
||||
/////////////////////////////
|
||||
|
||||
|
||||
inline u8 bswap(u8 val) {return val;}
|
||||
inline u16 bswap(u16 val) {return Common::swap16(val);}
|
||||
inline u32 bswap(u32 val) {return Common::swap32(val);}
|
||||
inline u64 bswap(u64 val) {return Common::swap64(val);}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Default read and write functions
|
||||
// ----------------
|
||||
u32 CheckDTLB(u32 _Address, XCheckTLBFlag _Flag);
|
||||
|
||||
template <class T>
|
||||
@ -123,15 +154,20 @@ void HWCALL HW_Default_Write(const T _Data, const u32 _Address){ LOG(MASTER_LOG,
|
||||
template <class T>
|
||||
void HWCALL HW_Default_Read(T _Data, const u32 _Address){ LOG(MASTER_LOG, "Illegal HW Read%i %08x", sizeof(T)*8, _Address); _dbg_assert_(MEMMAP, 0);}
|
||||
|
||||
|
||||
#define PAGE_SHIFT 10
|
||||
#define PAGE_SIZE (1 << PAGE_SHIFT)
|
||||
#define PAGE_MASK (PAGE_SHIFT - 1)
|
||||
|
||||
|
||||
template <class T, u8* P> void HWCALL HW_Read_Memory(T &_Data, const u32 _Address) { _Data = *(T*)&P[_Address & PAGE_MASK]; }
|
||||
template <class T, u8* P> void HWCALL 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. */
|
||||
// ----------------
|
||||
#define BLOCKSIZE 4
|
||||
#define CP_START 0x00 //0x0000 >> 10
|
||||
#define WII_IPC_START 0x00 //0x0000 >> 10
|
||||
@ -146,6 +182,7 @@ template <class T, u8* P> void HWCALL HW_Write_Memory(T _Data, const u32 _Addres
|
||||
#define AUDIO_START 0x1B
|
||||
#define GP_START 0x20
|
||||
|
||||
|
||||
void InitHWMemFuncs()
|
||||
{
|
||||
for (int i = 0; i < NUMHWMEMFUN; i++)
|
||||
@ -292,279 +329,17 @@ void InitHWMemFuncsWii()
|
||||
hwWriteWii32[AUDIO_START] = AudioInterface::Write32;
|
||||
}
|
||||
|
||||
|
||||
writeFn32 GetHWWriteFun32(const u32 _Address)
|
||||
{
|
||||
return hwWrite32[(_Address >> HWSHIFT) & (NUMHWMEMFUN-1)];
|
||||
}
|
||||
/////////////////////////////
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// =======================================================
|
||||
/* Functions to detect and trace memory read/write errors. Turn of JIT LoadStore to
|
||||
make it work, and add a return 0 at the beginning of CheckDTLB to avoid closing
|
||||
Dolphin just as it starts to get interesting. You can also try to change
|
||||
the TitleID write in IOCTL_ES_GETTITLEID to 0x00000000, otherwise it will never even
|
||||
get to making the bad dev/di request.
|
||||
|
||||
I'm currently at (---, 8021347c) : Write32: Program wrote [0x7fd5d340] to [0x933e00f8],
|
||||
0x8021347c seems to write the out buffer to a 0x933e.... address before it is copies
|
||||
to the 0x133e.... address for the Ioctlv. But why does it generate this bad address
|
||||
when it made a good one 120 milliseconds earlier?
|
||||
*/
|
||||
// -------------
|
||||
bool ValidMemory(const u32 _Address)
|
||||
{
|
||||
switch (_Address >> 24)
|
||||
{
|
||||
case 0x00:
|
||||
case 0x01:
|
||||
case 0x80:
|
||||
case 0x81:
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
return true;
|
||||
|
||||
case 0x10:
|
||||
case 0x11:
|
||||
case 0x12:
|
||||
case 0x13:
|
||||
case 0x90:
|
||||
case 0x91:
|
||||
case 0x92:
|
||||
case 0x93:
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
if (Core::GetStartupParameter().bWii)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
case 0x7e:
|
||||
case 0x7f:
|
||||
if (bFakeVMEM)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
|
||||
case 0xE0:
|
||||
if (_Address < (0xE0000000 + L1_CACHE_SIZE))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xC8:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CheckForBadAddresses(u32 Address, u32 Data, bool Read, int Bits)
|
||||
{
|
||||
if (!ValidMemory(Address))
|
||||
{
|
||||
if(Read)
|
||||
{
|
||||
LOG(CONSOLE, "Read%i: Program tried to read [%08x] from [%08x]", Bits, Address);
|
||||
//PanicAlert("Write_U32: Program tried to write [%08x] to [%08x]", _Address);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGV(CONSOLE, 0, "Write%i: Program tried to write [%08x] to [%08x]", Bits, Data, Address);
|
||||
//PanicAlert("Read: Program tried to write [%08x] to [%08x]", Data, Address);
|
||||
}
|
||||
}
|
||||
|
||||
if (Address == 0)
|
||||
{
|
||||
if(Read)
|
||||
{
|
||||
LOGV(CONSOLE, 1, "Read%i: Program read [0x%08x] from [0x%08x] * * * 0 * * *", Bits, Data, Address);
|
||||
//PanicAlert("Read: Program read [%08x] from [%08x]", Data, Address);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGV(CONSOLE, 1, "Write%i: Program wrote [0x%08x] to [0x%08x] * * * 0 * * *", Bits, Data, Address);
|
||||
//PanicAlert("Read: Program wrote [%08x] to [%08x]", Data, Address);
|
||||
}
|
||||
}
|
||||
/* Try to figure out where the dev/di Ioctl arguments are stored (including buffer out), so we can
|
||||
find the bad one */
|
||||
if(
|
||||
Data == 0x1090f4c0 // good out buffer right before it, for sound/smashbros_sound.brsar
|
||||
|| Data == 0x10913b00 // second one
|
||||
|| Data == 0x7fd5d340 // first bad out buffer
|
||||
|| Data == 0x133e00f8 // the address that store the bad 0x7fd5d340, this changes every time
|
||||
|| Data == 0x2a24aa // menu2\sc_title_en.pac byte size
|
||||
|| (
|
||||
(PC == 0x8021347c || PC == 0x801f6a20 || PC == 0x800202d0 || PC == 0x80229964
|
||||
|| PC == 0x801d88bc) /* this could be interesting, because the bad out buffer 0x7fd5d340
|
||||
is 0x80000000 - size = 0x7fd5d340 perhaps some function read 0x80000000, I dunno */
|
||||
&& Data == 0x80000000)
|
||||
)
|
||||
{
|
||||
if(Read)
|
||||
{
|
||||
LOGV(CONSOLE, 0, "Read%i: Program read [0x%08x] from [0x%08x] * * * * * * * * * * * *", Bits, Data, Address);
|
||||
//PanicAlert("Read%i: Program read [%08x] from [%08x]", Bits, Data, Address);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGV(CONSOLE, 0, "Write%i: Program wrote [0x%08x] to [0x%08x] * * * * * * * * * * * *", Bits,Data, Address);
|
||||
//PanicAlert("Write%i: Program wrote [0x%08x] to [0x%08x]", Bits, Data, Address);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CheckForBadAddresses8(u32 Address, u8 Data, bool Read)
|
||||
{CheckForBadAddresses(Address, (u32)Data, Read, 8);}
|
||||
|
||||
void CheckForBadAddresses16(u32 Address, u16 Data, bool Read)
|
||||
{CheckForBadAddresses(Address, (u32)Data, Read, 16);}
|
||||
|
||||
void CheckForBadAddresses32(u32 Address, u32 Data, bool Read)
|
||||
{CheckForBadAddresses(Address, (u32)Data, Read, 32);}
|
||||
|
||||
void CheckForBadAddresses64(u32 Address, u64 Data, bool Read)
|
||||
{CheckForBadAddresses(Address, (u32)Data, Read, 64);}
|
||||
// =============
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define ReadFromHardware2(_var, _type, _Address, EffectiveAddress, flag) \
|
||||
{ \
|
||||
if ((_Address & 0xC8000000) == 0xC8000000) \
|
||||
if (_Address < 0xcc000000) \
|
||||
{ \
|
||||
_var = bswap((*(u##_type*)&m_pEFB[_Address & EFB_MASK])); \
|
||||
} \
|
||||
else if (_Address <= 0xcc009000) \
|
||||
hwRead##_type[(_Address>>HWSHIFT) & (NUMHWMEMFUN-1)](_var, _Address); \
|
||||
/* WIIMODE */ \
|
||||
else if (((_Address & 0xFF000000) == 0xCD000000) && \
|
||||
(_Address <= 0xcd009000)) \
|
||||
hwReadWii##_type[(_Address>>HWSHIFT) & (NUMHWMEMFUN-1)](_var, _Address); \
|
||||
else if (((_Address & 0xFFF00000) == 0xCD800000) && \
|
||||
(_Address <= 0xCD809000)) \
|
||||
WII_IOBridge::Read##_type(_var, _Address); \
|
||||
else \
|
||||
{ \
|
||||
/* Disabled because the debugger makes trouble with */ \
|
||||
/*_dbg_assert_(MEMMAP,0); */ \
|
||||
} \
|
||||
else if (((_Address & 0xF0000000) == 0x80000000) || \
|
||||
((_Address & 0xF0000000) == 0xC0000000) || \
|
||||
((_Address & 0xF0000000) == 0x00000000)) \
|
||||
_var = bswap((*(u##_type*)&m_pRAM[_Address & RAM_MASK])); \
|
||||
else if (((_Address & 0xF0000000) == 0x90000000) || \
|
||||
((_Address & 0xF0000000) == 0xD0000000) || \
|
||||
((_Address & 0xF0000000) == 0x10000000)) \
|
||||
_var = bswap((*(u##_type*)&m_pEXRAM[_Address & EXRAM_MASK])); \
|
||||
else if ((_Address >= 0xE0000000) && (_Address < (0xE0000000+L1_CACHE_SIZE))) \
|
||||
{ \
|
||||
_var = bswap((*(u##_type*)&m_pL1Cache[_Address & L1_CACHE_MASK])); \
|
||||
} \
|
||||
else if (_Address >= 0xE0000000) \
|
||||
PanicAlert("READ: Invalid address: %08x", _Address); \
|
||||
else \
|
||||
{ \
|
||||
if (bFakeVMEM && ((_Address & 0xFE000000) == 0x7e000000) ) \
|
||||
{ \
|
||||
_var = bswap((*(u##_type*)&m_pFakeVMEM[_Address & FAKEVMEM_MASK])); \
|
||||
} \
|
||||
else {/* LOG(MEMMAP,"READ (unknown): %08x (PC: %08x)",_Address,PC);*/ \
|
||||
/*CCPU::EnableStepping(TRUE);*/ \
|
||||
/*PanicAlert("READ: Unknown Address", "1", MB_OK);*/ \
|
||||
u32 tmpAddress = CheckDTLB(EffectiveAddress, flag); \
|
||||
tmpAddress =(tmpAddress & 0xFFFFFFF0) | (_Address & 0xF); \
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) \
|
||||
_var = bswap((*(u##_type*)&m_pRAM[tmpAddress & RAM_MASK])); \
|
||||
} \
|
||||
} \
|
||||
/* Uncomment this: CheckForBadAddresses##_type(_Address, _var, true);*/ \
|
||||
}
|
||||
|
||||
|
||||
#define WriteToHardware2(_type, _Address, _Data, EffectiveAddress, flag) \
|
||||
{ \
|
||||
/* Uncomment this: CheckForBadAddresses##_type(_Address, _Data, false);*/ \
|
||||
if ((_Address & 0xC8000000) == 0xC8000000) \
|
||||
{ \
|
||||
if (_Address < 0xcc000000) \
|
||||
{ \
|
||||
*(u##_type*)&m_pEFB[_Address & EFB_MASK] = bswap(_Data); \
|
||||
return; \
|
||||
} \
|
||||
else if (_Address <= 0xcc009000) { \
|
||||
hwWrite##_type[(_Address>>HWSHIFT) & (NUMHWMEMFUN-1)](_Data,_Address); \
|
||||
return; \
|
||||
} \
|
||||
/* WIIMODE */ \
|
||||
else if (((_Address & 0xFF000000) == 0xCD000000) && \
|
||||
(_Address <= 0xcd009000)) { \
|
||||
hwWriteWii##_type[(_Address>>HWSHIFT) & (NUMHWMEMFUN-1)](_Data,_Address); \
|
||||
return; \
|
||||
} \
|
||||
else if (((_Address & 0xFFF00000) == 0xCD800000) && \
|
||||
(_Address <= 0xCD809000)) { \
|
||||
WII_IOBridge::Write##_type(_Data,_Address); \
|
||||
return; \
|
||||
} \
|
||||
else { \
|
||||
LOG(MEMMAP, "hwwrite [%08x] := %08x (PC: %08x)", _Address, _Data, PC); \
|
||||
_dbg_assert_msg_(MEMMAP,0,"Memory - Unknown HW address %08x", _Address); \
|
||||
} \
|
||||
} \
|
||||
else if (((_Address & 0xF0000000) == 0x80000000) || \
|
||||
((_Address & 0xF0000000) == 0xC0000000) || \
|
||||
((_Address & 0xF0000000) == 0x00000000)) \
|
||||
{ \
|
||||
*(u##_type*)&m_pRAM[_Address & RAM_MASK] = bswap(_Data); \
|
||||
return; \
|
||||
} \
|
||||
else if (((_Address & 0xF0000000) == 0x90000000) || \
|
||||
((_Address & 0xF0000000) == 0xD0000000) || \
|
||||
((_Address & 0xF0000000) == 0x10000000)) \
|
||||
{ \
|
||||
*(u##_type*)&m_pEXRAM[_Address & EXRAM_MASK] = bswap(_Data); \
|
||||
return; \
|
||||
} \
|
||||
else if ((_Address >= 0xE0000000) && (_Address < (0xE0000000+L1_CACHE_SIZE))) \
|
||||
{ \
|
||||
*(u##_type*)&m_pL1Cache[_Address & L1_CACHE_MASK] = bswap(_Data); \
|
||||
return; \
|
||||
} \
|
||||
else if (_Address >= 0xE0000000) \
|
||||
{ \
|
||||
LOG(MEMMAP,"WRITE: Cache address out of bounds (addr: %08x data: %08x)",_Address,_Data); \
|
||||
/* PanicAlert("WRITE: Cache address %08x out of bounds", _Address); */ \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
if (bFakeVMEM && ((_Address & 0xFE000000) == 0x7e000000)) \
|
||||
{ \
|
||||
*(u##_type*)&m_pFakeVMEM[_Address & FAKEVMEM_MASK] = bswap(_Data); \
|
||||
return; \
|
||||
} \
|
||||
/* LOG(MEMMAP,"WRITE: %08x (PC: %08x)",_Address,PC);*/ \
|
||||
/*MessageBox(NULL, "WRITE: unknown Address", "1", MB_OK);*/ \
|
||||
/*CCPU::EnableStepping(TRUE);*/ \
|
||||
u32 tmpAddress = CheckDTLB(EffectiveAddress, flag); \
|
||||
tmpAddress = (tmpAddress & 0xFFFFFFF0) | (_Address & 0xF); \
|
||||
*(u##_type*)&m_pRAM[tmpAddress & RAM_MASK] = bswap(_Data); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Init and Shutdown
|
||||
// ----------------
|
||||
bool IsInitialized()
|
||||
{
|
||||
return m_IsInitialized;
|
||||
@ -761,184 +536,149 @@ u32 Read_Instruction(const u32 em_address)
|
||||
{
|
||||
return jit.GetBlockCache()->GetOriginalCode(em_address);
|
||||
}
|
||||
//////////////////////////////////////////////////////////
|
||||
|
||||
u32 Read_Opcode(const u32 _Address)
|
||||
|
||||
|
||||
// =======================================================
|
||||
/* Functions to detect and trace memory read/write errors. Turn of JIT LoadStore to
|
||||
make it work, and add a return 0 at the beginning of CheckDTLB to avoid closing
|
||||
Dolphin just as it starts to get interesting. You can also try to change
|
||||
the TitleID write in IOCTL_ES_GETTITLEID to 0x00000000, otherwise it will never even
|
||||
get to making the bad dev/di request.
|
||||
|
||||
I'm currently at (---, 8021347c) : Write32: Program wrote [0x7fd5d340] to [0x933e00f8],
|
||||
0x8021347c seems to write the out buffer to a 0x933e.... address before it is copies
|
||||
to the 0x133e.... address for the Ioctlv. But why does it generate this bad address
|
||||
when it made a good one 120 milliseconds earlier?
|
||||
*/
|
||||
// -------------
|
||||
bool ValidMemory(const u32 _Address)
|
||||
{
|
||||
#ifdef LOGGING
|
||||
if (_Address == 0x00000000)
|
||||
switch (_Address >> 24)
|
||||
{
|
||||
PanicAlert("Program tried to read from [00000000]");
|
||||
return 0x00000000;
|
||||
case 0x00:
|
||||
case 0x01:
|
||||
case 0x80:
|
||||
case 0x81:
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
return true;
|
||||
|
||||
case 0x10:
|
||||
case 0x11:
|
||||
case 0x12:
|
||||
case 0x13:
|
||||
case 0x90:
|
||||
case 0x91:
|
||||
case 0x92:
|
||||
case 0x93:
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
if (Core::GetStartupParameter().bWii)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
case 0x7e:
|
||||
case 0x7f:
|
||||
if (bFakeVMEM)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
|
||||
case 0xE0:
|
||||
if (_Address < (0xE0000000 + L1_CACHE_SIZE))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xC8:
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
u32 _var = 0;
|
||||
ReadFromHardware2(_var, 32, _Address, _Address, FLAG_OPCODE);
|
||||
|
||||
return _var;
|
||||
return false;
|
||||
}
|
||||
|
||||
u8 Read_U8(const u32 _Address)
|
||||
void CheckForBadAddresses(u32 Address, u32 Data, bool Read, int Bits)
|
||||
{
|
||||
u8 _var = (u8)0xAFFEAFFE;
|
||||
ReadFromHardware2(_var, 8, _Address, _Address, FLAG_READ);
|
||||
#ifndef NOCHECK
|
||||
TMemCheck *mc = MemChecks::GetMemCheck(_Address);
|
||||
if (mc)
|
||||
if (!ValidMemory(Address))
|
||||
{
|
||||
mc->numHits++;
|
||||
mc->Action(_var, _Address,false,1,PC);
|
||||
if(Read)
|
||||
{
|
||||
LOG(CONSOLE, "Read%i: Program tried to read [%08x] from [%08x]", Bits, Address);
|
||||
//PanicAlert("Write_U32: Program tried to write [%08x] to [%08x]", _Address);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGV(CONSOLE, 0, "Write%i: Program tried to write [%08x] to [%08x]", Bits, Data, Address);
|
||||
//PanicAlert("Read: Program tried to write [%08x] to [%08x]", Data, Address);
|
||||
}
|
||||
#endif
|
||||
return (u8)_var;
|
||||
}
|
||||
|
||||
u16 Read_U16(const u32 _Address)
|
||||
if (Address == 0)
|
||||
{
|
||||
u16 _var = 0;
|
||||
ReadFromHardware2(_var, 16, _Address, _Address, FLAG_READ);
|
||||
#ifndef NOCHECK
|
||||
TMemCheck *mc = MemChecks::GetMemCheck(_Address);
|
||||
if (mc)
|
||||
if(Read)
|
||||
{
|
||||
mc->numHits++;
|
||||
mc->Action(_var, _Address,false,2,PC);
|
||||
LOGV(CONSOLE, 1, "Read%i: Program read [0x%08x] from [0x%08x] * * * 0 * * *", Bits, Data, Address);
|
||||
//PanicAlert("Read: Program read [%08x] from [%08x]", Data, Address);
|
||||
}
|
||||
#endif
|
||||
return (u16)_var;
|
||||
}
|
||||
|
||||
u32 Read_U32(const u32 _Address)
|
||||
else
|
||||
{
|
||||
#ifdef LOGGING
|
||||
if (_Address == 0x00000000)
|
||||
{
|
||||
//PanicAlert("Program tried to read from [00000000]");
|
||||
//return 0x00000000;
|
||||
LOGV(CONSOLE, 1, "Write%i: Program wrote [0x%08x] to [0x%08x] * * * 0 * * *", Bits, Data, Address);
|
||||
//PanicAlert("Read: Program wrote [%08x] to [%08x]", Data, Address);
|
||||
}
|
||||
}
|
||||
/* Try to figure out where the dev/di Ioctl arguments are stored (including buffer out), so we can
|
||||
find the bad one */
|
||||
if(
|
||||
Data == 0x1090f4c0 // good out buffer right before it, for sound/smashbros_sound.brsar
|
||||
|| Data == 0x10913b00 // second one
|
||||
|| Data == 0x7fd5d340 // first bad out buffer
|
||||
|| Data == 0x133e00f8 // the address that store the bad 0x7fd5d340, this changes every time
|
||||
|| Data == 0x2a24aa // menu2\sc_title_en.pac byte size
|
||||
|| (
|
||||
(PC == 0x8021347c || PC == 0x801f6a20 || PC == 0x800202d0 || PC == 0x80229964
|
||||
|| PC == 0x801d88bc) /* this could be interesting, because the bad out buffer 0x7fd5d340
|
||||
is 0x80000000 - size = 0x7fd5d340 perhaps some function read 0x80000000, I dunno */
|
||||
&& Data == 0x80000000)
|
||||
)
|
||||
{
|
||||
if(Read)
|
||||
{
|
||||
LOGV(CONSOLE, 0, "Read%i: Program read [0x%08x] from [0x%08x] * * * * * * * * * * * *", Bits, Data, Address);
|
||||
//PanicAlert("Read%i: Program read [%08x] from [%08x]", Bits, Data, Address);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGV(CONSOLE, 0, "Write%i: Program wrote [0x%08x] to [0x%08x] * * * * * * * * * * * *", Bits,Data, Address);
|
||||
//PanicAlert("Write%i: Program wrote [0x%08x] to [0x%08x]", Bits, Data, Address);
|
||||
}
|
||||
#endif
|
||||
|
||||
u32 _var = 0;
|
||||
ReadFromHardware2(_var, 32, _Address, _Address, FLAG_READ);
|
||||
#ifndef NOCHECK
|
||||
TMemCheck *mc = MemChecks::GetMemCheck(_Address);
|
||||
if (mc)
|
||||
{
|
||||
mc->numHits++;
|
||||
mc->Action(_var, _Address,false,4,PC);
|
||||
}
|
||||
#endif
|
||||
return _var;
|
||||
}
|
||||
|
||||
|
||||
u64 Read_U64(const u32 _Address)
|
||||
{
|
||||
u64 _var = 0;
|
||||
ReadFromHardware2(_var, 64, _Address, _Address, FLAG_READ);
|
||||
#ifndef NOCHECK
|
||||
TMemCheck *mc = MemChecks::GetMemCheck(_Address);
|
||||
if (mc)
|
||||
{
|
||||
mc->numHits++;
|
||||
mc->Action((u32)_var, _Address,false,8,PC);
|
||||
}
|
||||
#endif
|
||||
return _var;
|
||||
}
|
||||
void CheckForBadAddresses8(u32 Address, u8 Data, bool Read)
|
||||
{CheckForBadAddresses(Address, (u32)Data, Read, 8);}
|
||||
|
||||
void CheckForBadAddresses16(u32 Address, u16 Data, bool Read)
|
||||
{CheckForBadAddresses(Address, (u32)Data, Read, 16);}
|
||||
|
||||
void CheckForBadAddresses32(u32 Address, u32 Data, bool Read)
|
||||
{CheckForBadAddresses(Address, (u32)Data, Read, 32);}
|
||||
|
||||
void CheckForBadAddresses64(u32 Address, u64 Data, bool Read)
|
||||
{CheckForBadAddresses(Address, (u32)Data, Read, 64);}
|
||||
// =============
|
||||
|
||||
|
||||
void Write_U8(const u8 _Data, const u32 _Address)
|
||||
{
|
||||
#ifndef NOCHECK
|
||||
TMemCheck *mc = MemChecks::GetMemCheck(_Address);
|
||||
if (mc)
|
||||
{
|
||||
mc->numHits++;
|
||||
mc->Action(_Data,_Address,true,1,PC);
|
||||
}
|
||||
#endif
|
||||
WriteToHardware2(8, _Address, _Data, _Address, FLAG_WRITE);
|
||||
}
|
||||
|
||||
|
||||
void Write_U16(const u16 _Data, const u32 _Address)
|
||||
{
|
||||
#ifndef NOCHECK
|
||||
TMemCheck *mc = MemChecks::GetMemCheck(_Address);
|
||||
if (mc)
|
||||
{
|
||||
mc->numHits++;
|
||||
mc->Action(_Data,_Address,true,2,PC);
|
||||
}
|
||||
#endif
|
||||
|
||||
WriteToHardware2(16, _Address, _Data, _Address, FLAG_WRITE);
|
||||
}
|
||||
|
||||
|
||||
void Write_U32(const u32 _Data, const u32 _Address)
|
||||
{
|
||||
#ifndef NOCHECK
|
||||
TMemCheck *mc = MemChecks::GetMemCheck(_Address);
|
||||
if (mc)
|
||||
{
|
||||
mc->numHits++;
|
||||
mc->Action(_Data,_Address,true,4,PC);
|
||||
}
|
||||
#endif
|
||||
WriteToHardware2(32, _Address, _Data, _Address, FLAG_WRITE);
|
||||
}
|
||||
|
||||
|
||||
void WriteHW_U32(const u32 _Data, const u32 _Address)
|
||||
{
|
||||
hwWrite32[(_Address>>HWSHIFT) & (NUMHWMEMFUN-1)](_Data,_Address);
|
||||
}
|
||||
|
||||
|
||||
void Write_U64(const u64 _Data, const u32 _Address)
|
||||
{
|
||||
#ifndef NOCHECK
|
||||
TMemCheck *mc = MemChecks::GetMemCheck(_Address);
|
||||
if (mc)
|
||||
{
|
||||
mc->numHits++;
|
||||
mc->Action((u32)_Data,_Address,true,8,PC);
|
||||
}
|
||||
#endif
|
||||
|
||||
WriteToHardware2(64, _Address, _Data, _Address + 4, FLAG_WRITE);
|
||||
}
|
||||
|
||||
|
||||
u8 ReadUnchecked_U8(const u32 _Address)
|
||||
{
|
||||
u8 _var = (u8)0xAFFEAFFE;
|
||||
ReadFromHardware2(_var, 8, _Address, _Address, FLAG_NO_EXCEPTION);
|
||||
return (u8)_var;
|
||||
}
|
||||
|
||||
|
||||
u32 ReadUnchecked_U32(const u32 _Address)
|
||||
{
|
||||
u32 _var = 0;
|
||||
ReadFromHardware2(_var, 32, _Address, _Address, FLAG_NO_EXCEPTION);
|
||||
return _var;
|
||||
}
|
||||
|
||||
void WriteUnchecked_U8(const u8 _iValue, const u32 _Address)
|
||||
{
|
||||
WriteToHardware2(8, _Address, _iValue, _Address, FLAG_NO_EXCEPTION);
|
||||
}
|
||||
|
||||
|
||||
void WriteUnchecked_U32(const u32 _iValue, const u32 _Address)
|
||||
{
|
||||
WriteToHardware2(32, _Address, _iValue, _Address, FLAG_NO_EXCEPTION);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Other functions
|
||||
// ----------------
|
||||
void WriteBigEData(const u8 *_pData, const u32 _Address, const u32 _iSize)
|
||||
{
|
||||
memcpy(GetPointer(_Address), _pData, _iSize);
|
||||
@ -1110,261 +850,7 @@ bool IsRAMAddress(const u32 addr, bool allow_locked_cache)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// *********************************************************************************
|
||||
// Warning: Test Area
|
||||
//
|
||||
// This code is for TESTING and it works in interpreter mode ONLY. Some games (like
|
||||
// COD iirc) work thanks to this basic TLB emulation.
|
||||
// It is just a small hack and we have never spend enough time to finalize it.
|
||||
// Cheers PearPC!
|
||||
//
|
||||
// *********************************************************************************
|
||||
|
||||
/*
|
||||
* PearPC
|
||||
* ppc_mmu.cc
|
||||
*
|
||||
* Copyright (C) 2003, 2004 Sebastian Biallas (sb@biallas.net)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
|
||||
#define PPC_EXC_DSISR_PAGE (1<<30)
|
||||
#define PPC_EXC_DSISR_PROT (1<<27)
|
||||
#define PPC_EXC_DSISR_STORE (1<<25)
|
||||
|
||||
#define SDR1_HTABORG(v) (((v)>>16)&0xffff)
|
||||
#define SDR1_HTABMASK(v) ((v)&0x1ff)
|
||||
#define SDR1_PAGETABLE_BASE(v) ((v)&0xffff)
|
||||
#define SR_T (1<<31)
|
||||
#define SR_Ks (1<<30)
|
||||
#define SR_Kp (1<<29)
|
||||
#define SR_N (1<<28)
|
||||
#define SR_VSID(v) ((v)&0xffffff)
|
||||
#define SR_BUID(v) (((v)>>20)&0x1ff)
|
||||
#define SR_CNTRL_SPEC(v) ((v)&0xfffff)
|
||||
|
||||
#define EA_SR(v) (((v)>>28)&0xf)
|
||||
#define EA_PageIndex(v) (((v)>>12)&0xffff)
|
||||
#define EA_Offset(v) ((v)&0xfff)
|
||||
#define EA_API(v) (((v)>>22)&0x3f)
|
||||
|
||||
#define PA_RPN(v) (((v)>>12)&0xfffff)
|
||||
#define PA_Offset(v) ((v)&0xfff)
|
||||
|
||||
#define PTE1_V (1<<31)
|
||||
#define PTE1_VSID(v) (((v)>>7)&0xffffff)
|
||||
#define PTE1_H (1<<6)
|
||||
#define PTE1_API(v) ((v)&0x3f)
|
||||
|
||||
#define PTE2_RPN(v) ((v)&0xfffff000)
|
||||
#define PTE2_R (1<<8)
|
||||
#define PTE2_C (1<<7)
|
||||
#define PTE2_WIMG(v) (((v)>>3)&0xf)
|
||||
#define PTE2_PP(v) ((v)&3)
|
||||
|
||||
union UPTE1
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned API : 6;
|
||||
unsigned H : 1;
|
||||
unsigned VSID : 24;
|
||||
unsigned V : 1;
|
||||
};
|
||||
u32 Hex;
|
||||
};
|
||||
|
||||
union UPTE2
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned PP : 2;
|
||||
unsigned : 1;
|
||||
unsigned WIMG : 4;
|
||||
unsigned C : 1;
|
||||
unsigned R : 1;
|
||||
unsigned : 3;
|
||||
unsigned RPN : 20;
|
||||
};
|
||||
u32 Hex;
|
||||
};
|
||||
|
||||
u32 pagetable_base = 0;
|
||||
u32 pagetable_hashmask = 0;
|
||||
|
||||
void GenerateDSIException(u32 _EffectiveAdress, bool _bWrite)
|
||||
{
|
||||
if (_bWrite)
|
||||
PowerPC::ppcState.spr[SPR_DSISR] = PPC_EXC_DSISR_PAGE | PPC_EXC_DSISR_STORE;
|
||||
else
|
||||
PowerPC::ppcState.spr[SPR_DSISR] = PPC_EXC_DSISR_PAGE;
|
||||
|
||||
PowerPC::ppcState.spr[SPR_DAR] = _EffectiveAdress;
|
||||
|
||||
LOG(MEMMAP, "Generate DSI Exception 0x%08x", _EffectiveAdress);
|
||||
PowerPC::ppcState.Exceptions |= EXCEPTION_DSI;
|
||||
}
|
||||
|
||||
|
||||
void GenerateISIException()
|
||||
{
|
||||
// 4 bit for Set if the translation of an attempted access is not found in the primary hash table entry group
|
||||
// (HTEG), or in the rehashed secondary HTEG, or in the range of a DBAT register (page fault
|
||||
// condition); otherwise cleared.
|
||||
PowerPC::ppcState.spr[SPR_DSISR] = 0x4000000;
|
||||
LOG(MEMMAP, "Generate ISI Exception");
|
||||
PowerPC::ppcState.Exceptions |= EXCEPTION_ISI;
|
||||
}
|
||||
|
||||
|
||||
void SDRUpdated()
|
||||
{
|
||||
u32 htabmask = SDR1_HTABMASK(PowerPC::ppcState.spr[SPR_SDR]);
|
||||
u32 x = 1;
|
||||
u32 xx = 0;
|
||||
int n = 0;
|
||||
while ((htabmask & x) && (n < 9))
|
||||
{
|
||||
n++;
|
||||
xx|=x;
|
||||
x<<=1;
|
||||
}
|
||||
if (htabmask & ~xx)
|
||||
{
|
||||
return;
|
||||
}
|
||||
u32 htaborg = SDR1_HTABORG(PowerPC::ppcState.spr[SPR_SDR]);
|
||||
if (htaborg & xx)
|
||||
{
|
||||
return;
|
||||
}
|
||||
pagetable_base = htaborg<<16;
|
||||
pagetable_hashmask = ((xx<<10)|0x3ff);
|
||||
}
|
||||
|
||||
|
||||
u32 CheckDTLB(u32 _Address, XCheckTLBFlag _Flag)
|
||||
{
|
||||
//return 0;
|
||||
if (Core::GetStartupParameter().bWii) {
|
||||
// TLB is never used on Wii (except linux and stuff, but we don't care about that)
|
||||
PanicAlert("%s invalid memory region (0x%08x)\n\n"
|
||||
"There is no way to recover from this error,"
|
||||
"so Dolphin will now exit. Sorry!",
|
||||
_Flag == FLAG_WRITE ? "Write to" : "Read from", _Address);
|
||||
}
|
||||
else {
|
||||
PanicAlert("%s invalid memory region (0x%08x)\n\n"
|
||||
"This is either the game crashing randomly, or a TLB write."
|
||||
"Several games uses the TLB to map memory. This\n"
|
||||
"function is not supported in Dolphin. "
|
||||
"Unfortunately there is no way to recover from this error,"
|
||||
"so Dolphin will now exit abruptly. Sorry!",
|
||||
_Flag == FLAG_WRITE ? "Write to" : "Read from", _Address);
|
||||
}
|
||||
exit(0);
|
||||
u32 sr = PowerPC::ppcState.sr[EA_SR(_Address)];
|
||||
|
||||
u32 offset = EA_Offset(_Address); // 12 bit
|
||||
u32 page_index = EA_PageIndex(_Address); // 16 bit
|
||||
u32 VSID = SR_VSID(sr); // 24 bit
|
||||
u32 api = EA_API(_Address); // 6 bit (part of page_index)
|
||||
|
||||
u8* pRAM = GetPointer(0);
|
||||
|
||||
// hash function no 1 "xor" .360
|
||||
u32 hash1 = (VSID ^ page_index);
|
||||
u32 pteg_addr = ((hash1 & pagetable_hashmask)<<6) | pagetable_base;
|
||||
|
||||
// hash1
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
UPTE1 PTE1;
|
||||
PTE1.Hex = bswap(*(u32*)&pRAM[pteg_addr]);
|
||||
|
||||
if (PTE1.V && !PTE1.H)
|
||||
{
|
||||
if (VSID == PTE1.VSID && (api == PTE1.API))
|
||||
{
|
||||
UPTE2 PTE2;
|
||||
PTE2.Hex = bswap((*(u32*)&pRAM[(pteg_addr + 4)]));
|
||||
|
||||
// set the access bits
|
||||
switch (_Flag)
|
||||
{
|
||||
case FLAG_READ: PTE2.R = 1; break;
|
||||
case FLAG_WRITE: PTE2.C = 1; break;
|
||||
case FLAG_NO_EXCEPTION: break;
|
||||
case FLAG_OPCODE: break;
|
||||
}
|
||||
*(u32*)&pRAM[(pteg_addr + 4)] = bswap(PTE2.Hex);
|
||||
|
||||
return ((PTE2.RPN << 12) | offset);
|
||||
}
|
||||
}
|
||||
pteg_addr+=8;
|
||||
}
|
||||
|
||||
// hash function no 2 "not" .360
|
||||
hash1 = ~hash1;
|
||||
pteg_addr = ((hash1 & pagetable_hashmask)<<6) | pagetable_base;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
u32 pte = bswap(*(u32*)&pRAM[pteg_addr]);
|
||||
if ((pte & PTE1_V) && (pte & PTE1_H))
|
||||
{
|
||||
if (VSID == PTE1_VSID(pte) && (api == PTE1_API(pte)))
|
||||
{
|
||||
PanicAlert("TLB: Address found at the second hash function.\n"
|
||||
"i have never seen this before");
|
||||
|
||||
pte = bswap(*(u32*)&pRAM[(pteg_addr+4)]);
|
||||
|
||||
u32 physAddress = PTE2_RPN(pte) | offset;
|
||||
|
||||
// missing access bits
|
||||
return physAddress;
|
||||
}
|
||||
}
|
||||
pteg_addr+=8;
|
||||
}
|
||||
|
||||
|
||||
// exception generation
|
||||
switch(_Flag)
|
||||
{
|
||||
case FLAG_NO_EXCEPTION:
|
||||
break;
|
||||
|
||||
case FLAG_READ:
|
||||
GenerateDSIException(_Address, false);
|
||||
break;
|
||||
|
||||
case FLAG_WRITE:
|
||||
GenerateDSIException(_Address, true);
|
||||
break;
|
||||
|
||||
case FLAG_OPCODE:
|
||||
GenerateISIException();
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/////////////////////////////
|
||||
|
||||
|
||||
} // namespace
|
||||
|
@ -14,13 +14,22 @@
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#ifndef _MEMMAP_H
|
||||
#define _MEMMAP_H
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Includes
|
||||
// ----------------
|
||||
#include <string>
|
||||
|
||||
#include "Common.h"
|
||||
////////////////////////////
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Global declarations
|
||||
// ----------------
|
||||
class PointerWrap;
|
||||
|
||||
typedef void (HWCALL *writeFn8 )(const u8, const u32);
|
||||
@ -32,17 +41,20 @@ typedef void (HWCALL *readFn8 )(u8&, const u32);
|
||||
typedef void (HWCALL *readFn16)(u16&, const u32);
|
||||
typedef void (HWCALL *readFn32)(u32&, const u32);
|
||||
typedef void (HWCALL *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
|
||||
// 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
|
||||
|
||||
// The size should be 24mb only, but the RAM_MASK wouldn't work anymore
|
||||
enum
|
||||
{
|
||||
RAM_SIZE = 0x2000000,
|
||||
@ -62,6 +74,7 @@ namespace Memory
|
||||
#endif
|
||||
};
|
||||
|
||||
// Init and Shutdown
|
||||
bool IsInitialized();
|
||||
bool Init();
|
||||
bool Shutdown();
|
||||
@ -70,7 +83,9 @@ namespace Memory
|
||||
void Clear();
|
||||
bool AreMemoryBreakpointsActivated();
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// ONLY for use by GUI
|
||||
// ----------------
|
||||
u8 ReadUnchecked_U8(const u32 _Address);
|
||||
u32 ReadUnchecked_U32(const u32 _Address);
|
||||
|
||||
@ -96,8 +111,30 @@ namespace Memory
|
||||
}
|
||||
|
||||
u32 Read_Opcode(const u32 _Address);
|
||||
////////////////////////////////
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// For use by emulator
|
||||
// ----------------
|
||||
|
||||
// =================================
|
||||
/* Local byteswap shortcuts. They are placed inline so that they may hopefully be executed faster
|
||||
than otherwise */
|
||||
// ----------------
|
||||
inline u8 bswap(u8 val) {return val;}
|
||||
inline u16 bswap(u16 val) {return Common::swap16(val);}
|
||||
inline u32 bswap(u32 val) {return Common::swap32(val);}
|
||||
inline u64 bswap(u64 val) {return Common::swap64(val);}
|
||||
// =================
|
||||
|
||||
// =================================
|
||||
// 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);
|
||||
@ -116,9 +153,12 @@ namespace Memory
|
||||
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,
|
||||
@ -126,11 +166,12 @@ namespace Memory
|
||||
FLAG_WRITE,
|
||||
FLAG_OPCODE,
|
||||
};
|
||||
|
||||
u32 CheckDTLB(u32 _Address, XCheckTLBFlag _Flag);
|
||||
|
||||
extern u32 pagetable_base;
|
||||
extern u32 pagetable_hashmask;
|
||||
// ================
|
||||
|
||||
/////////////////////////////
|
||||
};
|
||||
|
||||
#endif
|
||||
|
688
Source/Core/Core/Src/HW/MemmapFunctions.cpp
Normal file
688
Source/Core/Core/Src/HW/MemmapFunctions.cpp
Normal file
@ -0,0 +1,688 @@
|
||||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Includes
|
||||
// ----------------
|
||||
#include "Common.h"
|
||||
#include "MemoryUtil.h"
|
||||
#include "MemArena.h"
|
||||
#include "ChunkFile.h"
|
||||
|
||||
#include "Memmap.h"
|
||||
#include "../Core.h"
|
||||
#include "../PowerPC/PowerPC.h"
|
||||
#include "../PowerPC/Jit64/Jit.h"
|
||||
#include "../PowerPC/Jit64/JitCache.h"
|
||||
#include "CPU.h"
|
||||
#include "PeripheralInterface.h"
|
||||
#include "DSP.h"
|
||||
#include "DVDInterface.h"
|
||||
#include "GPFifo.h"
|
||||
#include "VideoInterface.h"
|
||||
#include "SI.h"
|
||||
#include "EXI.h"
|
||||
#include "PixelEngine.h"
|
||||
#include "CommandProcessor.h"
|
||||
#include "AudioInterface.h"
|
||||
#include "MemoryInterface.h"
|
||||
#include "WII_IOB.h"
|
||||
#include "WII_IPC.h"
|
||||
|
||||
#include "../Debugger/Debugger_BreakPoints.h"
|
||||
#include "../Debugger/Debugger_SymbolMap.h"
|
||||
/////////////////////////////
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Declarations and definitions
|
||||
// ----------------
|
||||
namespace Memory
|
||||
{
|
||||
|
||||
// =================================
|
||||
// From Memmap.cpp
|
||||
// ----------------
|
||||
|
||||
// Pointers to low memory
|
||||
extern u8* m_pFakeVMEM;
|
||||
extern u8* m_pEXRAM; //wii
|
||||
extern u8* m_pEFB;
|
||||
|
||||
// Init
|
||||
extern bool m_IsInitialized;
|
||||
extern bool bFakeVMEM;
|
||||
|
||||
// Read and write shortcuts
|
||||
extern writeFn8 hwWrite8 [NUMHWMEMFUN];
|
||||
extern writeFn16 hwWrite16[NUMHWMEMFUN];
|
||||
extern writeFn32 hwWrite32[NUMHWMEMFUN];
|
||||
extern writeFn64 hwWrite64[NUMHWMEMFUN];
|
||||
|
||||
extern readFn8 hwRead8 [NUMHWMEMFUN];
|
||||
extern readFn16 hwRead16[NUMHWMEMFUN];
|
||||
extern readFn32 hwRead32[NUMHWMEMFUN];
|
||||
extern readFn64 hwRead64[NUMHWMEMFUN];
|
||||
|
||||
extern writeFn8 hwWriteWii8 [NUMHWMEMFUN];
|
||||
extern writeFn16 hwWriteWii16[NUMHWMEMFUN];
|
||||
extern writeFn32 hwWriteWii32[NUMHWMEMFUN];
|
||||
extern writeFn64 hwWriteWii64[NUMHWMEMFUN];
|
||||
|
||||
extern readFn8 hwReadWii8 [NUMHWMEMFUN];
|
||||
extern readFn16 hwReadWii16[NUMHWMEMFUN];
|
||||
extern readFn32 hwReadWii32[NUMHWMEMFUN];
|
||||
extern readFn64 hwReadWii64[NUMHWMEMFUN];
|
||||
|
||||
// ==============
|
||||
|
||||
|
||||
// ===============
|
||||
|
||||
/////////////////////////////
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Read and write
|
||||
// ----------------
|
||||
|
||||
|
||||
// =================================
|
||||
// The read and write macros that direct us to the right functions
|
||||
// ----------------
|
||||
/* Instructions: To test the TLB functions in F-Zero disable the "&& ((_Address & 0xFE000000)
|
||||
== 0x7e000000)" condition next to bFakeVMEM below. */
|
||||
// ----------------
|
||||
#define ReadFromHardware2(_var, _type, _Address, EffectiveAddress, flag) \
|
||||
{ \
|
||||
if ((_Address & 0xC8000000) == 0xC8000000) \
|
||||
if (_Address < 0xcc000000) \
|
||||
{ \
|
||||
_var = bswap((*(u##_type*)&m_pEFB[_Address & EFB_MASK])); \
|
||||
} \
|
||||
else if (_Address <= 0xcc009000) \
|
||||
hwRead##_type[(_Address>>HWSHIFT) & (NUMHWMEMFUN-1)](_var, _Address); \
|
||||
/* WIIMODE */ \
|
||||
else if (((_Address & 0xFF000000) == 0xCD000000) && \
|
||||
(_Address <= 0xcd009000)) \
|
||||
hwReadWii##_type[(_Address>>HWSHIFT) & (NUMHWMEMFUN-1)](_var, _Address); \
|
||||
else if (((_Address & 0xFFF00000) == 0xCD800000) && \
|
||||
(_Address <= 0xCD809000)) \
|
||||
WII_IOBridge::Read##_type(_var, _Address); \
|
||||
else \
|
||||
{ \
|
||||
/* Disabled because the debugger makes trouble with */ \
|
||||
/*_dbg_assert_(MEMMAP,0); */ \
|
||||
} \
|
||||
else if (((_Address & 0xF0000000) == 0x80000000) || \
|
||||
((_Address & 0xF0000000) == 0xC0000000) || \
|
||||
((_Address & 0xF0000000) == 0x00000000)) \
|
||||
_var = bswap((*(u##_type*)&m_pRAM[_Address & RAM_MASK])); \
|
||||
else if (((_Address & 0xF0000000) == 0x90000000) || \
|
||||
((_Address & 0xF0000000) == 0xD0000000) || \
|
||||
((_Address & 0xF0000000) == 0x10000000)) \
|
||||
_var = bswap((*(u##_type*)&m_pEXRAM[_Address & EXRAM_MASK])); \
|
||||
else if ((_Address >= 0xE0000000) && (_Address < (0xE0000000+L1_CACHE_SIZE))) \
|
||||
{ \
|
||||
_var = bswap((*(u##_type*)&m_pL1Cache[_Address & L1_CACHE_MASK])); \
|
||||
} \
|
||||
else if (_Address >= 0xE0000000) \
|
||||
PanicAlert("READ: Invalid address: %08x", _Address); \
|
||||
\
|
||||
/* If we get this far we may be in the TLB area */ \
|
||||
else \
|
||||
{ \
|
||||
/*if (bFakeVMEM && ((_Address & 0xFE000000) == 0x7e000000) )*/ \
|
||||
/*F-Zero:*/ if (bFakeVMEM) \
|
||||
{ \
|
||||
_var = bswap((*(u##_type*)&m_pFakeVMEM[_Address & FAKEVMEM_MASK])); \
|
||||
} \
|
||||
else {/* LOG(MEMMAP,"READ (unknown): %08x (PC: %08x)",_Address,PC);*/ \
|
||||
/*CCPU::EnableStepping(TRUE);*/ \
|
||||
/*PanicAlert("READ: Unknown Address", "1", MB_OK);*/ \
|
||||
u32 TmpAddress = CheckDTLB(EffectiveAddress, flag); \
|
||||
TmpAddress = (TmpAddress & 0xFFFFFFF0) | (_Address & 0xF); \
|
||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) \
|
||||
_var = bswap((*(u##_type*)&m_pRAM[TmpAddress & RAM_MASK])); \
|
||||
} \
|
||||
} \
|
||||
/* Debugging: CheckForBadAddresses##_type(_Address, _var, true);*/ \
|
||||
}
|
||||
|
||||
|
||||
#define WriteToHardware2(_type, _Address, _Data, EffectiveAddress, flag) \
|
||||
{ \
|
||||
/* Debugging: CheckForBadAddresses##_type(_Address, _Data, false);*/ \
|
||||
if ((_Address & 0xC8000000) == 0xC8000000) \
|
||||
{ \
|
||||
if (_Address < 0xcc000000) \
|
||||
{ \
|
||||
*(u##_type*)&m_pEFB[_Address & EFB_MASK] = bswap(_Data); \
|
||||
return; \
|
||||
} \
|
||||
else if (_Address <= 0xcc009000) { \
|
||||
hwWrite##_type[(_Address>>HWSHIFT) & (NUMHWMEMFUN-1)](_Data,_Address); \
|
||||
return; \
|
||||
} \
|
||||
/* WIIMODE */ \
|
||||
else if (((_Address & 0xFF000000) == 0xCD000000) && \
|
||||
(_Address <= 0xcd009000)) { \
|
||||
hwWriteWii##_type[(_Address>>HWSHIFT) & (NUMHWMEMFUN-1)](_Data,_Address); \
|
||||
return; \
|
||||
} \
|
||||
else if (((_Address & 0xFFF00000) == 0xCD800000) && \
|
||||
(_Address <= 0xCD809000)) { \
|
||||
WII_IOBridge::Write##_type(_Data,_Address); \
|
||||
return; \
|
||||
} \
|
||||
else { \
|
||||
LOG(MEMMAP, "hwwrite [%08x] := %08x (PC: %08x)", _Address, _Data, PC); \
|
||||
_dbg_assert_msg_(MEMMAP,0,"Memory - Unknown HW address %08x", _Address); \
|
||||
} \
|
||||
} \
|
||||
else if (((_Address & 0xF0000000) == 0x80000000) || \
|
||||
((_Address & 0xF0000000) == 0xC0000000) || \
|
||||
((_Address & 0xF0000000) == 0x00000000)) \
|
||||
{ \
|
||||
*(u##_type*)&m_pRAM[_Address & RAM_MASK] = bswap(_Data); \
|
||||
return; \
|
||||
} \
|
||||
else if (((_Address & 0xF0000000) == 0x90000000) || \
|
||||
((_Address & 0xF0000000) == 0xD0000000) || \
|
||||
((_Address & 0xF0000000) == 0x10000000)) \
|
||||
{ \
|
||||
*(u##_type*)&m_pEXRAM[_Address & EXRAM_MASK] = bswap(_Data); \
|
||||
return; \
|
||||
} \
|
||||
else if ((_Address >= 0xE0000000) && (_Address < (0xE0000000+L1_CACHE_SIZE))) \
|
||||
{ \
|
||||
*(u##_type*)&m_pL1Cache[_Address & L1_CACHE_MASK] = bswap(_Data); \
|
||||
return; \
|
||||
} \
|
||||
else if (_Address >= 0xE0000000) \
|
||||
{ \
|
||||
LOG(MEMMAP,"WRITE: Cache address out of bounds (addr: %08x data: %08x)",_Address,_Data); \
|
||||
/* PanicAlert("WRITE: Cache address %08x out of bounds", _Address); */ \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
/*if (bFakeVMEM && ((_Address & 0xFE000000) == 0x7e000000))*/ \
|
||||
/*F-Zero: */ if (bFakeVMEM) \
|
||||
{ \
|
||||
*(u##_type*)&m_pFakeVMEM[_Address & FAKEVMEM_MASK] = bswap(_Data); \
|
||||
return; \
|
||||
} \
|
||||
/* LOG(MEMMAP,"WRITE: %08x (PC: %08x)",_Address,PC);*/ \
|
||||
/*MessageBox(NULL, "WRITE: unknown Address", "1", MB_OK);*/ \
|
||||
/*CCPU::EnableStepping(TRUE);*/ \
|
||||
u32 tmpAddress = CheckDTLB(EffectiveAddress, flag); \
|
||||
tmpAddress = (tmpAddress & 0xFFFFFFF0) | (_Address & 0xF); \
|
||||
*(u##_type*)&m_pRAM[tmpAddress & RAM_MASK] = bswap(_Data); \
|
||||
} \
|
||||
}
|
||||
// =====================
|
||||
|
||||
|
||||
// =================================
|
||||
// These functions may be called by
|
||||
// ----------------
|
||||
u32 Read_Opcode(const u32 _Address)
|
||||
{
|
||||
#ifdef LOGGING
|
||||
if (_Address == 0x00000000)
|
||||
{
|
||||
PanicAlert("Program tried to read from [00000000]");
|
||||
return 0x00000000;
|
||||
}
|
||||
#endif
|
||||
|
||||
u32 _var = 0;
|
||||
ReadFromHardware2(_var, 32, _Address, _Address, FLAG_OPCODE);
|
||||
|
||||
return _var;
|
||||
}
|
||||
|
||||
u8 Read_U8(const u32 _Address)
|
||||
{
|
||||
u8 _var = (u8)0xAFFEAFFE;
|
||||
ReadFromHardware2(_var, 8, _Address, _Address, FLAG_READ);
|
||||
#ifndef NOCHECK
|
||||
TMemCheck *mc = MemChecks::GetMemCheck(_Address);
|
||||
if (mc)
|
||||
{
|
||||
mc->numHits++;
|
||||
mc->Action(_var, _Address,false,1,PC);
|
||||
}
|
||||
#endif
|
||||
return (u8)_var;
|
||||
}
|
||||
|
||||
u16 Read_U16(const u32 _Address)
|
||||
{
|
||||
u16 _var = 0;
|
||||
ReadFromHardware2(_var, 16, _Address, _Address, FLAG_READ);
|
||||
#ifndef NOCHECK
|
||||
TMemCheck *mc = MemChecks::GetMemCheck(_Address);
|
||||
if (mc)
|
||||
{
|
||||
mc->numHits++;
|
||||
mc->Action(_var, _Address,false,2,PC);
|
||||
}
|
||||
#endif
|
||||
return (u16)_var;
|
||||
}
|
||||
|
||||
u32 Read_U32(const u32 _Address)
|
||||
{
|
||||
#ifdef LOGGING
|
||||
if (_Address == 0x00000000)
|
||||
{
|
||||
//PanicAlert("Program tried to read from [00000000]");
|
||||
//return 0x00000000;
|
||||
}
|
||||
#endif
|
||||
|
||||
u32 _var = 0;
|
||||
ReadFromHardware2(_var, 32, _Address, _Address, FLAG_READ);
|
||||
#ifndef NOCHECK
|
||||
TMemCheck *mc = MemChecks::GetMemCheck(_Address);
|
||||
if (mc)
|
||||
{
|
||||
mc->numHits++;
|
||||
mc->Action(_var, _Address,false,4,PC);
|
||||
}
|
||||
#endif
|
||||
return _var;
|
||||
}
|
||||
|
||||
|
||||
u64 Read_U64(const u32 _Address)
|
||||
{
|
||||
u64 _var = 0;
|
||||
ReadFromHardware2(_var, 64, _Address, _Address, FLAG_READ);
|
||||
#ifndef NOCHECK
|
||||
TMemCheck *mc = MemChecks::GetMemCheck(_Address);
|
||||
if (mc)
|
||||
{
|
||||
mc->numHits++;
|
||||
mc->Action((u32)_var, _Address,false,8,PC);
|
||||
}
|
||||
#endif
|
||||
return _var;
|
||||
}
|
||||
|
||||
|
||||
void Write_U8(const u8 _Data, const u32 _Address)
|
||||
{
|
||||
#ifndef NOCHECK
|
||||
TMemCheck *mc = MemChecks::GetMemCheck(_Address);
|
||||
if (mc)
|
||||
{
|
||||
mc->numHits++;
|
||||
mc->Action(_Data,_Address,true,1,PC);
|
||||
}
|
||||
#endif
|
||||
WriteToHardware2(8, _Address, _Data, _Address, FLAG_WRITE);
|
||||
}
|
||||
|
||||
|
||||
void Write_U16(const u16 _Data, const u32 _Address)
|
||||
{
|
||||
#ifndef NOCHECK
|
||||
TMemCheck *mc = MemChecks::GetMemCheck(_Address);
|
||||
if (mc)
|
||||
{
|
||||
mc->numHits++;
|
||||
mc->Action(_Data,_Address,true,2,PC);
|
||||
}
|
||||
#endif
|
||||
|
||||
WriteToHardware2(16, _Address, _Data, _Address, FLAG_WRITE);
|
||||
}
|
||||
|
||||
|
||||
void Write_U32(const u32 _Data, const u32 _Address)
|
||||
{
|
||||
#ifndef NOCHECK
|
||||
TMemCheck *mc = MemChecks::GetMemCheck(_Address);
|
||||
if (mc)
|
||||
{
|
||||
mc->numHits++;
|
||||
mc->Action(_Data,_Address,true,4,PC);
|
||||
}
|
||||
#endif
|
||||
WriteToHardware2(32, _Address, _Data, _Address, FLAG_WRITE);
|
||||
}
|
||||
|
||||
|
||||
void WriteHW_U32(const u32 _Data, const u32 _Address)
|
||||
{
|
||||
hwWrite32[(_Address>>HWSHIFT) & (NUMHWMEMFUN-1)](_Data,_Address);
|
||||
}
|
||||
|
||||
|
||||
void Write_U64(const u64 _Data, const u32 _Address)
|
||||
{
|
||||
#ifndef NOCHECK
|
||||
TMemCheck *mc = MemChecks::GetMemCheck(_Address);
|
||||
if (mc)
|
||||
{
|
||||
mc->numHits++;
|
||||
mc->Action((u32)_Data,_Address,true,8,PC);
|
||||
}
|
||||
#endif
|
||||
|
||||
WriteToHardware2(64, _Address, _Data, _Address + 4, FLAG_WRITE);
|
||||
}
|
||||
|
||||
|
||||
u8 ReadUnchecked_U8(const u32 _Address)
|
||||
{
|
||||
u8 _var = (u8)0xAFFEAFFE;
|
||||
ReadFromHardware2(_var, 8, _Address, _Address, FLAG_NO_EXCEPTION);
|
||||
return (u8)_var;
|
||||
}
|
||||
|
||||
|
||||
u32 ReadUnchecked_U32(const u32 _Address)
|
||||
{
|
||||
u32 _var = 0;
|
||||
ReadFromHardware2(_var, 32, _Address, _Address, FLAG_NO_EXCEPTION);
|
||||
return _var;
|
||||
}
|
||||
|
||||
void WriteUnchecked_U8(const u8 _iValue, const u32 _Address)
|
||||
{
|
||||
WriteToHardware2(8, _Address, _iValue, _Address, FLAG_NO_EXCEPTION);
|
||||
}
|
||||
|
||||
|
||||
void WriteUnchecked_U32(const u32 _iValue, const u32 _Address)
|
||||
{
|
||||
WriteToHardware2(32, _Address, _iValue, _Address, FLAG_NO_EXCEPTION);
|
||||
}
|
||||
// =====================
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
|
||||
// *********************************************************************************
|
||||
// Warning: Test Area
|
||||
//
|
||||
// This code is for TESTING and it works in interpreter mode ONLY. Some games (like
|
||||
// COD iirc) work thanks to this basic TLB emulation.
|
||||
// It is just a small hack and we have never spend enough time to finalize it.
|
||||
// Cheers PearPC!
|
||||
//
|
||||
// *********************************************************************************
|
||||
|
||||
/*
|
||||
* PearPC
|
||||
* ppc_mmu.cc
|
||||
*
|
||||
* Copyright (C) 2003, 2004 Sebastian Biallas (sb@biallas.net)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
|
||||
#define PPC_EXC_DSISR_PAGE (1<<30)
|
||||
#define PPC_EXC_DSISR_PROT (1<<27)
|
||||
#define PPC_EXC_DSISR_STORE (1<<25)
|
||||
|
||||
#define SDR1_HTABORG(v) (((v)>>16)&0xffff)
|
||||
#define SDR1_HTABMASK(v) ((v)&0x1ff)
|
||||
#define SDR1_PAGETABLE_BASE(v) ((v)&0xffff)
|
||||
#define SR_T (1<<31)
|
||||
#define SR_Ks (1<<30)
|
||||
#define SR_Kp (1<<29)
|
||||
#define SR_N (1<<28)
|
||||
#define SR_VSID(v) ((v)&0xffffff)
|
||||
#define SR_BUID(v) (((v)>>20)&0x1ff)
|
||||
#define SR_CNTRL_SPEC(v) ((v)&0xfffff)
|
||||
|
||||
#define EA_SR(v) (((v)>>28)&0xf)
|
||||
#define EA_PageIndex(v) (((v)>>12)&0xffff)
|
||||
#define EA_Offset(v) ((v)&0xfff)
|
||||
#define EA_API(v) (((v)>>22)&0x3f)
|
||||
|
||||
#define PA_RPN(v) (((v)>>12)&0xfffff)
|
||||
#define PA_Offset(v) ((v)&0xfff)
|
||||
|
||||
#define PTE1_V (1<<31)
|
||||
#define PTE1_VSID(v) (((v)>>7)&0xffffff)
|
||||
#define PTE1_H (1<<6)
|
||||
#define PTE1_API(v) ((v)&0x3f)
|
||||
|
||||
#define PTE2_RPN(v) ((v)&0xfffff000)
|
||||
#define PTE2_R (1<<8)
|
||||
#define PTE2_C (1<<7)
|
||||
#define PTE2_WIMG(v) (((v)>>3)&0xf)
|
||||
#define PTE2_PP(v) ((v)&3)
|
||||
|
||||
union UPTE1
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned API : 6;
|
||||
unsigned H : 1;
|
||||
unsigned VSID : 24;
|
||||
unsigned V : 1;
|
||||
};
|
||||
u32 Hex;
|
||||
};
|
||||
|
||||
union UPTE2
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned PP : 2;
|
||||
unsigned : 1;
|
||||
unsigned WIMG : 4;
|
||||
unsigned C : 1;
|
||||
unsigned R : 1;
|
||||
unsigned : 3;
|
||||
unsigned RPN : 20;
|
||||
};
|
||||
u32 Hex;
|
||||
};
|
||||
|
||||
u32 pagetable_base = 0;
|
||||
u32 pagetable_hashmask = 0;
|
||||
|
||||
void GenerateDSIException(u32 _EffectiveAdress, bool _bWrite)
|
||||
{
|
||||
if (_bWrite)
|
||||
PowerPC::ppcState.spr[SPR_DSISR] = PPC_EXC_DSISR_PAGE | PPC_EXC_DSISR_STORE;
|
||||
else
|
||||
PowerPC::ppcState.spr[SPR_DSISR] = PPC_EXC_DSISR_PAGE;
|
||||
|
||||
PowerPC::ppcState.spr[SPR_DAR] = _EffectiveAdress;
|
||||
|
||||
LOG(MEMMAP, "Generate DSI Exception 0x%08x", _EffectiveAdress);
|
||||
PowerPC::ppcState.Exceptions |= EXCEPTION_DSI;
|
||||
}
|
||||
|
||||
|
||||
void GenerateISIException()
|
||||
{
|
||||
// 4 bit for Set if the translation of an attempted access is not found in the primary hash table entry group
|
||||
// (HTEG), or in the rehashed secondary HTEG, or in the range of a DBAT register (page fault
|
||||
// condition); otherwise cleared.
|
||||
PowerPC::ppcState.spr[SPR_DSISR] = 0x4000000;
|
||||
LOG(MEMMAP, "Generate ISI Exception");
|
||||
PowerPC::ppcState.Exceptions |= EXCEPTION_ISI;
|
||||
}
|
||||
|
||||
|
||||
void SDRUpdated()
|
||||
{
|
||||
u32 htabmask = SDR1_HTABMASK(PowerPC::ppcState.spr[SPR_SDR]);
|
||||
u32 x = 1;
|
||||
u32 xx = 0;
|
||||
int n = 0;
|
||||
while ((htabmask & x) && (n < 9))
|
||||
{
|
||||
n++;
|
||||
xx|=x;
|
||||
x<<=1;
|
||||
}
|
||||
if (htabmask & ~xx)
|
||||
{
|
||||
return;
|
||||
}
|
||||
u32 htaborg = SDR1_HTABORG(PowerPC::ppcState.spr[SPR_SDR]);
|
||||
if (htaborg & xx)
|
||||
{
|
||||
return;
|
||||
}
|
||||
pagetable_base = htaborg<<16;
|
||||
pagetable_hashmask = ((xx<<10)|0x3ff);
|
||||
}
|
||||
|
||||
|
||||
u32 CheckDTLB(u32 _Address, XCheckTLBFlag _Flag)
|
||||
{
|
||||
// Don't show the warnings if we are testing this code
|
||||
if(!bFakeVMEM)
|
||||
{
|
||||
if (Core::GetStartupParameter().bWii) {
|
||||
// TLB is never used on Wii (except linux and stuff, but we don't care about that)
|
||||
PanicAlert("%s invalid memory region (0x%08x)\n\n"
|
||||
"There is no way to recover from this error,"
|
||||
"so Dolphin will now exit. Sorry!",
|
||||
_Flag == FLAG_WRITE ? "Write to" : "Read from", _Address);
|
||||
}
|
||||
else {
|
||||
PanicAlert("%s invalid memory region (0x%08x)\n\n"
|
||||
"This is either the game crashing randomly, or a TLB write."
|
||||
"Several games uses the TLB to map memory. This\n"
|
||||
"function is not supported in Dolphin. "
|
||||
"Unfortunately there is no way to recover from this error,"
|
||||
"so Dolphin will now exit abruptly. Sorry!",
|
||||
_Flag == FLAG_WRITE ? "Write to" : "Read from", _Address);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
u32 sr = PowerPC::ppcState.sr[EA_SR(_Address)];
|
||||
|
||||
u32 offset = EA_Offset(_Address); // 12 bit
|
||||
u32 page_index = EA_PageIndex(_Address); // 16 bit
|
||||
u32 VSID = SR_VSID(sr); // 24 bit
|
||||
u32 api = EA_API(_Address); // 6 bit (part of page_index)
|
||||
|
||||
u8* pRAM = GetPointer(0);
|
||||
|
||||
// hash function no 1 "xor" .360
|
||||
u32 hash1 = (VSID ^ page_index);
|
||||
u32 pteg_addr = ((hash1 & pagetable_hashmask)<<6) | pagetable_base;
|
||||
|
||||
// hash1
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
UPTE1 PTE1;
|
||||
PTE1.Hex = bswap(*(u32*)&pRAM[pteg_addr]);
|
||||
|
||||
if (PTE1.V && !PTE1.H)
|
||||
{
|
||||
if (VSID == PTE1.VSID && (api == PTE1.API))
|
||||
{
|
||||
UPTE2 PTE2;
|
||||
PTE2.Hex = bswap((*(u32*)&pRAM[(pteg_addr + 4)]));
|
||||
|
||||
// set the access bits
|
||||
switch (_Flag)
|
||||
{
|
||||
case FLAG_READ: PTE2.R = 1; break;
|
||||
case FLAG_WRITE: PTE2.C = 1; break;
|
||||
case FLAG_NO_EXCEPTION: break;
|
||||
case FLAG_OPCODE: break;
|
||||
}
|
||||
*(u32*)&pRAM[(pteg_addr + 4)] = bswap(PTE2.Hex);
|
||||
|
||||
return ((PTE2.RPN << 12) | offset);
|
||||
}
|
||||
}
|
||||
pteg_addr+=8;
|
||||
}
|
||||
|
||||
// hash function no 2 "not" .360
|
||||
hash1 = ~hash1;
|
||||
pteg_addr = ((hash1 & pagetable_hashmask)<<6) | pagetable_base;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
u32 pte = bswap(*(u32*)&pRAM[pteg_addr]);
|
||||
if ((pte & PTE1_V) && (pte & PTE1_H))
|
||||
{
|
||||
if (VSID == PTE1_VSID(pte) && (api == PTE1_API(pte)))
|
||||
{
|
||||
PanicAlert("TLB: Address found at the second hash function.\n"
|
||||
"i have never seen this before");
|
||||
|
||||
pte = bswap(*(u32*)&pRAM[(pteg_addr+4)]);
|
||||
|
||||
u32 physAddress = PTE2_RPN(pte) | offset;
|
||||
|
||||
// missing access bits
|
||||
return physAddress;
|
||||
}
|
||||
}
|
||||
pteg_addr+=8;
|
||||
}
|
||||
|
||||
|
||||
// If we got this far something went wrong and we save the exception data
|
||||
switch(_Flag)
|
||||
{
|
||||
case FLAG_NO_EXCEPTION:
|
||||
break;
|
||||
|
||||
case FLAG_READ:
|
||||
GenerateDSIException(_Address, false);
|
||||
break;
|
||||
|
||||
case FLAG_WRITE:
|
||||
GenerateDSIException(_Address, true);
|
||||
break;
|
||||
|
||||
case FLAG_OPCODE:
|
||||
GenerateISIException();
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
// ***********************
|
||||
|
||||
|
||||
} // namespace
|
@ -44,6 +44,7 @@ files = ["Console.cpp",
|
||||
"HW/GPFifo.cpp",
|
||||
"HW/HW.cpp",
|
||||
"HW/Memmap.cpp",
|
||||
"HW/MemmapFunctions.cpp",
|
||||
"HW/MemoryInterface.cpp",
|
||||
"HW/PeripheralInterface.cpp",
|
||||
"HW/PixelEngine.cpp",
|
||||
|
Loading…
Reference in New Issue
Block a user