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
This commit is contained in:
skidau 2010-09-11 02:34:51 +00:00
parent 18123251d1
commit 9d57903065
8 changed files with 71 additions and 38 deletions

View File

@ -501,14 +501,6 @@ void Write_Opcode_JIT(const u32 _Address, const u32 _Value)
#endif #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) void WriteBigEData(const u8 *_pData, const u32 _Address, const u32 _iSize)
{ {
memcpy(GetPointer(_Address), _pData, _iSize); memcpy(GetPointer(_Address), _pData, _iSize);

View File

@ -177,7 +177,6 @@ u32 TranslateAddress(u32 _Address, XCheckTLBFlag _Flag);
void InvalidateTLBEntry(u32 _Address); void InvalidateTLBEntry(u32 _Address);
void GenerateDSIException(u32 _EffectiveAdress, bool _bWrite); void GenerateDSIException(u32 _EffectiveAdress, bool _bWrite);
void GenerateISIException(u32 _EffectiveAdress); void GenerateISIException(u32 _EffectiveAdress);
void GenerateISIException_JIT(u32 _EffectiveAdress);
extern u32 pagetable_base; extern u32 pagetable_base;
extern u32 pagetable_hashmask; extern u32 pagetable_hashmask;

View File

@ -608,7 +608,6 @@ void GenerateDSIException(u32 _EffectiveAddress, bool _bWrite)
void GenerateISIException(u32 _EffectiveAddress) void GenerateISIException(u32 _EffectiveAddress)
{ {
// Address of instruction could not be translated // Address of instruction could not be translated
SRR1 = (1 << 30) | (MSR & 0x3fffff);
NPC = _EffectiveAddress; NPC = _EffectiveAddress;
Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_ISI); Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_ISI);
@ -892,8 +891,8 @@ u32 TranslateBlockAddress(const u32 addr, const XCheckTLBFlag _Flag)
u32 result = 0; u32 result = 0;
UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr); UReg_MSR& m_MSR = ((UReg_MSR&)PowerPC::ppcState.msr);
// TODO: Check for enhanced mode before switching to Wii mode // Check for enhanced mode (secondary BAT enable) using 8 BATs
int bats = Core::g_CoreStartupParameter.bWii?8:4; int bats = (Core::g_CoreStartupParameter.bWii && HID4.SBE)?8:4;
for (int i = 0; i < bats; i++) { for (int i = 0; i < bats; i++) {
if (_Flag != FLAG_OPCODE) if (_Flag != FLAG_OPCODE)
@ -944,9 +943,15 @@ u32 TranslateBlockAddress(const u32 addr, const XCheckTLBFlag _Flag)
return 0; 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) 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; u32 tlb_addr = Core::g_CoreStartupParameter.bMMUBAT?TranslateBlockAddress(_Address, _Flag):0;
if (tlb_addr == 0) if (tlb_addr == 0)
{ {

View File

@ -456,6 +456,29 @@ union UReg_HID2
UReg_HID2() { Hex = 0; } 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 // SPR1 - Page Table format
union UReg_SPR1 union UReg_SPR1
{ {
@ -637,6 +660,7 @@ enum
SPR_HID0 = 1008, SPR_HID0 = 1008,
SPR_HID1 = 1009, SPR_HID1 = 1009,
SPR_HID2 = 920, SPR_HID2 = 920,
SPR_HID4 = 1011,
SPR_WPAR = 921, SPR_WPAR = 921,
SPR_DMAU = 922, SPR_DMAU = 922,
SPR_DMAL = 923, SPR_DMAL = 923,

View File

@ -593,7 +593,18 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
if (memory_exception) if (memory_exception)
{ {
ABI_CallFunctionC(reinterpret_cast<void *>(&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(); WriteExceptionExit();
} }

View File

@ -1877,7 +1877,19 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak
} }
case ISIException: { case ISIException: {
unsigned InstLoc = ibuild->GetImmValue(getOp1(I)); unsigned InstLoc = ibuild->GetImmValue(getOp1(I));
Jit->ABI_CallFunctionC(reinterpret_cast<void *>(&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(); Jit->WriteExceptionExit();
break; break;
} }

View File

@ -279,20 +279,13 @@ void CheckExceptions()
if (!exceptions) if (!exceptions)
return; 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: // Example procedure:
// set SRR0 to either PC or NPC // set SRR0 to either PC or NPC
//SRR0 = NPC; //SRR0 = NPC;
// save specified MSR bits // save specified MSR bits
//SRR1 = MSR & 0x87C0FFFF; //SRR1 = MSR & 0x87C0FFFF;
// copy ILE bit to LE // copy ILE bit to LE
//MSR |= (MSR >> 17) & 1; //MSR |= (MSR >> 16) & 1;
// clear MSR as specified // clear MSR as specified
//MSR &= ~0x04EF36; // 0x04FF36 also clears ME (only for machine check exception) //MSR &= ~0x04EF36; // 0x04FF36 also clears ME (only for machine check exception)
// set to exception type entry point // set to exception type entry point
@ -301,8 +294,9 @@ void CheckExceptions()
if (exceptions & EXCEPTION_ISI) if (exceptions & EXCEPTION_ISI)
{ {
SRR0 = NPC; SRR0 = NPC;
//GenerateISIException() sets up SRR1 // Page fault occurred
MSR |= (MSR >> 17) & 1; SRR1 = (MSR & 0x87C0FFFF) | (1 << 30);
MSR |= (MSR >> 16) & 1;
MSR &= ~0x04EF36; MSR &= ~0x04EF36;
NPC = 0x80000400; NPC = 0x80000400;
@ -312,10 +306,9 @@ void CheckExceptions()
else if (exceptions & EXCEPTION_PROGRAM) else if (exceptions & EXCEPTION_PROGRAM)
{ {
SRR0 = PC; SRR0 = PC;
SRR1 = MSR & 0x87C0FFFF;
// say that it's a trap exception // say that it's a trap exception
SRR1 |= 0x40000; SRR1 = (MSR & 0x87C0FFFF) | 0x40000;
MSR |= (MSR >> 17) & 1; MSR |= (MSR >> 16) & 1;
MSR &= ~0x04EF36; MSR &= ~0x04EF36;
NPC = 0x80000700; NPC = 0x80000700;
@ -326,7 +319,7 @@ void CheckExceptions()
{ {
SRR0 = NPC; SRR0 = NPC;
SRR1 = MSR & 0x87C0FFFF; SRR1 = MSR & 0x87C0FFFF;
MSR |= (MSR >> 17) & 1; MSR |= (MSR >> 16) & 1;
MSR &= ~0x04EF36; MSR &= ~0x04EF36;
NPC = 0x80000C00; NPC = 0x80000C00;
@ -338,12 +331,8 @@ void CheckExceptions()
//This happens a lot - Gamecube OS uses deferred FPU context switching //This happens a lot - Gamecube OS uses deferred FPU context switching
SRR0 = PC; // re-execute the instruction SRR0 = PC; // re-execute the instruction
SRR1 = MSR & 0x87C0FFFF; SRR1 = MSR & 0x87C0FFFF;
MSR |= (MSR >> 17) & 1; MSR |= (MSR >> 16) & 1;
MSR &= ~0x04EF36; MSR &= ~0x04EF36;
// TODO: Verify whether the code below is correct
//SRR1 = MSR & 0x0000FFFF;
//MSR |= (MSR >> 16) & 1;
//MSR &= ~0x04EF32;
NPC = 0x80000800; NPC = 0x80000800;
INFO_LOG(POWERPC, "EXCEPTION_FPU_UNAVAILABLE"); INFO_LOG(POWERPC, "EXCEPTION_FPU_UNAVAILABLE");
@ -353,7 +342,7 @@ void CheckExceptions()
{ {
SRR0 = PC; SRR0 = PC;
SRR1 = MSR & 0x87C0FFFF; SRR1 = MSR & 0x87C0FFFF;
MSR |= (MSR >> 17) & 1; MSR |= (MSR >> 16) & 1;
MSR &= ~0x04EF36; MSR &= ~0x04EF36;
NPC = 0x80000300; NPC = 0x80000300;
//DSISR and DAR regs are changed in GenerateDSIException() //DSISR and DAR regs are changed in GenerateDSIException()
@ -367,7 +356,7 @@ void CheckExceptions()
// perhaps we can get dcb* instructions to use this :p // perhaps we can get dcb* instructions to use this :p
SRR0 = PC; SRR0 = PC;
SRR1 = MSR & 0x87C0FFFF; SRR1 = MSR & 0x87C0FFFF;
MSR |= (MSR >> 17) & 1; MSR |= (MSR >> 16) & 1;
MSR &= ~0x04EF36; MSR &= ~0x04EF36;
NPC = 0x80000600; NPC = 0x80000600;
@ -385,7 +374,7 @@ void CheckExceptions()
// Pokemon gets this "too early", it hasn't a handler yet // Pokemon gets this "too early", it hasn't a handler yet
SRR0 = NPC; SRR0 = NPC;
SRR1 = MSR & 0x87C0FFFF; SRR1 = MSR & 0x87C0FFFF;
MSR |= (MSR >> 17) & 1; MSR |= (MSR >> 16) & 1;
MSR &= ~0x04EF36; MSR &= ~0x04EF36;
NPC = 0x80000500; NPC = 0x80000500;
@ -398,7 +387,7 @@ void CheckExceptions()
{ {
SRR0 = NPC; SRR0 = NPC;
SRR1 = MSR & 0x87C0FFFF; SRR1 = MSR & 0x87C0FFFF;
MSR |= (MSR >> 17) & 1; MSR |= (MSR >> 16) & 1;
MSR &= ~0x04EF36; MSR &= ~0x04EF36;
NPC = 0x80000900; NPC = 0x80000900;

View File

@ -118,6 +118,7 @@ void OnIdleIL();
// Easy register access macros. // Easy register access macros.
#define HID0 ((UReg_HID0&)PowerPC::ppcState.spr[SPR_HID0]) #define HID0 ((UReg_HID0&)PowerPC::ppcState.spr[SPR_HID0])
#define HID2 ((UReg_HID2&)PowerPC::ppcState.spr[SPR_HID2]) #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 DMAU (*(UReg_DMAU*)&PowerPC::ppcState.spr[SPR_DMAU])
#define DMAL (*(UReg_DMAL*)&PowerPC::ppcState.spr[SPR_DMAL]) #define DMAL (*(UReg_DMAL*)&PowerPC::ppcState.spr[SPR_DMAL])
#define PC PowerPC::ppcState.pc #define PC PowerPC::ppcState.pc