"better" ppc exception handling. I don't see any real world difference, though
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2896 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
8af05ec4fb
commit
c126c5a9f9
|
@ -518,10 +518,23 @@ void GenerateDSIException(u32 _EffectiveAdress, bool _bWrite)
|
|||
|
||||
void GenerateISIException()
|
||||
{
|
||||
// 4 bit for Set if the translation of an attempted access is not found in the primary hash table entry group
|
||||
// (HTEG), or in the rehashed secondary HTEG, or in the range of a DBAT register (page fault
|
||||
// condition); otherwise cleared.
|
||||
PowerPC::ppcState.spr[SPR_DSISR] = 0x4000000;
|
||||
// shuffle2: ISI exception doesn't modify DSISR at all, to my knowledge...
|
||||
//PowerPC::ppcState.spr[SPR_DSISR] = 0x4000000; // maybe this was a typo for PPC_EXC_DSISR_PAGE?
|
||||
|
||||
// Instead, it modifies bits 1-4 in SRR1 depending on conditions:
|
||||
// Bit 1: set if the translation of an attempted access is not found in the primary hash table entry group
|
||||
// (HTEG), or in the rehashed secondary HTEG, or in the range of a IBAT register (page fault
|
||||
// condition); otherwise cleared.
|
||||
// Bit 2: cleared
|
||||
// Bit 3: Set if the fetch access occurs to a direct-store segment (SR[T] = 1), to a noexecute
|
||||
// segment (N bit set in segment descriptor), or to guarded memory
|
||||
// when MSR[IR] = 1. Otherwise, cleared.
|
||||
// Bit 4: Set if a memory access is not permitted by the page or IBAT protection
|
||||
// mechanism, described in Chapter 7, “Memory Management”; otherwise cleared.
|
||||
// Only one of 1,3, or 4 may be set at a time
|
||||
|
||||
// For now let's just say that hash lookup failed
|
||||
SRR1 = 0x10000000;
|
||||
INFO_LOG(MEMMAP, "Generate ISI Exception");
|
||||
PowerPC::ppcState.Exceptions |= EXCEPTION_ISI;
|
||||
}
|
||||
|
|
|
@ -113,16 +113,18 @@ void CompiledBlock(UGeckoInstruction _inst)
|
|||
|
||||
void rfi(UGeckoInstruction _inst)
|
||||
{
|
||||
//Bits SRR1[0,5-9,16-23, 25-27, 30-31] are placed into the corresponding bits of the MSR.
|
||||
//MSR[13] is set to 0.
|
||||
const int mask = 0x87C0FF73;
|
||||
// Restore saved bits from SRR1 to MSR.
|
||||
const int mask = 0x87C0FFFF;
|
||||
MSR = (MSR & ~mask) | (SRR1 & mask);
|
||||
MSR &= 0xFFFDFFFF; //TODO: VERIFY
|
||||
NPC = SRR0; // TODO: VERIFY
|
||||
//MSR[13] is set to 0.
|
||||
MSR &= 0xFFFDFFFF;
|
||||
// Here we should check if there are pending exceptions, and if their corresponding enable bits are set
|
||||
// if above is true, we'd do:
|
||||
//PowerPC::CheckExceptions();
|
||||
//else
|
||||
// set NPC to saved offset and resume
|
||||
NPC = SRR0; // TODO: VERIFY...docs say ignore top two bits?
|
||||
m_EndBlock = true;
|
||||
// After an RFI, exceptions should be checked IMMEDIATELY without going back into
|
||||
// other code! TODO(ector): fix this properly
|
||||
// PowerPC::CheckExceptions();
|
||||
}
|
||||
|
||||
void rfid(UGeckoInstruction _inst)
|
||||
|
|
|
@ -209,90 +209,128 @@ void CheckExceptions()
|
|||
if (!ppcState.Exceptions)
|
||||
return;
|
||||
|
||||
// TODO(ector):
|
||||
// gcemu uses the mask 0x87C0FFFF instead of 0x0780FF77
|
||||
// Investigate!
|
||||
// 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
|
||||
|
||||
if (ppcState.Exceptions & EXCEPTION_FPU_UNAVAILABLE)
|
||||
{
|
||||
//This happens a lot - Gamecube OS uses deferred FPU context switching
|
||||
SRR0 = PC; // re-execute the instruction
|
||||
SRR1 = MSR & 0x0780FF77;
|
||||
NPC = 0x80000800;
|
||||
// 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;
|
||||
// clear MSR as specified
|
||||
//MSR &= ~0x04EF36; // 0x04FF36 also clears ME (only for machine check exception)
|
||||
// set to exception type entry point
|
||||
//NPC = 0x80000x00;
|
||||
|
||||
INFO_LOG(GEKKO, "EXCEPTION_FPU_UNAVAILABLE");
|
||||
ppcState.Exceptions &= ~EXCEPTION_FPU_UNAVAILABLE;
|
||||
SRR1 |= 0x02; //recoverable
|
||||
}
|
||||
else if (ppcState.Exceptions & EXCEPTION_SYSCALL)
|
||||
if (ppcState.Exceptions & EXCEPTION_ISI)
|
||||
{
|
||||
SRR0 = NPC; // execute next instruction when we come back from handler
|
||||
SRR1 = MSR & 0x0780FF77;
|
||||
NPC = 0x80000C00;
|
||||
|
||||
INFO_LOG(GEKKO, "EXCEPTION_SYSCALL (PC=%08x)", PC);
|
||||
ppcState.Exceptions &= ~EXCEPTION_SYSCALL;
|
||||
SRR1 |= 0x02; //recoverable
|
||||
}
|
||||
else if (ppcState.Exceptions & EXCEPTION_DSI)
|
||||
{
|
||||
SRR0 = PC; // re-execute the instruction
|
||||
SRR1 = MSR & 0x0780FF77;
|
||||
NPC = 0x80000300;
|
||||
|
||||
INFO_LOG(GEKKO, "EXCEPTION_DSI");
|
||||
ppcState.Exceptions &= ~EXCEPTION_DSI;
|
||||
//SRR1 |= 0x02; //make recoverable ?
|
||||
}
|
||||
else if (ppcState.Exceptions & EXCEPTION_ISI)
|
||||
{
|
||||
SRR0 = PC;
|
||||
SRR1 = (MSR & 0x0780FF77) | 0x40000000;
|
||||
SRR0 = NPC;
|
||||
//GenerateISIException() sets up SRR1
|
||||
SRR1 |= MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 17) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
NPC = 0x80000400;
|
||||
|
||||
INFO_LOG(GEKKO, "EXCEPTION_ISI");
|
||||
ppcState.Exceptions &= ~EXCEPTION_ISI;
|
||||
//SRR1 |= 0x02; //make recoverable ?
|
||||
}
|
||||
else if (ppcState.Exceptions & EXCEPTION_PROGRAM)
|
||||
{
|
||||
SRR0 = PC;
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
// say that it's a trap exception
|
||||
SRR1 |= 0x40000;
|
||||
MSR |= (MSR >> 17) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
NPC = 0x80000700;
|
||||
|
||||
INFO_LOG(GEKKO, "EXCEPTION_PROGRAM");
|
||||
ppcState.Exceptions &= ~EXCEPTION_PROGRAM;
|
||||
}
|
||||
else if (ppcState.Exceptions & EXCEPTION_SYSCALL)
|
||||
{
|
||||
SRR0 = NPC;
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 17) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
NPC = 0x80000C00;
|
||||
|
||||
INFO_LOG(GEKKO, "EXCEPTION_SYSCALL (PC=%08x)", PC);
|
||||
ppcState.Exceptions &= ~EXCEPTION_SYSCALL;
|
||||
}
|
||||
else if (ppcState.Exceptions & EXCEPTION_FPU_UNAVAILABLE)
|
||||
{
|
||||
//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 &= ~0x04EF36;
|
||||
NPC = 0x80000800;
|
||||
|
||||
INFO_LOG(GEKKO, "EXCEPTION_FPU_UNAVAILABLE");
|
||||
ppcState.Exceptions &= ~EXCEPTION_FPU_UNAVAILABLE;
|
||||
}
|
||||
else if (ppcState.Exceptions & EXCEPTION_DSI)
|
||||
{
|
||||
SRR0 = PC;
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 17) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
NPC = 0x80000300;
|
||||
//DSISR and DAR regs are changed in GenerateDSIException()
|
||||
|
||||
INFO_LOG(GEKKO, "EXCEPTION_DSI");
|
||||
ppcState.Exceptions &= ~EXCEPTION_DSI;
|
||||
}
|
||||
else if (ppcState.Exceptions & EXCEPTION_ALIGNMENT)
|
||||
{
|
||||
//This never happens ATM
|
||||
SRR0 = NPC;
|
||||
SRR1 = MSR & 0x0780FF77;
|
||||
// perhaps we can get dcb* instructions to use this :p
|
||||
SRR0 = PC;
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 17) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
NPC = 0x80000600;
|
||||
|
||||
//TODO crazy amount of DSISR options to check out
|
||||
|
||||
INFO_LOG(GEKKO, "EXCEPTION_ALIGNMENT");
|
||||
ppcState.Exceptions &= ~EXCEPTION_ALIGNMENT;
|
||||
//SRR1 |= 0x02; //make recoverable ?
|
||||
}
|
||||
|
||||
// EXTERNAL INTTERUPT
|
||||
else if (MSR & 0x0008000)
|
||||
else if (MSR & 0x0008000) //hacky...the exception shouldn't be generated if EE isn't set...
|
||||
{
|
||||
if (ppcState.Exceptions & EXCEPTION_EXTERNAL_INT)
|
||||
{
|
||||
// Pokemon gets this "too early", it hasn't a handler yet
|
||||
ppcState.Exceptions &= ~EXCEPTION_EXTERNAL_INT; // clear exception
|
||||
|
||||
SRR0 = NPC;
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 17) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
NPC = 0x80000500;
|
||||
SRR1 = (MSR & 0x0780FF77);
|
||||
|
||||
INFO_LOG(GEKKO, "EXCEPTION_EXTERNAL_INT");
|
||||
ppcState.Exceptions &= ~EXCEPTION_EXTERNAL_INT;
|
||||
|
||||
SRR1 |= 0x02; //set it to recoverable
|
||||
_dbg_assert_msg_(GEKKO, (SRR1 & 0x02) != 0, "GEKKO", "EXTERNAL_INT unrecoverable???"); // unrecoverable exception !?!
|
||||
_dbg_assert_msg_(GEKKO, (SRR1 & 0x02) != 0, "GEKKO", "EXTERNAL_INT unrecoverable???");
|
||||
}
|
||||
else if (ppcState.Exceptions & EXCEPTION_DECREMENTER)
|
||||
{
|
||||
SRR0 = NPC;
|
||||
SRR1 = MSR & 0x0000FF77;
|
||||
SRR1 = MSR & 0x87C0FFFF;
|
||||
MSR |= (MSR >> 17) & 1;
|
||||
MSR &= ~0x04EF36;
|
||||
NPC = 0x80000900;
|
||||
|
||||
ppcState.Exceptions &= ~EXCEPTION_DECREMENTER;
|
||||
|
||||
INFO_LOG(GEKKO, "EXCEPTION_DECREMENTER");
|
||||
SRR1 |= 0x02; //make recoverable
|
||||
ppcState.Exceptions &= ~EXCEPTION_DECREMENTER;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -300,7 +338,6 @@ void CheckExceptions()
|
|||
ERROR_LOG(GEKKO, "Unknown EXTERNAL INTERRUPT exception: Exceptions == %08x", ppcState.Exceptions);
|
||||
}
|
||||
}
|
||||
MSR &= ~0x0008000; // clear EE-bit so interrupts aren't possible anymore
|
||||
}
|
||||
|
||||
void OnIdle(u32 _uThreadAddr)
|
||||
|
|
Loading…
Reference in New Issue