Merge pull request #6585 from lioncash/exception

Interpreter_LoadStore: Handle alignment exceptions in lmw, lwarx, stmw, and stwcx + fixes for eciwx and ecowx
This commit is contained in:
Markus Wick 2018-04-03 09:52:36 +02:00 committed by GitHub
commit 1e0f72f2da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 57 additions and 9 deletions

View File

@ -17,6 +17,21 @@
bool Interpreter::m_reserve; bool Interpreter::m_reserve;
u32 Interpreter::m_reserve_address; u32 Interpreter::m_reserve_address;
namespace
{
void GenerateAlignmentException(u32 address)
{
PowerPC::ppcState.Exceptions |= EXCEPTION_ALIGNMENT;
PowerPC::ppcState.spr[SPR_DAR] = address;
}
void GenerateDSIException(u32 address)
{
PowerPC::ppcState.Exceptions |= EXCEPTION_DSI;
PowerPC::ppcState.spr[SPR_DAR] = address;
}
}
u32 Interpreter::Helper_Get_EA(const UGeckoInstruction inst) u32 Interpreter::Helper_Get_EA(const UGeckoInstruction inst)
{ {
return inst.RA ? (rGPR[inst.RA] + inst.SIMM_16) : (u32)inst.SIMM_16; return inst.RA ? (rGPR[inst.RA] + inst.SIMM_16) : (u32)inst.SIMM_16;
@ -198,6 +213,12 @@ void Interpreter::lmw(UGeckoInstruction inst)
{ {
u32 address = Helper_Get_EA(inst); u32 address = Helper_Get_EA(inst);
if ((address & 0b11) != 0)
{
GenerateAlignmentException(address);
return;
}
for (int i = inst.RD; i <= 31; i++, address += 4) for (int i = inst.RD; i <= 31; i++, address += 4)
{ {
const u32 temp_reg = PowerPC::Read_U32(address); const u32 temp_reg = PowerPC::Read_U32(address);
@ -220,6 +241,12 @@ void Interpreter::stmw(UGeckoInstruction inst)
{ {
u32 address = Helper_Get_EA(inst); u32 address = Helper_Get_EA(inst);
if ((address & 0b11) != 0)
{
GenerateAlignmentException(address);
return;
}
for (int i = inst.RS; i <= 31; i++, address += 4) for (int i = inst.RS; i <= 31; i++, address += 4)
{ {
PowerPC::Write_U32(rGPR[i], address); PowerPC::Write_U32(rGPR[i], address);
@ -410,10 +437,15 @@ void Interpreter::eciwx(UGeckoInstruction inst)
if (!(PowerPC::ppcState.spr[SPR_EAR] & 0x80000000)) if (!(PowerPC::ppcState.spr[SPR_EAR] & 0x80000000))
{ {
PowerPC::ppcState.Exceptions |= EXCEPTION_DSI; GenerateDSIException(EA);
return;
} }
if (EA & 3) if (EA & 3)
PowerPC::ppcState.Exceptions |= EXCEPTION_ALIGNMENT; {
GenerateAlignmentException(EA);
return;
}
rGPR[inst.RD] = PowerPC::Read_U32(EA); rGPR[inst.RD] = PowerPC::Read_U32(EA);
} }
@ -424,10 +456,15 @@ void Interpreter::ecowx(UGeckoInstruction inst)
if (!(PowerPC::ppcState.spr[SPR_EAR] & 0x80000000)) if (!(PowerPC::ppcState.spr[SPR_EAR] & 0x80000000))
{ {
PowerPC::ppcState.Exceptions |= EXCEPTION_DSI; GenerateDSIException(EA);
return;
} }
if (EA & 3) if (EA & 3)
PowerPC::ppcState.Exceptions |= EXCEPTION_ALIGNMENT; {
GenerateAlignmentException(EA);
return;
}
PowerPC::Write_U32(rGPR[inst.RS], EA); PowerPC::Write_U32(rGPR[inst.RS], EA);
} }
@ -780,6 +817,13 @@ void Interpreter::stwbrx(UGeckoInstruction inst)
void Interpreter::lwarx(UGeckoInstruction inst) void Interpreter::lwarx(UGeckoInstruction inst)
{ {
const u32 address = Helper_Get_EA_X(inst); const u32 address = Helper_Get_EA_X(inst);
if ((address & 0b11) != 0)
{
GenerateAlignmentException(address);
return;
}
const u32 temp = PowerPC::Read_U32(address); const u32 temp = PowerPC::Read_U32(address);
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI)) if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
@ -790,13 +834,19 @@ void Interpreter::lwarx(UGeckoInstruction inst)
} }
} }
void Interpreter::stwcxd(UGeckoInstruction inst)
{
// Stores Word Conditional indeXed // Stores Word Conditional indeXed
if (m_reserve) void Interpreter::stwcxd(UGeckoInstruction inst)
{ {
const u32 address = Helper_Get_EA_X(inst); const u32 address = Helper_Get_EA_X(inst);
if ((address & 0b11) != 0)
{
GenerateAlignmentException(address);
return;
}
if (m_reserve)
{
if (address == m_reserve_address) if (address == m_reserve_address)
{ {
PowerPC::Write_U32(rGPR[inst.RS], address); PowerPC::Write_U32(rGPR[inst.RS], address);

View File

@ -474,8 +474,6 @@ void CheckExceptions()
} }
else if (exceptions & EXCEPTION_ALIGNMENT) else if (exceptions & EXCEPTION_ALIGNMENT)
{ {
// This never happens ATM
// perhaps we can get dcb* instructions to use this :p
SRR0 = PC; SRR0 = PC;
SRR1 = MSR & 0x87C0FFFF; SRR1 = MSR & 0x87C0FFFF;
MSR |= (MSR >> 16) & 1; MSR |= (MSR >> 16) & 1;