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
}
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);

View File

@ -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;

View File

@ -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)
{

View File

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

View File

@ -593,7 +593,18 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
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();
}

View File

@ -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<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();
break;
}

View File

@ -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;

View File

@ -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