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:
commit
1e0f72f2da
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stores Word Conditional indeXed
|
||||||
void Interpreter::stwcxd(UGeckoInstruction inst)
|
void Interpreter::stwcxd(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
// Stores Word Conditional indeXed
|
|
||||||
if (m_reserve)
|
|
||||||
{
|
|
||||||
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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue