Merge pull request #350 from PCSX2/interpreter-tlb-handler

Interpreter tlb handler
This commit is contained in:
Gregory Hainaut 2014-12-02 21:47:56 +01:00
commit ec976743d6
4 changed files with 90 additions and 33 deletions

View File

@ -28,7 +28,7 @@ extern char* disVU1MicroLF(u32 code, u32 pc);
namespace R5900 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 GPR_REG[32];
extern const char * const COP0_REG[32]; extern const char * const COP0_REG[32];

View File

@ -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!!!!"); 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) void intBreakpoint(bool memcheck)
{ {
@ -127,39 +126,63 @@ void intCheckMemcheck()
static void execI() 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 // check if any breakpoints or memchecks are triggered by this instruction
if (isBreakpointNeeded(cpuRegs.pc)) if (isBreakpointNeeded(cpuRegs.pc))
intBreakpoint(false); intBreakpoint(false);
intCheckMemcheck(); 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 // interprete instruction
cpuRegs.code = memRead32( cpuRegs.pc ); cpuRegs.code = memRead32( pc );
// Honestly I think this code is useless nowadays.
#ifdef EXTRA_DEBUG
if( IsDebugBuild ) if( IsDebugBuild )
debugI(); debugI();
#endif
const OPCODE& opcode = GetCurrentInstruction(); const OPCODE& opcode = GetCurrentInstruction();
#if 0
static long int runs = 0;
//use this to find out what opcodes your game uses. very slow! (rama) //use this to find out what opcodes your game uses. very slow! (rama)
//runs++; runs++;
//if (runs > 1599999999){ //leave some time to startup the testgame if (runs > 1599999999){ //leave some time to startup the testgame
// if (opcode.Name[0] == 'L') { //find all opcodes beginning with "L" if (opcode.Name[0] == 'L') { //find all opcodes beginning with "L"
// Console.WriteLn ("Load %s", opcode.Name); Console.WriteLn ("Load %s", opcode.Name);
// } }
//} }
#endif
// Another method of instruction dumping: #if 0
/*if( cpuRegs.cycle > 0x4f24d714 ) static long int print_me = 0;
{ // Based on cycle
//CPU_LOG( "%s", disR5900Current.getCString()); // 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(); disOut.clear();
opcode.disasm( disOut ); disR5900Fasm(disOut, cpuRegs.code, pc);
disOut += '\n';
CPU_LOG( disOut.c_str() ); CPU_LOG( disOut.c_str() );
}*/ }
#endif
cpuBlockCycles += opcode.cycles; cpuBlockCycles += opcode.cycles;
cpuRegs.pc += 4;
opcode.interpret(); opcode.interpret();
} }
@ -479,23 +502,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()

View File

@ -37,6 +37,12 @@ namespace Exception
public: public:
explicit ExitCpuExecute() { } explicit ExitCpuExecute() { }
}; };
class CancelInstruction
{
public:
explicit CancelInstruction() { }
};
} }
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------

View File

@ -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