CPU: Handle reserved instructions/bus errors

This commit is contained in:
Connor McLaughlin 2019-10-04 13:41:12 +10:00
parent 01ad2fa5b6
commit 92ec5a0a14
2 changed files with 38 additions and 14 deletions

View File

@ -229,6 +229,15 @@ u32 Core::GetExceptionVector(Exception excode) const
void Core::RaiseException(Exception excode) void Core::RaiseException(Exception excode)
{ {
#ifdef Y_BUILD_CONFIG_RELEASE
if (excode == Exception::RI)
{
// Invalid op.
Log_DevPrintf("Invalid instruction at 0x%08X", m_current_instruction_pc);
DisassembleAndPrint(m_current_instruction_pc, 4, 0);
}
#endif
RaiseException(excode, m_current_instruction_pc, m_current_instruction_in_branch_delay_slot, RaiseException(excode, m_current_instruction_pc, m_current_instruction_in_branch_delay_slot,
m_current_instruction_was_branch_taken, m_current_instruction.cop.cop_n); m_current_instruction_was_branch_taken, m_current_instruction.cop.cop_n);
} }
@ -334,7 +343,7 @@ void Core::WriteRegDelayed(Reg rd, u32 value)
m_regs.r[static_cast<u8>(rd)] = value; m_regs.r[static_cast<u8>(rd)] = value;
} }
u32 Core::ReadCop0Reg(Cop0Reg reg) std::optional<u32> Core::ReadCop0Reg(Cop0Reg reg)
{ {
switch (reg) switch (reg)
{ {
@ -372,8 +381,8 @@ u32 Core::ReadCop0Reg(Cop0Reg reg)
return m_cop0_regs.PRID; return m_cop0_regs.PRID;
default: default:
Panic("Unknown COP0 reg"); Log_DevPrintf("Unknown COP0 reg %u", ZeroExtend32(static_cast<u8>(reg)));
return 0; return std::nullopt;
} }
} }
@ -440,7 +449,7 @@ void Core::WriteCop0Reg(Cop0Reg reg, u32 value)
break; break;
default: default:
Panic("Unknown COP0 reg"); Log_DevPrintf("Unknown COP0 reg %u", ZeroExtend32(static_cast<u8>(reg)));
break; break;
} }
} }
@ -820,10 +829,12 @@ void Core::ExecuteInstruction()
break; break;
default: default:
UnreachableCode(); {
RaiseException(Exception::RI);
break; break;
} }
} }
}
break; break;
case InstructionOp::lui: case InstructionOp::lui:
@ -1149,20 +1160,24 @@ void Core::ExecuteInstruction()
} }
break; break;
// COP1/COP3 are not present // swc0/lwc0/cop1/cop3 are essentially no-ops
case InstructionOp::cop1: case InstructionOp::cop1:
case InstructionOp::cop3: case InstructionOp::cop3:
case InstructionOp::lwc0:
case InstructionOp::lwc1: case InstructionOp::lwc1:
case InstructionOp::swc1:
case InstructionOp::lwc3: case InstructionOp::lwc3:
case InstructionOp::swc0:
case InstructionOp::swc1:
case InstructionOp::swc3: case InstructionOp::swc3:
{ {
RaiseException(Exception::CpU);
} }
break; break;
// everything else is reserved/invalid
default: default:
UnreachableCode(); {
RaiseException(Exception::RI);
}
break; break;
} }
} }
@ -1176,11 +1191,19 @@ void Core::ExecuteCop0Instruction()
switch (inst.cop.CommonOp()) switch (inst.cop.CommonOp())
{ {
case CopCommonInstruction::mfcn: case CopCommonInstruction::mfcn:
WriteRegDelayed(inst.r.rt, ReadCop0Reg(static_cast<Cop0Reg>(inst.r.rd.GetValue()))); {
const std::optional<u32> value = ReadCop0Reg(static_cast<Cop0Reg>(inst.r.rd.GetValue()));
if (value)
WriteRegDelayed(inst.r.rt, value.value());
else
RaiseException(Exception::RI);
}
break; break;
case CopCommonInstruction::mtcn: case CopCommonInstruction::mtcn:
{
WriteCop0Reg(static_cast<Cop0Reg>(inst.r.rd.GetValue()), ReadReg(inst.r.rt)); WriteCop0Reg(static_cast<Cop0Reg>(inst.r.rd.GetValue()), ReadReg(inst.r.rt));
}
break; break;
default: default:

View File

@ -4,6 +4,7 @@
#include "gte.h" #include "gte.h"
#include "types.h" #include "types.h"
#include <array> #include <array>
#include <optional>
class StateWrapper; class StateWrapper;
@ -107,7 +108,7 @@ private:
void WriteCacheControl(u32 value); void WriteCacheControl(u32 value);
// read/write cop0 regs // read/write cop0 regs
u32 ReadCop0Reg(Cop0Reg reg); std::optional<u32> ReadCop0Reg(Cop0Reg reg);
void WriteCop0Reg(Cop0Reg reg, u32 value); void WriteCop0Reg(Cop0Reg reg, u32 value);
Bus* m_bus = nullptr; Bus* m_bus = nullptr;