CPU: Fix incorrect exception vector for break

This commit is contained in:
Connor McLaughlin 2019-09-15 12:43:54 +10:00
parent 5babc076f5
commit 540f282213
3 changed files with 27 additions and 9 deletions

View File

@ -33,6 +33,7 @@ void Core::Reset()
m_cop0_regs.BDAM = 0; m_cop0_regs.BDAM = 0;
m_cop0_regs.BPCM = 0; m_cop0_regs.BPCM = 0;
m_cop0_regs.EPC = 0; m_cop0_regs.EPC = 0;
m_cop0_regs.sr.bits = 0;
SetPC(RESET_VECTOR); SetPC(RESET_VECTOR);
} }
@ -165,17 +166,31 @@ void Core::Branch(u32 target)
m_branched = true; m_branched = true;
} }
void Core::RaiseException(Exception excode) u32 Core::GetExceptionVector(Exception excode) const
{
const u32 base = m_cop0_regs.sr.BEV ? UINT32_C(0xbfc00100) : UINT32_C(0x80000000);
switch (excode)
{
case Exception::BP:
return base | UINT32_C(0x00000040);
default:
return base | UINT32_C(0x00000080);
}
}
void Core::RaiseException(Exception excode, u8 coprocessor /* = 0 */)
{ {
m_cop0_regs.EPC = m_in_branch_delay_slot ? (m_current_instruction_pc - UINT32_C(4)) : m_current_instruction_pc; m_cop0_regs.EPC = m_in_branch_delay_slot ? (m_current_instruction_pc - UINT32_C(4)) : m_current_instruction_pc;
m_cop0_regs.cause.Excode = excode; m_cop0_regs.cause.Excode = excode;
m_cop0_regs.cause.BD = m_in_branch_delay_slot; m_cop0_regs.cause.BD = m_in_branch_delay_slot;
m_cop0_regs.cause.CE = coprocessor;
// current -> previous // current -> previous, switch to kernel mode and disable interrupts
m_cop0_regs.sr.mode_bits <<= 2; m_cop0_regs.sr.mode_bits <<= 2;
// flush the pipeline - we don't want to execute the previously fetched instruction // flush the pipeline - we don't want to execute the previously fetched instruction
m_regs.npc = m_cop0_regs.sr.BEV ? UINT32_C(0xbfc00180) : UINT32_C(0x80000080); m_regs.npc = GetExceptionVector(excode);
FlushPipeline(); FlushPipeline();
} }
@ -830,7 +845,7 @@ void Core::ExecuteInstruction(Instruction inst)
if (!m_cop0_regs.sr.CU0 && InUserMode()) if (!m_cop0_regs.sr.CU0 && InUserMode())
{ {
Log_WarningPrintf("Coprocessor 0 not present in user mode"); Log_WarningPrintf("Coprocessor 0 not present in user mode");
RaiseException(Exception::CpU); RaiseException(Exception::CpU, 0);
return; return;
} }
@ -842,7 +857,7 @@ void Core::ExecuteInstruction(Instruction inst)
case InstructionOp::cop1: case InstructionOp::cop1:
case InstructionOp::cop2: case InstructionOp::cop2:
{ {
RaiseException(Exception::CpU); RaiseException(Exception::CpU, inst.cop.cop_n);
} }
break; break;

View File

@ -69,7 +69,10 @@ private:
void ExecuteInstruction(Instruction inst); void ExecuteInstruction(Instruction inst);
void ExecuteCop0Instruction(Instruction inst); void ExecuteCop0Instruction(Instruction inst);
void Branch(u32 target); void Branch(u32 target);
void RaiseException(Exception excode);
// exceptions
u32 GetExceptionVector(Exception excode) const;
void RaiseException(Exception excode, u8 coprocessor = 0);
// flushes any load delays if present // flushes any load delays if present
void FlushLoadDelay(); void FlushLoadDelay();

View File

@ -267,11 +267,11 @@ struct Cop0Registers
{ {
u32 bits; u32 bits;
BitField<u32, bool, 0, 1> IEc; // current interrupt enable BitField<u32, bool, 0, 1> IEc; // current interrupt enable
BitField<u32, bool, 1, 1> KUc; // current kernel/user mode, kernel = 1 BitField<u32, bool, 1, 1> KUc; // current kernel/user mode, user = 1
BitField<u32, bool, 2, 1> IEp; // previous interrupt enable BitField<u32, bool, 2, 1> IEp; // previous interrupt enable
BitField<u32, bool, 3, 1> KUp; // previous kernel/user mode, kernel = 1 BitField<u32, bool, 3, 1> KUp; // previous kernel/user mode, user = 1
BitField<u32, bool, 4, 1> IEo; // old interrupt enable BitField<u32, bool, 4, 1> IEo; // old interrupt enable
BitField<u32, bool, 5, 1> KUo; // old kernel/user mode, kernel = 1 BitField<u32, bool, 5, 1> KUo; // old kernel/user mode, user = 1
BitField<u32, u8, 8, 8> Im; // interrupt mask, set to 1 = allowed to trigger BitField<u32, u8, 8, 8> Im; // interrupt mask, set to 1 = allowed to trigger
BitField<u32, bool, 16, 1> Isc; // isolate cache, no writes to memory occur BitField<u32, bool, 16, 1> Isc; // isolate cache, no writes to memory occur
BitField<u32, bool, 17, 1> Swc; // swap data and instruction caches BitField<u32, bool, 17, 1> Swc; // swap data and instruction caches