"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()
|
void GenerateISIException()
|
||||||
{
|
{
|
||||||
// 4 bit for Set if the translation of an attempted access is not found in the primary hash table entry group
|
// shuffle2: ISI exception doesn't modify DSISR at all, to my knowledge...
|
||||||
// (HTEG), or in the rehashed secondary HTEG, or in the range of a DBAT register (page fault
|
//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.
|
// condition); otherwise cleared.
|
||||||
PowerPC::ppcState.spr[SPR_DSISR] = 0x4000000;
|
// 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");
|
INFO_LOG(MEMMAP, "Generate ISI Exception");
|
||||||
PowerPC::ppcState.Exceptions |= EXCEPTION_ISI;
|
PowerPC::ppcState.Exceptions |= EXCEPTION_ISI;
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,16 +113,18 @@ void CompiledBlock(UGeckoInstruction _inst)
|
||||||
|
|
||||||
void rfi(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.
|
// Restore saved bits from SRR1 to MSR.
|
||||||
//MSR[13] is set to 0.
|
const int mask = 0x87C0FFFF;
|
||||||
const int mask = 0x87C0FF73;
|
|
||||||
MSR = (MSR & ~mask) | (SRR1 & mask);
|
MSR = (MSR & ~mask) | (SRR1 & mask);
|
||||||
MSR &= 0xFFFDFFFF; //TODO: VERIFY
|
//MSR[13] is set to 0.
|
||||||
NPC = SRR0; // TODO: VERIFY
|
MSR &= 0xFFFDFFFF;
|
||||||
m_EndBlock = true;
|
// Here we should check if there are pending exceptions, and if their corresponding enable bits are set
|
||||||
// After an RFI, exceptions should be checked IMMEDIATELY without going back into
|
// if above is true, we'd do:
|
||||||
// other code! TODO(ector): fix this properly
|
|
||||||
//PowerPC::CheckExceptions();
|
//PowerPC::CheckExceptions();
|
||||||
|
//else
|
||||||
|
// set NPC to saved offset and resume
|
||||||
|
NPC = SRR0; // TODO: VERIFY...docs say ignore top two bits?
|
||||||
|
m_EndBlock = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rfid(UGeckoInstruction _inst)
|
void rfid(UGeckoInstruction _inst)
|
||||||
|
|
|
@ -209,90 +209,128 @@ void CheckExceptions()
|
||||||
if (!ppcState.Exceptions)
|
if (!ppcState.Exceptions)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// TODO(ector):
|
|
||||||
// gcemu uses the mask 0x87C0FFFF instead of 0x0780FF77
|
// 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)
|
// Example procedure:
|
||||||
{
|
// set SRR0 to either PC or NPC
|
||||||
//This happens a lot - Gamecube OS uses deferred FPU context switching
|
//SRR0 = NPC;
|
||||||
SRR0 = PC; // re-execute the instruction
|
// save specified MSR bits
|
||||||
SRR1 = MSR & 0x0780FF77;
|
//SRR1 = MSR & 0x87C0FFFF;
|
||||||
NPC = 0x80000800;
|
// 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");
|
if (ppcState.Exceptions & EXCEPTION_ISI)
|
||||||
ppcState.Exceptions &= ~EXCEPTION_FPU_UNAVAILABLE;
|
|
||||||
SRR1 |= 0x02; //recoverable
|
|
||||||
}
|
|
||||||
else if (ppcState.Exceptions & EXCEPTION_SYSCALL)
|
|
||||||
{
|
{
|
||||||
SRR0 = NPC; // execute next instruction when we come back from handler
|
SRR0 = NPC;
|
||||||
SRR1 = MSR & 0x0780FF77;
|
//GenerateISIException() sets up SRR1
|
||||||
NPC = 0x80000C00;
|
SRR1 |= MSR & 0x87C0FFFF;
|
||||||
|
MSR |= (MSR >> 17) & 1;
|
||||||
INFO_LOG(GEKKO, "EXCEPTION_SYSCALL (PC=%08x)", PC);
|
MSR &= ~0x04EF36;
|
||||||
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;
|
|
||||||
NPC = 0x80000400;
|
NPC = 0x80000400;
|
||||||
|
|
||||||
INFO_LOG(GEKKO, "EXCEPTION_ISI");
|
INFO_LOG(GEKKO, "EXCEPTION_ISI");
|
||||||
ppcState.Exceptions &= ~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)
|
else if (ppcState.Exceptions & EXCEPTION_ALIGNMENT)
|
||||||
{
|
{
|
||||||
//This never happens ATM
|
//This never happens ATM
|
||||||
SRR0 = NPC;
|
// perhaps we can get dcb* instructions to use this :p
|
||||||
SRR1 = MSR & 0x0780FF77;
|
SRR0 = PC;
|
||||||
|
SRR1 = MSR & 0x87C0FFFF;
|
||||||
|
MSR |= (MSR >> 17) & 1;
|
||||||
|
MSR &= ~0x04EF36;
|
||||||
NPC = 0x80000600;
|
NPC = 0x80000600;
|
||||||
|
|
||||||
|
//TODO crazy amount of DSISR options to check out
|
||||||
|
|
||||||
INFO_LOG(GEKKO, "EXCEPTION_ALIGNMENT");
|
INFO_LOG(GEKKO, "EXCEPTION_ALIGNMENT");
|
||||||
ppcState.Exceptions &= ~EXCEPTION_ALIGNMENT;
|
ppcState.Exceptions &= ~EXCEPTION_ALIGNMENT;
|
||||||
//SRR1 |= 0x02; //make recoverable ?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// EXTERNAL INTTERUPT
|
// 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)
|
if (ppcState.Exceptions & EXCEPTION_EXTERNAL_INT)
|
||||||
{
|
{
|
||||||
// Pokemon gets this "too early", it hasn't a handler yet
|
// Pokemon gets this "too early", it hasn't a handler yet
|
||||||
ppcState.Exceptions &= ~EXCEPTION_EXTERNAL_INT; // clear exception
|
|
||||||
|
|
||||||
SRR0 = NPC;
|
SRR0 = NPC;
|
||||||
|
SRR1 = MSR & 0x87C0FFFF;
|
||||||
|
MSR |= (MSR >> 17) & 1;
|
||||||
|
MSR &= ~0x04EF36;
|
||||||
NPC = 0x80000500;
|
NPC = 0x80000500;
|
||||||
SRR1 = (MSR & 0x0780FF77);
|
|
||||||
|
|
||||||
INFO_LOG(GEKKO, "EXCEPTION_EXTERNAL_INT");
|
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???");
|
||||||
_dbg_assert_msg_(GEKKO, (SRR1 & 0x02) != 0, "GEKKO", "EXTERNAL_INT unrecoverable???"); // unrecoverable exception !?!
|
|
||||||
}
|
}
|
||||||
else if (ppcState.Exceptions & EXCEPTION_DECREMENTER)
|
else if (ppcState.Exceptions & EXCEPTION_DECREMENTER)
|
||||||
{
|
{
|
||||||
SRR0 = NPC;
|
SRR0 = NPC;
|
||||||
SRR1 = MSR & 0x0000FF77;
|
SRR1 = MSR & 0x87C0FFFF;
|
||||||
|
MSR |= (MSR >> 17) & 1;
|
||||||
|
MSR &= ~0x04EF36;
|
||||||
NPC = 0x80000900;
|
NPC = 0x80000900;
|
||||||
|
|
||||||
ppcState.Exceptions &= ~EXCEPTION_DECREMENTER;
|
|
||||||
|
|
||||||
INFO_LOG(GEKKO, "EXCEPTION_DECREMENTER");
|
INFO_LOG(GEKKO, "EXCEPTION_DECREMENTER");
|
||||||
SRR1 |= 0x02; //make recoverable
|
ppcState.Exceptions &= ~EXCEPTION_DECREMENTER;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -300,7 +338,6 @@ void CheckExceptions()
|
||||||
ERROR_LOG(GEKKO, "Unknown EXTERNAL INTERRUPT exception: Exceptions == %08x", ppcState.Exceptions);
|
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)
|
void OnIdle(u32 _uThreadAddr)
|
||||||
|
|
Loading…
Reference in New Issue