Core: Start to handle jump in delay slot

This commit is contained in:
zilmar 2022-12-26 12:54:04 +10:30
parent 8803f17d85
commit f380d326fe
3 changed files with 85 additions and 23 deletions

View File

@ -84,7 +84,7 @@ void CCodeSection::GenerateSectionLinkage()
} }
else if (TargetSection[i] == nullptr && JumpInfo[i]->FallThrough) else if (TargetSection[i] == nullptr && JumpInfo[i]->FallThrough)
{ {
m_RecompilerOps->LinkJump(*JumpInfo[i], (uint32_t)-1); m_RecompilerOps->LinkJump(*JumpInfo[i]);
if (JumpInfo[i]->LinkAddress != (uint32_t)-1) if (JumpInfo[i]->LinkAddress != (uint32_t)-1)
{ {
JumpInfo[i]->RegSet.UnMap_GPR(31, false); JumpInfo[i]->RegSet.UnMap_GPR(31, false);
@ -105,7 +105,7 @@ void CCodeSection::GenerateSectionLinkage()
{ {
continue; continue;
} }
m_RecompilerOps->LinkJump(*JumpInfo[i], (uint32_t)-1); m_RecompilerOps->LinkJump(*JumpInfo[i]);
if (JumpInfo[i]->LinkAddress != (uint32_t)-1) if (JumpInfo[i]->LinkAddress != (uint32_t)-1)
{ {
JumpInfo[i]->RegSet.UnMap_GPR(31, false); JumpInfo[i]->RegSet.UnMap_GPR(31, false);
@ -151,7 +151,7 @@ void CCodeSection::GenerateSectionLinkage()
if (TargetSection[i]->m_EnterLabel.isValid()) if (TargetSection[i]->m_EnterLabel.isValid())
{ {
JumpInfo[i]->FallThrough = false; JumpInfo[i]->FallThrough = false;
m_RecompilerOps->LinkJump(*JumpInfo[i], TargetSection[i]->m_SectionID); m_RecompilerOps->LinkJump(*JumpInfo[i]);
if (JumpInfo[i]->LinkAddress != (uint32_t)-1) if (JumpInfo[i]->LinkAddress != (uint32_t)-1)
{ {
JumpInfo[i]->RegSet.UnMap_GPR(31, false); JumpInfo[i]->RegSet.UnMap_GPR(31, false);
@ -252,7 +252,7 @@ void CCodeSection::GenerateSectionLinkage()
if (TargetSection[i] == nullptr) if (TargetSection[i] == nullptr)
{ {
m_CodeBlock.Log("ExitBlock (from %d):", m_SectionID); m_CodeBlock.Log("ExitBlock (from %d):", m_SectionID);
m_RecompilerOps->LinkJump(*JumpInfo[i], (uint32_t)-1); m_RecompilerOps->LinkJump(*JumpInfo[i]);
if (JumpInfo[i]->LinkAddress != (uint32_t)-1) if (JumpInfo[i]->LinkAddress != (uint32_t)-1)
{ {
JumpInfo[i]->RegSet.UnMap_GPR(31, false); JumpInfo[i]->RegSet.UnMap_GPR(31, false);
@ -276,7 +276,7 @@ void CCodeSection::GenerateSectionLinkage()
stdstr_f Label("Section_%d (from %d):", TargetSection[i]->m_SectionID, m_SectionID); stdstr_f Label("Section_%d (from %d):", TargetSection[i]->m_SectionID, m_SectionID);
m_CodeBlock.Log(Label.c_str()); m_CodeBlock.Log(Label.c_str());
m_RecompilerOps->LinkJump(*JumpInfo[i], (uint32_t)-1); m_RecompilerOps->LinkJump(*JumpInfo[i]);
if (JumpInfo[i]->LinkAddress != (uint32_t)-1) if (JumpInfo[i]->LinkAddress != (uint32_t)-1)
{ {
JumpInfo[i]->RegSet.UnMap_GPR(31, false); JumpInfo[i]->RegSet.UnMap_GPR(31, false);

View File

@ -469,7 +469,44 @@ void CX86RecompilerOps::Compile_BranchCompare(RecompilerBranchCompare CompareTyp
void CX86RecompilerOps::Compile_Branch(RecompilerBranchCompare CompareType, bool Link) void CX86RecompilerOps::Compile_Branch(RecompilerBranchCompare CompareType, bool Link)
{ {
if (m_PipelineStage == PIPELINE_STAGE_NORMAL) if (m_PipelineStage == PIPELINE_STAGE_DELAY_SLOT)
{
Compile_BranchCompare(CompareType);
if (m_Section->m_Jump.FallThrough || (!m_Section->m_Cont.FallThrough && m_Section->m_Jump.LinkLocation.isValid()))
{
LinkJump(m_Section->m_Jump);
m_Assembler.MoveConstToVariable(&g_System->m_JumpDelayLocation, "System::m_JumpDelayLocation", m_CompilePC + ((int16_t)m_Opcode.offset << 2) + 8);
if (m_Section->m_Cont.LinkLocation.isValid())
{
// jump to link
g_Notify->BreakPoint(__FILE__, __LINE__);
}
}
if (m_Section->m_Cont.FallThrough)
{
LinkJump(m_Section->m_Cont);
m_Assembler.MoveConstToVariable(&g_System->m_JumpDelayLocation, "System::m_JumpDelayLocation", m_CompilePC + 8);
if (m_Section->m_Jump.LinkLocation.isValid())
{
// jump to link
g_Notify->BreakPoint(__FILE__, __LINE__);
}
}
if (m_Section->m_Jump.LinkLocation.isValid() || m_Section->m_Cont.LinkLocation.isValid())
{
g_Notify->BreakPoint(__FILE__, __LINE__);
}
if (Link)
{
Map_GPR_32bit(31, true, -1);
m_Assembler.MoveVariableToX86reg(GetMipsRegMapLo(31), &g_System->m_JumpToLocation, "System::m_JumpToLocation");
m_Assembler.add(GetMipsRegMapLo(31), 4);
}
OverflowDelaySlot(false);
}
else if (m_PipelineStage == PIPELINE_STAGE_NORMAL)
{ {
if (CompareType == RecompilerBranchCompare_COP1BCF || CompareType == RecompilerBranchCompare_COP1BCT) if (CompareType == RecompilerBranchCompare_COP1BCF || CompareType == RecompilerBranchCompare_COP1BCT)
{ {
@ -492,6 +529,11 @@ void CX86RecompilerOps::Compile_Branch(RecompilerBranchCompare CompareType, bool
} }
m_Section->m_Jump.JumpPC = m_CompilePC; m_Section->m_Jump.JumpPC = m_CompilePC;
m_Section->m_Jump.TargetPC = m_CompilePC + ((int16_t)m_Opcode.offset << 2) + 4; m_Section->m_Jump.TargetPC = m_CompilePC + ((int16_t)m_Opcode.offset << 2) + 4;
if (m_PipelineStage == PIPELINE_STAGE_DELAY_SLOT)
{
m_Section->m_Jump.TargetPC += 4;
m_EffectDelaySlot = true;
}
if (m_Section->m_JumpSection != nullptr) if (m_Section->m_JumpSection != nullptr)
{ {
m_Section->m_Jump.BranchLabel = stdstr_f("Section_%d", m_Section->m_JumpSection->m_SectionID); m_Section->m_Jump.BranchLabel = stdstr_f("Section_%d", m_Section->m_JumpSection->m_SectionID);
@ -565,15 +607,11 @@ void CX86RecompilerOps::Compile_Branch(RecompilerBranchCompare CompareType, bool
{ {
if (m_Section->m_Jump.LinkLocation.isValid()) if (m_Section->m_Jump.LinkLocation.isValid())
{ {
m_CodeBlock.Log("");
m_CodeBlock.Log(" %s:", m_Section->m_Jump.BranchLabel.c_str());
LinkJump(m_Section->m_Jump); LinkJump(m_Section->m_Jump);
m_Section->m_Jump.FallThrough = true; m_Section->m_Jump.FallThrough = true;
} }
else if (m_Section->m_Cont.LinkLocation.isValid()) else if (m_Section->m_Cont.LinkLocation.isValid())
{ {
m_CodeBlock.Log("");
m_CodeBlock.Log(" %s:", m_Section->m_Cont.BranchLabel.c_str());
LinkJump(m_Section->m_Cont); LinkJump(m_Section->m_Cont);
m_Section->m_Cont.FallThrough = true; m_Section->m_Cont.FallThrough = true;
} }
@ -607,8 +645,6 @@ void CX86RecompilerOps::Compile_Branch(RecompilerBranchCompare CompareType, bool
DelayLinkLocation = m_Assembler.newLabel(); DelayLinkLocation = m_Assembler.newLabel();
m_Assembler.JmpLabel("DoDelaySlot", DelayLinkLocation); m_Assembler.JmpLabel("DoDelaySlot", DelayLinkLocation);
m_CodeBlock.Log(" ");
m_CodeBlock.Log(" %s:", m_Section->m_Jump.BranchLabel.c_str());
LinkJump(m_Section->m_Jump); LinkJump(m_Section->m_Jump);
m_Assembler.MoveConstToVariable(&g_System->m_JumpToLocation, "System::m_JumpToLocation", m_Section->m_Jump.TargetPC); m_Assembler.MoveConstToVariable(&g_System->m_JumpToLocation, "System::m_JumpToLocation", m_Section->m_Jump.TargetPC);
} }
@ -621,8 +657,6 @@ void CX86RecompilerOps::Compile_Branch(RecompilerBranchCompare CompareType, bool
DelayLinkLocation = m_Assembler.newLabel(); DelayLinkLocation = m_Assembler.newLabel();
m_Assembler.JmpLabel("DoDelaySlot", DelayLinkLocation); m_Assembler.JmpLabel("DoDelaySlot", DelayLinkLocation);
m_CodeBlock.Log(" ");
m_CodeBlock.Log(" %s:", m_Section->m_Cont.BranchLabel.c_str());
LinkJump(m_Section->m_Cont); LinkJump(m_Section->m_Cont);
m_Assembler.MoveConstToVariable(&g_System->m_JumpToLocation, "System::m_JumpToLocation", m_Section->m_Cont.TargetPC); m_Assembler.MoveConstToVariable(&g_System->m_JumpToLocation, "System::m_JumpToLocation", m_Section->m_Cont.TargetPC);
} }
@ -637,8 +671,19 @@ void CX86RecompilerOps::Compile_Branch(RecompilerBranchCompare CompareType, bool
ResetX86Protection(); ResetX86Protection();
m_RegBeforeDelay = m_RegWorkingSet; m_RegBeforeDelay = m_RegWorkingSet;
} }
if (m_PipelineStage == PIPELINE_STAGE_NORMAL)
{
m_PipelineStage = PIPELINE_STAGE_DO_DELAY_SLOT; m_PipelineStage = PIPELINE_STAGE_DO_DELAY_SLOT;
} }
else
{
m_RegWorkingSet.SetBlockCycleCount(m_RegWorkingSet.GetBlockCycleCount() + g_System->CountPerOp());
m_Section->m_Jump.RegSet = m_RegWorkingSet;
m_Section->m_Cont.RegSet = m_RegWorkingSet;
m_Section->GenerateSectionLinkage();
m_PipelineStage = PIPELINE_STAGE_END_BLOCK;
}
}
else if (m_PipelineStage == PIPELINE_STAGE_DELAY_SLOT_DONE) else if (m_PipelineStage == PIPELINE_STAGE_DELAY_SLOT_DONE)
{ {
if (m_CompilePC + ((int16_t)m_Opcode.offset << 2) + 4 == m_CompilePC + 8) if (m_CompilePC + ((int16_t)m_Opcode.offset << 2) + 4 == m_CompilePC + 8)
@ -697,7 +742,6 @@ void CX86RecompilerOps::Compile_Branch(RecompilerBranchCompare CompareType, bool
if (JumpInfo->LinkLocation.isValid()) if (JumpInfo->LinkLocation.isValid())
{ {
m_CodeBlock.Log(" %s:", JumpInfo->BranchLabel.c_str());
LinkJump(*JumpInfo); LinkJump(*JumpInfo);
JumpInfo->FallThrough = true; JumpInfo->FallThrough = true;
m_PipelineStage = PIPELINE_STAGE_DO_DELAY_SLOT; m_PipelineStage = PIPELINE_STAGE_DO_DELAY_SLOT;
@ -2149,6 +2193,14 @@ void CX86RecompilerOps::J()
OverflowDelaySlot(false); OverflowDelaySlot(false);
return; return;
} }
R4300iOpcode DelaySlot;
g_MMU->MemoryValue32(m_CompilePC + 4, DelaySlot.Value);
if (R4300iInstruction(m_CompilePC + 4, DelaySlot.Value).HasDelaySlot())
{
m_Assembler.MoveConstToVariable(&g_System->m_JumpToLocation, "System::m_JumpToLocation", (m_CompilePC & 0xF0000000) + (m_Opcode.target << 2));
m_PipelineStage = PIPELINE_STAGE_DO_DELAY_SLOT;
return;
}
m_Section->m_Jump.TargetPC = (m_CompilePC & 0xF0000000) + (m_Opcode.target << 2); m_Section->m_Jump.TargetPC = (m_CompilePC & 0xF0000000) + (m_Opcode.target << 2);
m_Section->m_Jump.JumpPC = m_CompilePC; m_Section->m_Jump.JumpPC = m_CompilePC;
@ -8644,7 +8696,7 @@ bool CX86RecompilerOps::InheritParentInfo()
CJumpInfo * JumpInfo = m_Section == Parent->m_ContinueSection ? &Parent->m_Cont : &Parent->m_Jump; CJumpInfo * JumpInfo = m_Section == Parent->m_ContinueSection ? &Parent->m_Cont : &Parent->m_Jump;
m_Section->m_RegEnter = JumpInfo->RegSet; m_Section->m_RegEnter = JumpInfo->RegSet;
LinkJump(*JumpInfo, m_Section->m_SectionID); LinkJump(*JumpInfo);
SetRegWorkingSet(m_Section->m_RegEnter); SetRegWorkingSet(m_Section->m_RegEnter);
return true; return true;
} }
@ -8734,7 +8786,7 @@ bool CX86RecompilerOps::InheritParentInfo()
SetRegWorkingSet(JumpInfo->RegSet); SetRegWorkingSet(JumpInfo->RegSet);
m_RegWorkingSet.ResetX86Protection(); m_RegWorkingSet.ResetX86Protection();
LinkJump(*JumpInfo, m_Section->m_SectionID, Parent->m_SectionID); LinkJump(*JumpInfo);
if (JumpInfo->Reason == ExitReason_NormalNoSysCheck) if (JumpInfo->Reason == ExitReason_NormalNoSysCheck)
{ {
@ -9052,10 +9104,11 @@ bool CX86RecompilerOps::InheritParentInfo()
return true; return true;
} }
void CX86RecompilerOps::LinkJump(CJumpInfo & JumpInfo, uint32_t SectionID, uint32_t FromSectionID) void CX86RecompilerOps::LinkJump(CJumpInfo & JumpInfo)
{ {
if (JumpInfo.LinkLocation.isValid()) if (JumpInfo.LinkLocation.isValid())
{ {
m_CodeBlock.Log("");
m_Assembler.bind(JumpInfo.LinkLocation); m_Assembler.bind(JumpInfo.LinkLocation);
JumpInfo.LinkLocation = asmjit::Label(); JumpInfo.LinkLocation = asmjit::Label();
if (JumpInfo.LinkLocation2.isValid()) if (JumpInfo.LinkLocation2.isValid())
@ -9235,15 +9288,24 @@ void CX86RecompilerOps::OverflowDelaySlot(bool TestTimer)
m_RegWorkingSet.SetBlockCycleCount(m_RegWorkingSet.GetBlockCycleCount() + g_System->CountPerOp()); m_RegWorkingSet.SetBlockCycleCount(m_RegWorkingSet.GetBlockCycleCount() + g_System->CountPerOp());
m_RegWorkingSet.WriteBackRegisters(); m_RegWorkingSet.WriteBackRegisters();
UpdateCounters(m_RegWorkingSet, false, true); UpdateCounters(m_RegWorkingSet, false, true);
if (m_PipelineStage == PIPELINE_STAGE_DELAY_SLOT)
{
m_Assembler.MoveVariableToX86reg(asmjit::x86::ecx, &g_System->m_JumpToLocation, "System::m_JumpToLocation");
m_Assembler.MoveX86regToVariable(_PROGRAM_COUNTER, "PROGRAM_COUNTER", asmjit::x86::ecx);
m_Assembler.MoveVariableToX86reg(asmjit::x86::ecx, &g_System->m_JumpDelayLocation, "System::JumpDelayLocation");
m_Assembler.MoveX86regToVariable(&g_System->m_JumpToLocation, "System::m_JumpToLocation", asmjit::x86::ecx);
}
else
{
m_Assembler.MoveConstToVariable(_PROGRAM_COUNTER, "PROGRAM_COUNTER", CompilePC() + 4); m_Assembler.MoveConstToVariable(_PROGRAM_COUNTER, "PROGRAM_COUNTER", CompilePC() + 4);
}
if (g_SyncSystem) if (g_SyncSystem)
{ {
m_Assembler.CallThis((uint32_t)g_BaseSystem, AddressOf(&CN64System::SyncSystem), "CN64System::SyncSystem", 4); m_Assembler.CallThis((uint32_t)g_BaseSystem, AddressOf(&CN64System::SyncSystem), "CN64System::SyncSystem", 4);
} }
m_Assembler.MoveConstToVariable(&g_System->m_PipelineStage, "System->m_PipelineStage", PIPELINE_STAGE_JUMP); m_Assembler.MoveConstToVariable(&g_System->m_PipelineStage, "System->m_PipelineStage", PIPELINE_STAGE_JUMP);
if (TestTimer) if (TestTimer)
{ {
m_Assembler.MoveConstToVariable(&R4300iOp::m_TestTimer, "R4300iOp::m_TestTimer", TestTimer); m_Assembler.MoveConstToVariable(&R4300iOp::m_TestTimer, "R4300iOp::m_TestTimer", TestTimer);

View File

@ -224,7 +224,7 @@ public:
CRegInfo & GetRegWorkingSet(void); CRegInfo & GetRegWorkingSet(void);
void SetRegWorkingSet(const CRegInfo & RegInfo); void SetRegWorkingSet(const CRegInfo & RegInfo);
bool InheritParentInfo(); bool InheritParentInfo();
void LinkJump(CJumpInfo & JumpInfo, uint32_t SectionID = -1, uint32_t FromSectionID = -1); void LinkJump(CJumpInfo & JumpInfo);
void JumpToSection(CCodeSection * Section); void JumpToSection(CCodeSection * Section);
void JumpToUnknown(CJumpInfo * JumpInfo); void JumpToUnknown(CJumpInfo * JumpInfo);
void SetCurrentPC(uint32_t ProgramCounter); void SetCurrentPC(uint32_t ProgramCounter);