#include #include "../MIPS.h" #include "../MemoryUtils.h" #include "MA_EE.h" #include "offsetof_def.h" CMA_EE::CMA_EE() : CMA_MIPSIV(MIPS_REGSIZE_64) { m_pOpGeneral[0x1E] = std::bind(&CMA_EE::LQ, this); m_pOpGeneral[0x1F] = std::bind(&CMA_EE::SQ, this); m_pOpRegImm[0x18] = std::bind(&CMA_EE::MTSAB, this); m_pOpRegImm[0x19] = std::bind(&CMA_EE::MTSAH, this); m_pOpSpecial[0x28] = std::bind(&CMA_EE::MFSA, this); m_pOpSpecial[0x29] = std::bind(&CMA_EE::MTSA, this); m_pOpSpecial2[0x00] = std::bind(&CMA_EE::MADD, this); m_pOpSpecial2[0x01] = std::bind(&CMA_EE::MADDU, this); m_pOpSpecial2[0x04] = std::bind(&CMA_EE::PLZCW, this); m_pOpSpecial2[0x08] = std::bind(&CMA_EE::MMI0, this); m_pOpSpecial2[0x09] = std::bind(&CMA_EE::MMI2, this); m_pOpSpecial2[0x10] = std::bind(&CMA_EE::MFHI1, this); m_pOpSpecial2[0x11] = std::bind(&CMA_EE::MTHI1, this); m_pOpSpecial2[0x12] = std::bind(&CMA_EE::MFLO1, this); m_pOpSpecial2[0x13] = std::bind(&CMA_EE::MTLO1, this); m_pOpSpecial2[0x18] = std::bind(&CMA_EE::MULT1, this); m_pOpSpecial2[0x19] = std::bind(&CMA_EE::MULTU1, this); m_pOpSpecial2[0x1A] = std::bind(&CMA_EE::DIV1, this); m_pOpSpecial2[0x1B] = std::bind(&CMA_EE::DIVU1, this); m_pOpSpecial2[0x20] = std::bind(&CMA_EE::MADD1, this); m_pOpSpecial2[0x21] = std::bind(&CMA_EE::MADDU1, this); m_pOpSpecial2[0x28] = std::bind(&CMA_EE::MMI1, this); m_pOpSpecial2[0x29] = std::bind(&CMA_EE::MMI3, this); m_pOpSpecial2[0x30] = std::bind(&CMA_EE::PMFHL, this); m_pOpSpecial2[0x34] = std::bind(&CMA_EE::PSLLH, this); m_pOpSpecial2[0x36] = std::bind(&CMA_EE::PSRLH, this); m_pOpSpecial2[0x37] = std::bind(&CMA_EE::PSRAH, this); m_pOpSpecial2[0x3C] = std::bind(&CMA_EE::PSLLW, this); m_pOpSpecial2[0x3E] = std::bind(&CMA_EE::PSRLW, this); m_pOpSpecial2[0x3F] = std::bind(&CMA_EE::PSRAW, this); SetupReflectionTables(); } void CMA_EE::PushVector(unsigned int nReg) { m_codeGen->MD_PushRel(offsetof(CMIPS, m_State.nGPR[nReg])); } void CMA_EE::PullVector(unsigned int nReg) { m_codeGen->MD_PullRel(offsetof(CMIPS, m_State.nGPR[nReg])); } size_t CMA_EE::GetLoOffset(unsigned int index) { switch(index) { case 0: return offsetof(CMIPS, m_State.nLO[0]); break; case 1: return offsetof(CMIPS, m_State.nLO[1]); break; case 2: return offsetof(CMIPS, m_State.nLO1[0]); break; case 3: return offsetof(CMIPS, m_State.nLO1[1]); break; default: throw std::exception(); break; } } size_t CMA_EE::GetHiOffset(unsigned int index) { switch(index) { case 0: return offsetof(CMIPS, m_State.nHI[0]); break; case 1: return offsetof(CMIPS, m_State.nHI[1]); break; case 2: return offsetof(CMIPS, m_State.nHI1[0]); break; case 3: return offsetof(CMIPS, m_State.nHI1[1]); break; default: throw std::exception(); break; } } ////////////////////////////////////////////////// //General Opcodes ////////////////////////////////////////////////// //1E void CMA_EE::LQ() { if(m_nRT == 0) return; ComputeMemAccessPageRef(); m_codeGen->PushCst(0); m_codeGen->BeginIf(Jitter::CONDITION_NE); { ComputeMemAccessRef(0x10); m_codeGen->MD_LoadFromRef(); m_codeGen->MD_PullRel(offsetof(CMIPS, m_State.nGPR[m_nRT])); } m_codeGen->Else(); { ComputeMemAccessAddrNoXlat(); m_codeGen->PushCtx(); m_codeGen->PushIdx(1); m_codeGen->Call(reinterpret_cast(&MemoryUtils_GetQuadProxy), 2, Jitter::CJitter::RETURN_VALUE_128); m_codeGen->MD_PullRel(offsetof(CMIPS, m_State.nGPR[m_nRT])); m_codeGen->PullTop(); } m_codeGen->EndIf(); } //1F void CMA_EE::SQ() { ComputeMemAccessPageRef(); m_codeGen->PushCst(0); m_codeGen->BeginIf(Jitter::CONDITION_NE); { ComputeMemAccessRef(0x10); m_codeGen->MD_PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT])); m_codeGen->MD_StoreAtRef(); } m_codeGen->Else(); { ComputeMemAccessAddrNoXlat(); m_codeGen->PushCtx(); m_codeGen->MD_PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT])); m_codeGen->PushIdx(2); m_codeGen->Call(reinterpret_cast(&MemoryUtils_SetQuadProxy), 3, Jitter::CJitter::RETURN_VALUE_NONE); m_codeGen->PullTop(); } m_codeGen->EndIf(); } ////////////////////////////////////////////////// //RegImm Opcodes ////////////////////////////////////////////////// //18 void CMA_EE::MTSAB() { m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[0])); m_codeGen->PushCst(0x0F); m_codeGen->And(); m_codeGen->PushCst(m_nImmediate & 0x0F); m_codeGen->Xor(); m_codeGen->Shl(0x03); m_codeGen->PullRel(offsetof(CMIPS, m_State.nSA)); } //19 void CMA_EE::MTSAH() { m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[0])); m_codeGen->PushCst(0x07); m_codeGen->And(); m_codeGen->PushCst(m_nImmediate & 0x07); m_codeGen->Xor(); m_codeGen->Shl(0x04); m_codeGen->PullRel(offsetof(CMIPS, m_State.nSA)); } ////////////////////////////////////////////////// //Special Opcodes ////////////////////////////////////////////////// //28 void CMA_EE::MFSA() { m_codeGen->PushRel(offsetof(CMIPS, m_State.nSA)); m_codeGen->Srl(3); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[0])); } //29 void CMA_EE::MTSA() { m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[0])); m_codeGen->PushCst(0xF); m_codeGen->And(); m_codeGen->Shl(3); m_codeGen->PullRel(offsetof(CMIPS, m_State.nSA)); } ////////////////////////////////////////////////// //MMI Opcodes ////////////////////////////////////////////////// //00 void CMA_EE::MADD() { Generic_MADD(0, true); } //01 void CMA_EE::MADDU() { Generic_MADD(0, false); } //04 void CMA_EE::PLZCW() { if(m_nRD == 0) return; for(unsigned int i = 0; i < 2; i++) { m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[i])); m_codeGen->Lzc(); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[i])); } } //08 void CMA_EE::MMI0() { ((this)->*(m_pOpMmi0[(m_nOpcode >> 6) & 0x1F]))(); } //09 void CMA_EE::MMI2() { ((this)->*(m_pOpMmi2[(m_nOpcode >> 6) & 0x1F]))(); } //10 void CMA_EE::MFHI1() { if(m_nRD == 0) return; m_codeGen->PushRel(offsetof(CMIPS, m_State.nHI1[0])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[0])); m_codeGen->PushRel(offsetof(CMIPS, m_State.nHI1[1])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[1])); } //11 void CMA_EE::MTHI1() { m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[0])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nHI1[0])); m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[1])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nHI1[1])); } //12 void CMA_EE::MFLO1() { if(m_nRD == 0) return; m_codeGen->PushRel(offsetof(CMIPS, m_State.nLO1[0])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[0])); m_codeGen->PushRel(offsetof(CMIPS, m_State.nLO1[1])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[1])); } //13 void CMA_EE::MTLO1() { m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[0])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nLO1[0])); m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[1])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nLO1[1])); } //18 void CMA_EE::MULT1() { Template_Mult32(true, 1); } //19 void CMA_EE::MULTU1() { Template_Mult32(false, 1); } //1A void CMA_EE::DIV1() { Template_Div32(true, 1); } //1B void CMA_EE::DIVU1() { Template_Div32(false, 1); } //20 void CMA_EE::MADD1() { Generic_MADD(1, true); } //21 void CMA_EE::MADDU1() { Generic_MADD(1, false); } //28 void CMA_EE::MMI1() { ((this)->*(m_pOpMmi1[(m_nOpcode >> 6) & 0x1F]))(); } //29 void CMA_EE::MMI3() { ((this)->*(m_pOpMmi3[(m_nOpcode >> 6) & 0x1F]))(); } //30 void CMA_EE::PMFHL() { ((this)->*(m_pOpPmfhl[(m_nOpcode >> 6) & 0x1F]))(); } //34 void CMA_EE::PSLLH() { if(m_nRD == 0) return; PushVector(m_nRT); m_codeGen->MD_SllH(m_nSA); PullVector(m_nRD); } //36 void CMA_EE::PSRLH() { if(m_nRD == 0) return; PushVector(m_nRT); m_codeGen->MD_SrlH(m_nSA); PullVector(m_nRD); } //37 void CMA_EE::PSRAH() { if(m_nRD == 0) return; PushVector(m_nRT); m_codeGen->MD_SraH(m_nSA); PullVector(m_nRD); } //3C void CMA_EE::PSLLW() { if(m_nRD == 0) return; PushVector(m_nRT); m_codeGen->MD_SllW(m_nSA); PullVector(m_nRD); } //3E void CMA_EE::PSRLW() { if(m_nRD == 0) return; PushVector(m_nRT); m_codeGen->MD_SrlW(m_nSA); PullVector(m_nRD); } //3F void CMA_EE::PSRAW() { if(m_nRD == 0) return; PushVector(m_nRT); m_codeGen->MD_SraW(m_nSA); PullVector(m_nRD); } ////////////////////////////////////////////////// //MMI0 Opcodes ////////////////////////////////////////////////// //00 void CMA_EE::PADDW() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_AddW(); PullVector(m_nRD); } //01 void CMA_EE::PSUBW() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_SubW(); PullVector(m_nRD); } //02 void CMA_EE::PCGTW() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_CmpGtW(); PullVector(m_nRD); } //03 void CMA_EE::PMAXW() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_MaxW(); PullVector(m_nRD); } //04 void CMA_EE::PADDH() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_AddH(); PullVector(m_nRD); } //05 void CMA_EE::PSUBH() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_SubH(); PullVector(m_nRD); } //06 void CMA_EE::PCGTH() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_CmpGtH(); PullVector(m_nRD); } //07 void CMA_EE::PMAXH() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_MaxH(); PullVector(m_nRD); } //08 void CMA_EE::PADDB() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_AddB(); PullVector(m_nRD); } //09 void CMA_EE::PSUBB() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_SubB(); PullVector(m_nRD); } //0A void CMA_EE::PCGTB() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_CmpGtB(); PullVector(m_nRD); } //10 void CMA_EE::PADDSW() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_AddWSS(); PullVector(m_nRD); } //11 void CMA_EE::PSUBSW() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_SubWSS(); PullVector(m_nRD); } //12 void CMA_EE::PEXTLW() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_UnpackLowerWD(); PullVector(m_nRD); } //13 void CMA_EE::PPACW() { if(m_nRD == 0) return; //RS = A //RT = B //RD = A2 A0 B2 B0 //The order of operations here is quite important because RS, RT and RD can be equal //- Elements 1 and 3 in the destination register are unused in the source registers so, it's safe to write them first //- Element 2 in the destination register isn't used after the previous operations, so it's safe to override //- Only element 0 remains which is filled with element 0 from source, which is safe even if registers are the same //1 m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[2])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[1])); //3 m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[2])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[3])); //2 m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[0])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[2])); //0 m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[0])); } //14 void CMA_EE::PADDSH() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_AddHSS(); PullVector(m_nRD); } //15 void CMA_EE::PSUBSH() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_SubHSS(); PullVector(m_nRD); } //16 void CMA_EE::PEXTLH() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_UnpackLowerHW(); PullVector(m_nRD); } //17 void CMA_EE::PPACH() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_PackWH(); PullVector(m_nRD); } //18 void CMA_EE::PADDSB() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_AddBSS(); PullVector(m_nRD); } //1A void CMA_EE::PEXTLB() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_UnpackLowerBH(); PullVector(m_nRD); } //1B void CMA_EE::PPACB() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_PackHB(); PullVector(m_nRD); } //1E void CMA_EE::PEXT5() { if(m_nRD == 0) return; for(unsigned int i = 0; i < 4; i++) { m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[i])); m_codeGen->PushCst(0x001F); m_codeGen->And(); m_codeGen->Shl(3); m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[i])); m_codeGen->PushCst(0x03E0); m_codeGen->And(); m_codeGen->Shl(6); m_codeGen->Or(); m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[i])); m_codeGen->PushCst(0x7C00); m_codeGen->And(); m_codeGen->Shl(9); m_codeGen->Or(); m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[i])); m_codeGen->PushCst(0x8000); m_codeGen->And(); m_codeGen->Shl(16); m_codeGen->Or(); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[i])); } } //1F void CMA_EE::PPAC5() { if(m_nRD == 0) return; for(unsigned int i = 0; i < 4; i++) { m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[i])); m_codeGen->PushCst(0x80000000); m_codeGen->And(); m_codeGen->Srl(16); m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[i])); m_codeGen->PushCst(0x00F80000); m_codeGen->And(); m_codeGen->Srl(9); m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[i])); m_codeGen->PushCst(0x0000F800); m_codeGen->And(); m_codeGen->Srl(6); m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[i])); m_codeGen->PushCst(0x000000F8); m_codeGen->And(); m_codeGen->Srl(3); m_codeGen->Or(); m_codeGen->Or(); m_codeGen->Or(); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[i])); } } ////////////////////////////////////////////////// //MMI1 Opcodes ////////////////////////////////////////////////// //01 void CMA_EE::PABSW() { if(m_nRD == 0) return; //RD = (RT != 0x80000000) ? |RT| : 0x7FFFFFFF; for(unsigned int i = 0; i < 4; i++) { auto srcOffset = offsetof(CMIPS, m_State.nGPR[m_nRT].nV[i]); auto dstOffset = offsetof(CMIPS, m_State.nGPR[m_nRD].nV[i]); m_codeGen->PushRel(srcOffset); m_codeGen->PushCst(0x80000000); m_codeGen->BeginIf(Jitter::CONDITION_EQ); { m_codeGen->PushCst(0x7FFFFFFF); m_codeGen->PullRel(dstOffset); } m_codeGen->Else(); { m_codeGen->PushRel(srcOffset); m_codeGen->PushCst(0); m_codeGen->BeginIf(Jitter::CONDITION_LT); { m_codeGen->PushCst(0); m_codeGen->PushRel(srcOffset); m_codeGen->Sub(); m_codeGen->PullRel(dstOffset); } m_codeGen->Else(); { m_codeGen->PushRel(srcOffset); m_codeGen->PullRel(dstOffset); } m_codeGen->EndIf(); } m_codeGen->EndIf(); } } //02 void CMA_EE::PCEQW() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_CmpEqW(); PullVector(m_nRD); } //03 void CMA_EE::PMINW() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_MinW(); PullVector(m_nRD); } //06 void CMA_EE::PCEQH() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_CmpEqH(); PullVector(m_nRD); } //07 void CMA_EE::PMINH() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_MinH(); PullVector(m_nRD); } //0A void CMA_EE::PCEQB() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_CmpEqB(); PullVector(m_nRD); } //10 void CMA_EE::PADDUW() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_AddWUS(); PullVector(m_nRD); } //11 void CMA_EE::PSUBUW() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_SubWUS(); PullVector(m_nRD); } //12 void CMA_EE::PEXTUW() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_UnpackUpperWD(); PullVector(m_nRD); } //14 void CMA_EE::PADDUH() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_AddHUS(); PullVector(m_nRD); } //15 void CMA_EE::PSUBUH() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_SubHUS(); PullVector(m_nRD); } //16 void CMA_EE::PEXTUH() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_UnpackUpperHW(); PullVector(m_nRD); } //18 void CMA_EE::PADDUB() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_AddBUS(); PullVector(m_nRD); } //19 void CMA_EE::PSUBUB() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_SubBUS(); PullVector(m_nRD); } //1A void CMA_EE::PEXTUB() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_UnpackUpperBH(); PullVector(m_nRD); } //1B void CMA_EE::QFSRV() { PushVector(m_nRS); PushVector(m_nRT); m_codeGen->PushRel(offsetof(CMIPS, m_State.nSA)); m_codeGen->MD_Srl256(); PullVector(m_nRD); } ////////////////////////////////////////////////// //MMI2 Opcodes ////////////////////////////////////////////////// //02 void CMA_EE::PSLLVW() { Generic_PSxxV([this]() { m_codeGen->Shl(); }); } //03 void CMA_EE::PSRLVW() { Generic_PSxxV([this]() { m_codeGen->Srl(); }); } //08 void CMA_EE::PMFHI() { if(m_nRD == 0) return; for(unsigned int i = 0; i < 4; i++) { m_codeGen->PushRel(GetHiOffset(i)); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[i])); } } //09 void CMA_EE::PMFLO() { if(m_nRD == 0) return; for(unsigned int i = 0; i < 4; i++) { m_codeGen->PushRel(GetLoOffset(i)); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[i])); } } //0A void CMA_EE::PINTH() { if(m_nRD == 0) return; uint8 tempRegIndex = 32; for(unsigned int i = 0; i < 2; i++) { //B0/B2 m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[i + 0])); m_codeGen->PushCst(0xFFFF); m_codeGen->And(); //A0/A2 m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[i + 2])); m_codeGen->Shl(16); m_codeGen->Or(); m_codeGen->PullRel(offsetof(CMIPS, m_State.nCOP2[tempRegIndex].nV[(i * 2) + 0])); //B1/B3 m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[i + 0])); m_codeGen->Srl(16); //A1/A3 m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[i + 2])); m_codeGen->PushCst(0xFFFF0000); m_codeGen->And(); m_codeGen->Or(); m_codeGen->PullRel(offsetof(CMIPS, m_State.nCOP2[tempRegIndex].nV[(i * 2) + 1])); } m_codeGen->MD_PushRel(offsetof(CMIPS, m_State.nCOP2[tempRegIndex])); m_codeGen->MD_PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD])); } //0C void CMA_EE::PMULTW() { Generic_PMULTW(true); } //0D void CMA_EE::PDIVW() { for(unsigned int i = 0; i < 2; i++) { Template_Div32(true, i, i * 2); } } //0E void CMA_EE::PCPYLD() { if(m_nRD == 0) return; //A0 m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[0])); m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[1])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[3])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[2])); //B0 m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0])); m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[1])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[1])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[0])); } //10 void CMA_EE::PMADDH() { static const size_t offsets[8] = { offsetof(CMIPS, m_State.nLO[0]), offsetof(CMIPS, m_State.nLO[1]), offsetof(CMIPS, m_State.nHI[0]), offsetof(CMIPS, m_State.nHI[1]), offsetof(CMIPS, m_State.nLO1[0]), offsetof(CMIPS, m_State.nLO1[1]), offsetof(CMIPS, m_State.nHI1[0]), offsetof(CMIPS, m_State.nHI1[1])}; for(unsigned int i = 0; i < 4; i++) { //Lower 16-bits { m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[i])); m_codeGen->SignExt16(); m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[i])); m_codeGen->SignExt16(); m_codeGen->MultS(); m_codeGen->ExtLow64(); m_codeGen->PushRel(offsets[(i * 2) + 0]); m_codeGen->Add(); m_codeGen->PullRel(offsets[(i * 2) + 0]); } //Higher 16-bits { m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[i])); m_codeGen->Sra(16); m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[i])); m_codeGen->Sra(16); m_codeGen->MultS(); m_codeGen->ExtLow64(); m_codeGen->PushRel(offsets[(i * 2) + 1]); m_codeGen->Add(); m_codeGen->PullRel(offsets[(i * 2) + 1]); } } if(m_nRD != 0) { //Copy to RD m_codeGen->PushRel(offsetof(CMIPS, m_State.nLO[0])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[0])); m_codeGen->PushRel(offsetof(CMIPS, m_State.nHI[0])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[1])); m_codeGen->PushRel(offsetof(CMIPS, m_State.nLO1[0])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[2])); m_codeGen->PushRel(offsetof(CMIPS, m_State.nHI1[0])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[3])); } } //11 void CMA_EE::PHMADH() { static const size_t offsets[4] = { offsetof(CMIPS, m_State.nLO[0]), offsetof(CMIPS, m_State.nHI[0]), offsetof(CMIPS, m_State.nLO1[0]), offsetof(CMIPS, m_State.nHI1[0]), }; static const size_t clearOffsets[4] = { offsetof(CMIPS, m_State.nLO[1]), offsetof(CMIPS, m_State.nHI[1]), offsetof(CMIPS, m_State.nLO1[1]), offsetof(CMIPS, m_State.nHI1[1]), }; for(unsigned int i = 0; i < 4; i++) { m_codeGen->PushCst(0); m_codeGen->PullRel(clearOffsets[i]); } for(unsigned int i = 0; i < 4; i++) { //Lower 16-bits (An0 * An1) { m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[i])); m_codeGen->SignExt16(); m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[i])); m_codeGen->SignExt16(); m_codeGen->MultS(); m_codeGen->ExtLow64(); } //Higher 16-bits (Bn0 * Bn1) { m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[i])); m_codeGen->Sra(16); m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[i])); m_codeGen->Sra(16); m_codeGen->MultS(); m_codeGen->ExtLow64(); } m_codeGen->Add(); if(m_nRD != 0) { m_codeGen->PushTop(); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[i])); } //Store to LO/HI m_codeGen->PullRel(offsets[i]); } } //12 void CMA_EE::PAND() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_And(); PullVector(m_nRD); } //13 void CMA_EE::PXOR() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_Xor(); PullVector(m_nRD); } //1A void CMA_EE::PEXEH() { if(m_nRD == 0) return; for(unsigned int i = 0; i < 4; i += 2) { //Compute rd[1] //t0 = rt[0] & 0x0000FFFF //t1 = rt[1] & 0xFFFF0000 //t2 = t0 | t1 m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[i + 0])); m_codeGen->PushCst(0x0000FFFF); m_codeGen->And(); m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[i + 1])); m_codeGen->PushCst(0xFFFF0000); m_codeGen->And(); m_codeGen->Or(); //Compute rd[0] //t0 = rt[0] & 0xFFFF0000 //t1 = rt[1] & 0x0000FFFF //t2 = t0 | t1 m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[i + 0])); m_codeGen->PushCst(0xFFFF0000); m_codeGen->And(); m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[i + 1])); m_codeGen->PushCst(0x0000FFFF); m_codeGen->And(); m_codeGen->Or(); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[i + 0])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[i + 1])); } } //1B void CMA_EE::PREVH() { if(m_nRD == 0) return; for(unsigned int i = 0; i < 2; i++) { m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[(i * 2) + 0])); m_codeGen->Shl(16); m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[(i * 2) + 0])); m_codeGen->Srl(16); m_codeGen->Or(); m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[(i * 2) + 1])); m_codeGen->Shl(16); m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[(i * 2) + 1])); m_codeGen->Srl(16); m_codeGen->Or(); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[(i * 2) + 0])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[(i * 2) + 1])); } } //1C void CMA_EE::PMULTH() { static const size_t offsets[8] = { offsetof(CMIPS, m_State.nLO[0]), offsetof(CMIPS, m_State.nLO[1]), offsetof(CMIPS, m_State.nHI[0]), offsetof(CMIPS, m_State.nHI[1]), offsetof(CMIPS, m_State.nLO1[0]), offsetof(CMIPS, m_State.nLO1[1]), offsetof(CMIPS, m_State.nHI1[0]), offsetof(CMIPS, m_State.nHI1[1])}; for(unsigned int i = 0; i < 4; i++) { //Lower 16-bits { m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[i])); m_codeGen->SignExt16(); m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[i])); m_codeGen->SignExt16(); m_codeGen->MultS(); m_codeGen->ExtLow64(); m_codeGen->PullRel(offsets[(i * 2) + 0]); } //Higher 16-bits { m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[i])); m_codeGen->Sra(16); m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[i])); m_codeGen->Sra(16); m_codeGen->MultS(); m_codeGen->ExtLow64(); m_codeGen->PullRel(offsets[(i * 2) + 1]); } } if(m_nRD != 0) { //Copy to RD m_codeGen->PushRel(offsetof(CMIPS, m_State.nLO[0])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[0])); m_codeGen->PushRel(offsetof(CMIPS, m_State.nHI[0])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[1])); m_codeGen->PushRel(offsetof(CMIPS, m_State.nLO1[0])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[2])); m_codeGen->PushRel(offsetof(CMIPS, m_State.nHI1[0])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[3])); } } //1E void CMA_EE::PEXEW() { if(m_nRD == 0) return; size_t offset[4]; if(m_nRT == m_nRD) { offset[0] = offsetof(CMIPS, m_State.nGPR[m_nRT].nV[2]); offset[1] = offsetof(CMIPS, m_State.nGPR[m_nRT].nV[1]); offset[2] = offsetof(CMIPS, m_State.nCOP2T); offset[3] = offsetof(CMIPS, m_State.nGPR[m_nRT].nV[3]); m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0])); m_codeGen->PullRel(offset[2]); } else { offset[0] = offsetof(CMIPS, m_State.nGPR[m_nRT].nV[2]); offset[1] = offsetof(CMIPS, m_State.nGPR[m_nRT].nV[1]); offset[2] = offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]); offset[3] = offsetof(CMIPS, m_State.nGPR[m_nRT].nV[3]); } for(unsigned int i = 0; i < 4; i++) { m_codeGen->PushRel(offset[i]); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[i])); } } //1F void CMA_EE::PROT3W() { if(m_nRD == 0) return; size_t offset[4]; if(m_nRT == m_nRD) { offset[0] = offsetof(CMIPS, m_State.nGPR[m_nRT].nV[1]); offset[1] = offsetof(CMIPS, m_State.nGPR[m_nRT].nV[2]); offset[2] = offsetof(CMIPS, m_State.nCOP2T); offset[3] = offsetof(CMIPS, m_State.nGPR[m_nRT].nV[3]); m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0])); m_codeGen->PullRel(offset[2]); } else { offset[0] = offsetof(CMIPS, m_State.nGPR[m_nRT].nV[1]); offset[1] = offsetof(CMIPS, m_State.nGPR[m_nRT].nV[2]); offset[2] = offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]); offset[3] = offsetof(CMIPS, m_State.nGPR[m_nRT].nV[3]); } for(unsigned int i = 0; i < 4; i++) { m_codeGen->PushRel(offset[i]); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[i])); } } ////////////////////////////////////////////////// //MMI3 Opcodes ////////////////////////////////////////////////// //03 void CMA_EE::PSRAVW() { Generic_PSxxV([this]() { m_codeGen->Sra(); }); } //08 void CMA_EE::PMTHI() { for(unsigned int i = 0; i < 4; i++) { m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[i])); m_codeGen->PullRel(GetHiOffset(i)); } } //09 void CMA_EE::PMTLO() { for(unsigned int i = 0; i < 4; i++) { m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[i])); m_codeGen->PullRel(GetLoOffset(i)); } } //0A void CMA_EE::PINTEH() { if(m_nRD == 0) return; for(unsigned int i = 0; i < 4; i++) { m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[i])); m_codeGen->Shl(16); m_codeGen->PushCst(0xFFFF0000); m_codeGen->And(); m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[i])); m_codeGen->PushCst(0xFFFF); m_codeGen->And(); m_codeGen->Or(); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[i])); } } //0C void CMA_EE::PMULTUW() { Generic_PMULTW(false); } //0E void CMA_EE::PCPYUD() { if(m_nRD == 0) return; //A m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[2])); m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[3])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[1])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[0])); //B m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[2])); m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[3])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[3])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[2])); } //12 void CMA_EE::POR() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_Or(); PullVector(m_nRD); } //13 void CMA_EE::PNOR() { if(m_nRD == 0) return; PushVector(m_nRS); PushVector(m_nRT); m_codeGen->MD_Or(); m_codeGen->MD_Not(); PullVector(m_nRD); } //1A void CMA_EE::PEXCH() { if(m_nRD == 0) return; for(unsigned int i = 0; i < 4; i += 2) { //Compute rd[1] //t0 = rt[0] >> 16 //t1 = rt[1] & 0xFFFF0000 //t2 = t0 | t1 m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[i + 0])); m_codeGen->Srl(16); m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[i + 1])); m_codeGen->PushCst(0xFFFF0000); m_codeGen->And(); m_codeGen->Or(); //Compute rd[0] //t0 = rt[1] << 16 //t1 = rt[0] & 0x0000FFFF //t2 = t0 | t1 m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[i + 1])); m_codeGen->Shl(16); m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[i + 0])); m_codeGen->PushCst(0x0000FFFF); m_codeGen->And(); m_codeGen->Or(); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[i + 0])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[i + 1])); } } //1B void CMA_EE::PCPYH() { if(m_nRD == 0) return; for(unsigned int i = 0; i < 4; i += 2) { m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[i])); m_codeGen->PushCst(0xFFFF); m_codeGen->And(); m_codeGen->PushTop(); m_codeGen->Shl(16); m_codeGen->Or(); m_codeGen->PushTop(); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[i + 0])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[i + 1])); } } //1E void CMA_EE::PEXCW() { if(m_nRD == 0) return; size_t offset[4]; if(m_nRT == m_nRD) { offset[0] = offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]); offset[1] = offsetof(CMIPS, m_State.nGPR[m_nRT].nV[2]); offset[2] = offsetof(CMIPS, m_State.nCOP2T); offset[3] = offsetof(CMIPS, m_State.nGPR[m_nRT].nV[3]); m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[1])); m_codeGen->PullRel(offset[2]); } else { offset[0] = offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0]); offset[1] = offsetof(CMIPS, m_State.nGPR[m_nRT].nV[2]); offset[2] = offsetof(CMIPS, m_State.nGPR[m_nRT].nV[1]); offset[3] = offsetof(CMIPS, m_State.nGPR[m_nRT].nV[3]); } for(unsigned int i = 0; i < 4; i++) { m_codeGen->PushRel(offset[i]); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[i])); } } ////////////////////////////////////////////////// //PMFHL ////////////////////////////////////////////////// //00 void CMA_EE::PMFHL_LW() { if(m_nRD == 0) return; m_codeGen->PushRel(offsetof(CMIPS, m_State.nLO[0])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[0])); m_codeGen->PushRel(offsetof(CMIPS, m_State.nHI[0])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[1])); m_codeGen->PushRel(offsetof(CMIPS, m_State.nLO1[0])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[2])); m_codeGen->PushRel(offsetof(CMIPS, m_State.nHI1[0])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[3])); } //01 void CMA_EE::PMFHL_UW() { if(m_nRD == 0) return; m_codeGen->PushRel(offsetof(CMIPS, m_State.nLO[1])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[0])); m_codeGen->PushRel(offsetof(CMIPS, m_State.nHI[1])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[1])); m_codeGen->PushRel(offsetof(CMIPS, m_State.nLO1[1])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[2])); m_codeGen->PushRel(offsetof(CMIPS, m_State.nHI1[1])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[3])); } //03 void CMA_EE::PMFHL_LH() { if(m_nRD == 0) return; static const size_t offsets[8] = { offsetof(CMIPS, m_State.nLO[0]), offsetof(CMIPS, m_State.nLO[1]), offsetof(CMIPS, m_State.nHI[0]), offsetof(CMIPS, m_State.nHI[1]), offsetof(CMIPS, m_State.nLO1[0]), offsetof(CMIPS, m_State.nLO1[1]), offsetof(CMIPS, m_State.nHI1[0]), offsetof(CMIPS, m_State.nHI1[1])}; for(unsigned int i = 0; i < 4; i++) { m_codeGen->PushRel(offsets[(i * 2) + 0]); m_codeGen->PushCst(0xFFFF); m_codeGen->And(); m_codeGen->PushRel(offsets[(i * 2) + 1]); m_codeGen->Shl(16); m_codeGen->Or(); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[i])); } } //04 void CMA_EE::PMFHL_SH() { if(m_nRD == 0) return; static const auto emitClamp = [](CMipsJitter* codeGen, size_t offsetToClamp) { codeGen->PushRel(offsetToClamp); codeGen->PushCst(0x7FFF); codeGen->BeginIf(Jitter::CONDITION_GT); { codeGen->PushCst(0x7FFF); codeGen->PullRel(offsetToClamp); } codeGen->EndIf(); codeGen->PushRel(offsetToClamp); codeGen->PushCst(0xFFFF8000); codeGen->BeginIf(Jitter::CONDITION_LT); { codeGen->PushCst(0x8000); codeGen->PullRel(offsetToClamp); } codeGen->EndIf(); }; static const size_t offsets[8] = { offsetof(CMIPS, m_State.nLO[0]), offsetof(CMIPS, m_State.nLO[1]), offsetof(CMIPS, m_State.nHI[0]), offsetof(CMIPS, m_State.nHI[1]), offsetof(CMIPS, m_State.nLO1[0]), offsetof(CMIPS, m_State.nLO1[1]), offsetof(CMIPS, m_State.nHI1[0]), offsetof(CMIPS, m_State.nHI1[1])}; static const size_t tempOffset = offsetof(CMIPS, m_State.nCOP2T); for(unsigned int i = 0; i < 4; i++) { size_t dstOffset = offsetof(CMIPS, m_State.nGPR[m_nRD].nV[i]); //Lo part { m_codeGen->PushRel(offsets[(i * 2) + 0]); m_codeGen->PullRel(tempOffset); emitClamp(m_codeGen, tempOffset); m_codeGen->PushRel(tempOffset); m_codeGen->PullRel(dstOffset); } //Hi part { m_codeGen->PushRel(offsets[(i * 2) + 1]); m_codeGen->PullRel(tempOffset); emitClamp(m_codeGen, tempOffset); } //Merge { m_codeGen->PushRel(dstOffset); m_codeGen->PushRel(tempOffset); m_codeGen->Shl(16); m_codeGen->Or(); m_codeGen->PullRel(dstOffset); } } } ////////////////////////////////////////////////// //Generic Stuff ////////////////////////////////////////////////// void CMA_EE::Generic_MADD(unsigned int unit, bool isSigned) { //prod = (HI || LO) + (RS * RT) //LO = sex(prod[0]) //HI = sex(prod[1]) //RD = LO size_t lo[2]; size_t hi[2]; switch(unit) { case 0: lo[0] = offsetof(CMIPS, m_State.nLO[0]); lo[1] = offsetof(CMIPS, m_State.nLO[1]); hi[0] = offsetof(CMIPS, m_State.nHI[0]); hi[1] = offsetof(CMIPS, m_State.nHI[1]); break; case 1: lo[0] = offsetof(CMIPS, m_State.nLO1[0]); lo[1] = offsetof(CMIPS, m_State.nLO1[1]); hi[0] = offsetof(CMIPS, m_State.nHI1[0]); hi[1] = offsetof(CMIPS, m_State.nHI1[1]); break; default: throw std::runtime_error("Invalid unit number."); break; } m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[0])); m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[0])); if(isSigned) { m_codeGen->MultS(); } else { m_codeGen->Mult(); } m_codeGen->PushRel(lo[0]); m_codeGen->PushRel(hi[0]); m_codeGen->MergeTo64(); m_codeGen->Add64(); m_codeGen->PushTop(); m_codeGen->ExtHigh64(); m_codeGen->PushTop(); m_codeGen->SignExt(); m_codeGen->PullRel(hi[1]); m_codeGen->PullRel(hi[0]); m_codeGen->ExtLow64(); m_codeGen->PushTop(); m_codeGen->SignExt(); m_codeGen->PullRel(lo[1]); m_codeGen->PullRel(lo[0]); if(m_nRD != 0) { m_codeGen->PushRel(lo[0]); m_codeGen->PushRel(lo[1]); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[1])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[0])); } } void CMA_EE::Generic_PMULTW(bool isSigned) { for(unsigned int i = 0; i < 2; i++) { unsigned int regOffset = i * 2; m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[regOffset])); m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[regOffset])); if(isSigned) { m_codeGen->MultS(); } else { m_codeGen->Mult(); } m_codeGen->PushTop(); //LO m_codeGen->ExtLow64(); { m_codeGen->PushTop(); m_codeGen->SignExt(); m_codeGen->PullRel(GetLoOffset(regOffset + 1)); } m_codeGen->PullRel(GetLoOffset(regOffset + 0)); //HI m_codeGen->ExtHigh64(); { m_codeGen->PushTop(); m_codeGen->SignExt(); m_codeGen->PullRel(GetHiOffset(regOffset + 1)); } m_codeGen->PullRel(GetHiOffset(regOffset + 0)); } if(m_nRD != 0) { for(unsigned int i = 0; i < 2; i++) { unsigned int regOffset = i * 2; m_codeGen->PushRel(GetLoOffset(regOffset)); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[regOffset + 0])); m_codeGen->PushRel(GetHiOffset(regOffset)); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[regOffset + 1])); } } } void CMA_EE::Generic_PSxxV(const TemplateOperationFunctionType& function) { if(m_nRD == 0) return; for(unsigned int i = 0; i < 2; i++) { m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRT].nV[i * 2])); m_codeGen->PushRel(offsetof(CMIPS, m_State.nGPR[m_nRS].nV[i * 2])); function(); m_codeGen->PushTop(); m_codeGen->SignExt(); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[(i * 2) + 1])); m_codeGen->PullRel(offsetof(CMIPS, m_State.nGPR[m_nRD].nV[(i * 2) + 0])); } } ////////////////////////////////////////////////// //Opcode Tables ////////////////////////////////////////////////// // clang-format off CMA_EE::InstructionFuncConstant CMA_EE::m_pOpMmi0[0x20] = { //0x00 &CMA_EE::PADDW, &CMA_EE::PSUBW, &CMA_EE::PCGTW, &CMA_EE::PMAXW, &CMA_EE::PADDH, &CMA_EE::PSUBH, &CMA_EE::PCGTH, &CMA_EE::PMAXH, //0x08 &CMA_EE::PADDB, &CMA_EE::PSUBB, &CMA_EE::PCGTB, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, //0x10 &CMA_EE::PADDSW, &CMA_EE::PSUBSW, &CMA_EE::PEXTLW, &CMA_EE::PPACW, &CMA_EE::PADDSH, &CMA_EE::PSUBSH, &CMA_EE::PEXTLH, &CMA_EE::PPACH, //0x18 &CMA_EE::PADDSB, &CMA_EE::Illegal, &CMA_EE::PEXTLB, &CMA_EE::PPACB, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::PEXT5, &CMA_EE::PPAC5, }; CMA_EE::InstructionFuncConstant CMA_EE::m_pOpMmi1[0x20] = { //0x00 &CMA_EE::Illegal, &CMA_EE::PABSW, &CMA_EE::PCEQW, &CMA_EE::PMINW, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::PCEQH, &CMA_EE::PMINH, //0x08 &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::PCEQB, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, //0x10 &CMA_EE::PADDUW, &CMA_EE::PSUBUW, &CMA_EE::PEXTUW, &CMA_EE::Illegal, &CMA_EE::PADDUH, &CMA_EE::PSUBUH, &CMA_EE::PEXTUH, &CMA_EE::Illegal, //0x18 &CMA_EE::PADDUB, &CMA_EE::PSUBUB, &CMA_EE::PEXTUB, &CMA_EE::QFSRV, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, }; CMA_EE::InstructionFuncConstant CMA_EE::m_pOpMmi2[0x20] = { //0x00 &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::PSLLVW, &CMA_EE::PSRLVW, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, //0x08 &CMA_EE::PMFHI, &CMA_EE::PMFLO, &CMA_EE::PINTH, &CMA_EE::Illegal, &CMA_EE::PMULTW, &CMA_EE::PDIVW, &CMA_EE::PCPYLD, &CMA_EE::Illegal, //0x10 &CMA_EE::PMADDH, &CMA_EE::PHMADH, &CMA_EE::PAND, &CMA_EE::PXOR, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, //0x18 &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::PEXEH, &CMA_EE::PREVH, &CMA_EE::PMULTH, &CMA_EE::Illegal, &CMA_EE::PEXEW, &CMA_EE::PROT3W, }; CMA_EE::InstructionFuncConstant CMA_EE::m_pOpMmi3[0x20] = { //0x00 &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::PSRAVW, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, //0x08 &CMA_EE::PMTHI, &CMA_EE::PMTLO, &CMA_EE::PINTEH, &CMA_EE::Illegal, &CMA_EE::PMULTUW, &CMA_EE::Illegal, &CMA_EE::PCPYUD, &CMA_EE::Illegal, //0x10 &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::POR, &CMA_EE::PNOR, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, //0x18 &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::PEXCH, &CMA_EE::PCPYH, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::PEXCW, &CMA_EE::Illegal, }; CMA_EE::InstructionFuncConstant CMA_EE::m_pOpPmfhl[0x20] = { //0x00 &CMA_EE::PMFHL_LW, &CMA_EE::PMFHL_UW, &CMA_EE::Illegal, &CMA_EE::PMFHL_LH, &CMA_EE::PMFHL_SH, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, //0x08 &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, //0x10 &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, //0x18 &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, &CMA_EE::Illegal, }; // clang-format on