/**************************************************************************** * * * Project64 - A Nintendo 64 emulator. * * http://www.pj64-emu.com/ * * Copyright (C) 2012 Project64. All rights reserved. * * * * License: * * GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html * * * ****************************************************************************/ #include "stdafx.h" #include #include #include #include #include #include #include #include #include #include #include void InPermLoop(); bool DelaySlotEffectsCompare(uint32_t PC, uint32_t Reg1, uint32_t Reg2); static bool DelaySlotEffectsJump(uint32_t JumpPC) { OPCODE Command; if (!g_MMU->LW_VAddr(JumpPC, Command.Hex)) { return true; } switch (Command.op) { case R4300i_SPECIAL: switch (Command.funct) { case R4300i_SPECIAL_JR: return DelaySlotEffectsCompare(JumpPC, Command.rs, 0); case R4300i_SPECIAL_JALR: return DelaySlotEffectsCompare(JumpPC, Command.rs, 31); } break; case R4300i_REGIMM: switch (Command.rt) { case R4300i_REGIMM_BLTZ: case R4300i_REGIMM_BGEZ: case R4300i_REGIMM_BLTZL: case R4300i_REGIMM_BGEZL: case R4300i_REGIMM_BLTZAL: case R4300i_REGIMM_BGEZAL: return DelaySlotEffectsCompare(JumpPC, Command.rs, 0); } break; case R4300i_JAL: case R4300i_SPECIAL_JALR: return DelaySlotEffectsCompare(JumpPC, 31, 0); break; case R4300i_J: return false; case R4300i_BEQ: case R4300i_BNE: case R4300i_BLEZ: case R4300i_BGTZ: return DelaySlotEffectsCompare(JumpPC, Command.rs, Command.rt); case R4300i_CP1: switch (Command.fmt) { case R4300i_COP1_BC: switch (Command.ft) { case R4300i_COP1_BC_BCF: case R4300i_COP1_BC_BCT: case R4300i_COP1_BC_BCFL: case R4300i_COP1_BC_BCTL: { bool EffectDelaySlot = false; OPCODE NewCommand; if (!g_MMU->LW_VAddr(JumpPC + 4, NewCommand.Hex)) { return true; } if (NewCommand.op == R4300i_CP1) { if (NewCommand.fmt == R4300i_COP1_S && (NewCommand.funct & 0x30) == 0x30) { EffectDelaySlot = true; } if (NewCommand.fmt == R4300i_COP1_D && (NewCommand.funct & 0x30) == 0x30) { EffectDelaySlot = true; } } return EffectDelaySlot; } break; } break; } break; case R4300i_BEQL: case R4300i_BNEL: case R4300i_BLEZL: case R4300i_BGTZL: return DelaySlotEffectsCompare(JumpPC, Command.rs, Command.rt); } return true; } CCodeSection::CCodeSection(CCodeBlock * CodeBlock, uint32_t EnterPC, uint32_t ID, bool LinkAllowed) : m_BlockInfo(CodeBlock), m_SectionID(ID), m_EnterPC(EnterPC), m_EndPC((uint32_t)-1), m_ContinueSection(NULL), m_JumpSection(NULL), m_EndSection(false), m_LinkAllowed(LinkAllowed), m_Test(0), m_Test2(0), m_CompiledLocation(NULL), m_InLoop(false), m_DelaySlot(false), m_RecompilerOps(CodeBlock->RecompilerOps()) { CPU_Message("%s: ID %d EnterPC 0x%08X", __FUNCTION__, ID, EnterPC); m_RecompilerOps->SetCurrentSection(this); } CCodeSection::~CCodeSection() { } void CCodeSection::GenerateSectionLinkage() { CCodeSection * TargetSection[] = { m_ContinueSection, m_JumpSection }; CJumpInfo * JumpInfo[] = { &m_Cont, &m_Jump }; int i; for (i = 0; i < 2; i++) { if (JumpInfo[i]->LinkLocation == NULL && JumpInfo[i]->FallThrough == false) { JumpInfo[i]->TargetPC = (uint32_t)-1; } } if ((m_RecompilerOps->GetCurrentPC() & 0xFFC) == 0xFFC) { g_Notify->BreakPoint(__FILE__, __LINE__); #ifdef legacycode //Handle Fall througth uint8_t * Jump = NULL; for (i = 0; i < 2; i ++) { if (!JumpInfo[i]->FallThrough) { continue; } JumpInfo[i]->FallThrough = false; if (JumpInfo[i]->LinkLocation != NULL) { SetJump32(JumpInfo[i]->LinkLocation,(uint32_t *)*g_RecompPos); JumpInfo[i]->LinkLocation = NULL; if (JumpInfo[i]->LinkLocation2 != NULL) { SetJump32(JumpInfo[i]->LinkLocation2,(uint32_t *)*g_RecompPos); JumpInfo[i]->LinkLocation2 = NULL; } } PushImm32(stdstr_f("0x%08X",JumpInfo[i]->TargetPC).c_str(),JumpInfo[i]->TargetPC); if (JumpInfo[(i + 1) & 1]->LinkLocation == NULL) { break; } JmpLabel8("FinishBlock",0); Jump = *g_RecompPos - 1; } for (i = 0; i < 2; i ++) { if (JumpInfo[i]->LinkLocation == NULL) { continue; } JumpInfo[i]->FallThrough = false; if (JumpInfo[i]->LinkLocation != NULL) { SetJump32(JumpInfo[i]->LinkLocation,(uint32_t *)*g_RecompPos); JumpInfo[i]->LinkLocation = NULL; if (JumpInfo[i]->LinkLocation2 != NULL) { SetJump32(JumpInfo[i]->LinkLocation2,(uint32_t *)*g_RecompPos); JumpInfo[i]->LinkLocation2 = NULL; } } PushImm32(stdstr_f("0x%08X",JumpInfo[i]->TargetPC).c_str(),JumpInfo[i]->TargetPC); if (JumpInfo[(i + 1) & 1]->LinkLocation == NULL) { break; } JmpLabel8("FinishBlock",0); Jump = *g_RecompPos - 1; } if (Jump != NULL) { CPU_Message(" $FinishBlock:"); SetJump8(Jump,*g_RecompPos); } //MoveConstToVariable(m_RecompilerOps->GetCurrentPC() + 4,_PROGRAM_COUNTER,"PROGRAM_COUNTER"); m_RegWorkingSet.WriteBackRegisters(); m_RecompilerOps->UpdateCounters(m_RegWorkingSet,false,true); // WriteBackRegisters(Section); // if (g_SyncSystem) { MoveConstToX86reg((uint32_t)g_BaseSystem,x86_ECX); Call_Direct(AddressOf(&CN64System::SyncSystem), "CN64System::SyncSystem"); //} // MoveConstToVariable(DELAY_SLOT,&m_NextInstruction,"m_NextInstruction"); PushImm32(stdstr_f("0x%08X",m_RecompilerOps->GetCurrentPC() + 4).c_str(),m_RecompilerOps->GetCurrentPC() + 4); // check if there is an existing section MoveConstToX86reg((uint32_t)g_Recompiler,x86_ECX); Call_Direct(AddressOf(&CRecompiler::CompileDelaySlot), "CRecompiler::CompileDelaySlot"); JmpDirectReg(x86_EAX); ExitCodeBlock(); return; #endif } // Handle Perm Loop if (m_RecompilerOps->GetCurrentPC() == m_Jump.TargetPC && (m_Cont.FallThrough == false)) { if (!DelaySlotEffectsJump(m_RecompilerOps->GetCurrentPC())) { m_RecompilerOps->CompileInPermLoop(m_Jump.RegSet, m_RecompilerOps->GetCurrentPC()); } } if (TargetSection[0] != TargetSection[1] || TargetSection[0] == NULL) { for (i = 0; i < 2; i++) { if (JumpInfo[i]->LinkLocation == NULL && JumpInfo[i]->FallThrough == false) { if (TargetSection[i]) { TargetSection[i]->UnlinkParent(this, i == 0); TargetSection[i] = NULL; } } else if (TargetSection[i] == NULL && JumpInfo[i]->FallThrough) { m_RecompilerOps->LinkJump(*JumpInfo[i], (uint32_t)-1); m_RecompilerOps->CompileExit(JumpInfo[i]->JumpPC, JumpInfo[i]->TargetPC, JumpInfo[i]->RegSet, JumpInfo[i]->ExitReason); JumpInfo[i]->FallThrough = false; } else if (TargetSection[i] != NULL && JumpInfo[i] != NULL) { if (!JumpInfo[i]->FallThrough) { continue; } if (JumpInfo[i]->TargetPC == TargetSection[i]->m_EnterPC) { continue; } m_RecompilerOps->LinkJump(*JumpInfo[i], (uint32_t)-1); m_RecompilerOps->CompileExit(JumpInfo[i]->JumpPC, JumpInfo[i]->TargetPC, JumpInfo[i]->RegSet, JumpInfo[i]->ExitReason); //FreeSection(TargetSection[i],Section); } } } else { if (m_Cont.LinkLocation == NULL && m_Cont.FallThrough == false) { m_ContinueSection = NULL; } if (m_Jump.LinkLocation == NULL && m_Jump.FallThrough == false) { m_JumpSection = NULL; } if (m_JumpSection == NULL && m_ContinueSection == NULL) { //FreeSection(TargetSection[0],Section); } } TargetSection[0] = m_ContinueSection; TargetSection[1] = m_JumpSection; for (i = 0; i < 2; i++) { if (TargetSection[i] == NULL) { continue; } if (!JumpInfo[i]->FallThrough) { continue; } if (TargetSection[i]->m_CompiledLocation != NULL) { JumpInfo[i]->FallThrough = false; m_RecompilerOps->LinkJump(*JumpInfo[i], TargetSection[i]->m_SectionID); if (JumpInfo[i]->TargetPC <= m_RecompilerOps->GetCurrentPC()) { if (JumpInfo[i]->PermLoop) { CPU_Message("PermLoop *** 1"); m_RecompilerOps->CompileInPermLoop(JumpInfo[i]->RegSet, JumpInfo[i]->TargetPC); } else { m_RecompilerOps->UpdateCounters(JumpInfo[i]->RegSet, true, true); CPU_Message("CompileSystemCheck 5"); m_RecompilerOps->CompileSystemCheck(JumpInfo[i]->TargetPC, JumpInfo[i]->RegSet); } } else { m_RecompilerOps->UpdateCounters(JumpInfo[i]->RegSet, false, true); } JumpInfo[i]->RegSet.SetBlockCycleCount(0); m_RecompilerOps->SetRegWorkingSet(JumpInfo[i]->RegSet); m_RecompilerOps->SyncRegState(TargetSection[i]->m_RegEnter); m_RecompilerOps->JumpToSection(TargetSection[i]); } } for (i = 0; i < 2; i++) { if (TargetSection[i] == NULL) { continue; } if (TargetSection[i]->m_ParentSection.empty()) { continue; } for (SECTION_LIST::iterator iter = TargetSection[i]->m_ParentSection.begin(); iter != TargetSection[i]->m_ParentSection.end(); iter++) { CCodeSection * Parent = *iter; if (Parent->m_CompiledLocation != NULL) { continue; } if (Parent->m_InLoop) { continue; } if (JumpInfo[i]->PermLoop) { CPU_Message("PermLoop *** 2"); m_RecompilerOps->CompileInPermLoop(JumpInfo[i]->RegSet, JumpInfo[i]->TargetPC); } if (JumpInfo[i]->FallThrough) { JumpInfo[i]->FallThrough = false; m_RecompilerOps->JumpToUnknown(JumpInfo[i]); } } } for (i = 0; i < 2; i++) { if (JumpInfo[i]->FallThrough) { if (JumpInfo[i]->TargetPC < m_RecompilerOps->GetCurrentPC()) { m_RecompilerOps->UpdateCounters(JumpInfo[i]->RegSet, true, true); CPU_Message("CompileSystemCheck 7"); m_RecompilerOps->CompileSystemCheck(JumpInfo[i]->TargetPC, JumpInfo[i]->RegSet); } } } CPU_Message("====== End of Section %d ======", m_SectionID); for (i = 0; i < 2; i++) { if (JumpInfo[i]->FallThrough && (TargetSection[i] == NULL || !TargetSection[i]->GenerateNativeCode(m_BlockInfo->NextTest()))) { JumpInfo[i]->FallThrough = false; m_RecompilerOps->JumpToUnknown(JumpInfo[i]); } } //CPU_Message("Section %d",m_SectionID); for (i = 0; i < 2; i++) { if (JumpInfo[i]->LinkLocation == NULL) { continue; } if (TargetSection[i] == NULL) { CPU_Message("ExitBlock (from %d):", m_SectionID); m_RecompilerOps->LinkJump(*JumpInfo[i], (uint32_t)-1); m_RecompilerOps->CompileExit(JumpInfo[i]->JumpPC, JumpInfo[i]->TargetPC, JumpInfo[i]->RegSet, JumpInfo[i]->ExitReason); continue; } if (JumpInfo[i]->TargetPC != TargetSection[i]->m_EnterPC) { g_Notify->BreakPoint(__FILE__, __LINE__); } if (TargetSection[i]->m_CompiledLocation == NULL) { TargetSection[i]->GenerateNativeCode(m_BlockInfo->NextTest()); } else { stdstr_f Label("Section_%d (from %d):", TargetSection[i]->m_SectionID, m_SectionID); CPU_Message(Label.c_str()); m_RecompilerOps->LinkJump(*JumpInfo[i], (uint32_t)-1); m_RecompilerOps->SetRegWorkingSet(JumpInfo[i]->RegSet); if (JumpInfo[i]->TargetPC <= JumpInfo[i]->JumpPC) { m_RecompilerOps->UpdateCounters(m_RecompilerOps->GetRegWorkingSet(), true, true); if (JumpInfo[i]->PermLoop) { CPU_Message("PermLoop *** 3"); m_RecompilerOps->CompileInPermLoop(m_RecompilerOps->GetRegWorkingSet(), JumpInfo[i]->TargetPC); } else { CPU_Message("CompileSystemCheck 9"); m_RecompilerOps->CompileSystemCheck(JumpInfo[i]->TargetPC, m_RecompilerOps->GetRegWorkingSet()); } } else { m_RecompilerOps->UpdateCounters(m_RecompilerOps->GetRegWorkingSet(), false, true); } m_RecompilerOps->SyncRegState(TargetSection[i]->m_RegEnter); m_RecompilerOps->JumpToSection(TargetSection[i]); } } } void CCodeSection::SetDelaySlot() { m_DelaySlot = true; } void CCodeSection::SetJumpAddress(uint32_t JumpPC, uint32_t TargetPC, bool PermLoop) { m_Jump.JumpPC = JumpPC; m_Jump.TargetPC = TargetPC; m_Jump.BranchLabel.Format("0x%08X", TargetPC); m_Jump.PermLoop = PermLoop; } void CCodeSection::SetContinueAddress(uint32_t JumpPC, uint32_t TargetPC) { m_Cont.JumpPC = JumpPC; m_Cont.TargetPC = TargetPC; m_Cont.BranchLabel.Format("0x%08X", TargetPC); } bool CCodeSection::ParentContinue() { if (m_ParentSection.size() > 0) { for (SECTION_LIST::iterator iter = m_ParentSection.begin(); iter != m_ParentSection.end(); iter++) { CCodeSection * Parent = *iter; if (Parent->m_CompiledLocation != NULL) { continue; } if (IsAllParentLoops(Parent, true, m_BlockInfo->NextTest())) { continue; } return false; } m_RecompilerOps->SetCurrentSection(this); if (!m_RecompilerOps->InheritParentInfo()) { return false; } } return true; } bool CCodeSection::GenerateNativeCode(uint32_t Test) { if (m_CompiledLocation != NULL) { if (m_Test == Test) { return false; } m_Test = Test; if (m_ContinueSection != NULL && m_ContinueSection->GenerateNativeCode(Test)) { return true; } if (m_JumpSection != NULL && m_JumpSection->GenerateNativeCode(Test)) { return true; } return false; } if (!ParentContinue()) { return false; } m_CompiledLocation = *g_RecompPos; m_RecompilerOps->SetRegWorkingSet(m_RegEnter); m_RecompilerOps->SetCurrentPC(m_EnterPC); m_RecompilerOps->SetNextStepType(m_DelaySlot ? JUMP : NORMAL); if (m_RecompilerOps->GetCurrentPC() < m_BlockInfo->VAddrFirst()) { m_BlockInfo->SetVAddrFirst(m_RecompilerOps->GetCurrentPC()); } uint32_t ContinueSectionPC = m_ContinueSection ? m_ContinueSection->m_EnterPC : (uint32_t)-1; const OPCODE & Opcode = m_RecompilerOps->GetOpcode(); do { if (m_RecompilerOps->GetCurrentPC() > m_BlockInfo->VAddrLast()) { m_BlockInfo->SetVAddrLast(m_RecompilerOps->GetCurrentPC()); } m_RecompilerOps->PreCompileOpcode(); switch (Opcode.op) { case R4300i_SPECIAL: switch (Opcode.funct) { case R4300i_SPECIAL_SLL: m_RecompilerOps->SPECIAL_SLL(); break; case R4300i_SPECIAL_SRL: m_RecompilerOps->SPECIAL_SRL(); break; case R4300i_SPECIAL_SRA: m_RecompilerOps->SPECIAL_SRA(); break; case R4300i_SPECIAL_SLLV: m_RecompilerOps->SPECIAL_SLLV(); break; case R4300i_SPECIAL_SRLV: m_RecompilerOps->SPECIAL_SRLV(); break; case R4300i_SPECIAL_SRAV: m_RecompilerOps->SPECIAL_SRAV(); break; case R4300i_SPECIAL_JR: m_RecompilerOps->SPECIAL_JR(); break; case R4300i_SPECIAL_JALR: m_RecompilerOps->SPECIAL_JALR(); break; case R4300i_SPECIAL_MFLO: m_RecompilerOps->SPECIAL_MFLO(); break; case R4300i_SPECIAL_SYSCALL: m_RecompilerOps->SPECIAL_SYSCALL(); break; case R4300i_SPECIAL_MTLO: m_RecompilerOps->SPECIAL_MTLO(); break; case R4300i_SPECIAL_MFHI: m_RecompilerOps->SPECIAL_MFHI(); break; case R4300i_SPECIAL_MTHI: m_RecompilerOps->SPECIAL_MTHI(); break; case R4300i_SPECIAL_DSLLV: m_RecompilerOps->SPECIAL_DSLLV(); break; case R4300i_SPECIAL_DSRLV: m_RecompilerOps->SPECIAL_DSRLV(); break; case R4300i_SPECIAL_DSRAV: m_RecompilerOps->SPECIAL_DSRAV(); break; case R4300i_SPECIAL_MULT: m_RecompilerOps->SPECIAL_MULT(); break; case R4300i_SPECIAL_DIV: m_RecompilerOps->SPECIAL_DIV(); break; case R4300i_SPECIAL_DIVU: m_RecompilerOps->SPECIAL_DIVU(); break; case R4300i_SPECIAL_MULTU: m_RecompilerOps->SPECIAL_MULTU(); break; case R4300i_SPECIAL_DMULT: m_RecompilerOps->SPECIAL_DMULT(); break; case R4300i_SPECIAL_DMULTU: m_RecompilerOps->SPECIAL_DMULTU(); break; case R4300i_SPECIAL_DDIV: m_RecompilerOps->SPECIAL_DDIV(); break; case R4300i_SPECIAL_DDIVU: m_RecompilerOps->SPECIAL_DDIVU(); break; case R4300i_SPECIAL_ADD: m_RecompilerOps->SPECIAL_ADD(); break; case R4300i_SPECIAL_ADDU: m_RecompilerOps->SPECIAL_ADDU(); break; case R4300i_SPECIAL_SUB: m_RecompilerOps->SPECIAL_SUB(); break; case R4300i_SPECIAL_SUBU: m_RecompilerOps->SPECIAL_SUBU(); break; case R4300i_SPECIAL_AND: m_RecompilerOps->SPECIAL_AND(); break; case R4300i_SPECIAL_OR: m_RecompilerOps->SPECIAL_OR(); break; case R4300i_SPECIAL_XOR: m_RecompilerOps->SPECIAL_XOR(); break; case R4300i_SPECIAL_NOR: m_RecompilerOps->SPECIAL_NOR(); break; case R4300i_SPECIAL_SLT: m_RecompilerOps->SPECIAL_SLT(); break; case R4300i_SPECIAL_SLTU: m_RecompilerOps->SPECIAL_SLTU(); break; case R4300i_SPECIAL_DADD: m_RecompilerOps->SPECIAL_DADD(); break; case R4300i_SPECIAL_DADDU: m_RecompilerOps->SPECIAL_DADDU(); break; case R4300i_SPECIAL_DSUB: m_RecompilerOps->SPECIAL_DSUB(); break; case R4300i_SPECIAL_DSUBU: m_RecompilerOps->SPECIAL_DSUBU(); break; case R4300i_SPECIAL_DSLL: m_RecompilerOps->SPECIAL_DSLL(); break; case R4300i_SPECIAL_DSRL: m_RecompilerOps->SPECIAL_DSRL(); break; case R4300i_SPECIAL_DSRA: m_RecompilerOps->SPECIAL_DSRA(); break; case R4300i_SPECIAL_DSLL32: m_RecompilerOps->SPECIAL_DSLL32(); break; case R4300i_SPECIAL_DSRL32: m_RecompilerOps->SPECIAL_DSRL32(); break; case R4300i_SPECIAL_DSRA32: m_RecompilerOps->SPECIAL_DSRA32(); break; default: m_RecompilerOps->UnknownOpcode(); break; } break; case R4300i_REGIMM: switch (Opcode.rt) { case R4300i_REGIMM_BLTZ: m_RecompilerOps->Compile_Branch(CRecompilerOps::CompareTypeBLTZ, CRecompilerOps::BranchTypeRs, false); break; case R4300i_REGIMM_BGEZ: m_RecompilerOps->Compile_Branch(CRecompilerOps::CompareTypeBGEZ, CRecompilerOps::BranchTypeRs, false); break; case R4300i_REGIMM_BLTZL: m_RecompilerOps->Compile_BranchLikely(CRecompilerOps::CompareTypeBLTZ, false); break; case R4300i_REGIMM_BGEZL: m_RecompilerOps->Compile_BranchLikely(CRecompilerOps::CompareTypeBGEZ, false); break; case R4300i_REGIMM_BLTZAL: m_RecompilerOps->Compile_Branch(CRecompilerOps::CompareTypeBLTZ, CRecompilerOps::BranchTypeRs, true); break; case R4300i_REGIMM_BGEZAL: m_RecompilerOps->Compile_Branch(CRecompilerOps::CompareTypeBGEZ, CRecompilerOps::BranchTypeRs, true); break; default: m_RecompilerOps->UnknownOpcode(); break; } break; case R4300i_BEQ: m_RecompilerOps->Compile_Branch(CRecompilerOps::CompareTypeBEQ, CRecompilerOps::BranchTypeRsRt, false); break; case R4300i_BNE: m_RecompilerOps->Compile_Branch(CRecompilerOps::CompareTypeBNE, CRecompilerOps::BranchTypeRsRt, false); break; case R4300i_BGTZ: m_RecompilerOps->Compile_Branch(CRecompilerOps::CompareTypeBGTZ, CRecompilerOps::BranchTypeRs, false); break; case R4300i_BLEZ: m_RecompilerOps->Compile_Branch(CRecompilerOps::CompareTypeBLEZ, CRecompilerOps::BranchTypeRs, false); break; case R4300i_J: m_RecompilerOps->J(); break; case R4300i_JAL: m_RecompilerOps->JAL(); break; case R4300i_ADDI: m_RecompilerOps->ADDI(); break; case R4300i_ADDIU: m_RecompilerOps->ADDIU(); break; case R4300i_SLTI: m_RecompilerOps->SLTI(); break; case R4300i_SLTIU: m_RecompilerOps->SLTIU(); break; case R4300i_ANDI: m_RecompilerOps->ANDI(); break; case R4300i_ORI: m_RecompilerOps->ORI(); break; case R4300i_XORI: m_RecompilerOps->XORI(); break; case R4300i_LUI: m_RecompilerOps->LUI(); break; case R4300i_CP0: switch (Opcode.rs) { case R4300i_COP0_MF: m_RecompilerOps->COP0_MF(); break; case R4300i_COP0_MT: m_RecompilerOps->COP0_MT(); break; default: if ((Opcode.rs & 0x10) != 0) { switch (Opcode.funct) { case R4300i_COP0_CO_TLBR: m_RecompilerOps->COP0_CO_TLBR(); break; case R4300i_COP0_CO_TLBWI: m_RecompilerOps->COP0_CO_TLBWI(); break; case R4300i_COP0_CO_TLBWR: m_RecompilerOps->COP0_CO_TLBWR(); break; case R4300i_COP0_CO_TLBP: m_RecompilerOps->COP0_CO_TLBP(); break; case R4300i_COP0_CO_ERET: m_RecompilerOps->COP0_CO_ERET(); break; default: m_RecompilerOps->UnknownOpcode(); break; } } else { m_RecompilerOps->UnknownOpcode(); } } break; case R4300i_CP1: switch (Opcode.rs) { case R4300i_COP1_MF: m_RecompilerOps->COP1_MF(); break; case R4300i_COP1_DMF: m_RecompilerOps->COP1_DMF(); break; case R4300i_COP1_CF: m_RecompilerOps->COP1_CF(); break; case R4300i_COP1_MT: m_RecompilerOps->COP1_MT(); break; case R4300i_COP1_DMT: m_RecompilerOps->COP1_DMT(); break; case R4300i_COP1_CT: m_RecompilerOps->COP1_CT(); break; case R4300i_COP1_BC: switch (Opcode.ft) { case R4300i_COP1_BC_BCF: m_RecompilerOps->Compile_Branch(CRecompilerOps::CompareTypeCOP1BCF, CRecompilerOps::BranchTypeCop1, false); break; case R4300i_COP1_BC_BCT: m_RecompilerOps->Compile_Branch(CRecompilerOps::CompareTypeCOP1BCT, CRecompilerOps::BranchTypeCop1, false); break; case R4300i_COP1_BC_BCFL: m_RecompilerOps->Compile_BranchLikely(CRecompilerOps::CompareTypeCOP1BCF, false); break; case R4300i_COP1_BC_BCTL: m_RecompilerOps->Compile_BranchLikely(CRecompilerOps::CompareTypeCOP1BCT, false); break; default: m_RecompilerOps->UnknownOpcode(); break; } break; case R4300i_COP1_S: switch (Opcode.funct) { case R4300i_COP1_FUNCT_ADD: m_RecompilerOps->COP1_S_ADD(); break; case R4300i_COP1_FUNCT_SUB: m_RecompilerOps->COP1_S_SUB(); break; case R4300i_COP1_FUNCT_MUL: m_RecompilerOps->COP1_S_MUL(); break; case R4300i_COP1_FUNCT_DIV: m_RecompilerOps->COP1_S_DIV(); break; case R4300i_COP1_FUNCT_ABS: m_RecompilerOps->COP1_S_ABS(); break; case R4300i_COP1_FUNCT_NEG: m_RecompilerOps->COP1_S_NEG(); break; case R4300i_COP1_FUNCT_SQRT: m_RecompilerOps->COP1_S_SQRT(); break; case R4300i_COP1_FUNCT_MOV: m_RecompilerOps->COP1_S_MOV(); break; case R4300i_COP1_FUNCT_ROUND_L: m_RecompilerOps->COP1_S_ROUND_L(); break; case R4300i_COP1_FUNCT_TRUNC_L: m_RecompilerOps->COP1_S_TRUNC_L(); break; case R4300i_COP1_FUNCT_CEIL_L: m_RecompilerOps->COP1_S_CEIL_L(); break; case R4300i_COP1_FUNCT_FLOOR_L: m_RecompilerOps->COP1_S_FLOOR_L(); break; case R4300i_COP1_FUNCT_ROUND_W: m_RecompilerOps->COP1_S_ROUND_W(); break; case R4300i_COP1_FUNCT_TRUNC_W: m_RecompilerOps->COP1_S_TRUNC_W(); break; case R4300i_COP1_FUNCT_CEIL_W: m_RecompilerOps->COP1_S_CEIL_W(); break; case R4300i_COP1_FUNCT_FLOOR_W: m_RecompilerOps->COP1_S_FLOOR_W(); break; case R4300i_COP1_FUNCT_CVT_D: m_RecompilerOps->COP1_S_CVT_D(); break; case R4300i_COP1_FUNCT_CVT_W: m_RecompilerOps->COP1_S_CVT_W(); break; case R4300i_COP1_FUNCT_CVT_L: m_RecompilerOps->COP1_S_CVT_L(); break; case R4300i_COP1_FUNCT_C_F: case R4300i_COP1_FUNCT_C_UN: case R4300i_COP1_FUNCT_C_EQ: case R4300i_COP1_FUNCT_C_UEQ: case R4300i_COP1_FUNCT_C_OLT: case R4300i_COP1_FUNCT_C_ULT: case R4300i_COP1_FUNCT_C_OLE: case R4300i_COP1_FUNCT_C_ULE: case R4300i_COP1_FUNCT_C_SF: case R4300i_COP1_FUNCT_C_NGLE: case R4300i_COP1_FUNCT_C_SEQ: case R4300i_COP1_FUNCT_C_NGL: case R4300i_COP1_FUNCT_C_LT: case R4300i_COP1_FUNCT_C_NGE: case R4300i_COP1_FUNCT_C_LE: case R4300i_COP1_FUNCT_C_NGT: m_RecompilerOps->COP1_S_CMP(); break; default: m_RecompilerOps->UnknownOpcode(); break; } break; case R4300i_COP1_D: switch (Opcode.funct) { case R4300i_COP1_FUNCT_ADD: m_RecompilerOps->COP1_D_ADD(); break; case R4300i_COP1_FUNCT_SUB: m_RecompilerOps->COP1_D_SUB(); break; case R4300i_COP1_FUNCT_MUL: m_RecompilerOps->COP1_D_MUL(); break; case R4300i_COP1_FUNCT_DIV: m_RecompilerOps->COP1_D_DIV(); break; case R4300i_COP1_FUNCT_ABS: m_RecompilerOps->COP1_D_ABS(); break; case R4300i_COP1_FUNCT_NEG: m_RecompilerOps->COP1_D_NEG(); break; case R4300i_COP1_FUNCT_SQRT: m_RecompilerOps->COP1_D_SQRT(); break; case R4300i_COP1_FUNCT_MOV: m_RecompilerOps->COP1_D_MOV(); break; case R4300i_COP1_FUNCT_ROUND_L: m_RecompilerOps->COP1_D_ROUND_L(); break; case R4300i_COP1_FUNCT_TRUNC_L: m_RecompilerOps->COP1_D_TRUNC_L(); break; case R4300i_COP1_FUNCT_CEIL_L: m_RecompilerOps->COP1_D_CEIL_L(); break; case R4300i_COP1_FUNCT_FLOOR_L: m_RecompilerOps->COP1_D_FLOOR_L(); break; case R4300i_COP1_FUNCT_ROUND_W: m_RecompilerOps->COP1_D_ROUND_W(); break; case R4300i_COP1_FUNCT_TRUNC_W: m_RecompilerOps->COP1_D_TRUNC_W(); break; case R4300i_COP1_FUNCT_CEIL_W: m_RecompilerOps->COP1_D_CEIL_W(); break; case R4300i_COP1_FUNCT_FLOOR_W: m_RecompilerOps->COP1_D_FLOOR_W(); break; case R4300i_COP1_FUNCT_CVT_S: m_RecompilerOps->COP1_D_CVT_S(); break; case R4300i_COP1_FUNCT_CVT_W: m_RecompilerOps->COP1_D_CVT_W(); break; case R4300i_COP1_FUNCT_CVT_L: m_RecompilerOps->COP1_D_CVT_L(); break; case R4300i_COP1_FUNCT_C_F: case R4300i_COP1_FUNCT_C_UN: case R4300i_COP1_FUNCT_C_EQ: case R4300i_COP1_FUNCT_C_UEQ: case R4300i_COP1_FUNCT_C_OLT: case R4300i_COP1_FUNCT_C_ULT: case R4300i_COP1_FUNCT_C_OLE: case R4300i_COP1_FUNCT_C_ULE: case R4300i_COP1_FUNCT_C_SF: case R4300i_COP1_FUNCT_C_NGLE: case R4300i_COP1_FUNCT_C_SEQ: case R4300i_COP1_FUNCT_C_NGL: case R4300i_COP1_FUNCT_C_LT: case R4300i_COP1_FUNCT_C_NGE: case R4300i_COP1_FUNCT_C_LE: case R4300i_COP1_FUNCT_C_NGT: m_RecompilerOps->COP1_D_CMP(); break; default: m_RecompilerOps->UnknownOpcode(); break; } break; case R4300i_COP1_W: switch (Opcode.funct) { case R4300i_COP1_FUNCT_CVT_S: m_RecompilerOps->COP1_W_CVT_S(); break; case R4300i_COP1_FUNCT_CVT_D: m_RecompilerOps->COP1_W_CVT_D(); break; default: m_RecompilerOps->UnknownOpcode(); break; } break; case R4300i_COP1_L: switch (Opcode.funct) { case R4300i_COP1_FUNCT_CVT_S: m_RecompilerOps->COP1_L_CVT_S(); break; case R4300i_COP1_FUNCT_CVT_D: m_RecompilerOps->COP1_L_CVT_D(); break; default: m_RecompilerOps->UnknownOpcode(); break; } break; default: m_RecompilerOps->UnknownOpcode(); break; } break; case R4300i_BEQL: m_RecompilerOps->Compile_BranchLikely(CRecompilerOps::CompareTypeBEQ, false); break; case R4300i_BNEL: m_RecompilerOps->Compile_BranchLikely(CRecompilerOps::CompareTypeBNE, false); break; case R4300i_BGTZL: m_RecompilerOps->Compile_BranchLikely(CRecompilerOps::CompareTypeBGTZ, false); break; case R4300i_BLEZL: m_RecompilerOps->Compile_BranchLikely(CRecompilerOps::CompareTypeBLEZ, false); break; case R4300i_DADDIU: m_RecompilerOps->DADDIU(); break; case R4300i_LDL: m_RecompilerOps->LDL(); break; case R4300i_LDR: m_RecompilerOps->LDR(); break; case R4300i_LB: m_RecompilerOps->LB(); break; case R4300i_LH: m_RecompilerOps->LH(); break; case R4300i_LWL: m_RecompilerOps->LWL(); break; case R4300i_LW: m_RecompilerOps->LW(); break; case R4300i_LBU: m_RecompilerOps->LBU(); break; case R4300i_LHU: m_RecompilerOps->LHU(); break; case R4300i_LWR: m_RecompilerOps->LWR(); break; case R4300i_LWU: m_RecompilerOps->LWU(); break; case R4300i_SB: m_RecompilerOps->SB(); break; case R4300i_SH: m_RecompilerOps->SH(); break; case R4300i_SWL: m_RecompilerOps->SWL(); break; case R4300i_SW: m_RecompilerOps->SW(); break; case R4300i_SWR: m_RecompilerOps->SWR(); break; case R4300i_SDL: m_RecompilerOps->SDL(); break; case R4300i_SDR: m_RecompilerOps->SDR(); break; case R4300i_CACHE: m_RecompilerOps->CACHE(); break; case R4300i_LL: m_RecompilerOps->LL(); break; case R4300i_LWC1: m_RecompilerOps->LWC1(); break; case R4300i_LDC1: m_RecompilerOps->LDC1(); break; case R4300i_SC: m_RecompilerOps->SC(); break; case R4300i_LD: m_RecompilerOps->LD(); break; case R4300i_SWC1: m_RecompilerOps->SWC1(); break; case R4300i_SDC1: m_RecompilerOps->SDC1(); break; case R4300i_SD: m_RecompilerOps->SD(); break; default: m_RecompilerOps->UnknownOpcode(); break; } m_RecompilerOps->PostCompileOpcode(); if ((m_RecompilerOps->GetCurrentPC() & 0xFFC) == 0xFFC) { if (m_RecompilerOps->GetNextStepType() == DO_DELAY_SLOT) { g_Notify->BreakPoint(__FILE__, __LINE__); } if (m_RecompilerOps->GetNextStepType() == NORMAL) { if (m_DelaySlot) { m_RecompilerOps->CompileExit(m_RecompilerOps->GetCurrentPC(), m_Jump.TargetPC, m_RecompilerOps->GetRegWorkingSet(), CExitInfo::Normal); } else { m_RecompilerOps->CompileExit(m_RecompilerOps->GetCurrentPC(), m_RecompilerOps->GetCurrentPC() + 4, m_RecompilerOps->GetRegWorkingSet(), CExitInfo::Normal); } m_RecompilerOps->SetNextStepType(END_BLOCK); } } switch (m_RecompilerOps->GetNextStepType()) { case NORMAL: m_RecompilerOps->SetCurrentPC(m_RecompilerOps->GetCurrentPC() + 4); break; case DO_DELAY_SLOT: m_RecompilerOps->SetNextStepType(DELAY_SLOT); m_RecompilerOps->SetCurrentPC(m_RecompilerOps->GetCurrentPC() + 4); break; case DELAY_SLOT: m_RecompilerOps->SetNextStepType(DELAY_SLOT_DONE); m_RecompilerOps->GetRegWorkingSet().SetBlockCycleCount(m_RecompilerOps->GetRegWorkingSet().GetBlockCycleCount() - g_System->CountPerOp()); m_RecompilerOps->SetCurrentPC(m_RecompilerOps->GetCurrentPC() - 4); break; case JUMP: case END_BLOCK: // Do nothing, block will end break; default: CPU_Message("m_RecompilerOps->GetNextStepType() = %d", m_RecompilerOps->GetNextStepType()); g_Notify->BreakPoint(__FILE__, __LINE__); break; } if (m_DelaySlot) { if ((m_RecompilerOps->GetCurrentPC() & 0xFFC) != 0xFFC && m_Jump.JumpPC != (uint32_t)-1) { m_RecompilerOps->SetCurrentPC(m_Jump.JumpPC); m_Jump.RegSet = m_RecompilerOps->GetRegWorkingSet(); m_Jump.FallThrough = true; GenerateSectionLinkage(); } else { m_RecompilerOps->CompileExit(m_Jump.JumpPC, m_Jump.TargetPC, m_RecompilerOps->GetRegWorkingSet(), CExitInfo::Normal); } m_RecompilerOps->SetNextStepType(END_BLOCK); } else if (m_RecompilerOps->GetNextStepType() != END_BLOCK && m_RecompilerOps->GetCurrentPC() == ContinueSectionPC) { if (m_RecompilerOps->GetNextStepType() != NORMAL) { g_Notify->BreakPoint(__FILE__, __LINE__); } m_RecompilerOps->SetCurrentPC(m_RecompilerOps->GetCurrentPC() - 4); m_Cont.RegSet = m_RecompilerOps->GetRegWorkingSet(); m_Cont.FallThrough = true; m_Cont.JumpPC = m_RecompilerOps->GetCurrentPC(); GenerateSectionLinkage(); m_RecompilerOps->SetNextStepType(END_BLOCK); } } while (m_RecompilerOps->GetNextStepType() != END_BLOCK); return true; } void CCodeSection::AddParent(CCodeSection * Parent) { if (Parent == NULL) { m_RecompilerOps->SetRegWorkingSet(m_RegEnter); return; } // check to see if we already have the parent in the list for (SECTION_LIST::iterator iter = m_ParentSection.begin(); iter != m_ParentSection.end(); iter++) { if (*iter == Parent) { return; } } m_ParentSection.push_back(Parent); if (m_ParentSection.size() == 1) { if (Parent->m_ContinueSection == this) { m_RegEnter = Parent->m_Cont.RegSet; } else if (Parent->m_JumpSection == this) { m_RegEnter = Parent->m_Jump.RegSet; } else { g_Notify->DisplayError("How are these sections joined?????"); } } else { if (Parent->m_ContinueSection == this) { TestRegConstantStates(Parent->m_Cont.RegSet, m_RegEnter); } if (Parent->m_JumpSection == this) { TestRegConstantStates(Parent->m_Jump.RegSet, m_RegEnter); } } m_RecompilerOps->SetRegWorkingSet(m_RegEnter); } void CCodeSection::SwitchParent(CCodeSection * OldParent, CCodeSection * NewParent) { bool bFoundOldParent = false; for (SECTION_LIST::iterator iter = m_ParentSection.begin(); iter != m_ParentSection.end(); iter++) { if (*iter != OldParent) { continue; } bFoundOldParent = true; m_ParentSection.erase(iter); break; } if (!bFoundOldParent) { g_Notify->BreakPoint(__FILE__, __LINE__); } m_ParentSection.push_back(NewParent); } void CCodeSection::TestRegConstantStates(CRegInfo & Base, CRegInfo & Reg) { for (int i = 0; i < 32; i++) { if (Reg.GetMipsRegState(i) != Base.GetMipsRegState(i)) { Reg.SetMipsRegState(i, CRegInfo::STATE_UNKNOWN); } if (Reg.IsConst(i)) { if (Reg.Is32Bit(i)) { if (Reg.GetMipsRegLo(i) != Base.GetMipsRegLo(i)) { Reg.SetMipsRegState(i, CRegInfo::STATE_UNKNOWN); } } else { if (Reg.GetMipsReg(i) != Base.GetMipsReg(i)) { Reg.SetMipsRegState(i, CRegInfo::STATE_UNKNOWN); } } } } } void CCodeSection::DetermineLoop(uint32_t Test, uint32_t Test2, uint32_t TestID) { if (m_SectionID == TestID) { if (m_Test2 != Test2) { m_Test2 = Test2; if (m_ContinueSection) { m_ContinueSection->DetermineLoop(Test, Test2, TestID); } if (m_JumpSection) { m_JumpSection->DetermineLoop(Test, Test2, TestID); } if (m_Test != Test) { m_Test = Test; if (m_ContinueSection != NULL) { m_ContinueSection->DetermineLoop(Test, m_BlockInfo->NextTest(), m_ContinueSection->m_SectionID); } if (m_JumpSection != NULL) { m_JumpSection->DetermineLoop(Test, m_BlockInfo->NextTest(), m_JumpSection->m_SectionID); } } } else { m_InLoop = true; } } else { if (m_Test2 != Test2) { m_Test2 = Test2; if (m_ContinueSection) { m_ContinueSection->DetermineLoop(Test, Test2, TestID); } if (m_JumpSection) { m_JumpSection->DetermineLoop(Test, Test2, TestID); } } } } CCodeSection * CCodeSection::ExistingSection(uint32_t Addr, uint32_t Test) { if (m_EnterPC == Addr && m_LinkAllowed) { return this; } if (m_Test == Test) { return NULL; } m_Test = Test; CCodeSection * Section = m_JumpSection ? m_JumpSection->ExistingSection(Addr, Test) : NULL; if (Section != NULL) { return Section; } Section = m_ContinueSection ? m_ContinueSection->ExistingSection(Addr, Test) : NULL; if (Section != NULL) { return Section; } return NULL; } bool CCodeSection::SectionAccessible(uint32_t SectionId, uint32_t Test) { if (m_SectionID == SectionId) { return true; } if (m_Test == Test) { return false; } m_Test = Test; if (m_ContinueSection && m_ContinueSection->SectionAccessible(SectionId, Test)) { return true; } return m_JumpSection && m_JumpSection->SectionAccessible(SectionId, Test); } void CCodeSection::UnlinkParent(CCodeSection * Parent, bool ContinueSection) { CPU_Message("%s: Section %d Parent: %d ContinueSection = %s", __FUNCTION__, m_SectionID, Parent->m_SectionID, ContinueSection ? "Yes" : "No"); if (Parent->m_ContinueSection == this && Parent->m_JumpSection == this) { g_Notify->BreakPoint(__FILE__, __LINE__); } SECTION_LIST::iterator iter = m_ParentSection.begin(); while (iter != m_ParentSection.end()) { CCodeSection * ParentIter = *iter; if (ParentIter == Parent && (Parent->m_ContinueSection != this || Parent->m_JumpSection != this)) { m_ParentSection.erase(iter); iter = m_ParentSection.begin(); } else { iter++; } } if (ContinueSection && Parent->m_ContinueSection == this) { Parent->m_ContinueSection = NULL; } if (!ContinueSection && Parent->m_JumpSection == this) { Parent->m_JumpSection = NULL; } bool bRemove = false; if (m_ParentSection.size() > 0) { if (!m_BlockInfo->SectionAccessible(m_SectionID)) { for (SECTION_LIST::iterator iter = m_ParentSection.begin(); iter != m_ParentSection.end(); iter++) { CCodeSection * ParentIter = *iter; if (ParentIter->m_ContinueSection == this) { if (ParentIter->m_CompiledLocation) { g_Notify->BreakPoint(__FILE__, __LINE__); } ParentIter->m_ContinueSection = NULL; } if (ParentIter->m_JumpSection == this) { if (ParentIter->m_CompiledLocation) { g_Notify->BreakPoint(__FILE__, __LINE__); } ParentIter->m_JumpSection = NULL; } } bRemove = true; } } else { bRemove = true; } if (bRemove) { if (m_JumpSection != NULL) { m_JumpSection->UnlinkParent(this, false); } if (m_ContinueSection != NULL) { m_ContinueSection->UnlinkParent(this, true); } } } bool CCodeSection::IsAllParentLoops(CCodeSection * Parent, bool IgnoreIfCompiled, uint32_t Test) { if (IgnoreIfCompiled && Parent->m_CompiledLocation != NULL) { return true; } if (!m_InLoop) { return false; } if (!Parent->m_InLoop) { return false; } if (Parent->m_ParentSection.empty()) { return false; } if (this == Parent) { return true; } if (Parent->m_Test == Test) { return true; } Parent->m_Test = Test; for (SECTION_LIST::iterator iter = Parent->m_ParentSection.begin(); iter != Parent->m_ParentSection.end(); iter++) { CCodeSection * ParentSection = *iter; if (!IsAllParentLoops(ParentSection, IgnoreIfCompiled, Test)) { return false; } } return true; } bool CCodeSection::DisplaySectionInformation(uint32_t ID, uint32_t Test) { if (!CDebugSettings::bRecordRecompilerAsm()) { return false; } if (m_Test == Test) { return false; } m_Test = Test; if (m_SectionID != ID) { if (m_ContinueSection != NULL && m_ContinueSection->DisplaySectionInformation(ID, Test)) { return true; } if (m_JumpSection != NULL && m_JumpSection->DisplaySectionInformation(ID, Test)) { return true; } return false; } DisplaySectionInformation(); return true; } void CCodeSection::DisplaySectionInformation() { if (m_SectionID == 0) { return; } CPU_Message("====== Section %d ======", m_SectionID); CPU_Message("Start PC: 0x%X", m_EnterPC); if (g_System->bLinkBlocks()) { CPU_Message("End PC: 0x%X", m_EndPC); } CPU_Message("CompiledLocation: 0x%X", m_CompiledLocation); if (g_System->bLinkBlocks() && !m_ParentSection.empty()) { stdstr ParentList; for (SECTION_LIST::iterator iter = m_ParentSection.begin(); iter != m_ParentSection.end(); iter++) { CCodeSection * Parent = *iter; if (!ParentList.empty()) { ParentList += ", "; } ParentList += stdstr_f("%d", Parent->m_SectionID); } CPU_Message("Number of parents: %d (%s)", m_ParentSection.size(), ParentList.c_str()); } if (g_System->bLinkBlocks()) { CPU_Message("Jump Address: 0x%08X", m_Jump.JumpPC); CPU_Message("Jump Target Address: 0x%08X", m_Jump.TargetPC); if (m_JumpSection != NULL) { CPU_Message("Jump Section: %d", m_JumpSection->m_SectionID); } else { CPU_Message("Jump Section: None"); } CPU_Message("Continue Address: 0x%08X", m_Cont.JumpPC); CPU_Message("Continue Target Address: 0x%08X", m_Cont.TargetPC); if (m_ContinueSection != NULL) { CPU_Message("Continue Section: %d", m_ContinueSection->m_SectionID); } else { CPU_Message("Continue Section: None"); } CPU_Message("In Loop: %s", m_InLoop ? "Yes" : "No"); } CPU_Message("======================="); }