diff --git a/arch/mips/arch_mips.cpp b/arch/mips/arch_mips.cpp index d7b1d98071..a00275b58a 100644 --- a/arch/mips/arch_mips.cpp +++ b/arch/mips/arch_mips.cpp @@ -102,6 +102,7 @@ enum ElfMipsRelocationType : uint32_t // This range is reserved for vendor specific relocations. R_MIPS_LOVENDOR = 100, + R_MIPS_VCALLMS = 119, // MIPS R5900 (Emotion Engine) specific relocation for the Vector Unit (VU) micromode call instruction R_MIPS64_COPY = 125, R_MIPS_COPY = 126, R_MIPS_JUMP_SLOT = 127, @@ -165,6 +166,7 @@ static const char* GetRelocationString(ElfMipsRelocationType rel) { R_MIPS_TLS_TPREL_LO16, "R_MIPS_TLS_TPREL_LO16"}, { R_MIPS_GLOB_DAT, "R_MIPS_GLOB_DAT"}, { R_MIPS_LOVENDOR, "R_MIPS_LOVENDOR"}, + { R_MIPS_VCALLMS, "R_MIPS_VCALLMS"}, { R_MIPS64_COPY, "R_MIPS64_COPY"}, { R_MIPS_COPY, "R_MIPS_COPY"}, { R_MIPS_JUMP_SLOT, "R_MIPS_JUMP_SLOT"}, @@ -179,27 +181,24 @@ static const char* GetRelocationString(ElfMipsRelocationType rel) class MipsArchitecture: public Architecture { protected: + bool m_userWarnedAboutDelaySlots = false; + MipsVersion m_version; size_t m_bits; BNEndianness m_endian; - MipsVersion version_overwrite; uint32_t m_decomposeFlags; virtual bool Disassemble(const uint8_t* data, uint64_t addr, size_t maxLen, Instruction& result) { - MipsVersion version = version_overwrite; - memset(&result, 0, sizeof(result)); - if (m_bits == 64) - { - version = MIPS_64; - } - - if (mips_decompose((uint32_t*)data, maxLen, &result, version, addr, m_endian, m_decomposeFlags) != 0) + if (mips_decompose((uint32_t*)data, maxLen, &result, m_version, addr, m_endian, m_decomposeFlags) != 0) return false; return true; } - virtual size_t GetAddressSize() const override { return m_bits / 8; } + virtual size_t GetAddressSize() const override + { + return m_bits / 8; + } size_t InstructionHasBranchDelay(const Instruction& instr) { @@ -231,6 +230,10 @@ class MipsArchitecture: public Architecture case MIPS_JAL: case MIPS_JALR: case MIPS_JALR_HB: + case MIPS_BC0F: + case MIPS_BC0FL: + case MIPS_BC0T: + case MIPS_BC0TL: case MIPS_BC1F: case MIPS_BC1FL: case MIPS_BC1T: @@ -383,6 +386,10 @@ class MipsArchitecture: public Architecture else result.AddBranch(UnresolvedBranch, 0, nullptr, hasBranchDelay); break; + case MIPS_BC0F: + case MIPS_BC0FL: + case MIPS_BC0T: + case MIPS_BC0TL: case MIPS_BC1F: case MIPS_BC1FL: case MIPS_BC1T: @@ -407,8 +414,8 @@ class MipsArchitecture: public Architecture } public: - MipsArchitecture(const std::string& name, BNEndianness endian, size_t bits, MipsVersion version_in, uint32_t decomposeFlags = 0) - : Architecture(name), m_bits(bits), m_endian(endian), version_overwrite(version_in), m_decomposeFlags(decomposeFlags) + MipsArchitecture(const std::string& name, MipsVersion version, BNEndianness endian, size_t bits, uint32_t decomposeFlags = 0) + : Architecture(name), m_version(version), m_bits(bits), m_endian(endian), m_decomposeFlags(decomposeFlags) { Ref settings = Settings::Instance(); uint32_t flag_pseudo_ops = settings->Get("arch.mips.disassembly.pseudoOps") ? DECOMPOSE_FLAGS_PSEUDO_OP : 0; @@ -508,7 +515,16 @@ class MipsArchitecture: public Architecture { if (len < 8) { - LogWarn("Can not lift instruction with delay slot @ 0x%08" PRIx64, addr); + if (!m_userWarnedAboutDelaySlots) + { + + LogWarn("Can not lift instruction with delay slot @ 0x%08" PRIx64 "\n" + "Any future delay slot errors will be printed as debug logs\n" + "and can be viewed by setting the log capture level to debug.", addr); + m_userWarnedAboutDelaySlots = true; + } + else + LogDebug("Can not lift instruction with delay slot @ 0x%08" PRIx64, addr); return false; } @@ -524,11 +540,16 @@ class MipsArchitecture: public Architecture { InstructionInfo instrInfo; LowLevelILLabel trueCode, falseCode; + auto registerSize = [=](const InstructionOperand& op) -> size_t const + { + return get_register_width(Reg(op.reg), m_version); + }; + SetInstructionInfoForInstruction(addr, instr, instrInfo); - il.AddInstruction(il.If(GetConditionForInstruction(il, instr, GetAddressSize()), trueCode, falseCode)); + il.AddInstruction(il.If(GetConditionForInstruction(il, instr, registerSize), trueCode, falseCode)); il.MarkLabel(trueCode); il.SetCurrentAddress(this, addr + instr.size); - GetLowLevelILForInstruction(this, addr + instr.size, il, secondInstr, GetAddressSize(), m_decomposeFlags); + GetLowLevelILForInstruction(this, addr + instr.size, il, secondInstr, GetAddressSize(), m_decomposeFlags, m_version); for (size_t i = 0; i < instrInfo.branchCount; i++) { if (instrInfo.branchType[i] == TrueBranch) @@ -554,7 +575,7 @@ class MipsArchitecture: public Architecture nop = il.Nop(); il.AddInstruction(nop); - GetLowLevelILForInstruction(this, addr + instr.size, il, secondInstr, GetAddressSize(), m_decomposeFlags); + GetLowLevelILForInstruction(this, addr + instr.size, il, secondInstr, GetAddressSize(), m_decomposeFlags, m_version); LowLevelILInstruction delayed; uint32_t clobbered = BN_INVALID_REGISTER; @@ -581,7 +602,7 @@ class MipsArchitecture: public Architecture } else { - status = GetLowLevelILForInstruction(this, addr, il, instr, GetAddressSize(), m_decomposeFlags); + status = GetLowLevelILForInstruction(this, addr, il, instr, GetAddressSize(), m_decomposeFlags, m_version); } if (clobbered != BN_INVALID_REGISTER) @@ -732,7 +753,8 @@ class MipsArchitecture: public Architecture else { proceed = proceed && (left->operands[1].immediate == (right->operands[1].immediate + 7)); - addrToUse = (uint32_t)addr + ((&instr == right) ? 0 : 8); + // addrToUse = (uint32_t)addr + ((&instr == right) ? 0 : 8); + addrToUse = (uint32_t)addr + ((&instr == right) ? 0 : 4); } base = right; } @@ -746,12 +768,12 @@ class MipsArchitecture: public Architecture else base->operation = is32bit ? MIPS_LW : MIPS_LD; - return GetLowLevelILForInstruction(this, addrToUse, il, *base, GetAddressSize(), m_decomposeFlags); + return GetLowLevelILForInstruction(this, addrToUse, il, *base, GetAddressSize(), m_decomposeFlags, m_version); } } len = instr.size; - return GetLowLevelILForInstruction(this, addr, il, instr, GetAddressSize(), m_decomposeFlags); + return GetLowLevelILForInstruction(this, addr, il, instr, GetAddressSize(), m_decomposeFlags, m_version); } virtual bool GetInstructionInfo(const uint8_t* data, uint64_t addr, size_t maxLen, InstructionInfo& result) override @@ -770,17 +792,38 @@ class MipsArchitecture: public Architecture virtual bool GetInstructionText(const uint8_t* data, uint64_t addr, size_t& len, vector& result) override { Instruction instr; - char operand[64]; + char operand[64] = {0}; + char operation[64] = {0}; char padding[9]; const char* reg = NULL; + char dest[5] = {0}; + int first_operand = 0; if (!Disassemble(data, addr, len, instr)) return false; len = instr.size; memset(padding, 0x20, sizeof(padding)); - const char* operation = get_operation(instr.operation); - if (operation == NULL) + const char* operation_name = get_operation(instr.operation); + if (operation_name == NULL) return false; + strlcpy(operation, operation_name, sizeof(operation)); + + if (instr.operands[0].operandClass == V_DEST) + { + char* p = dest; + if (instr.operands[0].reg & 8) + *p++ = 'x'; + if (instr.operands[0].reg & 4) + *p++ = 'y'; + if (instr.operands[0].reg & 2) + *p++ = 'z'; + if (instr.operands[0].reg & 1) + *p++ = 'w'; + *p = '\0'; + strcat(operation, "."); + strcat(operation, dest); + first_operand++; + } size_t operationLen = strlen(operation); if (operationLen < 8) @@ -792,15 +835,17 @@ class MipsArchitecture: public Architecture result.emplace_back(InstructionToken, operation); result.emplace_back(TextToken, padding); - for (size_t i = 0; i < MAX_OPERANDS; i++) + for (size_t i = first_operand; i < MAX_OPERANDS; i++) { if (instr.operands[i].operandClass == NONE) return true; + operand[0] = '\0'; + int32_t imm = instr.operands[i].immediate; uint64_t label_imm = instr.operands[i].immediate; - if (i != 0) + if (i != first_operand) result.emplace_back(OperandSeparatorToken, ", "); switch (instr.operands[i].operandClass) @@ -881,6 +926,114 @@ class MipsArchitecture: public Architecture result.emplace_back(BraceToken, ")"); result.emplace_back(EndMemoryOperandToken, ""); break; + case V_REG: + // #define V_FMT "$vf%02d" // Use this if leading zeroes are preferred + #define V_FMT "$vf%d" + reg = NULL; + if (instr.operands[i].reg >= REG_VP) + reg = get_register((Reg)instr.operands[i].reg); + if (reg != NULL) + { + char reg_tmp[sizeof(operand)] = {0}; + if (instr.operands[i].reg >= REG_VI0 && instr.operands[i].reg <= REG_VI15) + { + switch (instr.operation) + { + case MIPS_VISWR: + case MIPS_VILWR: + if (i == 2) + { + snprintf(reg_tmp, sizeof(reg_tmp), "(%s).%s", reg, dest); + reg = reg_tmp; + } + break; + case MIPS_VLQI: + case MIPS_VSQI: + snprintf(reg_tmp, sizeof(reg_tmp), "(%s++)", reg); + reg = reg_tmp; + break; + case MIPS_VLQD: + case MIPS_VSQD: + snprintf(reg_tmp, sizeof(reg_tmp), "(--%s)", reg); + reg = reg_tmp; + break; + default: + break; + } + } + if (reg == reg_tmp) + { + // Done + } + else if (instr.operands[i].reg >= REG_VF0 && instr.operands[i].reg <= REG_VF31) + { + if (instr.operands[i].immediate > 0 && instr.operands[i].immediate <= 4) + snprintf(operand, sizeof(operand), "%s.%c", + reg, + "xyzw"[instr.operands[i].immediate-1]); + else if (dest[0]) + snprintf(operand, sizeof(operand), "%s.%s", reg, dest); + } + if (!operand[0]) + snprintf(operand, sizeof(operand), "%s", reg); + } + // else if ((instr.operands[i].reg >= REG_VACC && instr.operands[i].reg <= REG_VI15) && + // (reg = get_register((Reg)instr.operands[i].reg)) != NULL) + // { + // // if (instr.operands[i].reg == REG_VACC && dest[0]) + // // snprintf(operand, sizeof(operand), "%s.%s", reg, dest); + // // else + // snprintf(operand, sizeof(operand), "%s", reg); + // } + else if (instr.operands[i].immediate > 0 && instr.operands[i].immediate <= 4) + snprintf(operand, sizeof(operand), V_FMT ".%c", + instr.operands[i].reg, + "xyzw"[instr.operands[i].immediate-1]); + else if (instr.operands[i].immediate == 'A') + { + if (dest[0]) + snprintf(operand, sizeof(operand), "ACC.%s", dest); + else + snprintf(operand, sizeof(operand), "ACC"); + } + else if (instr.operands[i].immediate > 'A' && instr.operands[i].immediate <= 'Z') + snprintf(operand, sizeof(operand), "%c", + (char) instr.operands[i].immediate); + else if (dest[0]) + snprintf(operand, sizeof(operand), V_FMT ".%s", + instr.operands[i].reg, dest); + else + snprintf(operand, sizeof(operand), V_FMT, instr.operands[i].reg); + result.emplace_back(RegisterToken, operand); + break; + case V_DEST: + { + char* p = dest; + if (*p == '\0' && (instr.operands[i].reg & 0xF) != 0) + { + if (instr.operands[i].reg & 8) + *p++ = 'x'; + if (instr.operands[i].reg & 4) + *p++ = 'y'; + if (instr.operands[i].reg & 2) + *p++ = 'z'; + if (instr.operands[i].reg & 1) + *p++ = 'w'; + *p = '\0'; + } + break; + } + case V_REG_FIELD: + { + snprintf(operand, sizeof(operand), V_FMT ".%c", + instr.operands[i].reg, + "xyzw"[instr.operands[i].immediate]); + // char *p = operand; + // *p++ = "xyzw"[instr.operands[i].reg]; + // *p = '\0'; + result.emplace_back(RegisterToken, operand); + break; + } default: LogError("operandClass %x\n", instr.operands[i].operandClass); return false; @@ -1002,6 +1155,21 @@ class MipsArchitecture: public Architecture return "_countOnes32"; case CNMIPS_INTRIN_DPOP: return "_countOnes64"; + + case MIPS_INTRIN_R5900_VWAITQ: + return "__vwaitq"; + case MIPS_INTRIN_R5900_VU_MEM_LOAD: + return "__vu_mem_load"; + case MIPS_INTRIN_R5900_VU_MEM_STORE: + return "__vu_mem_store"; + case MIPS_INTRIN_R5900_VU0_CALLMS: + return "__vu0_callms"; + case MIPS_INTRIN_R5900_VU0_CALLMSR: + return "__vu0_callmsr"; + + case MIPS_INTRIN_COP0_CONDITION: + return "__COP0Condition"; + default: return ""; } @@ -1009,7 +1177,7 @@ class MipsArchitecture: public Architecture virtual vector GetAllIntrinsics() override { - return vector{ + auto intrinsics = vector{ MIPS_INTRIN_WSBH, MIPS_INTRIN_DSBH, MIPS_INTRIN_DSHD, @@ -1061,6 +1229,18 @@ class MipsArchitecture: public Architecture CNMIPS_INTRIN_POP, CNMIPS_INTRIN_DPOP, }; + if (m_version == MIPS_R5900) + { + auto r5900_intrinsics = { + MIPS_INTRIN_R5900_VWAITQ, + MIPS_INTRIN_R5900_VU_MEM_LOAD, + MIPS_INTRIN_R5900_VU_MEM_STORE, + MIPS_INTRIN_R5900_VU0_CALLMS, + MIPS_INTRIN_R5900_VU0_CALLMSR, + }; + intrinsics.insert(intrinsics.end(), std::begin(r5900_intrinsics), std::end(r5900_intrinsics)); + } + return intrinsics; } virtual vector GetIntrinsicInputs(uint32_t intrinsic) override @@ -1217,6 +1397,29 @@ class MipsArchitecture: public Architecture return { NameAndType("index", Type::IntegerType(8, false)), }; + + case MIPS_INTRIN_R5900_VU_MEM_LOAD: + return { + NameAndType("offset", Type::IntegerType(4, false)), + NameAndType("field", Type::IntegerType(2, false)), + }; + case MIPS_INTRIN_R5900_VU_MEM_STORE: + return { + NameAndType("offset", Type::IntegerType(4, false)), + NameAndType("field", Type::IntegerType(2, false)), + NameAndType("value", Type::FloatType(4)), + }; + case MIPS_INTRIN_R5900_VU0_CALLMS: + return { + NameAndType("address", Type::IntegerType(4, false)), + }; + case MIPS_INTRIN_R5900_VU0_CALLMSR: + // return { + // NameAndType("reg", Type::IntegerType(4, false)), + // }; + + case MIPS_INTRIN_COP0_CONDITION: + case MIPS_INTRIN_R5900_VWAITQ: default: return vector(); } @@ -1273,6 +1476,16 @@ class MipsArchitecture: public Architecture }; case MIPS_INTRIN_TLBSEARCH: return { Type::IntegerType(8, false) }; + + case MIPS_INTRIN_R5900_VU_MEM_LOAD: + // return { Type::ArrayType(Type::FloatType(4), 4) }; + return { Type::FloatType(4) }; + case MIPS_INTRIN_COP0_CONDITION: + return { Type::BoolType() }; + case MIPS_INTRIN_R5900_VU_MEM_STORE: + case MIPS_INTRIN_R5900_VU0_CALLMS: + case MIPS_INTRIN_R5900_VU0_CALLMSR: + case MIPS_INTRIN_R5900_VWAITQ: default: return vector>>(); } @@ -1457,6 +1670,10 @@ class MipsArchitecture: public Architecture FPREG_F8, FPREG_F9, FPREG_F10, FPREG_F11, FPREG_F12, FPREG_F13, FPREG_F14, FPREG_F15, FPREG_F16, FPREG_F17, FPREG_F18, FPREG_F19, FPREG_F20, FPREG_F21, FPREG_F22, FPREG_F23, FPREG_F24, FPREG_F25, FPREG_F26, FPREG_F27, FPREG_F28, FPREG_F29, FPREG_F30, FPREG_F31, + FPREG_FCR0, FPREG_FCR1, FPREG_FCR2, FPREG_FCR3, FPREG_FCR4, FPREG_FCR5, FPREG_FCR6, FPREG_FCR7, + FPREG_FCR8, FPREG_FCR9, FPREG_FCR10, FPREG_FCR11, FPREG_FCR12, FPREG_FCR13, FPREG_FCR14, FPREG_FCR15, + FPREG_FCR16, FPREG_FCR17, FPREG_FCR18, FPREG_FCR19, FPREG_FCR20, FPREG_FCR21, FPREG_FCR22, FPREG_FCR23, + FPREG_FCR24, FPREG_FCR25, FPREG_FCR26, FPREG_FCR27, FPREG_FCR28, FPREG_FCR29, FPREG_FCR30, FPREG_FCR31, FPCCREG_FCC0, FPCCREG_FCC1, FPCCREG_FCC2, FPCCREG_FCC3, FPCCREG_FCC4, FPCCREG_FCC5, FPCCREG_FCC6, FPCCREG_FCC7, REG_LO, REG_HI, // Coprocessor 0 register 0 @@ -1561,7 +1778,32 @@ class MipsArchitecture: public Architecture REG_DESAVE, }; - if ((m_decomposeFlags & DECOMPOSE_FLAGS_CAVIUM) != 0) + if (m_version == MIPS_R5900) { + // TODO: R5900 has 128-bit wide GPRs, $lo and $hi are 128-bit, and $lo1 and $hi1 are the upper 64 bits of $lo and $hi + uint32_t r5900_registers[] = { + R5900_SA, + REG_LO1, REG_HI1, + + REG_VP, + + REG_VI0, REG_VI1, REG_VI2, REG_VI3, REG_VI4, REG_VI5, REG_VI6, REG_VI7, REG_VI8, REG_VI9, + REG_VI10, REG_VI11, REG_VI12, REG_VI13, REG_VI14, REG_VI15, + REG_VCCR_STATUS, REG_VCCR_MAC, REG_VCCR_CLIPPING, REG_VCCR_19, + REG_VR, // CCR[2,20] + REG_VI, // CCR[2,21] + REG_VQ, // CCR[2,22] + REG_VCCR_23, REG_VCCR_24, REG_VCCR_25, REG_VCCR_TPC, REG_VCCR_CMSAR0, + REG_VCCR_FBRST, REG_VCCR_VPU_STAT, REG_VCCR_30, REG_VCCR_CMSAR1, + + REG_VACC, + REG_VF0, REG_VF1, REG_VF2, REG_VF3, REG_VF4, REG_VF5, REG_VF6, REG_VF7, REG_VF8, REG_VF9, + REG_VF10, REG_VF11, REG_VF12, REG_VF13, REG_VF14, REG_VF15, REG_VF16, REG_VF17, REG_VF18, REG_VF19, + REG_VF20, REG_VF21, REG_VF22, REG_VF23, REG_VF24, REG_VF25, REG_VF26, REG_VF27, REG_VF28, REG_VF29, + REG_VF30, REG_VF31, + }; + registers.insert(registers.end(), std::begin(r5900_registers), std::end(r5900_registers)); + } + else if ((m_decomposeFlags & DECOMPOSE_FLAGS_CAVIUM) != 0) { uint32_t cavium_registers[] = { @@ -1776,6 +2018,11 @@ class MipsArchitecture: public Architecture FPREG_F8, FPREG_F9, FPREG_F10, FPREG_F11, FPREG_F12, FPREG_F13, FPREG_F14, FPREG_F15, FPREG_F16, FPREG_F17, FPREG_F18, FPREG_F19, FPREG_F20, FPREG_F21, FPREG_F22, FPREG_F23, FPREG_F24, FPREG_F25, FPREG_F26, FPREG_F27, FPREG_F28, FPREG_F29, FPREG_F30, FPREG_F31, + FPREG_FCR0, FPREG_FCR1, FPREG_FCR2, FPREG_FCR3, FPREG_FCR4, FPREG_FCR5, FPREG_FCR6, FPREG_FCR7, + FPREG_FCR8, FPREG_FCR9, FPREG_FCR10, FPREG_FCR11, FPREG_FCR12, FPREG_FCR13, FPREG_FCR14, FPREG_FCR15, + FPREG_FCR16, FPREG_FCR17, FPREG_FCR18, FPREG_FCR19, FPREG_FCR20, FPREG_FCR21, FPREG_FCR22, FPREG_FCR23, + FPREG_FCR24, FPREG_FCR25, FPREG_FCR26, FPREG_FCR27, FPREG_FCR28, FPREG_FCR29, FPREG_FCR30, FPREG_FCR31, + REG_LO, REG_HI, // Coprocessor 0 register 0 REG_INDEX, @@ -1879,7 +2126,39 @@ class MipsArchitecture: public Architecture REG_DESAVE, }; - if ((m_decomposeFlags & DECOMPOSE_FLAGS_CAVIUM) != 0) + if (m_version == MIPS_R5900) { + // TODO: R5900 has 128-bit wide GPRs, $lo and $hi are 128-bit, and $lo1 and $hi1 are the upper 64 bits of $lo and $hi + uint32_t r5900_registers[] = { + R5900_SA, + REG_LO1, REG_HI1, + REG_VP, + + REG_VI0, REG_VI1, REG_VI2, REG_VI3, REG_VI4, REG_VI5, REG_VI6, REG_VI7, REG_VI8, REG_VI9, + REG_VI10, REG_VI11, REG_VI12, REG_VI13, REG_VI14, REG_VI15, + REG_VCCR_STATUS, REG_VCCR_MAC, REG_VCCR_CLIPPING, REG_VCCR_19, + REG_VR, // CCR[2,20] + REG_VI, // CCR[2,21] + REG_VQ, // CCR[2,22] + REG_VCCR_23, REG_VCCR_24, REG_VCCR_25, REG_VCCR_TPC, REG_VCCR_CMSAR0, + REG_VCCR_FBRST, REG_VCCR_VPU_STAT, REG_VCCR_30, REG_VCCR_CMSAR1, + + REG_VACC, + REG_VF0, REG_VF1, REG_VF2, REG_VF3, REG_VF4, REG_VF5, REG_VF6, REG_VF7, REG_VF8, REG_VF9, + REG_VF10, REG_VF11, REG_VF12, REG_VF13, REG_VF14, REG_VF15, REG_VF16, REG_VF17, REG_VF18, REG_VF19, + REG_VF20, REG_VF21, REG_VF22, REG_VF23, REG_VF24, REG_VF25, REG_VF26, REG_VF27, REG_VF28, REG_VF29, + REG_VF30, REG_VF31, + }; + registers.insert(registers.end(), std::begin(r5900_registers), std::end(r5900_registers)); + constexpr auto _r5900_registers_vpu = []() { + vector registers; + for (uint32_t i = REG_VACC_X; i < REG_VF31_XYZW; i++) + registers.push_back((Reg) i); + return registers; + }; + auto r5900_registers_vpu = _r5900_registers_vpu(); + registers.insert(registers.end(), r5900_registers_vpu.begin(), r5900_registers_vpu.end()); + } + else if ((m_decomposeFlags & DECOMPOSE_FLAGS_CAVIUM) != 0) { uint32_t cavium_registers[] = { @@ -2089,6 +2368,45 @@ class MipsArchitecture: public Architecture virtual BNRegisterInfo GetRegisterInfo(uint32_t reg) override { BNRegisterInfo result = {reg, 0, m_bits / 8, NoExtend}; + if (m_version == MIPS_R5900) { + result.size = get_register_width(reg, m_version, 16); + switch (reg) { + // case REG_LO: + // case REG_HI: + // result.size = 64 / 8; + // break; + case REG_LO1: + case REG_HI1: + // result.size = (128 / 2); + result.offset = 8; + if (reg == REG_LO1) + result.fullWidthRegister = REG_LO; + else if (reg == REG_HI1) + result.fullWidthRegister = REG_HI; + break; + default: + if (reg >= REG_VACC_X && reg <= REG_VF31_XYZW) + { + result.fullWidthRegister = REG_VACC + ((reg - REG_VACC_X) % 33); + if (reg >= REG_VACC_Y && reg <= REG_VF31_Y) + result.offset = 4; + else if (reg >= REG_VACC_Z && reg <= REG_VF31_Z) + result.offset = 8; + else if (reg >= REG_VACC_W && reg <= REG_VF31_W) + result.offset = 12; + + else if (reg >= REG_VACC_YZ && reg <= REG_VF31_YZ) + result.offset = 4; + else if (reg >= REG_VACC_ZW && reg <= REG_VF31_ZW) + result.offset = 12; + + else if (reg >= REG_VACC_YZW && reg <= REG_VF31_YZW) + result.offset = 4; + + // XXX: offsets are just wrong for discontinuous registers: XZ, XW, YW, XYW, XZW + } + } + } return result; } @@ -2408,6 +2726,9 @@ class MipsArchitecture: public Architecture return registers; } + MipsVersion GetMIPSVersion() { + return m_version; + } }; class MipsO32CallingConvention: public CallingConvention @@ -2471,6 +2792,77 @@ class MipsO32CallingConvention: public CallingConvention } }; +class MipsPS2CallingConvention: public CallingConvention +{ +public: + MipsPS2CallingConvention(Architecture* arch): CallingConvention(arch, "ps2") + { + } + virtual uint32_t GetIntegerReturnValueRegister() override + { + return REG_V0; + } + + virtual uint32_t GetHighIntegerReturnValueRegister() override + { + return REG_V1; + } + + virtual vector GetIntegerArgumentRegisters() override + { + return vector{ REG_A0, REG_A1, REG_A2, REG_A3, REG_T0, REG_T1, REG_T2, REG_T3 }; + } + + virtual vector GetFloatArgumentRegisters() override + { + return vector{ FPREG_F12, FPREG_F13, FPREG_F14, FPREG_F15, FPREG_F16, FPREG_F17, FPREG_F18, FPREG_F19 }; + } + + virtual uint32_t GetFloatReturnValueRegister() override + { + return FPREG_F0; + } + + virtual bool IsStackReservedForArgumentRegisters() override + { + return true; + } + + virtual vector GetCallerSavedRegisters() override + { + return vector { REG_AT, REG_V0, REG_V1, REG_A0, REG_A1, REG_A2, REG_A3, REG_T0, REG_T1, + REG_T2, REG_T3, REG_T4, REG_T5, REG_T6, REG_T7, REG_T8, REG_T9 }; + } + + virtual vector GetCalleeSavedRegisters() override + { + return vector { REG_S0, REG_S1, REG_S2, REG_S3, REG_S4, REG_S5, REG_S6, REG_S7, + REG_GP, REG_FP, FPREG_F20, FPREG_F21, FPREG_F22, FPREG_F23, FPREG_F24, FPREG_F25, + FPREG_F26, FPREG_F27, FPREG_F28, FPREG_F29, FPREG_F30, FPREG_F31 }; + } + + virtual uint32_t GetGlobalPointerRegister() override + { + return REG_GP; + } + + virtual vector GetImplicitlyDefinedRegisters() override + { + return vector { REG_T9 }; + } + + virtual RegisterValue GetIncomingRegisterValue(uint32_t reg, Function* func) override + { + RegisterValue result; + if (reg == REG_T9) + { + result.state = ConstantPointerValue; + result.value = func->GetStart(); + } + return result; + } +}; + class MipsN64CallingConvention: public CallingConvention { public: @@ -3013,7 +3405,8 @@ class MipsElfRelocationHandler: public RelocationHandler uint32_t inst2 = *(uint32_t*)(cur->relocationDataCache); Instruction instruction; memset(&instruction, 0, sizeof(instruction)); - if (mips_decompose(&inst2, sizeof(uint32_t), &instruction, arch->GetAddressSize() == 8 ? MIPS_64 : MIPS_32, cur->address, arch->GetEndianness(), DECOMPOSE_FLAGS_PSEUDO_OP)) + MipsArchitecture& march = dynamic_cast(*arch); + if (mips_decompose(&inst2, sizeof(uint32_t), &instruction, march.GetMIPSVersion(), cur->address, arch->GetEndianness(), DECOMPOSE_FLAGS_PSEUDO_OP)) break; int32_t immediate = swap(inst2) & 0xffff; @@ -3077,6 +3470,7 @@ class MipsElfRelocationHandler: public RelocationHandler dest64[0] = swap64(originalValue + displacement); break; } + case R_MIPS_LITERAL: case R_MIPS_GPREL32: { if (!GetGpAddr(view, gpAddr)) @@ -3085,6 +3479,8 @@ class MipsElfRelocationHandler: public RelocationHandler dest32[0] = swap(vRel32); break; } + case R_MIPS_VCALLMS: + break; default: break; } @@ -3164,6 +3560,10 @@ class MipsElfRelocationHandler: public RelocationHandler case R_MIPS_HIGHER: case R_MIPS_HIGHEST: break; + case R_MIPS_VCALLMS: + break; + case R_MIPS_LITERAL: + break; default: result[i].type = UnhandledRelocation; LogWarn("Unsupported relocation type: %llu (%s) @0x%llX", result[i].nativeType, @@ -3190,8 +3590,6 @@ class MipsElfRelocationHandler: public RelocationHandler case R_MIPS_LO16: case R_MIPS_CALL16: case R_MIPS_GOT16: - case R_MIPS_HIGHER: - case R_MIPS_HIGHEST: result = BN_NOCOERCE_EXTERN_PTR; break; default: @@ -3262,16 +3660,20 @@ extern "C" { InitMipsSettings(); - Architecture* mipseb = new MipsArchitecture("mips32", BigEndian, 32, MIPS_32); - Architecture* mipsel = new MipsArchitecture("mipsel32", LittleEndian, 32, MIPS_32); - Architecture* mips3 = new MipsArchitecture("mips3", BigEndian, 32, MIPS_3); - Architecture* mips3el = new MipsArchitecture("mipsel3", LittleEndian, 32, MIPS_3); - Architecture* mips64el = new MipsArchitecture("mipsel64", LittleEndian, 64, MIPS_64); - Architecture* mips64eb = new MipsArchitecture("mips64", BigEndian, 64, MIPS_64); - Architecture* cnmips64eb = new MipsArchitecture("cavium-mips64", BigEndian, 64, MIPS_64, DECOMPOSE_FLAGS_CAVIUM); + Architecture* mipsel = new MipsArchitecture("mipsel32", MIPS_32, LittleEndian, 32); + Architecture* mipseb = new MipsArchitecture("mips32", MIPS_32, BigEndian, 32); + Architecture* mips3 = new MipsArchitecture("mips3", MIPS_3, BigEndian, 32); + Architecture* mips3el = new MipsArchitecture("mipsel3", MIPS_3, LittleEndian, 32); + Architecture* mips64el = new MipsArchitecture("mipsel64", MIPS_64, LittleEndian, 64); + Architecture* mips64eb = new MipsArchitecture("mips64", MIPS_64, BigEndian, 64); + Architecture* cnmips64eb = new MipsArchitecture("cavium-mips64", MIPS_64, BigEndian, 64, DECOMPOSE_FLAGS_CAVIUM); + Architecture* r5900l = new MipsArchitecture("r5900l", MIPS_R5900, LittleEndian, 32); + Architecture* r5900b = new MipsArchitecture("r5900b", MIPS_R5900, BigEndian, 32); - Architecture::Register(mipseb); Architecture::Register(mipsel); + Architecture::Register(mipseb); + Architecture::Register(r5900l); + Architecture::Register(r5900b); Architecture::Register(mips3); Architecture::Register(mips3el); Architecture::Register(mips64el); @@ -3284,6 +3686,8 @@ extern "C" MipsN64CallingConvention* n64LE = new MipsN64CallingConvention(mips64el); MipsN64CallingConvention* n64BE = new MipsN64CallingConvention(mips64eb); MipsN64CallingConvention* n64BEc = new MipsN64CallingConvention(cnmips64eb); + MipsPS2CallingConvention* ps2LE = new MipsPS2CallingConvention(r5900l); + MipsPS2CallingConvention* ps2BE = new MipsPS2CallingConvention(r5900b); mipseb->RegisterCallingConvention(o32BE); mipseb->SetDefaultCallingConvention(o32BE); @@ -3291,24 +3695,36 @@ extern "C" mipsel->SetDefaultCallingConvention(o32LE); mips3->RegisterCallingConvention(o32BE); mips3->SetDefaultCallingConvention(o32BE); - mips3->RegisterCallingConvention(o32LE); - mips3->SetDefaultCallingConvention(o32LE); + mips3el->RegisterCallingConvention(o32LE); + mips3el->SetDefaultCallingConvention(o32LE); mips64el->RegisterCallingConvention(n64LE); mips64el->SetDefaultCallingConvention(n64LE); mips64eb->RegisterCallingConvention(n64BE); mips64eb->SetDefaultCallingConvention(n64BE); cnmips64eb->RegisterCallingConvention(n64BEc); cnmips64eb->SetDefaultCallingConvention(n64BEc); + r5900l->RegisterCallingConvention(ps2LE); + r5900l->SetDefaultCallingConvention(ps2LE); + r5900b->RegisterCallingConvention(ps2BE); + r5900b->SetDefaultCallingConvention(ps2BE); - MipsLinuxSyscallCallingConvention* linuxSyscallLE = new MipsLinuxSyscallCallingConvention(mipsel); MipsLinuxSyscallCallingConvention* linuxSyscallBE = new MipsLinuxSyscallCallingConvention(mipseb); + MipsLinuxSyscallCallingConvention* linuxSyscallLE = new MipsLinuxSyscallCallingConvention(mipsel); mipseb->RegisterCallingConvention(linuxSyscallBE); mipsel->RegisterCallingConvention(linuxSyscallLE); + MipsLinuxSyscallCallingConvention* linuxSyscallBE3 = new MipsLinuxSyscallCallingConvention(mips3); + MipsLinuxSyscallCallingConvention* linuxSyscallLE3 = new MipsLinuxSyscallCallingConvention(mips3el); mips3->RegisterCallingConvention(linuxSyscallBE); mips3el->RegisterCallingConvention(linuxSyscallLE); + MipsLinuxSyscallCallingConvention* linuxSyscallr5900LE = new MipsLinuxSyscallCallingConvention(r5900l); + MipsLinuxSyscallCallingConvention* linuxSyscallr5900BE = new MipsLinuxSyscallCallingConvention(r5900b); + r5900l->RegisterCallingConvention(linuxSyscallr5900LE); + r5900b->RegisterCallingConvention(linuxSyscallr5900BE); - mipseb->RegisterCallingConvention(new MipsLinuxRtlResolveCallingConvention(mipseb)); mipsel->RegisterCallingConvention(new MipsLinuxRtlResolveCallingConvention(mipsel)); + mipseb->RegisterCallingConvention(new MipsLinuxRtlResolveCallingConvention(mipseb)); + r5900l->RegisterCallingConvention(new MipsLinuxRtlResolveCallingConvention(r5900l)); + r5900b->RegisterCallingConvention(new MipsLinuxRtlResolveCallingConvention(r5900b)); mips3->RegisterCallingConvention(new MipsLinuxRtlResolveCallingConvention(mips3)); mips3el->RegisterCallingConvention(new MipsLinuxRtlResolveCallingConvention(mips3el)); mips64el->RegisterCallingConvention(new MipsLinuxRtlResolveCallingConvention(mips64el)); @@ -3316,8 +3732,8 @@ extern "C" cnmips64eb->RegisterCallingConvention(new MipsLinuxRtlResolveCallingConvention(cnmips64eb)); /* function recognizers */ - mipseb->RegisterFunctionRecognizer(new MipsImportedFunctionRecognizer()); mipsel->RegisterFunctionRecognizer(new MipsImportedFunctionRecognizer()); + mipseb->RegisterFunctionRecognizer(new MipsImportedFunctionRecognizer()); mips3->RegisterFunctionRecognizer(new MipsImportedFunctionRecognizer()); mips3el->RegisterFunctionRecognizer(new MipsImportedFunctionRecognizer()); @@ -3325,8 +3741,10 @@ extern "C" mipsel->RegisterRelocationHandler("ELF", new MipsElfRelocationHandler()); mips3->RegisterRelocationHandler("ELF", new MipsElfRelocationHandler()); mips3el->RegisterRelocationHandler("ELF", new MipsElfRelocationHandler()); - mips64el->RegisterRelocationHandler("ELF", new MipsElfRelocationHandler()); mips64eb->RegisterRelocationHandler("ELF", new MipsElfRelocationHandler()); + mips64el->RegisterRelocationHandler("ELF", new MipsElfRelocationHandler()); + r5900l->RegisterRelocationHandler("ELF", new MipsElfRelocationHandler()); + r5900b->RegisterRelocationHandler("ELF", new MipsElfRelocationHandler()); cnmips64eb->RegisterRelocationHandler("ELF", new MipsElfRelocationHandler()); // Register the architectures with the binary format parsers so that they know when to use diff --git a/arch/mips/il.cpp b/arch/mips/il.cpp index 331d3d1380..d0e14ee79b 100644 --- a/arch/mips/il.cpp +++ b/arch/mips/il.cpp @@ -1,5 +1,7 @@ #include "il.h" +#include "mips.h" + using namespace BinaryNinja; using namespace mips; @@ -61,6 +63,301 @@ static void ConditionExecute(LowLevelILFunction& il, ExprId cond, ExprId trueCas return; } +static void SaturatingAddSub(LowLevelILFunction& il, Instruction& instr, bool saturate, bool signedFlag, size_t bytes, bool subtract=false) +{ + // Perform saturating addition by applying the optimizations from https://web.archive.org/web/20190213215419/https://locklessinc.com/articles/sat_arithmetic/ + // TODO: optimize signed case by applying above link + InstructionOperand& op1 = instr.operands[0]; // rd + InstructionOperand& op2 = instr.operands[1]; // rs + InstructionOperand& op3 = instr.operands[2]; // rt + + auto signExtend = signedFlag ? SignExtend : ZeroExtend; + + + // Simple case: if either rs or rt is $zero, then it's equivalent to a 128-bit move + if (op3.reg == REG_ZERO) + { + // (If both are, then it's a 128-bit clear) + if (op2.reg == REG_ZERO) + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Const(16, 0), signExtend)); + else + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, op2.reg), signExtend)); + return; + } + else if (op2.reg == REG_ZERO) + { + if (!subtract) + { + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, op3.reg), signExtend)); + return; + } + else + { + // This cannot be done by a single negation, so let the code below handle it + } + } + // else + { + // Mask of the appropriate size for the pieces of rs and rd + const uint64_t mask = 0xFFFFFFFFFFFFFFFF >> (64 - (8 * bytes)); + + // Perform the appropriate number of piecewise additions, saturating if needed, then combine into the rd register + for (int i = 0; i < 16 / bytes; i++) + { + // How much to shift the piece + size_t shift = i * 8 * bytes; + ExprId rs_shifted = il.Register(16, op2.reg); + ExprId rt_shifted = il.Register(16, op3.reg); + + // Only need to shift if it's not the lowest-order piece + if (i > 0) + { + rs_shifted = il.LogicalShiftRight( 16, rs_shifted, il.Const(1, shift)); + rt_shifted = il.LogicalShiftRight( 16, rt_shifted, il.Const(1, shift)); + } + + // Mask the (shifted) piece to the appropriate size + rs_shifted = il.And(bytes, rs_shifted, il.Const(128, mask)); + rt_shifted = il.And(bytes, rt_shifted, il.Const(128, mask)); + + ExprId sum = 0; + + if (!saturate) + { + // Non-saturating add/sub is just add/sub ignoring overflows (sign is actually irrelevant) + if (!subtract) + sum = il.And(bytes, il.Add(bytes, rs_shifted, rt_shifted), il.Const(bytes, mask)); + else + sum = il.And(bytes, il.Sub(bytes, rs_shifted, rt_shifted), il.Const(bytes, mask)); + } + else + { + if (signedFlag) + { + rs_shifted = il.SignExtend(2 * bytes, rs_shifted); + rt_shifted = il.SignExtend(2 * bytes, rt_shifted); + } + else + { + rs_shifted = il.ZeroExtend(2 * bytes, rs_shifted); + rt_shifted = il.ZeroExtend(2 * bytes, rt_shifted); + + // For the unsigned case, we need to use the shifted and masked rs sub-value more than once so save it in temp0 + il.AddInstruction(il.SetRegister(2 * bytes, LLIL_TEMP(0), rs_shifted)); + rs_shifted = il.Register(2 * bytes, LLIL_TEMP(0)); + } + // This is an n-byte add, but if the sum is greater than 0xFFFFFFFF >> (32 - 8*n), the result is 0xFFFFFFFF >> (4-n) + // (Saturation for the signed case is more complicated, but the initial addition is the same) + // So we do a 2n-byte add and saturate the result if necessary + ExprId add_sub = 0; + if (!subtract) + add_sub = il.Add(2 * bytes, + rs_shifted, + rt_shifted); + else + add_sub = il.Sub(2 * bytes, + rs_shifted, + rt_shifted); + il.AddInstruction(il.SetRegister(2 * bytes, + LLIL_TEMP(1), + add_sub)); + + if (!signedFlag) + { + if (!subtract) + { + ExprId comparison = il.CompareUnsignedLessThan(bytes, + il.Register(bytes, LLIL_TEMP(1)), + il.Register(bytes, LLIL_TEMP(0))); + sum = il.Or(bytes, + il.Register(bytes, LLIL_TEMP(1)), + il.Neg(bytes, + il.BoolToInt(bytes, + comparison))); + } + else + { + ExprId comparison = il.CompareUnsignedLessEqual(bytes, + il.Register(bytes, LLIL_TEMP(1)), + il.Register(bytes, LLIL_TEMP(0))); + sum = il.And(bytes, + il.Register(bytes, LLIL_TEMP(1)), + il.Neg(bytes, + il.BoolToInt(bytes, + comparison))); + } + } + else + { + // bv.write(here, b'\x28\x26\x41\x70') # paddub + // bv.write(here, b'\x08\x22\x41\x70') # paddb + // bv.write(here, b'\x08\x26\x41\x70') # paddsb + // + // bv.write(here, b'\x28\x25\x41\x70') # padduh + // bv.write(here, b'\x08\x21\x41\x70') # paddh + // bv.write(here, b'\x08\x25\x41\x70') # paddsh + // + // bv.write(here, b'\x28\x24\x41\x70') # padduw + // bv.write(here, b'\x08\x20\x41\x70') # paddw + // bv.write(here, b'\x08\x24\x41\x70') # paddsw + + uint64_t clamp_overflow = 0x7FFFFFFF >> (32 - (8 * bytes)); + uint64_t clamp_under_lower_bound = 0x100000000 >> (32 - (8 * bytes)); + uint64_t clamp_under_upper_bound = 0x180000000 >> (32 - (8 * bytes)); + // uint64_t clamp4 = 0x80000000 >> (32 - (8 * bytes)); // clamp3 - clamp2 + uint64_t clamp_underflow = clamp_under_upper_bound - clamp_under_lower_bound; + + // Note: the Operation definition shows the overflow check before the underflow check, but + // that would mean an underflow would be detected as an overflow, and the underflow clamp + // would never be applied. So we do the underflow check first, under the assumption the + // reference manual is incorrect but the implementation in hardware would be correct. + + auto comparison_underflow = il.And(1, + il.CompareSignedGreaterThan(2 * bytes, + il.Register(2 * bytes, LLIL_TEMP(1)), + il.Const(2 * bytes, clamp_under_lower_bound)), + il.CompareSignedLessThan(bytes, + il.Register(2 * bytes, LLIL_TEMP(1)), + il.Const(2 * bytes, clamp_under_upper_bound))); + auto comparison_overflow = il.CompareSignedGreaterThan(bytes, + il.Register(2 * bytes, LLIL_TEMP(1)), + il.Const(2 * bytes, clamp_overflow)); + + LowLevelILLabel trueCase1, trueCase2, falseCase1, falseCase2, done; + il.AddInstruction(il.If(comparison_underflow, trueCase1, falseCase1)); + + il.MarkLabel(trueCase1); + il.AddInstruction(il.SetRegister(bytes, LLIL_TEMP(1), il.Const(bytes, clamp_underflow))); + il.AddInstruction(il.Goto(done)); + + il.MarkLabel(falseCase1); + il.AddInstruction(il.If(comparison_overflow, trueCase2, done)); + + il.MarkLabel(trueCase2); + il.AddInstruction(il.SetRegister(bytes, LLIL_TEMP(1), il.Const(bytes, clamp_overflow))); + + il.MarkLabel(done); + + sum = il.Register(bytes, LLIL_TEMP(1)); + + } + } + + auto shifted_sum = i == 0 ? sum : il.ShiftLeft(16, sum, il.Const(1, shift)); + if (i == 0) + { + il.AddInstruction(il.SetRegister(16, op1.reg, shifted_sum)); + } + else + { + il.AddInstruction(il.SetRegister(16, op1.reg, il.Or(16, il.Register(16, op1.reg), shifted_sum))); + } + } + } +} + +static void ParallelMinMax(LowLevelILFunction& il, Instruction& instr, size_t bytes, bool max=false) +{ + // Perform saturating addition by applying the optimizations from https://web.archive.org/web/20190213215419/https://locklessinc.com/articles/sat_arithmetic/ + // TODO: optimize signed case by applying above link + InstructionOperand& op1 = instr.operands[0]; // rd + InstructionOperand& op2 = instr.operands[1]; // rs + InstructionOperand& op3 = instr.operands[2]; // rt + + // Simple case: if either rs or rt is $zero, then it's equivalent to a 128-bit move + if (op3.reg == REG_ZERO && op2.reg == REG_ZERO) + il.AddInstruction(il.SetRegister(16, op1.reg, il.Const(16, 0))); + else + { + // Mask of the appropriate size for the pieces of rs and rd + const uint64_t mask = 0xFFFFFFFFFFFFFFFF >> (64 - (8 * bytes)); + + // Perform the appropriate number of piecewise additions, saturating if needed, then combine into the rd register + for (int i = 0; i < 16 / bytes; i++) + { + // How much to shift the piece + size_t shift = i * 8 * bytes; + ExprId rs_shifted = op2.reg != REG_ZERO ? il.Register(16, op2.reg) : il.Const(bytes, 0); + ExprId rt_shifted = op3.reg != REG_ZERO ? il.Register(16, op3.reg) : il.Const(bytes, 0); + + // Only need to shift if it's not the lowest-order piece + if (i > 0) + { + if (op2.reg != REG_ZERO) + rs_shifted = il.LogicalShiftRight( 16, rs_shifted, il.Const(1, shift)); + if (op3.reg != REG_ZERO) + rt_shifted = il.LogicalShiftRight( 16, rt_shifted, il.Const(1, shift)); + } + + // Mask the (shifted) piece to the appropriate size + if (op2.reg != REG_ZERO) + rs_shifted = il.And(bytes, rs_shifted, il.Const(128, mask)); + if (op3.reg != REG_ZERO) + rt_shifted = il.And(bytes, rt_shifted, il.Const(128, mask)); + + if (i == 0) + il.AddInstruction(il.SetRegister(16, LLIL_TEMP(2), il.Const(bytes, 0))); + + ExprId lhs = op2.reg != REG_ZERO ? il.Register(bytes, LLIL_TEMP(0)) : il.Const(bytes, 0); + ExprId rhs = op3.reg != REG_ZERO ? il.Register(bytes, LLIL_TEMP(1)) : il.Const(bytes, 0); + // if (op2.reg != REG_ZERO) + il.AddInstruction(il.SetRegister(bytes, LLIL_TEMP(0), rs_shifted)); + // if (op3.reg != REG_ZERO) + il.AddInstruction(il.SetRegister(bytes, LLIL_TEMP(1), rt_shifted)); + if (!max) + ConditionExecute(il, + il.CompareSignedLessThan(bytes, + // il.Register(bytes, LLIL_TEMP(0)), + // il.Register(bytes, LLIL_TEMP(1))), + lhs, rhs), + il.SetRegister(bytes, LLIL_TEMP(1), lhs)); + // il.SetRegister(bytes, LLIL_TEMP(1), il.Register(bytes, LLIL_TEMP(0)))); + else + ConditionExecute(il, + il.CompareSignedGreaterThan(bytes, + // il.Register(bytes, LLIL_TEMP(0)), + // il.Register(bytes, LLIL_TEMP(1))), + lhs, rhs), + il.SetRegister(bytes, LLIL_TEMP(1), lhs)); + // il.SetRegister(bytes, LLIL_TEMP(1), il.Register(bytes, LLIL_TEMP(0)))); + ExprId sum = il.Register(bytes, LLIL_TEMP(1)); + // // ExprId lhs = op2.reg != REG_ZERO ? il.Register(bytes, LLIL_TEMP(0)) : il.Const(bytes, 0); + // // ExprId rhs = op3.reg != REG_ZERO ? il.Register(bytes, LLIL_TEMP(1)) : il.Const(bytes, 0); + // // if (op2.reg != REG_ZERO) + // il.AddInstruction(il.SetRegister(bytes, LLIL_TEMP(0), rs_shifted)); + // // if (op3.reg != REG_ZERO) + // il.AddInstruction(il.SetRegister(bytes, LLIL_TEMP(1), rt_shifted)); + // if (!max) + // ConditionExecute(il, + // il.CompareSignedLessThan(bytes, + // il.Register(bytes, LLIL_TEMP(0)), + // il.Register(bytes, LLIL_TEMP(1))), + // // lhs, rhs), + // // il.SetRegister(bytes, LLIL_TEMP(1), lhs)); + // il.SetRegister(bytes, LLIL_TEMP(1), il.Register(bytes, LLIL_TEMP(0)))); + // else + // ConditionExecute(il, + // il.CompareSignedGreaterThan(bytes, + // il.Register(bytes, LLIL_TEMP(0)), + // il.Register(bytes, LLIL_TEMP(1))), + // // lhs, rhs), + // // il.SetRegister(bytes, LLIL_TEMP(1), lhs)); + // il.SetRegister(bytes, LLIL_TEMP(1), il.Register(bytes, LLIL_TEMP(0)))); + // ExprId sum = il.Register(bytes, LLIL_TEMP(1)); + + auto shifted_sum = i == 0 ? sum : il.ShiftLeft(16, sum, il.Const(1, shift)); + if (i == 0) + { + il.AddInstruction(il.SetRegister(16, LLIL_TEMP(2), shifted_sum)); + } + else + { + il.AddInstruction(il.SetRegister(16, LLIL_TEMP(2), il.Or(16, il.Register(16, LLIL_TEMP(2)), shifted_sum))); + } + } + il.AddInstruction(il.SetRegister(16, op1.reg, il.Register(16, LLIL_TEMP(2)))); + } +} static size_t GetILOperandMemoryAddress(LowLevelILFunction& il, InstructionOperand& operand, size_t addrSize, int32_t delta=0) { @@ -188,34 +485,40 @@ static void ConditionalJump(Architecture* arch, LowLevelILFunction& il, size_t c il.AddInstruction(il.Jump(il.ConstPointer(addrSize, f))); } -ExprId GetConditionForInstruction(LowLevelILFunction& il, Instruction& instr, size_t registerSize) +ExprId GetConditionForInstruction(LowLevelILFunction& il, Instruction& instr, std::function registerSize) { + InstructionOperand& op1 = instr.operands[0]; + InstructionOperand& op2 = instr.operands[1]; + InstructionOperand& op3 = instr.operands[2]; + InstructionOperand& op4 = instr.operands[3]; + (void) op3; + (void) op4; switch (instr.operation) { case MIPS_BEQ: case MIPS_BEQL: - return il.CompareEqual(registerSize, ReadILOperand(il, instr, 1, registerSize), ReadILOperand(il, instr, 2, registerSize)); + return il.CompareEqual(registerSize(op1), ReadILOperand(il, instr, 1, registerSize(op1)), ReadILOperand(il, instr, 2, registerSize(op2))); case MIPS_BNE: case MIPS_BNEL: - return il.CompareNotEqual(registerSize, ReadILOperand(il, instr, 1, registerSize), ReadILOperand(il, instr, 2, registerSize)); + return il.CompareNotEqual(registerSize(op1), ReadILOperand(il, instr, 1, registerSize(op1)), ReadILOperand(il, instr, 2, registerSize(op2))); case MIPS_BEQZ: - return il.CompareEqual(registerSize, ReadILOperand(il, instr, 1, registerSize), il.Const(registerSize, 0)); + return il.CompareEqual(registerSize(op1), ReadILOperand(il, instr, 1, registerSize(op1)), il.Const(registerSize(op1), 0)); case MIPS_BNEZ: - return il.CompareNotEqual(registerSize, ReadILOperand(il, instr, 1, registerSize), il.Const(registerSize, 0)); + return il.CompareNotEqual(registerSize(op1), ReadILOperand(il, instr, 1, registerSize(op1)), il.Const(registerSize(op1), 0)); case MIPS_BGEZ: case MIPS_BGEZL: case MIPS_BGEZAL: - return il.CompareSignedGreaterEqual(registerSize, ReadILOperand(il, instr, 1, registerSize), il.Const(registerSize, 0)); + return il.CompareSignedGreaterEqual(registerSize(op1), ReadILOperand(il, instr, 1, registerSize(op1)), il.Const(registerSize(op1), 0)); case MIPS_BGTZ: case MIPS_BGTZL: - return il.CompareSignedGreaterThan(registerSize, ReadILOperand(il, instr, 1, registerSize), il.Const(registerSize, 0)); + return il.CompareSignedGreaterThan(registerSize(op1), ReadILOperand(il, instr, 1, registerSize(op1)), il.Const(registerSize(op1), 0)); case MIPS_BLEZ: case MIPS_BLEZL: - return il.CompareSignedLessEqual(registerSize, ReadILOperand(il, instr, 1, registerSize), il.Const(registerSize, 0)); + return il.CompareSignedLessEqual(registerSize(op1), ReadILOperand(il, instr, 1, registerSize(op1)), il.Const(registerSize(op1), 0)); case MIPS_BLTZ: case MIPS_BLTZL: case MIPS_BLTZAL: - return il.CompareSignedLessThan(registerSize, ReadILOperand(il, instr, 1, registerSize), il.Const(registerSize, 0)); + return il.CompareSignedLessThan(registerSize(op1), ReadILOperand(il, instr, 1, registerSize(op1)), il.Const(registerSize(op1), 0)); case MIPS_BC1F: case MIPS_BC1FL: if (instr.operands[0].operandClass == FLAG) @@ -226,37 +529,49 @@ ExprId GetConditionForInstruction(LowLevelILFunction& il, Instruction& instr, si if (instr.operands[0].operandClass == FLAG) return il.Flag(instr.operands[0].reg); return il.Flag(FPCCREG_FCC0); + case MIPS_BC0F: + case MIPS_BC0FL: + return il.Not(0, il.Flag(CCREG_COC0)); + case MIPS_BC0T: + case MIPS_BC0TL: + return il.Flag(CCREG_COC0); + case MIPS_BC2F: + case MIPS_BC2FL: + return il.Not(0, il.Flag(CCREG_COC2)); + case MIPS_BC2T: + case MIPS_BC2TL: + return il.Flag(CCREG_COC2); case CNMIPS_BBIT0: - return il.CompareEqual(registerSize, - il.And(registerSize, - ReadILOperand(il, instr, 1, registerSize), - il.Const(registerSize, 1 << instr.operands[1].immediate) + return il.CompareEqual(registerSize(op1), + il.And(registerSize(op1), + ReadILOperand(il, instr, 1, registerSize(op1)), + il.Const(registerSize(op1), 1 << instr.operands[1].immediate) ), - il.Const(registerSize, 0) + il.Const(registerSize(op1), 0) ); case CNMIPS_BBIT032: - return il.CompareEqual(registerSize, - il.And(registerSize, - ReadILOperand(il, instr, 1, registerSize), - il.Const(registerSize, ((uint64_t)1) << (instr.operands[1].immediate + 32)) + return il.CompareEqual(registerSize(op1), + il.And(registerSize(op1), + ReadILOperand(il, instr, 1, registerSize(op1)), + il.Const(registerSize(op1), ((uint64_t)1) << (instr.operands[1].immediate + 32)) ), - il.Const(registerSize, 0) + il.Const(registerSize(op1), 0) ); case CNMIPS_BBIT1: - return il.CompareNotEqual(registerSize, - il.And(registerSize, - ReadILOperand(il, instr, 1, registerSize), - il.Const(registerSize, 1 << instr.operands[1].immediate) + return il.CompareNotEqual(registerSize(op1), + il.And(registerSize(op1), + ReadILOperand(il, instr, 1, registerSize(op1)), + il.Const(registerSize(op1), 1 << instr.operands[1].immediate) ), - il.Const(registerSize, 0) + il.Const(registerSize(op1), 0) ); case CNMIPS_BBIT132: - return il.CompareNotEqual(registerSize, - il.And(registerSize, - ReadILOperand(il, instr, 1, registerSize), - il.Const(registerSize, ((uint64_t)1) << (instr.operands[1].immediate + 32)) + return il.CompareNotEqual(registerSize(op1), + il.And(registerSize(op1), + ReadILOperand(il, instr, 1, registerSize(op1)), + il.Const(registerSize(op1), ((uint64_t)1) << (instr.operands[1].immediate + 32)) ), - il.Const(registerSize, 0) + il.Const(registerSize(op1), 0) ); default: @@ -796,7 +1111,16 @@ static void SignExtendHiLo(LowLevelILFunction& il, size_t registerSize) } } -bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFunction& il, Instruction& instr, size_t addrSize, uint32_t decomposeFlags) +#define DEFINE_HILO1(op) \ + auto hi = REG_HI; \ + auto lo = REG_LO; \ + if (instr.operation == op) \ + { \ + hi = REG_HI1; \ + lo = REG_LO1; \ + } + +bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFunction& il, Instruction& instr, size_t addrSize, uint32_t decomposeFlags, MipsVersion version) { LowLevelILLabel trueLabel, falseLabel, doneLabel, dirFlagSet, dirFlagClear, dirFlagDone; InstructionOperand& op1 = instr.operands[0]; @@ -804,121 +1128,163 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu InstructionOperand& op3 = instr.operands[2]; InstructionOperand& op4 = instr.operands[3]; LowLevelILLabel trueCode, falseCode, again; - size_t registerSize = addrSize; + size_t bytes = 4; + bool max = false; + // size_t registerSize = addrSize; + // std::function + bool signedFlag = false; + ExtendType extendType = SignExtend; + bool saturate = false; + auto registerSize = [=](const InstructionOperand& op) -> size_t const + { + return get_register_width(Reg(op.reg), version); + }; + auto registerSize5900 = [=](const InstructionOperand& op, size_t maxWidth=8) -> size_t const + { + if (version == MIPS_R5900) + return get_register_width(Reg(op.reg), version, maxWidth); + else + return get_register_width(Reg(op.reg), version); + }; BNEndianness endian = arch->GetEndianness(); switch (instr.operation) { - case MIPS_ADD: + case MIPS_ADDIU: + if (version == MIPS_R5900 && op1.reg == REG_SP) + { + il.AddInstruction(il.SetRegister(4, op1.reg, + il.Add(4, + ReadILOperand(il, instr, 2, registerSize(op2), 4), + ReadILOperand(il, instr, 3, registerSize(op3), 4)))); + break; + } case MIPS_ADDU: + case MIPS_ADD: case MIPS_ADDI: - case MIPS_ADDIU: if (op2.reg == REG_ZERO) - il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, ReadILOperand(il, instr, 3, registerSize, 4))); + il.AddInstruction(SetRegisterOrNop(il, 4, registerSize(op1), op1.reg, ReadILOperand(il, instr, 3, registerSize(op3), 4))); else il.AddInstruction( - SetRegisterOrNop(il, 4, registerSize, op1.reg, + SetRegisterOrNop(il, 4, registerSize(op1), op1.reg, il.Add(4, - ReadILOperand(il, instr, 2, registerSize, 4), - ReadILOperand(il, instr, 3, registerSize, 4)))); + ReadILOperand(il, instr, 2, registerSize(op2), 4), + ReadILOperand(il, instr, 3, registerSize(op3), 4)))); break; - case MIPS_DADD: case MIPS_DADDU: - case MIPS_DADDI: case MIPS_DADDIU: + case MIPS_DADD: + case MIPS_DADDI: if (op2.reg == REG_ZERO) - il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, ReadILOperand(il, instr, 3, registerSize))); + il.AddInstruction(SetRegisterOrNop(il, 8, registerSize(op1), op1.reg, ReadILOperand(il, instr, 3, registerSize(op3)))); else il.AddInstruction( - SetRegisterOrNop(il, 8, registerSize, op1.reg, + SetRegisterOrNop(il, 8, registerSize(op1), op1.reg, il.Add(8, - ReadILOperand(il, instr, 2, registerSize), - ReadILOperand(il, instr, 3, registerSize)))); + ReadILOperand(il, instr, 2, registerSize(op2)), + ReadILOperand(il, instr, 3, registerSize(op3))))); break; - case MIPS_SUB: case MIPS_SUBU: - il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, + case MIPS_SUB: + il.AddInstruction(SetRegisterOrNop(il, 4, registerSize(op1), op1.reg, il.Sub(4, - ReadILOperand(il, instr, 2, registerSize, 4), - ReadILOperand(il, instr, 3, registerSize, 4)))); + ReadILOperand(il, instr, 2, registerSize(op2), 4), + ReadILOperand(il, instr, 3, registerSize(op3), 4)))); break; - case MIPS_DSUB: case MIPS_DSUBU: - il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, + case MIPS_DSUB: + il.AddInstruction(SetRegisterOrNop(il, 8, registerSize(op1), op1.reg, il.Sub(8, - ReadILOperand(il, instr, 2, registerSize, 8), - ReadILOperand(il, instr, 3, registerSize, 8)))); + ReadILOperand(il, instr, 2, registerSize(op2), 8), + ReadILOperand(il, instr, 3, registerSize(op3), 8)))); break; case MIPS_AND: - il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, - il.And(registerSize, - ReadILOperand(il, instr, 2, registerSize), - ReadILOperand(il, instr, 3, registerSize)))); + il.AddInstruction(SetRegisterOrNop(il, registerSize(op2), registerSize(op1), op1.reg, + il.And(registerSize(op2), + ReadILOperand(il, instr, 2, registerSize(op2)), + ReadILOperand(il, instr, 3, registerSize(op3))), ZeroExtend)); break; case MIPS_ANDI: - il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, - il.And(registerSize, - ReadILOperand(il, instr, 2, registerSize), - il.Operand(1, il.Const(4, 0x0000ffff & op3.immediate))))); + il.AddInstruction(SetRegisterOrNop(il, registerSize(op2), registerSize(op1), op1.reg, + il.And(registerSize(op2), + ReadILOperand(il, instr, 2, registerSize(op2)), + il.Operand(1, il.Const(4, 0x0000ffff & op3.immediate))), ZeroExtend)); break; case MIPS_DIV: - il.AddInstruction(il.SetRegister(4, REG_LO, + il.AddInstruction(il.SetRegister(get_register_width(REG_LO, version), REG_LO, il.DivSigned(4, - ReadILOperand(il, instr, 1, registerSize, 4), - ReadILOperand(il, instr, 2, registerSize, 4)))); - il.AddInstruction(il.SetRegister(4, REG_HI, + ReadILOperand(il, instr, 1, 4, 4), + ReadILOperand(il, instr, 2, 4, 4)))); + il.AddInstruction(il.SetRegister(get_register_width(REG_HI, version), REG_HI, il.ModSigned(4, - ReadILOperand(il, instr, 1, registerSize, 4), - ReadILOperand(il, instr, 2, registerSize, 4)))); - SignExtendHiLo(il, registerSize); - break; + ReadILOperand(il, instr, 1, 4, 4), + ReadILOperand(il, instr, 2, 4, 4)))); + SignExtendHiLo(il, 4); + break; + case MIPS_DIV1: + il.AddInstruction(il.SetRegister(8, REG_LO1, + il.SignExtend(8, + il.DivSigned(4, + ReadILOperand(il, instr, 1, 4, 4), + ReadILOperand(il, instr, 2, 4, 4))))); + il.AddInstruction(il.SetRegister(8, REG_HI1, + il.SignExtend(8, + il.ModSigned(4, + ReadILOperand(il, instr, 1, 4, 4), + ReadILOperand(il, instr, 2, 4, 4))))); + break; + case MIPS_DIVU1: case MIPS_DIVU: - il.AddInstruction(il.SetRegister(4, REG_LO, + { + DEFINE_HILO1(MIPS_DIVU1); + il.AddInstruction(il.SetRegister(get_register_width(lo, version), lo, il.DivUnsigned(4, - ReadILOperand(il, instr, 1, registerSize, 4), - ReadILOperand(il, instr, 2, registerSize, 4)))); - il.AddInstruction(il.SetRegister(4, REG_HI, + ReadILOperand(il, instr, 1, 4, 4), + ReadILOperand(il, instr, 2, 4, 4)))); + il.AddInstruction(il.SetRegister(get_register_width(hi, version), hi, il.ModUnsigned(4, - ReadILOperand(il, instr, 1, registerSize, 4), - ReadILOperand(il, instr, 2, registerSize, 4)))); - SignExtendHiLo(il, registerSize); + ReadILOperand(il, instr, 1, 4, 4), + ReadILOperand(il, instr, 2, 4, 4)))); + if (lo == REG_LO) + SignExtendHiLo(il, registerSize(op1)); break; + } case MIPS_DDIV: - il.AddInstruction(il.SetRegister(8, REG_LO, + il.AddInstruction(il.SetRegister(get_register_width(REG_LO, version), REG_LO, il.DivSigned(8, - ReadILOperand(il, instr, 1, registerSize, 8), - ReadILOperand(il, instr, 2, registerSize, 8)))); - il.AddInstruction(il.SetRegister(8, REG_HI, + ReadILOperand(il, instr, 1, registerSize(op1), 8), + ReadILOperand(il, instr, 2, registerSize(op2), 8)))); + il.AddInstruction(il.SetRegister(get_register_width(REG_HI, version), REG_HI, il.ModSigned(8, - ReadILOperand(il, instr, 1, registerSize, 8), - ReadILOperand(il, instr, 2, registerSize, 8)))); + ReadILOperand(il, instr, 1, registerSize(op1), 8), + ReadILOperand(il, instr, 2, registerSize(op2), 8)))); break; case MIPS_DDIVU: - il.AddInstruction(il.SetRegister(8, REG_LO, + il.AddInstruction(il.SetRegister(get_register_width(REG_LO, version), REG_LO, il.DivUnsigned(8, - ReadILOperand(il, instr, 1, registerSize, 8), - ReadILOperand(il, instr, 2, registerSize, 8)))); - il.AddInstruction(il.SetRegister(8, REG_HI, + ReadILOperand(il, instr, 1, registerSize(op1), 8), + ReadILOperand(il, instr, 2, registerSize(op2), 8)))); + il.AddInstruction(il.SetRegister(get_register_width(REG_HI, version), REG_HI, il.ModUnsigned(8, - ReadILOperand(il, instr, 1, registerSize, 8), - ReadILOperand(il, instr, 2, registerSize, 8)))); + ReadILOperand(il, instr, 1, registerSize(op1), 8), + ReadILOperand(il, instr, 2, registerSize(op2), 8)))); break; case MIPS_MUL: - il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, + il.AddInstruction(SetRegisterOrNop(il, 4, registerSize(op1), op1.reg, il.Mult(4, - ReadILOperand(il, instr, 2, registerSize, 4), - ReadILOperand(il, instr, 3, registerSize, 4)))); + ReadILOperand(il, instr, 2, registerSize(op2), 4), + ReadILOperand(il, instr, 3, registerSize(op3), 4)))); break; case MIPS_XOR: - il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, - il.Xor(registerSize, - ReadILOperand(il, instr, 2, registerSize), - ReadILOperand(il, instr, 3, registerSize)))); + il.AddInstruction(SetRegisterOrNop(il, registerSize(op1), registerSize(op1), op1.reg, + il.Xor(registerSize(op2), + ReadILOperand(il, instr, 2, registerSize(op2)), + ReadILOperand(il, instr, 3, registerSize(op3))), ZeroExtend)); break; case MIPS_XORI: - il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, - il.Xor(registerSize, - ReadILOperand(il, instr, 2, registerSize), - il.Operand(1,il.Const(4, 0x0000ffff & op3.immediate))))); + il.AddInstruction(SetRegisterOrNop(il, registerSize(op1), registerSize(op1), op1.reg, + il.Xor(registerSize(op2), + ReadILOperand(il, instr, 2, registerSize(op2)), + il.Operand(1,il.Const(registerSize(op2), 0x0000ffff & op3.immediate))), ZeroExtend)); break; case MIPS_B: case MIPS_J: @@ -968,11 +1334,63 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu ConditionalJump(arch, il, il.Flag(FPCCREG_FCC0), addrSize, op1.immediate, addr + 8); return false; + case MIPS_BC2F: + case MIPS_BC2FL: + if (op1.operandClass == FLAG) + ConditionalJump(arch, il, il.Not(0, il.Flag(op1.reg)), addrSize, op2.immediate, addr + 8); + else + ConditionalJump(arch, il, il.Not(0, il.Flag(CCREG_COC2)), addrSize, op1.immediate, addr + 8); + return false; + + case MIPS_BC2T: + case MIPS_BC2TL: + if (op1.operandClass == FLAG) + ConditionalJump(arch, il, il.Flag(op1.reg), addrSize, op2.immediate, addr + 8); + else + ConditionalJump(arch, il, il.Flag(CCREG_COC2), addrSize, op1.immediate, addr + 8); + return false; + + case MIPS_BC0F: + case MIPS_BC0FL: + { + // il.AddInstruction(il.Intrinsic({RegisterOrFlag(true, LLIL_TEMP(0))}, MIPS_INTRIN_COP0_CONDITION, {})); + il.AddInstruction(il.Intrinsic({RegisterOrFlag(true, CCREG_COC0)}, MIPS_INTRIN_COP0_CONDITION, {})); + // il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_COP0_CONDITION, {}, CCREG_COC0)); + ConditionalJump(arch, il, GetConditionForInstruction(il, instr, registerSize), addrSize, op1.immediate, addr + 8); + // ConditionalJump(arch, il, il.Not(0, il.Flag(LLIL_TEMP(0))), addrSize, op1.immediate, addr + 8); + // il.AddInstruction(il.If(il.Not(0, il.Flag(LLIL_TEMP(0))), trueCode, falseCode)); + // il.MarkLabel(trueCode); + // il.AddInstruction(il.Jump(il.ConstPointer(addrSize, op1.immediate))); + // il.MarkLabel(falseCode); + // il.AddInstruction(il.Jump(il.ConstPointer(addrSize, addr + 8))); + return false; + } + case MIPS_BC0T: + case MIPS_BC0TL: + // il.AddInstruction(il.Intrinsic({RegisterOrFlag(true, LLIL_TEMP(0))}, MIPS_INTRIN_COP0_CONDITION, {})); + // // ConditionalJump(arch, il, il.Intrinsic({}, MIPS_INTRIN_COP0_CONDITION, {}, Flag::CCREG_COC0), addrSize, op1.immediate, addr + 8); + // // ConditionalJump(arch, il, GetConditionForInstruction(il, instr, registerSize), addrSize, op1.immediate, addr + 8); + // ConditionalJump(arch, il, il.Flag(LLIL_TEMP(0)), addrSize, op1.immediate, addr + 8); + // return false; + { + // il.AddInstruction(il.Intrinsic({RegisterOrFlag(true, LLIL_TEMP(0))}, MIPS_INTRIN_COP0_CONDITION, {})); + il.AddInstruction(il.Intrinsic({RegisterOrFlag(true, CCREG_COC0)}, MIPS_INTRIN_COP0_CONDITION, {})); + // il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_COP0_CONDITION, {}, CCREG_COC0)); + ConditionalJump(arch, il, GetConditionForInstruction(il, instr, registerSize), addrSize, op1.immediate, addr + 8); + // ConditionalJump(arch, il, il.Flag(LLIL_TEMP(0)), addrSize, op1.immediate, addr + 8); + // il.AddInstruction(il.If(il.Flag(LLIL_TEMP(0)), trueCode, falseCode)); + // il.MarkLabel(trueCode); + // il.AddInstruction(il.Jump(il.ConstPointer(addrSize, op1.immediate))); + // il.MarkLabel(falseCode); + // il.AddInstruction(il.Jump(il.ConstPointer(addrSize, addr + 8))); + return false; + } + case MIPS_BGEZAL: case MIPS_BLTZAL: il.AddInstruction(il.If(GetConditionForInstruction(il, instr, registerSize), trueCode, falseCode)); il.MarkLabel(trueCode); - il.AddInstruction(il.Call(ReadILOperand(il, instr, 2, registerSize))); + il.AddInstruction(il.Call(ReadILOperand(il, instr, 2, registerSize(op2)))); il.MarkLabel(falseCode); break; @@ -994,7 +1412,7 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu il.AddInstruction(il.SetRegister(1, LLIL_TEMP(0), il.Const(4,0))); il.MarkLabel(again); il.AddInstruction(il.If(il.CompareNotEqual(4, - il.And(4, il.ShiftLeft(4, ReadILOperand(il, instr, 2, registerSize, 4), il.Register(1, LLIL_TEMP(0))), il.Const(4, 0x80000000)), + il.And(4, il.ShiftLeft(4, ReadILOperand(il, instr, 2, registerSize(op2), 4), il.Register(1, LLIL_TEMP(0))), il.Const(4, 0x80000000)), il.Const(4,0)), trueCode, falseCode)); il.MarkLabel(trueCode); il.AddInstruction(il.SetRegister(1, LLIL_TEMP(0), il.Add(1, il.Const(1,1), il.Register(1, LLIL_TEMP(0))))); @@ -1016,7 +1434,7 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu il.AddInstruction(il.SetRegister(1, LLIL_TEMP(0), il.Const(4,0))); il.MarkLabel(again); il.AddInstruction(il.If(il.CompareNotEqual(8, - il.And(8, il.ShiftLeft(8, ReadILOperand(il, instr, 2, registerSize, 8), il.Register(1, LLIL_TEMP(0))), il.Const(8, 0x8000000000000000)), + il.And(8, il.ShiftLeft(8, ReadILOperand(il, instr, 2, registerSize(op2), 8), il.Register(1, LLIL_TEMP(0))), il.Const(8, 0x8000000000000000)), il.Const(8,0)), trueCode, falseCode)); il.MarkLabel(trueCode); il.AddInstruction(il.SetRegister(1, LLIL_TEMP(0), il.Add(1, il.Const(1,1), il.Register(1, LLIL_TEMP(0))))); @@ -1038,7 +1456,7 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu il.AddInstruction(il.SetRegister(1, LLIL_TEMP(0), il.Const(4,0))); il.MarkLabel(again); il.AddInstruction(il.If(il.CompareEqual(4, - il.And(4, il.ShiftLeft(4, ReadILOperand(il, instr, 2, registerSize, 4), il.Register(1, LLIL_TEMP(0))), il.Const(4, 0x80000000)), + il.And(4, il.ShiftLeft(4, ReadILOperand(il, instr, 2, registerSize(op2), 4), il.Register(1, LLIL_TEMP(0))), il.Const(4, 0x80000000)), il.Const(4,0)), trueCode, falseCode)); il.MarkLabel(trueCode); il.AddInstruction(il.SetRegister(1, LLIL_TEMP(0), il.Add(1, il.Const(1,1), il.Register(1, LLIL_TEMP(0))))); @@ -1060,7 +1478,7 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu il.AddInstruction(il.SetRegister(1, LLIL_TEMP(0), il.Const(4,0))); il.MarkLabel(again); il.AddInstruction(il.If(il.CompareEqual(8, - il.And(8, il.ShiftLeft(8, ReadILOperand(il, instr, 2, registerSize, 8), il.Register(1, LLIL_TEMP(0))), il.Const(8, 0x8000000000000000)), + il.And(8, il.ShiftLeft(8, ReadILOperand(il, instr, 2, registerSize(op2), 8), il.Register(1, LLIL_TEMP(0))), il.Const(8, 0x8000000000000000)), il.Const(8,0)), trueCode, falseCode)); il.MarkLabel(trueCode); il.AddInstruction(il.SetRegister(1, LLIL_TEMP(0), il.Add(1, il.Const(1,1), il.Register(1, LLIL_TEMP(0))))); @@ -1075,37 +1493,52 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu { operand = 2; } - il.AddInstruction(il.Call(ReadILOperand(il, instr, operand, registerSize, addrSize, true))); + il.AddInstruction(il.Call(ReadILOperand(il, instr, operand, registerSize(instr.operands[operand]), addrSize, true))); } break; case MIPS_JR: case MIPS_JR_HB: if (op1.reg == REG_RA) - il.AddInstruction(il.Return(ReadILOperand(il, instr, 1, registerSize))); + il.AddInstruction(il.Return(ReadILOperand(il, instr, 1, registerSize(op1), addrSize))); else - il.AddInstruction(il.Jump(ReadILOperand(il, instr, 1, registerSize))); + // il.AddInstruction(il.Jump(ReadILOperand(il, instr, 1, registerSize(op1)))); + il.AddInstruction(il.Jump(ReadILOperand(il, instr, 1, registerSize(op1), addrSize))); return false; case MIPS_ERET: - il.AddInstruction(il.Return(il.Register(registerSize, REG_ERROR_EPC))); + il.AddInstruction(il.Return(il.Register(addrSize, REG_ERROR_EPC))); break; case MIPS_LBUX: case MIPS_LBU: - il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.ZeroExtend(registerSize, ReadILOperand(il, instr, 2, registerSize, 1)))); + // il.AddInstruction(SetRegisterOrNop(il, registerSize(op1), registerSize(op1), op1.reg, il.ZeroExtend(registerSize(op1), ReadILOperand(il, instr, 2, registerSize(op2), 1)))); + il.AddInstruction(SetRegisterOrNop(il, 1, registerSize(op1), op1.reg, ReadILOperand(il, instr, 2, registerSize(op2), 1), ZeroExtend)); break; case MIPS_LB: - il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.SignExtend(registerSize, ReadILOperand(il, instr, 2, registerSize, 1)))); + // il.AddInstruction(SetRegisterOrNop(il, registerSize(op1), registerSize(op1), op1.reg, il.SignExtend(registerSize(op1), ReadILOperand(il, instr, 2, registerSize(op2), 1)))); + il.AddInstruction(SetRegisterOrNop(il, 1, registerSize(op1), op1.reg, ReadILOperand(il, instr, 2, registerSize(op2), 1), SignExtend)); break; case MIPS_MFHI: - il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.Register(registerSize, REG_HI))); + il.AddInstruction(SetRegisterOrNop(il, get_register_width(REG_HI, version), registerSize(op1), op1.reg, il.Register(get_register_width(REG_HI, version), REG_HI))); + break; + case MIPS_MFHI1: + il.AddInstruction(SetRegisterOrNop(il, get_register_width(REG_HI1, version), registerSize(op1), op1.reg, il.Register(get_register_width(REG_HI1, version), REG_HI1))); break; case MIPS_MFLO: - il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.Register(registerSize, REG_LO))); + il.AddInstruction(SetRegisterOrNop(il, get_register_width(REG_LO, version), registerSize(op1), op1.reg, il.Register(get_register_width(REG_LO, version), REG_LO))); + break; + case MIPS_MFLO1: + il.AddInstruction(SetRegisterOrNop(il, get_register_width(REG_LO1, version), registerSize(op1), op1.reg, il.Register(get_register_width(REG_LO1, version), REG_LO1))); break; case MIPS_MTHI: - il.AddInstruction(il.SetRegister(registerSize, REG_HI, ReadILOperand(il, instr, 1, registerSize))); + il.AddInstruction(il.SetRegister(get_register_width(REG_HI, version), REG_HI, ReadILOperand(il, instr, 1, registerSize(op1)))); + break; + case MIPS_MTHI1: + il.AddInstruction(il.SetRegister(get_register_width(REG_HI1, version), REG_HI1, ReadILOperand(il, instr, 1, registerSize(op1)))); break; case MIPS_MTLO: - il.AddInstruction(il.SetRegister(registerSize, REG_LO, ReadILOperand(il, instr, 1, registerSize))); + il.AddInstruction(il.SetRegister(get_register_width(REG_LO, version), REG_LO, ReadILOperand(il, instr, 1, registerSize(op1)))); + break; + case MIPS_MTLO1: + il.AddInstruction(il.SetRegister(get_register_width(REG_LO1, version), REG_LO1, ReadILOperand(il, instr, 1, registerSize(op1)))); break; case MIPS_DMFC0: il.AddInstruction(MoveFromCoprocessor(0, il, 8, op1.reg, op2.immediate, op3.immediate, decomposeFlags)); @@ -1114,7 +1547,14 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu il.AddInstruction(MoveFromCoprocessor(0, il, 4, op1.reg, op2.immediate, op3.immediate, decomposeFlags)); break; case MIPS_MFC1: - il.AddInstruction(MoveFromCoprocessor(1, il, 4, op1.reg, op2.immediate, op3.immediate, decomposeFlags)); + if (version == MIPS_R5900) + { + il.AddInstruction( + SetRegisterOrNop(il, 4, 8, op1.reg, il.Register(4, op2.reg))); + break; + } + else + il.AddInstruction(MoveFromCoprocessor(1, il, 4, op1.reg, op2.immediate, op3.immediate, decomposeFlags)); break; case MIPS_DMFC2: il.AddInstruction(MoveFromCoprocessor(2, il, 8, op1.reg, op2.immediate, 0, decomposeFlags)); @@ -1123,33 +1563,41 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu il.AddInstruction(MoveFromCoprocessor(2, il, 4, op1.reg, op2.immediate, 0, decomposeFlags)); break; case MIPS_DMTC0: - il.AddInstruction(MoveToCoprocessor(0, il, 8, op2.immediate, op3.immediate, ReadILOperand(il, instr, 1, registerSize), decomposeFlags)); + il.AddInstruction(MoveToCoprocessor(0, il, 8, op2.immediate, op3.immediate, ReadILOperand(il, instr, 1, registerSize(op1)), decomposeFlags)); break; case MIPS_MTC0: - il.AddInstruction(MoveToCoprocessor(0, il, 4, op2.immediate, op3.immediate, ReadILOperand(il, instr, 1, registerSize), decomposeFlags)); + il.AddInstruction(MoveToCoprocessor(0, il, 4, op2.immediate, op3.immediate, ReadILOperand(il, instr, 1, registerSize(op1)), decomposeFlags)); break; case MIPS_MTC1: - il.AddInstruction(MoveToCoprocessor(1, il, 4, op2.immediate, op3.immediate, ReadILOperand(il, instr, 1, registerSize), decomposeFlags)); + if (version == MIPS_R5900) + { + il.AddInstruction( + il.SetRegister(4, op2.reg, + op1.reg == REG_ZERO ? il.Const(4, 0) : il.Register(4, op1.reg))); + break; + } + else + il.AddInstruction(MoveToCoprocessor(1, il, 4, op2.immediate, op3.immediate, ReadILOperand(il, instr, 1, registerSize(op1)), decomposeFlags)); break; case MIPS_DMTC2: - il.AddInstruction(MoveToCoprocessor(2, il, 8, op2.immediate, 0, ReadILOperand(il, instr, 1, registerSize), decomposeFlags)); + il.AddInstruction(MoveToCoprocessor(2, il, 8, op2.immediate, 0, ReadILOperand(il, instr, 1, registerSize(op1)), decomposeFlags)); break; case MIPS_MTC2: - il.AddInstruction(MoveToCoprocessor(2, il, 4, op2.immediate, 0, ReadILOperand(il, instr, 1, registerSize), decomposeFlags)); + il.AddInstruction(MoveToCoprocessor(2, il, 4, op2.immediate, 0, ReadILOperand(il, instr, 1, registerSize(op1)), decomposeFlags)); break; case MIPS_MOVE: - il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, ReadILOperand(il, instr, 2, registerSize))); + il.AddInstruction(SetRegisterOrNop(il, registerSize(op1), registerSize(op1), op1.reg, ReadILOperand(il, instr, 2, registerSize(op2)))); break; case MIPS_MOVN: - il.AddInstruction(il.If(il.CompareNotEqual(registerSize, ReadILOperand(il, instr, 3, registerSize), il.Const(registerSize, 0)), trueCode, falseCode)); + il.AddInstruction(il.If(il.CompareNotEqual(registerSize(op3), ReadILOperand(il, instr, 3, registerSize(op3)), il.Const(registerSize(op3), 0)), trueCode, falseCode)); il.MarkLabel(trueCode); - il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, ReadILOperand(il, instr, 2, registerSize))); + il.AddInstruction(SetRegisterOrNop(il, registerSize(op1), registerSize(op1), op1.reg, ReadILOperand(il, instr, 2, registerSize(op2)))); il.MarkLabel(falseCode); break; case MIPS_MOVZ: - il.AddInstruction(il.If(il.CompareEqual(registerSize, ReadILOperand(il, instr, 3, registerSize), il.Const(registerSize, 0)), trueCode, falseCode)); + il.AddInstruction(il.If(il.CompareEqual(registerSize(op3), ReadILOperand(il, instr, 3, registerSize(op3)), il.Const(registerSize(op3), 0)), trueCode, falseCode)); il.MarkLabel(trueCode); - il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, ReadILOperand(il, instr, 2, registerSize))); + il.AddInstruction(SetRegisterOrNop(il, registerSize(op1), registerSize(op1), op1.reg, ReadILOperand(il, instr, 2, registerSize(op2)))); il.MarkLabel(falseCode); break; case MIPS_MSUB: @@ -1161,9 +1609,9 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu il.Or(8, il.ShiftLeft(8, il.Register(4, REG_HI), il.Const(1, 32)), il.ZeroExtend(8, il.Register(4, REG_LO))))); il.AddInstruction(il.SetRegisterSplit(4, REG_HI, REG_LO, il.Sub(8, il.Register(8, LLIL_TEMP(0)), - il.MultDoublePrecSigned(4, ReadILOperand(il, instr, 1, registerSize), ReadILOperand(il, instr, 2, registerSize))))); + il.MultDoublePrecSigned(4, ReadILOperand(il, instr, 1, registerSize(op1)), ReadILOperand(il, instr, 2, registerSize(op2)))))); - SignExtendHiLo(il, registerSize); + SignExtendHiLo(il, registerSize(op1)); break; case MIPS_MSUBU: //(HI,LO) = (HI,LO) - (GPR[rs] x GPR[rt]) @@ -1174,48 +1622,122 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu il.Or(8, il.ShiftLeft(8, il.Register(4, REG_HI), il.Const(1, 32)), il.ZeroExtend(8, il.Register(4, REG_LO))))); il.AddInstruction(il.SetRegisterSplit(4, REG_HI, REG_LO, il.Sub(8, il.Register(8, LLIL_TEMP(0)), - il.MultDoublePrecUnsigned(4, ReadILOperand(il, instr, 1, registerSize), ReadILOperand(il, instr, 2, registerSize))))); + il.MultDoublePrecUnsigned(4, ReadILOperand(il, instr, 1, registerSize(op1)), ReadILOperand(il, instr, 2, registerSize(op2)))))); - SignExtendHiLo(il, registerSize); + SignExtendHiLo(il, registerSize(op1)); break; + case MIPS_MULT1: case MIPS_MULT: - il.AddInstruction(il.SetRegisterSplit(4, REG_HI, REG_LO, il.MultDoublePrecSigned(4, ReadILOperand(il, instr, 1, registerSize), ReadILOperand(il, instr, 2, registerSize)))); - SignExtendHiLo(il, registerSize); + if (version == MIPS_R5900 && instr.numOperands == 3) { + // auto temp = LLIL_TEMP(0); + // il.AddInstruction(il.SetRegister(8, temp, + // il.MultDoublePrecSigned(8, + // ReadILOperand(il, instr, 2, 4, 4), + // ReadILOperand(il, instr, 3, 4, 4)))); + // il.AddInstruction(il.SetRegister(get_register_width(REG_HI, version), REG_HI, + // il.SignExtend(get_register_width(REG_HI, version), + // il.ArithShiftRight(8, + // il.Register(8, temp), + // il.Const(8, 32))))); + // il.AddInstruction(il.SetRegister(get_register_width(REG_LO, version), REG_LO, + // il.SignExtend(get_register_width(REG_LO, version), + // il.LowPart(4, + // il.Register(8, temp))))); + // SignExtendHiLo(il, 4); + // auto rd = op1.reg; + // if (rd != REG_ZERO) + // il.AddInstruction(SetRegisterOrNop(il, 4, 4, rd, il.Register(get_register_width(REG_LO, version), REG_LO))); + DEFINE_HILO1(MIPS_MULT1); + il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), + il.MultDoublePrecSigned(4, + ReadILOperand(il, instr, 2, 4, 4), + ReadILOperand(il, instr, 3, 4, 4)))); + il.AddInstruction(il.SetRegisterSplit(4, hi, lo, il.Register(8, LLIL_TEMP(0)))); + // il.AddInstruction(il.SetRegisterSplit(4, hi, lo, + // il.MultDoublePrecSigned(8, + // ReadILOperand(il, instr, 2, 4, 4), + // ReadILOperand(il, instr, 3, 4, 4)))); + if (lo == REG_LO) + SignExtendHiLo(il, 4); + auto rd = op1.reg; + if (rd != REG_ZERO) + il.AddInstruction(SetRegisterOrNop(il, 4, 8, rd, il.Register(4, LLIL_TEMP(0)))); + // il.AddInstruction(SetRegisterOrNop(il, 4, 8, rd, il.Register(get_register_width(lo, version), lo))); + } + else + { + // il.AddInstruction(il.SetRegisterSplit(get_register_width(REG_HI, version), REG_HI, REG_LO, + // il.MultDoublePrecSigned(4, + // ReadILOperand(il, instr, 1, 4, 4), + // ReadILOperand(il, instr, 2, 4, 4)))); + // SignExtendHiLo(il, 4); // TODO: registerSize??? + DEFINE_HILO1(MIPS_MADD1); + il.AddInstruction(il.SetRegisterSplit(4, hi, lo, + il.MultDoublePrecSigned(8, + ReadILOperand(il, instr, 1, 4, 4), + ReadILOperand(il, instr, 2, 4, 4)))); + if (lo == REG_LO) + SignExtendHiLo(il, 4); + } break; + case MIPS_MULTU1: case MIPS_MULTU: - il.AddInstruction(il.SetRegisterSplit(4, REG_HI, REG_LO, il.MultDoublePrecUnsigned(4, ReadILOperand(il, instr, 1, registerSize), ReadILOperand(il, instr, 2, registerSize)))); - SignExtendHiLo(il, registerSize); + if (version == MIPS_R5900 && instr.numOperands == 3) { + DEFINE_HILO1(MIPS_MULTU1); + + il.AddInstruction(il.SetRegisterSplit(4, hi, lo, + il.MultDoublePrecUnsigned(4, + ReadILOperand(il, instr, 2, 4), + ReadILOperand(il, instr, 3, 4)))); + if (lo == REG_LO) + SignExtendHiLo(il, 4); + auto rd = op1.reg; + if (rd != REG_ZERO) + il.AddInstruction(SetRegisterOrNop(il, 4, 8, rd, il.Register(get_register_width(lo, version), lo))); + } + else + { + DEFINE_HILO1(MIPS_MULTU1); + il.AddInstruction(il.SetRegisterSplit(4, hi, lo, + il.MultDoublePrecUnsigned(4, + ReadILOperand(il, instr, 1, 4), + ReadILOperand(il, instr, 2, 4)))); + if (lo == REG_LO) + SignExtendHiLo(il, 4); + } break; case MIPS_DMULT: - il.AddInstruction(il.SetRegisterSplit(8, REG_HI, REG_LO, il.MultDoublePrecSigned(8, ReadILOperand(il, instr, 1, registerSize), ReadILOperand(il, instr, 2, registerSize)))); + il.AddInstruction(il.SetRegisterSplit(8, REG_HI, REG_LO, il.MultDoublePrecSigned(8, ReadILOperand(il, instr, 1, registerSize(op1)), ReadILOperand(il, instr, 2, registerSize(op2))))); break; case MIPS_DMULTU: - il.AddInstruction(il.SetRegisterSplit(8, REG_HI, REG_LO, il.MultDoublePrecUnsigned(8, ReadILOperand(il, instr, 1, registerSize), ReadILOperand(il, instr, 2, registerSize)))); + il.AddInstruction(il.SetRegisterSplit(8, REG_HI, REG_LO, il.MultDoublePrecUnsigned(8, ReadILOperand(il, instr, 1, registerSize(op1)), ReadILOperand(il, instr, 2, registerSize(op2))))); break; - case MIPS_NEG: case MIPS_NEGU: - il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, - il.Neg(4, ReadILOperand(il, instr, 2, registerSize)))); + // This doesn't seem to matter, but using zero-extend to be consistent + // Also, turns out neg and negu are both pseudo instructions for sub/subu + case MIPS_NEG: + il.AddInstruction(SetRegisterOrNop(il, 4, registerSize(op1), op1.reg, + il.Neg(4, ReadILOperand(il, instr, 2, registerSize(op2))))); break; case MIPS_NOT: - il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, - il.Not(registerSize, ReadILOperand(il, instr, 2, registerSize)))); + il.AddInstruction(SetRegisterOrNop(il, registerSize(op2), registerSize(op1), op1.reg, + il.Not(registerSize(op2), ReadILOperand(il, instr, 2, registerSize(op2))))); break; case MIPS_NOR: - il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, - il.Not(registerSize, il.Or(registerSize, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize))))); + il.AddInstruction(SetRegisterOrNop(il, registerSize(op2), registerSize(op1), op1.reg, + il.Not(registerSize(op2), il.Or(registerSize(op2), ReadILOperand(il, instr, 2, registerSize(op2)), ReadILOperand(il, instr, 3, registerSize(op3)))))); break; case MIPS_OR: - il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, - il.Or(registerSize, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize)))); + il.AddInstruction(SetRegisterOrNop(il, registerSize(op2), registerSize(op1), op1.reg, + il.Or(registerSize(op2), ReadILOperand(il, instr, 2, registerSize(op2)), ReadILOperand(il, instr, 3, registerSize(op3))))); break; case MIPS_ORI: if (op2.reg == REG_ZERO) - il.AddInstruction(il.SetRegister(registerSize, op1.reg, il.Operand(1, il.Const(4, 0x0000ffff & op3.immediate)))); + il.AddInstruction(il.SetRegister(registerSize(op1), op1.reg, il.Operand(1, il.Const(4, 0x0000ffff & op3.immediate)))); else - il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, - il.Or(registerSize, - ReadILOperand(il, instr, 2, registerSize), + il.AddInstruction(SetRegisterOrNop(il, registerSize(op2), registerSize(op1), op1.reg, + il.Or(registerSize(op2), + ReadILOperand(il, instr, 2, registerSize(op2)), il.Operand(1, il.Const(4, 0x0000ffff & op3.immediate))))); break; case MIPS_RDHWR: @@ -1245,12 +1767,12 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu break; } case MIPS_SW: - il.AddInstruction(il.Store(4, GetILOperandMemoryAddress(il, op2, addrSize), ReadILOperand(il, instr, 1, registerSize, 4))); + il.AddInstruction(il.Store(4, GetILOperandMemoryAddress(il, op2, addrSize), ReadILOperand(il, instr, 1, registerSize(op1), 4))); break; case MIPS_SWL: { int32_t delta = endian == LittleEndian ? -3 : 0; - il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(LLIL_TEMP(0)) }, MIPS_INTRIN_GET_LEFT_PART32, { ReadILOperand(il, instr, 1, registerSize, 4) })); + il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(LLIL_TEMP(0)) }, MIPS_INTRIN_GET_LEFT_PART32, { ReadILOperand(il, instr, 1, registerSize(op1), 4) })); il.AddInstruction(il.Store(4, GetILOperandMemoryAddress(il, op2, addrSize, delta), il.Register(4, LLIL_TEMP(0)) @@ -1262,7 +1784,7 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu case MIPS_SDL: { int32_t delta = endian == LittleEndian ? -7 : 0; - il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(LLIL_TEMP(0)) }, MIPS_INTRIN_GET_LEFT_PART64, { ReadILOperand(il, instr, 1, registerSize, 8) })); + il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(LLIL_TEMP(0)) }, MIPS_INTRIN_GET_LEFT_PART64, { ReadILOperand(il, instr, 1, registerSize(op1), 8) })); il.AddInstruction(il.Store(8, GetILOperandMemoryAddress(il, op2, addrSize, delta), il.Register(8, LLIL_TEMP(0)) @@ -1273,7 +1795,7 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu case MIPS_SWR: { int32_t delta = endian == BigEndian ? -3 : 0; - il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(LLIL_TEMP(0)) }, MIPS_INTRIN_GET_RIGHT_PART32, { ReadILOperand(il, instr, 1, registerSize, 4) })); + il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(LLIL_TEMP(0)) }, MIPS_INTRIN_GET_RIGHT_PART32, { ReadILOperand(il, instr, 1, registerSize(op1), 4) })); il.AddInstruction(il.Store(4, GetILOperandMemoryAddress(il, op2, addrSize, delta), il.Register(4, LLIL_TEMP(0)) @@ -1285,7 +1807,7 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu case MIPS_SDR: { int32_t delta = endian == BigEndian ? -7 : 0; - il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(LLIL_TEMP(0)) }, MIPS_INTRIN_GET_RIGHT_PART64, { ReadILOperand(il, instr, 1, registerSize, 8) })); + il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(LLIL_TEMP(0)) }, MIPS_INTRIN_GET_RIGHT_PART64, { ReadILOperand(il, instr, 1, registerSize(op1), 8) })); il.AddInstruction(il.Store(8, GetILOperandMemoryAddress(il, op2, addrSize, delta), il.Register(8, LLIL_TEMP(0)) @@ -1299,43 +1821,68 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu LowLevelILLabel trueCode, falseCode, doneCode; il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(LLIL_TEMP(0)) }, MIPS_INTRIN_LLBIT_CHECK, {})); il.AddInstruction(il.If(il.CompareEqual(0, il.Register(0, LLIL_TEMP(0)), il.Const(0, 1)), - trueCode, falseCode)); + trueCode, falseCode)); il.MarkLabel(trueCode); - il.AddInstruction(il.Store(4, GetILOperandMemoryAddress(il, op2, addrSize), ReadILOperand(il, instr, 1, registerSize, 4))); - il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.Const(0, 1))); + il.AddInstruction(il.Store(4, GetILOperandMemoryAddress(il, op2, addrSize), ReadILOperand(il, instr, 1, registerSize(op1), 4))); + il.AddInstruction(SetRegisterOrNop(il, registerSize(op1), registerSize(op1), op1.reg, il.Const(0, 1))); il.AddInstruction(il.Goto(doneCode)); il.MarkLabel(falseCode); - il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.Const(0, 0))); + il.AddInstruction(SetRegisterOrNop(il, registerSize(op1), registerSize(op1), op1.reg, il.Const(0, 0))); il.MarkLabel(doneCode); break; } case MIPS_SD: - il.AddInstruction(il.Store(8, GetILOperandMemoryAddress(il, op2, addrSize), ReadILOperand(il, instr, 1, registerSize))); + il.AddInstruction(il.Store(8, GetILOperandMemoryAddress(il, op2, addrSize), ReadILOperand(il, instr, 1, registerSize(op1)))); + break; + case MIPS_SQ: + // Techinically, the store address should be automagically aligned by masking off the low 4 bits... + // il.AddInstruction(il.Store(16, + // il.And(addrSize, il.Const(addrSize, ~0x0F), GetILOperandMemoryAddress(il, op2, addrSize)), + // ReadILOperand(il, instr, 1, 16))); + // ...but that makes the IL ugly, so don't bother: + il.AddInstruction(il.Store(16, GetILOperandMemoryAddress(il, op2, addrSize), ReadILOperand(il, instr, 1, 16))); break; case MIPS_SCD: { LowLevelILLabel trueCode, falseCode, doneCode; il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(LLIL_TEMP(0)) }, MIPS_INTRIN_LLBIT_CHECK, {})); il.AddInstruction(il.If(il.CompareEqual(0, il.Register(0, LLIL_TEMP(0)), il.Const(0, 1)), - trueCode, falseCode)); + trueCode, falseCode)); il.MarkLabel(trueCode); - il.AddInstruction(il.Store(8, GetILOperandMemoryAddress(il, op2, addrSize), ReadILOperand(il, instr, 1, registerSize, 4))); - il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.Const(0, 1))); + il.AddInstruction(il.Store(8, GetILOperandMemoryAddress(il, op2, addrSize), ReadILOperand(il, instr, 1, registerSize(op1), 4))); + il.AddInstruction(SetRegisterOrNop(il, registerSize(op1), registerSize(op1), op1.reg, il.Const(0, 1))); il.AddInstruction(il.Goto(doneCode)); il.MarkLabel(falseCode); - il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.Const(0, 0))); + il.AddInstruction(SetRegisterOrNop(il, registerSize(op1), registerSize(op1), op1.reg, il.Const(0, 0))); il.MarkLabel(doneCode); break; } case MIPS_SWC1: - il.AddInstruction(MoveFromCoprocessor(1, il, 4, LLIL_TEMP(0), op1.immediate, 0, decomposeFlags)); - il.AddInstruction(WriteILOperand(il, instr, 1, addrSize, il.Register(4, LLIL_TEMP(0)))); + if (version == MIPS_R5900) + { + il.AddInstruction( + il.Store(4, GetILOperandMemoryAddress(il, op2, addrSize), + il.Register(4, op1.reg))); + } + else + { + il.AddInstruction(MoveFromCoprocessor(1, il, 4, LLIL_TEMP(0), op1.immediate, 0, decomposeFlags)); + il.AddInstruction(WriteILOperand(il, instr, 1, addrSize, il.Register(4, LLIL_TEMP(0)))); + } + break; + case MIPS_SDC1: + if (version == MIPS_R5900) + { + il.AddInstruction( + il.Store(8, GetILOperandMemoryAddress(il, op2, addrSize), + il.Register(8, op1.reg))); + } break; case MIPS_SWC2: il.AddInstruction(MoveFromCoprocessor(2, il, 4, LLIL_TEMP(0), op1.immediate, 0, decomposeFlags)); @@ -1350,23 +1897,23 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu break; case MIPS_EXT: //op1 = op4.imm bits in op2.reg at bit offset op3.imm - il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, - il.And(registerSize, - il.LogicalShiftRight(registerSize, - ReadILOperand(il, instr, 2, registerSize), + il.AddInstruction(SetRegisterOrNop(il, registerSize(op1), registerSize(op1), op1.reg, + il.And(registerSize(op1), + il.LogicalShiftRight(registerSize(op1), + ReadILOperand(il, instr, 2, registerSize(op2)), il.Const(1, op3.immediate) ), - il.Const(registerSize, (1< registerSize )); } else if (op3.immediate == 0 && op4.immediate == 0xf) { - il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, - il.SignExtend(8, il.LowPart(2, ReadILOperand(il, instr, 2, registerSize, registerSize))) + il.AddInstruction(SetRegisterOrNop(il, 8, registerSize(op1), op1.reg, + il.SignExtend(8, il.LowPart(2, ReadILOperand(il, instr, 2, registerSize(op2), 2))) // XXX: 2 => registerSize )); } else if (op3.immediate == 0 && op4.immediate == 0x1f) { - il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, - il.SignExtend(8, il.LowPart(4, ReadILOperand(il, instr, 2, registerSize, registerSize))) + il.AddInstruction(SetRegisterOrNop(il, 8, registerSize(op1), op1.reg, + il.SignExtend(8, il.LowPart(4, ReadILOperand(il, instr, 2, registerSize(op2), 4))) // XXX: 4 => registerSize )); } else { - il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, + il.AddInstruction(SetRegisterOrNop(il, 8, registerSize(op1), op1.reg, il.ArithShiftRight(8, il.ShiftLeft(8, - ReadILOperand(il, instr, 2, registerSize, 8), + ReadILOperand(il, instr, 2, registerSize(op2), 8), il.Const(8, 63 - (op3.immediate + op4.immediate)) ), il.Const(8, 63 - op4.immediate) @@ -1991,10 +2651,10 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu } else { - il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, + il.AddInstruction(SetRegisterOrNop(il, 8, registerSize(op1), op1.reg, il.ArithShiftRight(8, il.ShiftLeft(8, - ReadILOperand(il, instr, 2, registerSize, 8), + ReadILOperand(il, instr, 2, registerSize(op2), 8), il.Const(8, 63 - (32 + op3.immediate + op4.immediate)) ), il.Const(8, 63 - op4.immediate) @@ -2004,28 +2664,28 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu break; case CNMIPS_POP: - il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(op1.reg)}, CNMIPS_INTRIN_POP, {ReadILOperand(il, instr, 2, registerSize)})); + il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(op1.reg)}, CNMIPS_INTRIN_POP, {ReadILOperand(il, instr, 2, registerSize(op2))})); break; case CNMIPS_DPOP: - il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(op1.reg)}, CNMIPS_INTRIN_DPOP, {ReadILOperand(il, instr, 2, registerSize)})); + il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(op1.reg)}, CNMIPS_INTRIN_DPOP, {ReadILOperand(il, instr, 2, registerSize(op2))})); break; case CNMIPS_MTM0: - il.AddInstruction(il.SetRegister(registerSize, CNREG_MPL0, ReadILOperand(il, instr, 1, registerSize))); + il.AddInstruction(il.SetRegister(registerSize(op1), CNREG_MPL0, ReadILOperand(il, instr, 1, registerSize(op1)))); break; case CNMIPS_MTM1: - il.AddInstruction(il.SetRegister(registerSize, CNREG_MPL1, ReadILOperand(il, instr, 1, registerSize))); + il.AddInstruction(il.SetRegister(registerSize(op1), CNREG_MPL1, ReadILOperand(il, instr, 1, registerSize(op1)))); break; case CNMIPS_MTM2: - il.AddInstruction(il.SetRegister(registerSize, CNREG_MPL2, ReadILOperand(il, instr, 1, registerSize))); + il.AddInstruction(il.SetRegister(registerSize(op1), CNREG_MPL2, ReadILOperand(il, instr, 1, registerSize(op1)))); break; case CNMIPS_MTP0: - il.AddInstruction(il.SetRegister(registerSize, CNREG_P0, ReadILOperand(il, instr, 1, registerSize))); + il.AddInstruction(il.SetRegister(registerSize(op1), CNREG_P0, ReadILOperand(il, instr, 1, registerSize(op1)))); break; case CNMIPS_MTP1: - il.AddInstruction(il.SetRegister(registerSize, CNREG_P1, ReadILOperand(il, instr, 1, registerSize))); + il.AddInstruction(il.SetRegister(8, CNREG_P1, ReadILOperand(il, instr, 1, 8))); break; case CNMIPS_MTP2: - il.AddInstruction(il.SetRegister(registerSize, CNREG_P2, ReadILOperand(il, instr, 1, registerSize))); + il.AddInstruction(il.SetRegister(8, CNREG_P2, ReadILOperand(il, instr, 1, 8))); break; case CNMIPS_RDHWR: { @@ -2057,7 +2717,7 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu GetILOperandMemoryAddress(il, op2, addrSize), il.Add(4, il.Load(4, GetILOperandMemoryAddress(il, op2, addrSize)), - ReadILOperand(il, instr, 1, registerSize, 4) + ReadILOperand(il, instr, 1, registerSize(op1), 4) ) ) ); @@ -2069,30 +2729,30 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu GetILOperandMemoryAddress(il, op2, addrSize), il.Add(8, il.Load(8, GetILOperandMemoryAddress(il, op2, addrSize)), - ReadILOperand(il, instr, 1, registerSize, 8) + ReadILOperand(il, instr, 1, registerSize(op1), 8) ) ) ); break; case CNMIPS_SEQ: - il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.BoolToInt(registerSize, - il.CompareEqual(registerSize, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize))))); + il.AddInstruction(SetRegisterOrNop(il, 1, registerSize(op1), op1.reg, il.BoolToInt(1, + il.CompareEqual(registerSize(op2), ReadILOperand(il, instr, 2, registerSize(op2)), ReadILOperand(il, instr, 3, registerSize(op3)))))); break; case CNMIPS_SEQI: - il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.BoolToInt(registerSize, - il.CompareEqual(registerSize, ReadILOperand(il, instr, 2, registerSize), il.Const(registerSize, op3.immediate))))); + il.AddInstruction(SetRegisterOrNop(il, 1, registerSize(op1), op1.reg, il.BoolToInt(1, + il.CompareEqual(registerSize(op2), ReadILOperand(il, instr, 2, registerSize(op2)), il.Const(registerSize(op2), op3.immediate))))); break; case CNMIPS_SNE: - il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.BoolToInt(registerSize, - il.CompareNotEqual(registerSize, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize))))); + il.AddInstruction(SetRegisterOrNop(il, 1, registerSize(op1), op1.reg, il.BoolToInt(1, + il.CompareNotEqual(registerSize(op2), ReadILOperand(il, instr, 2, registerSize(op2)), ReadILOperand(il, instr, 3, registerSize(op3)))))); break; case CNMIPS_SNEI: - il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.BoolToInt(registerSize, - il.CompareNotEqual(registerSize, ReadILOperand(il, instr, 2, registerSize), il.Const(registerSize, op3.immediate))))); + il.AddInstruction(SetRegisterOrNop(il, 1, registerSize(op1), op1.reg, il.BoolToInt(1, + il.CompareNotEqual(1, ReadILOperand(il, instr, 2, registerSize(op2)), il.Const(registerSize(op2), op3.immediate))))); break; case CNMIPS_SYNCIOBDMA: @@ -2159,38 +2819,1066 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu break; - case MIPS_ADDR: - case MIPS_LDXC1: - case MIPS_LLO: - case MIPS_LUXC1: - case MIPS_LWC1: - case MIPS_LWC2: - case MIPS_LWC3: - case MIPS_LWXC1: - case MIPS_MFHC1: - case MIPS_MFHC2: - case MIPS_MOVT: - case MIPS_MULR: - case MIPS_SDC1: - case MIPS_SDC2: - case MIPS_SDC3: - case MIPS_SDXC1: - case MIPS_LDC1: - case MIPS_LDC2: - case MIPS_LDC3: + case MIPS_MTSAB: + { + ExprId shiftAmount; + if (op1.reg == REG_ZERO) + { + shiftAmount = il.Const(4,(op2.immediate & 0xF) << 3); + } + else + { + auto gprValue = il.Register(4, op1.reg); + auto gprLS4 = il.And(4, gprValue, il.Const(4, 0xF)); + ExprId xorResult; + if (op2.immediate & 0xF) + { + // Extract least-significant 4 bits of immediate value + // auto immLS4 = il.And(4, il.Const(4, op2.immediate), il.Const(4, 0xF)); + auto immLS4 = il.Const(4, op2.immediate & 0xF); - //unimplemented system functions - case MIPS_BC1ANY2: - case MIPS_BC1ANY4: - case MIPS_C2: - case MIPS_CFC1: - case MIPS_CFC2: - case MIPS_COP2: - case MIPS_COP3: - case MIPS_CTC1: - case MIPS_CTC2: - case MIPS_DERET: - case MIPS_DRET: + // Perform XOR operation between GPR[rs][3:0] and immediate[3:0] + xorResult = il.Xor(4, gprLS4, immLS4); + } + else + xorResult = gprLS4; + + // Multiply result by 8 (equivalent to left shift by 3) + shiftAmount = il.ShiftLeft(4, xorResult, il.Const(4, 3)); + } + + // Write the result to the SA register + il.AddInstruction(il.SetRegister(4, R5900_SA, shiftAmount)); + + break; + } + case MIPS_MTSAH: + { + auto rsVal = il.And(4, il.Register(4, op1.reg), il.Const(4, 0b111)); + auto immVal = il.Const(4, op2.immediate & 0b111); + + // Perform XOR + auto xorVal = il.Xor(4, rsVal, immVal); + + // Multiply by 16 + auto shiftAmount = il.Mult(4, xorVal, il.Const(4, 16)); + + // Set the SA register + il.AddInstruction(il.SetRegister(4, R5900_SA, shiftAmount)); + + break; + } + case MIPS_QFSRV: + { + // il.AddInstruction(il.SetRegister(16, op1.reg, + // il.LowPart(16, + // il.LogicalShiftRight(32, + // il.RegisterSplit(16, op2.reg, op3.reg), + // il.Register(1, R5900_SA))))); + if (op2.reg == REG_ZERO) + { + if (op3.reg == REG_ZERO) + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Const(16, 0))); + else + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, + il.LogicalShiftRight(16, + il.Register(16, op3.reg), + il.Register(1, R5900_SA)))); + } + else if (op3.reg == REG_ZERO) + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, + il.ShiftLeft(16, + il.Register(16, op2.reg), + il.Register(1, R5900_SA)))); + else + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, + il.Or(16, + il.ShiftLeft(16, + il.Register(16, op2.reg), + il.Register(1, R5900_SA)), + il.LogicalShiftRight(16, + il.Register(16, op3.reg), + il.Register(1, R5900_SA))))); + break; + } + case MIPS_PADDSB: + signedFlag = true; + case MIPS_PADDUB: + saturate = true; + case MIPS_PADDB: + { + SaturatingAddSub(il, instr, saturate, signedFlag, 1); + break; + } + case MIPS_PADDSH: + signedFlag = true; + case MIPS_PADDUH: + saturate = true; + case MIPS_PADDH: + { + SaturatingAddSub(il, instr, saturate, signedFlag, 2); + break; + } + case MIPS_PADDSW: + signedFlag = true; + case MIPS_PADDUW: + saturate = true; + case MIPS_PADDW: + { + SaturatingAddSub(il, instr, saturate, signedFlag, 4); + break; + } + case MIPS_PSUBSB: + signedFlag = true; + case MIPS_PSUBUB: + saturate = true; + case MIPS_PSUBB: + { + SaturatingAddSub(il, instr, saturate, signedFlag, 1, true); + break; + } + case MIPS_PSUBSH: + signedFlag = true; + case MIPS_PSUBUH: + saturate = true; + case MIPS_PSUBH: + { + SaturatingAddSub(il, instr, saturate, signedFlag, 2, true); + break; + } + case MIPS_PSUBSW: + signedFlag = true; + case MIPS_PSUBUW: + saturate = true; + case MIPS_PSUBW: + { + SaturatingAddSub(il, instr, saturate, signedFlag, 4, true); + break; + } + + case MIPS_PCPYUD: + { + // TODO: this really requires indexed vector registers + // il.AddInstruction(il.Unimplemented()); + if (op3.reg == REG_ZERO) + { + if (op2.reg == REG_ZERO) + { + il.AddInstruction(il.SetRegister(16, op1.reg, il.Const(16, 0))); + } + else + { + il.AddInstruction(il.SetRegister(16, op1.reg, + il.LogicalShiftRight(16, + il.Register(16, op2.reg), + il.Const(1, 64)))); + } + } + else if (op2.reg == REG_ZERO) + { + il.AddInstruction(il.SetRegister(16, op1.reg, + il.And(16, il.Register(16, op3.reg), + il.ShiftLeft(16, il.Const(8, 0xFFFFFFFFFFFFFFFF), il.Const(1, 64))))); + } + else + { + il.AddInstruction(il.SetRegister(16, op1.reg, + il.Or(16, + il.LogicalShiftRight(16, + il.Register(16, op2.reg), + il.Const(1, 64)), + il.And(16, il.Register(16, op3.reg), + il.ShiftLeft(16, il.Const(8, 0xFFFFFFFFFFFFFFFF), il.Const(1, 64)))))); + } + // il.ShiftLeft(16, + // il.LogicalShiftRight(16, + // il.Register(16, op3.reg), + // il.Const(1, 64)), + // il.Const(1, 64))))); + break; + } + case MIPS_PCPYLD: + { + // il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), + // il.ShiftLeft(16, + // il.Register(16, op2.reg), + // il.Const(1, 8)))); + // il.AddInstruction(il.SetRegister(8, op1.reg, + // il.Or(16, + // il.Register(16, LLIL_TEMP(0)), + // il.LowPart(8, il.Register(16, op3.reg))))); + il.AddInstruction(il.SetRegister(16, op1.reg, + il.Or(16, + il.ShiftLeft(16, + il.Register(16, op2.reg), + il.Const(1, 64)), + il.LowPart(8, il.Register(16, op3.reg))))); + break; + } + case MIPS_PCPYH: + { + // il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), + // il.ShiftLeft(16, + // il.Register(16, op2.reg), + // il.Const(1, 8)))); + // il.AddInstruction(il.SetRegister(8, op1.reg, + // il.Or(16, + // il.Register(16, LLIL_TEMP(0)), + // il.LowPart(8, il.Register(16, op3.reg))))); + // il.AddInstruction(il.SetRegister(16, op1.reg, + // il.Or(16, + // il.ShiftLeft(16, + // il.Register(16, op2.reg), + // il.Const(1, 64)), + // il.LowPart(8, il.Register(16, op3.reg))))); + il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), il.Register(2, op2.reg))); + il.AddInstruction(il.SetRegister(8, LLIL_TEMP(1), il.LogicalShiftRight(2, il.Register(16, op2.reg), il.Const(1, 64)))); + for (int i = 0; i < 4; i++) + { + il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), + il.Or(8, + il.Register(8, LLIL_TEMP(0)), + il.ShiftLeft(8, + il.Register(8, LLIL_TEMP(0)), + il.Const(1, 16))))); + il.AddInstruction(il.SetRegister(8, LLIL_TEMP(1), + il.Or(8, + il.Register(8, LLIL_TEMP(1)), + il.ShiftLeft(8, + il.Register(8, LLIL_TEMP(1)), + il.Const(1, 16))))); + } + il.AddInstruction(il.SetRegister(16, op1.reg, + il.Or(16, il.Register(8, LLIL_TEMP(0)), il.ShiftLeft(16, il.Register(8, LLIL_TEMP(1)), il.Const(1, 64))))); + break; + } + case MIPS_PAND: + { + il.AddInstruction(il.SetRegister(16, op1.reg, + il.And(16, + il.Register(16, op2.reg), + il.Register(16, op3.reg)))); + break; + } + case MIPS_PXOR: + { + il.AddInstruction(il.SetRegister(16, op1.reg, + il.Xor(16, + il.Register(16, op2.reg), + il.Register(16, op3.reg)))); + break; + } + case MIPS_POR: + { + il.AddInstruction(il.SetRegister(16, op1.reg, + il.Xor(16, + il.Register(16, op2.reg), + il.Register(16, op3.reg)))); + break; + } + case MIPS_PNOR: + { + if (op2.reg == REG_ZERO) + { + if (op3.reg == REG_ZERO) + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Const(16, -1), ZeroExtend)); + else + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Not(16, il.Register(16, op3.reg)), ZeroExtend)); + } + else if (op3.reg == REG_ZERO) + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Not(16, il.Register(16, op2.reg)), ZeroExtend)); + else + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, + il.Not(16, + il.Or(16, + il.Register(16, op2.reg), + il.Register(16, op3.reg))), ZeroExtend)); + break; + } + case MIPS_PMINH: + bytes = 2; + case MIPS_PMINW: + { + ParallelMinMax(il, instr, bytes); + break; + } + case MIPS_PMAXH: + bytes = 2; + case MIPS_PMAXW: + { + ParallelMinMax(il, instr, bytes, true); + break; + } + case MIPS_PROT3W: + { + il.AddInstruction(il.SetRegister(16, + LLIL_TEMP(0), + il.ShiftLeft(16, il.LogicalShiftRight(16, il.Register(16, op2.reg), il.Const(1, 96)), il.Const(1, 96)))); + il.AddInstruction(il.SetRegister(16, + LLIL_TEMP(0), + il.Or(16, + il.Register(16, LLIL_TEMP(0)), + il.ShiftLeft(16, il.And(16, il.Register(16, op2.reg), il.Const(4, 0xFFFFFFFF)), il.Const(1, 64))))); + il.AddInstruction(il.SetRegister(16, + LLIL_TEMP(0), + il.Or(16, + il.Register(16, LLIL_TEMP(0)), + il.ShiftLeft(16, il.And(16, il.LogicalShiftRight(16, il.Register(16, op2.reg), il.Const(1, 64)), il.Const(4, 0xFFFFFFFF)), il.Const(1, 32))))); + il.AddInstruction(il.SetRegister(16, + LLIL_TEMP(0), + il.Or(16, + il.Register(16, LLIL_TEMP(0)), + il.And(16, il.LogicalShiftRight(16, il.Register(16, op2.reg), il.Const(1, 32)), il.Const(4, 0xFFFFFFFF))))); + il.AddInstruction(il.SetRegister(16, op1.reg, il.Register(16, LLIL_TEMP(0)))); + break; + } + + case MIPS_ADDR: + case MIPS_LDXC1: + case MIPS_LLO: + case MIPS_LUXC1: + case MIPS_LWC1: + { + if (version == MIPS_R5900) + { + il.AddInstruction( + il.SetRegister(4, op1.reg, + il.Load(4, GetILOperandMemoryAddress(il, op2, addrSize)))); + break; + } + } + case MIPS_LDC1: + case MIPS_LDC2: + case MIPS_LDC3: + { + unsigned cop; + switch (instr.operation) + { + case MIPS_LDC1: cop = 1; break; + case MIPS_LDC2: cop = 2; break; + case MIPS_LDC3: cop = 3; break; + // default: il.Fail("Unhandled LDC1/2/3 instruction"); + default: break; + } + if (version == MIPS_R5900 && instr.operation == MIPS_LDC1) + il.AddInstruction( + il.SetRegister(8, op1.reg, + il.Load(8, GetILOperandMemoryAddress(il, op2, addrSize)))); + else + il.AddInstruction(MoveToCoprocessor(cop, il, 8, op1.reg, op1.immediate, + ReadILOperand(il, instr, 2, registerSize(op2)), decomposeFlags)); + break; + } + case MIPS_MFSA: + il.AddInstruction(SetRegisterOrNop(il, 8, registerSize(op1), op1.reg, il.Register(8, R5900_SA), ZeroExtend)); + break; + case MIPS_MTSA: + il.AddInstruction(SetRegisterOrNop(il, registerSize(op1), 8, R5900_SA, il.Register(8, op1.reg), ZeroExtend)); + break; + + case MIPS_ADDA_S: + if (version == MIPS_R5900) + { + il.AddInstruction(il.SetRegister(4, REG_VACC, il.FloatAdd(4, il.Register(4, op1.reg), il.Register(4, op2.reg)))); + break; + } + case MIPS_SUBA_S: + if (version == MIPS_R5900) + { + il.AddInstruction(il.SetRegister(4, REG_VACC, il.FloatSub(4, il.Register(4, op1.reg), il.Register(4, op2.reg)))); + break; + } + case MIPS_MULA_S: + if (version == MIPS_R5900) + { + il.AddInstruction(il.SetRegister(4, REG_VACC, il.FloatMult(4, il.Register(4, op1.reg), il.Register(4, op2.reg)))); + break; + } + case MIPS_MADDA_S: + if (version == MIPS_R5900) + { + il.AddInstruction(il.SetRegister(4, REG_VACC, + il.FloatAdd(4, il.Register(4, REG_VACC), + il.FloatMult(4, il.Register(4, op1.reg), il.Register(4, op2.reg))))); + break; + } + case MIPS_MSUBA_S: + if (version == MIPS_R5900) + { + il.AddInstruction(il.SetRegister(4, REG_VACC, + il.FloatAdd(4, il.Register(4, REG_VACC), + il.FloatMult(4, il.Register(4, op1.reg), il.Register(4, op2.reg))))); + break; + } + case MIPS_MADD_S: + if (version == MIPS_R5900) + { + il.AddInstruction(il.SetRegister(4, op1.reg, + il.FloatAdd(4, il.Register(4, REG_VACC), + il.FloatMult(4, il.Register(4, op2.reg), il.Register(4, op3.reg))))); + break; + } + case MIPS_MSUB_S: + if (version == MIPS_R5900) + { + il.AddInstruction(il.SetRegister(4, op1.reg, + il.FloatAdd(4, il.Register(4, REG_VACC), + il.FloatMult(4, il.Register(4, op2.reg), il.Register(4, op3.reg))))); + break; + } + + case MIPS_LQC2: + if (version == MIPS_R5900) + { + auto reg = op1.reg; + if (op2.operandClass == V_REG && reg < REG_VF0) + reg += REG_VF0; + il.AddInstruction(il.SetRegister(16, reg, + ReadILOperand(il, instr, 2, addrSize, 16))); + break; + } + case MIPS_SQC2: + if (version == MIPS_R5900) + { + auto reg = op1.reg; + if (op2.operandClass == V_REG && reg < REG_VF0) + reg += REG_VF0; + il.AddInstruction( + WriteILOperand(il, instr, 2, 16, il.Register(16, reg))); + break; + } + case MIPS_QMFC2: + case MIPS_QMFC2_I: + if (version == MIPS_R5900) + { + auto reg = op2.reg; + if (op2.operandClass == V_REG && reg < REG_VF0) + reg += REG_VF0; + il.AddInstruction( + SetRegisterOrNop(il,16, 16, op1.reg, il.Register(16, reg))); + break; + } + case MIPS_QMTC2: + case MIPS_QMTC2_I: + if (version == MIPS_R5900) + { + auto reg = op2.reg; + if (op2.operandClass == V_REG && reg < REG_VF0) + reg += REG_VF0; + il.AddInstruction( + il.SetRegister(16, reg, il.Register(16, op1.reg))); + break; + } + + case MIPS_PEXTLW: + case MIPS_PEXTLH: + case MIPS_PEXTLB: + { + switch (instr.operation) + { + case MIPS_PEXTLW: bytes = 4; break; + case MIPS_PEXTLH: bytes = 2; break; + case MIPS_PEXTLB: bytes = 1; break; + default: bytes = 0; + } + if (bytes == 0) + { + il.AddInstruction((il.Unimplemented())); + break; + } + const uint64_t mask = 0xFFFFFFFFFFFFFFFF >> (64 - (8 * bytes)); + for (int i = 0; i < 8 / bytes; i++) + { + if (op2.reg != REG_ZERO) + { + if (i == 0) + il.AddInstruction(il.SetRegister(16, LLIL_TEMP(0), + il.ShiftLeft(16, + il.And(2 * bytes, + il.Register(16, op2.reg), + il.Const(8, mask)), + il.Const(1, 2 * bytes)))); + else + il.AddInstruction(il.SetRegister(16, LLIL_TEMP(0), + il.Or(16, il.Register(16, LLIL_TEMP(0)), + il.ShiftLeft(16, + il.And(2 * bytes, + il.LogicalShiftRight(16, + il.Register(16, op2.reg), + il.Const(1, i * (bytes * 8))), il.Const(bytes, mask)), + il.Const(1, i * (16 * bytes + 1)))))); + } + if (op3.reg != REG_ZERO) + { + if (i == 0) + il.AddInstruction(il.SetRegister(16, LLIL_TEMP(1), + il.And(2 * bytes, + il.Register(16, op3.reg), + il.Const(bytes, mask)))); + else + il.AddInstruction(il.SetRegister(16, LLIL_TEMP(1), + il.Or(16, il.Register(16, LLIL_TEMP(1)), + il.ShiftLeft(16, + il.And(2 * bytes, + il.LogicalShiftRight(16, + il.Register(16, op3.reg), + il.Const(1, i * (bytes * 8))), il.Const(bytes, mask)), + il.Const(1, i * (16 * bytes)))))); + } + } + if (op2.reg == REG_ZERO) + { + if (op3.reg == REG_ZERO) + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Const(16, 0))); + else + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, LLIL_TEMP(1)))); + } + else if (op3.reg == REG_ZERO) + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, LLIL_TEMP(0)))); + else + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Or(16, il.Register(16, LLIL_TEMP(0)), il.Register(16, LLIL_TEMP(1))))); + break; + } + case MIPS_PEXTUW: + case MIPS_PEXTUH: + case MIPS_PEXTUB: + { + switch (instr.operation) + { + case MIPS_PEXTUW: bytes = 4; break; + case MIPS_PEXTUH: bytes = 2; break; + case MIPS_PEXTUB: bytes = 1; break; + default: bytes = 0; + } + if (bytes == 0) + { + il.AddInstruction((il.Unimplemented())); + break; + } + const uint64_t mask = 0xFFFFFFFFFFFFFFFF >> (64 - (8 * bytes)); + for (int i = 0; i < 8 / bytes; i++) + { + if (op2.reg != REG_ZERO) + { + // if (i == 0) + // il.AddInstruction(il.SetRegister(16, LLIL_TEMP(0), + // il.ShiftLeft(16, + // il.And(2 * bytes, + // il.Register(16, op2.reg), + // il.Const(8, mask)), + // il.Const(1, 2 * bytes)))); + // else + il.AddInstruction(il.SetRegister(16, LLIL_TEMP(0), + il.Or(16, il.Register(16, LLIL_TEMP(0)), + il.ShiftLeft(16, + il.And(2 * bytes, + il.LogicalShiftRight(16, + il.Register(16, op2.reg), + il.Const(1, 64 + i * (bytes * 8))), il.Const(bytes, mask)), + il.Const(1, i * (16 * bytes + 1)))))); + } + if (op3.reg != REG_ZERO) + { + if (i == 0) + il.AddInstruction(il.SetRegister(16, LLIL_TEMP(1), + il.And(2 * bytes, + il.LogicalShiftRight(16, il.Register(16, op3.reg), il.Const(1, 64)), + il.Const(bytes, mask)))); + else + il.AddInstruction(il.SetRegister(16, LLIL_TEMP(1), + il.Or(16, il.Register(16, LLIL_TEMP(1)), + il.ShiftLeft(16, + il.And(2 * bytes, + il.LogicalShiftRight(16, + il.Register(16, op3.reg), + il.Const(1, 64 + i * (bytes * 8))), il.Const(bytes, mask)), + il.Const(1, i * (16 * bytes)))))); + } + } + if (op2.reg == REG_ZERO) + { + if (op3.reg == REG_ZERO) + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Const(16, 0))); + else + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, LLIL_TEMP(1)))); + } + else if (op3.reg == REG_ZERO) + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, LLIL_TEMP(0)))); + else + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Or(16, il.Register(16, LLIL_TEMP(0)), il.Register(16, LLIL_TEMP(1))))); + break; + } + case MIPS_PPACW: + case MIPS_PPACH: + case MIPS_PPACB: + { + switch (instr.operation) + { + case MIPS_PPACW: bytes = 4; break; + case MIPS_PPACH: bytes = 2; break; + case MIPS_PPACB: bytes = 1; break; + default: bytes = 0; + } + if (bytes == 0) + { + il.AddInstruction((il.Unimplemented())); + break; + } + const uint64_t mask = 0xFFFFFFFFFFFFFFFF >> (64 - (8 * bytes)); + for (int i = 0; i < 8 / bytes; i++) + { + if (i == 0) + { + il.AddInstruction(il.SetRegister(16, LLIL_TEMP(0), + il.Or(16, + il.ShiftLeft(16, + il.And(16, + il.Register(16, op2.reg), + il.Const(bytes, mask)), + il.Const(1, i * bytes * 8 + 64)), + il.And(16, + il.Register(16, op3.reg), + il.Const(bytes, mask))))); + } + else + { + il.AddInstruction(il.SetRegister(16, LLIL_TEMP(0), + il.Or(16, + il.Register(16, LLIL_TEMP(0)), + il.Or(16, + il.ShiftLeft(16, + il.And(16, + il.LogicalShiftRight(16, + il.Register(16, op2.reg), + il.Const(1, 2 * i * (bytes * 8))), + il.Const(bytes, mask)), + il.Const(1, i * bytes * 8 + 64)), + il.ShiftLeft(16, + il.And(16, + il.LogicalShiftRight(16, + il.Register(16, op3.reg), + il.Const(1, 2 * i * (bytes * 8))), + il.Const(bytes, mask)), + il.Const(1, i * bytes * 8)))))); + } + + // if (op2.reg != REG_ZERO) + // { + // if (i == 0) + // il.AddInstruction(il.SetRegister(16, LLIL_TEMP(0), + // il.ShiftLeft(16, + // il.And(2 * bytes, + // il.Register(16, op2.reg), + // il.Const(8, mask)), + // il.Const(1, 2 * bytes)))); + // else + // il.AddInstruction(il.SetRegister(16, LLIL_TEMP(0), + // il.Or(16, il.Register(16, LLIL_TEMP(0)), + // il.ShiftLeft(16, + // il.And(2 * bytes, + // il.LogicalShiftRight(16, + // il.Register(16, op2.reg), + // il.Const(1, i * (bytes * 8))), il.Const(bytes, mask)), + // il.Const(1, i * (16 * bytes + 1)))))); + // } + // if (op3.reg != REG_ZERO) + // { + // if (i == 0) + // il.AddInstruction(il.SetRegister(16, LLIL_TEMP(1), + // il.And(2 * bytes, + // il.Register(16, op3.reg), + // il.Const(bytes, mask)))); + // else + // il.AddInstruction(il.SetRegister(16, LLIL_TEMP(1), + // il.Or(16, il.Register(16, LLIL_TEMP(1)), + // il.ShiftLeft(16, + // il.And(2 * bytes, + // il.LogicalShiftRight(16, + // il.Register(16, op3.reg), + // il.Const(1, i * (bytes * 8))), il.Const(bytes, mask)), + // il.Const(1, i * (16 * bytes)))))); + // } + } + // if (op2.reg == REG_ZERO) + // { + // if (op3.reg == REG_ZERO) + // il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Const(16, 0))); + // else + // il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, LLIL_TEMP(1)))); + // } + // else if (op3.reg == REG_ZERO) + // il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, LLIL_TEMP(0)))); + // else + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, LLIL_TEMP(0)))); + break; + } + + case MIPS_PSRLH: + bytes = 2; + case MIPS_PSRLW: + { + if (bytes == 0) + { + il.AddInstruction((il.Unimplemented())); + break; + } + const uint64_t mask = 0xFFFFFFFFFFFFFFFF >> (64 - (8 * bytes)); + const uint64_t shift_amount = op3.immediate; + for (int i = 0; i < 16 / bytes; i++) + { + if (i == 0) + il.AddInstruction(il.SetRegister(16, LLIL_TEMP(0), + il.And(16, + il.LogicalShiftRight(16, + il.Register(16, op2.reg), + il.Const(1, i * 16 + shift_amount)), + il.Const(16, mask)))); + else + il.AddInstruction(il.SetRegister(16, LLIL_TEMP(0), + il.Or(16, il.Register(16, LLIL_TEMP(0)), + il.ShiftLeft(16, + il.And(16, + il.LogicalShiftRight(16, + il.Register(16, op2.reg), + il.Const(1, i * 16 + shift_amount)), + il.Const(16, mask)), + il.Const(1, i * 16))))); + // if (i == 0) + // il.AddInstruction(il.SetRegister(16, LLIL_TEMP(0), + // il.ZeroExtend(bytes, + // il.And(16, + // il.LogicalShiftRight(16, + // il.Register(16, op2.reg), + // il.Const(1, i * 16 + shift_amount)), + // il.Const(16, mask))))); + // else + // il.AddInstruction(il.SetRegister(16, LLIL_TEMP(0), + // il.Or(16, il.Register(16, LLIL_TEMP(0)), + // il.ShiftLeft(16, + // il.ZeroExtend(bytes, + // il.And(16, + // il.LogicalShiftRight(16, + // il.Register(16, op2.reg), + // il.Const(1, i * 16 + shift_amount)), + // il.Const(16, mask))), + // il.Const(1, i * 16))))); + + } + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, LLIL_TEMP(0)))); + break; + } + + case MIPS_PSRAH: + bytes = 2; + case MIPS_PSRAW: + { + if (bytes == 0) + { + il.AddInstruction((il.Unimplemented())); + break; + } + const uint64_t mask = 0xFFFFFFFFFFFFFFFF >> (64 - (8 * bytes)); + const uint64_t shift_amount = op3.immediate; + for (int i = 0; i < 16 / bytes; i++) + { + if (i == 0) + il.AddInstruction(il.SetRegister(16, LLIL_TEMP(0), + il.SignExtend(bytes, + il.And(16, + il.ArithShiftRight(16, + il.Register(16, op2.reg), + il.Const(1, i * 16 + shift_amount)), + il.Const(16, mask))))); + else + il.AddInstruction(il.SetRegister(16, LLIL_TEMP(0), + il.Or(16, il.Register(16, LLIL_TEMP(0)), + il.ShiftLeft(16, + il.SignExtend(bytes, + il.And(16, + il.ArithShiftRight(16, + il.Register(16, op2.reg), + il.Const(1, i * 16 + shift_amount)), + il.Const(16, mask))), + il.Const(1, i * 16))))); + } + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, LLIL_TEMP(0)))); + break; + } + + case MIPS_PSLLH: + bytes = 2; + case MIPS_PSLLW: + { + if (bytes == 0) + { + il.AddInstruction((il.Unimplemented())); + break; + } + const uint64_t mask = 0xFFFFFFFFFFFFFFFF >> (64 - (8 * bytes)); + const uint64_t shift_amount = op3.immediate; + for (int i = 0; i < 16 / bytes; i++) + { + if (i == 0) + il.AddInstruction(il.SetRegister(16, LLIL_TEMP(0), + il.ShiftLeft(16, + il.And(16, + il.Register(16, op2.reg), + il.Const(16, mask)), + il.Const(1, shift_amount)))); + else + il.AddInstruction(il.SetRegister(16, LLIL_TEMP(0), + il.Or(16, il.Register(16, LLIL_TEMP(0)), + il.ShiftLeft(16, + il.And(16, + il.LogicalShiftRight(16, + il.Register(16, op2.reg), + il.Const(1, i * 16)), + il.Const(16, mask)), + il.Const(1, i * 16 + shift_amount))))); + } + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, LLIL_TEMP(0)))); + break; + } + + case MIPS_PCGTB: + case MIPS_PCGTH: + case MIPS_PCGTW: + { + if (op2.reg == REG_ZERO && op3.reg == REG_ZERO) + { + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Const(16, 0))); + break; + } + switch (instr.operation) + { + case MIPS_PCGTW: bytes = 4; break; + case MIPS_PCGTH: bytes = 2; break; + case MIPS_PCGTB: bytes = 1; break; + default: bytes = 0; + } + if (bytes == 0) + { + il.AddInstruction((il.Unimplemented())); + break; + } + const uint64_t mask = 0xFFFFFFFFFFFFFFFF >> (64 - (8 * bytes)); + for (int i = 0; i < 16 / bytes; i++) + { + if (i == 0) + il.AddInstruction(il.SetRegister(16, LLIL_TEMP(0), + il.BoolToInt(bytes, + il.CompareSignedGreaterThan(bytes, + op2.reg == REG_ZERO ? + il.Const(bytes, 0) : + il.And(bytes, + il.Register(16, op2.reg), + il.Const(bytes, mask)), + op3.reg == REG_ZERO ? + il.Const(bytes, 0) : + il.And(bytes, + il.Register(16, op3.reg), + il.Const(bytes, mask)))))); + else + il.AddInstruction(il.SetRegister(16, LLIL_TEMP(0), + il.Or(16, il.Register(16, LLIL_TEMP(0)), + il.ShiftLeft(16, + il.BoolToInt(bytes, + il.CompareSignedGreaterThan(bytes, + op2.reg == REG_ZERO ? + il.Const(bytes, 0) : + il.And(bytes, + il.LogicalShiftRight(16, + il.Register(16, op2.reg), + il.Const(1, i * bytes * 8)), + il.Const(bytes, mask)), + op3.reg == REG_ZERO ? + il.Const(bytes, 0) : + il.And(bytes, + il.LogicalShiftRight(16, + il.Register(16, op3.reg), + il.Const(1, i * bytes * 8)), + il.Const(bytes, mask)))), + il.Const(1, i * bytes * 8))))); + } + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, LLIL_TEMP(0)))); + break; + } + + // case MIPS_PEXCH: + case MIPS_PEXCW: + { + il.AddInstruction(il.SetRegister(16, op1.reg, + il.Or(16, + il.Xor(16, il.Register(16, op2.reg), + il.And(16, il.Register(16, op2.reg), + il.ShiftLeft(16, il.Const(16, 0xFFFFFFFFFFFFFFFF), il.Const(16, 32)))), + il.Or(16, + il.ShiftLeft(16, + il.And(16, il.LogicalShiftRight(64, il.Register(16, op2.reg), il.Const(16, 64)), + il.Const(16, 0xFFFFFFFF)), + il.Const(16, 32)), + il.ShiftLeft(16, + il.And(16, il.LogicalShiftRight(64, il.Register(16, op2.reg), il.Const(16, 32)), + il.Const(16, 0xFFFFFFFF)), + il.Const(16, 64)) + )))); + break; + } + case MIPS_PEXEW: + { + il.AddInstruction(il.SetRegister(16, op1.reg, + il.Or(16, + il.Xor(16, il.Register(16, op2.reg), + il.And(16, il.Register(16, op2.reg), + il.ShiftLeft(16, il.Const(16, 0xFFFFFFFFFFFFFFFF), il.Const(16, 32)))), + il.Or(16, + il.ShiftLeft(16, + il.And(16, il.LogicalShiftRight(64, il.Register(16, op2.reg), il.Const(16, 64)), + il.Const(16, 0xFFFFFFFF)), + il.Const(16, 32)), + il.ShiftLeft(16, + il.And(16, il.LogicalShiftRight(64, il.Register(16, op2.reg), il.Const(16, 32)), + il.Const(16, 0xFFFFFFFF)), + il.Const(16, 64)) + )))); + break; + } + case MIPS_PEXT5: + { + for (int i = 0; i < 4; i++) + { + int shift = i * 32; + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(i), + il.And(4, + il.LogicalShiftRight(16, + il.Register(16, op2.reg), + il.Const(1, shift)), + il.Const(2, 0xFFFF)))); + // il.AddInstruction(il.SetRegister(4, LLIL_TEMP(i), + // il.ShiftLeft(16, + // il.Or(4, + // il.Or(4, + // il.ShiftLeft(4, + // il.And(4, + // il.LogicalShiftRight(4, il.Register(4, LLIL_TEMP(i)), il.Const(1, 15)), + // il.Const(1, 1)), + // il.Const(1, 31)), + // il.ShiftLeft(4, + // il.And(4, + // il.LogicalShiftRight(4, il.Register(4, LLIL_TEMP(i)), il.Const(1, 10)), + // il.Const(1, 0x1f)), + // il.Const(1, 19))), + // il.Or(4, + // il.ShiftLeft(4, + // il.And(4, + // il.LogicalShiftRight(4, il.Register(4, LLIL_TEMP(i)), il.Const(1, 5)), + // il.Const(1, 0x1f)), + // il.Const(1, 10)), + // il.ShiftLeft(4, + // il.And(4, + // il.Register(4, LLIL_TEMP(i)), + // il.Const(1, 0x1f)), + // il.Const(1, 3)))), + // il.Const(1, shift)))); + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(i), + il.ShiftLeft(16, + il.Or(4, + il.Or(4, + il.ShiftLeft(4, il.And(4, il.Register(4, LLIL_TEMP(i)), il.Const(4, 1 << 15)), il.Const(1, 31-15)), + il.ShiftLeft(4, il.And(4, il.Register(4, LLIL_TEMP(i)), il.Const(4, 0x1f << 10)), il.Const(1, 19-10))), + il.Or(4, + il.ShiftLeft(4, il.And(4, il.Register(4, LLIL_TEMP(i)), il.Const(4, 0x1f << 5)), il.Const(1, 11-5)), + il.ShiftLeft(4, il.And(4, il.Register(4, LLIL_TEMP(i)), il.Const(4, 0x1f)), il.Const(1, 3)))), + il.Const(1, shift)))); + + } + il.AddInstruction(il.SetRegister(16, op1.reg, + il.Or(16, + il.Or(16, il.Register(16, LLIL_TEMP(0)), il.Register(16, LLIL_TEMP(1))), + il.Or(16, il.Register(16, LLIL_TEMP(2)), il.Register(16, LLIL_TEMP(3)))))); + + break; + } + case MIPS_PHMADH: + { + for (int i = 0; i < 4; i++) + { + if (i == 0) + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(i), + il.Add(4, + il.Mult(4, + il.And(4, il.Register(16, op2.reg), il.Const(2, 0xFFFF)), + il.And(4, il.Register(16, op3.reg), il.Const(2, 0xFFFF))), + il.Mult(4, + il.And(4, il.LogicalShiftRight(16, il.Register(16, op2.reg), il.Const(1, i * 32 + 16)), il.Const(2, 0xFFFF)), + il.And(4, il.LogicalShiftRight(16, il.Register(16, op3.reg), il.Const(1, i * 32 + 16)), il.Const(2, 0xFFFF))) + ))); + else + il.AddInstruction(il.SetRegister(4, LLIL_TEMP(i), + il.Add(4, + il.Mult(4, + il.And(4, il.LogicalShiftRight(16, il.Register(16, op2.reg), il.Const(1, i * 32)), il.Const(2, 0xFFFF)), + il.And(4, il.LogicalShiftRight(16, il.Register(16, op3.reg), il.Const(1, i * 32)), il.Const(2, 0xFFFF))), + il.Mult(4, + il.And(4, il.LogicalShiftRight(16, il.Register(16, op2.reg), il.Const(1, i * 32 + 16)), il.Const(2, 0xFFFF)), + il.And(4, il.LogicalShiftRight(16, il.Register(16, op3.reg), il.Const(1, i * 32 + 16)), il.Const(2, 0xFFFF))) + ))); + } + il.AddInstruction(il.SetRegister(16, REG_LO, il.Or(16, + il.LowPart(4, il.Register(4, LLIL_TEMP(0))), + il.ShiftLeft(16, il.LowPart(4, il.Register(4, LLIL_TEMP(2))), il.Const(1, 64))))); + il.AddInstruction(il.SetRegister(16, REG_HI, il.Or(16, + il.LowPart(4, il.Register(4, LLIL_TEMP(1))), + il.ShiftLeft(16, il.LowPart(4, il.Register(4, LLIL_TEMP(3))), il.Const(1, 64))))); + il.AddInstruction(il.SetRegister(16, op1.reg, + il.Or(16, + il.Or(16, + il.LowPart(4, il.Register(4, LLIL_TEMP(0))), + il.ShiftLeft(4, il.LowPart(4, il.Register(4, LLIL_TEMP(1))), il.Const(1, 32))), + il.Or(16, + il.ShiftLeft(4, il.LowPart(4, il.Register(4, LLIL_TEMP(2))), il.Const(1, 64)), + il.ShiftLeft(4, il.LowPart(4, il.Register(4, LLIL_TEMP(3))), il.Const(1, 96)))))); + break; + } + + case MIPS_CTC1: + case MIPS_CTC2: + if (version == MIPS_R5900) + { + il.AddInstruction(il.SetRegister(4, op2.reg, il.Register(4, op1.reg))); + break; + } + case MIPS_CFC1: + case MIPS_CFC2: + if (version == MIPS_R5900) + { + il.AddInstruction(il.SetRegister(4, op1.reg, il.Register(4, op2.reg))); + break; + } + + case MIPS_LWC2: + case MIPS_LWC3: + case MIPS_LWXC1: + case MIPS_MFHC1: + case MIPS_MFHC2: + case MIPS_MOVT: + case MIPS_MULR: + // case MIPS_SDC1: + case MIPS_SDC2: + case MIPS_SDC3: + case MIPS_SDXC1: + // case MIPS_LDC1: + // case MIPS_LDC2: + // case MIPS_LDC3: + + //unimplemented system functions + case MIPS_BC1ANY2: + case MIPS_BC1ANY4: + case MIPS_C2: + case MIPS_COP2: + case MIPS_COP3: + case MIPS_DERET: + case MIPS_DRET: case MIPS_JALX: //Special instruction for switching to MIPS32/microMIPS32/MIPS16e case MIPS_MTHC1: case MIPS_MTHC2: @@ -2202,6 +3890,11 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu // Floating point instructions case MIPS_RSQRT_D: case MIPS_RSQRT_S: + if (version == MIPS_R5900) + { + il.AddInstruction(il.SetRegister(4, op1.reg, il.FloatDiv(4, il.Register(4, op3.reg), il.FloatSqrt(4, il.Register(4, op3.reg))))); + break; + } case MIPS_RSQRT: case MIPS_RSQRT1: case MIPS_RSQRT2: @@ -2216,10 +3909,1014 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu case MIPS_NMSUB_S: case MIPS_MADD_D: case MIPS_MADD_PS: - case MIPS_MADD_S: + // case MIPS_MADD_S: case MIPS_MADDF_D: case MIPS_MADDF_S: - il.AddInstruction(il.Unimplemented()); + // R5900 instructions + // case MIPS_LQ: + // case MIPS_SQ: + case MIPS_DSLRV: + // case MIPS_MFSA: + // case MIPS_MTSA: + // case MIPS_MTSAB: + // case MIPS_MTSAH: + // case MIPS_MFHI1: + // case MIPS_MTHI1: + // case MIPS_MFLO1: + // case MIPS_MTLO1: + // case MIPS_MULT1: + // case MIPS_MULTU1: + // case MIPS_DIV1: + // case MIPS_DIVU1: + // case MIPS_MADD1: + // case MIPS_MADDU1: + // case MIPS_PLZCW: + // case MIPS_PMFHL: + // case MIPS_PMTHL: + // case MIPS_PSLLH: + // case MIPS_PSRLH: + // case MIPS_PSRAH: + // case MIPS_PSLLW: + // case MIPS_PSRLW: + // case MIPS_PSRAW: + // case MIPS_MFHI1: + // case MIPS_MTHI1: + // case MIPS_MFLO1: + // case MIPS_MTLO1: + // case MIPS_MULT1: + // case MIPS_MULTU1: + // case MIPS_DIV1: + // case MIPS_DIVU1: + // case MIPS_MADD1: + // case MIPS_MADDU1: + case MIPS_PMFHL: + case MIPS_PMTHL: + // case MIPS_PSLLH: + // case MIPS_PSRLH: + // case MIPS_PSRAH: + // case MIPS_PSLLW: + // case MIPS_PSRLW: + // case MIPS_PSRAW: + // case MIPS_PADDW: + // case MIPS_PSUBW: + // case MIPS_PCGTW: + // case MIPS_PMAXW: + // case MIPS_PADDH: + // case MIPS_PSUBH: + // case MIPS_PCGTH: + // case MIPS_PMAXH: + // case MIPS_PADDB: + // case MIPS_PSUBB: + // case MIPS_PCGTB: + // case MIPS_PADDSW: + // case MIPS_PSUBSW: + // case MIPS_PEXTLW: + // case MIPS_PPACW: + // case MIPS_PADDSH: + // case MIPS_PSUBSH: + // case MIPS_PEXTLH: + // case MIPS_PPACH: + // case MIPS_PADDSB: + // case MIPS_PSUBSB: + // case MIPS_PEXTLB: + // case MIPS_PPACB: + // case MIPS_PEXT5: + case MIPS_PPAC5: + case MIPS_PABSW: + case MIPS_PCEQW: + // case MIPS_PMINW: + case MIPS_PADSBH: + case MIPS_PABSH: + case MIPS_PCEQH: + // case MIPS_PMINH: + case MIPS_PCEQB: + // case MIPS_PADDUW: + // case MIPS_PSUBUW: + // case MIPS_PEXTUW: + // case MIPS_PADDUH: + // case MIPS_PSUBUH: + // case MIPS_PEXTUH: + // case MIPS_PADDUB: + // case MIPS_PSUBUB: + // case MIPS_PEXTUB: + // case MIPS_QFSRV: + case MIPS_PMADDW: + case MIPS_PSLLVW: + case MIPS_PSRLVW: + case MIPS_PMSUBW: + case MIPS_PMFHI: + case MIPS_PMFLO: + case MIPS_PINTH: + case MIPS_PMULTW: + case MIPS_PDIVW: + // case MIPS_PCPYLD: + case MIPS_PMADDH: + // case MIPS_PHMADH: + // case MIPS_PAND: + // case MIPS_PXOR: + case MIPS_PMSUBH: + case MIPS_PHMSBH: + case MIPS_PEXEH: + case MIPS_PREVH: + case MIPS_PMULTH: + case MIPS_PDIVBW: + // case MIPS_PEXEW: + // case MIPS_PROT3W: + case MIPS_PMADDUW: + case MIPS_PSRAVW: + case MIPS_PMTHI: + case MIPS_PMTLO: + case MIPS_PINTEH: + case MIPS_PMULTUW: + case MIPS_PDIVUW: + // case MIPS_PCPYUD: + // case MIPS_POR: + // case MIPS_PNOR: + // case MIPS_PEXCH: + // case MIPS_PCPYH: + // case MIPS_PEXCW: + // case MIPS_BC0F: + // case MIPS_BC0T: + // case MIPS_BC0FL: + // case MIPS_BC0TL: + // case MIPS_MADDA_S: + // case MIPS_MSUBA_S: + // case MIPS_MAX_S: + // case MIPS_MIN_S: + case MIPS_MMI0: + case MIPS_MMI1: + case MIPS_MMI2: + case MIPS_MMI3: + il.AddInstruction(il.Unimplemented()); + break; + + case MIPS_MAX_S: + { + ConditionExecute(il, + il.FloatCompareGreaterEqual(4, il.Register(4, op2.reg), il.Register(4, op3.reg)), + // il.CompareSignedGreaterEqual(4, + // il.FloatToInt(4, il.FloatSub(4, + // il.Register(4, op2.reg), il.Register(4, op3.reg))), il.Const(4, 0) + // ), + il.SetRegister(4, op1.reg, il.Register(4, op2.reg)), + il.SetRegister(4, op1.reg, il.Register(4, op3.reg))); + break; + } + case MIPS_MIN_S: + { + ConditionExecute(il, + il.FloatCompareLessEqual(4, il.Register(4, op2.reg), il.Register(4, op3.reg)), + // il.CompareSignedLessEqual(4, + // il.FloatToInt(4, il.FloatSub(4, + // il.Register(4, op2.reg), il.Register(4, op3.reg))), il.Const(4, 0) + // ), + il.SetRegister(4, op1.reg, il.Register(4, op2.reg)), + il.SetRegister(4, op1.reg, il.Register(4, op3.reg))); + break; + } + + + // Emotion Engine VPU0 (macro) instructions + case MIPS_VNOP: + il.AddInstruction(il.Nop()); + break; + case MIPS_VWAITQ: + il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_R5900_VWAITQ, {})); + break; + + case MIPS_VMR32: + { + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.Register(4, op3.reg + REG_VF0_Y))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.Register(4, op3.reg + REG_VF0_Z))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.Register(4, op3.reg + REG_VF0_W))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.Register(4, op3.reg + REG_VF0_X))); + break; + } + case MIPS_VABS: + { + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatAbs(4, il.Register(4, op3.reg + REG_VF0_Y)))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatAbs(4, il.Register(4, op3.reg + REG_VF0_Z)))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatAbs(4, il.Register(4, op3.reg + REG_VF0_W)))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatAbs(4, il.Register(4, op3.reg + REG_VF0_X)))); + break; + } + case MIPS_VMOVE: + { + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.Register(4, op3.reg + REG_VF0_X))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.Register(4, op3.reg + REG_VF0_Y))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.Register(4, op3.reg + REG_VF0_Z))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.Register(4, op3.reg + REG_VF0_W))); + break; + } + case MIPS_VMFIR: + { + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.SignExtend(4,il.Register(2, op3.reg)))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.SignExtend(4,il.Register(2, op3.reg)))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.SignExtend(4,il.Register(2, op3.reg)))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.SignExtend(4,il.Register(2, op3.reg)))); + break; + } + case MIPS_VMTIR: + { + il.AddInstruction(il.SetRegister(2, op1.reg, il.Register(4, op2.reg + REG_VF0_X + (op2.immediate - 1) * 33))); + break; + } + + case MIPS_VADD: + { + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + REG_VF0_X)))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + REG_VF0_Y)))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + REG_VF0_Z)))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + REG_VF0_W)))); + break; + } + case MIPS_VADDA: + { + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_X - REG_VACC, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + REG_VF0_X)))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Y - REG_VACC, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + REG_VF0_Y)))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Z - REG_VACC, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + REG_VF0_Z)))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_W - REG_VACC, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + REG_VF0_W)))); + break; + } + case MIPS_VADDAx: + case MIPS_VADDAy: + case MIPS_VADDAz: + case MIPS_VADDAw: + { + unsigned char dest = op1.reg; + auto bc = REG_VF0_X + (op4.immediate - 1) * 33; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_X - REG_VACC, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + bc)))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Y - REG_VACC, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + bc)))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Z - REG_VACC, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + bc)))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_W - REG_VACC, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + bc)))); + break; + } + case MIPS_VADDx: + case MIPS_VADDy: + case MIPS_VADDz: + case MIPS_VADDw: + { + unsigned char dest = op1.reg; + auto bc = REG_VF0_X + (op4.immediate - 1) * 33; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + bc)))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + bc)))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + bc)))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + bc)))); + break; + } + case MIPS_VADDq: + case MIPS_VADDi: + { + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg)))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg)))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg)))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg)))); + break; + } + + // VSUB + case MIPS_VSUB: + { + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + REG_VF0_X)))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + REG_VF0_Y)))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + REG_VF0_Z)))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + REG_VF0_W)))); + break; + } + case MIPS_VSUBA: + { + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_X - REG_VACC, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + REG_VF0_X)))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Y - REG_VACC, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + REG_VF0_Y)))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Z - REG_VACC, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + REG_VF0_Z)))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_W - REG_VACC, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + REG_VF0_W)))); + break; + } + case MIPS_VSUBAx: + case MIPS_VSUBAy: + case MIPS_VSUBAz: + case MIPS_VSUBAw: + { + unsigned char dest = op1.reg; + auto bc = REG_VF0_X + (op4.immediate - 1) * 33; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_X - REG_VACC, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + bc)))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Y - REG_VACC, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + bc)))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Z - REG_VACC, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + bc)))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_W - REG_VACC, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + bc)))); + break; + } + case MIPS_VSUBx: + case MIPS_VSUBy: + case MIPS_VSUBz: + case MIPS_VSUBw: + { + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg)))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg)))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg)))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg)))); + break; + } + case MIPS_VSUBq: + case MIPS_VSUBi: + { + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg)))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg)))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg)))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg)))); + break; + } + + // VMUL + case MIPS_VMUL: + { + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + REG_VF0_X)))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + REG_VF0_Y)))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + REG_VF0_Z)))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + REG_VF0_W)))); + break; + } + case MIPS_VMULA: + { + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_X - REG_VACC, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + REG_VF0_X)))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Y - REG_VACC, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + REG_VF0_Y)))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Z - REG_VACC, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + REG_VF0_Z)))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_W - REG_VACC, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + REG_VF0_W)))); + break; + } + case MIPS_VMULAx: + case MIPS_VMULAy: + case MIPS_VMULAz: + case MIPS_VMULAw: + { + unsigned char dest = op1.reg; + auto bc = REG_VF0_X + (op4.immediate - 1) * 33; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_X - REG_VACC, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + bc)))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Y - REG_VACC, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + bc)))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Z - REG_VACC, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + bc)))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_W - REG_VACC, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + bc)))); + break; + } + case MIPS_VMULAq: + case MIPS_VMULAi: + { + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_X - REG_VACC, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg)))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Y - REG_VACC, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg)))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Z - REG_VACC, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg)))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_W - REG_VACC, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg)))); + break; + } + + case MIPS_VMULx: + case MIPS_VMULy: + case MIPS_VMULz: + case MIPS_VMULw: + { + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg)))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg)))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg)))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg)))); + break; + } + case MIPS_VMULq: + case MIPS_VMULi: + { + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg)))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg)))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg)))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg)))); + break; + } + + case MIPS_VMADD: + { + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatAdd(4, il.Register(4, REG_VACC_X), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + REG_VF0_X))))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatAdd(4, il.Register(4, REG_VACC_Y), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + REG_VF0_Y))))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatAdd(4, il.Register(4, REG_VACC_Z), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + REG_VF0_Z))))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatAdd(4, il.Register(4, REG_VACC_W), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + REG_VF0_W))))); + break; + } + case MIPS_VMADDA: + { + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_X - REG_VACC, il.FloatAdd(4, il.Register(4, op2.reg + REG_VACC_X - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + REG_VF0_X))))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Y - REG_VACC, il.FloatAdd(4, il.Register(4, op2.reg + REG_VACC_Y - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + REG_VF0_Y))))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Z - REG_VACC, il.FloatAdd(4, il.Register(4, op2.reg + REG_VACC_Z - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + REG_VF0_Z))))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_W - REG_VACC, il.FloatAdd(4, il.Register(4, op2.reg + REG_VACC_W - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + REG_VF0_W))))); + break; + } + case MIPS_VMSUB: + { + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatSub(4, il.Register(4, REG_VACC_X), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + REG_VF0_X))))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatSub(4, il.Register(4, REG_VACC_Y), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + REG_VF0_Y))))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatSub(4, il.Register(4, REG_VACC_Z), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + REG_VF0_Z))))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatSub(4, il.Register(4, REG_VACC_W), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + REG_VF0_W))))); + break; + } + case MIPS_VMSUBA: + { + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_X - REG_VACC, il.FloatSub(4, il.Register(4, op2.reg + REG_VACC_X - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + REG_VF0_X))))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Y - REG_VACC, il.FloatSub(4, il.Register(4, op2.reg + REG_VACC_Y - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + REG_VF0_Y))))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Z - REG_VACC, il.FloatSub(4, il.Register(4, op2.reg + REG_VACC_Z - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + REG_VF0_Z))))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_W - REG_VACC, il.FloatSub(4, il.Register(4, op2.reg + REG_VACC_W - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + REG_VF0_W))))); + break; + } + case MIPS_VMADDAx: + case MIPS_VMADDAy: + case MIPS_VMADDAz: + case MIPS_VMADDAw: + { + unsigned char dest = op1.reg; + auto bc = REG_VF0_X + (op4.immediate - 1) * 33; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_X - REG_VACC, il.FloatAdd(4, il.Register(4, op2.reg + REG_VACC_X - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + bc))))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Y - REG_VACC, il.FloatAdd(4, il.Register(4, op2.reg + REG_VACC_Y - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + bc))))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Z - REG_VACC, il.FloatAdd(4, il.Register(4, op2.reg + REG_VACC_Z - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + bc))))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_W - REG_VACC, il.FloatAdd(4, il.Register(4, op2.reg + REG_VACC_W - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + bc))))); + break; + } + case MIPS_VMSUBAx: + case MIPS_VMSUBAy: + case MIPS_VMSUBAz: + case MIPS_VMSUBAw: + { + unsigned char dest = op1.reg; + auto bc = REG_VF0_X + (op4.immediate - 1) * 33; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_X - REG_VACC, il.FloatSub(4, il.Register(4, op2.reg + REG_VACC_X - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + bc))))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Y - REG_VACC, il.FloatSub(4, il.Register(4, op2.reg + REG_VACC_Y - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + bc))))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Z - REG_VACC, il.FloatSub(4, il.Register(4, op2.reg + REG_VACC_Z - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + bc))))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_W - REG_VACC, il.FloatSub(4, il.Register(4, op2.reg + REG_VACC_W - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + bc))))); + break; + } + case MIPS_VMADDx: + case MIPS_VMADDy: + case MIPS_VMADDz: + case MIPS_VMADDw: + { + unsigned char dest = op1.reg; + auto bc = REG_VF0_X + (op4.immediate - 1) * 33; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatAdd(4, il.Register(4, REG_VACC_X), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + bc))))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatAdd(4, il.Register(4, REG_VACC_Y), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + bc))))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatAdd(4, il.Register(4, REG_VACC_Z), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + bc))))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatAdd(4, il.Register(4, REG_VACC_W), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + bc))))); + break; + } + case MIPS_VMSUBx: + case MIPS_VMSUBy: + case MIPS_VMSUBz: + case MIPS_VMSUBw: + { + unsigned char dest = op1.reg; + auto bc = REG_VF0_X + (op4.immediate - 1) * 33; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatSub(4, il.Register(4, REG_VACC_X), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + bc))))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatSub(4, il.Register(4, REG_VACC_Y), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + bc))))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatSub(4, il.Register(4, REG_VACC_Z), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + bc))))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatSub(4, il.Register(4, REG_VACC_W), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + bc))))); + break; + } + case MIPS_VMADDq: + case MIPS_VMADDi: + { + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatAdd(4, il.Register(4, op2.reg + REG_VACC_X - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg))))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatAdd(4, il.Register(4, op2.reg + REG_VACC_Y - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg))))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatAdd(4, il.Register(4, op2.reg + REG_VACC_Z - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg))))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatAdd(4, il.Register(4, op2.reg + REG_VACC_W - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg))))); + break; + } + case MIPS_VMSUBq: + case MIPS_VMSUBi: + { + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatSub(4, il.Register(4, op2.reg + REG_VACC_X - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg))))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatSub(4, il.Register(4, op2.reg + REG_VACC_Y - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg))))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatSub(4, il.Register(4, op2.reg + REG_VACC_Z - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg))))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatSub(4, il.Register(4, op2.reg + REG_VACC_W - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg))))); + break; + } + case MIPS_VDIV: + { + il.AddInstruction(il.SetRegister(4, op1.reg, il.FloatDiv(4, il.Register(4, op2.reg + REG_VF0_X + (op2.immediate) * 33), il.Register(4, op3.reg + REG_VF0_X + (op3.immediate) * 33)))); + break; + } + + case MIPS_VSQRT: + { + il.AddInstruction(il.SetRegister(4, op1.reg, il.FloatSqrt(4, il.Register(4, op2.reg + REG_VF0_X + (op2.immediate) * 33)))); + break; + } + case MIPS_VRSQRT: + { + il.AddInstruction(il.SetRegister(4, op1.reg, il.FloatDiv(4, il.Register(4, op2.reg + REG_VF0_X + (op2.immediate) * 33), il.FloatSqrt(4, il.Register(4, op3.reg + REG_VF0_X + (op3.immediate) * 33))))); + break; + } + + // VF[fd]x = ACCx - VF[fs]y × VF[ft]z + // VF[fd]y = ACCy - VF[fs]z × VF[ft]x + // VF[fd]z = ACCz - VF[fs]x × VF[ft]y + case MIPS_VOPMSUB: + { + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatSub(4, il.Register(4, REG_VACC_X), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + REG_VF0_Z))))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatSub(4, il.Register(4, REG_VACC_Y), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + REG_VF0_X))))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatSub(4, il.Register(4, REG_VACC_Z), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + REG_VF0_Y))))); + break; + } + // ACCx = VF[fs]y × VF[ft]z + // ACCy = VF[fs]z × VF[ft]x + // ACCz = VF[fs]x × VF[ft]y + case MIPS_VOPMULA: + { + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, REG_VACC_X, il.FloatMult(4, il.Register(4, op2.reg + REG_VF0_Y), il.Register(4, op3.reg + REG_VF0_Z)))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, REG_VACC_Y, il.FloatMult(4, il.Register(4, op2.reg + REG_VF0_Z), il.Register(4, op3.reg + REG_VF0_X)))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, REG_VACC_Z, il.FloatMult(4, il.Register(4, op2.reg + REG_VF0_X), il.Register(4, op3.reg + REG_VF0_Y)))); + break; + } + + case MIPS_VILWR: + { + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(op2.reg)}, MIPS_INTRIN_R5900_VU_MEM_LOAD, {il.Mult(4, il.Register(4, op3.reg), il.Const(4, 16)), il.Const(2, 0)})); + if (dest & (1 << 2)) + il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(op2.reg)}, MIPS_INTRIN_R5900_VU_MEM_LOAD, {il.Mult(4, il.Register(4, op3.reg), il.Const(4, 16)), il.Const(2, 1)})); + if (dest & (1 << 1)) + il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(op2.reg)}, MIPS_INTRIN_R5900_VU_MEM_LOAD, {il.Mult(4, il.Register(4, op3.reg), il.Const(4, 16)), il.Const(2, 2)})); + if (dest & (1 << 0)) + il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(op2.reg)}, MIPS_INTRIN_R5900_VU_MEM_LOAD, {il.Mult(4, il.Register(4, op3.reg), il.Const(4, 16)), il.Const(2, 3)})); + break; + } + + case MIPS_VISWR: + { + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_R5900_VU_MEM_STORE, {il.Mult(4, il.Register(4, op3.reg), il.Const(4, 16)), il.Const(2, 0), il.Register(4, op2.reg)})); + if (dest & (1 << 2)) + il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_R5900_VU_MEM_STORE, {il.Mult(4, il.Register(4, op3.reg), il.Const(4, 16)), il.Const(2, 1), il.Register(4, op2.reg)})); + if (dest & (1 << 1)) + il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_R5900_VU_MEM_STORE, {il.Mult(4, il.Register(4, op3.reg), il.Const(4, 16)), il.Const(2, 2), il.Register(4, op2.reg)})); + if (dest & (1 << 0)) + il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_R5900_VU_MEM_STORE, {il.Mult(4, il.Register(4, op3.reg), il.Const(4, 16)), il.Const(2, 3), il.Register(4, op2.reg)})); + break; + } + + case MIPS_VLQI: + case MIPS_VLQD: + { + // il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(LLIL_TEMP(0))}, MIPS_INTRIN_R5900_VU_MEM_LOAD, {il.Mult(4, il.Register(4, op2.reg), il.Const(4, 16))})); + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(op2.reg + REG_VF0_X)}, MIPS_INTRIN_R5900_VU_MEM_LOAD, {il.Mult(4, il.Register(4, op3.reg), il.Const(4, 16)), il.Const(2, 0)})); + if (dest & (1 << 2)) + il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(op2.reg + REG_VF0_Y)}, MIPS_INTRIN_R5900_VU_MEM_LOAD, {il.Mult(4, il.Register(4, op3.reg), il.Const(4, 16)), il.Const(2, 1)})); + if (dest & (1 << 1)) + il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(op2.reg + REG_VF0_Z)}, MIPS_INTRIN_R5900_VU_MEM_LOAD, {il.Mult(4, il.Register(4, op3.reg), il.Const(4, 16)), il.Const(2, 2)})); + if (dest & (1 << 0)) + il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(op2.reg + REG_VF0_W)}, MIPS_INTRIN_R5900_VU_MEM_LOAD, {il.Mult(4, il.Register(4, op3.reg), il.Const(4, 16)), il.Const(2, 3)})); + il.AddInstruction(il.SetRegister(2, op3.reg, il.Add(2, il.Register(2, op3.reg), il.Const(2, op1.immediate)))); + break; + } + + case MIPS_VSQI: + case MIPS_VSQD: + { + // il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(LLIL_TEMP(0))}, MIPS_INTRIN_R5900_VU_MEM_LOAD, {il.Mult(4, il.Register(4, op2.reg), il.Const(4, 16))})); + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_R5900_VU_MEM_STORE, {il.Mult(4, il.Register(4, op3.reg), il.Const(4, 16)), il.Const(2, 0), il.Register(4, op2.reg + REG_VF0_X)})); + if (dest & (1 << 2)) + il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_R5900_VU_MEM_STORE, {il.Mult(4, il.Register(4, op3.reg), il.Const(4, 16)), il.Const(2, 1), il.Register(4, op2.reg + REG_VF0_Y)})); + if (dest & (1 << 1)) + il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_R5900_VU_MEM_STORE, {il.Mult(4, il.Register(4, op3.reg), il.Const(4, 16)), il.Const(2, 2), il.Register(4, op2.reg + REG_VF0_Z)})); + if (dest & (1 << 0)) + il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_R5900_VU_MEM_STORE, {il.Mult(4, il.Register(4, op3.reg), il.Const(4, 16)), il.Const(2, 3), il.Register(4, op2.reg + REG_VF0_W)})); + il.AddInstruction(il.SetRegister(2, op3.reg, il.Add(2, il.Register(2, op3.reg), il.Const(2, op1.immediate)))); + break; + } + + case MIPS_VCALLMS: + { + il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_R5900_VU0_CALLMS, {il.Const(4, op1.immediate << 3)})); + break; + } + case MIPS_VCALLMSR: + { + il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_R5900_VU0_CALLMSR, {})); + break; + } + + case MIPS_VIADD: + case MIPS_VIADDI: + { + il.AddInstruction(il.SetRegister(2, op1.reg, il.Add(2, il.Register(2, op2.reg), ReadILOperand(il, instr, 3, 2, 1)))); + break; + } + case MIPS_VFTOI0: + { + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatToInt(4, il.Register(4, op3.reg + REG_VF0_X)))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatToInt(4, il.Register(4, op3.reg + REG_VF0_Y)))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatToInt(4, il.Register(4, op3.reg + REG_VF0_Z)))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatToInt(4, il.Register(4, op3.reg + REG_VF0_W)))); + break; + } + case MIPS_VITOF0: + { + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.IntToFloat(4, il.Register(4, op3.reg + REG_VF0_X)))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.IntToFloat(4, il.Register(4, op3.reg + REG_VF0_Y)))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.IntToFloat(4, il.Register(4, op3.reg + REG_VF0_Z)))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.IntToFloat(4, il.Register(4, op3.reg + REG_VF0_W)))); + break; + } + case MIPS_VFTOI15: + case MIPS_VFTOI12: + case MIPS_VFTOI4: + { + int shift = 4; + switch (instr.operation) + { + case MIPS_VFTOI15: shift = 15; break; + case MIPS_VFTOI12: shift = 12; break; + case MIPS_VFTOI4: shift = 4; break; + } + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.RoundToInt(4, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.FloatConstSingle(1 << shift))))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.RoundToInt(4, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.FloatConstSingle(1 << shift))))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.RoundToInt(4, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.FloatConstSingle(1 << shift))))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.RoundToInt(4, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_W), il.FloatConstSingle(1 << shift))))); + break; + } + case MIPS_VITOF15: + case MIPS_VITOF12: + case MIPS_VITOF4: + { + int shift = 4; + switch (instr.operation) + { + case MIPS_VITOF15: shift = 15; break; + case MIPS_VITOF12: shift = 12; break; + case MIPS_VITOF4: shift = 4; break; + } + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatDiv(4, il.Register(4, op3.reg + REG_VF0_X), il.FloatConstSingle(1 << shift)))); + if (dest & (1 << 2)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatDiv(4, il.Register(4, op3.reg + REG_VF0_Y), il.FloatConstSingle(1 << shift)))); + if (dest & (1 << 1)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatDiv(4, il.Register(4, op3.reg + REG_VF0_Z), il.FloatConstSingle(1 << shift)))); + if (dest & (1 << 0)) + il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatDiv(4, il.Register(4, op3.reg + REG_VF0_W), il.FloatConstSingle(1 << shift)))); + break; + } + case MIPS_VIOR: + { + il.AddInstruction(il.SetRegister(2, op1.reg, il.Or(2, il.Register(2, op2.reg), il.Register(2, op3.reg)))); + break; + } + case MIPS_VMINI: + { + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + ConditionExecute(il, + il.FloatCompareLessThan(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + REG_VF0_X)), + il.SetRegister(4, op2.reg + REG_VF0_X, il.Register(4, op3.reg + REG_VF0_X)), + + il.SetRegister(4, op2.reg + REG_VF0_X, il.Register(4, op4.reg + REG_VF0_X))); + if (dest & (1 << 2)) + ConditionExecute(il, + il.FloatCompareLessThan(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + REG_VF0_Y)), + il.SetRegister(4, op2.reg + REG_VF0_Y, il.Register(4, op3.reg + REG_VF0_Y)), + + il.SetRegister(4, op2.reg + REG_VF0_Y, il.Register(4, op4.reg + REG_VF0_Y))); + if (dest & (1 << 1)) + ConditionExecute(il, + il.FloatCompareLessThan(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + REG_VF0_Z)), + il.SetRegister(4, op2.reg + REG_VF0_Z, il.Register(4, op3.reg + REG_VF0_Z)), + + il.SetRegister(4, op2.reg + REG_VF0_Z, il.Register(4, op4.reg + REG_VF0_Z))); + if (dest & (1 << 0)) + ConditionExecute(il, + il.FloatCompareLessThan(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + REG_VF0_W)), + il.SetRegister(4, op2.reg + REG_VF0_W, il.Register(4, op3.reg + REG_VF0_W)), + + il.SetRegister(4, op2.reg + REG_VF0_W, il.Register(4, op4.reg + REG_VF0_W))); + break; + } + case MIPS_VMINIx: + case MIPS_VMINIy: + case MIPS_VMINIz: + case MIPS_VMINIw: + { + unsigned char dest = op1.reg; + auto bc = REG_VF0_X + (op4.immediate - 1) * 33; + if (dest & (1 << 3)) + ConditionExecute(il, + il.FloatCompareLessThan(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + bc)), + il.SetRegister(4, op2.reg + REG_VF0_X, il.Register(4, op3.reg + REG_VF0_X)), + + il.SetRegister(4, op2.reg + REG_VF0_X, il.Register(4, op4.reg + bc))); + if (dest & (1 << 2)) + ConditionExecute(il, + il.FloatCompareLessThan(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + bc)), + il.SetRegister(4, op2.reg + REG_VF0_Y, il.Register(4, op3.reg + REG_VF0_Y)), + + il.SetRegister(4, op2.reg + REG_VF0_Y, il.Register(4, op4.reg + bc))); + if (dest & (1 << 1)) + ConditionExecute(il, + il.FloatCompareLessThan(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + bc)), + il.SetRegister(4, op2.reg + REG_VF0_Z, il.Register(4, op3.reg + REG_VF0_Z)), + + il.SetRegister(4, op2.reg + REG_VF0_Z, il.Register(4, op4.reg + bc))); + if (dest & (1 << 0)) + ConditionExecute(il, + il.FloatCompareLessThan(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + bc)), + il.SetRegister(4, op2.reg + REG_VF0_W, il.Register(4, op3.reg + REG_VF0_W)), + + il.SetRegister(4, op2.reg + REG_VF0_W, il.Register(4, op4.reg + bc))); + break; + } + case MIPS_VMAX: + { + unsigned char dest = op1.reg; + if (dest & (1 << 3)) + ConditionExecute(il, + il.FloatCompareGreaterThan(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + REG_VF0_X)), + il.SetRegister(4, op2.reg + REG_VF0_X, il.Register(4, op3.reg + REG_VF0_X)), + + il.SetRegister(4, op2.reg + REG_VF0_X, il.Register(4, op4.reg + REG_VF0_X))); + if (dest & (1 << 2)) + ConditionExecute(il, + il.FloatCompareGreaterThan(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + REG_VF0_Y)), + il.SetRegister(4, op2.reg + REG_VF0_Y, il.Register(4, op3.reg + REG_VF0_Y)), + + il.SetRegister(4, op2.reg + REG_VF0_Y, il.Register(4, op4.reg + REG_VF0_Y))); + if (dest & (1 << 1)) + ConditionExecute(il, + il.FloatCompareGreaterThan(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + REG_VF0_Z)), + il.SetRegister(4, op2.reg + REG_VF0_Z, il.Register(4, op3.reg + REG_VF0_Z)), + + il.SetRegister(4, op2.reg + REG_VF0_Z, il.Register(4, op4.reg + REG_VF0_Z))); + if (dest & (1 << 0)) + ConditionExecute(il, + il.FloatCompareGreaterThan(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + REG_VF0_W)), + il.SetRegister(4, op2.reg + REG_VF0_W, il.Register(4, op3.reg + REG_VF0_W)), + + il.SetRegister(4, op2.reg + REG_VF0_W, il.Register(4, op4.reg + REG_VF0_W))); + break; + } + case MIPS_VMAXx: + case MIPS_VMAXy: + case MIPS_VMAXz: + case MIPS_VMAXw: + { + unsigned char dest = op1.reg; + auto bc = REG_VF0_X + (op4.immediate - 1) * 33; + if (dest & (1 << 3)) + ConditionExecute(il, + il.FloatCompareGreaterThan(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + bc)), + il.SetRegister(4, op2.reg + REG_VF0_X, il.Register(4, op3.reg + REG_VF0_X)), + + il.SetRegister(4, op2.reg + REG_VF0_X, il.Register(4, op4.reg + bc))); + if (dest & (1 << 2)) + ConditionExecute(il, + il.FloatCompareGreaterThan(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + bc)), + il.SetRegister(4, op2.reg + REG_VF0_Y, il.Register(4, op3.reg + REG_VF0_Y)), + + il.SetRegister(4, op2.reg + REG_VF0_Y, il.Register(4, op4.reg + bc))); + if (dest & (1 << 1)) + ConditionExecute(il, + il.FloatCompareGreaterThan(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + bc)), + il.SetRegister(4, op2.reg + REG_VF0_Z, il.Register(4, op3.reg + REG_VF0_Z)), + + il.SetRegister(4, op2.reg + REG_VF0_Z, il.Register(4, op4.reg + bc))); + if (dest & (1 << 0)) + ConditionExecute(il, + il.FloatCompareGreaterThan(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + bc)), + il.SetRegister(4, op2.reg + REG_VF0_W, il.Register(4, op3.reg + REG_VF0_W)), + + il.SetRegister(4, op2.reg + REG_VF0_W, il.Register(4, op4.reg + bc))); + break; + } + + + // case MIPS_VDIV: + // case MIPS_VIADD: + // case MIPS_VIADDI: + // case MIPS_VMADD: + // case MIPS_VMADDAx: + // case MIPS_VMADDAy: + // case MIPS_VMADDAz: + // case MIPS_VMADDAw: + // case MIPS_VMADDx: + // case MIPS_VMADDy: + // case MIPS_VMADDz: + // case MIPS_VMADDw: + // case MIPS_VMUL: + // case MIPS_VMULAx: + // case MIPS_VMULAy: + // case MIPS_VMULAz: + // case MIPS_VMULAw: + // case MIPS_VMULq: + // case MIPS_VMULw: + // case MIPS_VMULx: + // case MIPS_VMULy: + // case MIPS_VMULz: + // case MIPS_VSUB: + // case MIPS_VSUBx: + // case MIPS_VSUBy: + // case MIPS_VSUBz: + // case MIPS_VSUBw: + + // case MIPS_VMAX: + // case MIPS_VMAXx: + // case MIPS_VMAXy: + // case MIPS_VMAXz: + // case MIPS_VMAXw: + // case MIPS_VMINI: + // case MIPS_VMINIx: + // case MIPS_VMINIy: + // case MIPS_VMINIz: + // case MIPS_VMINIw: + // ACCx = VF[fs]y × VF[ft]z + // ACCy = VF[fs]z × VF[ft]x + // ACCz = VF[fs]x × VF[ft]y + // case MIPS_VOPMULA: + // VF[fd]x = ACCx - VF[fs]y × VF[ft]z + // VF[fd]y = ACCy - VF[fs]z × VF[ft]x + // VF[fd]z = ACCz - VF[fs]x × VF[ft]y + // case MIPS_VOPMSUB: + // Mnemonic + // SQRT Q, VF[ft]ftf + // Operation + // Q = & & & &|VF[ft]ftf| + // case MIPS_VRSQRT: + // case MIPS_VSQRT: + + + // case MIPS_VFTOI4: + // case MIPS_VFTOI12: + // case MIPS_VFTOI15: + // case MIPS_VITOF4: + // case MIPS_VITOF12: + // case MIPS_VITOF15: + il.AddInstruction(il.Unimplemented()); break; // instructions that are just internal placeholders for other diff --git a/arch/mips/il.h b/arch/mips/il.h index df84f4a699..b67596070f 100644 --- a/arch/mips/il.h +++ b/arch/mips/il.h @@ -79,6 +79,15 @@ enum MipsIntrinsic : uint32_t CNMIPS_INTRIN_HWR31, CNMIPS_INTRIN_POP, CNMIPS_INTRIN_DPOP, + + MIPS_INTRIN_R5900_VWAITQ, + MIPS_INTRIN_R5900_VU_MEM_LOAD, + MIPS_INTRIN_R5900_VU_MEM_STORE, + MIPS_INTRIN_R5900_VU0_CALLMS, + MIPS_INTRIN_R5900_VU0_CALLMSR, + + MIPS_INTRIN_COP0_CONDITION, + MIPS_INTRIN_INVALID=0xFFFFFFFF, }; @@ -88,6 +97,74 @@ bool GetLowLevelILForInstruction( BinaryNinja::LowLevelILFunction& il, mips::Instruction& instr, size_t addrSize, - uint32_t decomposeFlags); + uint32_t decomposeFlags, + mips::MipsVersion version); + +BinaryNinja::ExprId GetConditionForInstruction(BinaryNinja::LowLevelILFunction& il, mips::Instruction& instr, std::function registerSize); +#ifdef __cplusplus +extern "C" { + namespace mips { +#endif -BinaryNinja::ExprId GetConditionForInstruction(BinaryNinja::LowLevelILFunction& il, mips::Instruction& instr, size_t registerSize); +static inline const size_t get_register_width(size_t reg, MipsVersion version, size_t maxWidth=8) { + size_t width = 32; + switch (version) + { + case MIPS_1: + case MIPS_2: + case MIPS_3: + case MIPS_4: + case MIPS_32: + width = 32; + break; + case MIPS_64: + width = 64; + break; + case MIPS_R5900: + switch (reg) + { + case REG_LO: + case REG_HI: + width = 128; + break; + case REG_LO1: + case REG_HI1: + width = 64; + break; + case R5900_SA: + case REG_VI: + case REG_VQ: + case REG_VR: // Technically 23-bit + case REG_VP: + width = 32; + break; + default: + if (reg >= REG_VI0 && reg <= REG_VI15) + width = 16; + else if (reg >= REG_VCCR_STATUS && reg <= REG_VCCR_CMSAR1) + width = 32; + else if (REG_ZERO <= reg && reg <= REG_RA) + width = 128; // 64; // 128 + else if (FPREG_F0 <= reg && reg <= FPREG_F31) + width = 32; + else if (reg >= REG_VACC && reg <= REG_VF31) + width = 128; + else if (reg >= REG_VACC_X && reg <= REG_VF31_W) + width = 32; + else if (reg >= REG_VACC_XY && reg <= REG_VF31_ZW) + width = 64; + else if (reg >= REG_VACC_XYZ && reg <= REG_VF31_YZW) + width = 96; + else if (reg >= REG_VACC_XYZW && reg <= REG_VF31_XYZW) + width = 128; + } + default: + break; + } + width /= 8; + return width <= maxWidth ? width : maxWidth; +} +#ifdef __cplusplus +} +}//end namespace +#endif \ No newline at end of file diff --git a/arch/mips/mips/mips.c b/arch/mips/mips/mips.c index e046d795de..b03a2f014f 100644 --- a/arch/mips/mips/mips.c +++ b/arch/mips/mips/mips.c @@ -10,6 +10,7 @@ using namespace mips; #endif #define REG_ reg +#define V_REG_ reg #define FLAG_ reg #define FPREG_ reg #define FPCCREG_ reg @@ -22,6 +23,7 @@ using namespace mips; do { \ instruction->operands[0].operandClass = A;\ instruction->operands[0].VAR(A) = a;\ + instruction->numOperands = 1;\ } while (0); #define INS_2(A,a,B,b)\ @@ -30,6 +32,7 @@ using namespace mips; instruction->operands[0].VAR(A) = a;\ instruction->operands[1].operandClass = B;\ instruction->operands[1].VAR(B) = b;\ + instruction->numOperands = 2;\ } while (0); #define INS_3(A,a,B,b,C,c)\ @@ -40,6 +43,7 @@ using namespace mips; instruction->operands[1].VAR(B) = b;\ instruction->operands[2].operandClass = C;\ instruction->operands[2].VAR(C) = c;\ + instruction->numOperands = 3;\ } while (0); #define INS_4(A,a,B,b,C,c,D,d)\ @@ -52,6 +56,7 @@ using namespace mips; instruction->operands[2].VAR(C) = c;\ instruction->operands[3].operandClass = D;\ instruction->operands[3].VAR(D) = d;\ + instruction->numOperands = 4;\ } while (0); @@ -67,7 +72,7 @@ static Operation cavium_mips_base_table[8][8] = { }; //Fields are: [Version][opcode_high][opcode_low] -static Operation mips_base_table[6][8][8] = { +static Operation mips_base_table[7][8][8] = { { //MIPS version 1 {MIPS_INVALID, MIPS_INVALID, MIPS_J, MIPS_JAL, MIPS_BEQ, MIPS_BNE, MIPS_BLEZ, MIPS_BGTZ}, {MIPS_ADDI, MIPS_ADDIU, MIPS_SLTI, MIPS_SLTIU, MIPS_ANDI, MIPS_ORI, MIPS_XORI, MIPS_LUI}, @@ -122,11 +127,20 @@ static Operation mips_base_table[6][8][8] = { {MIPS_SB, MIPS_SH, MIPS_SWL, MIPS_SW, MIPS_SDL, MIPS_SDR, MIPS_SWR, MIPS_CACHE}, {MIPS_LL, MIPS_LWC1, MIPS_LWC2, MIPS_PREF, MIPS_LLD, MIPS_LDC1, MIPS_LDC2, MIPS_LD}, {MIPS_SC, MIPS_SWC1, MIPS_SWC2, MIPS_INVALID, MIPS_SCD, MIPS_SDC1, MIPS_SDC2, MIPS_SD} + },{ // MIPS r5900 + {MIPS_INVALID, MIPS_INVALID, MIPS_J, MIPS_JAL, MIPS_BEQ, MIPS_BNE, MIPS_BLEZ, MIPS_BGTZ}, + {MIPS_ADDI, MIPS_ADDIU, MIPS_SLTI, MIPS_SLTIU, MIPS_ANDI, MIPS_ORI, MIPS_XORI, MIPS_LUI}, + {MIPS_COP0, MIPS_COP1, MIPS_COP2, MIPS_INVALID, MIPS_BEQL, MIPS_BNEL, MIPS_BLEZL, MIPS_BGTZL}, + {MIPS_DADDI, MIPS_DADDIU, MIPS_LDL, MIPS_LDR, MIPS_INVALID, MIPS_INVALID, MIPS_LQ, MIPS_SQ}, + {MIPS_LB, MIPS_LH, MIPS_LWL, MIPS_LW, MIPS_LBU, MIPS_LHU, MIPS_LWR, MIPS_LWU}, + {MIPS_SB, MIPS_SH, MIPS_SWL, MIPS_SW, MIPS_SDL, MIPS_SDR, MIPS_SWR, MIPS_CACHE}, + {MIPS_INVALID, MIPS_LWC1, MIPS_INVALID, MIPS_PREF, MIPS_INVALID, MIPS_INVALID, MIPS_LDC2, MIPS_LD}, + {MIPS_INVALID, MIPS_SWC1, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_SDC2, MIPS_SD} } }; //Fields are: [Version][function_high][function_low] -static Operation mips_special_table[6][8][8] = { +static Operation mips_special_table[7][8][8] = { { //MIPS version 1 {MIPS_SLL, MIPS_INVALID, MIPS_SRL, MIPS_SRA, MIPS_SLLV, MIPS_INVALID, MIPS_SRLV, MIPS_SRAV}, {MIPS_JR, MIPS_JALR, MIPS_INVALID, MIPS_INVALID, MIPS_SYSCALL, MIPS_BREAK, MIPS_INVALID, MIPS_INVALID}, @@ -181,10 +195,19 @@ static Operation mips_special_table[6][8][8] = { {MIPS_INVALID, MIPS_INVALID, MIPS_SLT, MIPS_SLTU, MIPS_DADD, MIPS_DADDU, MIPS_DSUB, MIPS_DSUBU}, {MIPS_TGE, MIPS_TGEU, MIPS_TLT, MIPS_TLTU, MIPS_TEQ, MIPS_INVALID, MIPS_TNE, MIPS_INVALID}, {MIPS_DSLL, MIPS_INVALID, MIPS_DSRL, MIPS_DSRA, MIPS_DSLL32, MIPS_INVALID, MIPS_DSRL32, MIPS_DSRA32} + },{ //MIPS r5900 + {MIPS_SLL, MIPS_MOVCI, MIPS_SRL, MIPS_SRA, MIPS_SLLV, MIPS_INVALID, MIPS_SRLV, MIPS_SRAV}, + {MIPS_JR, MIPS_JALR, MIPS_MOVZ, MIPS_MOVN, MIPS_SYSCALL, MIPS_BREAK, MIPS_INVALID, MIPS_SYNC}, + {MIPS_MFHI, MIPS_MTHI, MIPS_MFLO, MIPS_MTLO, MIPS_DSLLV, MIPS_INVALID, MIPS_DSRLV, MIPS_DSRAV}, + {MIPS_MULT, MIPS_MULTU, MIPS_DIV, MIPS_DIVU, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_ADD, MIPS_ADDU, MIPS_SUB, MIPS_SUBU, MIPS_AND, MIPS_OR, MIPS_XOR, MIPS_NOR}, + {MIPS_INVALID, MIPS_INVALID, MIPS_SLT, MIPS_SLTU, MIPS_DADD, MIPS_DADDU, MIPS_DSUB, MIPS_DSUBU}, + {MIPS_TGE, MIPS_TGEU, MIPS_TLT, MIPS_TLTU, MIPS_TEQ, MIPS_INVALID, MIPS_TNE, MIPS_INVALID}, + {MIPS_DSLL, MIPS_INVALID, MIPS_DSRL, MIPS_DSRA, MIPS_DSLL32, MIPS_INVALID, MIPS_DSRL32, MIPS_DSRA32} } }; -static Operation mips_regimm_table[6][4][8] = { +static Operation mips_regimm_table[7][4][8] = { { //MIPS version 1 {MIPS_BLTZ, MIPS_BGEZ, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, @@ -215,6 +238,11 @@ static Operation mips_regimm_table[6][4][8] = { {MIPS_TGEI, MIPS_TGEIU, MIPS_TLTI, MIPS_TLTIU, MIPS_TEQI, MIPS_INVALID, MIPS_TNEI, MIPS_INVALID}, {MIPS_BLTZAL, MIPS_BGEZAL, MIPS_BLTZALL, MIPS_BGEZALL, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_SYNCI} + },{ //MIPS r5900 + {MIPS_BLTZ, MIPS_BGEZ, MIPS_BLTZL, MIPS_BGEZL, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_TGEI, MIPS_TGEIU, MIPS_TLTI, MIPS_TLTIU, MIPS_TEQI, MIPS_INVALID, MIPS_TNEI, MIPS_INVALID}, + {MIPS_BLTZAL, MIPS_BGEZAL, MIPS_BLTZALL, MIPS_BGEZALL, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_MTSAB, MIPS_MTSAH, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID} } }; @@ -325,487 +353,829 @@ static Operation mips_v5_cop1x_table[8][8] = { {MIPS_NMSUB_S, MIPS_NMSUB_D, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_NMSUB_PS, MIPS_INVALID}, }; +static Operation mips_mmi_r5900_table[8][8] = { // 0x1c + {MIPS_MADD, MIPS_MADDU, MIPS_INVALID, MIPS_INVALID, MIPS_PLZCW}, + {MIPS_MMI0 /* MMI0 */, MIPS_MMI2 /* MMI2 */, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_MFHI1, MIPS_MTHI1, MIPS_MFLO1, MIPS_MTLO1, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_MULT1, MIPS_MULTU1, MIPS_DIV1, MIPS_DIVU1, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_MADD1, MIPS_MADDU1, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_MMI1 /* MMI1 */, MIPS_MMI3 /* MMI3 */, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_PMFHL, MIPS_PMTHL, MIPS_INVALID, MIPS_INVALID, MIPS_PSLLH, MIPS_INVALID, MIPS_PSRLH, MIPS_PSRAH}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_PSLLW, MIPS_INVALID, MIPS_PSRLW, MIPS_PSRAW} +}; -static const char* const OperationStrings[] = { - "INVALID", - "abs.d", - "abs.ps", - "abs.s", - "add.d", - "add.ps", - "add.s", - "add", - "addi", - "addiu", - "addr", - "addu", - "align", - "alnv.ps", - "and", - "andi", - "b", - "bal", - "bc1any2", - "bc1any4", - "bc1eqz", - "bc1f", - "bc1fl", - "bc1nez", - "bc1t", - "bc1tl", - "bc2eqz", - "bc2f", - "bc2fl", - "bc2nez", - "bc2t", - "bc2tl", - "bcnez", - "beq", - "beql", - "beqz", - "bgez", - "bgezal", - "bgezall", - "bgezl", - "bgtz", - "bgtzl", - "bitswap", - "blez", - "blezl", - "bltz", - "bltzal", - "bltzall", - "bltzl", - "bne", - "bnel", - "bnez", - "bnz.b", - "bnz.d", - "bnz.h", - "bnz.w", - "break", - "bshfl", - "bz.b", - "bz.d", - "bz.h", - "bz.w", - "c.df.d", - "c.eq.d", - "c.eq.ps", - "c.eq.s", - "c.eq", - "c.f.d", - "c.f.ps", - "c.f.s", - "c.f", - "c.le.d", - "c.le.ps", - "c.le.s", - "c.le", - "c.lt.d", - "c.lt.ps", - "c.lt.s", - "c.lt", - "c.nge.d", - "c.nge.ps", - "c.nge.s", - "c.nge", - "c.ngl.d", - "c.ngl.ps", - "c.ngl.s", - "c.ngl", - "c.ngle.d", - "c.ngle.ps", - "c.ngle.s", - "c.ngle", - "c.ngt.d", - "c.ngt.ps", - "c.ngt.s", - "c.ngt", - "c.ole.d", - "c.ole.ps", - "c.ole.s", - "c.ole", - "c.olt.d", - "c.olt.ps", - "c.olt.s", - "c.olt", - "c.seq.d", - "c.seq.ps", - "c.seq.s", - "c.seq", - "c.sf.d", - "c.sf.ps", - "c.sf.s", - "c.sf", - "c.ueq.d", - "c.ueq.ps", - "c.ueq.s", - "c.ueq", - "c.ule.d", - "c.ule.ps", - "c.ule.s", - "c.ule", - "c.ult.d", - "c.ult.ps", - "c.ult.s", - "c.ult", - "c.un.d", - "c.un.ps", - "c.un.s", - "c.un", - "c1", - "c2", - "cache", - "ceil.l.d", - "ceil.l.s", - "ceil.l", - "ceil.w.d", - "ceil.w.s", - "ceil.w", - "cfc0", - "cfc1", - "cfc2", - "class.d", - "class.s", - "clo", - "clz", - "cop0", - "cop1", - "cop1x", - "cop2", - "cop3", - "ctc0", - "ctc1", - "ctc2", - "cvt.d.s", - "cvt.d.w", - "cvt.l.d", - "cvt.l.s", - "cvt.l", - "cvt.ps.pw", - "cvt.ps.s", - "cvt.ps", - "cvt.pw.ps", - "cvt.s.d", - "cvt.s.l", - "cvt.s.pl", - "cvt.s.pu", - "cvt.s.w", - "cvt.w.d", - "cvt.w.s", - "cvt.w", - "dadd", - "daddi", - "daddiu", - "daddu", - "dbshfl", - "dclo", - "dclz", - "ddiv", - "ddivu", - "deret", - "dext", - "dextm", - "dextu", - "di", - "dins", - "dinsm", - "dinsu", - "div.d", - "div.ps", - "div.s", - "div", - "divu", - "dmfc0", - "dmfc1", - "dmfc2", - "dmult", - "dmultu", - "dmtc0", - "dmtc1", - "dmtc2", - "dret", - "drotr", - "drotr32", - "drotrv", - "dsbh", - "dshd", - "dsll", - "dsll32", - "dsllv", - "dsra", - "dsra32", - "dsrav", - "dsrl", - "dsrl32", - "dsrlv", - "dsub", - "dsubu", - "ehb", - "ei", - "eret", - "ext", - "floor.l.d", - "floor.l.s", - "floor.l", - "floor.w.d", - "floor.w.s", - "floor.w", - "ins", - "j", - "jal", - "jalr.hb", - "jalr", - "jalx", - "jr.hb", - "jr", - "lb", - "lbu", - "lbux", - "ld", - "ldc1", - "ldc2", - "ldc3", - "ldl", - "ldr", - "ldxc1", - "lh", - "lhi", - "lhu", - "lhx", - "li", - "ll", - "lld", - "llo", - "lui", - "luxc1", - "lw", - "lwc1", - "lwc2", - "lwc3", - "lwl", - "lwr", - "lwu", - "lwx", - "lwxc1", - "lx", - "madd.d", - "madd.ps", - "madd.s", - "madd", - "maddf.d", - "maddf.s", - "maddu", - "mfc0", - "mfc1", - "mfc2", - "mfhc1", - "mfhc2", - "mfhi", - "mflo", - "mov.d", - "mov.ps", - "mov.s", - "movcf", - "movci", - "move", - "movf.d", - "movf.ps", - "movf.s", - "movf", - "movn.d", - "movn.ps", - "movn.s", - "movn", - "movt.d", - "movt.ps", - "movt.s", - "movt", - "movz.d", - "movz.ps", - "movz.s", - "movz", - "msub.d", - "msub.ps", - "msub.s", - "msub", - "msubf.d", - "msubf.s", - "msubu", - "mtc0", - "mtc1", - "mtc2", - "mthc1", - "mthc2", - "mthi", - "mtlo", - "mul.d", - "mul.ps", - "mul.s", - "mul", - "mulr", - "mult", - "multu", - "neg.d", - "neg.ps", - "neg.s", - "neg", - "negu", - "nmadd.d", - "nmadd.ps", - "nmadd.s", - "nmsub.d", - "nmsub.ps", - "nmsub.s", - "nop", - "nor", - "not", - "or", - "ori", - "pause", - "pll.ps", - "plu.ps", - "pref", - "prefx", - "pul.ps", - "puu.ps", - "rdhwr", - "rdpgpr", - "recip.d", - "recip.s", - "recip", - "recip1", - "recip2", - "rint.d", - "rint.s", - "rotr", - "rotrv", - "round.l.d", - "round.l.s", - "round.l", - "round.w.d", - "round.w.s", - "round.w", - "rsqrt.d", - "rsqrt.s", - "rsqrt", - "rsqrt1", - "rsqrt2", - "sb", - "sc", - "scd", - "sd", - "sdbbp", - "sdc1", - "sdc2", - "sdc3", - "sdl", - "sdr", - "sdxc1", - "seb", - "seh", - "sel.d", - "sel.s", - "sh", - "sll", - "sllv", - "slt", - "slti", - "sltiu", - "sltu", - "sqrt.d", - "sqrt.ps", - "sqrt.s", - "sra", - "srav", - "srl", - "srlv", - "ssnop", - "sub.d", - "sub.ps", - "sub.s", - "sub", - "subu", - "suxc1", - "sw", - "swc1", - "swc2", - "swc3", - "swl", - "swr", - "swxc1", - "sync", - "synci", - "syscall", - "teq", - "teqi", - "tge", - "tgei", - "tgeiu", - "tgeu", - "tlbinv", - "tlbinvf", - "tlbp", - "tlbr", - "tlbwi", - "tlbwr", - "tlt", - "tlti", - "tltiu", - "tltu", - "tne", - "tnei", - "trap", - "trunc.l.d", - "trunc.l.s", - "trunc.l", - "trunc.w.d", - "trunc.w.s", - "trunc.w", - "wait", - "wrpgpr", - "wsbh", - "xor", - "xori", - - // cavium instructions - "baddu", - "bbit0", - "bbit032", - "bbit1", - "bbit132", - "cins", - "cins32", - "cvm", - "dmul", - "dpop", - "exts", - "exts32", - "mtm0", - "mtm1", - "mtm2", - "mtp0", - "mtp1", - "mtp2", - "pop", - "rdhwr", - "saa", - "saad", - "seq", - "seqi", - "sne", - "snei", - "synciobdma", - "syncs", - "syncw", - "syncws", - "v3mulu", - "vmm0", - "vmulu", - "zcb", - "zcbt", +static Operation mips_r5900_mmi0_table[8][4] = { + {MIPS_PADDW, MIPS_PSUBW, MIPS_PCGTW, MIPS_PMAXW}, + {MIPS_PADDH, MIPS_PSUBH, MIPS_PCGTH, MIPS_PMAXH}, + {MIPS_PADDB, MIPS_PSUBB, MIPS_PCGTB, MIPS_INVALID}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_PADDSW, MIPS_PSUBSW, MIPS_PEXTLW, MIPS_PPACW}, + {MIPS_PADDSH, MIPS_PSUBSH, MIPS_PEXTLH, MIPS_PPACH}, + {MIPS_PADDSB, MIPS_PSUBSB, MIPS_PEXTLB, MIPS_PPACB}, + {MIPS_INVALID, MIPS_INVALID, MIPS_PEXT5, MIPS_PPAC5}, +}; + +static Operation mips_r5900_mmi1_table[8][4] = { + {MIPS_INVALID, MIPS_PABSW, MIPS_PCEQW, MIPS_PMINW}, + {MIPS_PADSBH, MIPS_PABSH, MIPS_PCEQH, MIPS_PMINH}, + {MIPS_INVALID, MIPS_INVALID, MIPS_PCEQB, MIPS_INVALID}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_PADDUW, MIPS_PSUBUW, MIPS_PEXTUW, MIPS_INVALID}, + {MIPS_PADDUH, MIPS_PSUBUH, MIPS_PEXTUH, MIPS_INVALID}, + {MIPS_PADDUB, MIPS_PSUBUB, MIPS_PEXTUB, MIPS_QFSRV}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, +}; + +static Operation mips_r5900_mmi2_table[8][4] = { + {MIPS_PMADDW, MIPS_INVALID, MIPS_PSLLVW, MIPS_PSRLVW}, // 000 + {MIPS_PMSUBW, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, // 001 + {MIPS_PMFHI, MIPS_PMFLO, MIPS_PINTH, MIPS_INVALID}, // 010 + {MIPS_PMULTW, MIPS_PDIVW, MIPS_PCPYLD, MIPS_INVALID}, // 011 + {MIPS_PMADDH, MIPS_PHMADH, MIPS_PAND, MIPS_PXOR}, // 100 + {MIPS_PMSUBH, MIPS_PHMSBH, MIPS_INVALID, MIPS_INVALID}, // 101 + {MIPS_INVALID, MIPS_INVALID, MIPS_PEXEH, MIPS_PREVH}, // 110 + {MIPS_PMULTH, MIPS_PDIVBW, MIPS_PEXEW, MIPS_PROT3W}, // 111 +}; +static Operation mips_r5900_mmi3_table[8][4] = { + {MIPS_PMADDUW, MIPS_INVALID, MIPS_INVALID, MIPS_PSRAVW}, // 000 + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, // 001 + {MIPS_PMTHI, MIPS_PMTLO, MIPS_PINTEH, MIPS_INVALID}, // 010 + {MIPS_PMULTUW, MIPS_PDIVUW, MIPS_PCPYUD, MIPS_INVALID}, // 011 + {MIPS_INVALID, MIPS_INVALID, MIPS_POR, MIPS_PNOR}, // 100 + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, // 101 + {MIPS_INVALID, MIPS_INVALID, MIPS_PEXCH, MIPS_PCPYH}, // 110 + {MIPS_INVALID, MIPS_INVALID, MIPS_PEXCW, MIPS_INVALID}, // 111 +}; + +static Operation mips_r5900_cop2_special1_table[8][8] = { + {MIPS_VADDx, MIPS_VADDy, MIPS_VADDz, MIPS_VADDw, MIPS_VSUBx, MIPS_VSUBy, MIPS_VSUBz, MIPS_VSUBw}, + {MIPS_VMADDx, MIPS_VMADDy, MIPS_VMADDz, MIPS_VMADDw, MIPS_VMSUBx, MIPS_VMSUBy, MIPS_VMSUBz, MIPS_VMSUBw}, + {MIPS_VMAXx, MIPS_VMAXy, MIPS_VMAXz, MIPS_VMAXw, MIPS_VMINIx, MIPS_VMINIy, MIPS_VMINIz, MIPS_VMINIw}, + {MIPS_VMULx, MIPS_VMULy, MIPS_VMULz, MIPS_VMULw, MIPS_VMULq, MIPS_VMAXi, MIPS_VMULi, MIPS_VMINIi}, + {MIPS_VADDq, MIPS_VMADDq, MIPS_VADDi, MIPS_VMADDi, MIPS_VSUBq, MIPS_VMSUBq, MIPS_VSUBi, MIPS_VMSUBi}, + {MIPS_VADD, MIPS_VMADD, MIPS_VMUL, MIPS_VMAX, MIPS_VSUB, MIPS_VMSUB, MIPS_VOPMSUB, MIPS_VMINI}, + {MIPS_VIADD, MIPS_VISUB, MIPS_VIADDI, MIPS_INVALID, MIPS_VIAND, MIPS_VIOR, MIPS_INVALID, MIPS_INVALID}, + {MIPS_VCALLMS, MIPS_VCALLMSR, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, +}; + +static Operation mips_r5900_cop2_special2_table[16][8] = { + {MIPS_VADDAx, MIPS_VADDAy, MIPS_VADDAz, MIPS_VADDAw, MIPS_VSUBAx, MIPS_VSUBAy, MIPS_VSUBAz, MIPS_VSUBAw}, + {MIPS_VMADDAx, MIPS_VMADDAy, MIPS_VMADDAz, MIPS_VMADDAw, MIPS_VMSUBAx, MIPS_VMSUBAy, MIPS_VMSUBAz, MIPS_VMSUBAw}, + {MIPS_VITOF0, MIPS_VITOF4, MIPS_VITOF12, MIPS_VITOF15, MIPS_VFTOI0, MIPS_VFTOI4, MIPS_VFTOI12, MIPS_VFTOI15}, + {MIPS_VMULAx, MIPS_VMULAy, MIPS_VMULAz, MIPS_VMULAw, MIPS_VMULAq, MIPS_VABS, MIPS_VMULAi, MIPS_VCLIPw}, + {MIPS_VADDAq, MIPS_VMADDAq, MIPS_VADDAi, MIPS_VMADDAi, MIPS_VSUBAq, MIPS_VMSUBAq, MIPS_VSUBAi, MIPS_VMSUBAi}, + {MIPS_VADDA, MIPS_VMADDA, MIPS_VMULA, MIPS_INVALID, MIPS_VSUBA, MIPS_VMSUBA, MIPS_VOPMULA, MIPS_VNOP}, + {MIPS_VMOVE, MIPS_VMR32, MIPS_INVALID, MIPS_INVALID, MIPS_VLQI, MIPS_VSQI, MIPS_VLQD, MIPS_VSQD}, + {MIPS_VDIV, MIPS_VSQRT, MIPS_VRSQRT, MIPS_VWAITQ, MIPS_VMTIR, MIPS_VMFIR, MIPS_VILWR, MIPS_VISWR}, + {MIPS_VRNEXT, MIPS_VRGET, MIPS_VRINIT, MIPS_VRXOR, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, +}; +static Operation mips_r5900_cop1_S_table[8][8] = { + {MIPS_ADD_S, MIPS_SUB_S, MIPS_MUL_S, MIPS_DIV_S, MIPS_SQRT_S, MIPS_ABS_S, MIPS_MOV_S, MIPS_NEG_S}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_RSQRT_S, MIPS_INVALID}, + {MIPS_ADDA_S, MIPS_SUBA_S, MIPS_MULA_S, MIPS_INVALID, MIPS_MADD_S, MIPS_MSUB_S, MIPS_MADDA_S, MIPS_MSUBA_S}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_CVT_W_S, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_MAX_S, MIPS_MIN_S, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {MIPS_C_F_S, MIPS_INVALID, MIPS_C_EQ_S, MIPS_INVALID, MIPS_C_LT_S, MIPS_INVALID, MIPS_C_LE_S, MIPS_INVALID}, + {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, +}; + +static const char* const OperationStrings[] = { + "INVALID", + "abs.d", + "abs.ps", + "abs.s", + "add.d", + "add.ps", + "add.s", + "add", + "addi", + "addiu", + "addr", + "addu", + "align", + "alnv.ps", + "and", + "andi", + "b", + "bal", + "bc1any2", + "bc1any4", + "bc1eqz", + "bc1f", + "bc1fl", + "bc1nez", + "bc1t", + "bc1tl", + "bc2eqz", + "bc2f", + "bc2fl", + "bc2nez", + "bc2t", + "bc2tl", + "bcnez", + "beq", + "beql", + "beqz", + "bgez", + "bgezal", + "bgezall", + "bgezl", + "bgtz", + "bgtzl", + "bitswap", + "blez", + "blezl", + "bltz", + "bltzal", + "bltzall", + "bltzl", + "bne", + "bnel", + "bnez", + "bnz.b", + "bnz.d", + "bnz.h", + "bnz.w", + "break", + "bshfl", + "bz.b", + "bz.d", + "bz.h", + "bz.w", + "c.df.d", + "c.eq.d", + "c.eq.ps", + "c.eq.s", + "c.eq", + "c.f.d", + "c.f.ps", + "c.f.s", + "c.f", + "c.le.d", + "c.le.ps", + "c.le.s", + "c.le", + "c.lt.d", + "c.lt.ps", + "c.lt.s", + "c.lt", + "c.nge.d", + "c.nge.ps", + "c.nge.s", + "c.nge", + "c.ngl.d", + "c.ngl.ps", + "c.ngl.s", + "c.ngl", + "c.ngle.d", + "c.ngle.ps", + "c.ngle.s", + "c.ngle", + "c.ngt.d", + "c.ngt.ps", + "c.ngt.s", + "c.ngt", + "c.ole.d", + "c.ole.ps", + "c.ole.s", + "c.ole", + "c.olt.d", + "c.olt.ps", + "c.olt.s", + "c.olt", + "c.seq.d", + "c.seq.ps", + "c.seq.s", + "c.seq", + "c.sf.d", + "c.sf.ps", + "c.sf.s", + "c.sf", + "c.ueq.d", + "c.ueq.ps", + "c.ueq.s", + "c.ueq", + "c.ule.d", + "c.ule.ps", + "c.ule.s", + "c.ule", + "c.ult.d", + "c.ult.ps", + "c.ult.s", + "c.ult", + "c.un.d", + "c.un.ps", + "c.un.s", + "c.un", + "c1", + "c2", + "cache", + "ceil.l.d", + "ceil.l.s", + "ceil.l", + "ceil.w.d", + "ceil.w.s", + "ceil.w", + "cfc0", + "cfc1", + "cfc2", + "class.d", + "class.s", + "clo", + "clz", + "cop0", + "cop1", + "cop1x", + "cop2", + "cop3", + "ctc0", + "ctc1", + "ctc2", + "cvt.d.s", + "cvt.d.w", + "cvt.l.d", + "cvt.l.s", + "cvt.l", + "cvt.ps.pw", + "cvt.ps.s", + "cvt.ps", + "cvt.pw.ps", + "cvt.s.d", + "cvt.s.l", + "cvt.s.pl", + "cvt.s.pu", + "cvt.s.w", + "cvt.w.d", + "cvt.w.s", + "cvt.w", + "dadd", + "daddi", + "daddiu", + "daddu", + "dbshfl", + "dclo", + "dclz", + "ddiv", + "ddivu", + "deret", + "dext", + "dextm", + "dextu", + "di", + "dins", + "dinsm", + "dinsu", + "div.d", + "div.ps", + "div.s", + "div", + "divu", + "dmfc0", + "dmfc1", + "dmfc2", + "dmult", + "dmultu", + "dmtc0", + "dmtc1", + "dmtc2", + "dret", + "drotr", + "drotr32", + "drotrv", + "dsbh", + "dshd", + "dsll", + "dsll32", + "dsllv", + "dsra", + "dsra32", + "dsrav", + "dsrl", + "dsrl32", + "dsrlv", + "dsub", + "dsubu", + "ehb", + "ei", + "eret", + "ext", + "floor.l.d", + "floor.l.s", + "floor.l", + "floor.w.d", + "floor.w.s", + "floor.w", + "ins", + "j", + "jal", + "jalr.hb", + "jalr", + "jalx", + "jr.hb", + "jr", + "lb", + "lbu", + "lbux", + "ld", + "ldc1", + "ldc2", + "ldc3", + "ldl", + "ldr", + "ldxc1", + "lh", + "lhi", + "lhu", + "lhx", + "li", + "ll", + "lld", + "llo", + "lui", + "luxc1", + "lw", + "lwc1", + "lwc2", + "lwc3", + "lwl", + "lwr", + "lwu", + "lwx", + "lwxc1", + "lx", + "madd.d", + "madd.ps", + "madd.s", + "madd", + "maddf.d", + "maddf.s", + "maddu", + "mfc0", + "mfc1", + "mfc2", + "mfhc1", + "mfhc2", + "mfhi", + "mflo", + "mov.d", + "mov.ps", + "mov.s", + "movcf", + "movci", + "move", + "movf.d", + "movf.ps", + "movf.s", + "movf", + "movn.d", + "movn.ps", + "movn.s", + "movn", + "movt.d", + "movt.ps", + "movt.s", + "movt", + "movz.d", + "movz.ps", + "movz.s", + "movz", + "msub.d", + "msub.ps", + "msub.s", + "msub", + "msubf.d", + "msubf.s", + "msubu", + "mtc0", + "mtc1", + "mtc2", + "mthc1", + "mthc2", + "mthi", + "mtlo", + "mul.d", + "mul.ps", + "mul.s", + "mul", + "mulr", + "mult", + "multu", + "neg.d", + "neg.ps", + "neg.s", + "neg", + "negu", + "nmadd.d", + "nmadd.ps", + "nmadd.s", + "nmsub.d", + "nmsub.ps", + "nmsub.s", + "nop", + "nor", + "not", + "or", + "ori", + "pause", + "pll.ps", + "plu.ps", + "pref", + "prefx", + "pul.ps", + "puu.ps", + "rdhwr", + "rdpgpr", + "recip.d", + "recip.s", + "recip", + "recip1", + "recip2", + "rint.d", + "rint.s", + "rotr", + "rotrv", + "round.l.d", + "round.l.s", + "round.l", + "round.w.d", + "round.w.s", + "round.w", + "rsqrt.d", + "rsqrt.s", + "rsqrt", + "rsqrt1", + "rsqrt2", + "sb", + "sc", + "scd", + "sd", + "sdbbp", + "sdc1", + "sdc2", + "sdc3", + "sdl", + "sdr", + "sdxc1", + "seb", + "seh", + "sel.d", + "sel.s", + "sh", + "sll", + "sllv", + "slt", + "slti", + "sltiu", + "sltu", + "sqrt.d", + "sqrt.ps", + "sqrt.s", + "sra", + "srav", + "srl", + "srlv", + "ssnop", + "sub.d", + "sub.ps", + "sub.s", + "sub", + "subu", + "suxc1", + "sw", + "swc1", + "swc2", + "swc3", + "swl", + "swr", + "swxc1", + "sync", + "synci", + "syscall", + "teq", + "teqi", + "tge", + "tgei", + "tgeiu", + "tgeu", + "tlbinv", + "tlbinvf", + "tlbp", + "tlbr", + "tlbwi", + "tlbwr", + "tlt", + "tlti", + "tltiu", + "tltu", + "tne", + "tnei", + "trap", + "trunc.l.d", + "trunc.l.s", + "trunc.l", + "trunc.w.d", + "trunc.w.s", + "trunc.w", + "wait", + "wrpgpr", + "wsbh", + "xor", + "xori", + + // cavium instructions + "baddu", + "bbit0", + "bbit032", + "bbit1", + "bbit132", + "cins", + "cins32", + "cvm", + "dmul", + "dpop", + "exts", + "exts32", + "mtm0", + "mtm1", + "mtm2", + "mtp0", + "mtp1", + "mtp2", + "pop", + "rdhwr", + "saa", + "saad", + "seq", + "seqi", + "sne", + "snei", + "synciobdma", + "syncs", + "syncw", + "syncws", + "v3mulu", + "vmm0", + "vmulu", + "zcb", + "zcbt", + // r5900 instructions + "lq", + "sq", + "dslrv", + "mfsa", + "mtsa", + "mtsab", + "mtsah", + "plzcw", + "mfhi1", + "mthi1", + "mflo1", + "mlto1", + "mult1", + "multu1", + "div1", + "divu1", + "madd1", + "maddu1", + "pmfhl", + "pmthl", + "psllh", + "psrlh", + "psrah", + "psllw", + "psrlw", + "psraw", + "paddw", + "psubw", + "pcgtw", + "pmaxw", + "paddh", + "psubh", + "pcgth", + "pmaxh", + "paddb", + "psubb", + "pcgtb", + "paddsw", + "psubsw", + "pextlw", + "ppacw", + "paddsh", + "psubsh", + "pextlh", + "ppach", + "paddsb", + "psubsb", + "pextlb", + "ppacb", + "pext5", + "ppac5", + "pabsw", + "pceqw", + "pminw", + "padsbh", + "pabsh", + "pceqh", + "pminh", + "pceqb", + "padduw", + "psubuw", + "pextuw", + "padduh", + "psubuh", + "pextuh", + "paddub", + "psubub", + "pextub", + "qfsrv", + "pmaddw", + "psllvw", + "psrlvw", + "pmsubw", + "pmfhi", + "pmflo", + "pinth", + "pmultw", + "pdivw", + "pcpyld", + "pmaddh", + "phmadh", + "pand", + "pxor", + "pmsubh", + "phmsbh", + "pexeh", + "prevh", + "pmulth", + "pdivbw", + "pexew", + "prot3w", + "pmadduw", + "psravw", + "pmthi", + "pmtlo", + "pinteh", + "pmultuw", + "pdivuw", + "pcpyud", + "por", + "pnor", + "pexch", + "pcpyh", + "pexcw", + "bc0f", + "bc0t", + "bc0fl", + "bc0tl", + "adda.s", + "suba.s", + "mula.s", + "madda.s", + "msuba.s", + "max.s", + "min.s", + "qmfc2", + "qmfc2.i", + "qmfc2.ni", + "qmtc2", + "qmtc2.i", + "qmtc2.ni", + "vaddx", + "vaddy", + "vaddz", + "vaddw", + "vsubx", + "vsuby", + "vsubz", + "vsubw", + "vmaddx", + "vmaddy", + "vmaddz", + "vmaddw", + "vmsubx", + "vmsuby", + "vmsubz", + "vmsubw", + "vmaxx", + "vmaxy", + "vmaxz", + "vmaxw", + "vminix", + "vminiy", + "vminiz", + "vminiw", + "vmulx", + "vmuly", + "vmulz", + "vmulw", + "vmulq", + "vmaxi", + "vmuli", + "vminii", + "vaddq", + "vmaddq", + "vaddi", + "vmaddi", + "vsubq", + "vmsubq", + "vsubi", + "vmsubi", + "vadd", + "vmadd", + "vmul", + "vmax", + "vsub", + "vmsub", + "vopmsub", + "vmini", + "viadd", + "visub", + "viaddi", + "viand", + "vior", + "vcallms", + "vcallmsr", + "vaddax", + "vadday", + "vaddaz", + "vaddaw", + "vsubax", + "vsubay", + "vsubaz", + "vsubaw", + "vmaddax", + "vmadday", + "vmaddaz", + "vmaddaw", + "vmsubax", + "vmsubay", + "vmsubaz", + "vmsubaw", + "vitof0", + "vitof4", + "vitof12", + "vitof15", + "vftoi0", + "vftoi4", + "vftoi12", + "vftoi15", + "vmulax", + "vmulay", + "vmulaz", + "vmulaw", + "vmulaq", + "vabs", + "vmulai", + "vclipw", + "vaddaq", + "vmaddaq", + "vaddai", + "vmaddai", + "vsubaq", + "vmsubaq", + "vsubai", + "vmsubai", + "vadda", + "vmadda", + "vmula", + "vsuba", + "vmsuba", + "vopmula", + "vnop", + "vmove", + "vmr32", + "vlqi", + "vsqi", + "vlqd", + "vsqd", + "vdiv", + "vsqrt", + "vrsqrt", + "vwaitq", + "vmtir", + "vmfir", + "vilwr", + "viswr", + "vrnext", + "vrget", + "vrinit", + "vrxor", + + "mmi0", + "mmi1", + "mmi2", + "mmi3", + "lqc2", + "sqc2", }; static const char * const RegisterStrings[] = { @@ -905,6 +1275,38 @@ static const char * const RegisterStrings[] = { "$f29", "$f30", "$f31", + "$fcr0", + "$fcr1", + "$fcr2", + "$fcr3", + "$fcr4", + "$fcr5", + "$fcr6", + "$fcr7", + "$fcr8", + "$fcr9", + "$fcr10", + "$fcr11", + "$fcr12", + "$fcr13", + "$fcr14", + "$fcr15", + "$fcr16", + "$fcr17", + "$fcr18", + "$fcr19", + "$fcr20", + "$fcr21", + "$fcr22", + "$fcr23", + "$fcr24", + "$fcr25", + "$fcr26", + "$fcr27", + "$fcr28", + "$fcr29", + "$fcr30", + "$fcr31", "$lo", "$hi", "cop0_Index", @@ -1154,6 +1556,91 @@ static const char * const RegisterStrings[] = { "CVMX_HSH_STARTSHA512", "CVMX_GFM_XORMUL1", + + "$sa", + + "$lo1", + "$hi1", + + "$P", + + "$vi0", "$vi1", "$vi2", "$vi3", "$vi4", "$vi5", "$vi6", "$vi7", "$vi8", "$vi9", + "$vi10", "$vi11", "$vi12", "$vi13", "$vi14", "$vi15", + + "CCR_STATUS", "CCR_MAC", "CCR_CLIPPING", "CCR[2,19]", + "$R", "$I", "$Q", + "CCR[2,23]", "CCR[2,24]", "CCR[2,25]", "CCR_TPC", "CCR_CMSAR0", + "CCR_FBRST", "CCR_VPU_STAT", "CCR[2,30]", "CCR_CMSAR1", + + "$acc", + "$vf0", "$vf1", "$vf2", "$vf3", "$vf4", "$vf5", "$vf6", "$vf7", "$vf8", "$vf9", + "$vf10", "$vf11", "$vf12", "$vf13", "$vf14", "$vf15", "$vf16", "$vf17", "$vf18", "$vf19", + "$vf20", "$vf21", "$vf22", "$vf23", "$vf24", "$vf25", "$vf26", "$vf27", "$vf28", "$vf29", + "$vf30", "$vf31", + + "$acc.x", "$vf0.x", "$vf1.x", "$vf2.x", "$vf3.x", "$vf4.x", "$vf5.x", "$vf6.x", + "$vf7.x", "$vf8.x", "$vf9.x", "$vf10.x", "$vf11.x", "$vf12.x", "$vf13.x", "$vf14.x", + "$vf15.x", "$vf16.x", "$vf17.x", "$vf18.x", "$vf19.x", "$vf20.x", "$vf21.x", "$vf22.x", + "$vf23.x", "$vf24.x", "$vf25.x", "$vf26.x", "$vf27.x", "$vf28.x", "$vf29.x", "$vf30.x", + "$vf31.x", "$acc.y", "$vf0.y", "$vf1.y", "$vf2.y", "$vf3.y", "$vf4.y", "$vf5.y", + "$vf6.y", "$vf7.y", "$vf8.y", "$vf9.y", "$vf10.y", "$vf11.y", "$vf12.y", "$vf13.y", + "$vf14.y", "$vf15.y", "$vf16.y", "$vf17.y", "$vf18.y", "$vf19.y", "$vf20.y", "$vf21.y", + "$vf22.y", "$vf23.y", "$vf24.y", "$vf25.y", "$vf26.y", "$vf27.y", "$vf28.y", "$vf29.y", + "$vf30.y", "$vf31.y", "$acc.z", "$vf0.z", "$vf1.z", "$vf2.z", "$vf3.z", "$vf4.z", + "$vf5.z", "$vf6.z", "$vf7.z", "$vf8.z", "$vf9.z", "$vf10.z", "$vf11.z", "$vf12.z", + "$vf13.z", "$vf14.z", "$vf15.z", "$vf16.z", "$vf17.z", "$vf18.z", "$vf19.z", "$vf20.z", + "$vf21.z", "$vf22.z", "$vf23.z", "$vf24.z", "$vf25.z", "$vf26.z", "$vf27.z", "$vf28.z", + "$vf29.z", "$vf30.z", "$vf31.z", "$acc.w", "$vf0.w", "$vf1.w", "$vf2.w", "$vf3.w", + "$vf4.w", "$vf5.w", "$vf6.w", "$vf7.w", "$vf8.w", "$vf9.w", "$vf10.w", "$vf11.w", + "$vf12.w", "$vf13.w", "$vf14.w", "$vf15.w", "$vf16.w", "$vf17.w", "$vf18.w", "$vf19.w", + "$vf20.w", "$vf21.w", "$vf22.w", "$vf23.w", "$vf24.w", "$vf25.w", "$vf26.w", "$vf27.w", + "$vf28.w", "$vf29.w", "$vf30.w", "$vf31.w", "$acc.xy", "$vf0.xy", "$vf1.xy", "$vf2.xy", + "$vf3.xy", "$vf4.xy", "$vf5.xy", "$vf6.xy", "$vf7.xy", "$vf8.xy", "$vf9.xy", "$vf10.xy", + "$vf11.xy", "$vf12.xy", "$vf13.xy", "$vf14.xy", "$vf15.xy", "$vf16.xy", "$vf17.xy", "$vf18.xy", + "$vf19.xy", "$vf20.xy", "$vf21.xy", "$vf22.xy", "$vf23.xy", "$vf24.xy", "$vf25.xy", "$vf26.xy", + "$vf27.xy", "$vf28.xy", "$vf29.xy", "$vf30.xy", "$vf31.xy", "$acc.xz", "$vf0.xz", "$vf1.xz", + "$vf2.xz", "$vf3.xz", "$vf4.xz", "$vf5.xz", "$vf6.xz", "$vf7.xz", "$vf8.xz", "$vf9.xz", + "$vf10.xz", "$vf11.xz", "$vf12.xz", "$vf13.xz", "$vf14.xz", "$vf15.xz", "$vf16.xz", "$vf17.xz", + "$vf18.xz", "$vf19.xz", "$vf20.xz", "$vf21.xz", "$vf22.xz", "$vf23.xz", "$vf24.xz", "$vf25.xz", + "$vf26.xz", "$vf27.xz", "$vf28.xz", "$vf29.xz", "$vf30.xz", "$vf31.xz", "$acc.xw", "$vf0.xw", + "$vf1.xw", "$vf2.xw", "$vf3.xw", "$vf4.xw", "$vf5.xw", "$vf6.xw", "$vf7.xw", "$vf8.xw", + "$vf9.xw", "$vf10.xw", "$vf11.xw", "$vf12.xw", "$vf13.xw", "$vf14.xw", "$vf15.xw", "$vf16.xw", + "$vf17.xw", "$vf18.xw", "$vf19.xw", "$vf20.xw", "$vf21.xw", "$vf22.xw", "$vf23.xw", "$vf24.xw", + "$vf25.xw", "$vf26.xw", "$vf27.xw", "$vf28.xw", "$vf29.xw", "$vf30.xw", "$vf31.xw", "$acc.yz", + "$vf0.yz", "$vf1.yz", "$vf2.yz", "$vf3.yz", "$vf4.yz", "$vf5.yz", "$vf6.yz", "$vf7.yz", + "$vf8.yz", "$vf9.yz", "$vf10.yz", "$vf11.yz", "$vf12.yz", "$vf13.yz", "$vf14.yz", "$vf15.yz", + "$vf16.yz", "$vf17.yz", "$vf18.yz", "$vf19.yz", "$vf20.yz", "$vf21.yz", "$vf22.yz", "$vf23.yz", + "$vf24.yz", "$vf25.yz", "$vf26.yz", "$vf27.yz", "$vf28.yz", "$vf29.yz", "$vf30.yz", "$vf31.yz", + "$acc.yw", "$vf0.yw", "$vf1.yw", "$vf2.yw", "$vf3.yw", "$vf4.yw", "$vf5.yw", "$vf6.yw", + "$vf7.yw", "$vf8.yw", "$vf9.yw", "$vf10.yw", "$vf11.yw", "$vf12.yw", "$vf13.yw", "$vf14.yw", + "$vf15.yw", "$vf16.yw", "$vf17.yw", "$vf18.yw", "$vf19.yw", "$vf20.yw", "$vf21.yw", "$vf22.yw", + "$vf23.yw", "$vf24.yw", "$vf25.yw", "$vf26.yw", "$vf27.yw", "$vf28.yw", "$vf29.yw", "$vf30.yw", + "$vf31.yw", "$acc.zw", "$vf0.zw", "$vf1.zw", "$vf2.zw", "$vf3.zw", "$vf4.zw", "$vf5.zw", + "$vf6.zw", "$vf7.zw", "$vf8.zw", "$vf9.zw", "$vf10.zw", "$vf11.zw", "$vf12.zw", "$vf13.zw", + "$vf14.zw", "$vf15.zw", "$vf16.zw", "$vf17.zw", "$vf18.zw", "$vf19.zw", "$vf20.zw", "$vf21.zw", + "$vf22.zw", "$vf23.zw", "$vf24.zw", "$vf25.zw", "$vf26.zw", "$vf27.zw", "$vf28.zw", "$vf29.zw", + "$vf30.zw", "$vf31.zw", "$acc.xyz", "$vf0.xyz", "$vf1.xyz", "$vf2.xyz", "$vf3.xyz", "$vf4.xyz", + "$vf5.xyz", "$vf6.xyz", "$vf7.xyz", "$vf8.xyz", "$vf9.xyz", "$vf10.xyz", "$vf11.xyz", "$vf12.xyz", + "$vf13.xyz", "$vf14.xyz", "$vf15.xyz", "$vf16.xyz", "$vf17.xyz", "$vf18.xyz", "$vf19.xyz", "$vf20.xyz", + "$vf21.xyz", "$vf22.xyz", "$vf23.xyz", "$vf24.xyz", "$vf25.xyz", "$vf26.xyz", "$vf27.xyz", "$vf28.xyz", + "$vf29.xyz", "$vf30.xyz", "$vf31.xyz", "$acc.xyw", "$vf0.xyw", "$vf1.xyw", "$vf2.xyw", "$vf3.xyw", + "$vf4.xyw", "$vf5.xyw", "$vf6.xyw", "$vf7.xyw", "$vf8.xyw", "$vf9.xyw", "$vf10.xyw", "$vf11.xyw", + "$vf12.xyw", "$vf13.xyw", "$vf14.xyw", "$vf15.xyw", "$vf16.xyw", "$vf17.xyw", "$vf18.xyw", "$vf19.xyw", + "$vf20.xyw", "$vf21.xyw", "$vf22.xyw", "$vf23.xyw", "$vf24.xyw", "$vf25.xyw", "$vf26.xyw", "$vf27.xyw", + "$vf28.xyw", "$vf29.xyw", "$vf30.xyw", "$vf31.xyw", "$acc.xzw", "$vf0.xzw", "$vf1.xzw", "$vf2.xzw", + "$vf3.xzw", "$vf4.xzw", "$vf5.xzw", "$vf6.xzw", "$vf7.xzw", "$vf8.xzw", "$vf9.xzw", "$vf10.xzw", + "$vf11.xzw", "$vf12.xzw", "$vf13.xzw", "$vf14.xzw", "$vf15.xzw", "$vf16.xzw", "$vf17.xzw", "$vf18.xzw", + "$vf19.xzw", "$vf20.xzw", "$vf21.xzw", "$vf22.xzw", "$vf23.xzw", "$vf24.xzw", "$vf25.xzw", "$vf26.xzw", + "$vf27.xzw", "$vf28.xzw", "$vf29.xzw", "$vf30.xzw", "$vf31.xzw", "$acc.yzw", "$vf0.yzw", "$vf1.yzw", + "$vf2.yzw", "$vf3.yzw", "$vf4.yzw", "$vf5.yzw", "$vf6.yzw", "$vf7.yzw", "$vf8.yzw", "$vf9.yzw", + "$vf10.yzw", "$vf11.yzw", "$vf12.yzw", "$vf13.yzw", "$vf14.yzw", "$vf15.yzw", "$vf16.yzw", "$vf17.yzw", + "$vf18.yzw", "$vf19.yzw", "$vf20.yzw", "$vf21.yzw", "$vf22.yzw", "$vf23.yzw", "$vf24.yzw", "$vf25.yzw", + "$vf26.yzw", "$vf27.yzw", "$vf28.yzw", "$vf29.yzw", "$vf30.yzw", "$vf31.yzw", "$acc.xyzw", "$vf0.xyzw", + "$vf1.xyzw", "$vf2.xyzw", "$vf3.xyzw", "$vf4.xyzw", "$vf5.xyzw", "$vf6.xyzw", "$vf7.xyzw", "$vf8.xyzw", + "$vf9.xyzw", "$vf10.xyzw", "$vf11.xyzw", "$vf12.xyzw", "$vf13.xyzw", "$vf14.xyzw", "$vf15.xyzw", "$vf16.xyzw", + "$vf17.xyzw", "$vf18.xyzw", "$vf19.xyzw", "$vf20.xyzw", "$vf21.xyzw", "$vf22.xyzw", "$vf23.xyzw", "$vf24.xyzw", + "$vf25.xyzw", "$vf26.xyzw", "$vf27.xyzw", "$vf28.xyzw", "$vf29.xyzw", "$vf30.xyzw", "$vf31.xyzw" + }; static const char * const FlagStrings[] = { @@ -1164,7 +1651,9 @@ static const char * const FlagStrings[] = { "$fcc4", "$fcc5", "$fcc6", - "$fcc7" + "$fcc7", + "$coc0", + "$coc2", }; static const char * const HintStrings[] = { @@ -1265,6 +1754,8 @@ uint32_t mips_decompose_instruction( { case 0: instruction->operation = mips_special_table[version-1][ins.decode.func_hi][ins.decode.func_lo]; + if (instruction->operation == MIPS_INVALID && version == MIPS_R5900) + instruction->operation = MIPS_ADDI; break; case 1: instruction->operation = mips_regimm_table[version-1][ins.decode.rt_hi][ins.decode.rt_lo]; @@ -1293,13 +1784,19 @@ uint32_t mips_decompose_instruction( } } + else if (version == MIPS_R5900) + instruction->operation = mips_mmi_r5900_table[ins.decode.func_hi][ins.decode.func_lo]; break; case 0x1f: if (version == MIPS_32) instruction->operation = mips32_special3_table[ins.decode.func_hi][ins.decode.func_lo]; else if (version == MIPS_64) instruction->operation = mips64_special3_table[ins.decode.func_hi][ins.decode.func_lo]; + else if (version == MIPS_R5900) + instruction->operation = mips_base_table[version-1][ins.decode.op_hi][ins.decode.op_lo]; break; + // case 0x12: + // printf("Inst: %08" PRIx64 ":%08X\n", address, ins.value); default: if ((flags & DECOMPOSE_FLAGS_CAVIUM) == 0) instruction->operation = mips_base_table[version-1][ins.decode.op_hi][ins.decode.op_lo]; @@ -1308,7 +1805,7 @@ uint32_t mips_decompose_instruction( } //Now deal with aliases and stage 2 decoding - if (version == MIPS_32 || version == MIPS_64) + if (version == MIPS_32 || version == MIPS_64 || version == MIPS_R5900) { switch (instruction->operation) { @@ -1368,6 +1865,17 @@ uint32_t mips_decompose_instruction( case MIPS_DSRLV: if (ins.bits.bit6 == 1) instruction->operation = MIPS_DROTRV; + case MIPS_MMI0: + instruction->operation = mips_r5900_mmi0_table[ins.r.sa >> 2][ins.r.sa & 3]; + break; + case MIPS_MMI1: + instruction->operation = mips_r5900_mmi1_table[ins.r.sa >> 2][ins.r.sa & 3]; + break; + case MIPS_MMI2: + instruction->operation = mips_r5900_mmi2_table[ins.r.sa >> 2][ins.r.sa & 3]; + break; + case MIPS_MMI3: + instruction->operation = mips_r5900_mmi3_table[ins.r.sa >> 2][ins.r.sa & 3]; break; case MIPS_COP0: switch (ins.r.rs) @@ -1390,6 +1898,20 @@ uint32_t mips_decompose_instruction( instruction->operation = MIPS_DMTC0; break; case 6: instruction->operation = MIPS_CTC0; break; + case 8: + { + if (version != MIPS_R5900) + return 1; + switch (ins.decode.rt_lo) + { + case 0: instruction->operation = MIPS_BC0F; break; + case 1: instruction->operation = MIPS_BC0T; break; + case 2: instruction->operation = MIPS_BC0FL; break; + case 3: instruction->operation = MIPS_BC0TL; break; + default: return 1; + } + break; + } case 10: instruction->operation = MIPS_RDPGPR; break; case 11: if (ins.bits.bit5 == 1) @@ -1412,6 +1934,18 @@ uint32_t mips_decompose_instruction( case 24: instruction->operation = MIPS_ERET; break; case 31: instruction->operation = MIPS_DERET; break; case 32: instruction->operation = MIPS_WAIT; break; + case 56: + if (version == MIPS_R5900) + { + instruction->operation = MIPS_EI; + break; + } + case 57: + if (version == MIPS_R5900) + { + instruction->operation = MIPS_DI; + break; + } } } break; @@ -1452,7 +1986,10 @@ uint32_t mips_decompose_instruction( break; case 10: instruction->operation = MIPS_BC1ANY4; break; case 16: //S - instruction->operation = mips_v5_cop1_S_table[ins.decode.func_hi][ins.decode.func_lo]; + if (version == MIPS_R5900) + instruction->operation = mips_r5900_cop1_S_table[ins.decode.func_hi][ins.decode.func_lo]; + else + instruction->operation = mips_v5_cop1_S_table[ins.decode.func_hi][ins.decode.func_lo]; if (instruction->operation == MIPS_MOVCF) { if (ins.bits.bit16 == 1) @@ -1499,26 +2036,35 @@ uint32_t mips_decompose_instruction( { if (ins.r.rs < 8) { - static const Operation opmap[8] = - { - MIPS_MFC2, // 00000 - MIPS_DMFC2, // 00001 - MIPS_CFC2, // 00010 - MIPS_MFHC2, // 00011 - MIPS_MTC2, // 00100 - MIPS_DMTC2, // 00101 - MIPS_CTC2, // 00110 - MIPS_MTHC2 // 00111 - }; - instruction->operation = opmap[ins.r.rs]; + static const Operation opmap[2][8] = + {{ + MIPS_MFC2, // 00000 + MIPS_DMFC2, // 00001 + MIPS_CFC2, // 00010 + MIPS_MFHC2, // 00011 + MIPS_MTC2, // 00100 + MIPS_DMTC2, // 00101 + MIPS_CTC2, // 00110 + MIPS_MTHC2 // 00111 + },{ + MIPS_INVALID, // 00000 + MIPS_QMFC2, // 00001 + MIPS_CFC2, // 00010 + MIPS_INVALID, // 00011 + MIPS_INVALID, // 00100 + MIPS_QMTC2, // 00101 + MIPS_CTC2, // 00110 + MIPS_INVALID // 00111 + }}; + instruction->operation = opmap[version == MIPS_R5900][ins.r.rs]; } else if (ins.r.rs == 8) { static const Operation opmap[4] = { MIPS_BC2F, // 01000:00 - MIPS_BC2FL, // 01000:10 MIPS_BC2T, // 01000:01 + MIPS_BC2FL, // 01000:10 MIPS_BC2TL // 01000:11 }; instruction->operation = opmap[ins.r.rt & 3]; @@ -1538,6 +2084,16 @@ uint32_t mips_decompose_instruction( }; instruction->operation = opmap[ins.r.rs & 7]; } + else if (ins.r.rs < 32 && version == MIPS_R5900) + { + if (ins.r.function > 59) + { + uint32_t opcode = (ins.r.function & 3) | (ins.r.sa << 2); + instruction->operation = mips_r5900_cop2_special2_table[opcode >> 3][opcode & 7]; + } + else + instruction->operation = mips_r5900_cop2_special1_table[ins.decode.func_hi][ins.decode.func_lo]; + } else { instruction->operation = MIPS_COP2; @@ -1658,7 +2214,8 @@ uint32_t mips_decompose_instruction( } } - //Now that we have the proper instructions aliased figure out what our operands are + int i = 1; // operand index counter for V* instructions + // Stage 3: Now that we have the proper instructions aliased figure out what our operands are switch(instruction->operation) { //Zero operand instructions @@ -1691,6 +2248,13 @@ uint32_t mips_decompose_instruction( INS_1(IMM, ins.r.sa); break; //1 operand instructions + case MIPS_BC0F: + case MIPS_BC0FL: + case MIPS_BC0T: + case MIPS_BC0TL: + // INS_1(IMM, (ins.i.immediate << 2)) + INS_1(LABEL, (4 + address + (ins.i.immediate<<2)) & registerMask) + break; case MIPS_COP2: INS_1(IMM, (ins.value & 0x1ffffff)) break; @@ -1707,11 +2271,18 @@ uint32_t mips_decompose_instruction( break; case MIPS_DI: case MIPS_EI: - if (ins.r.rt != 0) + if (ins.r.rt != 0 && version != MIPS_R5900) INS_1(REG, ins.r.rt) break; case MIPS_MFHI: case MIPS_MFLO: + case MIPS_MFHI1: + case MIPS_MFLO1: + INS_1(REG, ins.r.rd) + if (ins.r.sa + ins.r.rt + ins.r.rs != 0) + return 1; + break; + case MIPS_MFSA: INS_1(REG, ins.r.rd) if (ins.r.sa + ins.r.rt + ins.r.rs != 0) return 1; @@ -1730,10 +2301,25 @@ uint32_t mips_decompose_instruction( break; case MIPS_MTHI: case MIPS_MTLO: - INS_1(REG,ins.r.rs) + case MIPS_MTHI1: + case MIPS_MTLO1: + case MIPS_MTSA: + INS_1(REG, ins.r.rs) if (ins.r.rd + ins.r.rt + ins.r.sa != 0) return 1; break; + case MIPS_PMFHI: + case MIPS_PMFLO: + INS_1(REG, ins.r.rd) + if (ins.r.rs + ins.r.rt != 0) + return 1; + break; + case MIPS_PMTHI: + case MIPS_PMTLO: + INS_1(REG, ins.r.rs) + if (ins.r.rd + ins.r.rt != 0) + return 1; + break; case MIPS_BAL: case MIPS_B: INS_1(LABEL, (4 + address + (ins.i.immediate<<2)) & registerMask); @@ -1765,6 +2351,23 @@ uint32_t mips_decompose_instruction( INS_2(FLAG, (FPCCREG_FCC0 + ((ins.value >> 18) & 7)), LABEL, (4 + address + (ins.i.immediate<<2)) & registerMask); } break; + case MIPS_BC2F: + case MIPS_BC2FL: + case MIPS_BC2T: + case MIPS_BC2TL: + if (((ins.value >> 18) & 7) == 0) + { + INS_1(LABEL, (4 + address + (ins.i.immediate<<2)) & registerMask); + } + else + { + INS_2(FLAG, (CCREG_COC2 + ((ins.value >> 18) & 7)), LABEL, (4 + address + (ins.i.immediate<<2)) & registerMask); + } + break; + case MIPS_MTSAB: + case MIPS_MTSAH: + INS_2(REG, ins.i.rs, IMM, ins.i.immediate) + break; case MIPS_CLO: case MIPS_CLZ: case MIPS_NOT: @@ -1776,13 +2379,18 @@ uint32_t mips_decompose_instruction( case MIPS_RDHWR: INS_2(REG, ins.r.rt, IMM, ins.r.rd); break; + case MIPS_RSQRT_S: + if (version == MIPS_R5900) + { + INS_3(REG, ins.f.fd + FPREG_F0, REG, ins.f.fs + FPREG_F0, REG, ins.f.ft + FPREG_F0); + break; + } case MIPS_TRUNC_W_S: case MIPS_TRUNC_W_D: case MIPS_TRUNC_L_S: case MIPS_TRUNC_L_D: case MIPS_SQRT_S: case MIPS_SQRT_D: - case MIPS_RSQRT_S: case MIPS_RSQRT_D: case MIPS_ROUND_W_S: case MIPS_ROUND_W_D: @@ -1791,7 +2399,7 @@ uint32_t mips_decompose_instruction( case MIPS_RECIP_S: case MIPS_RECIP_D: INS_2(REG, ins.f.fd + FPREG_F0, REG, ins.f.fs + FPREG_F0); - if (ins.f.ft != 0) + if (0 && ins.f.ft != 0) return 1; break; case MIPS_BC1EQZ: @@ -1877,13 +2485,33 @@ uint32_t mips_decompose_instruction( case MIPS_DIVU: case MIPS_DMULT: case MIPS_DMULTU: + case MIPS_MSUB: + case MIPS_MSUBU: + if (ins.r.rd != 0 || ins.r.sa != 0) + return 1; + INS_2(REG, ins.r.rs, REG, ins.r.rt) + break; + case MIPS_MULT1: + case MIPS_MULTU1: + case MIPS_MADDU1: + if (version != MIPS_R5900) + return 1; case MIPS_MULT: case MIPS_MULTU: case MIPS_MADD: case MIPS_MADDU: - case MIPS_MSUB: - case MIPS_MSUBU: - if (ins.r.rd != 0 || ins.r.sa != 0) + if (ins.r.sa != 0 + || (version != MIPS_R5900 && ins.r.rd != 0)) + return 1; + if (ins.r.rd != 0) + INS_3(REG, ins.r.rd, REG, ins.r.rs, REG, ins.r.rt) + else + INS_2(REG, ins.r.rs, REG, ins.r.rt) + break; + case MIPS_PDIVBW: + case MIPS_PDIVUW: + case MIPS_PDIVW: + if (ins.r.rd != 0) return 1; INS_2(REG, ins.r.rs, REG, ins.r.rt) break; @@ -1911,13 +2539,35 @@ uint32_t mips_decompose_instruction( case MIPS_BITSWAP: case MIPS_DSBH: case MIPS_DSHD: + case MIPS_PABSH: + case MIPS_PABSW: + INS_2(REG, ins.r.rd, REG, ins.r.rt) + break; + case MIPS_PCPYH: + case MIPS_PEXCH: + case MIPS_PEXCW: + case MIPS_PEXEH: + case MIPS_PEXEW: + case MIPS_PEXT5: + case MIPS_PPAC5: + case MIPS_PREVH: + case MIPS_PROT3W: + if (ins.r.rs != 0) + return 1; INS_2(REG, ins.r.rd, REG, ins.r.rt) break; + case MIPS_PLZCW: + if (ins.r.rt != 0) + return 1; + INS_2(REG, ins.r.rd, REG, ins.r.rs) + break; case MIPS_CFC0: case MIPS_CTC0: + INS_2(REG, ins.r.rt, REG, ins.f.fs + CPREG_0) + break; case MIPS_CFC1: case MIPS_CTC1: - INS_2(REG, ins.r.rt, REG, ins.f.fs + CPREG_0) + INS_2(REG, ins.r.rt, REG, ins.f.fs + FPREG_FCR0) break; case MIPS_DMFC1: case MIPS_MFC1: @@ -1929,13 +2579,18 @@ uint32_t mips_decompose_instruction( if (ins.r.function + ins.r.sa != 0) return 1; break; + case MIPS_CTC2: + case MIPS_CFC2: + if (version == MIPS_R5900) + { + INS_2(REG, ins.r.rt, V_REG, ins.v.fs + REG_VI0); + break; + } case MIPS_DMFC2: case MIPS_MFC2: case MIPS_DMTC2: case MIPS_MTC2: - case MIPS_CFC2: case MIPS_MFHC2: - case MIPS_CTC2: case MIPS_MTHC2: INS_2(REG, ins.i.rt, IMM, ins.i.immediate); break; @@ -2015,7 +2670,16 @@ uint32_t mips_decompose_instruction( return 1; INS_2(REG, ins.f.fd + FPREG_F0, REG, ins.f.fs + FPREG_F0) break; - + case MIPS_MADDA_S: + case MIPS_MSUBA_S: + case MIPS_ADDA_S: + case MIPS_SUBA_S: + case MIPS_MULA_S: + INS_2(REG, FPREG_F0 + ins.f.fs, REG, FPREG_F0 + ins.f.ft) + break; + case MIPS_SQRT_PS: + INS_2(REG, FPREG_F0 + ins.f.fd, REG, FPREG_F0 + ins.f.ft) + break; case MIPS_LBUX: case MIPS_LHX: case MIPS_LWX: @@ -2051,11 +2715,16 @@ uint32_t mips_decompose_instruction( case MIPS_SW: case MIPS_SWL: case MIPS_SWR: + case MIPS_LQ: + case MIPS_SQ: instruction->operands[0].operandClass = REG; instruction->operands[1].operandClass = MEM_IMM; instruction->operands[0].reg = ins.i.rt; instruction->operands[1].reg = ins.i.rs; instruction->operands[1].immediate = ins.i.immediate; + // These next two lines are suspect, so commenting them out + // if (instruction->operation == MIPS_SQ) + // instruction->operands[1].immediate = MIPS_SQ; break; case MIPS_PREF: case MIPS_PREFX: @@ -2085,25 +2754,150 @@ uint32_t mips_decompose_instruction( instruction->operands[1].immediate = ins.f.ft; instruction->operands[1].reg = ins.f.fr; break; + case MIPS_LWC1: case MIPS_SWC1: - case MIPS_SWC2: - case MIPS_SWC3: case MIPS_LDC1: - case MIPS_LDC2: - case MIPS_LDC3: case MIPS_SDC1: + // This special case for the R5900 seems wrong: it's trying to use a FP register for the base register + // instruction->operands[1].reg = version != MIPS_R5900 ? ins.i.rs : (FPREG_F0 + ins.f.fr); + if (version == MIPS_R5900) + { + instruction->operands[0].reg = FPREG_F0 + ins.f.ft; + instruction->operands[0].operandClass = REG; + instruction->operands[1].operandClass = MEM_IMM; + instruction->operands[1].reg = ins.i.rs; + instruction->operands[1].immediate = ins.i.immediate; + break; + } + case MIPS_QMFC2: + case MIPS_QMTC2: + if (version == MIPS_R5900) + { + // TODO: non-interlock (NI)? + instruction->operands[0].operandClass = REG; + instruction->operands[0].reg = ins.i.rt; + instruction->operands[1].operandClass = V_REG; + instruction->operands[1].reg = ins.v.fs; + if (ins.v.bc & 1) + instruction->operation += 1; + } + break; case MIPS_SDC2: - case MIPS_SDC3: - case MIPS_LWC1: + case MIPS_LDC2: + if (version == MIPS_R5900) + { + instruction->operands[0].operandClass = V_REG; + instruction->operands[0].reg = ins.f.ft + REG_VF0; + instruction->operands[1].operandClass = MEM_IMM; + instruction->operands[1].reg = ins.i.rs; + instruction->operands[1].immediate = ins.i.immediate; + switch (instruction->operation) + { + case MIPS_LDC2: + instruction->operation = MIPS_LQC2; break; + case MIPS_SDC2: + instruction->operation = MIPS_SQC2; break; + default: + instruction->operation = MIPS_INVALID; + } + break; + } + case MIPS_SWC2: case MIPS_LWC2: + case MIPS_SWC3: + case MIPS_LDC3: + case MIPS_SDC3: case MIPS_LWC3: + instruction->operands[0].reg = ins.i.rt; + instruction->operands[0].immediate = ins.i.rt; instruction->operands[0].operandClass = IMM; + // instruction->operands[0].operandClass = REG; instruction->operands[1].operandClass = MEM_IMM; - instruction->operands[0].reg = ins.i.rt; instruction->operands[1].reg = ins.i.rs; instruction->operands[1].immediate = ins.i.immediate; break; + case MIPS_DIV1: + case MIPS_DIVU1: + if (version == MIPS_R5900) { + if (ins.r.sa != 0) + return 1; + INS_2(REG, ins.r.rs, REG, ins.r.rt) + break; + } //3 operand instructions + // case MIPS_MULT1: + // case MIPS_MULTU1: + // case MIPS_MADDU1: + // { + // if (ins.r.sa != 0) + // return 1; + // INS_3(REG, ins.r.rd, REG, ins.r.rs, REG, ins.r.rt) + // break; + // } + case MIPS_PADDB: + case MIPS_PADDH: + case MIPS_PADDW: + case MIPS_PADDSB: + case MIPS_PADDSH: + case MIPS_PADDSW: + case MIPS_PADDUB: + case MIPS_PADDUH: + case MIPS_PADDUW: + case MIPS_PADSBH: + case MIPS_PAND: + case MIPS_PCEQB: + case MIPS_PCEQH: + case MIPS_PCEQW: + case MIPS_PCGTB: + case MIPS_PCGTH: + case MIPS_PCGTW: + case MIPS_PCPYLD: + case MIPS_PCPYUD: + case MIPS_PEXTLB: + case MIPS_PEXTLH: + case MIPS_PEXTLW: + case MIPS_PEXTUB: + case MIPS_PEXTUH: + case MIPS_PEXTUW: + case MIPS_PHMADH: + case MIPS_PHMSBH: + case MIPS_PINTEH: + case MIPS_PINTH: + case MIPS_PMADDH: + case MIPS_PMADDUW: + case MIPS_PMADDW: + case MIPS_PMAXH: + case MIPS_PMAXW: + case MIPS_PMINH: + case MIPS_PMINW: + case MIPS_PMSUBH: + case MIPS_PMSUBW: + case MIPS_PMULTH: + case MIPS_PMULTUW: + case MIPS_PMULTW: + case MIPS_PNOR: + case MIPS_POR: + case MIPS_PPACB: + case MIPS_PPACH: + case MIPS_PPACW: + case MIPS_PSUBB: + case MIPS_PSUBH: + case MIPS_PSUBSB: + case MIPS_PSUBSH: + case MIPS_PSUBSW: + case MIPS_PSUBUB: + case MIPS_PSUBUH: + case MIPS_PSUBUW: + case MIPS_PSUBW: + case MIPS_PXOR: + case MIPS_QFSRV: + INS_3(REG, ins.r.rd, REG, ins.r.rs, REG, ins.r.rt) + break; + case MIPS_PSLLVW: + case MIPS_PSRAVW: + case MIPS_PSRLVW: + INS_3(REG, ins.r.rd, REG, ins.r.rt, REG, ins.r.rs) + break; case MIPS_DIV_S: case MIPS_DIV_D: case MIPS_MUL_S: @@ -2128,11 +2922,12 @@ uint32_t mips_decompose_instruction( case MIPS_MADDF_S: case MIPS_MSUBF_D: case MIPS_MSUBF_S: + case MIPS_RSQRT: INS_3(REG, ins.f.fd + FPREG_F0, REG, ins.f.fs + FPREG_F0, REG, ins.f.ft + FPREG_F0) break; case MIPS_MOVF: case MIPS_MOVT: - INS_3(REG, ins.r.rd, REG, ins.r.rs, FLAG, (ins.r.rt>>2) + FPCCREG_FCC0) + INS_3(REG, ins.r.rd, REG, ins.r.rs, FLAG, ((ins.r.rt>>2) & 7) + FPCCREG_FCC0) if (ins.r.sa != 0 || ins.bits.bit17 != 0) return 1; break; @@ -2142,7 +2937,7 @@ uint32_t mips_decompose_instruction( case MIPS_MOVT_S: case MIPS_MOVT_D: case MIPS_MOVT_PS: - INS_3(REG, ins.f.fd + FPREG_F0, REG, ins.f.fs + FPREG_F0, FLAG, (ins.r.rt>>2) + FPCCREG_FCC0) + INS_3(REG, ins.f.fd + FPREG_F0, REG, ins.f.fs + FPREG_F0, FLAG, ((ins.r.rt>>2) & 7) + FPCCREG_FCC0) if (ins.bits.bit17 != 0) return 1; break; @@ -2197,9 +2992,15 @@ uint32_t mips_decompose_instruction( case MIPS_ROTR: case MIPS_DROTR: case MIPS_DROTR32: + case MIPS_PSLLH: + case MIPS_PSLLW: + case MIPS_PSRAH: + case MIPS_PSRAW: + case MIPS_PSRLH: + case MIPS_PSRLW: INS_3(REG, ins.r.rd, REG, ins.r.rt, IMM, ins.r.sa) - if (ins.r.rs != 1) - return 1; + // if (ins.r.rs != 1) + // return 1; break; case MIPS_DSLL: case MIPS_DSRA: @@ -2236,14 +3037,27 @@ uint32_t mips_decompose_instruction( break; case MIPS_DMFC0: case MIPS_DMTC0: + INS_3(REG, ins.r.rt, IMM, ins.r.rd, IMM, (ins.r.function & 7)) + break; case MIPS_MFC0: case MIPS_MTC0: - INS_3(REG, ins.r.rt, IMM, ins.r.rd, IMM, (ins.r.function & 7)) + if (version == MIPS_R5900) + INS_2(REG, ins.r.rt, REG, CPREG_0 + ins.r.rd) + else + INS_3(REG, ins.r.rt, IMM, ins.r.rd, IMM, (ins.r.function & 7)) break; case MIPS_MADD_S: + case MIPS_MSUB_S: + if (version == MIPS_R5900) + { + INS_3(REG, ins.f.fd + FPREG_F0, + REG, ins.f.fs + FPREG_F0, + REG, ins.f.ft + FPREG_F0); + break; + } + case MIPS_MADD_D: case MIPS_MADD_PS: - case MIPS_MSUB_S: case MIPS_MSUB_D: case MIPS_MSUB_PS: case MIPS_NMADD_S: @@ -2353,6 +3167,520 @@ uint32_t mips_decompose_instruction( instruction->operands[0].immediate = 0; break; + case MIPS_MIN_S: + case MIPS_MAX_S: + INS_3(REG, FPREG_F0 + ins.f.fd, REG, FPREG_F0 + ins.f.fs, REG, FPREG_F0 + ins.f.ft); + break; + + // case MIPS_VADDx: + // case MIPS_VADDy: + // case MIPS_VADDz: + // case MIPS_VADDw: + // case MIPS_VSUBx: + // case MIPS_VSUBy: + // case MIPS_VSUBz: + // case MIPS_VSUBw: + // case MIPS_VMADDx: + // case MIPS_VMADDy: + // case MIPS_VMADDz: + // case MIPS_VMADDw: + // case MIPS_VMSUBx: + // case MIPS_VMSUBy: + // case MIPS_VMSUBz: + // case MIPS_VMSUBw: + // case MIPS_VMAXx: + // case MIPS_VMAXy: + // case MIPS_VMAXz: + // case MIPS_VMAXw: + // case MIPS_VMINIx: + // case MIPS_VMINIy: + // case MIPS_VMINIz: + // case MIPS_VMINIw: + // case MIPS_VMULx: + // case MIPS_VMULy: + // case MIPS_VMULz: + // case MIPS_VMULw: + // case MIPS_VMULq: + // case MIPS_VMAXi: + // case MIPS_VMULi: + // case MIPS_VMINIi: + // case MIPS_VADDq: + // case MIPS_VMADDq: + // case MIPS_VADDi: + // case MIPS_VMADDi: + // case MIPS_VSUBq: + // case MIPS_VMSUBq: + // case MIPS_VSUBi: + // case MIPS_VMSUBi: + // case MIPS_VADD: + // case MIPS_VMADD: + // case MIPS_VMUL: + // case MIPS_VMAX: + // case MIPS_VSUB: + // case MIPS_VMSUB: + // case MIPS_VOPMSUB: + // case MIPS_VMINI: + // case MIPS_VIADD: + // case MIPS_VISUB: + // case MIPS_VIADDI: + // case MIPS_VIAND: + // case MIPS_VIOR: + // case MIPS_VCALLMS: + // case MIPS_VCALLMSR: + // case MIPS_VADDAx: + // case MIPS_VADDAy: + // case MIPS_VADDAz: + // case MIPS_VADDAw: + // case MIPS_VSUBAx: + // case MIPS_VSUBAy: + // case MIPS_VSUBAz: + // case MIPS_VSUBAw: + // case MIPS_VMADDAx: + // case MIPS_VMADDAy: + // case MIPS_VMADDAz: + // case MIPS_VMADDAw: + // case MIPS_VMSUBAx: + // case MIPS_VMSUBAy: + // case MIPS_VMSUBAz: + // case MIPS_VMSUBAw: + // case MIPS_VITOF0: + // case MIPS_VITOF4: + // case MIPS_VITOF12: + // case MIPS_VITOF15: + // case MIPS_VFTOI0: + // case MIPS_VFTOI4: + // case MIPS_VFTOI12: + // case MIPS_VFTOI15: + // case MIPS_VMULAx: + // case MIPS_VMULAy: + // case MIPS_VMULAz: + // case MIPS_VMULAw: + // case MIPS_VMULAq: + // case MIPS_VABS: + // case MIPS_VMULAi: + // case MIPS_VCLIPw: + // case MIPS_VADDAq: + // case MIPS_VMADDAq: + // case MIPS_VADDAi: + // case MIPS_VMADDAi: + // case MIPS_VSUBAq: + // case MIPS_VMSUBAq: + // case MIPS_VSUBAi: + // case MIPS_VMSUBAi: + // case MIPS_VADDA: + // case MIPS_VMADDA: + // case MIPS_VMULA: + // case MIPS_VSUBA: + // case MIPS_VMSUBA: + // case MIPS_VOPMULA: + // case MIPS_VNOP: + // case MIPS_VMOVE: + // case MIPS_VMR32: + // case MIPS_VLQI: + // case MIPS_VSQI: + // case MIPS_VLQD: + // case MIPS_VSQD: + // case MIPS_VDIV: + // case MIPS_VSQRT: + // case MIPS_VRSQRT: + // case MIPS_VWAITQ: + // case MIPS_VMTIR: + // case MIPS_VMFIR: + // case MIPS_VILWR: + // case MIPS_VISWR: + // case MIPS_VRNEXT: + // case MIPS_VRGET: + // case MIPS_VRINIT: + // case MIPS_VRXOR: + break; + + case MIPS_VILWR: + case MIPS_VISWR: + instruction->operands[i].reg = ins.v.ft + REG_VI0; + instruction->operands[i++].operandClass = V_REG; + instruction->operands[i].reg = ins.v.fs + REG_VI0; + instruction->operands[i++].operandClass = V_REG; + + instruction->operands[0].reg = ins.v.dest; + instruction->operands[0].operandClass = V_DEST; + instruction->operands[0].immediate = 1; + break; + + case MIPS_VCALLMS: + instruction->operands[0].immediate = ins.vi.imm15; // << 3; + instruction->operands[0].operandClass = IMM; + break; + + case MIPS_VCALLMSR: + instruction->operands[0].reg = REG_VCCR_CMSAR0; + instruction->operands[0].operandClass = REG; + break; + + // + case MIPS_VNOP: + case MIPS_VWAITQ: + break; + + // .dest ft.dest, (is++).dest + case MIPS_VLQI: + instruction->operands[i].reg = ins.v.ft; + instruction->operands[i++].operandClass = V_REG; + instruction->operands[i].reg = ins.v.fs + REG_VI0; + instruction->operands[i++].operandClass = V_REG; + + instruction->operands[0].reg = ins.v.dest; + instruction->operands[0].operandClass = V_DEST; + instruction->operands[0].immediate = 1; + break; + // .dest fs.dest, (it++).dest + case MIPS_VSQI: + instruction->operands[i].reg = ins.v.fs; + instruction->operands[i++].operandClass = V_REG; + instruction->operands[i].reg = ins.v.ft + REG_VI0; + instruction->operands[i++].operandClass = V_REG; + + instruction->operands[0].reg = ins.v.dest; + instruction->operands[0].operandClass = V_DEST; + instruction->operands[0].immediate = 1; + break; + // .dest ft.dest, (--is).dest + case MIPS_VLQD: + instruction->operands[i].reg = ins.v.ft; + instruction->operands[i++].operandClass = V_REG; + instruction->operands[i].reg = ins.v.fs + REG_VI0; + instruction->operands[i++].operandClass = V_REG; + + instruction->operands[0].reg = ins.v.dest; + instruction->operands[0].operandClass = V_DEST; + instruction->operands[0].immediate = -1; + break; + // .dest fs.dest, (--it).dest + case MIPS_VSQD: + instruction->operands[i].reg = ins.v.fs; + instruction->operands[i++].operandClass = V_REG; + instruction->operands[i].reg = ins.v.ft + REG_VI0; + instruction->operands[i++].operandClass = V_REG; + + instruction->operands[0].reg = ins.v.dest; + instruction->operands[0].operandClass = V_DEST; + instruction->operands[0].immediate = -1; + break; + + // it, is, Imm5 + case MIPS_VIADDI: + i = 0; + instruction->operands[i].reg = ins.v.ft + REG_VI0; + instruction->operands[i++].operandClass = V_REG; + instruction->operands[i].reg = ins.v.fs + REG_VI0; + instruction->operands[i++].operandClass = V_REG; + instruction->operands[i].reg = ins.v.fd; + instruction->operands[i++].operandClass = IMM; + break; + + // id, is, it + case MIPS_VIADD: + case MIPS_VISUB: + case MIPS_VIAND: + case MIPS_VIOR: + i = 0; + instruction->operands[i].reg = ins.v.fd + REG_VI0; + instruction->operands[i++].operandClass = V_REG; + instruction->operands[i].reg = ins.v.fs + REG_VI0; + instruction->operands[i++].operandClass = V_REG; + instruction->operands[i].reg = ins.v.ft + REG_VI0; + instruction->operands[i++].operandClass = V_REG; + break; + + // .dest ft.dest is + case MIPS_VMFIR: + instruction->operands[i].reg = ins.v.ft; + instruction->operands[i++].operandClass = V_REG; + instruction->operands[i].reg = ins.v.fs + REG_VI0; + instruction->operands[i++].operandClass = V_REG; + + instruction->operands[0].reg = ins.v.dest; + instruction->operands[0].operandClass = V_DEST; + break; + // .dest it, fs.dest + case MIPS_VMTIR: + i = 0; + instruction->operands[i].reg = ins.v.ft + REG_VI0; + instruction->operands[i++].operandClass = V_REG; + instruction->operands[i].reg = ins.v.fs; + instruction->operands[i].immediate = ins.v.bc + 1; + instruction->operands[i++].operandClass = V_REG; + break; + + // bc.dest fs.dest, ft.bc + case MIPS_VCLIPw: + instruction->operands[i].reg = ins.v.fs; + instruction->operands[i++].operandClass = V_REG; + instruction->operands[i].reg = ins.v.ft; + instruction->operands[i].immediate = ins.v.bc + 1; + instruction->operands[i++].operandClass = V_REG; + + instruction->operands[0].reg = ins.v.dest; + instruction->operands[0].operandClass = V_DEST; + break; + + // bc.dest fd.dest, fs.dest, ft.bc + case MIPS_VMINIx: + case MIPS_VMINIy: + case MIPS_VMINIz: + case MIPS_VMINIw: + + case MIPS_VADDx: + case MIPS_VADDy: + case MIPS_VADDz: + case MIPS_VADDw: + + case MIPS_VSUBx: + case MIPS_VSUBy: + case MIPS_VSUBz: + case MIPS_VSUBw: + + case MIPS_VMULx: + case MIPS_VMULy: + case MIPS_VMULz: + case MIPS_VMULw: + + case MIPS_VMAXx: + case MIPS_VMAXy: + case MIPS_VMAXz: + case MIPS_VMAXw: + + case MIPS_VMADDx: + case MIPS_VMADDy: + case MIPS_VMADDz: + case MIPS_VMADDw: + + case MIPS_VMSUBx: + case MIPS_VMSUBy: + case MIPS_VMSUBz: + case MIPS_VMSUBw: + // The broadcast field if present will override the dest field + instruction->operands[3].immediate = ins.v.bc + 1; + // Fall through + + // VOPMSUB.xyz ACC.xyz, fs.xyz, ft.xyz + case MIPS_VOPMSUB: + // Fall through + + // .dest fd.dest, fs.dest, ft.dest + case MIPS_VADD: + case MIPS_VSUB: + case MIPS_VMUL: + case MIPS_VMAX: + case MIPS_VMINI: + case MIPS_VMADD: + case MIPS_VMSUB: + instruction->operands[i].reg = ins.v.fd; + instruction->operands[i++].operandClass = V_REG; + instruction->operands[i].reg = ins.v.fs; + instruction->operands[i++].operandClass = V_REG; + instruction->operands[i].reg = ins.v.ft; + instruction->operands[i++].operandClass = V_REG; + + instruction->operands[0].reg = ins.v.dest; + instruction->operands[0].operandClass = V_DEST; + break; + + // i.dest fd.dest, fs.dest, I + case MIPS_VMAXi: + case MIPS_VMULi: + case MIPS_VMINIi: + case MIPS_VADDi: + case MIPS_VMADDi: + case MIPS_VSUBi: + case MIPS_VMSUBi: + instruction->operands[i].reg = ins.v.fd; + instruction->operands[i++].operandClass = V_REG; + instruction->operands[i].reg = ins.v.fs; + instruction->operands[i++].operandClass = V_REG; + instruction->operands[i].reg = REG_VI; + instruction->operands[i++].operandClass = V_REG; + + instruction->operands[0].reg = ins.v.dest; + instruction->operands[0].operandClass = V_DEST; + break; + + // i.dest ACC.dest, fs.dest, I + case MIPS_VMULAi: + case MIPS_VADDAi: + case MIPS_VMADDAi: + case MIPS_VSUBAi: + case MIPS_VMSUBAi: + instruction->operands[i].reg = REG_VACC; + instruction->operands[i++].operandClass = V_REG; + instruction->operands[i].reg = ins.v.fs; + instruction->operands[i++].operandClass = V_REG; + instruction->operands[i].reg = REG_VI; + instruction->operands[i++].operandClass = V_REG; + + instruction->operands[0].reg = ins.v.dest; + instruction->operands[0].operandClass = V_DEST; + break; + + // Abc.dest ACC.dest, fs.dest, ft.bc + case MIPS_VADDAx: + case MIPS_VADDAy: + case MIPS_VADDAz: + case MIPS_VADDAw: + + case MIPS_VMULAx: + case MIPS_VMULAy: + case MIPS_VMULAz: + case MIPS_VMULAw: + + case MIPS_VMADDAx: + case MIPS_VMADDAy: + case MIPS_VMADDAz: + case MIPS_VMADDAw: + + case MIPS_VMSUBAx: + case MIPS_VMSUBAy: + case MIPS_VMSUBAz: + case MIPS_VMSUBAw: + instruction->operands[3].immediate = ins.v.bc + 1; + // Fall through + + // VOPMULA.xyz ACC.xyz, fs.xyz, ft.xyz + case MIPS_VOPMULA: + instruction->operands[i].reg = REG_VACC; + instruction->operands[i++].operandClass = V_REG; + instruction->operands[i].reg = ins.v.fs; + instruction->operands[i++].operandClass = V_REG; + instruction->operands[i].reg = ins.v.ft; + instruction->operands[i++].operandClass = V_REG; + + instruction->operands[0].reg = ins.v.dest; + instruction->operands[0].operandClass = V_DEST; + break; + + // .dest ACC.dest, fs.dest, ft.dest + case MIPS_VADDA: + case MIPS_VMADDA: + case MIPS_VMULA: + case MIPS_VSUBA: + case MIPS_VMSUBA: + // instruction->operands[i].immediate = 'A'; + instruction->operands[i].reg = REG_VACC; + instruction->operands[i++].operandClass = V_REG; + instruction->operands[i].reg = ins.v.fs; + instruction->operands[i++].operandClass = V_REG; + instruction->operands[i].reg = ins.v.ft; + instruction->operands[i++].operandClass = V_REG; + + instruction->operands[0].reg = ins.v.dest; + instruction->operands[0].operandClass = V_DEST; + break; + + // .dest ACC.dest, fs.dest, Q + case MIPS_VMULAq: + case MIPS_VADDAq: + case MIPS_VMADDAq: + case MIPS_VSUBAq: + case MIPS_VMSUBAq: + // instruction->operands[i].immediate = 'A'; + instruction->operands[i].reg = REG_VACC; + instruction->operands[i++].operandClass = V_REG; + instruction->operands[i].reg = ins.v.fs; + instruction->operands[i++].operandClass = V_REG; + // instruction->operands[i].immediate = 'Q'; + instruction->operands[i].reg = REG_VQ; + instruction->operands[i++].operandClass = V_REG; + + instruction->operands[0].reg = ins.v.dest; + instruction->operands[0].operandClass = V_DEST; + break; + + // .dest fd.dest, fs.dest, Q + case MIPS_VADDq: + case MIPS_VMADDq: + case MIPS_VSUBq: + case MIPS_VMSUBq: + case MIPS_VMULq: + instruction->operands[i].reg = ins.v.fd; + instruction->operands[i++].operandClass = V_REG; + instruction->operands[i].reg = ins.v.fs; + instruction->operands[i++].operandClass = V_REG; + // instruction->operands[i].immediate = 'Q'; + instruction->operands[i].reg = REG_VQ; + instruction->operands[i++].operandClass = V_REG; + + instruction->operands[0].reg = ins.v.dest; + instruction->operands[0].operandClass = V_DEST; + break; + case MIPS_VDIV: + instruction->operands[i].reg = ins.v.fs; + instruction->operands[i].immediate = ins.v.dest & 3; + instruction->operands[i++].operandClass = V_REG_FIELD; + instruction->operands[i].reg = ins.v.ft; + instruction->operands[i].immediate = (ins.v.dest >> 2) & 3; + instruction->operands[i++].operandClass = V_REG_FIELD; + // instruction->operands[0].immediate = 'Q'; + instruction->operands[0].reg = REG_VQ; + instruction->operands[0].operandClass = V_REG; + break; + case MIPS_VSQRT: + instruction->operands[i].reg = ins.v.ft; + instruction->operands[i].immediate = (ins.v.dest >> 2) & 3; + instruction->operands[i++].operandClass = V_REG_FIELD; + // instruction->operands[0].immediate = 'Q'; + instruction->operands[0].reg = REG_VQ; + instruction->operands[0].operandClass = V_REG; + break; + case MIPS_VRSQRT: + instruction->operands[i].reg = ins.v.fs; + instruction->operands[i].immediate = ins.v.dest & 3; + instruction->operands[i++].operandClass = V_REG_FIELD; + instruction->operands[i].reg = ins.v.ft; + instruction->operands[i].immediate = (ins.v.dest >> 2) & 3; + instruction->operands[i++].operandClass = V_REG_FIELD; + // instruction->operands[0].immediate = 'Q'; + instruction->operands[0].reg = REG_VQ; + instruction->operands[0].operandClass = V_REG; + break; + case MIPS_VRINIT: + case MIPS_VRXOR: + instruction->operands[i].reg = ins.v.fs; + instruction->operands[i].immediate = ins.v.dest & 3; + instruction->operands[i++].operandClass = V_REG_FIELD; + // instruction->operands[0].immediate = 'R'; + instruction->operands[0].reg = REG_VR; + instruction->operands[0].operandClass = V_REG; + break; + case MIPS_VRGET: + case MIPS_VRNEXT: + instruction->operands[i].reg = ins.v.ft; + instruction->operands[i++].operandClass = V_REG; + // instruction->operands[i].immediate = 'R'; + instruction->operands[0].reg = REG_VR; + instruction->operands[i++].operandClass = V_REG; + instruction->operands[0].reg = ins.v.dest; + instruction->operands[0].operandClass = V_DEST; + break; + + // .dest ft.dest, fs.dest + case MIPS_VFTOI0: + case MIPS_VFTOI4: + case MIPS_VFTOI12: + case MIPS_VFTOI15: + case MIPS_VITOF0: + case MIPS_VITOF4: + case MIPS_VITOF12: + case MIPS_VITOF15: + case MIPS_VMOVE: + case MIPS_VMR32: + case MIPS_VABS: + instruction->operands[i].reg = ins.v.ft; + instruction->operands[i++].operandClass = V_REG; + instruction->operands[i].reg = ins.v.fs; + instruction->operands[i++].operandClass = V_REG; + + instruction->operands[0].reg = ins.v.dest; + instruction->operands[0].operandClass = V_DEST; + break; default: return 1; } @@ -2364,13 +3692,35 @@ uint32_t mips_disassemble( char* outBuffer, uint32_t outBufferSize) { - char operands[MAX_OPERANDS][64] = {{0},{0},{0},{0}}; + char operands[MAX_OPERANDS+1][64] = {{0},{0},{0},{0}, {0}}; + char operation[64] = {0}; char* operandPtr = NULL; - for (uint32_t i = 0; + char dest[5] = {0}; + int first_operand = 0; + const char* reg = NULL; + + strlcpy(operation, OperationStrings[instruction->operation], sizeof(operation)); + if (instruction->operands[0].operandClass == V_DEST) + { + char* p = dest; + if (instruction->operands[0].reg & 8) + *p++ = 'x'; + if (instruction->operands[0].reg & 4) + *p++ = 'y'; + if (instruction->operands[0].reg & 2) + *p++ = 'z'; + if (instruction->operands[0].reg & 1) + *p++ = 'w'; + *p = '\0'; + strcat(operation, "."); + strcat(operation, dest); + first_operand++; + } + for (uint32_t i = first_operand; i < MAX_OPERANDS && instruction->operands[i].operandClass != NONE; i++) { operandPtr = operands[i]; - if (i != 0) + if (i != first_operand) { *operandPtr++ = ','; *operandPtr++ = ' '; @@ -2418,16 +3768,136 @@ uint32_t mips_disassemble( RegisterStrings[instruction->operands[i].immediate], RegisterStrings[instruction->operands[i].reg]); break; + case V_REG: + // #define V_FMT "$vf%02d" // Use this if leading zeroes are preferred + #define V_FMT "$vf%d" + reg = NULL; + if (instruction->operands[i].reg >= REG_VP) + reg = get_register((Reg)instruction->operands[i].reg); + if (reg != NULL) + { + if (instruction->operands[i].reg >= REG_VI0 && instruction->operands[i].reg <= REG_VI15) + { + switch (instruction->operation) + { + case MIPS_VISWR: + case MIPS_VILWR: + if (i == 2) + { + snprintf(operandPtr, 64, "(%s).%s", reg, dest); + continue; + } + break; + case MIPS_VLQI: + case MIPS_VSQI: + snprintf(operandPtr, 64, "(%s++)", reg); + continue; + case MIPS_VLQD: + case MIPS_VSQD: + snprintf(operandPtr, 64, "(--%s)", reg); + continue; + default: + break; + } + } + if (instruction->operands[i].reg >= REG_VF0 && instruction->operands[i].reg <= REG_VF31) + { + if (instruction->operands[i].immediate > 0 && instruction->operands[i].immediate <= 4) + snprintf(operandPtr, 64, "%s.%c", + reg, + "xyzw"[instruction->operands[i].immediate-1]); + else if (dest[0]) + snprintf(operandPtr, 64, "%s.%s", reg, dest); + } + else + snprintf(operandPtr, 64, "%s", reg); + } + else if (instruction->operands[i].immediate > 0 && instruction->operands[i].immediate <= 4) + snprintf(operandPtr, 64, V_FMT ".%c", + instruction->operands[i].reg, + "xyzw"[instruction->operands[i].immediate-1]); + else if (instruction->operands[i].immediate == 'A') + { + if (dest[0]) + snprintf(operandPtr, 64, "ACC.%s", dest); + else + snprintf(operandPtr, 64, "ACC"); + } + else if (instruction->operands[i].immediate > 'A' && instruction->operands[i].immediate <= 'Z') + snprintf(operandPtr, 64, "%c", + (char) instruction->operands[i].immediate); + else if (dest[0]) + snprintf(operandPtr, 64, V_FMT ".%s", + instruction->operands[i].reg, dest); + else + snprintf(operandPtr, 64, V_FMT, instruction->operands[i].reg); + break; + case V_DEST: + { + // char* p = dest; + // if (*p == '\0' && (instruction->operands[i].reg & 0xF) != 0) + // { + // if (instruction->operands[i].reg & 8) + // *p++ = 'x'; + // if (instruction->operands[i].reg & 4) + // *p++ = 'y'; + // if (instruction->operands[i].reg & 2) + // *p++ = 'z'; + // if (instruction->operands[i].reg & 1) + // *p++ = 'w'; + // *p = '\0'; + // } + break; + } + case V_REG_FIELD: + { + snprintf(operandPtr, 64, V_FMT ".%c", + instruction->operands[i].reg, + "xyzw"[instruction->operands[i].immediate]); + break; + } + // case V_REG: + // strcpy(operandPtr, RegisterStrings[instruction->operands[i].reg + FPREG_F0]); + // if (dest[0]) + // { + // strcat(operandPtr, "_"); + // strcat(operandPtr, dest); + // } + // break; + // case V_DEST: + // { + // char* p = dest; + // if (instruction->operands[i].reg & 8) + // *p++ = 'x'; + // if (instruction->operands[i].reg & 4) + // *p++ = 'y'; + // if (instruction->operands[i].reg & 2) + // *p++ = 'z'; + // if (instruction->operands[i].reg & 1) + // *p++ = 'w'; + // *p = '\0'; + // strcat(operation, "."); + // strcat(operation, dest); + // break; + // } + // case V_REG_FIELD: + // { + // char *p = operandPtr; + // *p++ = "xyzw"[instruction->operands[i].reg]; + // *p = '\0'; + // break; + // } } } if (instruction->operation != MIPS_INVALID && instruction->operation < MIPS_OPERATION_END) { - snprintf(outBuffer, outBufferSize, "%s\t%s%s%s%s", - OperationStrings[instruction->operation], - operands[0], - operands[1], - operands[2], - operands[3]); + snprintf(outBuffer, outBufferSize, "%-13s\t%s%s%s%s", + // OperationStrings[instruction->operation], + operation, + operands[first_operand], + operands[first_operand+1], + operands[first_operand+2], + operands[first_operand+3]); return 0; } return 1; diff --git a/arch/mips/mips/mips.h b/arch/mips/mips/mips.h index 8725f97d7d..d65a72aaa5 100644 --- a/arch/mips/mips/mips.h +++ b/arch/mips/mips/mips.h @@ -513,6 +513,260 @@ namespace mips CNMIPS_ZCB, CNMIPS_ZCBT, + // r5900 Processor Specific Opcodes + MIPS_LQ, + MIPS_SQ, + MIPS_DSLRV, + MIPS_MFSA, + MIPS_MTSA, + MIPS_MTSAB, + MIPS_MTSAH, + MIPS_PLZCW, + MIPS_MFHI1, + MIPS_MTHI1, + MIPS_MFLO1, + MIPS_MTLO1, + MIPS_MULT1, + MIPS_MULTU1, + MIPS_DIV1, + MIPS_DIVU1, + MIPS_MADD1, + MIPS_MADDU1, + MIPS_PMFHL, + MIPS_PMTHL, + MIPS_PSLLH, + MIPS_PSRLH, + MIPS_PSRAH, + MIPS_PSLLW, + MIPS_PSRLW, + MIPS_PSRAW, + MIPS_PADDW, + MIPS_PSUBW, + MIPS_PCGTW, + MIPS_PMAXW, + MIPS_PADDH, + MIPS_PSUBH, + MIPS_PCGTH, + MIPS_PMAXH, + MIPS_PADDB, + MIPS_PSUBB, + MIPS_PCGTB, + MIPS_PADDSW, + MIPS_PSUBSW, + MIPS_PEXTLW, + MIPS_PPACW, + MIPS_PADDSH, + MIPS_PSUBSH, + MIPS_PEXTLH, + MIPS_PPACH, + MIPS_PADDSB, + MIPS_PSUBSB, + MIPS_PEXTLB, + MIPS_PPACB, + MIPS_PEXT5, + MIPS_PPAC5, + MIPS_PABSW, + MIPS_PCEQW, + MIPS_PMINW, + MIPS_PADSBH, + MIPS_PABSH, + MIPS_PCEQH, + MIPS_PMINH, + MIPS_PCEQB, + MIPS_PADDUW, + MIPS_PSUBUW, + MIPS_PEXTUW, + MIPS_PADDUH, + MIPS_PSUBUH, + MIPS_PEXTUH, + MIPS_PADDUB, + MIPS_PSUBUB, + MIPS_PEXTUB, + MIPS_QFSRV, + MIPS_PMADDW, + MIPS_PSLLVW, + MIPS_PSRLVW, + MIPS_PMSUBW, + MIPS_PMFHI, + MIPS_PMFLO, + MIPS_PINTH, + MIPS_PMULTW, + MIPS_PDIVW, + MIPS_PCPYLD, + MIPS_PMADDH, + MIPS_PHMADH, + MIPS_PAND, + MIPS_PXOR, + MIPS_PMSUBH, + MIPS_PHMSBH, + MIPS_PEXEH, + MIPS_PREVH, + MIPS_PMULTH, + MIPS_PDIVBW, + MIPS_PEXEW, + MIPS_PROT3W, + MIPS_PMADDUW, + MIPS_PSRAVW, + MIPS_PMTHI, + MIPS_PMTLO, + MIPS_PINTEH, + MIPS_PMULTUW, + MIPS_PDIVUW, + MIPS_PCPYUD, + MIPS_POR, + MIPS_PNOR, + MIPS_PEXCH, + MIPS_PCPYH, + MIPS_PEXCW, + MIPS_BC0F, + MIPS_BC0T, + MIPS_BC0FL, + MIPS_BC0TL, + MIPS_ADDA_S, + MIPS_SUBA_S, + MIPS_MULA_S, + MIPS_MADDA_S, + MIPS_MSUBA_S, + MIPS_MAX_S, + MIPS_MIN_S, + MIPS_QMFC2, + MIPS_QMFC2_I, + MIPS_QMFC2_NI, + MIPS_QMTC2, + MIPS_QMTC2_I, + MIPS_QMTC2_NI, + + // R5900 VU operations + MIPS_VADDx, + MIPS_VADDy, + MIPS_VADDz, + MIPS_VADDw, + MIPS_VSUBx, + MIPS_VSUBy, + MIPS_VSUBz, + MIPS_VSUBw, + MIPS_VMADDx, + MIPS_VMADDy, + MIPS_VMADDz, + MIPS_VMADDw, + MIPS_VMSUBx, + MIPS_VMSUBy, + MIPS_VMSUBz, + MIPS_VMSUBw, + MIPS_VMAXx, + MIPS_VMAXy, + MIPS_VMAXz, + MIPS_VMAXw, + MIPS_VMINIx, + MIPS_VMINIy, + MIPS_VMINIz, + MIPS_VMINIw, + MIPS_VMULx, + MIPS_VMULy, + MIPS_VMULz, + MIPS_VMULw, + MIPS_VMULq, + MIPS_VMAXi, + MIPS_VMULi, + MIPS_VMINIi, + MIPS_VADDq, + MIPS_VMADDq, + MIPS_VADDi, + MIPS_VMADDi, + MIPS_VSUBq, + MIPS_VMSUBq, + MIPS_VSUBi, + MIPS_VMSUBi, + MIPS_VADD, + MIPS_VMADD, + MIPS_VMUL, + MIPS_VMAX, + MIPS_VSUB, + MIPS_VMSUB, + MIPS_VOPMSUB, + MIPS_VMINI, + MIPS_VIADD, + MIPS_VISUB, + MIPS_VIADDI, + MIPS_VIAND, + MIPS_VIOR, + MIPS_VCALLMS, + MIPS_VCALLMSR, + MIPS_VADDAx, + MIPS_VADDAy, + MIPS_VADDAz, + MIPS_VADDAw, + MIPS_VSUBAx, + MIPS_VSUBAy, + MIPS_VSUBAz, + MIPS_VSUBAw, + MIPS_VMADDAx, + MIPS_VMADDAy, + MIPS_VMADDAz, + MIPS_VMADDAw, + MIPS_VMSUBAx, + MIPS_VMSUBAy, + MIPS_VMSUBAz, + MIPS_VMSUBAw, + MIPS_VITOF0, + MIPS_VITOF4, + MIPS_VITOF12, + MIPS_VITOF15, + MIPS_VFTOI0, + MIPS_VFTOI4, + MIPS_VFTOI12, + MIPS_VFTOI15, + MIPS_VMULAx, + MIPS_VMULAy, + MIPS_VMULAz, + MIPS_VMULAw, + MIPS_VMULAq, + MIPS_VABS, + MIPS_VMULAi, + MIPS_VCLIPw, + MIPS_VADDAq, + MIPS_VMADDAq, + MIPS_VADDAi, + MIPS_VMADDAi, + MIPS_VSUBAq, + MIPS_VMSUBAq, + MIPS_VSUBAi, + MIPS_VMSUBAi, + MIPS_VADDA, + MIPS_VMADDA, + MIPS_VMULA, + MIPS_VSUBA, + MIPS_VMSUBA, + MIPS_VOPMULA, + MIPS_VNOP, + MIPS_VMOVE, + MIPS_VMR32, + MIPS_VLQI, + MIPS_VSQI, + MIPS_VLQD, + MIPS_VSQD, + MIPS_VDIV, + MIPS_VSQRT, + MIPS_VRSQRT, + MIPS_VWAITQ, + MIPS_VMTIR, + MIPS_VMFIR, + MIPS_VILWR, + MIPS_VISWR, + MIPS_VRNEXT, + MIPS_VRGET, + MIPS_VRINIT, + MIPS_VRXOR, + + // r5900 tables + MIPS_MMI0, + MIPS_MMI1, + MIPS_MMI2, + MIPS_MMI3, + + MIPS_LQC2, + MIPS_SQC2, + MIPS_OPERATION_END }; @@ -554,7 +808,7 @@ namespace mips REG_GP, // Global pointer REG_SP, // Stack Pointer REG_FP, // Frame Pointer - REG_RA, // Return Adress + REG_RA, // Return Address CPREG_0, CPREG_1, CPREG_2, @@ -619,6 +873,38 @@ namespace mips FPREG_F29, FPREG_F30, FPREG_F31, + FPREG_FCR0, + FPREG_FCR1, + FPREG_FCR2, + FPREG_FCR3, + FPREG_FCR4, + FPREG_FCR5, + FPREG_FCR6, + FPREG_FCR7, + FPREG_FCR8, + FPREG_FCR9, + FPREG_FCR10, + FPREG_FCR11, + FPREG_FCR12, + FPREG_FCR13, + FPREG_FCR14, + FPREG_FCR15, + FPREG_FCR16, + FPREG_FCR17, + FPREG_FCR18, + FPREG_FCR19, + FPREG_FCR20, + FPREG_FCR21, + FPREG_FCR22, + FPREG_FCR23, + FPREG_FCR24, + FPREG_FCR25, + FPREG_FCR26, + FPREG_FCR27, + FPREG_FCR28, + FPREG_FCR29, + FPREG_FCR30, + FPREG_FCR31, REG_LO, REG_HI, @@ -916,6 +1202,95 @@ namespace mips CNREG2_424F_HSH_STARTSHA512, CNREG2_425D_GFM_XORMUL1, + R5900_SA, + + // R5900 Special registers (upper 64 bits of $lo and $hi) + REG_LO1, + REG_HI1, + + // Emotion Engine VPU registers + + REG_VP, + + REG_VI0, REG_VI1, REG_VI2, REG_VI3, REG_VI4, REG_VI5, REG_VI6, REG_VI7, REG_VI8, REG_VI9, + REG_VI10, REG_VI11, REG_VI12, REG_VI13, REG_VI14, REG_VI15, + REG_VCCR_STATUS, REG_VCCR_MAC, REG_VCCR_CLIPPING, REG_VCCR_19, + // REG_VCCR_R, REG_VCCR_I, REG_VCCR_Q, + REG_VR, + REG_VI, + REG_VQ, + REG_VCCR_23, REG_VCCR_24, REG_VCCR_25, REG_VCCR_TPC, REG_VCCR_CMSAR0, + REG_VCCR_FBRST, REG_VCCR_VPU_STAT, REG_VCCR_30, REG_VCCR_CMSAR1, + + REG_VACC, // R5900 FPU ACC register + REG_VF0, REG_VF1, REG_VF2, REG_VF3, REG_VF4, REG_VF5, REG_VF6, REG_VF7, REG_VF8, REG_VF9, + REG_VF10, REG_VF11, REG_VF12, REG_VF13, REG_VF14, REG_VF15, REG_VF16, REG_VF17, REG_VF18, REG_VF19, + REG_VF20, REG_VF21, REG_VF22, REG_VF23, REG_VF24, REG_VF25, REG_VF26, REG_VF27, REG_VF28, REG_VF29, + REG_VF30, REG_VF31, + + REG_VACC_X, REG_VF0_X, REG_VF1_X, REG_VF2_X, REG_VF3_X, REG_VF4_X, REG_VF5_X, REG_VF6_X, + REG_VF7_X, REG_VF8_X, REG_VF9_X, REG_VF10_X, REG_VF11_X, REG_VF12_X, REG_VF13_X, REG_VF14_X, + REG_VF15_X, REG_VF16_X, REG_VF17_X, REG_VF18_X, REG_VF19_X, REG_VF20_X, REG_VF21_X, REG_VF22_X, + REG_VF23_X, REG_VF24_X, REG_VF25_X, REG_VF26_X, REG_VF27_X, REG_VF28_X, REG_VF29_X, REG_VF30_X, + REG_VF31_X, REG_VACC_Y, REG_VF0_Y, REG_VF1_Y, REG_VF2_Y, REG_VF3_Y, REG_VF4_Y, REG_VF5_Y, + REG_VF6_Y, REG_VF7_Y, REG_VF8_Y, REG_VF9_Y, REG_VF10_Y, REG_VF11_Y, REG_VF12_Y, REG_VF13_Y, + REG_VF14_Y, REG_VF15_Y, REG_VF16_Y, REG_VF17_Y, REG_VF18_Y, REG_VF19_Y, REG_VF20_Y, REG_VF21_Y, + REG_VF22_Y, REG_VF23_Y, REG_VF24_Y, REG_VF25_Y, REG_VF26_Y, REG_VF27_Y, REG_VF28_Y, REG_VF29_Y, + REG_VF30_Y, REG_VF31_Y, REG_VACC_Z, REG_VF0_Z, REG_VF1_Z, REG_VF2_Z, REG_VF3_Z, REG_VF4_Z, + REG_VF5_Z, REG_VF6_Z, REG_VF7_Z, REG_VF8_Z, REG_VF9_Z, REG_VF10_Z, REG_VF11_Z, REG_VF12_Z, + REG_VF13_Z, REG_VF14_Z, REG_VF15_Z, REG_VF16_Z, REG_VF17_Z, REG_VF18_Z, REG_VF19_Z, REG_VF20_Z, + REG_VF21_Z, REG_VF22_Z, REG_VF23_Z, REG_VF24_Z, REG_VF25_Z, REG_VF26_Z, REG_VF27_Z, REG_VF28_Z, + REG_VF29_Z, REG_VF30_Z, REG_VF31_Z, REG_VACC_W, REG_VF0_W, REG_VF1_W, REG_VF2_W, REG_VF3_W, + REG_VF4_W, REG_VF5_W, REG_VF6_W, REG_VF7_W, REG_VF8_W, REG_VF9_W, REG_VF10_W, REG_VF11_W, + REG_VF12_W, REG_VF13_W, REG_VF14_W, REG_VF15_W, REG_VF16_W, REG_VF17_W, REG_VF18_W, REG_VF19_W, + REG_VF20_W, REG_VF21_W, REG_VF22_W, REG_VF23_W, REG_VF24_W, REG_VF25_W, REG_VF26_W, REG_VF27_W, + REG_VF28_W, REG_VF29_W, REG_VF30_W, REG_VF31_W, REG_VACC_XY, REG_VF0_XY, REG_VF1_XY, REG_VF2_XY, + REG_VF3_XY, REG_VF4_XY, REG_VF5_XY, REG_VF6_XY, REG_VF7_XY, REG_VF8_XY, REG_VF9_XY, REG_VF10_XY, + REG_VF11_XY, REG_VF12_XY, REG_VF13_XY, REG_VF14_XY, REG_VF15_XY, REG_VF16_XY, REG_VF17_XY, REG_VF18_XY, + REG_VF19_XY, REG_VF20_XY, REG_VF21_XY, REG_VF22_XY, REG_VF23_XY, REG_VF24_XY, REG_VF25_XY, REG_VF26_XY, + REG_VF27_XY, REG_VF28_XY, REG_VF29_XY, REG_VF30_XY, REG_VF31_XY, REG_VACC_XZ, REG_VF0_XZ, REG_VF1_XZ, + REG_VF2_XZ, REG_VF3_XZ, REG_VF4_XZ, REG_VF5_XZ, REG_VF6_XZ, REG_VF7_XZ, REG_VF8_XZ, REG_VF9_XZ, + REG_VF10_XZ, REG_VF11_XZ, REG_VF12_XZ, REG_VF13_XZ, REG_VF14_XZ, REG_VF15_XZ, REG_VF16_XZ, REG_VF17_XZ, + REG_VF18_XZ, REG_VF19_XZ, REG_VF20_XZ, REG_VF21_XZ, REG_VF22_XZ, REG_VF23_XZ, REG_VF24_XZ, REG_VF25_XZ, + REG_VF26_XZ, REG_VF27_XZ, REG_VF28_XZ, REG_VF29_XZ, REG_VF30_XZ, REG_VF31_XZ, REG_VACC_XW, REG_VF0_XW, + REG_VF1_XW, REG_VF2_XW, REG_VF3_XW, REG_VF4_XW, REG_VF5_XW, REG_VF6_XW, REG_VF7_XW, REG_VF8_XW, + REG_VF9_XW, REG_VF10_XW, REG_VF11_XW, REG_VF12_XW, REG_VF13_XW, REG_VF14_XW, REG_VF15_XW, REG_VF16_XW, + REG_VF17_XW, REG_VF18_XW, REG_VF19_XW, REG_VF20_XW, REG_VF21_XW, REG_VF22_XW, REG_VF23_XW, REG_VF24_XW, + REG_VF25_XW, REG_VF26_XW, REG_VF27_XW, REG_VF28_XW, REG_VF29_XW, REG_VF30_XW, REG_VF31_XW, REG_VACC_YZ, + REG_VF0_YZ, REG_VF1_YZ, REG_VF2_YZ, REG_VF3_YZ, REG_VF4_YZ, REG_VF5_YZ, REG_VF6_YZ, REG_VF7_YZ, + REG_VF8_YZ, REG_VF9_YZ, REG_VF10_YZ, REG_VF11_YZ, REG_VF12_YZ, REG_VF13_YZ, REG_VF14_YZ, REG_VF15_YZ, + REG_VF16_YZ, REG_VF17_YZ, REG_VF18_YZ, REG_VF19_YZ, REG_VF20_YZ, REG_VF21_YZ, REG_VF22_YZ, REG_VF23_YZ, + REG_VF24_YZ, REG_VF25_YZ, REG_VF26_YZ, REG_VF27_YZ, REG_VF28_YZ, REG_VF29_YZ, REG_VF30_YZ, REG_VF31_YZ, + REG_VACC_YW, REG_VF0_YW, REG_VF1_YW, REG_VF2_YW, REG_VF3_YW, REG_VF4_YW, REG_VF5_YW, REG_VF6_YW, + REG_VF7_YW, REG_VF8_YW, REG_VF9_YW, REG_VF10_YW, REG_VF11_YW, REG_VF12_YW, REG_VF13_YW, REG_VF14_YW, + REG_VF15_YW, REG_VF16_YW, REG_VF17_YW, REG_VF18_YW, REG_VF19_YW, REG_VF20_YW, REG_VF21_YW, REG_VF22_YW, + REG_VF23_YW, REG_VF24_YW, REG_VF25_YW, REG_VF26_YW, REG_VF27_YW, REG_VF28_YW, REG_VF29_YW, REG_VF30_YW, + REG_VF31_YW, REG_VACC_ZW, REG_VF0_ZW, REG_VF1_ZW, REG_VF2_ZW, REG_VF3_ZW, REG_VF4_ZW, REG_VF5_ZW, + REG_VF6_ZW, REG_VF7_ZW, REG_VF8_ZW, REG_VF9_ZW, REG_VF10_ZW, REG_VF11_ZW, REG_VF12_ZW, REG_VF13_ZW, + REG_VF14_ZW, REG_VF15_ZW, REG_VF16_ZW, REG_VF17_ZW, REG_VF18_ZW, REG_VF19_ZW, REG_VF20_ZW, REG_VF21_ZW, + REG_VF22_ZW, REG_VF23_ZW, REG_VF24_ZW, REG_VF25_ZW, REG_VF26_ZW, REG_VF27_ZW, REG_VF28_ZW, REG_VF29_ZW, + REG_VF30_ZW, REG_VF31_ZW, REG_VACC_XYZ, REG_VF0_XYZ, REG_VF1_XYZ, REG_VF2_XYZ, REG_VF3_XYZ, REG_VF4_XYZ, + REG_VF5_XYZ, REG_VF6_XYZ, REG_VF7_XYZ, REG_VF8_XYZ, REG_VF9_XYZ, REG_VF10_XYZ, REG_VF11_XYZ, REG_VF12_XYZ, + REG_VF13_XYZ, REG_VF14_XYZ, REG_VF15_XYZ, REG_VF16_XYZ, REG_VF17_XYZ, REG_VF18_XYZ, REG_VF19_XYZ, REG_VF20_XYZ, + REG_VF21_XYZ, REG_VF22_XYZ, REG_VF23_XYZ, REG_VF24_XYZ, REG_VF25_XYZ, REG_VF26_XYZ, REG_VF27_XYZ, REG_VF28_XYZ, + REG_VF29_XYZ, REG_VF30_XYZ, REG_VF31_XYZ, REG_VACC_XYW, REG_VF0_XYW, REG_VF1_XYW, REG_VF2_XYW, REG_VF3_XYW, + REG_VF4_XYW, REG_VF5_XYW, REG_VF6_XYW, REG_VF7_XYW, REG_VF8_XYW, REG_VF9_XYW, REG_VF10_XYW, REG_VF11_XYW, + REG_VF12_XYW, REG_VF13_XYW, REG_VF14_XYW, REG_VF15_XYW, REG_VF16_XYW, REG_VF17_XYW, REG_VF18_XYW, REG_VF19_XYW, + REG_VF20_XYW, REG_VF21_XYW, REG_VF22_XYW, REG_VF23_XYW, REG_VF24_XYW, REG_VF25_XYW, REG_VF26_XYW, REG_VF27_XYW, + REG_VF28_XYW, REG_VF29_XYW, REG_VF30_XYW, REG_VF31_XYW, REG_VACC_XZW, REG_VF0_XZW, REG_VF1_XZW, REG_VF2_XZW, + REG_VF3_XZW, REG_VF4_XZW, REG_VF5_XZW, REG_VF6_XZW, REG_VF7_XZW, REG_VF8_XZW, REG_VF9_XZW, REG_VF10_XZW, + REG_VF11_XZW, REG_VF12_XZW, REG_VF13_XZW, REG_VF14_XZW, REG_VF15_XZW, REG_VF16_XZW, REG_VF17_XZW, REG_VF18_XZW, + REG_VF19_XZW, REG_VF20_XZW, REG_VF21_XZW, REG_VF22_XZW, REG_VF23_XZW, REG_VF24_XZW, REG_VF25_XZW, REG_VF26_XZW, + REG_VF27_XZW, REG_VF28_XZW, REG_VF29_XZW, REG_VF30_XZW, REG_VF31_XZW, REG_VACC_YZW, REG_VF0_YZW, REG_VF1_YZW, + REG_VF2_YZW, REG_VF3_YZW, REG_VF4_YZW, REG_VF5_YZW, REG_VF6_YZW, REG_VF7_YZW, REG_VF8_YZW, REG_VF9_YZW, + REG_VF10_YZW, REG_VF11_YZW, REG_VF12_YZW, REG_VF13_YZW, REG_VF14_YZW, REG_VF15_YZW, REG_VF16_YZW, REG_VF17_YZW, + REG_VF18_YZW, REG_VF19_YZW, REG_VF20_YZW, REG_VF21_YZW, REG_VF22_YZW, REG_VF23_YZW, REG_VF24_YZW, REG_VF25_YZW, + REG_VF26_YZW, REG_VF27_YZW, REG_VF28_YZW, REG_VF29_YZW, REG_VF30_YZW, REG_VF31_YZW, REG_VACC_XYZW, REG_VF0_XYZW, + REG_VF1_XYZW, REG_VF2_XYZW, REG_VF3_XYZW, REG_VF4_XYZW, REG_VF5_XYZW, REG_VF6_XYZW, REG_VF7_XYZW, REG_VF8_XYZW, + REG_VF9_XYZW, REG_VF10_XYZW, REG_VF11_XYZW, REG_VF12_XYZW, REG_VF13_XYZW, REG_VF14_XYZW, REG_VF15_XYZW, REG_VF16_XYZW, + REG_VF17_XYZW, REG_VF18_XYZW, REG_VF19_XYZW, REG_VF20_XYZW, REG_VF21_XYZW, REG_VF22_XYZW, REG_VF23_XYZW, REG_VF24_XYZW, + REG_VF25_XYZW, REG_VF26_XYZW, REG_VF27_XYZW, REG_VF28_XYZW, REG_VF29_XYZW, REG_VF30_XYZW, REG_VF31_XYZW, + // Last valid register END_REG }; @@ -929,6 +1304,8 @@ namespace mips FPCCREG_FCC5, FPCCREG_FCC6, FPCCREG_FCC7, + CCREG_COC0, + CCREG_COC2, END_FLAG }; @@ -940,7 +1317,10 @@ namespace mips LABEL, MEM_IMM, MEM_REG, - HINT + HINT, + V_REG, + V_DEST, + V_REG_FIELD, }; enum Hint { @@ -962,7 +1342,8 @@ namespace mips MIPS_4, MIPS_32, MIPS_64, - MIPS_VERSION_END + MIPS_R5900, + MIPS_VERSION_END, }; #ifndef __cplusplus @@ -1014,6 +1395,25 @@ namespace mips uint32_t opcode:6; }; + struct vtype { + uint32_t bc:2; + uint32_t op_4:4; + uint32_t fd:5; + uint32_t fs:5; + uint32_t ft:5; + uint32_t dest:4; + uint32_t co:1; + uint32_t opcode:6; + }; + + struct vitype { + uint32_t func:6; + uint32_t imm15:15; + uint32_t dest:4; + uint32_t co:1; + uint32_t opcode:6; + }; + struct ttype { uint32_t function:6; uint32_t code:10; @@ -1034,6 +1434,8 @@ namespace mips struct jtype j; struct rtype r; struct ftype f; + struct vtype v; + struct vitype vi; struct ttype t; struct stype s; uint32_t value; @@ -1087,6 +1489,7 @@ namespace mips Operation operation; InstructionOperand operands[MAX_OPERANDS]; uint32_t size; + uint32_t numOperands; }; #ifndef __cplusplus @@ -1124,7 +1527,9 @@ namespace mips const char* get_register(Reg reg); const char* get_flag(enum Flag flag); const char* get_hint(Hint hint); + #ifdef __cplusplus } }//end namespace #endif + diff --git a/arch/mips/mips/test.c b/arch/mips/mips/test.c index df00904347..2a90df4858 100644 --- a/arch/mips/mips/test.c +++ b/arch/mips/mips/test.c @@ -61,7 +61,6 @@ int main(int ac, char **av) uint32_t insword = 0; uint64_t baseaddr = 0; int instindex = 1; - int c = 0; int version = -1; int flags = 0; int result = 0; @@ -79,6 +78,8 @@ int main(int ac, char **av) version = MIPS_3; else if (!strcmp("-mips4", av[1])) version = MIPS_4; + else if (!strcmp("-r5900", av[1])) + version = MIPS_R5900; else if (!strcmp("-cavium", av[1])) { version = MIPS_64; @@ -161,18 +162,32 @@ int main(int ac, char **av) while (instindex < ac) { - insword = strtoul(av[instindex], NULL, 16); - - if (0 == disassemble(insword, baseaddr, version, flags, instxt)) + char *p = av[instindex]; + char buf[9] = {0}; + while (strnlen(p, 8) > 0 && strlen(strncpy(buf, p, 8)) <= 8) { - printf("%08llX: %08X %s\n", baseaddr, insword, instxt); - } - else - { - printf("%08llX: %08X ??\n", baseaddr, insword); + char *endptr; + insword = strtoul(buf, &endptr, 16); + if (endptr == buf) + { + fprintf(stderr, "ERROR: invalid opcode starting at \"%s\"\n", p); + result = -1; + goto cleanup; + } + if (version == MIPS_R5900) + insword = ntohl(insword); + if (0 == disassemble(insword, baseaddr, version, flags, instxt)) + { + printf("%08llX: %08X %s\n", baseaddr, insword, instxt); + } + else + { + printf("%08llX: %08X ??\n", baseaddr, insword); + } + baseaddr += 4; + p += 8; } - baseaddr += 4; instindex++; }