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"
|
RelativePath=".\Src\Hw\Memmap.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\Src\HW\MemmapFunctions.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\Src\HW\SystemTimers.cpp"
|
RelativePath=".\Src\HW\SystemTimers.cpp"
|
||||||
>
|
>
|
||||||
|
|
|
@ -15,6 +15,21 @@
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// 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 "Common.h"
|
||||||
#include "MemoryUtil.h"
|
#include "MemoryUtil.h"
|
||||||
#include "MemArena.h"
|
#include "MemArena.h"
|
||||||
|
@ -42,26 +57,44 @@
|
||||||
#include "../ConfigManager.h"
|
#include "../ConfigManager.h"
|
||||||
#include "../Debugger/Debugger_BreakPoints.h"
|
#include "../Debugger/Debugger_BreakPoints.h"
|
||||||
#include "../Debugger/Debugger_SymbolMap.h"
|
#include "../Debugger/Debugger_SymbolMap.h"
|
||||||
|
/////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Declarations and definitions
|
||||||
|
// ----------------
|
||||||
namespace Memory
|
namespace Memory
|
||||||
{
|
{
|
||||||
|
|
||||||
// GLOBAL DEFINES
|
// =================================
|
||||||
|
// LOCAL SETTINGS
|
||||||
|
// ----------------
|
||||||
|
|
||||||
|
// Disable Memory Checks
|
||||||
// #define NOCHECK
|
// #define NOCHECK
|
||||||
|
|
||||||
// TLBHack = 1 in a patch ini will set this to true.
|
// Always disable memory checks if the Release build
|
||||||
static bool bFakeVMEM = false;
|
|
||||||
|
|
||||||
#ifndef LOGGING
|
#ifndef LOGGING
|
||||||
#define NOCHECK
|
#define NOCHECK
|
||||||
#endif
|
#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;
|
u8* base = NULL;
|
||||||
|
|
||||||
|
// The MemArena class
|
||||||
|
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
|
// Pointers to low memory
|
||||||
|
@ -70,9 +103,7 @@ u8* m_pFakeVMEM = NULL;
|
||||||
u8* m_pEXRAM = NULL; //wii
|
u8* m_pEXRAM = NULL; //wii
|
||||||
u8* m_pEFB = NULL;
|
u8* m_pEFB = NULL;
|
||||||
u8* m_pL1Cache = NULL;
|
u8* m_pL1Cache = NULL;
|
||||||
bool m_IsInitialized = false;
|
bool m_IsInitialized = false; // Save the Init(), Shutdown() state
|
||||||
|
|
||||||
MemArena g_arena;
|
|
||||||
|
|
||||||
// Pointers into the "View" (rarely used)
|
// Pointers into the "View" (rarely used)
|
||||||
u8* m_pPhysicalFakeVMEM;
|
u8* m_pPhysicalFakeVMEM;
|
||||||
|
@ -85,10 +116,9 @@ u8* m_pVirtualUncachedEXRAM;
|
||||||
u8* m_pVirtualEFB;
|
u8* m_pVirtualEFB;
|
||||||
u8* m_pVirtualL1Cache;
|
u8* m_pVirtualL1Cache;
|
||||||
|
|
||||||
#define NUMHWMEMFUN 64
|
// =================================
|
||||||
#define HWSHIFT 10
|
// Read and write shortcuts
|
||||||
#define HW_MASK 0x3FF
|
// ----------------
|
||||||
|
|
||||||
writeFn8 hwWrite8 [NUMHWMEMFUN];
|
writeFn8 hwWrite8 [NUMHWMEMFUN];
|
||||||
writeFn16 hwWrite16[NUMHWMEMFUN];
|
writeFn16 hwWrite16[NUMHWMEMFUN];
|
||||||
writeFn32 hwWrite32[NUMHWMEMFUN];
|
writeFn32 hwWrite32[NUMHWMEMFUN];
|
||||||
|
@ -108,13 +138,14 @@ readFn8 hwReadWii8 [NUMHWMEMFUN];
|
||||||
readFn16 hwReadWii16[NUMHWMEMFUN];
|
readFn16 hwReadWii16[NUMHWMEMFUN];
|
||||||
readFn32 hwReadWii32[NUMHWMEMFUN];
|
readFn32 hwReadWii32[NUMHWMEMFUN];
|
||||||
readFn64 hwReadWii64[NUMHWMEMFUN];
|
readFn64 hwReadWii64[NUMHWMEMFUN];
|
||||||
|
// ===============
|
||||||
|
|
||||||
|
/////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
inline u8 bswap(u8 val) {return val;}
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
inline u16 bswap(u16 val) {return Common::swap16(val);}
|
// Default read and write functions
|
||||||
inline u32 bswap(u32 val) {return Common::swap32(val);}
|
// ----------------
|
||||||
inline u64 bswap(u64 val) {return Common::swap64(val);}
|
|
||||||
|
|
||||||
u32 CheckDTLB(u32 _Address, XCheckTLBFlag _Flag);
|
u32 CheckDTLB(u32 _Address, XCheckTLBFlag _Flag);
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
|
@ -123,15 +154,20 @@ void HWCALL HW_Default_Write(const T _Data, const u32 _Address){ LOG(MASTER_LOG,
|
||||||
template <class T>
|
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);}
|
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_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 HWCALL HW_Read_Memory(T &_Data, const u32 _Address) { _Data = *(T*)&P[_Address & PAGE_MASK]; }
|
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; }
|
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 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
|
||||||
|
@ -146,6 +182,7 @@ template <class T, u8* P> void HWCALL HW_Write_Memory(T _Data, const u32 _Addres
|
||||||
#define AUDIO_START 0x1B
|
#define AUDIO_START 0x1B
|
||||||
#define GP_START 0x20
|
#define GP_START 0x20
|
||||||
|
|
||||||
|
|
||||||
void InitHWMemFuncs()
|
void InitHWMemFuncs()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < NUMHWMEMFUN; i++)
|
for (int i = 0; i < NUMHWMEMFUN; i++)
|
||||||
|
@ -292,279 +329,17 @@ void InitHWMemFuncsWii()
|
||||||
hwWriteWii32[AUDIO_START] = AudioInterface::Write32;
|
hwWriteWii32[AUDIO_START] = AudioInterface::Write32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
writeFn32 GetHWWriteFun32(const u32 _Address)
|
writeFn32 GetHWWriteFun32(const u32 _Address)
|
||||||
{
|
{
|
||||||
return hwWrite32[(_Address >> HWSHIFT) & (NUMHWMEMFUN-1)];
|
return hwWrite32[(_Address >> HWSHIFT) & (NUMHWMEMFUN-1)];
|
||||||
}
|
}
|
||||||
|
/////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Init and Shutdown
|
||||||
|
// ----------------
|
||||||
// =======================================================
|
|
||||||
/* 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); \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool IsInitialized()
|
bool IsInitialized()
|
||||||
{
|
{
|
||||||
return m_IsInitialized;
|
return m_IsInitialized;
|
||||||
|
@ -761,184 +536,149 @@ u32 Read_Instruction(const u32 em_address)
|
||||||
{
|
{
|
||||||
return jit.GetBlockCache()->GetOriginalCode(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
|
switch (_Address >> 24)
|
||||||
if (_Address == 0x00000000)
|
|
||||||
{
|
{
|
||||||
PanicAlert("Program tried to read from [00000000]");
|
case 0x00:
|
||||||
return 0x00000000;
|
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
|
return false;
|
||||||
|
|
||||||
u32 _var = 0;
|
|
||||||
ReadFromHardware2(_var, 32, _Address, _Address, FLAG_OPCODE);
|
|
||||||
|
|
||||||
return _var;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 Read_U8(const u32 _Address)
|
void CheckForBadAddresses(u32 Address, u32 Data, bool Read, int Bits)
|
||||||
{
|
{
|
||||||
u8 _var = (u8)0xAFFEAFFE;
|
if (!ValidMemory(Address))
|
||||||
ReadFromHardware2(_var, 8, _Address, _Address, FLAG_READ);
|
{
|
||||||
#ifndef NOCHECK
|
if(Read)
|
||||||
TMemCheck *mc = MemChecks::GetMemCheck(_Address);
|
{
|
||||||
if (mc)
|
LOG(CONSOLE, "Read%i: Program tried to read [%08x] from [%08x]", Bits, Address);
|
||||||
{
|
//PanicAlert("Write_U32: Program tried to write [%08x] to [%08x]", _Address);
|
||||||
mc->numHits++;
|
}
|
||||||
mc->Action(_var, _Address,false,1,PC);
|
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;
|
if(Read)
|
||||||
ReadFromHardware2(_var, 16, _Address, _Address, FLAG_READ);
|
{
|
||||||
#ifndef NOCHECK
|
LOGV(CONSOLE, 1, "Read%i: Program read [0x%08x] from [0x%08x] * * * 0 * * *", Bits, Data, Address);
|
||||||
TMemCheck *mc = MemChecks::GetMemCheck(_Address);
|
//PanicAlert("Read: Program read [%08x] from [%08x]", Data, Address);
|
||||||
if (mc)
|
}
|
||||||
{
|
else
|
||||||
mc->numHits++;
|
{
|
||||||
mc->Action(_var, _Address,false,2,PC);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
/* Try to figure out where the dev/di Ioctl arguments are stored (including buffer out), so we can
|
||||||
return (u16)_var;
|
find the bad one */
|
||||||
}
|
if(
|
||||||
|
Data == 0x1090f4c0 // good out buffer right before it, for sound/smashbros_sound.brsar
|
||||||
u32 Read_U32(const u32 _Address)
|
|| Data == 0x10913b00 // second one
|
||||||
{
|
|| Data == 0x7fd5d340 // first bad out buffer
|
||||||
#ifdef LOGGING
|
|| Data == 0x133e00f8 // the address that store the bad 0x7fd5d340, this changes every time
|
||||||
if (_Address == 0x00000000)
|
|| Data == 0x2a24aa // menu2\sc_title_en.pac byte size
|
||||||
{
|
|| (
|
||||||
//PanicAlert("Program tried to read from [00000000]");
|
(PC == 0x8021347c || PC == 0x801f6a20 || PC == 0x800202d0 || PC == 0x80229964
|
||||||
//return 0x00000000;
|
|| 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)
|
void CheckForBadAddresses8(u32 Address, u8 Data, bool Read)
|
||||||
{
|
{CheckForBadAddresses(Address, (u32)Data, Read, 8);}
|
||||||
u64 _var = 0;
|
|
||||||
ReadFromHardware2(_var, 64, _Address, _Address, FLAG_READ);
|
void CheckForBadAddresses16(u32 Address, u16 Data, bool Read)
|
||||||
#ifndef NOCHECK
|
{CheckForBadAddresses(Address, (u32)Data, Read, 16);}
|
||||||
TMemCheck *mc = MemChecks::GetMemCheck(_Address);
|
|
||||||
if (mc)
|
void CheckForBadAddresses32(u32 Address, u32 Data, bool Read)
|
||||||
{
|
{CheckForBadAddresses(Address, (u32)Data, Read, 32);}
|
||||||
mc->numHits++;
|
|
||||||
mc->Action((u32)_var, _Address,false,8,PC);
|
void CheckForBadAddresses64(u32 Address, u64 Data, bool Read)
|
||||||
}
|
{CheckForBadAddresses(Address, (u32)Data, Read, 64);}
|
||||||
#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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// 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);
|
||||||
|
@ -1110,261 +850,7 @@ bool IsRAMAddress(const u32 addr, bool allow_locked_cache)
|
||||||
return false;
|
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
|
} // namespace
|
||||||
|
|
|
@ -14,13 +14,22 @@
|
||||||
|
|
||||||
// Official SVN repository and contact information can be found at
|
// Official SVN repository and contact information can be found at
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#ifndef _MEMMAP_H
|
#ifndef _MEMMAP_H
|
||||||
#define _MEMMAP_H
|
#define _MEMMAP_H
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Includes
|
||||||
|
// ----------------
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Global declarations
|
||||||
|
// ----------------
|
||||||
class PointerWrap;
|
class PointerWrap;
|
||||||
|
|
||||||
typedef void (HWCALL *writeFn8 )(const u8, const u32);
|
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 *readFn16)(u16&, const u32);
|
||||||
typedef void (HWCALL *readFn32)(u32&, const u32);
|
typedef void (HWCALL *readFn32)(u32&, const u32);
|
||||||
typedef void (HWCALL *readFn64)(u64&, const u32);
|
typedef void (HWCALL *readFn64)(u64&, const u32);
|
||||||
|
////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
namespace Memory
|
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.
|
// 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,
|
// on 32-bit, you have to mask your offsets with 0x3FFFFFFF. This means that some things are mirrored,
|
||||||
// but eh... it works.
|
// but eh... it works.
|
||||||
extern u8 *base;
|
extern u8 *base;
|
||||||
extern u8* m_pRAM;
|
extern u8* m_pRAM;
|
||||||
extern u8* m_pL1Cache;
|
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
|
enum
|
||||||
{
|
{
|
||||||
RAM_SIZE = 0x2000000,
|
RAM_SIZE = 0x2000000,
|
||||||
|
@ -57,11 +69,12 @@ namespace Memory
|
||||||
IO_SIZE = 0x10000,
|
IO_SIZE = 0x10000,
|
||||||
EXRAM_SIZE = 0x4000000,
|
EXRAM_SIZE = 0x4000000,
|
||||||
EXRAM_MASK = 0x3FFFFFF,
|
EXRAM_MASK = 0x3FFFFFF,
|
||||||
#ifdef _M_IX86
|
#ifdef _M_IX86
|
||||||
MEMVIEW32_MASK = 0x3FFFFFFF,
|
MEMVIEW32_MASK = 0x3FFFFFFF,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Init and Shutdown
|
||||||
bool IsInitialized();
|
bool IsInitialized();
|
||||||
bool Init();
|
bool Init();
|
||||||
bool Shutdown();
|
bool Shutdown();
|
||||||
|
@ -70,7 +83,9 @@ namespace Memory
|
||||||
void Clear();
|
void Clear();
|
||||||
bool AreMemoryBreakpointsActivated();
|
bool AreMemoryBreakpointsActivated();
|
||||||
|
|
||||||
//ONLY for use by GUI
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// ONLY for use by GUI
|
||||||
|
// ----------------
|
||||||
u8 ReadUnchecked_U8(const u32 _Address);
|
u8 ReadUnchecked_U8(const u32 _Address);
|
||||||
u32 ReadUnchecked_U32(const u32 _Address);
|
u32 ReadUnchecked_U32(const u32 _Address);
|
||||||
|
|
||||||
|
@ -88,16 +103,38 @@ namespace Memory
|
||||||
inline u8* GetMainRAMPtr() {return m_pRAM;}
|
inline u8* GetMainRAMPtr() {return m_pRAM;}
|
||||||
inline u32 ReadFast32(const u32 _Address)
|
inline u32 ReadFast32(const u32 _Address)
|
||||||
{
|
{
|
||||||
#ifdef _M_IX86
|
#ifdef _M_IX86
|
||||||
return Common::swap32(*(u32 *)(base + (_Address & MEMVIEW32_MASK))); //ReadUnchecked_U32(_Address);
|
return Common::swap32(*(u32 *)(base + (_Address & MEMVIEW32_MASK))); // ReadUnchecked_U32(_Address);
|
||||||
#elif defined(_M_X64)
|
#elif defined(_M_X64)
|
||||||
return Common::swap32(*(u32 *)(base + _Address));
|
return Common::swap32(*(u32 *)(base + _Address));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 Read_Opcode(const u32 _Address);
|
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
|
||||||
|
|
||||||
//For use by emulator
|
|
||||||
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);
|
||||||
|
@ -116,9 +153,12 @@ namespace Memory
|
||||||
void DMA_LCToMemory(const u32 _iMemAddr, const u32 _iCacheAddr, const u32 _iNumBlocks);
|
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 DMA_MemoryToLC(const u32 _iCacheAddr, const u32 _iMemAddr, const u32 _iNumBlocks);
|
||||||
void Memset(const u32 _Address, const u8 _Data, const u32 _iLength);
|
void Memset(const u32 _Address, const u8 _Data, const u32 _iLength);
|
||||||
|
// =================
|
||||||
|
|
||||||
|
// =================================
|
||||||
|
// TLB functions
|
||||||
|
// ----------------
|
||||||
void SDRUpdated();
|
void SDRUpdated();
|
||||||
|
|
||||||
enum XCheckTLBFlag
|
enum XCheckTLBFlag
|
||||||
{
|
{
|
||||||
FLAG_NO_EXCEPTION,
|
FLAG_NO_EXCEPTION,
|
||||||
|
@ -126,11 +166,12 @@ namespace Memory
|
||||||
FLAG_WRITE,
|
FLAG_WRITE,
|
||||||
FLAG_OPCODE,
|
FLAG_OPCODE,
|
||||||
};
|
};
|
||||||
|
|
||||||
u32 CheckDTLB(u32 _Address, XCheckTLBFlag _Flag);
|
u32 CheckDTLB(u32 _Address, XCheckTLBFlag _Flag);
|
||||||
|
|
||||||
extern u32 pagetable_base;
|
extern u32 pagetable_base;
|
||||||
extern u32 pagetable_hashmask;
|
extern u32 pagetable_hashmask;
|
||||||
|
// ================
|
||||||
|
|
||||||
|
/////////////////////////////
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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/GPFifo.cpp",
|
||||||
"HW/HW.cpp",
|
"HW/HW.cpp",
|
||||||
"HW/Memmap.cpp",
|
"HW/Memmap.cpp",
|
||||||
|
"HW/MemmapFunctions.cpp",
|
||||||
"HW/MemoryInterface.cpp",
|
"HW/MemoryInterface.cpp",
|
||||||
"HW/PeripheralInterface.cpp",
|
"HW/PeripheralInterface.cpp",
|
||||||
"HW/PixelEngine.cpp",
|
"HW/PixelEngine.cpp",
|
||||||
|
|
Loading…
Reference in New Issue