"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:
Shawn Hoffman 2009-04-06 14:15:02 +00:00
parent 8af05ec4fb
commit c126c5a9f9
3 changed files with 109 additions and 57 deletions

View File

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

View File

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

View File

@ -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
if (ppcState.Exceptions & EXCEPTION_ISI)
{
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;
}
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; // execute next instruction when we come back from handler
SRR1 = MSR & 0x0780FF77;
{
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;
SRR1 |= 0x02; //recoverable
}
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; // re-execute the instruction
SRR1 = MSR & 0x0780FF77;
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;
//SRR1 |= 0x02; //make recoverable ?
}
else if (ppcState.Exceptions & EXCEPTION_ISI)
{
SRR0 = PC;
SRR1 = (MSR & 0x0780FF77) | 0x40000000;
NPC = 0x80000400;
INFO_LOG(GEKKO, "EXCEPTION_ISI");
ppcState.Exceptions &= ~EXCEPTION_ISI;
//SRR1 |= 0x02; //make recoverable ?
}
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 ?
ppcState.Exceptions &= ~EXCEPTION_ALIGNMENT;
}
// 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)