Added an option "Alternate RFI" to the Game Properties to enable alternate interrupt timing. Try enabling this option if a game hangs, works only in the Interpreter or Dolphin crashes. This option fixes Die Hard: Vendetta and Medabots Infinity.

Fixed the interpreter to execute instructions in the right number of cycles.  It used to execute all instructions in one cycle.

Added a trace function to the interpreter making it easier to determine differences between the interpreter and the recompilers.

Removed the "Enable self modifying code check" as it was not useful.

Fixes issue 2407.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6183 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
skidau 2010-09-06 10:27:33 +00:00
parent 3bdeb923ef
commit 34aebffff9
18 changed files with 89 additions and 52 deletions

View File

@ -293,6 +293,7 @@ void SConfig::LoadSettings()
ini.Get("Core", "RunCompareClient", &m_LocalCoreStartupParameter.bRunCompareClient, false);
ini.Get("Core", "MMU", &m_LocalCoreStartupParameter.bMMU, false);
ini.Get("Core", "TLBHack", &m_LocalCoreStartupParameter.iTLBHack, 0);
ini.Get("Core", "AlternateRFI", &m_LocalCoreStartupParameter.bAlternateRFI, false);
ini.Get("Core", "FrameLimit", &m_Framelimit, 1); // auto frame limit by default
ini.Get("Core", "UseFPS", &b_UseFPS, false); // use vps as default

View File

@ -47,7 +47,7 @@ SCoreStartupParameter::SCoreStartupParameter()
bLockThreads(false),
bEnableCheats(false),
bRunCompareServer(false), bRunCompareClient(false),
bMMU(false), bSMC(false), iTLBHack(0), SelectedLanguage(0), bWii(false),
bMMU(false), bAlternateRFI(false), iTLBHack(0), SelectedLanguage(0), bWii(false),
bConfirmStop(false), bHideCursor(false),
bAutoHideCursor(false), bUsePanicHandlers(true),
iRenderWindowXPos(0), iRenderWindowYPos(0),
@ -70,8 +70,8 @@ void SCoreStartupParameter::LoadDefaults()
bLockThreads = true;
bEnableFPRF = false;
bMMU = false;
bSMC = false;
iTLBHack = 0;
bAlternateRFI = false;
SelectedLanguage = 0;
bWii = false;

View File

@ -79,8 +79,8 @@ struct SCoreStartupParameter
bool bRunCompareClient;
bool bMMU;
bool bSMC;
int iTLBHack;
bool bAlternateRFI;
int SelectedLanguage;

View File

@ -265,11 +265,6 @@ inline void WriteToHardware(u32 em_address, const T data, u32 effective_address,
((em_address & 0xF0000000) == 0x00000000))
{
*(T*)&m_pRAM[em_address & RAM_MASK] = bswap(data);
// Required for games with self modifying code (e.g. Monster House)
if (Core::g_CoreStartupParameter.bSMC)
Write_Opcode_JIT(em_address, 0x14141414);
return;
}
else if (((em_address & 0xF0000000) == 0x90000000) ||

View File

@ -2799,6 +2799,7 @@ DEFINE_LUA_FUNCTION(emulua_loadrom, "filename")
game_ini.Get("Core", "EnableFPRF", &StartUp.bEnableFPRF, StartUp.bEnableFPRF);
game_ini.Get("Core", "MMU", &StartUp.bMMU, StartUp.bMMU);
game_ini.Get("Core", "TLBHack", &StartUp.iTLBHack, StartUp.iTLBHack);
game_ini.Get("Core", "AlternateRFI", &StartUp.bAlternateRFI, StartUp.bAlternateRFI);
// Wii settings
if (StartUp.bWii)
{

View File

@ -75,13 +75,44 @@ static void patches()
}*/
}
void Interpreter::SingleStepInner(void)
int startTrace = 0;
void Trace( UGeckoInstruction &instCode )
{
char regs[500]="";
for (int i=0; i<32; i++) {
sprintf(regs, "%sr%02d: %08x ", regs, i, PowerPC::ppcState.gpr[i]);
}
char fregs[500]="";
for (int i=0; i<32; i++) {
sprintf(fregs, "%sf%02d: %08x %08x ", fregs, i, PowerPC::ppcState.ps[i][0], PowerPC::ppcState.ps[i][1]);
}
char ppcInst[256];
DisassembleGekko(instCode.hex, PC, ppcInst, 256);
DEBUG_LOG(POWERPC, "INTER PC: %08x SRR0: %08x SRR1: %08x CRfast: %02x%02x%02x%02x%02x%02x%02x%02x FPSCR: %08x MSR: %08x LR: %08x %s %s %08x %s", PC, SRR0, SRR1, PowerPC::ppcState.cr_fast[0], PowerPC::ppcState.cr_fast[1], PowerPC::ppcState.cr_fast[2], PowerPC::ppcState.cr_fast[3], PowerPC::ppcState.cr_fast[4], PowerPC::ppcState.cr_fast[5], PowerPC::ppcState.cr_fast[6], PowerPC::ppcState.cr_fast[7], PowerPC::ppcState.fpscr, PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs, fregs, instCode.hex, ppcInst);
}
int Interpreter::SingleStepInner(void)
{
static UGeckoInstruction instCode;
NPC = PC + sizeof(UGeckoInstruction);
instCode.hex = Memory::Read_Opcode(PC);
// Uncomment to trace the interpreter
//if ((PC & 0xffffff)>=0x0ab54c && (PC & 0xffffff)<=0x0ab624)
// startTrace = 1;
//else
// startTrace = 0;
if (startTrace)
{
Trace(instCode);
}
if (instCode.hex != 0)
{
UReg_MSR& msr = (UReg_MSR&)MSR;
@ -131,6 +162,9 @@ void Interpreter::SingleStepInner(void)
PowerPC::ppcState.DebugCount++;
#endif
patches();
GekkoOPInfo *opinfo = GetOpInfo(instCode);
return opinfo->numCyclesMinusOne + 1;
}
void Interpreter::SingleStep()
@ -224,11 +258,12 @@ void Interpreter::Run()
{
m_EndBlock = false;
int i;
int cycles = 0;
for (i = 0; !m_EndBlock; i++)
{
SingleStepInner();
cycles += SingleStepInner();
}
CoreTiming::downcount -= i;
CoreTiming::downcount -= cycles;
}
}

View File

@ -29,7 +29,8 @@ public:
void Shutdown();
void Reset();
void SingleStep();
void SingleStepInner();
int SingleStepInner();
void Run();
void ClearCache();
const char *GetName();

View File

@ -255,7 +255,7 @@ void Jit64::HLEFunction(UGeckoInstruction _inst)
fpr.Flush(FLUSH_ALL);
ABI_CallFunctionCC((void*)&HLE::Execute, js.compilerPC, _inst.hex);
MOV(32, R(EAX), M(&NPC));
WriteExitDestInEAX(0);
WriteExitDestInEAX();
}
void Jit64::DoNothing(UGeckoInstruction _inst)
@ -321,7 +321,7 @@ void Jit64::WriteExit(u32 destination, int exit_num)
}
}
void Jit64::WriteExitDestInEAX(int exit_num)
void Jit64::WriteExitDestInEAX()
{
MOV(32, M(&PC), R(EAX));
Cleanup();
@ -379,7 +379,7 @@ void Jit64::Trace()
}
#endif
NOTICE_LOG(DYNA_REC, "JIT64 PC: %08x SRR0: %08x SRR1: %08x CRfast: %02x%02x%02x%02x%02x%02x%02x%02x FPSCR: %08x MSR: %08x LR: %08x %s %s",
DEBUG_LOG(DYNA_REC, "JIT64 PC: %08x SRR0: %08x SRR1: %08x CRfast: %02x%02x%02x%02x%02x%02x%02x%02x FPSCR: %08x MSR: %08x LR: %08x %s %s",
PC, SRR0, SRR1, PowerPC::ppcState.cr_fast[0], PowerPC::ppcState.cr_fast[1], PowerPC::ppcState.cr_fast[2], PowerPC::ppcState.cr_fast[3],
PowerPC::ppcState.cr_fast[4], PowerPC::ppcState.cr_fast[5], PowerPC::ppcState.cr_fast[6], PowerPC::ppcState.cr_fast[7], PowerPC::ppcState.fpscr,
PowerPC::ppcState.msr, PowerPC::ppcState.spr[8], regs, fregs);

View File

@ -141,7 +141,7 @@ public:
// Utilities for use by opcodes
void WriteExit(u32 destination, int exit_num);
void WriteExitDestInEAX(int exit_num);
void WriteExitDestInEAX();
void WriteExceptionExit();
void WriteRfiExitDestInEAX();
void WriteCallInterpreter(UGeckoInstruction _inst);

View File

@ -68,9 +68,12 @@ void Jit64::rfi(UGeckoInstruction inst)
MOV(32, R(EAX), M(&SRR1));
AND(32, R(EAX), Imm32(mask & clearMSR13));
OR(32, M(&MSR), R(EAX));
// NPC = SRR0;
// NPC = SRR0;
MOV(32, R(EAX), M(&SRR0));
WriteRfiExitDestInEAX();
if (Core::g_CoreStartupParameter.bAlternateRFI)
WriteExitDestInEAX();
else
WriteRfiExitDestInEAX();
}
void Jit64::bx(UGeckoInstruction inst)
@ -92,7 +95,7 @@ void Jit64::bx(UGeckoInstruction inst)
destination = js.compilerPC + SignExt26(inst.LI << 2);
#ifdef ACID_TEST
if (inst.LK)
AND(32, M(&CR), Imm32(~(0xFF000000)));
AND(32, M(&PowerPC::ppcState.cr), Imm32(~(0xFF000000)));
#endif
if (destination == js.compilerPC)
{
@ -181,7 +184,7 @@ void Jit64::bcctrx(UGeckoInstruction inst)
if (inst.LK_3)
MOV(32, M(&LR), Imm32(js.compilerPC + 4)); // LR = PC + 4;
AND(32, R(EAX), Imm32(0xFFFFFFFC));
WriteExitDestInEAX(0);
WriteExitDestInEAX();
}
else
{
@ -203,7 +206,7 @@ void Jit64::bcctrx(UGeckoInstruction inst)
//MOV(32, M(&PC), R(EAX)); => Already done in WriteExitDestInEAX()
if (inst.LK_3)
MOV(32, M(&LR), Imm32(js.compilerPC + 4)); // LR = PC + 4;
WriteExitDestInEAX(0);
WriteExitDestInEAX();
// Would really like to continue the block here, but it ends. TODO.
SetJumpTarget(b);
WriteExit(js.compilerPC + 4, 1);
@ -241,14 +244,14 @@ void Jit64::bclrx(UGeckoInstruction inst)
// This below line can be used to prove that blr "eats flags" in practice.
// This observation will let us do a lot of fun observations.
#ifdef ACID_TEST
AND(32, M(&CR), Imm32(~(0xFF000000)));
AND(32, M(&PowerPC::ppcState.cr), Imm32(~(0xFF000000)));
#endif
MOV(32, R(EAX), M(&LR));
AND(32, R(EAX), Imm32(0xFFFFFFFC));
if (inst.LK)
MOV(32, M(&LR), Imm32(js.compilerPC + 4));
WriteExitDestInEAX(0);
WriteExitDestInEAX();
if ((inst.BO & BO_DONT_CHECK_CONDITION) == 0)
SetJumpTarget( pConditionDontBranch );

View File

@ -290,14 +290,14 @@ void Jit64::cmpXX(UGeckoInstruction inst)
MOV(32, M(&LR), Imm32(js.compilerPC + 4));
MOV(32, R(EAX), M(&CTR));
AND(32, R(EAX), Imm32(0xFFFFFFFC));
WriteExitDestInEAX(0);
WriteExitDestInEAX();
}
else if ((js.next_inst.OPCD == 19) && (js.next_inst.SUBOP10 == 16)) // bclrx
{
MOV(32, R(EAX), M(&LR));
if (js.next_inst.LK)
MOV(32, M(&LR), Imm32(js.compilerPC + 4));
WriteExitDestInEAX(0);
WriteExitDestInEAX();
}
else
{
@ -395,7 +395,7 @@ void Jit64::cmpXX(UGeckoInstruction inst)
MOV(32, M(&LR), Imm32(js.compilerPC + 4));
MOV(32, R(EAX), M(&CTR));
AND(32, R(EAX), Imm32(0xFFFFFFFC));
WriteExitDestInEAX(0);
WriteExitDestInEAX();
}
else if ((js.next_inst.OPCD == 19) && (js.next_inst.SUBOP10 == 16)) // bclrx
{
@ -403,7 +403,7 @@ void Jit64::cmpXX(UGeckoInstruction inst)
AND(32, R(EAX), Imm32(0xFFFFFFFC));
if (js.next_inst.LK)
MOV(32, M(&LR), Imm32(js.compilerPC + 4));
WriteExitDestInEAX(0);
WriteExitDestInEAX();
}
else
{

View File

@ -104,14 +104,11 @@ void Jit64::mfspr(UGeckoInstruction inst)
}
}
// =======================================================================================
// Don't interpret this, if we do we get thrown out
// --------------
void Jit64::mtmsr(UGeckoInstruction inst)
{
INSTRUCTION_START
JITDISABLE(SystemRegisters)
// Don't interpret this, if we do we get thrown out
//JITDISABLE(SystemRegisters)
if (!gpr.R(inst.RS).IsImm())
{
gpr.Lock(inst.RS);
@ -123,8 +120,6 @@ void Jit64::mtmsr(UGeckoInstruction inst)
fpr.Flush(FLUSH_ALL);
WriteExit(js.compilerPC + 4, 0);
}
// ==============
void Jit64::mfmsr(UGeckoInstruction inst)
{

View File

@ -717,7 +717,7 @@ static void regWriteExit(RegInfo& RI, InstLoc dest) {
if (isImm(*dest)) {
RI.Jit->WriteExit(RI.Build->GetImmValue(dest), RI.exitNumber++);
} else {
RI.Jit->WriteExitDestInOpArg(regLocForInst(RI, dest), RI.exitNumber++);
RI.Jit->WriteExitDestInOpArg(regLocForInst(RI, dest));
}
}
@ -1831,7 +1831,7 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak
}
case InterpreterBranch: {
Jit->MOV(32, R(EAX), M(&NPC));
Jit->WriteExitDestInOpArg(R(EAX), 0);
Jit->WriteExitDestInOpArg(R(EAX));
break;
}
case RFIExit: {
@ -1848,7 +1848,10 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak
Jit->MOV(32, M(&MSR), R(EAX));
// NPC = SRR0;
Jit->MOV(32, R(EAX), M(&SRR0));
Jit->WriteRfiExitDestInOpArg(R(EAX));
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bAlternateRFI)
Jit->WriteExitDestInOpArg(R(EAX));
else
Jit->WriteRfiExitDestInOpArg(R(EAX));
break;
}
case FPExceptionCheckStart: {

View File

@ -246,7 +246,7 @@ void JitIL::HLEFunction(UGeckoInstruction _inst)
{
ABI_CallFunctionCC((void*)&HLE::Execute, js.compilerPC, _inst.hex);
MOV(32, R(EAX), M(&NPC));
WriteExitDestInOpArg(R(EAX), 0);
WriteExitDestInOpArg(R(EAX));
}
void JitIL::DoNothing(UGeckoInstruction _inst)
@ -314,7 +314,7 @@ void JitIL::WriteExit(u32 destination, int exit_num)
}
}
void JitIL::WriteExitDestInOpArg(const Gen::OpArg& arg, int exit_num)
void JitIL::WriteExitDestInOpArg(const Gen::OpArg& arg)
{
MOV(32, M(&PC), arg);
Cleanup();

View File

@ -110,7 +110,7 @@ public:
// Utilities for use by opcodes
void WriteExit(u32 destination, int exit_num);
void WriteExitDestInOpArg(const Gen::OpArg& arg, int exit_num);
void WriteExitDestInOpArg(const Gen::OpArg& arg);
void WriteExceptionExit();
void WriteRfiExitDestInOpArg(const Gen::OpArg& arg);
void WriteCallInterpreter(UGeckoInstruction _inst);

View File

@ -106,9 +106,9 @@ bool BootCore(const std::string& _rFilename)
game_ini.Get("Core", "CPUThread", &StartUp.bCPUThread, StartUp.bCPUThread);
game_ini.Get("Core", "SkipIdle", &StartUp.bSkipIdle, StartUp.bSkipIdle);
game_ini.Get("Core", "EnableFPRF", &StartUp.bEnableFPRF, StartUp.bEnableFPRF);
game_ini.Get("Core", "TLBHack", &StartUp.iTLBHack, StartUp.iTLBHack);
game_ini.Get("Core", "MMU", &StartUp.bMMU, StartUp.bMMU);
game_ini.Get("Core", "SMC", &StartUp.bSMC, StartUp.bSMC);
game_ini.Get("Core", "TLBHack", &StartUp.iTLBHack, StartUp.iTLBHack);
game_ini.Get("Core", "AlternateRFI", &StartUp.bAlternateRFI, StartUp.bAlternateRFI);
// Wii settings
if (StartUp.bWii)
{

View File

@ -291,8 +291,11 @@ void CISOProperties::CreateGUIControls(bool IsWad)
CPUThread = new wxCheckBox(m_GameConfig, ID_USEDUALCORE, _("Enable Dual Core"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
SkipIdle = new wxCheckBox(m_GameConfig, ID_IDLESKIP, _("Enable Idle Skipping"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
MMU = new wxCheckBox(m_GameConfig, ID_MMU, _("Enable MMU"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
MMU->SetToolTip(wxT("Enables the Memory Management Unit, needed for some games (slow)."));
TLBHack = new wxCheckBox(m_GameConfig, ID_TLBHACK, _("MMU Speed Hack"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
SMC = new wxCheckBox(m_GameConfig, ID_MMU, _("Enable self modifying code check"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
TLBHack->SetToolTip(wxT("Fast version of the MMU. Does not work for every game."));
AlternateRFI = new wxCheckBox(m_GameConfig, ID_RFI, _("Alternate RFI"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
AlternateRFI->SetToolTip(wxT("If a game hangs, works only in the Interpreter or Dolphin crashes, this option may fix the game."));
// Wii Console
sbWiiOverrides = new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Wii Console"));
EnableProgressiveScan = new wxCheckBox(m_GameConfig, ID_ENABLEPROGRESSIVESCAN, _("Enable Progressive Scan"), wxDefaultPosition, wxDefaultSize, wxCHK_3STATE|wxCHK_ALLOW_3RD_STATE_FOR_USER, wxDefaultValidator);
@ -352,7 +355,7 @@ void CISOProperties::CreateGUIControls(bool IsWad)
sbCoreOverrides->Add(SkipIdle, 0, wxEXPAND|wxLEFT, 5);
sbCoreOverrides->Add(MMU, 0, wxEXPAND|wxLEFT, 5);
sbCoreOverrides->Add(TLBHack, 0, wxEXPAND|wxLEFT, 5);
sbCoreOverrides->Add(SMC, 0, wxEXPAND|wxLEFT, 5);
sbCoreOverrides->Add(AlternateRFI, 0, wxEXPAND|wxLEFT, 5);
sbWiiOverrides->Add(EnableProgressiveScan, 0, wxEXPAND|wxLEFT, 5);
sbWiiOverrides->Add(EnableWideScreen, 0, wxEXPAND|wxLEFT, 5);
sbVideoOverrides->Add(ForceFiltering, 0, wxEXPAND|wxLEFT, 5);
@ -826,10 +829,10 @@ void CISOProperties::LoadGameConfig()
else
TLBHack->Set3StateValue(wxCHK_UNDETERMINED);
if (GameIni.Get("Core", "SMC", &bTemp))
SMC->Set3StateValue((wxCheckBoxState)bTemp);
if (GameIni.Get("Core", "AlternateRFI", &bTemp))
AlternateRFI->Set3StateValue((wxCheckBoxState)bTemp);
else
SMC->Set3StateValue(wxCHK_UNDETERMINED);
AlternateRFI->Set3StateValue(wxCHK_UNDETERMINED);
if (GameIni.Get("Wii", "ProgressiveScan", &bTemp))
EnableProgressiveScan->Set3StateValue((wxCheckBoxState)bTemp);
@ -922,10 +925,10 @@ bool CISOProperties::SaveGameConfig()
else
GameIni.Set("Core", "TLBHack", TLBHack->Get3StateValue());
if (SMC->Get3StateValue() == wxCHK_UNDETERMINED)
GameIni.DeleteKey("Core", "SMC");
if (AlternateRFI->Get3StateValue() == wxCHK_UNDETERMINED)
GameIni.DeleteKey("Core", "AlternateRFI");
else
GameIni.Set("Core", "SMC", SMC->Get3StateValue());
GameIni.Set("Core", "AlternateRFI", AlternateRFI->Get3StateValue());
if (EnableProgressiveScan->Get3StateValue() == wxCHK_UNDETERMINED)
GameIni.DeleteKey("Wii", "ProgressiveScan");

View File

@ -84,7 +84,7 @@ class CISOProperties : public wxDialog
wxStaticText *OverrideText;
// Core
wxCheckBox *CPUThread, *SkipIdle, *MMU, *SMC, *TLBHack;
wxCheckBox *CPUThread, *SkipIdle, *MMU, *AlternateRFI, *TLBHack;
// Wii
wxCheckBox *EnableProgressiveScan, *EnableWideScreen;
// Video
@ -166,7 +166,7 @@ class CISOProperties : public wxDialog
ID_IDLESKIP,
ID_MMU,
ID_TLBHACK,
ID_SMC,
ID_RFI,
ID_FORCEFILTERING,
ID_EFBCOPYDISABLE,
ID_EFBTOTEXTUREENABLE,