Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PowerPC: Raise alignment exceptions in more situations #9865

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions Source/Core/Common/Arm64Emitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -673,14 +673,19 @@ static constexpr u32 MaskImm26(s64 distance)
}

// FixupBranch branching
void ARM64XEmitter::SetJumpTarget(FixupBranch const& branch)
void ARM64XEmitter::SetJumpTarget(const FixupBranch& branch)
{
SetJumpTarget(branch, m_code);
}

void ARM64XEmitter::SetJumpTarget(const FixupBranch& branch, const u8* target)
{
if (!branch.ptr)
return;

bool Not = false;
u32 inst = 0;
s64 distance = (s64)(m_code - branch.ptr);
s64 distance = static_cast<s64>(target - branch.ptr);
distance >>= 2;

switch (branch.type)
Expand Down
3 changes: 2 additions & 1 deletion Source/Core/Common/Arm64Emitter.h
Original file line number Diff line number Diff line change
Expand Up @@ -695,7 +695,8 @@ class ARM64XEmitter
bool HasWriteFailed() const { return m_write_failed; }

// FixupBranch branching
void SetJumpTarget(FixupBranch const& branch);
void SetJumpTarget(const FixupBranch& branch);
void SetJumpTarget(const FixupBranch& branch, const u8* target);
[[nodiscard]] FixupBranch CBZ(ARM64Reg Rt);
[[nodiscard]] FixupBranch CBNZ(ARM64Reg Rt);
[[nodiscard]] FixupBranch B(CCFlags cond);
Expand Down
41 changes: 41 additions & 0 deletions Source/Core/Common/x64Emitter.h
Original file line number Diff line number Diff line change
Expand Up @@ -1098,6 +1098,15 @@ class XEmitter
ABI_CallFunction(func);
}

template <typename FunctionPointer>
void ABI_CallFunctionPCC(FunctionPointer func, const void* param1, u32 param2, u32 param3)
{
MOV(64, R(ABI_PARAM1), Imm64(reinterpret_cast<u64>(param1)));
MOV(32, R(ABI_PARAM2), Imm32(param2));
MOV(32, R(ABI_PARAM3), Imm32(param3));
ABI_CallFunction(func);
}

template <typename FunctionPointer>
void ABI_CallFunctionPPC(FunctionPointer func, const void* param1, const void* param2, u32 param3)
{
Expand Down Expand Up @@ -1126,6 +1135,16 @@ class XEmitter
ABI_CallFunction(func);
}

template <typename FunctionPointer>
void ABI_CallFunctionPRC(FunctionPointer func, const void* ptr, X64Reg reg1, u32 param3)
{
if (reg1 != ABI_PARAM2)
MOV(64, R(ABI_PARAM2), R(reg1));
MOV(64, R(ABI_PARAM1), Imm64(reinterpret_cast<u64>(ptr)));
MOV(32, R(ABI_PARAM3), Imm32(param3));
ABI_CallFunction(func);
}

// Pass two registers as parameters.
template <typename FunctionPointer>
void ABI_CallFunctionRR(FunctionPointer func, X64Reg reg1, X64Reg reg2)
Expand All @@ -1143,6 +1162,16 @@ class XEmitter
ABI_CallFunction(func);
}

template <typename FunctionPointer>
void ABI_CallFunctionPRRC(FunctionPointer func, const void* ptr, X64Reg reg1, X64Reg reg2,
u32 param4)
{
MOVTwo(64, ABI_PARAM2, reg1, 0, ABI_PARAM3, reg2);
MOV(64, R(ABI_PARAM1), Imm64(reinterpret_cast<u64>(ptr)));
MOV(32, R(ABI_PARAM4), Imm32(param4));
ABI_CallFunction(func);
}

template <typename FunctionPointer>
void ABI_CallFunctionAC(int bits, FunctionPointer func, const Gen::OpArg& arg1, u32 param2)
{
Expand All @@ -1158,8 +1187,20 @@ class XEmitter
{
if (!arg2.IsSimpleReg(ABI_PARAM2))
MOV(bits, R(ABI_PARAM2), arg2);
MOV(64, R(ABI_PARAM1), Imm64(reinterpret_cast<u64>(ptr1)));
MOV(32, R(ABI_PARAM3), Imm32(param3));
ABI_CallFunction(func);
}

template <typename FunctionPointer>
void ABI_CallFunctionPACC(int bits, FunctionPointer func, const void* ptr1,
const Gen::OpArg& arg2, u32 param3, u32 param4)
{
if (!arg2.IsSimpleReg(ABI_PARAM2))
MOV(bits, R(ABI_PARAM2), arg2);
MOV(64, R(ABI_PARAM1), Imm64(reinterpret_cast<u64>(ptr1)));
MOV(32, R(ABI_PARAM3), Imm32(param3));
MOV(32, R(ABI_PARAM4), Imm32(param4));
ABI_CallFunction(func);
}

Expand Down
12 changes: 6 additions & 6 deletions Source/Core/Core/Boot/Boot_BS2Emu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,9 +172,9 @@ bool CBoot::RunApploader(Core::System& system, const Core::CPUThreadGuard& guard
ppc_state.gpr[4] = iAppLoaderFuncAddr + 4;
ppc_state.gpr[5] = iAppLoaderFuncAddr + 8;
RunFunction(system, *entry);
const u32 iAppLoaderInit = mmu.Read_U32(iAppLoaderFuncAddr + 0);
const u32 iAppLoaderMain = mmu.Read_U32(iAppLoaderFuncAddr + 4);
const u32 iAppLoaderClose = mmu.Read_U32(iAppLoaderFuncAddr + 8);
const u32 iAppLoaderInit = mmu.Read_U32(iAppLoaderFuncAddr + 0, UGeckoInstruction{});
const u32 iAppLoaderMain = mmu.Read_U32(iAppLoaderFuncAddr + 4, UGeckoInstruction{});
const u32 iAppLoaderClose = mmu.Read_U32(iAppLoaderFuncAddr + 8, UGeckoInstruction{});

// iAppLoaderInit
DEBUG_LOG_FMT(BOOT, "Call iAppLoaderInit");
Expand All @@ -200,9 +200,9 @@ bool CBoot::RunApploader(Core::System& system, const Core::CPUThreadGuard& guard
// iAppLoaderMain returns 0 when there are no more sections to copy.
while (ppc_state.gpr[3] != 0x00)
{
const u32 ram_address = mmu.Read_U32(0x81300004);
const u32 length = mmu.Read_U32(0x81300008);
const u32 dvd_offset = mmu.Read_U32(0x8130000c) << (is_wii ? 2 : 0);
const u32 ram_address = mmu.Read_U32(0x81300004, UGeckoInstruction{});
const u32 length = mmu.Read_U32(0x81300008, UGeckoInstruction{});
const u32 dvd_offset = mmu.Read_U32(0x8130000c, UGeckoInstruction{}) << (is_wii ? 2 : 0);

INFO_LOG_FMT(BOOT, "DVDRead: offset: {:08x} memOffset: {:08x} length: {}", dvd_offset,
ram_address, length);
Expand Down
1 change: 1 addition & 0 deletions Source/Core/Core/Config/MainSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ const Info<bool> MAIN_LOW_DCBZ_HACK{{System::Main, "Core", "LowDCBZHack"}, false
const Info<bool> MAIN_FLOAT_EXCEPTIONS{{System::Main, "Core", "FloatExceptions"}, false};
const Info<bool> MAIN_DIVIDE_BY_ZERO_EXCEPTIONS{{System::Main, "Core", "DivByZeroExceptions"},
false};
const Info<bool> MAIN_ALIGNMENT_EXCEPTIONS{{System::Main, "Core", "AlignmentExceptions"}, false};
const Info<bool> MAIN_FPRF{{System::Main, "Core", "FPRF"}, false};
const Info<bool> MAIN_ACCURATE_NANS{{System::Main, "Core", "AccurateNaNs"}, false};
const Info<bool> MAIN_DISABLE_ICACHE{{System::Main, "Core", "DisableICache"}, false};
Expand Down
1 change: 1 addition & 0 deletions Source/Core/Core/Config/MainSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ extern const Info<bool> MAIN_FAST_DISC_SPEED;
extern const Info<bool> MAIN_LOW_DCBZ_HACK;
extern const Info<bool> MAIN_FLOAT_EXCEPTIONS;
extern const Info<bool> MAIN_DIVIDE_BY_ZERO_EXCEPTIONS;
extern const Info<bool> MAIN_ALIGNMENT_EXCEPTIONS;
extern const Info<bool> MAIN_FPRF;
extern const Info<bool> MAIN_ACCURATE_NANS;
extern const Info<bool> MAIN_DISABLE_ICACHE;
Expand Down
1 change: 1 addition & 0 deletions Source/Core/Core/ConfigLoaders/NetPlayConfigLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class NetPlayConfigLayerLoader final : public Config::ConfigLayerLoader
layer->Set(Config::GFX_PERF_QUERIES_ENABLE, m_settings.perf_queries_enable);
layer->Set(Config::MAIN_FLOAT_EXCEPTIONS, m_settings.float_exceptions);
layer->Set(Config::MAIN_DIVIDE_BY_ZERO_EXCEPTIONS, m_settings.divide_by_zero_exceptions);
layer->Set(Config::MAIN_ALIGNMENT_EXCEPTIONS, m_settings.alignment_exceptions);
layer->Set(Config::MAIN_FPRF, m_settings.fprf);
layer->Set(Config::MAIN_ACCURATE_NANS, m_settings.accurate_nans);
layer->Set(Config::MAIN_DISABLE_ICACHE, m_settings.disable_icache);
Expand Down
12 changes: 6 additions & 6 deletions Source/Core/Core/FifoPlayer/FifoPlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -702,12 +702,12 @@ void FifoPlayer::LoadTextureMemory()

void FifoPlayer::WriteCP(u32 address, u16 value)
{
m_system.GetMMU().Write_U16(value, 0xCC000000 | address);
m_system.GetMMU().Write_U16(value, 0xCC000000 | address, UGeckoInstruction{});
}

void FifoPlayer::WritePI(u32 address, u32 value)
{
m_system.GetMMU().Write_U32(value, 0xCC003000 | address);
m_system.GetMMU().Write_U32(value, 0xCC003000 | address, UGeckoInstruction{});
}

void FifoPlayer::FlushWGP()
Expand Down Expand Up @@ -805,14 +805,14 @@ bool FifoPlayer::ShouldLoadXF(u8 reg)

bool FifoPlayer::IsIdleSet() const
{
CommandProcessor::UCPStatusReg status =
m_system.GetMMU().Read_U16(0xCC000000 | CommandProcessor::STATUS_REGISTER);
CommandProcessor::UCPStatusReg status = m_system.GetMMU().Read_U16(
0xCC000000 | CommandProcessor::STATUS_REGISTER, UGeckoInstruction{});
return status.CommandIdle;
}

bool FifoPlayer::IsHighWatermarkSet() const
{
CommandProcessor::UCPStatusReg status =
m_system.GetMMU().Read_U16(0xCC000000 | CommandProcessor::STATUS_REGISTER);
CommandProcessor::UCPStatusReg status = m_system.GetMMU().Read_U16(
0xCC000000 | CommandProcessor::STATUS_REGISTER, UGeckoInstruction{});
return status.OverflowHiWatermark;
}
2 changes: 1 addition & 1 deletion Source/Core/Core/HLE/HLE_OS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ void HLE_write_console(const Core::CPUThreadGuard& guard)
std::string report_message = GetStringVA(system, guard, 4);
if (PowerPC::MMU::HostIsRAMAddress(guard, ppc_state.gpr[5]))
{
const u32 size = system.GetMMU().Read_U32(ppc_state.gpr[5]);
const u32 size = system.GetMMU().HostRead_U32(guard, ppc_state.gpr[5]);
if (size > report_message.size())
WARN_LOG_FMT(OSREPORT_HLE, "__write_console uses an invalid size of {:#010x}", size);
else if (size == 0)
Expand Down
1 change: 1 addition & 0 deletions Source/Core/Core/NetPlayClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -879,6 +879,7 @@ void NetPlayClient::OnStartGame(sf::Packet& packet)
packet >> m_net_settings.perf_queries_enable;
packet >> m_net_settings.float_exceptions;
packet >> m_net_settings.divide_by_zero_exceptions;
packet >> m_net_settings.alignment_exceptions;
packet >> m_net_settings.fprf;
packet >> m_net_settings.accurate_nans;
packet >> m_net_settings.disable_icache;
Expand Down
1 change: 1 addition & 0 deletions Source/Core/Core/NetPlayProto.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ struct NetSettings
bool perf_queries_enable = false;
bool float_exceptions = false;
bool divide_by_zero_exceptions = false;
bool alignment_exceptions = false;
bool fprf = false;
bool accurate_nans = false;
bool disable_icache = false;
Expand Down
2 changes: 2 additions & 0 deletions Source/Core/Core/NetPlayServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1409,6 +1409,7 @@ bool NetPlayServer::SetupNetSettings()
settings.perf_queries_enable = Config::Get(Config::GFX_PERF_QUERIES_ENABLE);
settings.float_exceptions = Config::Get(Config::MAIN_FLOAT_EXCEPTIONS);
settings.divide_by_zero_exceptions = Config::Get(Config::MAIN_DIVIDE_BY_ZERO_EXCEPTIONS);
settings.alignment_exceptions = Config::Get(Config::MAIN_ALIGNMENT_EXCEPTIONS);
settings.fprf = Config::Get(Config::MAIN_FPRF);
settings.accurate_nans = Config::Get(Config::MAIN_ACCURATE_NANS);
settings.disable_icache = Config::Get(Config::MAIN_DISABLE_ICACHE);
Expand Down Expand Up @@ -1617,6 +1618,7 @@ bool NetPlayServer::StartGame()
spac << m_settings.perf_queries_enable;
spac << m_settings.float_exceptions;
spac << m_settings.divide_by_zero_exceptions;
spac << m_settings.alignment_exceptions;
spac << m_settings.fprf;
spac << m_settings.accurate_nans;
spac << m_settings.disable_icache;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ s32 CachedInterpreter::InterpretAndCheckExceptions(
}
operands.func(operands.interpreter, operands.inst);

if ((ppc_state.Exceptions & (EXCEPTION_DSI | EXCEPTION_PROGRAM)) != 0)
if ((ppc_state.Exceptions & (ANY_LOADSTORE_EXCEPTION | EXCEPTION_PROGRAM)) != 0)
{
ppc_state.pc = operands.current_pc;
ppc_state.downcount -= operands.downcount;
Expand Down Expand Up @@ -335,7 +335,7 @@ bool CachedInterpreter::DoJit(u32 em_address, JitBlock* b, u32 nextPC)
js.firstFPInstructionFound = true;
}

// Instruction may cause a DSI Exception or Program Exception.
// Instruction may cause a DSI exception, alignment exception or program exception.
if ((jo.memcheck && (op.opinfo->flags & FL_LOADSTORE) != 0) ||
(!op.canEndBlock && ShouldHandleFPExceptionForInstruction(&op)))
{
Expand Down
13 changes: 7 additions & 6 deletions Source/Core/Core/PowerPC/Gekko.h
Original file line number Diff line number Diff line change
Expand Up @@ -916,14 +916,15 @@ enum
EXCEPTION_DECREMENTER = 0x00000001,
EXCEPTION_SYSCALL = 0x00000002,
EXCEPTION_EXTERNAL_INT = 0x00000004,
EXCEPTION_DSI = 0x00000008,
EXCEPTION_ISI = 0x00000010,
EXCEPTION_ISI = 0x00000008,
EXCEPTION_DSI = 0x00000010,
EXCEPTION_ALIGNMENT = 0x00000020,
EXCEPTION_FPU_UNAVAILABLE = 0x00000040,
EXCEPTION_PROGRAM = 0x00000080,
EXCEPTION_PERFORMANCE_MONITOR = 0x00000100,
EXCEPTION_FAKE_MEMCHECK_HIT = 0x00000040,
EXCEPTION_FPU_UNAVAILABLE = 0x00000080,
EXCEPTION_PROGRAM = 0x00000100,
EXCEPTION_PERFORMANCE_MONITOR = 0x00000200,

EXCEPTION_FAKE_MEMCHECK_HIT = 0x00000200,
ANY_LOADSTORE_EXCEPTION = EXCEPTION_DSI | EXCEPTION_ALIGNMENT | EXCEPTION_FAKE_MEMCHECK_HIT,
};

enum CPUEmuFeatureFlags : u32
Expand Down
12 changes: 10 additions & 2 deletions Source/Core/Core/PowerPC/Interpreter/ExceptionUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,18 @@ enum class ProgramExceptionCause : u32
Trap = 1 << (31 - 14),
};

inline void GenerateAlignmentException(PowerPC::PowerPCState& ppc_state, u32 address)
inline void GenerateAlignmentException(PowerPC::PowerPCState& ppc_state, u32 effective_address,
UGeckoInstruction inst)
{
ppc_state.Exceptions |= EXCEPTION_ALIGNMENT;
ppc_state.spr[SPR_DAR] = address;
ppc_state.spr[SPR_DAR] = effective_address;

// It has not been hardware tested what gets used instead of RD and RA in
// the cases documented as undefined. For now, simply use RD and RA
const bool x = inst.OPCD >= 32;
const u32 op = x ? inst.SUBOP10 : (inst.OPCD >> 1);
const u32 dsisr = ((op >> 8) << 15) | ((op & 0b11111) << 10) | (inst.RD << 5) | (inst.RA);
ppc_state.spr[SPR_DSISR] = dsisr;
}

inline void GenerateDSIException(PowerPC::PowerPCState& ppc_state, u32 address)
Expand Down
4 changes: 2 additions & 2 deletions Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ int Interpreter::SingleStepInner()
else if (m_ppc_state.msr.FP)
{
RunInterpreterOp(*this, m_prev_inst);
if ((m_ppc_state.Exceptions & EXCEPTION_DSI) != 0)
if ((m_ppc_state.Exceptions & ANY_LOADSTORE_EXCEPTION) != 0)
{
CheckExceptions();
}
Expand All @@ -176,7 +176,7 @@ int Interpreter::SingleStepInner()
else
{
RunInterpreterOp(*this, m_prev_inst);
if ((m_ppc_state.Exceptions & EXCEPTION_DSI) != 0)
if ((m_ppc_state.Exceptions & ANY_LOADSTORE_EXCEPTION) != 0)
{
CheckExceptions();
}
Expand Down
Loading