diff --git a/Source/Core/Core/Core.vcproj b/Source/Core/Core/Core.vcproj
index 05a2e17a54..af0d405876 100644
--- a/Source/Core/Core/Core.vcproj
+++ b/Source/Core/Core/Core.vcproj
@@ -527,6 +527,10 @@
RelativePath=".\Src\Hw\Memmap.h"
>
+
+
diff --git a/Source/Core/Core/Src/HW/Memmap.cpp b/Source/Core/Core/Src/HW/Memmap.cpp
index b991b65bd2..3b4f4a682e 100644
--- a/Source/Core/Core/Src/HW/Memmap.cpp
+++ b/Source/Core/Core/Src/HW/Memmap.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
+ .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
@@ -123,15 +154,20 @@ void HWCALL HW_Default_Write(const T _Data, const u32 _Address){ LOG(MASTER_LOG,
template
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 void HWCALL HW_Read_Memory(T &_Data, const u32 _Address) { _Data = *(T*)&P[_Address & PAGE_MASK]; }
template 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 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)
-{
- 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);
+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);
+ }
}
-#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);
+ 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);
+ }
}
-#endif
- return (u16)_var;
-}
-
-u32 Read_U32(const u32 _Address)
-{
-#ifdef LOGGING
- if (_Address == 0x00000000)
- {
- //PanicAlert("Program tried to read from [00000000]");
- //return 0x00000000;
+ /* 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
diff --git a/Source/Core/Core/Src/HW/Memmap.h b/Source/Core/Core/Src/HW/Memmap.h
index 12b5e4822a..9105ee8409 100644
--- a/Source/Core/Core/Src/HW/Memmap.h
+++ b/Source/Core/Core/Src/HW/Memmap.h
@@ -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
-
#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,
@@ -57,11 +69,12 @@ namespace Memory
IO_SIZE = 0x10000,
EXRAM_SIZE = 0x4000000,
EXRAM_MASK = 0x3FFFFFF,
-#ifdef _M_IX86
- MEMVIEW32_MASK = 0x3FFFFFFF,
-#endif
+ #ifdef _M_IX86
+ MEMVIEW32_MASK = 0x3FFFFFFF,
+ #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
+ ///////////////////////////////////////////////////////////////////////////////////
+ // ONLY for use by GUI
+ // ----------------
u8 ReadUnchecked_U8(const u32 _Address);
u32 ReadUnchecked_U32(const u32 _Address);
@@ -88,16 +103,38 @@ namespace Memory
inline u8* GetMainRAMPtr() {return m_pRAM;}
inline u32 ReadFast32(const u32 _Address)
{
-#ifdef _M_IX86
- return Common::swap32(*(u32 *)(base + (_Address & MEMVIEW32_MASK))); //ReadUnchecked_U32(_Address);
-#elif defined(_M_X64)
+ #ifdef _M_IX86
+ return Common::swap32(*(u32 *)(base + (_Address & MEMVIEW32_MASK))); // ReadUnchecked_U32(_Address);
+ #elif defined(_M_X64)
return Common::swap32(*(u32 *)(base + _Address));
-#endif
+ #endif
}
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);
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
diff --git a/Source/Core/Core/Src/HW/MemmapFunctions.cpp b/Source/Core/Core/Src/HW/MemmapFunctions.cpp
new file mode 100644
index 0000000000..4ed0846e7a
--- /dev/null
+++ b/Source/Core/Core/Src/HW/MemmapFunctions.cpp
@@ -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
\ No newline at end of file
diff --git a/Source/Core/Core/Src/SConscript b/Source/Core/Core/Src/SConscript
index 083fdd3219..9838f39e16 100644
--- a/Source/Core/Core/Src/SConscript
+++ b/Source/Core/Core/Src/SConscript
@@ -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",