diff --git a/pcsx2/DebugTools/Debug.h b/pcsx2/DebugTools/Debug.h index e5b1950287..9e9e4b0fdb 100644 --- a/pcsx2/DebugTools/Debug.h +++ b/pcsx2/DebugTools/Debug.h @@ -28,7 +28,7 @@ extern char* disVU1MicroLF(u32 code, u32 pc); namespace R5900 { - void disR5900Fasm( std::string& output, u32 code, u32 pc, bool simplify); + void disR5900Fasm( std::string& output, u32 code, u32 pc, bool simplify = false); extern const char * const GPR_REG[32]; extern const char * const COP0_REG[32]; diff --git a/pcsx2/Interpreter.cpp b/pcsx2/Interpreter.cpp index 59a90181c1..a4448e8d4c 100644 --- a/pcsx2/Interpreter.cpp +++ b/pcsx2/Interpreter.cpp @@ -45,7 +45,6 @@ static void debugI() if( cpuRegs.GPR.n.r0.UD[0] || cpuRegs.GPR.n.r0.UD[1] ) Console.Error("R0 is not zero!!!!"); } -//long int runs=0; void intBreakpoint(bool memcheck) { @@ -127,39 +126,63 @@ void intCheckMemcheck() static void execI() { + // execI is called for every instruction so it must remains as light as possible. + // If you enable the next define, Interpreter will be much slower (around + // ~4fps on 3.9GHz Haswell vs ~8fps (even 10fps on dev build)) + // Extra note: due to some cycle count issue PCSX2's internal debugger is + // not yet usable with the interpreter +//#define EXTRA_DEBUG +#ifdef EXTRA_DEBUG // check if any breakpoints or memchecks are triggered by this instruction if (isBreakpointNeeded(cpuRegs.pc)) intBreakpoint(false); intCheckMemcheck(); +#endif + + u32 pc = cpuRegs.pc; + // We need to increase the pc before executing the memRead32. An exception could appears + // and it expects the PC counter to be pre-incremented + cpuRegs.pc += 4; // interprete instruction - cpuRegs.code = memRead32( cpuRegs.pc ); + cpuRegs.code = memRead32( pc ); + // Honestly I think this code is useless nowadays. +#ifdef EXTRA_DEBUG if( IsDebugBuild ) debugI(); +#endif const OPCODE& opcode = GetCurrentInstruction(); +#if 0 + static long int runs = 0; //use this to find out what opcodes your game uses. very slow! (rama) - //runs++; - //if (runs > 1599999999){ //leave some time to startup the testgame - // if (opcode.Name[0] == 'L') { //find all opcodes beginning with "L" - // Console.WriteLn ("Load %s", opcode.Name); - // } - //} + runs++; + if (runs > 1599999999){ //leave some time to startup the testgame + if (opcode.Name[0] == 'L') { //find all opcodes beginning with "L" + Console.WriteLn ("Load %s", opcode.Name); + } + } +#endif - // Another method of instruction dumping: - /*if( cpuRegs.cycle > 0x4f24d714 ) - { - //CPU_LOG( "%s", disR5900Current.getCString()); +#if 0 + static long int print_me = 0; + // Based on cycle + // if( cpuRegs.cycle > 0x4f24d714 ) + // Or dump from a particular PC (useful to debug handler/syscall) + if (cpuRegs.pc == 0x80000000) { + print_me = 2000; + } + if (print_me) { + print_me--; disOut.clear(); - opcode.disasm( disOut ); - disOut += '\n'; + disR5900Fasm(disOut, cpuRegs.code, pc); CPU_LOG( disOut.c_str() ); - }*/ + } +#endif cpuBlockCycles += opcode.cycles; - cpuRegs.pc += 4; opcode.interpret(); } @@ -479,23 +502,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