diff --git a/src/pse/cpu_core.cpp b/src/pse/cpu_core.cpp index d17c180b0..371153d4e 100644 --- a/src/pse/cpu_core.cpp +++ b/src/pse/cpu_core.cpp @@ -33,6 +33,7 @@ void Core::Reset() m_cop0_regs.BDAM = 0; m_cop0_regs.BPCM = 0; m_cop0_regs.EPC = 0; + m_cop0_regs.sr.bits = 0; SetPC(RESET_VECTOR); } @@ -165,17 +166,31 @@ void Core::Branch(u32 target) 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.cause.Excode = excode; 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; // 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(); } @@ -830,7 +845,7 @@ void Core::ExecuteInstruction(Instruction inst) if (!m_cop0_regs.sr.CU0 && InUserMode()) { Log_WarningPrintf("Coprocessor 0 not present in user mode"); - RaiseException(Exception::CpU); + RaiseException(Exception::CpU, 0); return; } @@ -842,7 +857,7 @@ void Core::ExecuteInstruction(Instruction inst) case InstructionOp::cop1: case InstructionOp::cop2: { - RaiseException(Exception::CpU); + RaiseException(Exception::CpU, inst.cop.cop_n); } break; diff --git a/src/pse/cpu_core.h b/src/pse/cpu_core.h index 6634492b9..1e774e605 100644 --- a/src/pse/cpu_core.h +++ b/src/pse/cpu_core.h @@ -69,7 +69,10 @@ private: void ExecuteInstruction(Instruction inst); void ExecuteCop0Instruction(Instruction inst); 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 void FlushLoadDelay(); diff --git a/src/pse/cpu_types.h b/src/pse/cpu_types.h index ebe15d3e7..ec5a6e2bf 100644 --- a/src/pse/cpu_types.h +++ b/src/pse/cpu_types.h @@ -267,11 +267,11 @@ struct Cop0Registers { u32 bits; BitField IEc; // current interrupt enable - BitField KUc; // current kernel/user mode, kernel = 1 + BitField KUc; // current kernel/user mode, user = 1 BitField IEp; // previous interrupt enable - BitField KUp; // previous kernel/user mode, kernel = 1 + BitField KUp; // previous kernel/user mode, user = 1 BitField IEo; // old interrupt enable - BitField KUo; // old kernel/user mode, kernel = 1 + BitField KUo; // old kernel/user mode, user = 1 BitField Im; // interrupt mask, set to 1 = allowed to trigger BitField Isc; // isolate cache, no writes to memory occur BitField Swc; // swap data and instruction caches