From 9d57903065a30ad261bfbd8005e4dd81927eb023 Mon Sep 17 00:00:00 2001 From: skidau Date: Sat, 11 Sep 2010 02:34:51 +0000 Subject: [PATCH] Emulation accuracy improvements * Implemented HID4.SBE flag * Implemented but disabled MSR[IR] and MSR[DR] * In-lined ISI exception calls * Fixed and verified exception handling according to docs * Code clean-up in the memory functions git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6199 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/Core/Src/HW/Memmap.cpp | 8 ----- Source/Core/Core/Src/HW/Memmap.h | 1 - Source/Core/Core/Src/HW/MemmapFunctions.cpp | 13 ++++--- Source/Core/Core/Src/PowerPC/Gekko.h | 24 +++++++++++++ Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp | 13 ++++++- .../Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp | 14 +++++++- Source/Core/Core/Src/PowerPC/PowerPC.cpp | 35 +++++++------------ Source/Core/Core/Src/PowerPC/PowerPC.h | 1 + 8 files changed, 71 insertions(+), 38 deletions(-) diff --git a/Source/Core/Core/Src/HW/Memmap.cpp b/Source/Core/Core/Src/HW/Memmap.cpp index 3966dc473f..f10f4cfe2f 100644 --- a/Source/Core/Core/Src/HW/Memmap.cpp +++ b/Source/Core/Core/Src/HW/Memmap.cpp @@ -501,14 +501,6 @@ void Write_Opcode_JIT(const u32 _Address, const u32 _Value) #endif } -void GenerateISIException_JIT(u32 _EffectiveAddress) -{ - GenerateISIException(_EffectiveAddress); - - // Remove the invalid instruction from the icache, forcing a recompile - Write_Opcode_JIT(_EffectiveAddress, JIT_ICACHE_INVALID_WORD); -} - void WriteBigEData(const u8 *_pData, const u32 _Address, const u32 _iSize) { memcpy(GetPointer(_Address), _pData, _iSize); diff --git a/Source/Core/Core/Src/HW/Memmap.h b/Source/Core/Core/Src/HW/Memmap.h index 01e023e36a..673ee032c2 100644 --- a/Source/Core/Core/Src/HW/Memmap.h +++ b/Source/Core/Core/Src/HW/Memmap.h @@ -177,7 +177,6 @@ u32 TranslateAddress(u32 _Address, XCheckTLBFlag _Flag); void InvalidateTLBEntry(u32 _Address); void GenerateDSIException(u32 _EffectiveAdress, bool _bWrite); void GenerateISIException(u32 _EffectiveAdress); -void GenerateISIException_JIT(u32 _EffectiveAdress); extern u32 pagetable_base; extern u32 pagetable_hashmask; diff --git a/Source/Core/Core/Src/HW/MemmapFunctions.cpp b/Source/Core/Core/Src/HW/MemmapFunctions.cpp index 3b8a6780ba..cf34a12f68 100644 --- a/Source/Core/Core/Src/HW/MemmapFunctions.cpp +++ b/Source/Core/Core/Src/HW/MemmapFunctions.cpp @@ -608,7 +608,6 @@ void GenerateDSIException(u32 _EffectiveAddress, bool _bWrite) void GenerateISIException(u32 _EffectiveAddress) { // Address of instruction could not be translated - SRR1 = (1 << 30) | (MSR & 0x3fffff); NPC = _EffectiveAddress; Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_ISI); @@ -892,8 +891,8 @@ u32 TranslateBlockAddress(const u32 addr, const XCheckTLBFlag _Flag) u32 result = 0; UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr); - // TODO: Check for enhanced mode before switching to Wii mode - int bats = Core::g_CoreStartupParameter.bWii?8:4; + // Check for enhanced mode (secondary BAT enable) using 8 BATs + int bats = (Core::g_CoreStartupParameter.bWii && HID4.SBE)?8:4; for (int i = 0; i < bats; i++) { if (_Flag != FLAG_OPCODE) @@ -944,9 +943,15 @@ u32 TranslateBlockAddress(const u32 addr, const XCheckTLBFlag _Flag) return 0; } +// Translate effective address using BAT or PAT. Returns 0 if the address cannot be translated. u32 TranslateAddress(const u32 _Address, const XCheckTLBFlag _Flag) { - // TODO: Check for MSR data/instruction address translation flag before translating + // Check MSR[IR] bit before translating instruction addresses. Rogue Leader clears IR and DR?? + //if ((_Flag == FLAG_OPCODE) && !(MSR & (1 << (31 - 26)))) return _Address; + + // Check MSR[DR] bit before translating data addresses + //if (((_Flag == FLAG_READ) || (_Flag == FLAG_WRITE)) && !(MSR & (1 << (31 - 27)))) return _Address; + u32 tlb_addr = Core::g_CoreStartupParameter.bMMUBAT?TranslateBlockAddress(_Address, _Flag):0; if (tlb_addr == 0) { diff --git a/Source/Core/Core/Src/PowerPC/Gekko.h b/Source/Core/Core/Src/PowerPC/Gekko.h index 0c9422b336..87915c3b84 100644 --- a/Source/Core/Core/Src/PowerPC/Gekko.h +++ b/Source/Core/Core/Src/PowerPC/Gekko.h @@ -456,6 +456,29 @@ union UReg_HID2 UReg_HID2() { Hex = 0; } }; +// Hardware Implementation-Dependent Register 4 +union UReg_HID4 +{ + struct + { + unsigned : 20; + unsigned L2CFI : 1; + unsigned L2MUM : 1; + unsigned DBP : 1; + unsigned LPE : 1; + unsigned ST0 : 1; + unsigned SBE : 1; + unsigned : 1; + unsigned BPD : 2; + unsigned L2FM : 2; + unsigned : 1; + }; + u32 Hex; + + UReg_HID4(u32 _hex) { Hex = _hex; } + UReg_HID4() { Hex = 0; } +}; + // SPR1 - Page Table format union UReg_SPR1 { @@ -637,6 +660,7 @@ enum SPR_HID0 = 1008, SPR_HID1 = 1009, SPR_HID2 = 920, + SPR_HID4 = 1011, SPR_WPAR = 921, SPR_DMAU = 922, SPR_DMAL = 923, diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp index 8db6e94bbf..d3baf4edd7 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp @@ -593,7 +593,18 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc if (memory_exception) { - ABI_CallFunctionC(reinterpret_cast(&Memory::GenerateISIException_JIT), js.compilerPC); + // Address of instruction could not be translated + MOV(32, M(&NPC), Imm32(js.compilerPC)); + OR(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_ISI)); + + // Remove the invalid instruction from the icache, forcing a recompile + if (js.compilerPC & JIT_ICACHE_VMEM_BIT) + MOV(32, M((jit->GetBlockCache()->GetICacheVMEM() + (js.compilerPC & JIT_ICACHE_MASK))), Imm32(JIT_ICACHE_INVALID_WORD)); + else if (js.blockStart & JIT_ICACHE_EXRAM_BIT) + MOV(32, M((jit->GetBlockCache()->GetICacheEx() + (js.compilerPC & JIT_ICACHEEX_MASK))), Imm32(JIT_ICACHE_INVALID_WORD)); + else + MOV(32, M((jit->GetBlockCache()->GetICache() + (js.compilerPC & JIT_ICACHE_MASK))), Imm32(JIT_ICACHE_INVALID_WORD)); + WriteExceptionExit(); } diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp index c385418d63..fe086179c2 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp @@ -1877,7 +1877,19 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak } case ISIException: { unsigned InstLoc = ibuild->GetImmValue(getOp1(I)); - Jit->ABI_CallFunctionC(reinterpret_cast(&Memory::GenerateISIException_JIT), InstLoc); + + // Address of instruction could not be translated + Jit->MOV(32, M(&NPC), Imm32(InstLoc)); + Jit->OR(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_ISI)); + + // Remove the invalid instruction from the icache, forcing a recompile + if (InstLoc & JIT_ICACHE_VMEM_BIT) + Jit->MOV(32, M((jit->GetBlockCache()->GetICacheVMEM() + (InstLoc & JIT_ICACHE_MASK))), Imm32(JIT_ICACHE_INVALID_WORD)); + else if (InstLoc & JIT_ICACHE_EXRAM_BIT) + Jit->MOV(32, M((jit->GetBlockCache()->GetICacheEx() + (InstLoc & JIT_ICACHEEX_MASK))), Imm32(JIT_ICACHE_INVALID_WORD)); + else + Jit->MOV(32, M((jit->GetBlockCache()->GetICache() + (InstLoc & JIT_ICACHE_MASK))), Imm32(JIT_ICACHE_INVALID_WORD)); + Jit->WriteExceptionExit(); break; } diff --git a/Source/Core/Core/Src/PowerPC/PowerPC.cpp b/Source/Core/Core/Src/PowerPC/PowerPC.cpp index 3729b020e2..adfab31dff 100644 --- a/Source/Core/Core/Src/PowerPC/PowerPC.cpp +++ b/Source/Core/Core/Src/PowerPC/PowerPC.cpp @@ -279,20 +279,13 @@ void CheckExceptions() if (!exceptions) return; - // gcemu uses the mask 0x87C0FFFF instead of 0x0780FF77 - // shuffle2: the MSR bits saved to SRR1 depend on the type of - // exception being taken, the common mask is 0x87C00008. - // I guess gcemu just uses 0x87C0FFFF for simplicity - // I think we should too, or else we would have to check what type of - // exception a rfi is returning from - I doubt a real cpu does this - // Example procedure: // set SRR0 to either PC or NPC //SRR0 = NPC; // save specified MSR bits //SRR1 = MSR & 0x87C0FFFF; // copy ILE bit to LE - //MSR |= (MSR >> 17) & 1; + //MSR |= (MSR >> 16) & 1; // clear MSR as specified //MSR &= ~0x04EF36; // 0x04FF36 also clears ME (only for machine check exception) // set to exception type entry point @@ -301,8 +294,9 @@ void CheckExceptions() if (exceptions & EXCEPTION_ISI) { SRR0 = NPC; - //GenerateISIException() sets up SRR1 - MSR |= (MSR >> 17) & 1; + // Page fault occurred + SRR1 = (MSR & 0x87C0FFFF) | (1 << 30); + MSR |= (MSR >> 16) & 1; MSR &= ~0x04EF36; NPC = 0x80000400; @@ -312,10 +306,9 @@ void CheckExceptions() else if (exceptions & EXCEPTION_PROGRAM) { SRR0 = PC; - SRR1 = MSR & 0x87C0FFFF; // say that it's a trap exception - SRR1 |= 0x40000; - MSR |= (MSR >> 17) & 1; + SRR1 = (MSR & 0x87C0FFFF) | 0x40000; + MSR |= (MSR >> 16) & 1; MSR &= ~0x04EF36; NPC = 0x80000700; @@ -326,7 +319,7 @@ void CheckExceptions() { SRR0 = NPC; SRR1 = MSR & 0x87C0FFFF; - MSR |= (MSR >> 17) & 1; + MSR |= (MSR >> 16) & 1; MSR &= ~0x04EF36; NPC = 0x80000C00; @@ -338,12 +331,8 @@ void CheckExceptions() //This happens a lot - Gamecube OS uses deferred FPU context switching SRR0 = PC; // re-execute the instruction SRR1 = MSR & 0x87C0FFFF; - MSR |= (MSR >> 17) & 1; + MSR |= (MSR >> 16) & 1; MSR &= ~0x04EF36; - // TODO: Verify whether the code below is correct - //SRR1 = MSR & 0x0000FFFF; - //MSR |= (MSR >> 16) & 1; - //MSR &= ~0x04EF32; NPC = 0x80000800; INFO_LOG(POWERPC, "EXCEPTION_FPU_UNAVAILABLE"); @@ -353,7 +342,7 @@ void CheckExceptions() { SRR0 = PC; SRR1 = MSR & 0x87C0FFFF; - MSR |= (MSR >> 17) & 1; + MSR |= (MSR >> 16) & 1; MSR &= ~0x04EF36; NPC = 0x80000300; //DSISR and DAR regs are changed in GenerateDSIException() @@ -367,7 +356,7 @@ void CheckExceptions() // perhaps we can get dcb* instructions to use this :p SRR0 = PC; SRR1 = MSR & 0x87C0FFFF; - MSR |= (MSR >> 17) & 1; + MSR |= (MSR >> 16) & 1; MSR &= ~0x04EF36; NPC = 0x80000600; @@ -385,7 +374,7 @@ void CheckExceptions() // Pokemon gets this "too early", it hasn't a handler yet SRR0 = NPC; SRR1 = MSR & 0x87C0FFFF; - MSR |= (MSR >> 17) & 1; + MSR |= (MSR >> 16) & 1; MSR &= ~0x04EF36; NPC = 0x80000500; @@ -398,7 +387,7 @@ void CheckExceptions() { SRR0 = NPC; SRR1 = MSR & 0x87C0FFFF; - MSR |= (MSR >> 17) & 1; + MSR |= (MSR >> 16) & 1; MSR &= ~0x04EF36; NPC = 0x80000900; diff --git a/Source/Core/Core/Src/PowerPC/PowerPC.h b/Source/Core/Core/Src/PowerPC/PowerPC.h index 532f65bd42..9ac979bcfb 100644 --- a/Source/Core/Core/Src/PowerPC/PowerPC.h +++ b/Source/Core/Core/Src/PowerPC/PowerPC.h @@ -118,6 +118,7 @@ void OnIdleIL(); // Easy register access macros. #define HID0 ((UReg_HID0&)PowerPC::ppcState.spr[SPR_HID0]) #define HID2 ((UReg_HID2&)PowerPC::ppcState.spr[SPR_HID2]) +#define HID4 ((UReg_HID4&)PowerPC::ppcState.spr[SPR_HID4]) #define DMAU (*(UReg_DMAU*)&PowerPC::ppcState.spr[SPR_DMAU]) #define DMAL (*(UReg_DMAL*)&PowerPC::ppcState.spr[SPR_DMAL]) #define PC PowerPC::ppcState.pc