Fixed some race conditions with PPC exceptions and external interrupts.

This may help fixing issues related to video interrupts handling.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6157 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
dok.slade 2010-09-01 22:03:51 +00:00
parent 625d78fb59
commit 8d6f98439e
16 changed files with 64 additions and 48 deletions

View File

@ -16,6 +16,7 @@
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "Atomic.h"
#include "GPFifo.h"
#include "Memmap.h"
@ -605,7 +606,7 @@ void GenerateDSIException(u32 _EffectiveAddress, bool _bWrite)
PowerPC::ppcState.spr[SPR_DAR] = _EffectiveAddress;
PowerPC::ppcState.Exceptions |= EXCEPTION_DSI;
Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_DSI);
}
@ -615,7 +616,7 @@ void GenerateISIException(u32 _EffectiveAddress)
SRR1 = (1 << 30) | (MSR & 0x3fffff);
NPC = _EffectiveAddress;
PowerPC::ppcState.Exceptions |= EXCEPTION_ISI;
Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_ISI);
}

View File

@ -17,6 +17,7 @@
#include <stdio.h>
#include "Common.h"
#include "Atomic.h"
#include "ChunkFile.h"
#include "../PowerPC/PowerPC.h"
@ -155,7 +156,7 @@ void Write32(const u32 _uValue, const u32 _iAddress)
switch(_iAddress & 0xFFF)
{
case PI_INTERRUPT_CAUSE:
m_InterruptCause &= ~_uValue; // writes turn them off
Common::AtomicAnd(m_InterruptCause, ~_uValue); // writes turn them off
UpdateException();
return;
@ -203,9 +204,9 @@ void Write32(const u32 _uValue, const u32 _iAddress)
void UpdateException()
{
if ((m_InterruptCause & m_InterruptMask) != 0)
PowerPC::ppcState.Exceptions |= EXCEPTION_EXTERNAL_INT;
Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_EXTERNAL_INT);
else
PowerPC::ppcState.Exceptions &= ~EXCEPTION_EXTERNAL_INT;
Common::AtomicAnd(PowerPC::ppcState.Exceptions, ~EXCEPTION_EXTERNAL_INT);
}
static const char *Debug_GetInterruptName(u32 _causemask)
@ -247,9 +248,9 @@ void SetInterrupt(u32 _causemask, bool _bSet)
}
if (_bSet)
m_InterruptCause |= _causemask;
Common::AtomicOr(m_InterruptCause, _causemask);
else
m_InterruptCause &= ~_causemask;// is there any reason to have this possibility?
Common::AtomicAnd(m_InterruptCause, ~_causemask);// is there any reason to have this possibility?
// F|RES: i think the hw devices reset the interrupt in the PI to 0
// if the interrupt cause is eliminated. that isnt done by software (afaik)
UpdateException();
@ -258,9 +259,9 @@ void SetInterrupt(u32 _causemask, bool _bSet)
void SetResetButton(bool _bSet)
{
if (_bSet)
m_InterruptCause &= ~INT_CAUSE_RST_BUTTON;
Common::AtomicAnd(m_InterruptCause, ~INT_CAUSE_RST_BUTTON);
else
m_InterruptCause |= INT_CAUSE_RST_BUTTON;
Common::AtomicOr(m_InterruptCause, INT_CAUSE_RST_BUTTON);
}
void ToggleResetButtonCallback(u64 userdata, int cyclesLate)

View File

@ -58,6 +58,7 @@ IPC_HLE_PERIOD: For the Wiimote this is the call schedule:
#include "Common.h"
#include "Atomic.h"
#include "../PatchEngine.h"
#include "SystemTimers.h"
#include "../PluginManager.h"
@ -192,7 +193,7 @@ void DecrementerCallback(u64 userdata, int cyclesLate)
// A: Because it's 64bit (0xffffffffffffffff)...?
fakeDec = -1;
PowerPC::ppcState.spr[SPR_DEC] = 0xFFFFFFFF;
PowerPC::ppcState.Exceptions |= EXCEPTION_DECREMENTER;
Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_DECREMENTER);
}
void DecrementerSet()

View File

@ -25,6 +25,7 @@
#include "../../ConfigManager.h"
#include "PowerPCDisasm.h"
#include "../../IPC_HLE/WII_IPC_HLE.h"
#include "Atomic.h"
namespace {
@ -107,7 +108,7 @@ void Interpreter::SingleStepInner(void)
}
else
{
PowerPC::ppcState.Exceptions |= EXCEPTION_FPU_UNAVAILABLE;
Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_FPU_UNAVAILABLE);
PowerPC::CheckExceptions();
m_EndBlock = true;
}

View File

@ -19,6 +19,7 @@
#include "../../HW/CPU.h"
#include "../../HLE/HLE.h"
#include "../PPCAnalyst.h"
#include "Atomic.h"
void Interpreter::bx(UGeckoInstruction _inst)
{
@ -134,7 +135,7 @@ void Interpreter::rfid(UGeckoInstruction _inst)
// We do it anyway, though :P
void Interpreter::sc(UGeckoInstruction _inst)
{
PowerPC::ppcState.Exceptions |= EXCEPTION_SYSCALL;
Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_SYSCALL);
PowerPC::CheckExceptions();
m_EndBlock = true;
}

View File

@ -17,6 +17,7 @@
#include "Interpreter.h"
#include "../../Core.h"
#include "Atomic.h"
void Interpreter::Helper_UpdateCR0(u32 _uValue)
{
@ -174,7 +175,7 @@ void Interpreter::twi(UGeckoInstruction _inst)
|| (((u32)a <(u32)b) && (TO & 0x02))
|| (((u32)a >(u32)b) && (TO & 0x01)))
{
PowerPC::ppcState.Exceptions |= EXCEPTION_PROGRAM;
Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_PROGRAM);
PowerPC::CheckExceptions();
m_EndBlock = true; // Dunno about this
}
@ -402,7 +403,7 @@ void Interpreter::tw(UGeckoInstruction _inst)
|| (((u32)a <(u32)b) && (TO & 0x02))
|| (((u32)a >(u32)b) && (TO & 0x01)))
{
PowerPC::ppcState.Exceptions |= EXCEPTION_PROGRAM;
Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_PROGRAM);
PowerPC::CheckExceptions();
m_EndBlock = true; // Dunno about this
}

View File

@ -16,6 +16,7 @@
// http://code.google.com/p/dolphin-emu/
#include "Common.h"
#include "Atomic.h"
#include "MathUtil.h"
#include "../../HW/Memmap.h"
@ -405,10 +406,10 @@ void Interpreter::eciwx(UGeckoInstruction _inst)
if (!(PowerPC::ppcState.spr[SPR_EAR] & 0x80000000))
{
PowerPC::ppcState.Exceptions |= EXCEPTION_DSI;
Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_DSI);
}
if (EA & 3)
PowerPC::ppcState.Exceptions |= EXCEPTION_ALIGNMENT;
Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_ALIGNMENT);
// _assert_msg_(POWERPC,0,"eciwx - fill r%i with word @ %08x from device %02x",
// _inst.RS, EA, PowerPC::ppcState.spr[SPR_EAR] & 0x1f);
@ -427,10 +428,10 @@ void Interpreter::ecowx(UGeckoInstruction _inst)
if (!(PowerPC::ppcState.spr[SPR_EAR] & 0x80000000))
{
PowerPC::ppcState.Exceptions |= EXCEPTION_DSI;
Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_DSI);
}
if (EA & 3)
PowerPC::ppcState.Exceptions |= EXCEPTION_ALIGNMENT;
Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_ALIGNMENT);
// _assert_msg_(POWERPC,0,"ecowx - send stw request (%08x@%08x) to device %02x",
// m_GPR[_inst.RS], EA, PowerPC::ppcState.spr[SPR_EAR] & 0x1f);

View File

@ -36,6 +36,7 @@ static const unsigned short FPU_ROUND_MASK = 3 << 10;
#endif
#include "CPUDetect.h"
#include "Atomic.h"
#include "../../CoreTiming.h"
#include "../../HW/Memmap.h"
#include "../../HW/GPFifo.h"
@ -413,7 +414,7 @@ void Interpreter::mtspr(UGeckoInstruction _inst)
if (!(oldValue >> 31) && (m_GPR[_inst.RD]>>31)) //top bit from 0 to 1
{
PanicAlert("Interesting - Software triggered Decrementer exception");
PowerPC::ppcState.Exceptions |= EXCEPTION_DECREMENTER;
Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_DECREMENTER);
}
else
{

View File

@ -562,7 +562,7 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
gpr.Flush(FLUSH_ALL);
fpr.Flush(FLUSH_ALL);
TEST(32, M(&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_DSI));
TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_DSI));
FixupBranch noMemException = J_CC(CC_Z);
// If a memory exception occurs, the exception handler will read

View File

@ -55,7 +55,7 @@
#define MEMCHECK_START \
FixupBranch memException; \
if (js.memcheck) \
{ TEST(32, M(&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_DSI)); \
{ TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_DSI)); \
memException = J_CC(CC_NZ); }
#define MEMCHECK_END \

View File

@ -193,7 +193,8 @@ void Jit64AsmRoutineManager::Generate()
//FP blocks test for FPU available, jump here if false
fpException = AlignCode4();
OR(32, M(&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_FPU_UNAVAILABLE));
LOCK();
OR(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_FPU_UNAVAILABLE));
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExceptions));
MOV(32, R(EAX), M(&NPC));
MOV(32, M(&PC), R(EAX));
@ -205,7 +206,7 @@ void Jit64AsmRoutineManager::Generate()
ABI_CallFunction(reinterpret_cast<void *>(&CoreTiming::Advance));
testExceptions = GetCodePtr();
TEST(32, M(&PowerPC::ppcState.Exceptions), Imm32(0xFFFFFFFF));
TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(0xFFFFFFFF));
FixupBranch skipExceptions = J_CC(CC_Z);
MOV(32, R(EAX), M(&PC));
MOV(32, M(&NPC), R(EAX));

View File

@ -48,7 +48,8 @@ void Jit64::sc(UGeckoInstruction inst)
gpr.Flush(FLUSH_ALL);
fpr.Flush(FLUSH_ALL);
MOV(32, M(&PC), Imm32(js.compilerPC + 4));
OR(32, M(&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_SYSCALL));
LOCK();
OR(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_SYSCALL));
WriteExceptionExit();
}

View File

@ -1716,7 +1716,8 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak
}
case SystemCall: {
unsigned InstLoc = ibuild->GetImmValue(getOp1(I));
Jit->OR(32, M(&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_SYSCALL));
Jit->LOCK();
Jit->OR(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_SYSCALL));
Jit->MOV(32, M(&PC), Imm32(InstLoc + 4));
Jit->WriteExceptionExit();
break;
@ -1759,7 +1760,7 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak
}
case FPExceptionCheckEnd: {
unsigned InstLoc = ibuild->GetImmValue(getOp1(I));
Jit->TEST(32, M(&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_DSI));
Jit->TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_DSI));
FixupBranch noMemException = Jit->J_CC(CC_Z);
// If a memory exception occurs, the exception handler will read

View File

@ -197,7 +197,8 @@ void JitILAsmRoutineManager::Generate()
fpException = AlignCode4();
MOV(32, R(EAX), M(&PC));
MOV(32, M(&NPC), R(EAX));
OR(32, M(&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_FPU_UNAVAILABLE));
LOCK();
OR(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_FPU_UNAVAILABLE));
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExceptions));
MOV(32, R(EAX), M(&NPC));
MOV(32, M(&PC), R(EAX));
@ -209,7 +210,7 @@ void JitILAsmRoutineManager::Generate()
ABI_CallFunction(reinterpret_cast<void *>(&CoreTiming::Advance));
testExceptions = GetCodePtr();
TEST(32, M(&PowerPC::ppcState.Exceptions), Imm32(0xFFFFFFFF));
TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(0xFFFFFFFF));
FixupBranch skipExceptions = J_CC(CC_Z);
MOV(32, R(EAX), M(&PC));
MOV(32, M(&NPC), R(EAX));

View File

@ -18,6 +18,7 @@
#include <float.h>
#include "Common.h"
#include "Atomic.h"
#include "MathUtil.h"
#include "ChunkFile.h"
@ -262,8 +263,11 @@ void Stop()
void CheckExceptions()
{
// Read volatile data once
u32 exceptions = ppcState.Exceptions;
// This check is unnecessary in JIT mode. However, it probably doesn't really hurt.
if (!ppcState.Exceptions)
if (!exceptions)
return;
// gcemu uses the mask 0x87C0FFFF instead of 0x0780FF77
@ -285,7 +289,7 @@ void CheckExceptions()
// set to exception type entry point
//NPC = 0x80000x00;
if (ppcState.Exceptions & EXCEPTION_ISI)
if (exceptions & EXCEPTION_ISI)
{
SRR0 = NPC;
//GenerateISIException() sets up SRR1
@ -294,9 +298,9 @@ void CheckExceptions()
NPC = 0x80000400;
INFO_LOG(POWERPC, "EXCEPTION_ISI");
ppcState.Exceptions &= ~EXCEPTION_ISI;
Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_ISI);
}
else if (ppcState.Exceptions & EXCEPTION_PROGRAM)
else if (exceptions & EXCEPTION_PROGRAM)
{
SRR0 = PC;
SRR1 = MSR & 0x87C0FFFF;
@ -307,9 +311,9 @@ void CheckExceptions()
NPC = 0x80000700;
INFO_LOG(POWERPC, "EXCEPTION_PROGRAM");
ppcState.Exceptions &= ~EXCEPTION_PROGRAM;
Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_PROGRAM);
}
else if (ppcState.Exceptions & EXCEPTION_SYSCALL)
else if (exceptions & EXCEPTION_SYSCALL)
{
SRR0 = NPC;
SRR1 = MSR & 0x87C0FFFF;
@ -318,9 +322,9 @@ void CheckExceptions()
NPC = 0x80000C00;
INFO_LOG(POWERPC, "EXCEPTION_SYSCALL (PC=%08x)", PC);
ppcState.Exceptions &= ~EXCEPTION_SYSCALL;
Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_SYSCALL);
}
else if (ppcState.Exceptions & EXCEPTION_FPU_UNAVAILABLE)
else if (exceptions & EXCEPTION_FPU_UNAVAILABLE)
{
//This happens a lot - Gamecube OS uses deferred FPU context switching
SRR0 = PC; // re-execute the instruction
@ -334,9 +338,9 @@ void CheckExceptions()
NPC = 0x80000800;
INFO_LOG(POWERPC, "EXCEPTION_FPU_UNAVAILABLE");
ppcState.Exceptions &= ~EXCEPTION_FPU_UNAVAILABLE;
Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_FPU_UNAVAILABLE);
}
else if (ppcState.Exceptions & EXCEPTION_DSI)
else if (exceptions & EXCEPTION_DSI)
{
SRR0 = PC;
SRR1 = MSR & 0x87C0FFFF;
@ -346,9 +350,9 @@ void CheckExceptions()
//DSISR and DAR regs are changed in GenerateDSIException()
INFO_LOG(POWERPC, "EXCEPTION_DSI");
ppcState.Exceptions &= ~EXCEPTION_DSI;
Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_DSI);
}
else if (ppcState.Exceptions & EXCEPTION_ALIGNMENT)
else if (exceptions & EXCEPTION_ALIGNMENT)
{
//This never happens ATM
// perhaps we can get dcb* instructions to use this :p
@ -361,13 +365,13 @@ void CheckExceptions()
//TODO crazy amount of DSISR options to check out
INFO_LOG(POWERPC, "EXCEPTION_ALIGNMENT");
ppcState.Exceptions &= ~EXCEPTION_ALIGNMENT;
Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_ALIGNMENT);
}
// EXTERNAL INTERRUPT
else if (MSR & 0x0008000) //hacky...the exception shouldn't be generated if EE isn't set...
{
if (ppcState.Exceptions & EXCEPTION_EXTERNAL_INT)
if (exceptions & EXCEPTION_EXTERNAL_INT)
{
// Pokemon gets this "too early", it hasn't a handler yet
SRR0 = NPC;
@ -377,11 +381,11 @@ void CheckExceptions()
NPC = 0x80000500;
INFO_LOG(POWERPC, "EXCEPTION_EXTERNAL_INT");
ppcState.Exceptions &= ~EXCEPTION_EXTERNAL_INT;
Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_EXTERNAL_INT);
_dbg_assert_msg_(POWERPC, (SRR1 & 0x02) != 0, "GEKKO", "EXTERNAL_INT unrecoverable???");
}
else if (ppcState.Exceptions & EXCEPTION_DECREMENTER)
else if (exceptions & EXCEPTION_DECREMENTER)
{
SRR0 = NPC;
SRR1 = MSR & 0x87C0FFFF;
@ -390,12 +394,12 @@ void CheckExceptions()
NPC = 0x80000900;
INFO_LOG(POWERPC, "EXCEPTION_DECREMENTER");
ppcState.Exceptions &= ~EXCEPTION_DECREMENTER;
Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_DECREMENTER);
}
else
{
_dbg_assert_msg_(POWERPC, 0, "Unknown EXT interrupt: Exceptions == %08x", ppcState.Exceptions);
ERROR_LOG(POWERPC, "Unknown EXTERNAL INTERRUPT exception: Exceptions == %08x", ppcState.Exceptions);
_dbg_assert_msg_(POWERPC, 0, "Unknown EXT interrupt: Exceptions == %08x", exceptions);
ERROR_LOG(POWERPC, "Unknown EXTERNAL INTERRUPT exception: Exceptions == %08x", exceptions);
}
}
}

View File

@ -59,7 +59,7 @@ struct GC_ALIGNED64(PowerPCState)
u32 fpscr; // floating point flags/status bits
// Exception management.
u32 Exceptions;
volatile u32 Exceptions;
u32 sr[16]; // Segment registers.