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:
parent
18123251d1
commit
9d57903065
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue