From a30bd8631171a5d8ee6c96efafa522bb054874be Mon Sep 17 00:00:00 2001 From: Gregory Hainaut Date: Fri, 14 Nov 2014 22:46:31 +0100 Subject: [PATCH] pcsx2: interpreter: add an exception for tlb miss When a tlb miss is detected current instruction must be skipped. We need to immediately switch to the handler Typical instruction bug case: lw a0, 0x8(a0) a0 mustn't be loaded if we have a miss v2: create a dedicated exception for tlb miss v3: * rename exception to CancelInstruction * add a basic state machine on the exec loop so we keep same behavior for eeloadReplaceOSDSYS and eeGameStarting v4: remove assert --- pcsx2/Interpreter.cpp | 57 +++++++++++++++++++++++++++++++------------ pcsx2/R5900.h | 6 +++++ pcsx2/vtlb.cpp | 3 +++ 3 files changed, 50 insertions(+), 16 deletions(-) diff --git a/pcsx2/Interpreter.cpp b/pcsx2/Interpreter.cpp index 59a90181c1..60f2cb435c 100644 --- a/pcsx2/Interpreter.cpp +++ b/pcsx2/Interpreter.cpp @@ -479,23 +479,48 @@ static void intEventTest() static void intExecute() { - try { - if (g_SkipBiosHack) { - do - execI(); - while (cpuRegs.pc != EELOAD_START); - eeloadReplaceOSDSYS(); + bool instruction_was_cancelled; + enum ExecuteState { + RESET, + REPLACE_OSDSYS_DONE, + GAME_STARTING_DONE + }; + ExecuteState state = RESET; + do { + instruction_was_cancelled = false; + try { + // The execution was splited in three parts so it is easier to + // resume it after a cancelled instruction. + switch (state) { + case RESET: + if (g_SkipBiosHack) { + do + execI(); + while (cpuRegs.pc != EELOAD_START); + eeloadReplaceOSDSYS(); + } + state = REPLACE_OSDSYS_DONE; + + case REPLACE_OSDSYS_DONE: + if (ElfEntry != 0xFFFFFFFF) { + do + execI(); + while (cpuRegs.pc != ElfEntry); + eeGameStarting(); + } + state = GAME_STARTING_DONE; + + case GAME_STARTING_DONE: + while (true) + execI(); + } } - if (ElfEntry != 0xFFFFFFFF) { - do - execI(); - while (cpuRegs.pc != ElfEntry); - eeGameStarting(); - } else { - while (true) - execI(); - } - } catch( Exception::ExitCpuExecute& ) { } + catch( Exception::ExitCpuExecute& ) { } + catch( Exception::CancelInstruction& ) { instruction_was_cancelled = true; } + + // For example a tlb miss will throw an exception. Cpu must be resumed + // to execute the handler + } while (instruction_was_cancelled); } static void intCheckExecutionState() diff --git a/pcsx2/R5900.h b/pcsx2/R5900.h index 4504a6fed7..cd027895a2 100644 --- a/pcsx2/R5900.h +++ b/pcsx2/R5900.h @@ -37,6 +37,12 @@ namespace Exception public: explicit ExitCpuExecute() { } }; + + class CancelInstruction + { + public: + explicit CancelInstruction() { } + }; } // -------------------------------------------------------------------------------------- diff --git a/pcsx2/vtlb.cpp b/pcsx2/vtlb.cpp index a26ba37bac..da746654b9 100644 --- a/pcsx2/vtlb.cpp +++ b/pcsx2/vtlb.cpp @@ -376,6 +376,9 @@ static __ri void vtlb_Miss(u32 addr,u32 mode) cpuTlbMissW(addr, cpuRegs.branch); else cpuTlbMissR(addr, cpuRegs.branch); + + // Exception handled. Current instruction need to be stopped + throw Exception::CancelInstruction(); } // The exception terminate the program on linux which is very annoying