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",