bool CCodeBlock::Compile() { CPU_Message("====== Code Block ======"); CPU_Message("Native entry point: %X", CompiledLocation()); CPU_Message("Start of Block: %X", VAddrEnter()); CPU_Message("No of Sections: %d", NoOfSections()); CPU_Message("====== recompiled code ======"); m_RecompilerOps->EnterCodeBlock(); if (g_System->bLinkBlocks()) { while (m_EnterSection->GenerateNativeCode(NextTest())); } else { if (!m_EnterSection->GenerateNativeCode(NextTest())) { return false; } } m_RecompilerOps->CompileExitCode(); uint32_t PAddr; g_TransVaddr->TranslateVaddr(VAddrFirst(), PAddr); MD5(g_MMU->Rdram() + PAddr, (VAddrLast() - VAddrFirst()) + 4).get_digest(m_Hash); #if defined(ANDROID) && (defined(__arm__) || defined(_M_ARM)) __clear_cache_android((uint8_t *)((uint32_t)m_CompiledLocation & ~1), (uint8_t *)(*g_RecompPos)); #endif return true; }
void CCodeBlock::CompileExitCode() { for (EXIT_LIST::iterator ExitIter = m_ExitInfo.begin(); ExitIter != m_ExitInfo.end(); ExitIter++) { CPU_Message(""); CPU_Message(" $Exit_%d",ExitIter->ID); SetJump32(ExitIter->JumpLoc,(uint32_t *)m_RecompPos); m_NextInstruction = ExitIter->NextInstruction; m_EnterSection->CompileExit((uint32_t)-1, ExitIter->TargetPC,ExitIter->ExitRegSet,ExitIter->reason,true,NULL); } }
void MmxUnpackHighWord(int Dest, int Source) { BYTE x86Command = 0; CPU_Message(" punpckhwd %s, %s", mmx_Name(Dest), mmx_Name(Source)); switch (Dest) { case x86_MM0: x86Command = 0 << 3; break; case x86_MM1: x86Command = 1 << 3; break; case x86_MM2: x86Command = 2 << 3; break; case x86_MM3: x86Command = 3 << 3; break; case x86_MM4: x86Command = 4 << 3; break; case x86_MM5: x86Command = 5 << 3; break; case x86_MM6: x86Command = 6 << 3; break; case x86_MM7: x86Command = 7 << 3; break; } switch (Source) { case x86_MM0: x86Command |= 0; break; case x86_MM1: x86Command |= 1; break; case x86_MM2: x86Command |= 2; break; case x86_MM3: x86Command |= 3; break; case x86_MM4: x86Command |= 4; break; case x86_MM5: x86Command |= 5; break; case x86_MM6: x86Command |= 6; break; case x86_MM7: x86Command |= 7; break; } PUTDST16(RecompPos,0x690f); PUTDST8(RecompPos, 0xC0 | x86Command); }
void MmxCompareGreaterWordRegToReg(int Dest, int Source) { BYTE x86Command = 0; CPU_Message(" pcmpgtw %s, %s", mmx_Name(Dest), mmx_Name(Source)); switch (Dest) { case x86_MM0: x86Command = 0 << 3; break; case x86_MM1: x86Command = 1 << 3; break; case x86_MM2: x86Command = 2 << 3; break; case x86_MM3: x86Command = 3 << 3; break; case x86_MM4: x86Command = 4 << 3; break; case x86_MM5: x86Command = 5 << 3; break; case x86_MM6: x86Command = 6 << 3; break; case x86_MM7: x86Command = 7 << 3; break; } switch (Source) { case x86_MM0: x86Command |= 0; break; case x86_MM1: x86Command |= 1; break; case x86_MM2: x86Command |= 2; break; case x86_MM3: x86Command |= 3; break; case x86_MM4: x86Command |= 4; break; case x86_MM5: x86Command |= 5; break; case x86_MM6: x86Command |= 6; break; case x86_MM7: x86Command |= 7; break; } PUTDST16(RecompPos,0x650f); PUTDST8(RecompPos, 0xC0 | x86Command); }
void SseXorRegToReg(int Dest, int Source) { BYTE x86Command = 0; CPU_Message(" xorps %s, %s", sse_Name(Dest), sse_Name(Source)); switch (Dest) { case x86_XMM0: x86Command = 0x00; break; case x86_XMM1: x86Command = 0x08; break; case x86_XMM2: x86Command = 0x10; break; case x86_XMM3: x86Command = 0x18; break; case x86_XMM4: x86Command = 0x20; break; case x86_XMM5: x86Command = 0x28; break; case x86_XMM6: x86Command = 0x30; break; case x86_XMM7: x86Command = 0x38; break; } switch (Source) { case x86_XMM0: x86Command += 0x00; break; case x86_XMM1: x86Command += 0x01; break; case x86_XMM2: x86Command += 0x02; break; case x86_XMM3: x86Command += 0x03; break; case x86_XMM4: x86Command += 0x04; break; case x86_XMM5: x86Command += 0x05; break; case x86_XMM6: x86Command += 0x06; break; case x86_XMM7: x86Command += 0x07; break; } PUTDST16(RecompPos,0x570f); PUTDST8(RecompPos, 0xC0 | x86Command); }
void SseShuffleReg(int Dest, int Source, BYTE Immed) { BYTE x86Command = 0; CPU_Message(" shufps %s, %s, %02X", sse_Name(Dest), sse_Name(Source), Immed); switch (Dest) { case x86_XMM0: x86Command = 0x00; break; case x86_XMM1: x86Command = 0x08; break; case x86_XMM2: x86Command = 0x10; break; case x86_XMM3: x86Command = 0x18; break; case x86_XMM4: x86Command = 0x20; break; case x86_XMM5: x86Command = 0x28; break; case x86_XMM6: x86Command = 0x30; break; case x86_XMM7: x86Command = 0x38; break; } switch (Source) { case x86_XMM0: x86Command += 0x00; break; case x86_XMM1: x86Command += 0x01; break; case x86_XMM2: x86Command += 0x02; break; case x86_XMM3: x86Command += 0x03; break; case x86_XMM4: x86Command += 0x04; break; case x86_XMM5: x86Command += 0x05; break; case x86_XMM6: x86Command += 0x06; break; case x86_XMM7: x86Command += 0x07; break; } PUTDST16(RecompPos,0xC60f); PUTDST8(RecompPos, 0xC0 | x86Command); PUTDST8(RecompPos, Immed); }
void SseMoveAlignedN64MemToReg(int sseReg, int AddrReg) { BYTE x86Command = 0; CPU_Message(" movaps %s, xmmword ptr [Dmem+%s]",sse_Name(sseReg), x86_Name(AddrReg)); switch (sseReg) { case x86_XMM0: x86Command = 0x80; break; case x86_XMM1: x86Command = 0x88; break; case x86_XMM2: x86Command = 0x90; break; case x86_XMM3: x86Command = 0x98; break; case x86_XMM4: x86Command = 0xA0; break; case x86_XMM5: x86Command = 0xA8; break; case x86_XMM6: x86Command = 0xB0; break; case x86_XMM7: x86Command = 0xB8; break; } switch (AddrReg) { case x86_EAX: x86Command += 0x00; break; case x86_EBX: x86Command += 0x03; break; case x86_ECX: x86Command += 0x01; break; case x86_EDX: x86Command += 0x02; break; case x86_ESI: x86Command += 0x06; break; case x86_EDI: x86Command += 0x07; break; case x86_ESP: x86Command += 0x04; break; case x86_EBP: x86Command += 0x05; break; } PUTDST16(RecompPos,0x280f); PUTDST8(RecompPos, x86Command); PUTDSTPTR(RecompPos, RSPInfo.DMEM); }
bool CCodeBlock::Compile() { CPU_Message("====== Code Block ======"); CPU_Message("x86 code at: %X",CompiledLocation()); CPU_Message("Start of Block: %X",VAddrEnter() ); CPU_Message("No of Sections: %d",NoOfSections() ); CPU_Message("====== recompiled code ======"); EnterCodeBlock(); if (g_SyncSystem) { //if ((uint32_t)BlockInfo.CompiledLocation == 0x60A7B73B) //{ // X86BreakPoint(__FILEW__,__LINE__); //} //MoveConstToVariable((uint32_t)BlockInfo.CompiledLocation,&CurrentBlock,"CurrentBlock"); } if (g_System->bLinkBlocks()) { while (m_EnterSection->GenerateX86Code(NextTest())); } else { if (!m_EnterSection->GenerateX86Code(NextTest())) { return false; } } CompileExitCode(); uint32_t PAddr; g_TransVaddr->TranslateVaddr(VAddrFirst(),PAddr); MD5(g_MMU->Rdram() + PAddr,(VAddrLast() - VAddrFirst()) + 4).get_digest(m_Hash); return true; }
void MmxPmulhwRegToVariable(int Dest, void * Variable, char * VariableName) { BYTE x86Command = 0; CPU_Message(" pmulhw %s, [%s]", mmx_Name(Dest), VariableName); switch (Dest) { case x86_MM0: x86Command = 0x05; break; case x86_MM1: x86Command = 0x0D; break; case x86_MM2: x86Command = 0x15; break; case x86_MM3: x86Command = 0x1D; break; case x86_MM4: x86Command = 0x25; break; case x86_MM5: x86Command = 0x2D; break; case x86_MM6: x86Command = 0x35; break; case x86_MM7: x86Command = 0x3D; break; } PUTDST16(RecompPos,0xe50f); PUTDST8(RecompPos, x86Command); PUTDSTPTR(RecompPos, Variable); }
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); }
void MmxPsllwImmed(int Dest, BYTE Immed) { BYTE x86Command = 0; CPU_Message(" psllw %s, %i", mmx_Name(Dest), Immed); switch (Dest) { case x86_MM0: x86Command = 0xF0; break; case x86_MM1: x86Command = 0xF1; break; case x86_MM2: x86Command = 0xF2; break; case x86_MM3: x86Command = 0xF3; break; case x86_MM4: x86Command = 0xF4; break; case x86_MM5: x86Command = 0xF5; break; case x86_MM6: x86Command = 0xF6; break; case x86_MM7: x86Command = 0xF7; break; } PUTDST16(RecompPos,0x710f); PUTDST8(RecompPos, x86Command); PUTDST8(RecompPos, Immed); }
void MmxPsrawImmed(int Dest, BYTE Immed) { BYTE x86Command = 0; CPU_Message(" psraw %s, %i", mmx_Name(Dest), Immed); switch (Dest) { case x86_MM0: x86Command = 0xE0; break; case x86_MM1: x86Command = 0xE1; break; case x86_MM2: x86Command = 0xE2; break; case x86_MM3: x86Command = 0xE3; break; case x86_MM4: x86Command = 0xE4; break; case x86_MM5: x86Command = 0xE5; break; case x86_MM6: x86Command = 0xE6; break; case x86_MM7: x86Command = 0xE7; break; } PUTDST16(RecompPos,0x710f); PUTDST8(RecompPos, x86Command); PUTDST8(RecompPos, Immed); }
void MmxMoveQwordVariableToReg(int Dest, void *Variable, char *VariableName) { BYTE x86Command = 0; CPU_Message(" movq %s, qword ptr [%s]",mmx_Name(Dest), VariableName); switch (Dest) { case x86_MM0: x86Command = 0x05; break; case x86_MM1: x86Command = 0x0D; break; case x86_MM2: x86Command = 0x15; break; case x86_MM3: x86Command = 0x1D; break; case x86_MM4: x86Command = 0x25; break; case x86_MM5: x86Command = 0x2D; break; case x86_MM6: x86Command = 0x35; break; case x86_MM7: x86Command = 0x3D; break; } PUTDST16(RecompPos,0x6f0f); PUTDST8(RecompPos, x86Command); PUTDSTPTR(RecompPos, Variable); }
void SseMoveAlignedRegToVariable(int sseReg, void *Variable, char *VariableName) { BYTE x86Command = 0; CPU_Message(" movaps xmmword ptr [%s], %s",VariableName, sse_Name(sseReg)); switch (sseReg) { case x86_XMM0: x86Command = 0x05; break; case x86_XMM1: x86Command = 0x0D; break; case x86_XMM2: x86Command = 0x15; break; case x86_XMM3: x86Command = 0x1D; break; case x86_XMM4: x86Command = 0x25; break; case x86_XMM5: x86Command = 0x2D; break; case x86_XMM6: x86Command = 0x35; break; case x86_XMM7: x86Command = 0x3D; break; } PUTDST16(RecompPos,0x290f); PUTDST8(RecompPos, x86Command); PUTDSTPTR(RecompPos, Variable); }
void SseMoveUnalignedVariableToReg(void *Variable, char *VariableName, int sseReg) { BYTE x86Command = 0; CPU_Message(" movups %s, xmmword ptr [%s]",sse_Name(sseReg), VariableName); switch (sseReg) { case x86_XMM0: x86Command = 0x05; break; case x86_XMM1: x86Command = 0x0D; break; case x86_XMM2: x86Command = 0x15; break; case x86_XMM3: x86Command = 0x1D; break; case x86_XMM4: x86Command = 0x25; break; case x86_XMM5: x86Command = 0x2D; break; case x86_XMM6: x86Command = 0x35; break; case x86_XMM7: x86Command = 0x3D; break; } PUTDST16(RecompPos,0x100f); PUTDST8(RecompPos, x86Command); PUTDSTPTR(RecompPos, Variable); }
void MmxShuffleMemoryToReg(int Dest, void * Variable, char * VariableName, BYTE Immed) { BYTE x86Command = 0; CPU_Message(" pshufw %s, [%s], %02X", mmx_Name(Dest), VariableName, Immed); switch (Dest) { case x86_MM0: x86Command = 0x05; break; case x86_MM1: x86Command = 0x0D; break; case x86_MM2: x86Command = 0x15; break; case x86_MM3: x86Command = 0x1D; break; case x86_MM4: x86Command = 0x25; break; case x86_MM5: x86Command = 0x2D; break; case x86_MM6: x86Command = 0x35; break; case x86_MM7: x86Command = 0x3D; break; } PUTDST16(RecompPos,0x700f); PUTDST8(RecompPos, x86Command); PUTDSTPTR(RecompPos, Variable); PUTDST8(RecompPos, Immed); }
bool CCodeBlock::SetSection(CCodeSection * & Section, CCodeSection * CurrentSection, uint32_t TargetPC, bool LinkAllowed, uint32_t CurrentPC) { if (Section != NULL) { g_Notify->BreakPoint(__FILE__, __LINE__); } if (TargetPC >= ((CurrentPC + 0x1000) & 0xFFFFF000)) { return false; } if (TargetPC < m_EnterSection->m_EnterPC) { return false; } if (LinkAllowed) { if (Section != NULL) { g_Notify->BreakPoint(__FILE__, __LINE__); } SectionMap::const_iterator itr = m_SectionMap.find(TargetPC); if (itr != m_SectionMap.end()) { Section = itr->second; Section->AddParent(CurrentSection); } } if (Section == NULL) { Section = new CCodeSection(this, TargetPC, m_Sections.size(), LinkAllowed); if (Section == NULL) { g_Notify->BreakPoint(__FILE__, __LINE__); return false; } m_Sections.push_back(Section); if (LinkAllowed) { m_SectionMap.insert(SectionMap::value_type(TargetPC, Section)); } Section->AddParent(CurrentSection); if (TargetPC <= CurrentPC && TargetPC != m_VAddrEnter) { CCodeSection * SplitSection = NULL; for (SectionMap::const_iterator itr = m_SectionMap.begin(); itr != m_SectionMap.end(); itr++) { if (itr->first >= TargetPC) { break; } SplitSection = itr->second; } if (SplitSection == NULL) { g_Notify->BreakPoint(__FILE__, __LINE__); } if (SplitSection->m_EndPC == (uint32_t)-1) { g_Notify->BreakPoint(__FILE__, __LINE__); } if (SplitSection->m_EndPC >= TargetPC) { CPU_Message("%s: Split Section: %d with section: %d", __FUNCTION__, SplitSection->m_SectionID, Section->m_SectionID); CCodeSection * BaseSection = Section; BaseSection->m_EndPC = SplitSection->m_EndPC; BaseSection->SetJumpAddress(SplitSection->m_Jump.JumpPC, SplitSection->m_Jump.TargetPC, SplitSection->m_Jump.PermLoop); BaseSection->m_JumpSection = SplitSection->m_JumpSection; BaseSection->SetContinueAddress(SplitSection->m_Cont.JumpPC, SplitSection->m_Cont.TargetPC); BaseSection->m_ContinueSection = SplitSection->m_ContinueSection; BaseSection->m_JumpSection->SwitchParent(SplitSection, BaseSection); BaseSection->m_ContinueSection->SwitchParent(SplitSection, BaseSection); BaseSection->AddParent(SplitSection); SplitSection->m_EndPC = TargetPC - 4; SplitSection->m_JumpSection = NULL; SplitSection->m_ContinueSection = BaseSection; SplitSection->SetContinueAddress(TargetPC - 4, TargetPC); SplitSection->SetJumpAddress((uint32_t)-1, (uint32_t)-1, false); } } } return true; }
void CCodeSection::UnlinkParent(CCodeSection * Parent, bool ContinueSection) { if (this == NULL) { return; } 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); } } }
void MmxEmptyMultimediaState(void) { CPU_Message(" emms"); PUTDST16(RecompPos,0x770f); }
BOOL WriteToVectorDest2 (DWORD DestReg, int PC, BOOL RecursiveCall) { OPCODE RspOp; DWORD BranchTarget = 0; signed int BranchImmed = 0; DWORD JumpTarget = 0; BOOL JumpUncond = FALSE; int Instruction_State = NextInstruction; if (Compiler.bDest == FALSE) return TRUE; if (Instruction_State == DELAY_SLOT) { return TRUE; } do { PC += 4; if (PC >= 0x1000) { return TRUE; } RSP_LW_IMEM(PC, &RspOp.Hex); switch (RspOp.op) { case RSP_REGIMM: switch (RspOp.rt) { case RSP_REGIMM_BLTZ: case RSP_REGIMM_BGEZ: case RSP_REGIMM_BLTZAL: case RSP_REGIMM_BGEZAL: Instruction_State = DO_DELAY_SLOT; break; default: CompilerWarning("Unkown opcode in WriteToVectorDest\n%s",RSPOpcodeName(RspOp.Hex,PC)); return TRUE; } break; case RSP_SPECIAL: switch (RspOp.funct) { case RSP_SPECIAL_SLL: case RSP_SPECIAL_SRL: case RSP_SPECIAL_SRA: case RSP_SPECIAL_SLLV: case RSP_SPECIAL_SRLV: case RSP_SPECIAL_SRAV: case RSP_SPECIAL_ADD: case RSP_SPECIAL_ADDU: case RSP_SPECIAL_SUB: case RSP_SPECIAL_SUBU: case RSP_SPECIAL_AND: case RSP_SPECIAL_OR: case RSP_SPECIAL_XOR: case RSP_SPECIAL_NOR: case RSP_SPECIAL_SLT: case RSP_SPECIAL_SLTU: case RSP_SPECIAL_BREAK: break; case RSP_SPECIAL_JR: Instruction_State = DO_DELAY_SLOT; break; default: CompilerWarning("Unkown opcode in WriteToVectorDest\n%s",RSPOpcodeName(RspOp.Hex,PC)); return TRUE; } break; case RSP_J: case RSP_JAL: if (!JumpTarget) { JumpUncond = TRUE; JumpTarget = (RspOp.target << 2) & 0xFFC; } Instruction_State = DO_DELAY_SLOT; break; case RSP_BEQ: case RSP_BNE: case RSP_BLEZ: case RSP_BGTZ: Instruction_State = DO_DELAY_SLOT; BranchTarget = (PC + ((short)RspOp.offset << 2) + 4) & 0xFFC; BranchImmed = (short)RspOp.offset; break; case RSP_ADDI: case RSP_ADDIU: case RSP_SLTI: case RSP_SLTIU: case RSP_ANDI: case RSP_ORI: case RSP_XORI: case RSP_LUI: case RSP_CP0: break; case RSP_CP2: if ((RspOp.rs & 0x10) != 0) { switch (RspOp.funct) { case RSP_VECTOR_VMULF: case RSP_VECTOR_VMUDL: case RSP_VECTOR_VMUDM: case RSP_VECTOR_VMUDN: case RSP_VECTOR_VMUDH: case RSP_VECTOR_VMACF: case RSP_VECTOR_VMADL: case RSP_VECTOR_VMADM: case RSP_VECTOR_VMADN: case RSP_VECTOR_VMADH: case RSP_VECTOR_VADD: case RSP_VECTOR_VADDC: case RSP_VECTOR_VSUB: case RSP_VECTOR_VSUBC: case RSP_VECTOR_VAND: case RSP_VECTOR_VOR: case RSP_VECTOR_VXOR: case RSP_VECTOR_VNXOR: case RSP_VECTOR_VABS: if (DestReg == RspOp.rd) { return TRUE; } if (DestReg == RspOp.rt) { return TRUE; } if (DestReg == RspOp.sa) { return FALSE; } break; case RSP_VECTOR_VMOV: if (DestReg == RspOp.rt) { return TRUE; } break; case RSP_VECTOR_VCR: case RSP_VECTOR_VRCP: case RSP_VECTOR_VRCPH: case RSP_VECTOR_VRSQH: case RSP_VECTOR_VCH: case RSP_VECTOR_VCL: return TRUE; case RSP_VECTOR_VMRG: case RSP_VECTOR_VLT: case RSP_VECTOR_VEQ: case RSP_VECTOR_VGE: if (DestReg == RspOp.rd) { return TRUE; } if (DestReg == RspOp.rt) { return TRUE; } if (DestReg == RspOp.sa) { return FALSE; } break; case RSP_VECTOR_VSAW: if (DestReg == RspOp.sa) { return FALSE; } break; default: CompilerWarning("Unkown opcode in WriteToVectorDest\n%s",RSPOpcodeName(RspOp.Hex,PC)); return TRUE; } } else { switch (RspOp.rs) { case RSP_COP2_CF: case RSP_COP2_CT: break; case RSP_COP2_MT: /* if (DestReg == RspOp.rd) { return FALSE; } */ break; case RSP_COP2_MF: if (DestReg == RspOp.rd) { return TRUE; } break; default: CompilerWarning("Unkown opcode in WriteToVectorDest\n%s",RSPOpcodeName(RspOp.Hex,PC)); return TRUE; } } break; case RSP_LB: case RSP_LH: case RSP_LW: case RSP_LBU: case RSP_LHU: case RSP_SB: case RSP_SH: case RSP_SW: break; case RSP_LC2: switch (RspOp.rd) { case RSP_LSC2_SV: case RSP_LSC2_DV: case RSP_LSC2_RV: break; case RSP_LSC2_QV: case RSP_LSC2_LV: case RSP_LSC2_UV: case RSP_LSC2_PV: case RSP_LSC2_TV: break; default: CompilerWarning("Unkown opcode in WriteToVectorDest\n%s",RSPOpcodeName(RspOp.Hex,PC)); return TRUE; } break; case RSP_SC2: switch (RspOp.rd) { case RSP_LSC2_BV: case RSP_LSC2_SV: case RSP_LSC2_LV: case RSP_LSC2_DV: case RSP_LSC2_QV: case RSP_LSC2_RV: case RSP_LSC2_PV: case RSP_LSC2_UV: case RSP_LSC2_HV: case RSP_LSC2_FV: case RSP_LSC2_WV: case RSP_LSC2_TV: if (DestReg == RspOp.rt) { return TRUE; } break; default: CompilerWarning("Unkown opcode in WriteToVectorDest\n%s",RSPOpcodeName(RspOp.Hex,PC)); return TRUE; } break; default: CompilerWarning("Unkown opcode in WriteToVectorDest\n%s",RSPOpcodeName(RspOp.Hex,PC)); return TRUE; } switch (Instruction_State) { case NORMAL: break; case DO_DELAY_SLOT: Instruction_State = DELAY_SLOT; break; case DELAY_SLOT: if (JumpUncond) { PC = JumpTarget - 0x04; Instruction_State = NORMAL; } else { Instruction_State = FINISH_BLOCK; } JumpUncond = FALSE; break; } } while (Instruction_State != FINISH_BLOCK); /*** ** This is a tricky situation because most of the ** microcode does loops, so looping back and checking ** can prove effective, but it's still a branch.. ***/ if (BranchTarget != 0 && RecursiveCall == FALSE) { DWORD BranchTaken, BranchFall; /* analysis of branch taken */ BranchTaken = WriteToVectorDest2(DestReg, BranchTarget - 4, TRUE); /* analysis of branch as nop */ BranchFall = WriteToVectorDest2(DestReg, PC, TRUE); if (BranchImmed < 0) { if (BranchTaken != FALSE) { /* ** took this back branch and found a place ** that needs this vector as a source **/ return TRUE; } else if (BranchFall == HIT_BRANCH) { /* (dlist) risky? the loop ended, hit another branch after loop-back */ #if !defined(RSP_SAFE_ANALYSIS) CPU_Message("WriteToDest: Backward branch hit, BranchFall = Hit branch (returning FALSE)"); return FALSE; #endif return TRUE; } else { /* otherwise this is completely valid */ return BranchFall; } } else { if (BranchFall != FALSE) { /* ** took this forward branch and found a place ** that needs this vector as a source **/ return TRUE; } else if (BranchTaken == HIT_BRANCH) { /* (dlist) risky? jumped forward, hit another branch */ #if !defined(RSP_SAFE_ANALYSIS) CPU_Message("WriteToDest: Forward branch hit, BranchTaken = Hit branch (returning FALSE)"); return FALSE; #endif return TRUE; } else { /* otherwise this is completely valid */ return BranchTaken; } } } else { return HIT_BRANCH; } }
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]->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(JumpInfo[i]->RegSet, true, true); if (JumpInfo[i]->PermLoop) { CPU_Message("PermLoop *** 3"); m_RecompilerOps->CompileInPermLoop(JumpInfo[i]->RegSet, JumpInfo[i]->TargetPC); } else { CPU_Message("CompileSystemCheck 9"); m_RecompilerOps->CompileSystemCheck(JumpInfo[i]->TargetPC, JumpInfo[i]->RegSet); } } else { m_RecompilerOps->UpdateCounters(m_RecompilerOps->GetRegWorkingSet(), false, true); } m_RecompilerOps->SetRegWorkingSet(JumpInfo[i]->RegSet); m_RecompilerOps->SyncRegState(TargetSection[i]->m_RegEnter); m_RecompilerOps->JumpToSection(TargetSection[i]); } } }
bool CCodeBlock::CreateBlockLinkage(CCodeSection * EnterSection) { CCodeSection * CurrentSection = EnterSection; CPU_Message("Section %d", CurrentSection->m_SectionID); for (uint32_t TestPC = EnterSection->m_EnterPC, EndPC = ((EnterSection->m_EnterPC + 0x1000) & 0xFFFFF000); TestPC <= EndPC; TestPC += 4) { if (TestPC != EndPC) { SectionMap::const_iterator itr = m_SectionMap.find(TestPC); if (itr != m_SectionMap.end() && CurrentSection != itr->second) { if (CurrentSection->m_ContinueSection != NULL && CurrentSection->m_ContinueSection != itr->second) { g_Notify->BreakPoint(__FILE__, __LINE__); } if (CurrentSection->m_ContinueSection == NULL) { SetSection(CurrentSection->m_ContinueSection, CurrentSection, TestPC, true, TestPC); CurrentSection->SetContinueAddress(TestPC - 4, TestPC); } CurrentSection->m_EndPC = TestPC - 4; CurrentSection = itr->second; CPU_Message("Section %d", CurrentSection->m_SectionID); if (EnterSection != m_EnterSection) { if (CurrentSection->m_JumpSection != NULL || CurrentSection->m_ContinueSection != NULL || CurrentSection->m_EndSection) { break; } } } } else { CurrentSection->m_EndSection = true; break; } bool LikelyBranch, EndBlock, IncludeDelaySlot, PermLoop; uint32_t TargetPC, ContinuePC; CurrentSection->m_EndPC = TestPC; if (!AnalyzeInstruction(TestPC, TargetPC, ContinuePC, LikelyBranch, IncludeDelaySlot, EndBlock, PermLoop)) { g_Notify->BreakPoint(__FILE__, __LINE__); return false; } if (TestPC + 4 == EndPC && IncludeDelaySlot) { TargetPC = (uint32_t)-1; ContinuePC = (uint32_t)-1; EndBlock = true; } if (TargetPC == (uint32_t)-1 && !EndBlock) { if (ContinuePC != (uint32_t)-1) { g_Notify->BreakPoint(__FILE__, __LINE__); } continue; } if (EndBlock) { CPU_Message("%s: End Block", __FUNCTION__); CurrentSection->m_EndSection = true; // find other sections that need compiling break; } if (ContinuePC != (uint32_t)-1) { CPU_Message("%s: SetContinueAddress TestPC = %X ContinuePC = %X", __FUNCTION__, TestPC, ContinuePC); CurrentSection->SetContinueAddress(TestPC, ContinuePC); if (!SetSection(CurrentSection->m_ContinueSection, CurrentSection, ContinuePC, true, TestPC)) { ContinuePC = (uint32_t)-1; } } if (LikelyBranch) { CPU_Message("%s: SetJumpAddress TestPC = %X Target = %X", __FUNCTION__, TestPC, TestPC + 4); CurrentSection->SetJumpAddress(TestPC, TestPC + 4, false); if (SetSection(CurrentSection->m_JumpSection, CurrentSection, TestPC + 4, false, TestPC)) { bool BranchLikelyBranch, BranchEndBlock, BranchIncludeDelaySlot, BranchPermLoop; uint32_t BranchTargetPC, BranchContinuePC; CCodeSection * JumpSection = CurrentSection->m_JumpSection; if (!AnalyzeInstruction(JumpSection->m_EnterPC, BranchTargetPC, BranchContinuePC, BranchLikelyBranch, BranchIncludeDelaySlot, BranchEndBlock, BranchPermLoop)) { g_Notify->BreakPoint(__FILE__, __LINE__); return false; } if (BranchLikelyBranch || BranchIncludeDelaySlot || BranchPermLoop) { g_Notify->BreakPoint(__FILE__, __LINE__); return false; } JumpSection->m_EndPC = TestPC + 4; if (BranchEndBlock) { CPU_Message("%s: Jump End Block", __FUNCTION__); JumpSection->m_EndSection = true; TargetPC = (uint32_t)-1; } else { JumpSection->SetJumpAddress(TestPC, TargetPC, false); } JumpSection->SetDelaySlot(); SetSection(JumpSection->m_JumpSection, JumpSection, TargetPC, true, TestPC); } else { g_Notify->BreakPoint(__FILE__, __LINE__); } } else if (TargetPC != ((uint32_t)-1)) { CPU_Message("%s: SetJumpAddress TestPC = %X Target = %X", __FUNCTION__, TestPC, TargetPC); CurrentSection->SetJumpAddress(TestPC, TargetPC, PermLoop); if (PermLoop || !SetSection(CurrentSection->m_JumpSection, CurrentSection, TargetPC, true, TestPC)) { if (ContinuePC == (uint32_t)-1) { CurrentSection->m_EndSection = true; } } } TestPC += IncludeDelaySlot ? 8 : 4; //Find the next section CCodeSection * NewSection = NULL; for (SectionMap::const_iterator itr = m_SectionMap.begin(); itr != m_SectionMap.end(); itr++) { if (CurrentSection->m_JumpSection != NULL || CurrentSection->m_ContinueSection != NULL || CurrentSection->m_EndSection) { continue; } NewSection = itr->second; break; } if (NewSection == NULL) { break; } if (CurrentSection == NewSection) { g_Notify->BreakPoint(__FILE__, __LINE__); } CurrentSection = NewSection; if (CurrentSection->m_JumpSection != NULL || CurrentSection->m_ContinueSection != NULL || CurrentSection->m_EndSection) { break; } TestPC = CurrentSection->m_EnterPC; CPU_Message("a. Section %d", CurrentSection->m_SectionID); TestPC -= 4; } for (SectionMap::iterator itr = m_SectionMap.begin(); itr != m_SectionMap.end(); itr++) { CCodeSection * Section = itr->second; if (Section->m_JumpSection != NULL || Section->m_ContinueSection != NULL || Section->m_EndSection) { continue; } if (!CreateBlockLinkage(Section)) { return false; } break; } if (CurrentSection->m_EndPC == (uint32_t)-1) { g_Notify->BreakPoint(__FILE__, __LINE__); } return true; }
bool CCodeBlock::AnalyzeInstruction(uint32_t PC, uint32_t & TargetPC, uint32_t & ContinuePC, bool & LikelyBranch, bool & IncludeDelaySlot, bool & EndBlock, bool & PermLoop) { TargetPC = (uint32_t)-1; ContinuePC = (uint32_t)-1; LikelyBranch = false; IncludeDelaySlot = false; EndBlock = false; PermLoop = false; OPCODE Command; if (!g_MMU->LW_VAddr(PC, Command.Hex)) { g_Notify->BreakPoint(__FILE__, __LINE__); return false; } #ifdef _DEBUG const char * Name = R4300iOpcodeName(Command.Hex, PC); CPU_Message(" 0x%08X %s", PC, Name); #endif switch (Command.op) { case R4300i_SPECIAL: switch (Command.funct) { case R4300i_SPECIAL_SLL: case R4300i_SPECIAL_SRL: case R4300i_SPECIAL_SRA: case R4300i_SPECIAL_SLLV: case R4300i_SPECIAL_SRLV: case R4300i_SPECIAL_SRAV: case R4300i_SPECIAL_MFHI: case R4300i_SPECIAL_MTHI: case R4300i_SPECIAL_MFLO: case R4300i_SPECIAL_MTLO: case R4300i_SPECIAL_DSLLV: case R4300i_SPECIAL_DSRLV: case R4300i_SPECIAL_DSRAV: case R4300i_SPECIAL_ADD: case R4300i_SPECIAL_ADDU: case R4300i_SPECIAL_SUB: case R4300i_SPECIAL_SUBU: case R4300i_SPECIAL_AND: case R4300i_SPECIAL_OR: case R4300i_SPECIAL_XOR: case R4300i_SPECIAL_NOR: case R4300i_SPECIAL_SLT: case R4300i_SPECIAL_SLTU: case R4300i_SPECIAL_DADD: case R4300i_SPECIAL_DADDU: case R4300i_SPECIAL_DSUB: case R4300i_SPECIAL_DSUBU: case R4300i_SPECIAL_DSLL: case R4300i_SPECIAL_DSRL: case R4300i_SPECIAL_DSRA: case R4300i_SPECIAL_DSLL32: case R4300i_SPECIAL_DSRL32: case R4300i_SPECIAL_DSRA32: case R4300i_SPECIAL_MULT: case R4300i_SPECIAL_MULTU: case R4300i_SPECIAL_DIV: case R4300i_SPECIAL_DIVU: case R4300i_SPECIAL_DMULT: case R4300i_SPECIAL_DMULTU: case R4300i_SPECIAL_DDIV: case R4300i_SPECIAL_DDIVU: break; case R4300i_SPECIAL_JALR: case R4300i_SPECIAL_JR: EndBlock = true; IncludeDelaySlot = true; break; case R4300i_SPECIAL_SYSCALL: case R4300i_SPECIAL_BREAK: EndBlock = true; break; default: g_Notify->BreakPoint(__FILE__, __LINE__); return false; } break; case R4300i_REGIMM: switch (Command.rt) { case R4300i_REGIMM_BLTZ: case R4300i_REGIMM_BLTZAL: TargetPC = PC + ((int16_t)Command.offset << 2) + 4; if (TargetPC == PC + 8) { TargetPC = (uint32_t)-1; } else { if (TargetPC == PC && !DelaySlotEffectsCompare(PC, Command.rs, 0)) { PermLoop = true; } ContinuePC = PC + 8; IncludeDelaySlot = true; } break; case R4300i_REGIMM_BGEZ: case R4300i_REGIMM_BGEZAL: TargetPC = PC + ((int16_t)Command.offset << 2) + 4; if (TargetPC == PC + 8) { TargetPC = (uint32_t)-1; } else { if (TargetPC == PC) { if (Command.rs == 0) { TargetPC = (uint32_t)-1; EndBlock = true; } else { if (!DelaySlotEffectsCompare(PC, Command.rs, Command.rt)) { PermLoop = true; } } } if (Command.rs != 0) { ContinuePC = PC + 8; } IncludeDelaySlot = true; } break; case R4300i_REGIMM_BLTZL: case R4300i_REGIMM_BGEZL: TargetPC = PC + ((int16_t)Command.offset << 2) + 4; if (TargetPC == PC) { if (!DelaySlotEffectsCompare(PC, Command.rs, 0)) { PermLoop = true; } } ContinuePC = PC + 8; LikelyBranch = true; IncludeDelaySlot = true; break; default: if (Command.Hex == 0x0407000D) { EndBlock = true; break; } g_Notify->BreakPoint(__FILE__, __LINE__); return false; } break; case R4300i_J: TargetPC = (PC & 0xF0000000) + (Command.target << 2); if (TargetPC == PC) { PermLoop = true; } IncludeDelaySlot = true; break; case R4300i_JAL: EndBlock = true; IncludeDelaySlot = true; break; case R4300i_BEQ: TargetPC = PC + ((int16_t)Command.offset << 2) + 4; if (TargetPC == PC + 8) { TargetPC = (uint32_t)-1; } else { if (Command.rs != 0 || Command.rt != 0) { ContinuePC = PC + 8; } if (TargetPC == PC && !DelaySlotEffectsCompare(PC, Command.rs, Command.rt)) { PermLoop = true; } IncludeDelaySlot = true; } break; case R4300i_BNE: case R4300i_BLEZ: case R4300i_BGTZ: TargetPC = PC + ((int16_t)Command.offset << 2) + 4; if (TargetPC == PC + 8) { TargetPC = (uint32_t)-1; } else { if (TargetPC == PC) { if (!DelaySlotEffectsCompare(PC, Command.rs, Command.rt)) { PermLoop = true; } } ContinuePC = PC + 8; IncludeDelaySlot = true; } break; case R4300i_CP0: switch (Command.rs) { case R4300i_COP0_MT: case R4300i_COP0_MF: break; default: if ((Command.rs & 0x10) != 0) { switch (Command.funct) { case R4300i_COP0_CO_TLBR: case R4300i_COP0_CO_TLBWI: case R4300i_COP0_CO_TLBWR: case R4300i_COP0_CO_TLBP: break; case R4300i_COP0_CO_ERET: EndBlock = true; break; default: g_Notify->BreakPoint(__FILE__, __LINE__); return false; } } else { g_Notify->BreakPoint(__FILE__, __LINE__); return false; } break; } break; case R4300i_CP1: switch (Command.fmt) { case R4300i_COP1_MF: case R4300i_COP1_DMF: case R4300i_COP1_CF: case R4300i_COP1_MT: case R4300i_COP1_DMT: case R4300i_COP1_CT: case R4300i_COP1_S: case R4300i_COP1_D: case R4300i_COP1_W: case R4300i_COP1_L: break; case R4300i_COP1_BC: switch (Command.ft) { case R4300i_COP1_BC_BCF: case R4300i_COP1_BC_BCT: TargetPC = PC + ((int16_t)Command.offset << 2) + 4; if (TargetPC == PC + 8) { TargetPC = (uint32_t)-1; } else { if (TargetPC == PC) { g_Notify->BreakPoint(__FILE__, __LINE__); } ContinuePC = PC + 8; IncludeDelaySlot = true; } break; case R4300i_COP1_BC_BCFL: case R4300i_COP1_BC_BCTL: TargetPC = PC + ((int16_t)Command.offset << 2) + 4; if (TargetPC == PC) { g_Notify->BreakPoint(__FILE__, __LINE__); } ContinuePC = PC + 8; LikelyBranch = true; IncludeDelaySlot = true; break; default: g_Notify->BreakPoint(__FILE__, __LINE__); } break; default: g_Notify->BreakPoint(__FILE__, __LINE__); return false; } break; case R4300i_ANDI: case R4300i_ORI: case R4300i_XORI: case R4300i_LUI: case R4300i_ADDI: case R4300i_ADDIU: case R4300i_SLTI: case R4300i_SLTIU: case R4300i_DADDI: case R4300i_DADDIU: case R4300i_LDL: case R4300i_LDR: case R4300i_LB: case R4300i_LH: case R4300i_LWL: case R4300i_LW: case R4300i_LBU: case R4300i_LHU: case R4300i_LWR: case R4300i_LWU: case R4300i_SB: case R4300i_SH: case R4300i_SWL: case R4300i_SW: case R4300i_SDL: case R4300i_SDR: case R4300i_SWR: case R4300i_CACHE: case R4300i_LL: case R4300i_LWC1: case R4300i_LDC1: case R4300i_LD: case R4300i_SC: case R4300i_SWC1: case R4300i_SDC1: case R4300i_SD: break; case R4300i_BEQL: TargetPC = PC + ((int16_t)Command.offset << 2) + 4; if (TargetPC == PC) { if (!DelaySlotEffectsCompare(PC, Command.rs, Command.rt)) { PermLoop = true; } } if (Command.rs != 0 || Command.rt != 0) { ContinuePC = PC + 8; } IncludeDelaySlot = true; LikelyBranch = true; break; case R4300i_BNEL: case R4300i_BLEZL: case R4300i_BGTZL: TargetPC = PC + ((int16_t)Command.offset << 2) + 4; ContinuePC = PC + 8; if (TargetPC == PC) { if (!DelaySlotEffectsCompare(PC, Command.rs, Command.rt)) { PermLoop = true; } } LikelyBranch = true; IncludeDelaySlot = true; break; default: if (Command.Hex == 0x7C1C97C0 || Command.Hex == 0xF1F3F5F7) { EndBlock = true; break; } g_Notify->BreakPoint(__FILE__, __LINE__); return false; } return true; }
uint32_t WriteToAccum2(int32_t Location, int32_t PC, int32_t RecursiveCall) { RSPOPCODE RspOp; uint32_t BranchTarget = 0; int32_t BranchImmed = 0; uint32_t JumpTarget = 0; int32_t JumpUncond = 0; int32_t Instruction_State = RSPNextInstruction; if (Compiler.bAccum == 0) return 1; if (Instruction_State == DELAY_SLOT) { return 1; } do { PC += 4; if (PC >= 0x1000) { return 1; } RSP_LW_IMEM(PC, &RspOp.Hex); switch (RspOp.op) { case RSP_REGIMM: switch (RspOp.rt) { case RSP_REGIMM_BLTZ: case RSP_REGIMM_BGEZ: case RSP_REGIMM_BLTZAL: case RSP_REGIMM_BGEZAL: Instruction_State = DO_DELAY_SLOT; break; default: CompilerWarning("Unkown opcode in WriteToAccum\n%s", RSPOpcodeName(RspOp.Hex, PC)); return 1; } break; case RSP_SPECIAL: switch (RspOp.funct) { case RSP_SPECIAL_SLL: case RSP_SPECIAL_SRL: case RSP_SPECIAL_SRA: case RSP_SPECIAL_SLLV: case RSP_SPECIAL_SRLV: case RSP_SPECIAL_SRAV: case RSP_SPECIAL_ADD: case RSP_SPECIAL_ADDU: case RSP_SPECIAL_SUB: case RSP_SPECIAL_SUBU: case RSP_SPECIAL_AND: case RSP_SPECIAL_OR: case RSP_SPECIAL_XOR: case RSP_SPECIAL_NOR: case RSP_SPECIAL_SLT: case RSP_SPECIAL_SLTU: case RSP_SPECIAL_BREAK: break; case RSP_SPECIAL_JR: Instruction_State = DO_DELAY_SLOT; break; default: CompilerWarning("Unkown opcode in WriteToAccum\n%s", RSPOpcodeName(RspOp.Hex, PC)); return 1; } break; case RSP_J: case RSP_JAL: if (!JumpTarget) { JumpUncond = 1; JumpTarget = (RspOp.target << 2) & 0xFFC; } Instruction_State = DO_DELAY_SLOT; break; case RSP_BEQ: case RSP_BNE: case RSP_BLEZ: case RSP_BGTZ: Instruction_State = DO_DELAY_SLOT; BranchTarget = (PC + ((int16_t) RspOp.offset << 2) + 4) & 0xFFC; BranchImmed = (int16_t) RspOp.offset; break; case RSP_ADDI: case RSP_ADDIU: case RSP_SLTI: case RSP_SLTIU: case RSP_ANDI: case RSP_ORI: case RSP_XORI: case RSP_LUI: case RSP_CP0: break; case RSP_CP2: if ((RspOp.rs & 0x10) != 0) { switch (RspOp.funct) { case RSP_VECTOR_VMULF: case RSP_VECTOR_VMUDL: case RSP_VECTOR_VMUDM: case RSP_VECTOR_VMUDN: case RSP_VECTOR_VMUDH: return 0; case RSP_VECTOR_VMACF: case RSP_VECTOR_VMADL: case RSP_VECTOR_VMADM: case RSP_VECTOR_VMADN: case RSP_VECTOR_VMADH: return 1; case RSP_VECTOR_VABS: // hope this is ok case RSP_VECTOR_VADD: case RSP_VECTOR_VADDC: case RSP_VECTOR_VSUB: case RSP_VECTOR_VSUBC: case RSP_VECTOR_VAND: case RSP_VECTOR_VOR: case RSP_VECTOR_VXOR: case RSP_VECTOR_VNXOR: case RSP_VECTOR_VCR: case RSP_VECTOR_VCH: case RSP_VECTOR_VCL: case RSP_VECTOR_VRCP: case RSP_VECTOR_VRCPL: // hope this is ok case RSP_VECTOR_VRCPH: case RSP_VECTOR_VRSQL: case RSP_VECTOR_VRSQH: // hope this is ok case RSP_VECTOR_VLT: case RSP_VECTOR_VEQ: case RSP_VECTOR_VGE: if (Location == Low16BitAccum) { return 0; } break; case RSP_VECTOR_VMOV: case RSP_VECTOR_VMRG: break; case RSP_VECTOR_VSAW: return 1; default: CompilerWarning ("Unkown opcode in WriteToVectorDest\n%s", RSPOpcodeName(RspOp.Hex, PC)); return 1; } } else { switch (RspOp.rs) { case RSP_COP2_CF: case RSP_COP2_CT: case RSP_COP2_MT: case RSP_COP2_MF: break; default: CompilerWarning ("Unkown opcode in WriteToVectorDest\n%s", RSPOpcodeName(RspOp.Hex, PC)); return 1; } } break; case RSP_LB: case RSP_LH: case RSP_LW: case RSP_LBU: case RSP_LHU: case RSP_SB: case RSP_SH: case RSP_SW: break; case RSP_LC2: switch (RspOp.rd) { case RSP_LSC2_SV: case RSP_LSC2_DV: case RSP_LSC2_RV: case RSP_LSC2_QV: case RSP_LSC2_LV: case RSP_LSC2_UV: case RSP_LSC2_PV: case RSP_LSC2_TV: break; default: CompilerWarning("Unkown opcode in WriteToAccum\n%s", RSPOpcodeName(RspOp.Hex, PC)); return 1; } break; case RSP_SC2: switch (RspOp.rd) { case RSP_LSC2_BV: case RSP_LSC2_SV: case RSP_LSC2_LV: case RSP_LSC2_DV: case RSP_LSC2_QV: case RSP_LSC2_RV: case RSP_LSC2_PV: case RSP_LSC2_UV: case RSP_LSC2_HV: case RSP_LSC2_FV: case RSP_LSC2_WV: case RSP_LSC2_TV: break; default: CompilerWarning("Unkown opcode in WriteToAccum\n%s", RSPOpcodeName(RspOp.Hex, PC)); return 1; } break; default: CompilerWarning("Unkown opcode in WriteToAccum\n%s", RSPOpcodeName(RspOp.Hex, PC)); return 1; } switch (Instruction_State) { case NORMAL: break; case DO_DELAY_SLOT: Instruction_State = DELAY_SLOT; break; case DELAY_SLOT: if (JumpUncond) { PC = JumpTarget - 0x04; Instruction_State = NORMAL; } else { Instruction_State = FINISH_BLOCK; } JumpUncond = 0; break; } } while (Instruction_State != FINISH_BLOCK); /*** ** This is a tricky situation because most of the ** microcode does loops, so looping back and checking ** can prove effective, but it's still a branch.. ***/ if (BranchTarget != 0 && RecursiveCall == 0) { uint32_t BranchTaken, BranchFall; /* analysis of branch taken */ BranchTaken = WriteToAccum2(Location, BranchTarget - 4, 1); /* analysis of branch as nop */ BranchFall = WriteToAccum2(Location, PC, 1); if (BranchImmed < 0) { if (BranchTaken != 0) { /* ** took this back branch and couldnt find a place ** that resets the accum or hit a branch etc **/ return 1; } else if (BranchFall == HIT_BRANCH) { /* risky? the loop ended, hit another branch after loop-back */ #if !defined(RSP_SAFE_ANALYSIS) CPU_Message ("WriteToDest: Backward branch hit, BranchFall = Hit branch (returning 0)"); return 0; #endif return 1; } else { /* otherwise this is completely valid */ return BranchFall; } } else { if (BranchFall != 0) { /* ** took this forward branch and couldnt find a place ** that resets the accum or hit a branch etc **/ return 1; } else if (BranchTaken == HIT_BRANCH) { /* risky? jumped forward, hit another branch */ #if !defined(RSP_SAFE_ANALYSIS) CPU_Message ("WriteToDest: Forward branch hit, BranchTaken = Hit branch (returning 0)"); return 0; #endif return 1; } else { /* otherwise this is completely valid */ return BranchTaken; } } } else { return HIT_BRANCH; } }
BOOL CompareInstructions(DWORD PC, OPCODE * Top, OPCODE * Bottom) { OPCODE_INFO info0, info1; DWORD InstructionType; GetInstructionInfo(PC - 4, Top, &info0); GetInstructionInfo(PC, Bottom, &info1); #ifdef COMPARE_INSTRUCTIONS_VERBOSE CPU_Message("Comparing %s (%X)", RSPOpcodeName ( Top->Hex, PC - 4 ), PC - 4); CPU_Message("to %s (%X)", RSPOpcodeName ( Bottom->Hex, PC), PC); #endif /* usually branches and such */ if ((info0.flags & InvalidOpcode) != 0) return FALSE; if ((info1.flags & InvalidOpcode) != 0) return FALSE; if ((info0.flags & Flag_Instruction) != 0 && (info1.flags & Flag_Instruction) != 0) return FALSE; InstructionType = (info0.flags & Instruction_Mask) << 2; InstructionType |= info1.flags & Instruction_Mask; InstructionType &= 0x0F; /* Paranoia */ /* 4 bit range, 16 possible combinations */ switch (InstructionType) { /* ** Detect noop instruction, 7 cases, (see flags) */ case 0x01: case 0x02: case 0x03: /* First is a noop */ return TRUE; case 0x00: /* Both ??? */ case 0x10: case 0x20: case 0x30: /* Second is a noop */ return FALSE; case 0x06: /* GPR than Vector - 01,10 */ if ((info0.flags & MemOperation_Mask) != 0 && (info1.flags & MemOperation_Mask) != 0) { /* TODO: We have a vector & GPR memory operation */ return FALSE; } else if ((info1.flags & MemOperation_Mask) != 0) { /* We have a vector memory operation */ return (info1.IndexReg == info0.DestReg) ? FALSE : TRUE; } /* We could have memory or normal gpr instruction here ** paired with some kind of vector operation */ return TRUE; case 0x0A: /* Vector than Vector - 10,10 */ /* ** Check for Vector Store than Vector multiply (VMULF) ** ** This basically gives preferences to putting stores ** as close to the finish of an operation as possible */ if ((info0.flags & Store_Operation) != 0 && (info1.flags & Accum_Operation) != 0 && !(info1.flags & VEC_Accumulate)) { return FALSE; } /* ** Look for loads and than some kind of vector operation ** that does no accumulating, there is no reason to reorder */ if ((info0.flags & Load_Operation) != 0 && (info1.flags & Accum_Operation) != 0 && !(info1.flags & VEC_Accumulate)) { return FALSE; } if ((info0.flags & MemOperation_Mask) != 0 && (info1.flags & MemOperation_Mask) != 0) { /* ** TODO: This is a bitch, its best to leave it alone **/ return FALSE; } else if ((info1.flags & MemOperation_Mask) != 0) { /* Remember stored reg & loaded reg are the same */ if (info0.DestReg == info1.DestReg) { return FALSE; } if (info1.flags & Load_Operation) { if (info0.SourceReg0 == info1.DestReg) { return FALSE; } if (info0.SourceReg1 == info1.DestReg) { return FALSE; } } else if (info1.flags & Store_Operation) { /* It can store source regs */ return TRUE; } return TRUE; } else if ((info0.flags & MemOperation_Mask) != 0) { /* Remember stored reg & loaded reg are the same */ if (info0.DestReg == info1.DestReg) { return FALSE; } if (info0.flags & Load_Operation) { if (info1.SourceReg0 == info0.DestReg) { return FALSE; } if (info1.SourceReg1 == info0.DestReg) { return FALSE; } } else if (info0.flags & Store_Operation) { /* It can store source regs */ return TRUE; } return TRUE; } else if ((info0.flags & VEC_Accumulate) != 0) { /* ** Example: ** VMACF ** VMUDH or VMADH or VADD */ return FALSE; } else if ((info1.flags & VEC_Accumulate) != 0) { /* ** Example: ** VMULF ** VMADH */ return FALSE; } else { /* ** Example: ** VMULF or VADDC ** VADD or VMUDH */ return FALSE; } break; case 0x09: /* Vector than GPR - 10,01 */ /********** ** this is where the bias comes into play, otherwise ** we can sit here all day swapping these 2 types ***********/ return FALSE; case 0x05: /* GPR than GPR - 01,01 */ case 0x07: /* GPR than Cop2 - 01, 11 */ case 0x0D: /* Cop2 than GPR - 11, 01 */ case 0x0F: /* Cop2 than Cop2 - 11, 11 */ return FALSE; case 0x0B: /* Vector than Cop2 - 10, 11 */ if (info1.flags & Load_Operation) { /* Move To Cop2 (dest) from GPR (source) */ if (info1.DestReg == info0.DestReg) { return FALSE; } if (info1.DestReg == info0.SourceReg0) { return FALSE; } if (info1.DestReg == info0.SourceReg1) { return FALSE; } } else if (info1.flags & Store_Operation) { /* Move From Cop2 (source) to GPR (dest) */ if (info1.SourceReg0 == info0.DestReg) { return FALSE; } if (info1.SourceReg0 == info0.SourceReg0) { return FALSE; } if (info1.SourceReg0 == info0.SourceReg1) { return FALSE; } } else { CompilerWarning("ReOrder: Unhandled Vector than Cop2"); } // we want vectors on top return FALSE; case 0x0E: /* Cop2 than Vector - 11, 10 */ if (info0.flags & Load_Operation) { /* Move To Cop2 (dest) from GPR (source) */ if (info0.DestReg == info1.DestReg) { return FALSE; } if (info0.DestReg == info1.SourceReg0) { return FALSE; } if (info0.DestReg == info1.SourceReg1) { return FALSE; } } else if (info0.flags & Store_Operation) { /* Move From Cop2 (source) to GPR (dest) */ if (info0.SourceReg0 == info1.DestReg) { return FALSE; } if (info0.SourceReg0 == info1.SourceReg0) { return FALSE; } if (info0.SourceReg0 == info1.SourceReg1) { return FALSE; } if (info0.DestReg == info1.SourceReg0) { return FALSE; } } else { CompilerWarning("ReOrder: Unhandled Cop2 than Vector"); } // we want this at the top return TRUE; default: CompilerWarning("ReOrder: Unhandled instruction type: %i", InstructionType); } return FALSE; }
void CCodeSection::DisplaySectionInformation() { if (m_SectionID == 0) { return; } CPU_Message("====== Section %d ======", m_SectionID); CPU_Message("Start PC: %X", m_EnterPC); if (g_System->bLinkBlocks()) { CPU_Message("End PC: %X", m_EndPC); } CPU_Message("CompiledLocation: %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("======================="); }