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
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue