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:
parent
625d78fb59
commit
8d6f98439e
|
@ -16,6 +16,7 @@
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
#include "Atomic.h"
|
||||||
|
|
||||||
#include "GPFifo.h"
|
#include "GPFifo.h"
|
||||||
#include "Memmap.h"
|
#include "Memmap.h"
|
||||||
|
@ -605,7 +606,7 @@ void GenerateDSIException(u32 _EffectiveAddress, bool _bWrite)
|
||||||
|
|
||||||
PowerPC::ppcState.spr[SPR_DAR] = _EffectiveAddress;
|
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);
|
SRR1 = (1 << 30) | (MSR & 0x3fffff);
|
||||||
NPC = _EffectiveAddress;
|
NPC = _EffectiveAddress;
|
||||||
|
|
||||||
PowerPC::ppcState.Exceptions |= EXCEPTION_ISI;
|
Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_ISI);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
#include "Atomic.h"
|
||||||
#include "ChunkFile.h"
|
#include "ChunkFile.h"
|
||||||
#include "../PowerPC/PowerPC.h"
|
#include "../PowerPC/PowerPC.h"
|
||||||
|
|
||||||
|
@ -155,7 +156,7 @@ void Write32(const u32 _uValue, const u32 _iAddress)
|
||||||
switch(_iAddress & 0xFFF)
|
switch(_iAddress & 0xFFF)
|
||||||
{
|
{
|
||||||
case PI_INTERRUPT_CAUSE:
|
case PI_INTERRUPT_CAUSE:
|
||||||
m_InterruptCause &= ~_uValue; // writes turn them off
|
Common::AtomicAnd(m_InterruptCause, ~_uValue); // writes turn them off
|
||||||
UpdateException();
|
UpdateException();
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -203,9 +204,9 @@ void Write32(const u32 _uValue, const u32 _iAddress)
|
||||||
void UpdateException()
|
void UpdateException()
|
||||||
{
|
{
|
||||||
if ((m_InterruptCause & m_InterruptMask) != 0)
|
if ((m_InterruptCause & m_InterruptMask) != 0)
|
||||||
PowerPC::ppcState.Exceptions |= EXCEPTION_EXTERNAL_INT;
|
Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_EXTERNAL_INT);
|
||||||
else
|
else
|
||||||
PowerPC::ppcState.Exceptions &= ~EXCEPTION_EXTERNAL_INT;
|
Common::AtomicAnd(PowerPC::ppcState.Exceptions, ~EXCEPTION_EXTERNAL_INT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *Debug_GetInterruptName(u32 _causemask)
|
static const char *Debug_GetInterruptName(u32 _causemask)
|
||||||
|
@ -247,9 +248,9 @@ void SetInterrupt(u32 _causemask, bool _bSet)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_bSet)
|
if (_bSet)
|
||||||
m_InterruptCause |= _causemask;
|
Common::AtomicOr(m_InterruptCause, _causemask);
|
||||||
else
|
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
|
// 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)
|
// if the interrupt cause is eliminated. that isnt done by software (afaik)
|
||||||
UpdateException();
|
UpdateException();
|
||||||
|
@ -258,9 +259,9 @@ void SetInterrupt(u32 _causemask, bool _bSet)
|
||||||
void SetResetButton(bool _bSet)
|
void SetResetButton(bool _bSet)
|
||||||
{
|
{
|
||||||
if (_bSet)
|
if (_bSet)
|
||||||
m_InterruptCause &= ~INT_CAUSE_RST_BUTTON;
|
Common::AtomicAnd(m_InterruptCause, ~INT_CAUSE_RST_BUTTON);
|
||||||
else
|
else
|
||||||
m_InterruptCause |= INT_CAUSE_RST_BUTTON;
|
Common::AtomicOr(m_InterruptCause, INT_CAUSE_RST_BUTTON);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ToggleResetButtonCallback(u64 userdata, int cyclesLate)
|
void ToggleResetButtonCallback(u64 userdata, int cyclesLate)
|
||||||
|
|
|
@ -58,6 +58,7 @@ IPC_HLE_PERIOD: For the Wiimote this is the call schedule:
|
||||||
|
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
#include "Atomic.h"
|
||||||
#include "../PatchEngine.h"
|
#include "../PatchEngine.h"
|
||||||
#include "SystemTimers.h"
|
#include "SystemTimers.h"
|
||||||
#include "../PluginManager.h"
|
#include "../PluginManager.h"
|
||||||
|
@ -192,7 +193,7 @@ void DecrementerCallback(u64 userdata, int cyclesLate)
|
||||||
// A: Because it's 64bit (0xffffffffffffffff)...?
|
// A: Because it's 64bit (0xffffffffffffffff)...?
|
||||||
fakeDec = -1;
|
fakeDec = -1;
|
||||||
PowerPC::ppcState.spr[SPR_DEC] = 0xFFFFFFFF;
|
PowerPC::ppcState.spr[SPR_DEC] = 0xFFFFFFFF;
|
||||||
PowerPC::ppcState.Exceptions |= EXCEPTION_DECREMENTER;
|
Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_DECREMENTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DecrementerSet()
|
void DecrementerSet()
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "../../ConfigManager.h"
|
#include "../../ConfigManager.h"
|
||||||
#include "PowerPCDisasm.h"
|
#include "PowerPCDisasm.h"
|
||||||
#include "../../IPC_HLE/WII_IPC_HLE.h"
|
#include "../../IPC_HLE/WII_IPC_HLE.h"
|
||||||
|
#include "Atomic.h"
|
||||||
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -107,7 +108,7 @@ void Interpreter::SingleStepInner(void)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PowerPC::ppcState.Exceptions |= EXCEPTION_FPU_UNAVAILABLE;
|
Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_FPU_UNAVAILABLE);
|
||||||
PowerPC::CheckExceptions();
|
PowerPC::CheckExceptions();
|
||||||
m_EndBlock = true;
|
m_EndBlock = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "../../HW/CPU.h"
|
#include "../../HW/CPU.h"
|
||||||
#include "../../HLE/HLE.h"
|
#include "../../HLE/HLE.h"
|
||||||
#include "../PPCAnalyst.h"
|
#include "../PPCAnalyst.h"
|
||||||
|
#include "Atomic.h"
|
||||||
|
|
||||||
void Interpreter::bx(UGeckoInstruction _inst)
|
void Interpreter::bx(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
|
@ -134,7 +135,7 @@ void Interpreter::rfid(UGeckoInstruction _inst)
|
||||||
// We do it anyway, though :P
|
// We do it anyway, though :P
|
||||||
void Interpreter::sc(UGeckoInstruction _inst)
|
void Interpreter::sc(UGeckoInstruction _inst)
|
||||||
{
|
{
|
||||||
PowerPC::ppcState.Exceptions |= EXCEPTION_SYSCALL;
|
Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_SYSCALL);
|
||||||
PowerPC::CheckExceptions();
|
PowerPC::CheckExceptions();
|
||||||
m_EndBlock = true;
|
m_EndBlock = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#include "Interpreter.h"
|
#include "Interpreter.h"
|
||||||
#include "../../Core.h"
|
#include "../../Core.h"
|
||||||
|
#include "Atomic.h"
|
||||||
|
|
||||||
void Interpreter::Helper_UpdateCR0(u32 _uValue)
|
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 & 0x02))
|
||||||
|| (((u32)a >(u32)b) && (TO & 0x01)))
|
|| (((u32)a >(u32)b) && (TO & 0x01)))
|
||||||
{
|
{
|
||||||
PowerPC::ppcState.Exceptions |= EXCEPTION_PROGRAM;
|
Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_PROGRAM);
|
||||||
PowerPC::CheckExceptions();
|
PowerPC::CheckExceptions();
|
||||||
m_EndBlock = true; // Dunno about this
|
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 & 0x02))
|
||||||
|| (((u32)a >(u32)b) && (TO & 0x01)))
|
|| (((u32)a >(u32)b) && (TO & 0x01)))
|
||||||
{
|
{
|
||||||
PowerPC::ppcState.Exceptions |= EXCEPTION_PROGRAM;
|
Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_PROGRAM);
|
||||||
PowerPC::CheckExceptions();
|
PowerPC::CheckExceptions();
|
||||||
m_EndBlock = true; // Dunno about this
|
m_EndBlock = true; // Dunno about this
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
// http://code.google.com/p/dolphin-emu/
|
// http://code.google.com/p/dolphin-emu/
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
#include "Atomic.h"
|
||||||
#include "MathUtil.h"
|
#include "MathUtil.h"
|
||||||
|
|
||||||
#include "../../HW/Memmap.h"
|
#include "../../HW/Memmap.h"
|
||||||
|
@ -405,10 +406,10 @@ void Interpreter::eciwx(UGeckoInstruction _inst)
|
||||||
|
|
||||||
if (!(PowerPC::ppcState.spr[SPR_EAR] & 0x80000000))
|
if (!(PowerPC::ppcState.spr[SPR_EAR] & 0x80000000))
|
||||||
{
|
{
|
||||||
PowerPC::ppcState.Exceptions |= EXCEPTION_DSI;
|
Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_DSI);
|
||||||
}
|
}
|
||||||
if (EA & 3)
|
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",
|
// _assert_msg_(POWERPC,0,"eciwx - fill r%i with word @ %08x from device %02x",
|
||||||
// _inst.RS, EA, PowerPC::ppcState.spr[SPR_EAR] & 0x1f);
|
// _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))
|
if (!(PowerPC::ppcState.spr[SPR_EAR] & 0x80000000))
|
||||||
{
|
{
|
||||||
PowerPC::ppcState.Exceptions |= EXCEPTION_DSI;
|
Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_DSI);
|
||||||
}
|
}
|
||||||
if (EA & 3)
|
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",
|
// _assert_msg_(POWERPC,0,"ecowx - send stw request (%08x@%08x) to device %02x",
|
||||||
// m_GPR[_inst.RS], EA, PowerPC::ppcState.spr[SPR_EAR] & 0x1f);
|
// m_GPR[_inst.RS], EA, PowerPC::ppcState.spr[SPR_EAR] & 0x1f);
|
||||||
|
|
|
@ -36,6 +36,7 @@ static const unsigned short FPU_ROUND_MASK = 3 << 10;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "CPUDetect.h"
|
#include "CPUDetect.h"
|
||||||
|
#include "Atomic.h"
|
||||||
#include "../../CoreTiming.h"
|
#include "../../CoreTiming.h"
|
||||||
#include "../../HW/Memmap.h"
|
#include "../../HW/Memmap.h"
|
||||||
#include "../../HW/GPFifo.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
|
if (!(oldValue >> 31) && (m_GPR[_inst.RD]>>31)) //top bit from 0 to 1
|
||||||
{
|
{
|
||||||
PanicAlert("Interesting - Software triggered Decrementer exception");
|
PanicAlert("Interesting - Software triggered Decrementer exception");
|
||||||
PowerPC::ppcState.Exceptions |= EXCEPTION_DECREMENTER;
|
Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_DECREMENTER);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -562,7 +562,7 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc
|
||||||
gpr.Flush(FLUSH_ALL);
|
gpr.Flush(FLUSH_ALL);
|
||||||
fpr.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);
|
FixupBranch noMemException = J_CC(CC_Z);
|
||||||
|
|
||||||
// If a memory exception occurs, the exception handler will read
|
// If a memory exception occurs, the exception handler will read
|
||||||
|
|
|
@ -55,7 +55,7 @@
|
||||||
#define MEMCHECK_START \
|
#define MEMCHECK_START \
|
||||||
FixupBranch memException; \
|
FixupBranch memException; \
|
||||||
if (js.memcheck) \
|
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); }
|
memException = J_CC(CC_NZ); }
|
||||||
|
|
||||||
#define MEMCHECK_END \
|
#define MEMCHECK_END \
|
||||||
|
|
|
@ -193,7 +193,8 @@ void Jit64AsmRoutineManager::Generate()
|
||||||
|
|
||||||
//FP blocks test for FPU available, jump here if false
|
//FP blocks test for FPU available, jump here if false
|
||||||
fpException = AlignCode4();
|
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));
|
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExceptions));
|
||||||
MOV(32, R(EAX), M(&NPC));
|
MOV(32, R(EAX), M(&NPC));
|
||||||
MOV(32, M(&PC), R(EAX));
|
MOV(32, M(&PC), R(EAX));
|
||||||
|
@ -205,7 +206,7 @@ void Jit64AsmRoutineManager::Generate()
|
||||||
ABI_CallFunction(reinterpret_cast<void *>(&CoreTiming::Advance));
|
ABI_CallFunction(reinterpret_cast<void *>(&CoreTiming::Advance));
|
||||||
|
|
||||||
testExceptions = GetCodePtr();
|
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);
|
FixupBranch skipExceptions = J_CC(CC_Z);
|
||||||
MOV(32, R(EAX), M(&PC));
|
MOV(32, R(EAX), M(&PC));
|
||||||
MOV(32, M(&NPC), R(EAX));
|
MOV(32, M(&NPC), R(EAX));
|
||||||
|
|
|
@ -48,7 +48,8 @@ void Jit64::sc(UGeckoInstruction inst)
|
||||||
gpr.Flush(FLUSH_ALL);
|
gpr.Flush(FLUSH_ALL);
|
||||||
fpr.Flush(FLUSH_ALL);
|
fpr.Flush(FLUSH_ALL);
|
||||||
MOV(32, M(&PC), Imm32(js.compilerPC + 4));
|
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();
|
WriteExceptionExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1716,7 +1716,8 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak
|
||||||
}
|
}
|
||||||
case SystemCall: {
|
case SystemCall: {
|
||||||
unsigned InstLoc = ibuild->GetImmValue(getOp1(I));
|
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->MOV(32, M(&PC), Imm32(InstLoc + 4));
|
||||||
Jit->WriteExceptionExit();
|
Jit->WriteExceptionExit();
|
||||||
break;
|
break;
|
||||||
|
@ -1759,7 +1760,7 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak
|
||||||
}
|
}
|
||||||
case FPExceptionCheckEnd: {
|
case FPExceptionCheckEnd: {
|
||||||
unsigned InstLoc = ibuild->GetImmValue(getOp1(I));
|
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);
|
FixupBranch noMemException = Jit->J_CC(CC_Z);
|
||||||
|
|
||||||
// If a memory exception occurs, the exception handler will read
|
// If a memory exception occurs, the exception handler will read
|
||||||
|
|
|
@ -197,7 +197,8 @@ void JitILAsmRoutineManager::Generate()
|
||||||
fpException = AlignCode4();
|
fpException = AlignCode4();
|
||||||
MOV(32, R(EAX), M(&PC));
|
MOV(32, R(EAX), M(&PC));
|
||||||
MOV(32, M(&NPC), R(EAX));
|
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));
|
ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExceptions));
|
||||||
MOV(32, R(EAX), M(&NPC));
|
MOV(32, R(EAX), M(&NPC));
|
||||||
MOV(32, M(&PC), R(EAX));
|
MOV(32, M(&PC), R(EAX));
|
||||||
|
@ -209,7 +210,7 @@ void JitILAsmRoutineManager::Generate()
|
||||||
ABI_CallFunction(reinterpret_cast<void *>(&CoreTiming::Advance));
|
ABI_CallFunction(reinterpret_cast<void *>(&CoreTiming::Advance));
|
||||||
|
|
||||||
testExceptions = GetCodePtr();
|
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);
|
FixupBranch skipExceptions = J_CC(CC_Z);
|
||||||
MOV(32, R(EAX), M(&PC));
|
MOV(32, R(EAX), M(&PC));
|
||||||
MOV(32, M(&NPC), R(EAX));
|
MOV(32, M(&NPC), R(EAX));
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
#include "Atomic.h"
|
||||||
#include "MathUtil.h"
|
#include "MathUtil.h"
|
||||||
#include "ChunkFile.h"
|
#include "ChunkFile.h"
|
||||||
|
|
||||||
|
@ -262,8 +263,11 @@ void Stop()
|
||||||
|
|
||||||
void CheckExceptions()
|
void CheckExceptions()
|
||||||
{
|
{
|
||||||
|
// Read volatile data once
|
||||||
|
u32 exceptions = ppcState.Exceptions;
|
||||||
|
|
||||||
// This check is unnecessary in JIT mode. However, it probably doesn't really hurt.
|
// This check is unnecessary in JIT mode. However, it probably doesn't really hurt.
|
||||||
if (!ppcState.Exceptions)
|
if (!exceptions)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// gcemu uses the mask 0x87C0FFFF instead of 0x0780FF77
|
// gcemu uses the mask 0x87C0FFFF instead of 0x0780FF77
|
||||||
|
@ -285,7 +289,7 @@ void CheckExceptions()
|
||||||
// set to exception type entry point
|
// set to exception type entry point
|
||||||
//NPC = 0x80000x00;
|
//NPC = 0x80000x00;
|
||||||
|
|
||||||
if (ppcState.Exceptions & EXCEPTION_ISI)
|
if (exceptions & EXCEPTION_ISI)
|
||||||
{
|
{
|
||||||
SRR0 = NPC;
|
SRR0 = NPC;
|
||||||
//GenerateISIException() sets up SRR1
|
//GenerateISIException() sets up SRR1
|
||||||
|
@ -294,9 +298,9 @@ void CheckExceptions()
|
||||||
NPC = 0x80000400;
|
NPC = 0x80000400;
|
||||||
|
|
||||||
INFO_LOG(POWERPC, "EXCEPTION_ISI");
|
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;
|
SRR0 = PC;
|
||||||
SRR1 = MSR & 0x87C0FFFF;
|
SRR1 = MSR & 0x87C0FFFF;
|
||||||
|
@ -307,9 +311,9 @@ void CheckExceptions()
|
||||||
NPC = 0x80000700;
|
NPC = 0x80000700;
|
||||||
|
|
||||||
INFO_LOG(POWERPC, "EXCEPTION_PROGRAM");
|
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;
|
SRR0 = NPC;
|
||||||
SRR1 = MSR & 0x87C0FFFF;
|
SRR1 = MSR & 0x87C0FFFF;
|
||||||
|
@ -318,9 +322,9 @@ void CheckExceptions()
|
||||||
NPC = 0x80000C00;
|
NPC = 0x80000C00;
|
||||||
|
|
||||||
INFO_LOG(POWERPC, "EXCEPTION_SYSCALL (PC=%08x)", PC);
|
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
|
//This happens a lot - Gamecube OS uses deferred FPU context switching
|
||||||
SRR0 = PC; // re-execute the instruction
|
SRR0 = PC; // re-execute the instruction
|
||||||
|
@ -334,9 +338,9 @@ void CheckExceptions()
|
||||||
NPC = 0x80000800;
|
NPC = 0x80000800;
|
||||||
|
|
||||||
INFO_LOG(POWERPC, "EXCEPTION_FPU_UNAVAILABLE");
|
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;
|
SRR0 = PC;
|
||||||
SRR1 = MSR & 0x87C0FFFF;
|
SRR1 = MSR & 0x87C0FFFF;
|
||||||
|
@ -346,9 +350,9 @@ void CheckExceptions()
|
||||||
//DSISR and DAR regs are changed in GenerateDSIException()
|
//DSISR and DAR regs are changed in GenerateDSIException()
|
||||||
|
|
||||||
INFO_LOG(POWERPC, "EXCEPTION_DSI");
|
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
|
//This never happens ATM
|
||||||
// perhaps we can get dcb* instructions to use this :p
|
// 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
|
//TODO crazy amount of DSISR options to check out
|
||||||
|
|
||||||
INFO_LOG(POWERPC, "EXCEPTION_ALIGNMENT");
|
INFO_LOG(POWERPC, "EXCEPTION_ALIGNMENT");
|
||||||
ppcState.Exceptions &= ~EXCEPTION_ALIGNMENT;
|
Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_ALIGNMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// EXTERNAL INTERRUPT
|
// EXTERNAL INTERRUPT
|
||||||
else if (MSR & 0x0008000) //hacky...the exception shouldn't be generated if EE isn't set...
|
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
|
// Pokemon gets this "too early", it hasn't a handler yet
|
||||||
SRR0 = NPC;
|
SRR0 = NPC;
|
||||||
|
@ -377,11 +381,11 @@ void CheckExceptions()
|
||||||
NPC = 0x80000500;
|
NPC = 0x80000500;
|
||||||
|
|
||||||
INFO_LOG(POWERPC, "EXCEPTION_EXTERNAL_INT");
|
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???");
|
_dbg_assert_msg_(POWERPC, (SRR1 & 0x02) != 0, "GEKKO", "EXTERNAL_INT unrecoverable???");
|
||||||
}
|
}
|
||||||
else if (ppcState.Exceptions & EXCEPTION_DECREMENTER)
|
else if (exceptions & EXCEPTION_DECREMENTER)
|
||||||
{
|
{
|
||||||
SRR0 = NPC;
|
SRR0 = NPC;
|
||||||
SRR1 = MSR & 0x87C0FFFF;
|
SRR1 = MSR & 0x87C0FFFF;
|
||||||
|
@ -390,12 +394,12 @@ void CheckExceptions()
|
||||||
NPC = 0x80000900;
|
NPC = 0x80000900;
|
||||||
|
|
||||||
INFO_LOG(POWERPC, "EXCEPTION_DECREMENTER");
|
INFO_LOG(POWERPC, "EXCEPTION_DECREMENTER");
|
||||||
ppcState.Exceptions &= ~EXCEPTION_DECREMENTER;
|
Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_DECREMENTER);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_dbg_assert_msg_(POWERPC, 0, "Unknown EXT interrupt: Exceptions == %08x", ppcState.Exceptions);
|
_dbg_assert_msg_(POWERPC, 0, "Unknown EXT interrupt: Exceptions == %08x", exceptions);
|
||||||
ERROR_LOG(POWERPC, "Unknown EXTERNAL INTERRUPT exception: Exceptions == %08x", ppcState.Exceptions);
|
ERROR_LOG(POWERPC, "Unknown EXTERNAL INTERRUPT exception: Exceptions == %08x", exceptions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ struct GC_ALIGNED64(PowerPCState)
|
||||||
u32 fpscr; // floating point flags/status bits
|
u32 fpscr; // floating point flags/status bits
|
||||||
|
|
||||||
// Exception management.
|
// Exception management.
|
||||||
u32 Exceptions;
|
volatile u32 Exceptions;
|
||||||
|
|
||||||
u32 sr[16]; // Segment registers.
|
u32 sr[16]; // Segment registers.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue