mirror of https://github.com/PCSX2/pcsx2.git
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
This commit is contained in:
parent
374048e1c6
commit
a30bd86311
|
@ -479,23 +479,48 @@ static void intEventTest()
|
||||||
|
|
||||||
static void intExecute()
|
static void intExecute()
|
||||||
{
|
{
|
||||||
try {
|
bool instruction_was_cancelled;
|
||||||
if (g_SkipBiosHack) {
|
enum ExecuteState {
|
||||||
do
|
RESET,
|
||||||
execI();
|
REPLACE_OSDSYS_DONE,
|
||||||
while (cpuRegs.pc != EELOAD_START);
|
GAME_STARTING_DONE
|
||||||
eeloadReplaceOSDSYS();
|
};
|
||||||
|
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) {
|
catch( Exception::ExitCpuExecute& ) { }
|
||||||
do
|
catch( Exception::CancelInstruction& ) { instruction_was_cancelled = true; }
|
||||||
execI();
|
|
||||||
while (cpuRegs.pc != ElfEntry);
|
// For example a tlb miss will throw an exception. Cpu must be resumed
|
||||||
eeGameStarting();
|
// to execute the handler
|
||||||
} else {
|
} while (instruction_was_cancelled);
|
||||||
while (true)
|
|
||||||
execI();
|
|
||||||
}
|
|
||||||
} catch( Exception::ExitCpuExecute& ) { }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void intCheckExecutionState()
|
static void intCheckExecutionState()
|
||||||
|
|
|
@ -37,6 +37,12 @@ namespace Exception
|
||||||
public:
|
public:
|
||||||
explicit ExitCpuExecute() { }
|
explicit ExitCpuExecute() { }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CancelInstruction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit CancelInstruction() { }
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -376,6 +376,9 @@ static __ri void vtlb_Miss(u32 addr,u32 mode)
|
||||||
cpuTlbMissW(addr, cpuRegs.branch);
|
cpuTlbMissW(addr, cpuRegs.branch);
|
||||||
else
|
else
|
||||||
cpuTlbMissR(addr, cpuRegs.branch);
|
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
|
// The exception terminate the program on linux which is very annoying
|
||||||
|
|
Loading…
Reference in New Issue