From 680816f88185edaec9bb4b7cb899f2cfe63eefd5 Mon Sep 17 00:00:00 2001 From: kat Date: Sun, 12 Jan 2025 16:54:50 -0500 Subject: [PATCH 01/16] MIPS r5900 (PS2 EE) support --- arch/mips/arch_mips.cpp | 110 ++++--- arch/mips/il.cpp | 36 +++ arch/mips/mips/mips.c | 635 ++++++++++++++++++++++++++++++++++++++-- arch/mips/mips/mips.h | 250 +++++++++++++++- 4 files changed, 962 insertions(+), 69 deletions(-) diff --git a/arch/mips/arch_mips.cpp b/arch/mips/arch_mips.cpp index d7b1d98071..c323ed13b8 100644 --- a/arch/mips/arch_mips.cpp +++ b/arch/mips/arch_mips.cpp @@ -179,27 +179,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_bits == 64 ? MIPS_64 : MIPS_32, 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) { @@ -407,8 +404,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 +505,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; } @@ -847,15 +853,18 @@ class MipsArchitecture: public Architecture break; case MEM_IMM: result.emplace_back(BeginMemoryOperandToken, ""); - if (imm < -9) - snprintf(operand, sizeof(operand), "-%#x", -imm); - else if (imm < 0) - snprintf(operand, sizeof(operand), "-%d", -imm); - else if (imm < 10) - snprintf(operand, sizeof(operand), "%d", imm); - else - snprintf(operand, sizeof(operand), "%#x", imm); - result.emplace_back(IntegerToken, operand, imm); + if (imm != 0) + { + if (imm < -9) + snprintf(operand, sizeof(operand), "-%#x", -imm); + else if (imm < 0) + snprintf(operand, sizeof(operand), "-%d", -imm); + else if (imm < 10) + snprintf(operand, sizeof(operand), "%d", imm); + else + snprintf(operand, sizeof(operand), "%#x", imm); + result.emplace_back(IntegerToken, operand, imm); + } if (instr.operands[i].reg == REG_ZERO) break; result.emplace_back(BraceToken, "("); @@ -3013,7 +3022,14 @@ 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)) + + MipsVersion version; + if (arch->GetName().substr(0, 5) == "r5900") + version = MIPS_R5900; + else + version = arch->GetAddressSize() == 8 ? MIPS_64 : MIPS_32; + + if (mips_decompose(&inst2, sizeof(uint32_t), &instruction, version, cur->address, arch->GetEndianness(), DECOMPOSE_FLAGS_PSEUDO_OP)) break; int32_t immediate = swap(inst2) & 0xffff; @@ -3190,8 +3206,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 +3276,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); @@ -3289,10 +3307,14 @@ extern "C" mipseb->SetDefaultCallingConvention(o32BE); mipsel->RegisterCallingConvention(o32LE); mipsel->SetDefaultCallingConvention(o32LE); + r5900l->RegisterCallingConvention(o32LE); + r5900l->SetDefaultCallingConvention(o32LE); + r5900b->RegisterCallingConvention(o32BE); + r5900b->SetDefaultCallingConvention(o32BE); 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); @@ -3300,15 +3322,23 @@ extern "C" cnmips64eb->RegisterCallingConvention(n64BEc); cnmips64eb->SetDefaultCallingConvention(n64BEc); - 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 +3346,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 +3355,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..81ba85b994 100644 --- a/arch/mips/il.cpp +++ b/arch/mips/il.cpp @@ -2159,6 +2159,42 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu break; + case MIPS_MTSAB: + { + auto gprValue = il.Register(4, op1.reg); + auto gprLS4 = il.And(4, gprValue, il.Const(4, 0xF)); + + // Extract least-significant 4 bits of immediate value + auto immLS4 = il.And(4, il.Const(4, op2.immediate), il.Const(4, 0xF)); + + // Perform XOR operation between GPR[rs][3:0] and immediate[3:0] + auto xorResult = il.Xor(4, gprLS4, immLS4); + + // Multiply result by 8 (equivalent to left shift by 3) + auto 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_ADDR: case MIPS_LDXC1: case MIPS_LLO: diff --git a/arch/mips/mips/mips.c b/arch/mips/mips/mips.c index e046d795de..e6afe21617 100644 --- a/arch/mips/mips/mips.c +++ b/arch/mips/mips/mips.c @@ -67,7 +67,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 +122,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 +190,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_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {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 +233,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,6 +348,100 @@ 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 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", @@ -805,7 +922,244 @@ static const char* const OperationStrings[] = { "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", + "qmtc2", + "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", }; static const char * const RegisterStrings[] = { @@ -1154,6 +1508,8 @@ static const char * const RegisterStrings[] = { "CVMX_HSH_STARTSHA512", "CVMX_GFM_XORMUL1", + + "sa" }; static const char * const FlagStrings[] = { @@ -1293,6 +1649,8 @@ 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) @@ -1308,7 +1666,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 +1726,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 +1759,18 @@ 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; + } + } case 10: instruction->operation = MIPS_RDPGPR; break; case 11: if (ins.bits.bit5 == 1) @@ -1412,6 +1793,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 +1845,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 +1895,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 +1943,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 +2073,7 @@ uint32_t mips_decompose_instruction( } } - //Now that we have the proper instructions aliased figure out what our operands are + // Stage 3: Now that we have the proper instructions aliased figure out what our operands are switch(instruction->operation) { //Zero operand instructions @@ -1691,6 +2106,12 @@ 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)) + break; case MIPS_COP2: INS_1(IMM, (ins.value & 0x1ffffff)) break; @@ -1707,11 +2128,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 +2158,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 +2208,10 @@ 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_MTSAB: + case MIPS_MTSAH: + INS_2(REG, ins.i.rs, IMM, ins.i.immediate) + break; case MIPS_CLO: case MIPS_CLZ: case MIPS_NOT: @@ -1877,16 +2324,31 @@ uint32_t mips_decompose_instruction( case MIPS_DIVU: case MIPS_DMULT: case MIPS_DMULTU: - 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) return 1; INS_2(REG, ins.r.rs, REG, ins.r.rt) break; + case MIPS_MULT: + case MIPS_MADD: + case MIPS_MADDU: + 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; case MIPS_LUI: if (ins.i.rs != 0) return 1; @@ -1911,8 +2373,27 @@ 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) case MIPS_CFC0: case MIPS_CTC0: case MIPS_CFC1: @@ -2015,7 +2496,14 @@ uint32_t mips_decompose_instruction( return 1; INS_2(REG, ins.f.fd + FPREG_F0, REG, ins.f.fs + FPREG_F0) break; - + 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,6 +2539,8 @@ 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; @@ -2099,11 +2589,86 @@ uint32_t mips_decompose_instruction( case MIPS_LWC3: instruction->operands[0].operandClass = IMM; instruction->operands[1].operandClass = MEM_IMM; - instruction->operands[0].reg = ins.i.rt; - instruction->operands[1].reg = ins.i.rs; + instruction->operands[0].reg = version != MIPS_R5900 ? ins.i.rt : (FPREG_F0 + ins.f.ft); + instruction->operands[1].reg = version != MIPS_R5900 ? ins.i.rs : (FPREG_F0 + ins.f.fr); instruction->operands[1].immediate = ins.i.immediate; break; //3 operand instructions + case MIPS_MULT1: + case MIPS_MULTU1: + case MIPS_DIV1: + case MIPS_DIVU1: + 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,6 +2693,7 @@ 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: @@ -2197,6 +2763,12 @@ 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; @@ -2236,9 +2808,14 @@ 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_MADD_D: diff --git a/arch/mips/mips/mips.h b/arch/mips/mips/mips.h index 8725f97d7d..d4c45efa23 100644 --- a/arch/mips/mips/mips.h +++ b/arch/mips/mips/mips.h @@ -513,6 +513,251 @@ 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_QMTC2, + 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_OPERATION_END }; @@ -916,6 +1161,8 @@ namespace mips CNREG2_424F_HSH_STARTSHA512, CNREG2_425D_GFM_XORMUL1, + R5900_SA, + // Last valid register END_REG }; @@ -962,7 +1209,8 @@ namespace mips MIPS_4, MIPS_32, MIPS_64, - MIPS_VERSION_END + MIPS_R5900, + MIPS_VERSION_END, }; #ifndef __cplusplus From 7527192d38b9fa3c002139b589b841b1405434bb Mon Sep 17 00:00:00 2001 From: kat Date: Tue, 14 Jan 2025 08:18:11 -0500 Subject: [PATCH 02/16] [mips r5900] PADDUW lifting --- arch/mips/il.cpp | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/arch/mips/il.cpp b/arch/mips/il.cpp index 81ba85b994..c08b9905b8 100644 --- a/arch/mips/il.cpp +++ b/arch/mips/il.cpp @@ -2194,6 +2194,48 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu break; } + case MIPS_PADDUW: + { + for (int i = 0; i < 4; i++) + { + size_t offset = i * 32; + auto rs_segment = il.And(16, + il.LogicalShiftRight( + 16, + il.Register(16, op2.reg), + il.Const(4, offset) + ), + il.Const(128, 0xFFFFFFFF) + ); + auto rt_segment = il.And(16, + il.LogicalShiftRight( + 16, + il.Register(16, op3.reg), + il.Const(4, offset) + ), + il.Const(128, 0xFFFFFFFF) + ); + + auto sum = il.Add(8, rs_segment, rt_segment); + + // This is a 4 byte add, but if the sum is greater than 0xFFFFFFFF, the result is 0xFFFFFFFF + // So we do an 8 bit add and and the result + + auto saturated_sum = il.And(4, sum, il.Const(4, 0xFFFFFFFF)); + + auto shifted_sum = il.ShiftLeft(16, saturated_sum, il.Const(4, offset)); + 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))); + } + } + + break; + } case MIPS_ADDR: case MIPS_LDXC1: From 7ee84cb2b5f0b4ce340b383f4a26cab2719ba2e9 Mon Sep 17 00:00:00 2001 From: Galen Williamson Date: Fri, 7 Feb 2025 19:20:29 -0500 Subject: [PATCH 03/16] [mips] Fix r5900 mult not assigning to destination register --- arch/mips/il.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/mips/il.cpp b/arch/mips/il.cpp index c08b9905b8..38e60d90b4 100644 --- a/arch/mips/il.cpp +++ b/arch/mips/il.cpp @@ -1181,6 +1181,9 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu 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 (rd != REG_ZERO) + // mflo + il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, rd, il.Register(registerSize, REG_LO))); break; 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)))); From fd596fb838fd9ca001964acfa2f6ee32fed0e481 Mon Sep 17 00:00:00 2001 From: Galen Williamson Date: Tue, 11 Feb 2025 14:10:19 -0500 Subject: [PATCH 04/16] WIP [mips] merging dev into PR https://github.com/Vector35/binaryninja-api/pull/6311: MIPS r5900 (PS2 EE) support --- arch/mips/arch_mips.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/arch/mips/arch_mips.cpp b/arch/mips/arch_mips.cpp index c323ed13b8..7acee523b2 100644 --- a/arch/mips/arch_mips.cpp +++ b/arch/mips/arch_mips.cpp @@ -188,7 +188,7 @@ class MipsArchitecture: public Architecture virtual bool Disassemble(const uint8_t* data, uint64_t addr, size_t maxLen, Instruction& result) { memset(&result, 0, sizeof(result)); - if (mips_decompose((uint32_t*)data, maxLen, &result, m_bits == 64 ? MIPS_64 : MIPS_32, 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; } @@ -3022,14 +3022,7 @@ class MipsElfRelocationHandler: public RelocationHandler uint32_t inst2 = *(uint32_t*)(cur->relocationDataCache); Instruction instruction; memset(&instruction, 0, sizeof(instruction)); - - MipsVersion version; - if (arch->GetName().substr(0, 5) == "r5900") - version = MIPS_R5900; - else - version = arch->GetAddressSize() == 8 ? MIPS_64 : MIPS_32; - - if (mips_decompose(&inst2, sizeof(uint32_t), &instruction, version, cur->address, arch->GetEndianness(), DECOMPOSE_FLAGS_PSEUDO_OP)) + if (mips_decompose(&inst2, sizeof(uint32_t), &instruction, m_version, cur->address, arch->GetEndianness(), DECOMPOSE_FLAGS_PSEUDO_OP)) break; int32_t immediate = swap(inst2) & 0xffff; From c3df502948deb004382104be9c24cd77ad4fca5f Mon Sep 17 00:00:00 2001 From: Galen Williamson Date: Wed, 12 Feb 2025 14:09:47 -0500 Subject: [PATCH 05/16] WIP [mips] Fixing PR for r5900: merged from dev, integrate MIPS version awareness, fix 3-op variants of MULT/U and MADD/U, WIP tweaking register size on R5900 --- arch/mips/arch_mips.cpp | 35 ++++++++++++++++++----- arch/mips/il.cpp | 62 +++++++++++++++++++++++++++++++++++------ arch/mips/il.h | 3 +- arch/mips/mips/mips.c | 19 +++++++++++-- arch/mips/mips/mips.h | 5 ++++ arch/mips/mips/test.c | 3 +- 6 files changed, 107 insertions(+), 20 deletions(-) diff --git a/arch/mips/arch_mips.cpp b/arch/mips/arch_mips.cpp index 7acee523b2..6957ca3638 100644 --- a/arch/mips/arch_mips.cpp +++ b/arch/mips/arch_mips.cpp @@ -534,7 +534,7 @@ class MipsArchitecture: public Architecture il.AddInstruction(il.If(GetConditionForInstruction(il, instr, GetAddressSize()), 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) @@ -560,7 +560,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; @@ -587,7 +587,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) @@ -752,12 +752,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 @@ -1570,7 +1570,12 @@ 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[] = { REG_LO1, REG_HI1 }; + registers.insert(registers.end(), std::begin(r5900_registers), std::end(r5900_registers)); + } + else if ((m_decomposeFlags & DECOMPOSE_FLAGS_CAVIUM) != 0) { uint32_t cavium_registers[] = { @@ -1888,7 +1893,11 @@ class MipsArchitecture: public Architecture REG_DESAVE, }; - if ((m_decomposeFlags & DECOMPOSE_FLAGS_CAVIUM) != 0) + if (m_version == MIPS_R5900) { + uint32_t r5900_registers[] = { REG_LO1, REG_HI1 }; + registers.insert(registers.end(), std::begin(r5900_registers), std::end(r5900_registers)); + } + else if ((m_decomposeFlags & DECOMPOSE_FLAGS_CAVIUM) != 0) { uint32_t cavium_registers[] = { @@ -2098,6 +2107,18 @@ class MipsArchitecture: public Architecture virtual BNRegisterInfo GetRegisterInfo(uint32_t reg) override { BNRegisterInfo result = {reg, 0, m_bits / 8, NoExtend}; + if (m_version == MIPS_R5900) { + switch (reg) { + case REG_LO: + case REG_HI: + case REG_LO1: + case REG_HI1: + result.size = 64 / 8; + default: + if (REG_ZERO <= reg && reg <= REG_RA) + result.size = 128 / 8; + } + } return result; } diff --git a/arch/mips/il.cpp b/arch/mips/il.cpp index 38e60d90b4..b92ee5711c 100644 --- a/arch/mips/il.cpp +++ b/arch/mips/il.cpp @@ -796,7 +796,7 @@ 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) +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]; @@ -1179,15 +1179,61 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu SignExtendHiLo(il, registerSize); break; 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 (rd != REG_ZERO) - // mflo - il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, rd, il.Register(registerSize, REG_LO))); + if (version == MIPS_R5900 && instr.numOperands == 3) { + auto temp = LLIL_TEMP(0); + il.AddInstruction(il.SetRegister(8, temp, + il.MultDoublePrecSigned(4, + ReadILOperand(il, instr, 2, registerSize), + ReadILOperand(il, instr, 3, registerSize)))); + il.AddInstruction(il.SetRegister(registerSize, REG_HI, il.SignExtend(8, il.ArithShiftRight(8, il.Register(8, temp), il.Const(8, 32))))); + il.AddInstruction(il.SetRegister(registerSize, REG_LO, il.SignExtend(8, il.LowPart(4, il.Register(8, temp))))); + // il.AddInstruction(il.SetRegisterSplit(4, REG_HI, REG_LO, + // il.MultDoublePrecSigned(8, + // ReadILOperand(il, instr, 2, registerSize), + // ReadILOperand(il, instr, 3, registerSize)))); + SignExtendHiLo(il, registerSize); + auto rd = op1.reg; + if (rd != REG_ZERO) + il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, rd, il.Register(registerSize, REG_LO))); + } + // if (version == MIPS_R5900 && instr.numOperands == 3) { + // il.AddInstruction(il.SetRegisterSplit(4, REG_HI, REG_LO, + // il.MultDoublePrecSigned(8, + // ReadILOperand(il, instr, 2, registerSize), + // ReadILOperand(il, instr, 3, registerSize)))); + // SignExtendHiLo(il, registerSize); + // auto rd = op1.reg; + // if (rd != REG_ZERO) + // il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, rd, il.Register(registerSize, REG_LO))); + // } + else + { + 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); + } break; 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) { + il.AddInstruction(il.SetRegisterSplit(4, REG_HI, REG_LO, + il.MultDoublePrecUnsigned(4, + ReadILOperand(il, instr, 2, registerSize), + ReadILOperand(il, instr, 3, registerSize)))); + SignExtendHiLo(il, registerSize); + auto rd = op1.reg; + if (rd != REG_ZERO) + il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, rd, il.Register(registerSize, REG_LO))); + } + else + { + 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); + } 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)))); diff --git a/arch/mips/il.h b/arch/mips/il.h index df84f4a699..6babadc15e 100644 --- a/arch/mips/il.h +++ b/arch/mips/il.h @@ -88,6 +88,7 @@ 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, size_t registerSize); diff --git a/arch/mips/mips/mips.c b/arch/mips/mips/mips.c index e6afe21617..b7d6cc4a36 100644 --- a/arch/mips/mips/mips.c +++ b/arch/mips/mips/mips.c @@ -22,6 +22,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 +31,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 +42,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 +55,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); @@ -126,7 +130,7 @@ static Operation mips_base_table[7][8][8] = { {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_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}, @@ -1509,7 +1513,10 @@ static const char * const RegisterStrings[] = { "CVMX_HSH_STARTSHA512", "CVMX_GFM_XORMUL1", - "sa" + "sa", + + "$lo1", + "$hi1", }; static const char * const FlagStrings[] = { @@ -1657,6 +1664,8 @@ uint32_t mips_decompose_instruction( 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; default: if ((flags & DECOMPOSE_FLAGS_CAVIUM) == 0) @@ -2546,6 +2555,8 @@ uint32_t mips_decompose_instruction( instruction->operands[0].reg = ins.i.rt; instruction->operands[1].reg = ins.i.rs; instruction->operands[1].immediate = ins.i.immediate; + if (instruction->operation == MIPS_SQ) + instruction->operands[1].immediate = MIPS_SQ; break; case MIPS_PREF: case MIPS_PREFX: @@ -2590,7 +2601,9 @@ uint32_t mips_decompose_instruction( instruction->operands[0].operandClass = IMM; instruction->operands[1].operandClass = MEM_IMM; instruction->operands[0].reg = version != MIPS_R5900 ? ins.i.rt : (FPREG_F0 + ins.f.ft); - instruction->operands[1].reg = version != MIPS_R5900 ? ins.i.rs : (FPREG_F0 + ins.f.fr); + // 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); + instruction->operands[1].reg = ins.i.rs; instruction->operands[1].immediate = ins.i.immediate; break; //3 operand instructions diff --git a/arch/mips/mips/mips.h b/arch/mips/mips/mips.h index d4c45efa23..98465bbc03 100644 --- a/arch/mips/mips/mips.h +++ b/arch/mips/mips/mips.h @@ -1163,6 +1163,10 @@ namespace mips R5900_SA, + // R5900 Special registers (upper 64 bits of $lo and $hi) + REG_LO1, + REG_HI1, + // Last valid register END_REG }; @@ -1335,6 +1339,7 @@ namespace mips Operation operation; InstructionOperand operands[MAX_OPERANDS]; uint32_t size; + uint32_t numOperands; }; #ifndef __cplusplus diff --git a/arch/mips/mips/test.c b/arch/mips/mips/test.c index df00904347..d15086fea6 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; From 4b91b62c235e01c102b434263c9655afa9b6417f Mon Sep 17 00:00:00 2001 From: Galen Williamson Date: Thu, 13 Feb 2025 16:22:38 -0500 Subject: [PATCH 06/16] WIP [mips] Fixing PR for r5900: adding lifting for missing r5900 instructions, starting to fix R5900 register size --- arch/mips/arch_mips.cpp | 18 ++- arch/mips/il.cpp | 326 +++++++++++++++++++++++++++++++++++----- arch/mips/mips/mips.h | 35 ++++- 3 files changed, 339 insertions(+), 40 deletions(-) diff --git a/arch/mips/arch_mips.cpp b/arch/mips/arch_mips.cpp index 6957ca3638..0bf6f1f6ce 100644 --- a/arch/mips/arch_mips.cpp +++ b/arch/mips/arch_mips.cpp @@ -2108,15 +2108,23 @@ class MipsArchitecture: public Architecture { BNRegisterInfo result = {reg, 0, m_bits / 8, NoExtend}; if (m_version == MIPS_R5900) { + result.size = get_register_width(reg, m_version); switch (reg) { - case REG_LO: - case REG_HI: + // case REG_LO: + // case REG_HI: + // result.size = 64 / 8; + // break; case REG_LO1: case REG_HI1: - result.size = 64 / 8; + // result.size = (128 / 2); + if (reg == REG_LO1) + result.fullWidthRegister = REG_LO; + else if (reg == REG_HI1) + result.fullWidthRegister = REG_HI; + break; default: - if (REG_ZERO <= reg && reg <= REG_RA) - result.size = 128 / 8; + // if (REG_ZERO <= reg && reg < REG_GP) + // result.size = 128 / 8; } } return result; diff --git a/arch/mips/il.cpp b/arch/mips/il.cpp index b92ee5711c..87e1c03226 100644 --- a/arch/mips/il.cpp +++ b/arch/mips/il.cpp @@ -1098,15 +1098,27 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu case MIPS_MFHI: il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.Register(registerSize, REG_HI))); break; + case MIPS_MFHI1: + il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.Register(registerSize, REG_HI1))); + break; case MIPS_MFLO: il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.Register(registerSize, REG_LO))); break; + case MIPS_MFLO1: + il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.Register(registerSize, REG_LO1))); + break; case MIPS_MTHI: il.AddInstruction(il.SetRegister(registerSize, REG_HI, ReadILOperand(il, instr, 1, registerSize))); break; + case MIPS_MTHI1: + il.AddInstruction(il.SetRegister(registerSize, REG_HI1, ReadILOperand(il, instr, 1, registerSize))); + break; case MIPS_MTLO: il.AddInstruction(il.SetRegister(registerSize, REG_LO, ReadILOperand(il, instr, 1, registerSize))); break; + case MIPS_MTLO1: + il.AddInstruction(il.SetRegister(registerSize, REG_LO1, ReadILOperand(il, instr, 1, registerSize))); + break; case MIPS_DMFC0: il.AddInstruction(MoveFromCoprocessor(0, il, 8, op1.reg, op2.immediate, op3.immediate, decomposeFlags)); break; @@ -1346,7 +1358,7 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu case MIPS_SC: { LowLevelILLabel trueCode, falseCode, doneCode; - il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(LLIL_TEMP(0)) }, MIPS_INTRIN_LLBIT_CHECK, {})); + 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)); il.MarkLabel(trueCode); @@ -1364,6 +1376,9 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu case MIPS_SD: il.AddInstruction(il.Store(8, GetILOperandMemoryAddress(il, op2, addrSize), ReadILOperand(il, instr, 1, registerSize))); break; + case MIPS_SQ: + il.AddInstruction(il.Store(16, GetILOperandMemoryAddress(il, op2, addrSize), ReadILOperand(il, instr, 1, registerSize))); + break; case MIPS_SCD: { LowLevelILLabel trueCode, falseCode, doneCode; @@ -1471,6 +1486,9 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu case MIPS_LD: il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, ReadILOperand(il, instr, 2, registerSize))); break; + case MIPS_LQ: + il.AddInstruction(SetRegisterOrNop(il, 16, registerSize, op1.reg, ReadILOperand(il, instr, 2, registerSize))); + break; case MIPS_LWL: { int32_t delta = endian == LittleEndian ? -3 : 0; @@ -2243,45 +2261,158 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu break; } - case MIPS_PADDUW: + case MIPS_PADDUB: { - for (int i = 0; i < 4; i++) - { - size_t offset = i * 32; - auto rs_segment = il.And(16, - il.LogicalShiftRight( - 16, - il.Register(16, op2.reg), - il.Const(4, offset) - ), - il.Const(128, 0xFFFFFFFF) - ); - auto rt_segment = il.And(16, - il.LogicalShiftRight( - 16, - il.Register(16, op3.reg), - il.Const(4, offset) - ), - il.Const(128, 0xFFFFFFFF) - ); + if (op3.reg == REG_ZERO) + if (op2.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, op2.reg))); + else if (op2.reg == REG_ZERO) + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, op3.reg))); + else + { + for (int i = 0; i < 16; i++) + { + size_t offset = i * 8; + auto rs_segment = il.And(16, + il.LogicalShiftRight( + 16, + il.Register(16, op2.reg), + il.Const(4, offset) + ), + il.Const(128, 0xFFFFFFFF) + ); + auto rt_segment = il.And(16, + il.LogicalShiftRight( + 16, + il.Register(16, op3.reg), + il.Const(4, offset) + ), + il.Const(128, 0xFFFFFFFF) + ); - auto sum = il.Add(8, rs_segment, rt_segment); + auto sum = il.Add(1, rs_segment, rt_segment); - // This is a 4 byte add, but if the sum is greater than 0xFFFFFFFF, the result is 0xFFFFFFFF - // So we do an 8 bit add and and the result + // This is a 1 byte add, but if the sum is greater than 0xFFFF, the result is 0xFFFF + // So we do an 8 bit add and and the result - auto saturated_sum = il.And(4, sum, il.Const(4, 0xFFFFFFFF)); + auto saturated_sum = il.And(1, sum, il.Const(1, 0xFF)); - auto shifted_sum = il.ShiftLeft(16, saturated_sum, il.Const(4, offset)); - if (i == 0) - { - il.AddInstruction(il.SetRegister(16, op1.reg, shifted_sum)); - } + auto shifted_sum = il.ShiftLeft(16, saturated_sum, il.Const(4, offset)); + 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))); + } + } + } + + break; + } case MIPS_PADDUH: + { + if (op3.reg == REG_ZERO) + if (op2.reg == REG_ZERO) + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Const(16, 0))); else - { - il.AddInstruction(il.SetRegister(16, op1.reg, il.Or(16, il.Register(16, op1.reg), shifted_sum))); - } - } + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, op2.reg))); + else if (op2.reg == REG_ZERO) + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, op3.reg))); + else + { + for (int i = 0; i < 8; i++) + { + size_t offset = i * 16; + auto rs_segment = il.And(16, + il.LogicalShiftRight( + 16, + il.Register(16, op2.reg), + il.Const(4, offset) + ), + il.Const(128, 0xFFFFFFFF) + ); + auto rt_segment = il.And(16, + il.LogicalShiftRight( + 16, + il.Register(16, op3.reg), + il.Const(4, offset) + ), + il.Const(128, 0xFFFFFFFF) + ); + + auto sum = il.Add(2, rs_segment, rt_segment); + + // This is a 2 byte add, but if the sum is greater than 0xFFFF, the result is 0xFFFF + // So we do an 8 bit add and and the result + + auto saturated_sum = il.And(2, sum, il.Const(2, 0xFFFF)); + + auto shifted_sum = il.ShiftLeft(16, saturated_sum, il.Const(4, offset)); + 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))); + } + } + } + + break; + } + case MIPS_PADDUW: + { + if (op3.reg == REG_ZERO) + if (op2.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, op2.reg))); + else if (op2.reg == REG_ZERO) + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, op3.reg))); + else + { + for (int i = 0; i < 4; i++) + { + size_t offset = i * 32; + auto rs_segment = il.And(16, + il.LogicalShiftRight( + 16, + il.Register(16, op2.reg), + il.Const(4, offset) + ), + il.Const(128, 0xFFFFFFFF) + ); + auto rt_segment = il.And(16, + il.LogicalShiftRight( + 16, + il.Register(16, op3.reg), + il.Const(4, offset) + ), + il.Const(128, 0xFFFFFFFF) + ); + + auto sum = il.Add(4, rs_segment, rt_segment); + + // This is a 4 byte add, but if the sum is greater than 0xFFFFFFFF, the result is 0xFFFFFFFF + // So we do an 8 bit add and and the result + + auto saturated_sum = il.And(4, sum, il.Const(4, 0xFFFFFFFF)); + + auto shifted_sum = il.ShiftLeft(16, saturated_sum, il.Const(4, offset)); + 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))); + } + } + } break; } @@ -2346,6 +2477,133 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu case MIPS_MADD_S: case MIPS_MADDF_D: case MIPS_MADDF_S: + // 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_MMI0: + case MIPS_MMI1: + case MIPS_MMI2: + case MIPS_MMI3: il.AddInstruction(il.Unimplemented()); break; diff --git a/arch/mips/mips/mips.h b/arch/mips/mips/mips.h index 98465bbc03..f8da11d3ee 100644 --- a/arch/mips/mips/mips.h +++ b/arch/mips/mips/mips.h @@ -799,7 +799,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, @@ -1381,3 +1381,36 @@ namespace mips } }//end namespace #endif + +static inline const size_t get_register_width(Reg reg, MipsVersion version) { + 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 = 64; + break; + case REG_LO1: + case REG_HI1: + width = 128; + break; + default: + if (REG_ZERO <= reg && reg < REG_GP) + width = 128; + } + } + return width / 8; +} \ No newline at end of file From 471389c65949c5e00d965f1e45da646ed7e12bad Mon Sep 17 00:00:00 2001 From: Galen Williamson Date: Fri, 14 Feb 2025 20:35:49 -0500 Subject: [PATCH 07/16] WIP [mips] Fixing PR for r5900: fixed register sizes depending on instruction context; lifting unsigned unsigned padd* and saturating paddu* --- arch/mips/arch_mips.cpp | 10 +- arch/mips/il.cpp | 1099 +++++++++++++++++++++++++-------------- arch/mips/il.h | 48 +- arch/mips/mips/mips.h | 33 +- 4 files changed, 759 insertions(+), 431 deletions(-) diff --git a/arch/mips/arch_mips.cpp b/arch/mips/arch_mips.cpp index 0bf6f1f6ce..b87d69a45c 100644 --- a/arch/mips/arch_mips.cpp +++ b/arch/mips/arch_mips.cpp @@ -530,8 +530,13 @@ 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, m_version); @@ -2108,7 +2113,7 @@ class MipsArchitecture: public Architecture { BNRegisterInfo result = {reg, 0, m_bits / 8, NoExtend}; if (m_version == MIPS_R5900) { - result.size = get_register_width(reg, m_version); + result.size = get_register_width(reg, m_version, 16); switch (reg) { // case REG_LO: // case REG_HI: @@ -2123,6 +2128,7 @@ class MipsArchitecture: public Architecture result.fullWidthRegister = REG_HI; break; default: + break; // if (REG_ZERO <= reg && reg < REG_GP) // result.size = 128 / 8; } diff --git a/arch/mips/il.cpp b/arch/mips/il.cpp index 87e1c03226..f8fc969055 100644 --- a/arch/mips/il.cpp +++ b/arch/mips/il.cpp @@ -188,34 +188,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) @@ -227,36 +233,36 @@ ExprId GetConditionForInstruction(LowLevelILFunction& il, Instruction& instr, si return il.Flag(instr.operands[0].reg); return il.Flag(FPCCREG_FCC0); 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: @@ -804,7 +810,14 @@ 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 registerSize = addrSize; + // std::function + auto signExtend = SignExtend; + bool saturate = false; + auto registerSize = [=](const InstructionOperand& op) -> size_t const + { + return get_register_width(Reg(op.reg), version); + }; BNEndianness endian = arch->GetEndianness(); switch (instr.operation) { @@ -813,111 +826,111 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu 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: 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, + 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, + 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))))); break; case MIPS_ANDI: - il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, - il.And(registerSize, - ReadILOperand(il, instr, 2, registerSize), + 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))))); break; case MIPS_DIV: - il.AddInstruction(il.SetRegister(4, REG_LO, - il.DivSigned(4, - ReadILOperand(il, instr, 1, registerSize, 4), - ReadILOperand(il, instr, 2, registerSize, 4)))); - il.AddInstruction(il.SetRegister(4, REG_HI, + il.AddInstruction(il.SetRegister(get_register_width(REG_LO, version), REG_LO, + il.DivSigned(registerSize(op1), + ReadILOperand(il, instr, 1, registerSize(op1), registerSize(op1)), + ReadILOperand(il, instr, 2, registerSize(op2), registerSize(op2))))); + 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); + ReadILOperand(il, instr, 1, registerSize(op1), registerSize(op1)), + ReadILOperand(il, instr, 2, registerSize(op2), registerSize(op2))))); + SignExtendHiLo(il, registerSize(op1)); break; case MIPS_DIVU: - il.AddInstruction(il.SetRegister(4, REG_LO, + il.AddInstruction(il.SetRegister(get_register_width(REG_LO, version), REG_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, registerSize(op1), 4), + ReadILOperand(il, instr, 2, registerSize(op2), 4)))); + il.AddInstruction(il.SetRegister(get_register_width(REG_HI, version), REG_HI, il.ModUnsigned(4, - ReadILOperand(il, instr, 1, registerSize, 4), - ReadILOperand(il, instr, 2, registerSize, 4)))); - SignExtendHiLo(il, registerSize); + ReadILOperand(il, instr, 1, registerSize(op1), 4), + ReadILOperand(il, instr, 2, registerSize(op2), 4)))); + 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))))); break; case MIPS_XORI: - il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, - il.Xor(registerSize, - ReadILOperand(il, instr, 2, registerSize), + 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(4, 0x0000ffff & op3.immediate))))); break; case MIPS_B: @@ -972,7 +985,7 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu 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 +1007,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 +1029,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 +1051,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 +1073,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,49 +1088,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, registerSize, registerSize, op1.reg, il.Register(registerSize, REG_HI1))); + 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, registerSize, registerSize, op1.reg, il.Register(registerSize, REG_LO1))); + 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(registerSize, REG_HI1, ReadILOperand(il, instr, 1, registerSize))); + 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(registerSize, REG_LO1, ReadILOperand(il, instr, 1, registerSize))); + 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)); @@ -1135,33 +1151,33 @@ 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)); + 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: @@ -1173,9 +1189,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]) @@ -1186,97 +1202,104 @@ 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_MULT: if (version == MIPS_R5900 && instr.numOperands == 3) { auto temp = LLIL_TEMP(0); il.AddInstruction(il.SetRegister(8, temp, il.MultDoublePrecSigned(4, - ReadILOperand(il, instr, 2, registerSize), - ReadILOperand(il, instr, 3, registerSize)))); - il.AddInstruction(il.SetRegister(registerSize, REG_HI, il.SignExtend(8, il.ArithShiftRight(8, il.Register(8, temp), il.Const(8, 32))))); - il.AddInstruction(il.SetRegister(registerSize, REG_LO, il.SignExtend(8, il.LowPart(4, il.Register(8, temp))))); + ReadILOperand(il, instr, 2, registerSize(op2), 4), + ReadILOperand(il, instr, 3, registerSize(op3), 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))))); // il.AddInstruction(il.SetRegisterSplit(4, REG_HI, REG_LO, // il.MultDoublePrecSigned(8, - // ReadILOperand(il, instr, 2, registerSize), - // ReadILOperand(il, instr, 3, registerSize)))); - SignExtendHiLo(il, registerSize); + // ReadILOperand(il, instr, 2, registerSize(op2)), + // ReadILOperand(il, instr, 3, registerSize(op3))))); + SignExtendHiLo(il, registerSize(op1)); auto rd = op1.reg; if (rd != REG_ZERO) - il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, rd, il.Register(registerSize, REG_LO))); + il.AddInstruction(SetRegisterOrNop(il, 4, registerSize(op1), rd, il.Register(get_register_width(REG_LO, version), REG_LO))); } // if (version == MIPS_R5900 && instr.numOperands == 3) { // il.AddInstruction(il.SetRegisterSplit(4, REG_HI, REG_LO, // il.MultDoublePrecSigned(8, - // ReadILOperand(il, instr, 2, registerSize), - // ReadILOperand(il, instr, 3, registerSize)))); - // SignExtendHiLo(il, registerSize); + // ReadILOperand(il, instr, 2, registerSize(op2)), + // ReadILOperand(il, instr, 3, registerSize(op3))))); + // SignExtendHiLo(il, registerSize(op1)); // auto rd = op1.reg; // if (rd != REG_ZERO) // il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, rd, il.Register(registerSize, REG_LO))); // } else { - il.AddInstruction(il.SetRegisterSplit(4, REG_HI, REG_LO, + il.AddInstruction(il.SetRegisterSplit(get_register_width(REG_HI, version), REG_HI, REG_LO, il.MultDoublePrecSigned(4, - ReadILOperand(il, instr, 1, registerSize), - ReadILOperand(il, instr, 2, registerSize)))); - SignExtendHiLo(il, registerSize); + ReadILOperand(il, instr, 1, registerSize(op1), 4), + ReadILOperand(il, instr, 2, registerSize(op2), 4)))); + SignExtendHiLo(il, registerSize(op1)); // TODO: registerSize??? } break; case MIPS_MULTU: if (version == MIPS_R5900 && instr.numOperands == 3) { il.AddInstruction(il.SetRegisterSplit(4, REG_HI, REG_LO, il.MultDoublePrecUnsigned(4, - ReadILOperand(il, instr, 2, registerSize), - ReadILOperand(il, instr, 3, registerSize)))); - SignExtendHiLo(il, registerSize); + ReadILOperand(il, instr, 2, registerSize(op2)), + ReadILOperand(il, instr, 3, registerSize(op3))))); + SignExtendHiLo(il, registerSize(op1)); auto rd = op1.reg; if (rd != REG_ZERO) - il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, rd, il.Register(registerSize, REG_LO))); + il.AddInstruction(SetRegisterOrNop(il, 4, 8, rd, il.Register(get_register_width(REG_LO, version), REG_LO))); } else { 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); + ReadILOperand(il, instr, 1, registerSize(op1)), + ReadILOperand(il, instr, 2, registerSize(op2))))); + SignExtendHiLo(il, registerSize(op1)); } 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)))); + 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: @@ -1306,12 +1329,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)) @@ -1323,7 +1346,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)) @@ -1334,7 +1357,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)) @@ -1346,7 +1369,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)) @@ -1363,21 +1386,21 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu 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: - il.AddInstruction(il.Store(16, GetILOperandMemoryAddress(il, op2, addrSize), ReadILOperand(il, instr, 1, registerSize))); + il.AddInstruction(il.Store(16, GetILOperandMemoryAddress(il, op2, addrSize), ReadILOperand(il, instr, 1, 16))); break; case MIPS_SCD: { @@ -1387,12 +1410,12 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu 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; @@ -1414,23 +1437,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) @@ -2058,10 +2147,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) @@ -2071,28 +2160,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: { @@ -2124,7 +2213,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) ) ) ); @@ -2136,30 +2225,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: @@ -2262,16 +2351,23 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu break; } case MIPS_PADDUB: + signExtend = ZeroExtend; + case MIPS_PADDSB: + saturate = true; + case MIPS_PADDB: { if (op3.reg == REG_ZERO) + { if (op2.reg == REG_ZERO) - il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Const(16, 0))); + 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))); + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, op2.reg), signExtend)); + } else if (op2.reg == REG_ZERO) - il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, op3.reg))); + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, op3.reg), signExtend)); else { + // il.AddInstruction(il.SetRegister(16, LLIL_TEMP(0), il.Register(16, op1.reg))); for (int i = 0; i < 16; i++) { size_t offset = i * 8; @@ -2279,27 +2375,54 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu il.LogicalShiftRight( 16, il.Register(16, op2.reg), - il.Const(4, offset) + il.Const(1, offset) ), - il.Const(128, 0xFFFFFFFF) + il.Const(128, 0xFF) ); auto rt_segment = il.And(16, il.LogicalShiftRight( 16, il.Register(16, op3.reg), - il.Const(4, offset) + il.Const(1, offset) ), - il.Const(128, 0xFFFFFFFF) + il.Const(128, 0xFF) ); - auto sum = il.Add(1, rs_segment, rt_segment); + auto sum = 0; - // This is a 1 byte add, but if the sum is greater than 0xFFFF, the result is 0xFFFF - // So we do an 8 bit add and and the result - - auto saturated_sum = il.And(1, sum, il.Const(1, 0xFF)); + // auto saturated_sum = sum; + if (saturate) + { + // This is a 1 byte add, but if the sum is greater than 0xFF, the result is 0xFF + // So we do an 2 byte add and bitwise-and the result + // saturated_sum = il.And(1, sum, il.Const(1, 0xFF)); + // saturated_sum = il.And(1, il.Register(1, LLIL_TEMP(0)), il.Const(1, 0xFF)); + il.AddInstruction(il.SetRegister(1, LLIL_TEMP(0), rs_segment)); + il.AddInstruction(SetRegisterOrNop(il, 2, 2, + LLIL_TEMP(1), + il.Add(2, + il.Register(1, LLIL_TEMP(0)), + rt_segment), signExtend)); + ExprId comparison = 0; + if (signExtend == ZeroExtend) + comparison = il.CompareUnsignedLessThan(1, + il.Register(1, LLIL_TEMP(1)), + il.Register(1, LLIL_TEMP(0))); + else + { + // TODO! + } + sum = il.Or(1, + il.Register(1, LLIL_TEMP(0)), + il.Neg(1, + il.BoolToInt(1, + comparison))); + // padd\w* \$\w*, \$[^z]+, \$[^z]+ + } + else + sum = il.And(1, il.Add(2, rs_segment, rt_segment), il.Const(1, 0xFF)); - auto shifted_sum = il.ShiftLeft(16, saturated_sum, il.Const(4, offset)); + auto shifted_sum = il.ShiftLeft(16, sum, il.Const(1, offset)); if (i == 0) { il.AddInstruction(il.SetRegister(16, op1.reg, shifted_sum)); @@ -2312,45 +2435,129 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu } break; - } case MIPS_PADDUH: + } + // case MIPS_PADDUH: + // { + // if (op3.reg == REG_ZERO) + // if (op2.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, op2.reg))); + // else if (op2.reg == REG_ZERO) + // il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, op3.reg))); + // else + // { + // for (int i = 0; i < 8; i++) + // { + // size_t offset = i * 16; + // auto rs_segment = il.And(16, + // il.LogicalShiftRight( + // 16, + // il.Register(16, op2.reg), + // il.Const(4, offset) + // ), + // il.Const(128, 0xFFFFFFFF) + // ); + // auto rt_segment = il.And(16, + // il.LogicalShiftRight( + // 16, + // il.Register(16, op3.reg), + // il.Const(4, offset) + // ), + // il.Const(128, 0xFFFFFFFF) + // ); + // + // auto sum = il.Add(2, rs_segment, rt_segment); + // + // // This is a 2 byte add, but if the sum is greater than 0xFFFF, the result is 0xFFFF + // // So we do an 8 bit add and and the result + // + // auto saturated_sum = il.And(2, sum, il.Const(2, 0xFFFF)); + // + // auto shifted_sum = il.ShiftLeft(16, saturated_sum, il.Const(4, offset)); + // 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))); + // } + // } + // } + // + // break; + // } + case MIPS_PADDUH: + signExtend = ZeroExtend; + case MIPS_PADDSH: + saturate = true; + case MIPS_PADDH: { + const uint64_t bytes = 2; + uint64_t mask = 0xFFFFFFFFFFFFFFFF >> (64 - (8 * bytes)); if (op3.reg == REG_ZERO) + { if (op2.reg == REG_ZERO) - il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Const(16, 0))); + 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))); + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, op2.reg), signExtend)); + } else if (op2.reg == REG_ZERO) - il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, op3.reg))); + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, op3.reg), signExtend)); else { - for (int i = 0; i < 8; i++) + // il.AddInstruction(il.SetRegister(16, LLIL_TEMP(0), il.Register(16, op1.reg))); + for (int i = 0; i < 16 / bytes; i++) { - size_t offset = i * 16; - auto rs_segment = il.And(16, - il.LogicalShiftRight( - 16, - il.Register(16, op2.reg), - il.Const(4, offset) - ), - il.Const(128, 0xFFFFFFFF) - ); - auto rt_segment = il.And(16, - il.LogicalShiftRight( - 16, - il.Register(16, op3.reg), - il.Const(4, offset) - ), - il.Const(128, 0xFFFFFFFF) - ); - - auto sum = il.Add(2, rs_segment, rt_segment); + size_t offset = i * 8 * bytes; + auto rs_shift = il.Register(16, op2.reg); + auto rt_shift = il.Register(16, op3.reg); + if (i > 0) + { + rs_shift = il.LogicalShiftRight( 16, il.Register(16, op2.reg), il.Const(1, offset)); + rt_shift = il.LogicalShiftRight( 16, il.Register(16, op3.reg), il.Const(1, offset)); + } + auto rs_segment = il.And(16, rs_shift, il.Const(128, mask)); + auto rt_segment = il.And(16, rt_shift, il.Const(128, mask)); - // This is a 2 byte add, but if the sum is greater than 0xFFFF, the result is 0xFFFF - // So we do an 8 bit add and and the result + auto sum = 0; - auto saturated_sum = il.And(2, sum, il.Const(2, 0xFFFF)); + // auto saturated_sum = sum; + if (saturate) + { + // This is a 1 byte add, but if the sum is greater than 0xFF, the result is 0xFF + // So we do an 2 byte add and bitwise-and the result + // saturated_sum = il.And(1, sum, il.Const(1, 0xFF)); + // saturated_sum = il.And(1, il.Register(1, LLIL_TEMP(0)), il.Const(1, 0xFF)); + il.AddInstruction(il.SetRegister(bytes, LLIL_TEMP(0), rs_segment)); + il.AddInstruction(SetRegisterOrNop(il, 2 * bytes, 2 * bytes, + LLIL_TEMP(1), + il.Add(2 * bytes, + il.Register(bytes, LLIL_TEMP(0)), + rt_segment), signExtend)); + ExprId comparison = 0; + if (signExtend == ZeroExtend) + { + 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(0)), + il.Neg(bytes, + il.BoolToInt(bytes, + comparison))); + } + else + { + // TODO! + } + // padd\w* \$\w*, \$[^z]+, \$[^z]+ + } + else + sum = il.And(bytes, il.Add(bytes, rs_segment, rt_segment), il.Const(1, mask)); - auto shifted_sum = il.ShiftLeft(16, saturated_sum, il.Const(4, offset)); + auto shifted_sum = i == 0 ? sum : il.ShiftLeft(16, sum, il.Const(1, offset)); if (i == 0) { il.AddInstruction(il.SetRegister(16, op1.reg, shifted_sum)); @@ -2365,44 +2572,92 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu break; } case MIPS_PADDUW: + signExtend = ZeroExtend; + case MIPS_PADDSW: + saturate = true; + case MIPS_PADDW: { + size_t bytes = 4; + uint64_t mask = 0xFFFFFFFFFFFFFFFF >> (64 - (8 * bytes)); if (op3.reg == REG_ZERO) + { if (op2.reg == REG_ZERO) - il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Const(16, 0))); + 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))); + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, op2.reg), signExtend)); + } else if (op2.reg == REG_ZERO) - il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, op3.reg))); + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, op3.reg), signExtend)); else { - for (int i = 0; i < 4; i++) + // il.AddInstruction(il.SetRegister(16, LLIL_TEMP(0), il.Register(16, op1.reg))); + for (int i = 0; i < 16 / bytes; i++) { - size_t offset = i * 32; - auto rs_segment = il.And(16, - il.LogicalShiftRight( - 16, - il.Register(16, op2.reg), - il.Const(4, offset) - ), - il.Const(128, 0xFFFFFFFF) - ); - auto rt_segment = il.And(16, - il.LogicalShiftRight( - 16, - il.Register(16, op3.reg), - il.Const(4, offset) - ), - il.Const(128, 0xFFFFFFFF) - ); - - auto sum = il.Add(4, rs_segment, rt_segment); + // size_t offset = i * 8 * bytes; + // auto rs_segment = il.And(16, + // il.LogicalShiftRight( + // 16, + // il.Register(16, op2.reg), + // il.Const(1, offset) + // ), + // il.Const(128, mask) + // ); + // auto rt_segment = il.And(16, + // il.LogicalShiftRight( + // 16, + // il.Register(16, op3.reg), + // il.Const(1, offset) + // ), + // il.Const(128, mask) + // ); + size_t offset = i * 8 * bytes; + auto rs_shift = il.Register(16, op2.reg); + auto rt_shift = il.Register(16, op3.reg); + if (i > 0) + { + rs_shift = il.LogicalShiftRight( 16, il.Register(16, op2.reg), il.Const(1, offset)); + rt_shift = il.LogicalShiftRight( 16, il.Register(16, op3.reg), il.Const(1, offset)); + } + auto rs_segment = il.And(16, rs_shift, il.Const(128, mask)); + auto rt_segment = il.And(16, rt_shift, il.Const(128, mask)); - // This is a 4 byte add, but if the sum is greater than 0xFFFFFFFF, the result is 0xFFFFFFFF - // So we do an 8 bit add and and the result + auto sum = 0; - auto saturated_sum = il.And(4, sum, il.Const(4, 0xFFFFFFFF)); + // auto saturated_sum = sum; + if (saturate) + { + // This is a 1 byte add, but if the sum is greater than 0xFF, the result is 0xFF + // So we do an 2 byte add and bitwise-and the result + // saturated_sum = il.And(1, sum, il.Const(1, 0xFF)); + // saturated_sum = il.And(1, il.Register(1, LLIL_TEMP(0)), il.Const(1, 0xFF)); + il.AddInstruction(il.SetRegister(bytes, LLIL_TEMP(0), rs_segment)); + il.AddInstruction(SetRegisterOrNop(il, 2 * bytes, 2 * bytes, + LLIL_TEMP(1), + il.Add(2 * bytes, + il.Register(bytes, LLIL_TEMP(0)), + rt_segment), signExtend)); + ExprId comparison = 0; + if (signExtend == ZeroExtend) + { + 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(0)), + il.Neg(bytes, + il.BoolToInt(1, + comparison))); + } + else + { + // TODO! + } + // padd\w* \$\w*, \$[^z]+, \$[^z]+ + } + else + sum = il.And(bytes, il.Add(bytes, rs_segment, rt_segment), il.Const(1, mask)); - auto shifted_sum = il.ShiftLeft(16, saturated_sum, il.Const(4, offset)); + auto shifted_sum = i == 0 ? sum : il.ShiftLeft(16, sum, il.Const(1, offset)); if (i == 0) { il.AddInstruction(il.SetRegister(16, op1.reg, shifted_sum)); @@ -2416,6 +2671,58 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu break; } + // case MIPS_PADDUW: + // { + // if (op3.reg == REG_ZERO) + // if (op2.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, op2.reg))); + // else if (op2.reg == REG_ZERO) + // il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, op3.reg))); + // else + // { + // for (int i = 0; i < 4; i++) + // { + // size_t offset = i * 32; + // auto rs_segment = il.And(16, + // il.LogicalShiftRight( + // 16, + // il.Register(16, op2.reg), + // il.Const(4, offset) + // ), + // il.Const(128, 0xFFFFFFFF) + // ); + // auto rt_segment = il.And(16, + // il.LogicalShiftRight( + // 16, + // il.Register(16, op3.reg), + // il.Const(4, offset) + // ), + // il.Const(128, 0xFFFFFFFF) + // ); + // + // auto sum = il.Add(4, rs_segment, rt_segment); + // + // // This is a 4 byte add, but if the sum is greater than 0xFFFFFFFF, the result is 0xFFFFFFFF + // // So we do an 8 bit add and and the result + // + // auto saturated_sum = il.And(4, sum, il.Const(4, 0xFFFFFFFF)); + // + // auto shifted_sum = il.ShiftLeft(16, saturated_sum, il.Const(4, offset)); + // 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))); + // } + // } + // } + // + // break; + // } case MIPS_ADDR: case MIPS_LDXC1: @@ -2522,26 +2829,26 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu case MIPS_PSLLW: case MIPS_PSRLW: case MIPS_PSRAW: - case MIPS_PADDW: + // case MIPS_PADDW: case MIPS_PSUBW: case MIPS_PCGTW: case MIPS_PMAXW: - case MIPS_PADDH: + // case MIPS_PADDH: case MIPS_PSUBH: case MIPS_PCGTH: case MIPS_PMAXH: - case MIPS_PADDB: + // case MIPS_PADDB: case MIPS_PSUBB: case MIPS_PCGTB: - case MIPS_PADDSW: + // case MIPS_PADDSW: case MIPS_PSUBSW: case MIPS_PEXTLW: case MIPS_PPACW: - case MIPS_PADDSH: + // case MIPS_PADDSH: case MIPS_PSUBSH: case MIPS_PEXTLH: case MIPS_PPACH: - case MIPS_PADDSB: + // case MIPS_PADDSB: case MIPS_PSUBSB: case MIPS_PEXTLB: case MIPS_PPACB: diff --git a/arch/mips/il.h b/arch/mips/il.h index 6babadc15e..5ed63ce3af 100644 --- a/arch/mips/il.h +++ b/arch/mips/il.h @@ -91,4 +91,50 @@ bool GetLowLevelILForInstruction( uint32_t decomposeFlags, mips::MipsVersion version); -BinaryNinja::ExprId GetConditionForInstruction(BinaryNinja::LowLevelILFunction& il, mips::Instruction& instr, size_t registerSize); +BinaryNinja::ExprId GetConditionForInstruction(BinaryNinja::LowLevelILFunction& il, mips::Instruction& instr, std::function registerSize); +#ifdef __cplusplus +extern "C" { + namespace mips { +#endif + +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 = 64; + break; + case REG_LO1: + case REG_HI1: + width = 128; + break; + default: + if (REG_ZERO <= reg && reg < REG_GP) + width = 128; // 64; // 128 + else if (FPREG_F0 <= reg && reg <= FPREG_F31) + width = 64; + } + 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.h b/arch/mips/mips/mips.h index f8da11d3ee..0e07095ef9 100644 --- a/arch/mips/mips/mips.h +++ b/arch/mips/mips/mips.h @@ -1377,40 +1377,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 -static inline const size_t get_register_width(Reg reg, MipsVersion version) { - 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 = 64; - break; - case REG_LO1: - case REG_HI1: - width = 128; - break; - default: - if (REG_ZERO <= reg && reg < REG_GP) - width = 128; - } - } - return width / 8; -} \ No newline at end of file From 783ad4ad29989aed09e8017ade87ef74e36b187b Mon Sep 17 00:00:00 2001 From: Galen Williamson Date: Mon, 17 Feb 2025 18:25:01 -0500 Subject: [PATCH 08/16] WIP [mips] Fixing PR for r5900: lifting all variants of PADD* and PSUB* --- arch/mips/il.cpp | 604 +++++++++++++++++++---------------------------- 1 file changed, 239 insertions(+), 365 deletions(-) diff --git a/arch/mips/il.cpp b/arch/mips/il.cpp index f8fc969055..7d42f06b35 100644 --- a/arch/mips/il.cpp +++ b/arch/mips/il.cpp @@ -61,6 +61,199 @@ 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 comparison1 = 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 comparison2 = 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(comparison1, 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(comparison2, 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)); + + } + // padd\w* \$\w*, \$[^z]+, \$[^z]+ + } + + 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 size_t GetILOperandMemoryAddress(LowLevelILFunction& il, InstructionOperand& operand, size_t addrSize, int32_t delta=0) { @@ -812,7 +1005,7 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu LowLevelILLabel trueCode, falseCode, again; // size_t registerSize = addrSize; // std::function - auto signExtend = SignExtend; + bool signedFlag = false; bool saturate = false; auto registerSize = [=](const InstructionOperand& op) -> size_t const { @@ -2350,379 +2543,60 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu break; } - case MIPS_PADDUB: - signExtend = ZeroExtend; case MIPS_PADDSB: + signedFlag = true; + case MIPS_PADDUB: saturate = true; case MIPS_PADDB: { - if (op3.reg == REG_ZERO) - { - 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)); - } - else if (op2.reg == REG_ZERO) - il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, op3.reg), signExtend)); - else - { - // il.AddInstruction(il.SetRegister(16, LLIL_TEMP(0), il.Register(16, op1.reg))); - for (int i = 0; i < 16; i++) - { - size_t offset = i * 8; - auto rs_segment = il.And(16, - il.LogicalShiftRight( - 16, - il.Register(16, op2.reg), - il.Const(1, offset) - ), - il.Const(128, 0xFF) - ); - auto rt_segment = il.And(16, - il.LogicalShiftRight( - 16, - il.Register(16, op3.reg), - il.Const(1, offset) - ), - il.Const(128, 0xFF) - ); - - auto sum = 0; - - // auto saturated_sum = sum; - if (saturate) - { - // This is a 1 byte add, but if the sum is greater than 0xFF, the result is 0xFF - // So we do an 2 byte add and bitwise-and the result - // saturated_sum = il.And(1, sum, il.Const(1, 0xFF)); - // saturated_sum = il.And(1, il.Register(1, LLIL_TEMP(0)), il.Const(1, 0xFF)); - il.AddInstruction(il.SetRegister(1, LLIL_TEMP(0), rs_segment)); - il.AddInstruction(SetRegisterOrNop(il, 2, 2, - LLIL_TEMP(1), - il.Add(2, - il.Register(1, LLIL_TEMP(0)), - rt_segment), signExtend)); - ExprId comparison = 0; - if (signExtend == ZeroExtend) - comparison = il.CompareUnsignedLessThan(1, - il.Register(1, LLIL_TEMP(1)), - il.Register(1, LLIL_TEMP(0))); - else - { - // TODO! - } - sum = il.Or(1, - il.Register(1, LLIL_TEMP(0)), - il.Neg(1, - il.BoolToInt(1, - comparison))); - // padd\w* \$\w*, \$[^z]+, \$[^z]+ - } - else - sum = il.And(1, il.Add(2, rs_segment, rt_segment), il.Const(1, 0xFF)); - - auto shifted_sum = il.ShiftLeft(16, sum, il.Const(1, offset)); - 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))); - } - } - } - + SaturatingAddSub(il, instr, saturate, signedFlag, 1); break; } - // case MIPS_PADDUH: - // { - // if (op3.reg == REG_ZERO) - // if (op2.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, op2.reg))); - // else if (op2.reg == REG_ZERO) - // il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, op3.reg))); - // else - // { - // for (int i = 0; i < 8; i++) - // { - // size_t offset = i * 16; - // auto rs_segment = il.And(16, - // il.LogicalShiftRight( - // 16, - // il.Register(16, op2.reg), - // il.Const(4, offset) - // ), - // il.Const(128, 0xFFFFFFFF) - // ); - // auto rt_segment = il.And(16, - // il.LogicalShiftRight( - // 16, - // il.Register(16, op3.reg), - // il.Const(4, offset) - // ), - // il.Const(128, 0xFFFFFFFF) - // ); - // - // auto sum = il.Add(2, rs_segment, rt_segment); - // - // // This is a 2 byte add, but if the sum is greater than 0xFFFF, the result is 0xFFFF - // // So we do an 8 bit add and and the result - // - // auto saturated_sum = il.And(2, sum, il.Const(2, 0xFFFF)); - // - // auto shifted_sum = il.ShiftLeft(16, saturated_sum, il.Const(4, offset)); - // 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))); - // } - // } - // } - // - // break; - // } - case MIPS_PADDUH: - signExtend = ZeroExtend; case MIPS_PADDSH: + signedFlag = true; + case MIPS_PADDUH: saturate = true; case MIPS_PADDH: { - const uint64_t bytes = 2; - uint64_t mask = 0xFFFFFFFFFFFFFFFF >> (64 - (8 * bytes)); - if (op3.reg == REG_ZERO) - { - 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)); - } - else if (op2.reg == REG_ZERO) - il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, op3.reg), signExtend)); - else - { - // il.AddInstruction(il.SetRegister(16, LLIL_TEMP(0), il.Register(16, op1.reg))); - for (int i = 0; i < 16 / bytes; i++) - { - size_t offset = i * 8 * bytes; - auto rs_shift = il.Register(16, op2.reg); - auto rt_shift = il.Register(16, op3.reg); - if (i > 0) - { - rs_shift = il.LogicalShiftRight( 16, il.Register(16, op2.reg), il.Const(1, offset)); - rt_shift = il.LogicalShiftRight( 16, il.Register(16, op3.reg), il.Const(1, offset)); - } - auto rs_segment = il.And(16, rs_shift, il.Const(128, mask)); - auto rt_segment = il.And(16, rt_shift, il.Const(128, mask)); - - auto sum = 0; - - // auto saturated_sum = sum; - if (saturate) - { - // This is a 1 byte add, but if the sum is greater than 0xFF, the result is 0xFF - // So we do an 2 byte add and bitwise-and the result - // saturated_sum = il.And(1, sum, il.Const(1, 0xFF)); - // saturated_sum = il.And(1, il.Register(1, LLIL_TEMP(0)), il.Const(1, 0xFF)); - il.AddInstruction(il.SetRegister(bytes, LLIL_TEMP(0), rs_segment)); - il.AddInstruction(SetRegisterOrNop(il, 2 * bytes, 2 * bytes, - LLIL_TEMP(1), - il.Add(2 * bytes, - il.Register(bytes, LLIL_TEMP(0)), - rt_segment), signExtend)); - ExprId comparison = 0; - if (signExtend == ZeroExtend) - { - 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(0)), - il.Neg(bytes, - il.BoolToInt(bytes, - comparison))); - } - else - { - // TODO! - } - // padd\w* \$\w*, \$[^z]+, \$[^z]+ - } - else - sum = il.And(bytes, il.Add(bytes, rs_segment, rt_segment), il.Const(1, mask)); - - auto shifted_sum = i == 0 ? sum : il.ShiftLeft(16, sum, il.Const(1, offset)); - 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))); - } - } - } - + SaturatingAddSub(il, instr, saturate, signedFlag, 2); break; } - case MIPS_PADDUW: - signExtend = ZeroExtend; case MIPS_PADDSW: + signedFlag = true; + case MIPS_PADDUW: saturate = true; case MIPS_PADDW: { - size_t bytes = 4; - uint64_t mask = 0xFFFFFFFFFFFFFFFF >> (64 - (8 * bytes)); - if (op3.reg == REG_ZERO) - { - 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)); - } - else if (op2.reg == REG_ZERO) - il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, op3.reg), signExtend)); - else - { - // il.AddInstruction(il.SetRegister(16, LLIL_TEMP(0), il.Register(16, op1.reg))); - for (int i = 0; i < 16 / bytes; i++) - { - // size_t offset = i * 8 * bytes; - // auto rs_segment = il.And(16, - // il.LogicalShiftRight( - // 16, - // il.Register(16, op2.reg), - // il.Const(1, offset) - // ), - // il.Const(128, mask) - // ); - // auto rt_segment = il.And(16, - // il.LogicalShiftRight( - // 16, - // il.Register(16, op3.reg), - // il.Const(1, offset) - // ), - // il.Const(128, mask) - // ); - size_t offset = i * 8 * bytes; - auto rs_shift = il.Register(16, op2.reg); - auto rt_shift = il.Register(16, op3.reg); - if (i > 0) - { - rs_shift = il.LogicalShiftRight( 16, il.Register(16, op2.reg), il.Const(1, offset)); - rt_shift = il.LogicalShiftRight( 16, il.Register(16, op3.reg), il.Const(1, offset)); - } - auto rs_segment = il.And(16, rs_shift, il.Const(128, mask)); - auto rt_segment = il.And(16, rt_shift, il.Const(128, mask)); - - auto sum = 0; - - // auto saturated_sum = sum; - if (saturate) - { - // This is a 1 byte add, but if the sum is greater than 0xFF, the result is 0xFF - // So we do an 2 byte add and bitwise-and the result - // saturated_sum = il.And(1, sum, il.Const(1, 0xFF)); - // saturated_sum = il.And(1, il.Register(1, LLIL_TEMP(0)), il.Const(1, 0xFF)); - il.AddInstruction(il.SetRegister(bytes, LLIL_TEMP(0), rs_segment)); - il.AddInstruction(SetRegisterOrNop(il, 2 * bytes, 2 * bytes, - LLIL_TEMP(1), - il.Add(2 * bytes, - il.Register(bytes, LLIL_TEMP(0)), - rt_segment), signExtend)); - ExprId comparison = 0; - if (signExtend == ZeroExtend) - { - 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(0)), - il.Neg(bytes, - il.BoolToInt(1, - comparison))); - } - else - { - // TODO! - } - // padd\w* \$\w*, \$[^z]+, \$[^z]+ - } - else - sum = il.And(bytes, il.Add(bytes, rs_segment, rt_segment), il.Const(1, mask)); - - auto shifted_sum = i == 0 ? sum : il.ShiftLeft(16, sum, il.Const(1, offset)); - 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))); - } - } - } - + 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_PADDUW: - // { - // if (op3.reg == REG_ZERO) - // if (op2.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, op2.reg))); - // else if (op2.reg == REG_ZERO) - // il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, op3.reg))); - // else - // { - // for (int i = 0; i < 4; i++) - // { - // size_t offset = i * 32; - // auto rs_segment = il.And(16, - // il.LogicalShiftRight( - // 16, - // il.Register(16, op2.reg), - // il.Const(4, offset) - // ), - // il.Const(128, 0xFFFFFFFF) - // ); - // auto rt_segment = il.And(16, - // il.LogicalShiftRight( - // 16, - // il.Register(16, op3.reg), - // il.Const(4, offset) - // ), - // il.Const(128, 0xFFFFFFFF) - // ); - // - // auto sum = il.Add(4, rs_segment, rt_segment); - // - // // This is a 4 byte add, but if the sum is greater than 0xFFFFFFFF, the result is 0xFFFFFFFF - // // So we do an 8 bit add and and the result - // - // auto saturated_sum = il.And(4, sum, il.Const(4, 0xFFFFFFFF)); - // - // auto shifted_sum = il.ShiftLeft(16, saturated_sum, il.Const(4, offset)); - // 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))); - // } - // } - // } - // - // break; - // } case MIPS_ADDR: case MIPS_LDXC1: @@ -2830,26 +2704,26 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu case MIPS_PSRLW: case MIPS_PSRAW: // case MIPS_PADDW: - case MIPS_PSUBW: + // case MIPS_PSUBW: case MIPS_PCGTW: case MIPS_PMAXW: // case MIPS_PADDH: - case MIPS_PSUBH: + // case MIPS_PSUBH: case MIPS_PCGTH: case MIPS_PMAXH: // case MIPS_PADDB: - case MIPS_PSUBB: + // case MIPS_PSUBB: case MIPS_PCGTB: // case MIPS_PADDSW: - case MIPS_PSUBSW: + // case MIPS_PSUBSW: case MIPS_PEXTLW: case MIPS_PPACW: // case MIPS_PADDSH: - case MIPS_PSUBSH: + // case MIPS_PSUBSH: case MIPS_PEXTLH: case MIPS_PPACH: // case MIPS_PADDSB: - case MIPS_PSUBSB: + // case MIPS_PSUBSB: case MIPS_PEXTLB: case MIPS_PPACB: case MIPS_PEXT5: @@ -2863,13 +2737,13 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu case MIPS_PMINH: case MIPS_PCEQB: // case MIPS_PADDUW: - case MIPS_PSUBUW: + // case MIPS_PSUBUW: case MIPS_PEXTUW: // case MIPS_PADDUH: - case MIPS_PSUBUH: + // case MIPS_PSUBUH: case MIPS_PEXTUH: // case MIPS_PADDUB: - case MIPS_PSUBUB: + // case MIPS_PSUBUB: case MIPS_PEXTUB: case MIPS_QFSRV: case MIPS_PMADDW: From 190ad6df8f777b2ee8af0fe85d795dfb547fe27c Mon Sep 17 00:00:00 2001 From: Galen Williamson Date: Mon, 3 Mar 2025 15:56:41 -0500 Subject: [PATCH 09/16] WIP [mips] Fixing PR for r5900: lots more lifting --- arch/mips/arch_mips.cpp | 245 ++++- arch/mips/il.cpp | 2022 +++++++++++++++++++++++++++++++++------ arch/mips/il.h | 45 +- arch/mips/mips/mips.c | 712 +++++++++++++- arch/mips/mips/mips.h | 109 ++- 5 files changed, 2798 insertions(+), 335 deletions(-) diff --git a/arch/mips/arch_mips.cpp b/arch/mips/arch_mips.cpp index b87d69a45c..d1836a8324 100644 --- a/arch/mips/arch_mips.cpp +++ b/arch/mips/arch_mips.cpp @@ -743,7 +743,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; } @@ -781,17 +782,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) @@ -803,15 +825,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) @@ -858,18 +882,15 @@ class MipsArchitecture: public Architecture break; case MEM_IMM: result.emplace_back(BeginMemoryOperandToken, ""); - if (imm != 0) - { - if (imm < -9) - snprintf(operand, sizeof(operand), "-%#x", -imm); - else if (imm < 0) - snprintf(operand, sizeof(operand), "-%d", -imm); - else if (imm < 10) - snprintf(operand, sizeof(operand), "%d", imm); - else - snprintf(operand, sizeof(operand), "%#x", imm); - result.emplace_back(IntegerToken, operand, imm); - } + if (imm < -9) + snprintf(operand, sizeof(operand), "-%#x", -imm); + else if (imm < 0) + snprintf(operand, sizeof(operand), "-%d", -imm); + else if (imm < 10) + snprintf(operand, sizeof(operand), "%d", imm); + else + snprintf(operand, sizeof(operand), "%#x", imm); + result.emplace_back(IntegerToken, operand, imm); if (instr.operands[i].reg == REG_ZERO) break; result.emplace_back(BraceToken, "("); @@ -895,6 +916,102 @@ 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) + { + if (instr.operands[i].reg >= REG_VI0 && instr.operands[i].reg <= REG_VI15) + { + char reg_tmp[sizeof(operand)] = {0}; + switch (instr.operation) + { + 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; + } + } + 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; @@ -1016,6 +1133,9 @@ class MipsArchitecture: public Architecture return "_countOnes32"; case CNMIPS_INTRIN_DPOP: return "_countOnes64"; + + case MIPS_INTRIN_R5900_VWAITQ: + return "__vwaitq"; default: return ""; } @@ -1023,7 +1143,7 @@ class MipsArchitecture: public Architecture virtual vector GetAllIntrinsics() override { - return vector{ + auto intrinsics = vector{ MIPS_INTRIN_WSBH, MIPS_INTRIN_DSBH, MIPS_INTRIN_DSHD, @@ -1075,6 +1195,14 @@ class MipsArchitecture: public Architecture CNMIPS_INTRIN_POP, CNMIPS_INTRIN_DPOP, }; + if (m_version == MIPS_R5900) + { + auto r5900_intrinsics = { + MIPS_INTRIN_R5900_VWAITQ, + }; + intrinsics.insert(intrinsics.end(), std::begin(r5900_intrinsics), std::end(r5900_intrinsics)); + } + return intrinsics; } virtual vector GetIntrinsicInputs(uint32_t intrinsic) override @@ -1231,6 +1359,8 @@ class MipsArchitecture: public Architecture return { NameAndType("index", Type::IntegerType(8, false)), }; + + case MIPS_INTRIN_R5900_VWAITQ: default: return vector(); } @@ -1287,6 +1417,7 @@ class MipsArchitecture: public Architecture }; case MIPS_INTRIN_TLBSEARCH: return { Type::IntegerType(8, false) }; + case MIPS_INTRIN_R5900_VWAITQ: default: return vector>>(); } @@ -1577,7 +1708,27 @@ class MipsArchitecture: public Architecture 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[] = { REG_LO1, REG_HI1 }; + 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) @@ -1899,8 +2050,36 @@ class MipsArchitecture: public Architecture }; if (m_version == MIPS_R5900) { - uint32_t r5900_registers[] = { REG_LO1, REG_HI1 }; + // 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) { @@ -2122,15 +2301,33 @@ class MipsArchitecture: public Architecture 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: - break; - // if (REG_ZERO <= reg && reg < REG_GP) - // result.size = 128 / 8; + 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; diff --git a/arch/mips/il.cpp b/arch/mips/il.cpp index 7d42f06b35..e5ce140188 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; @@ -100,53 +102,53 @@ static void SaturatingAddSub(LowLevelILFunction& il, Instruction& instr, bool sa 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); + 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)); - } + 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) + { + 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 + // 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, @@ -156,37 +158,37 @@ static void SaturatingAddSub(LowLevelILFunction& il, Instruction& instr, bool sa add_sub = il.Sub(2 * bytes, rs_shifted, rt_shifted); - il.AddInstruction(il.SetRegister(2 * bytes, - LLIL_TEMP(1), + il.AddInstruction(il.SetRegister(2 * bytes, + LLIL_TEMP(1), add_sub)); - if (!signedFlag) - { - if (!subtract) - { - ExprId comparison = il.CompareUnsignedLessThan(bytes, + 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, + sum = il.Or(bytes, il.Register(bytes, LLIL_TEMP(1)), il.Neg(bytes, il.BoolToInt(bytes, comparison))); - } - else - { - ExprId comparison = il.CompareUnsignedLessEqual(bytes, + } + else + { + ExprId comparison = il.CompareUnsignedLessEqual(bytes, il.Register(bytes, LLIL_TEMP(1)), il.Register(bytes, LLIL_TEMP(0))); - sum = il.And(bytes, + sum = il.And(bytes, il.Register(bytes, LLIL_TEMP(1)), il.Neg(bytes, il.BoolToInt(bytes, comparison))); - } - } - else - { + } + } + 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 @@ -199,59 +201,161 @@ static void SaturatingAddSub(LowLevelILFunction& il, Instruction& instr, bool sa // 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; + 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. + // 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 comparison1 = il.And(1, - il.CompareSignedGreaterThan(2 * bytes, + 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.CompareSignedLessThan(bytes, il.Register(2 * bytes, LLIL_TEMP(1)), il.Const(2 * bytes, clamp_under_upper_bound))); - auto comparison2 = il.CompareSignedGreaterThan(bytes, + 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(comparison1, trueCase1, falseCase1)); + 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(trueCase1); - il.AddInstruction(il.SetRegister(bytes, LLIL_TEMP(1), il.Const(bytes, clamp_underflow))); - il.AddInstruction(il.Goto(done)); + il.MarkLabel(trueCase2); + il.AddInstruction(il.SetRegister(bytes, LLIL_TEMP(1), il.Const(bytes, clamp_overflow))); - il.MarkLabel(falseCase1); - il.AddInstruction(il.If(comparison2, trueCase2, done)); + 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))); + } + } + } +} - il.MarkLabel(trueCase2); - il.AddInstruction(il.SetRegister(bytes, LLIL_TEMP(1), il.Const(bytes, clamp_overflow))); +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 - il.MarkLabel(done); + // 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)); - sum = il.Register(bytes, LLIL_TEMP(1)); + // 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); - } - // padd\w* \$\w*, \$[^z]+, \$[^z]+ - } + // 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)); + } - 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))); - } - } + // 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)))); } } @@ -995,6 +1099,15 @@ static void SignExtendHiLo(LowLevelILFunction& il, size_t registerSize) } } +#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; @@ -1003,21 +1116,39 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu InstructionOperand& op3 = instr.operands[2]; InstructionOperand& op4 = instr.operands[3]; LowLevelILLabel trueCode, falseCode, again; + 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), op1.reg, ReadILOperand(il, instr, 3, registerSize(op3), 4))); else @@ -1027,10 +1158,10 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu 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), op1.reg, ReadILOperand(il, instr, 3, registerSize(op3)))); else @@ -1040,15 +1171,15 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu ReadILOperand(il, instr, 2, registerSize(op2)), ReadILOperand(il, instr, 3, registerSize(op3))))); break; - case MIPS_SUB: case MIPS_SUBU: + case MIPS_SUB: il.AddInstruction(SetRegisterOrNop(il, 4, registerSize(op1), op1.reg, il.Sub(4, ReadILOperand(il, instr, 2, registerSize(op2), 4), ReadILOperand(il, instr, 3, registerSize(op3), 4)))); break; - case MIPS_DSUB: case MIPS_DSUBU: + case MIPS_DSUB: il.AddInstruction(SetRegisterOrNop(il, 8, registerSize(op1), op1.reg, il.Sub(8, ReadILOperand(il, instr, 2, registerSize(op2), 8), @@ -1058,36 +1189,53 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu 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))))); + ReadILOperand(il, instr, 3, registerSize(op3))), ZeroExtend)); break; case MIPS_ANDI: 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))))); + il.Operand(1, il.Const(4, 0x0000ffff & op3.immediate))), ZeroExtend)); break; case MIPS_DIV: il.AddInstruction(il.SetRegister(get_register_width(REG_LO, version), REG_LO, - il.DivSigned(registerSize(op1), - ReadILOperand(il, instr, 1, registerSize(op1), registerSize(op1)), - ReadILOperand(il, instr, 2, registerSize(op2), registerSize(op2))))); + il.DivSigned(4, + 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(op1), registerSize(op1)), - ReadILOperand(il, instr, 2, registerSize(op2), registerSize(op2))))); - SignExtendHiLo(il, registerSize(op1)); + 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(get_register_width(REG_LO, version), REG_LO, + { + DEFINE_HILO1(MIPS_DIVU1); + il.AddInstruction(il.SetRegister(get_register_width(lo, version), lo, il.DivUnsigned(4, - ReadILOperand(il, instr, 1, registerSize(op1), 4), - ReadILOperand(il, instr, 2, registerSize(op2), 4)))); - il.AddInstruction(il.SetRegister(get_register_width(REG_HI, version), 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(op1), 4), - ReadILOperand(il, instr, 2, registerSize(op2), 4)))); - SignExtendHiLo(il, registerSize(op1)); + 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(get_register_width(REG_LO, version), REG_LO, il.DivSigned(8, @@ -1118,13 +1266,13 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu 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))))); + ReadILOperand(il, instr, 3, registerSize(op3))), ZeroExtend)); break; case MIPS_XORI: 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(4, 0x0000ffff & op3.immediate))))); + il.Operand(1,il.Const(registerSize(op2), 0x0000ffff & op3.immediate))), ZeroExtend)); break; case MIPS_B: case MIPS_J: @@ -1335,7 +1483,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)); @@ -1350,7 +1505,15 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu 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(op1)), 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(op1)), decomposeFlags)); @@ -1399,68 +1562,84 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu SignExtendHiLo(il, registerSize(op1)); break; + case MIPS_MULT1: case MIPS_MULT: if (version == MIPS_R5900 && instr.numOperands == 3) { - auto temp = LLIL_TEMP(0); - il.AddInstruction(il.SetRegister(8, temp, - il.MultDoublePrecSigned(4, - ReadILOperand(il, instr, 2, registerSize(op2), 4), - ReadILOperand(il, instr, 3, registerSize(op3), 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))))); - // il.AddInstruction(il.SetRegisterSplit(4, REG_HI, REG_LO, - // il.MultDoublePrecSigned(8, - // ReadILOperand(il, instr, 2, registerSize(op2)), - // ReadILOperand(il, instr, 3, registerSize(op3))))); - SignExtendHiLo(il, registerSize(op1)); + // 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, registerSize(op1), rd, il.Register(get_register_width(REG_LO, version), REG_LO))); - } - // if (version == MIPS_R5900 && instr.numOperands == 3) { - // il.AddInstruction(il.SetRegisterSplit(4, REG_HI, REG_LO, - // il.MultDoublePrecSigned(8, - // ReadILOperand(il, instr, 2, registerSize(op2)), - // ReadILOperand(il, instr, 3, registerSize(op3))))); - // SignExtendHiLo(il, registerSize(op1)); - // auto rd = op1.reg; - // if (rd != REG_ZERO) - // il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, rd, il.Register(registerSize, REG_LO))); - // } + 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, registerSize(op1), 4), - ReadILOperand(il, instr, 2, registerSize(op2), 4)))); - SignExtendHiLo(il, registerSize(op1)); // TODO: registerSize??? + // 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: if (version == MIPS_R5900 && instr.numOperands == 3) { - il.AddInstruction(il.SetRegisterSplit(4, REG_HI, REG_LO, + DEFINE_HILO1(MIPS_MULTU1); + + il.AddInstruction(il.SetRegisterSplit(4, hi, lo, il.MultDoublePrecUnsigned(4, - ReadILOperand(il, instr, 2, registerSize(op2)), - ReadILOperand(il, instr, 3, registerSize(op3))))); - SignExtendHiLo(il, registerSize(op1)); + 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(REG_LO, version), REG_LO))); + il.AddInstruction(SetRegisterOrNop(il, 4, 8, rd, il.Register(get_register_width(lo, version), lo))); } else { - il.AddInstruction(il.SetRegisterSplit(4, REG_HI, REG_LO, + DEFINE_HILO1(MIPS_MULTU1); + il.AddInstruction(il.SetRegisterSplit(4, hi, lo, il.MultDoublePrecUnsigned(4, - ReadILOperand(il, instr, 1, registerSize(op1)), - ReadILOperand(il, instr, 2, registerSize(op2))))); - SignExtendHiLo(il, registerSize(op1)); + ReadILOperand(il, instr, 1, 4), + ReadILOperand(il, instr, 2, 4)))); + if (lo == REG_LO) + SignExtendHiLo(il, 4); } break; case MIPS_DMULT: @@ -1469,8 +1648,10 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu case MIPS_DMULTU: 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: + // 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; @@ -1574,9 +1755,9 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu case MIPS_SC: { LowLevelILLabel trueCode, falseCode, doneCode; - il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(LLIL_TEMP(0)) }, MIPS_INTRIN_LLBIT_CHECK,{})); + 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(op1), 4))); @@ -1593,6 +1774,11 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu 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: @@ -1600,7 +1786,7 @@ 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(8, GetILOperandMemoryAddress(il, op2, addrSize), ReadILOperand(il, instr, 1, registerSize(op1), 4))); @@ -1614,8 +1800,25 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu 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.LowPart(4, il.Register(8, 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)); @@ -1703,7 +1906,7 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu il.AddInstruction(SetRegisterOrNop(il, 8, registerSize(op1), op1.reg, ReadILOperand(il, instr, 2, registerSize(op2)))); break; case MIPS_LQ: - il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, ReadILOperand(il, instr, 2, registerSize(op2), addrSize))); + il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, ReadILOperand(il, instr, 2, addrSize, 16))); break; case MIPS_LWL: { @@ -1898,61 +2101,80 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu ReadILOperand(il, instr, 2, registerSize(op2), 2), ZeroExtend)); break; + case MIPS_MADD1: case MIPS_MADD: if (version == MIPS_R5900 && instr.numOperands == 3) { - il.AddInstruction(il.SetRegisterSplit(4, REG_HI, REG_LO, + DEFINE_HILO1(MIPS_MADD1); + // il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0), + // il.Add(8, + // il.RegisterSplit(4, hi, lo), + // il.MultDoublePrecSigned(8, + // 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.Add(8, - il.RegisterSplit(4, REG_HI, REG_LO), - il.MultDoublePrecSigned(4, - ReadILOperand(il, instr, 2, registerSize(op2), 4), - ReadILOperand(il, instr, 3, registerSize(op3), 4) + il.RegisterSplit(4, hi, lo), + il.MultDoublePrecSigned(8, + ReadILOperand(il, instr, 2, 4, 4), + ReadILOperand(il, instr, 3, 4, 4) ) ) )); - SignExtendHiLo(il, registerSize(op1)); + 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(REG_LO, version), REG_LO))); + il.AddInstruction(SetRegisterOrNop(il, 4, 8, rd, il.Register(get_register_width(lo, version), lo))); } else { - il.AddInstruction(il.SetRegisterSplit(4, REG_HI, REG_LO, + DEFINE_HILO1(MIPS_MADD1); + il.AddInstruction(il.SetRegisterSplit(4, hi, lo, il.Add(8, - il.RegisterSplit(4, REG_HI, REG_LO), + il.RegisterSplit(4, hi, lo), il.MultDoublePrecSigned(4, - ReadILOperand(il, instr, 1, registerSize(op1), 4), - ReadILOperand(il, instr, 2, registerSize(op2), 4) + ReadILOperand(il, instr, 1, 4, 4), + ReadILOperand(il, instr, 2, 4, 4) ) ) )); - SignExtendHiLo(il, registerSize(op1)); + if (lo == REG_LO) + SignExtendHiLo(il, 4); } break; + case MIPS_MADDU1: case MIPS_MADDU: if (version == MIPS_R5900 && instr.numOperands == 3) { - il.AddInstruction(il.SetRegisterSplit(4, REG_HI, REG_LO, + DEFINE_HILO1(MIPS_MADDU1); + il.AddInstruction(il.SetRegisterSplit(4, hi, lo, il.Add(8, - il.RegisterSplit(4, REG_HI, REG_LO), + il.RegisterSplit(4, hi, lo), il.MultDoublePrecUnsigned(4, - ReadILOperand(il, instr, 2, registerSize(op2), 4), - ReadILOperand(il, instr, 3, registerSize(op3), 4) + ReadILOperand(il, instr, 2, 4, 4), + ReadILOperand(il, instr, 3, 4, 4) )))); - SignExtendHiLo(il, registerSize(op1)); + 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(REG_LO, version), REG_LO))); + il.AddInstruction(SetRegisterOrNop(il, 4, 8, rd, il.Register(get_register_width(lo, version), lo))); } else { - il.AddInstruction(il.SetRegisterSplit(4, REG_HI, REG_LO, + DEFINE_HILO1(MIPS_MADDU1); + il.AddInstruction(il.SetRegisterSplit(4, hi, lo, il.Add(8, - il.RegisterSplit(4, REG_HI, REG_LO), + il.RegisterSplit(4, hi, lo), il.MultDoublePrecUnsigned(4, - ReadILOperand(il, instr, 1, registerSize(op1), 4), - ReadILOperand(il, instr, 2, registerSize(op2), 4) + ReadILOperand(il, instr, 1, 4, 4), + ReadILOperand(il, instr, 2, 4, 4) )))); + if (lo == REG_LO) + SignExtendHiLo(il, 4); } - - SignExtendHiLo(il, registerSize(op1)); break; case MIPS_DROTR32: op3.immediate += 32; @@ -2001,13 +2223,27 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu case MIPS_BGEZALL: case MIPS_BLTZALL: break; - case MIPS_ADD_S: - il.AddInstruction(il.SetRegister(4, op1.reg, il.FloatAdd(4, il.Register(4, op2.reg), il.Register(4, op3.reg)))); + case MIPS_NEG_S: + il.AddInstruction(il.SetRegister(4, op1.reg, il.FloatNeg(4, il.Register(4, op2.reg)))); + break; + case MIPS_ABS_S: + case MIPS_ABS_D: + il.AddInstruction(il.SetRegister(registerSize(op1), op1.reg, il.FloatAbs(registerSize(op2), il.Register(registerSize(op2), op2.reg)))); + break; + case MIPS_MOV_S: + il.AddInstruction(il.SetRegister(registerSize(op1), op1.reg, il.Register(registerSize(op2), op2.reg))); break; case MIPS_ADD_D: - il.AddInstruction(il.SetRegisterSplit(4, op1.reg | 1, op1.reg & (~1), - il.FloatAdd(8, il.RegisterSplit(4, op2.reg | 1, op2.reg & (~1)), - il.RegisterSplit(4, op3.reg + 1, op3.reg)))); + if (version != MIPS_R5900) + { + il.AddInstruction(il.SetRegisterSplit(4, op1.reg | 1, op1.reg & (~1), + il.FloatAdd(8, il.RegisterSplit(4, op2.reg | 1, op2.reg & (~1)), + il.RegisterSplit(4, op3.reg + 1, op3.reg)))); + break; + } + // Fall through + case MIPS_ADD_S: + il.AddInstruction(il.SetRegister(registerSize(op1), op1.reg, il.FloatAdd(registerSize(op2), il.Register(registerSize(op2), op2.reg), il.Register(registerSize(op3), op3.reg)))); break; case MIPS_SUB_S: il.AddInstruction(il.SetRegister(4, op1.reg, il.FloatSub(4, il.Register(4, op2.reg), il.Register(4, op3.reg)))); @@ -2510,17 +2746,31 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu case MIPS_MTSAB: { - auto gprValue = il.Register(4, op1.reg); - auto gprLS4 = il.And(4, gprValue, il.Const(4, 0xF)); - - // Extract least-significant 4 bits of immediate value - auto immLS4 = il.And(4, il.Const(4, op2.immediate), il.Const(4, 0xF)); + 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); - // Perform XOR operation between GPR[rs][3:0] and immediate[3:0] - auto xorResult = il.Xor(4, gprLS4, immLS4); + // 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) - auto shiftAmount = il.ShiftLeft(4, xorResult, il.Const(4, 3)); + // 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)); @@ -2543,6 +2793,39 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu 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: @@ -2598,43 +2881,759 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu break; } + case MIPS_PCPYUD: + { + // TODO: this really requires indexed vector registers + // il.AddInstruction(il.Unimplemented()); + 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_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: + { + 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; - //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: - case MIPS_JALX: //Special instruction for switching to MIPS32/microMIPS32/MIPS16e - case MIPS_MTHC1: - case MIPS_MTHC2: - case MIPS_PREFX: - case MIPS_WRPGPR: + 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,4, 4, op1.reg, il.Register(4, 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(4, reg, il.Register(4, 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; + } + /* + Opcode "pcgth" is unimplemented (LLIL) + Opcode "ppacb" is unimplemented (LLIL) + Opcode "psllh" is unimplemented (LLIL) + Opcode "psrah" is unimplemented (LLIL) + Opcode "psrlh" is unimplemented (LLIL) + */ + + + 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: + case MIPS_PREFX: + case MIPS_WRPGPR: case MIPS_RDPGPR: case MIPS_SUXC1: case MIPS_SWXC1: @@ -2655,15 +3654,15 @@ 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: // R5900 instructions // case MIPS_LQ: // case MIPS_SQ: case MIPS_DSLRV: - case MIPS_MFSA: - case MIPS_MTSA: + // case MIPS_MFSA: + // case MIPS_MTSA: // case MIPS_MTSAB: // case MIPS_MTSAH: // case MIPS_MFHI1: @@ -2689,63 +3688,63 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu // 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_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_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_PCGTW: + // case MIPS_PMAXW: // case MIPS_PADDH: // case MIPS_PSUBH: - case MIPS_PCGTH: - case MIPS_PMAXH: + // case MIPS_PCGTH: + // case MIPS_PMAXH: // case MIPS_PADDB: // case MIPS_PSUBB: - case MIPS_PCGTB: + // case MIPS_PCGTB: // case MIPS_PADDSW: // case MIPS_PSUBSW: - case MIPS_PEXTLW: - case MIPS_PPACW: + // case MIPS_PEXTLW: + // case MIPS_PPACW: // case MIPS_PADDSH: // case MIPS_PSUBSH: - case MIPS_PEXTLH: - case MIPS_PPACH: + // case MIPS_PEXTLH: + // case MIPS_PPACH: // case MIPS_PADDSB: // case MIPS_PSUBSB: - case MIPS_PEXTLB: - case MIPS_PPACB: + // case MIPS_PEXTLB: + // case MIPS_PPACB: case MIPS_PEXT5: case MIPS_PPAC5: case MIPS_PABSW: case MIPS_PCEQW: - case MIPS_PMINW: + // case MIPS_PMINW: case MIPS_PADSBH: case MIPS_PABSH: case MIPS_PCEQH: - case MIPS_PMINH: + // case MIPS_PMINH: case MIPS_PCEQB: // case MIPS_PADDUW: // case MIPS_PSUBUW: - case MIPS_PEXTUW: + // case MIPS_PEXTUW: // case MIPS_PADDUH: // case MIPS_PSUBUH: - case MIPS_PEXTUH: + // case MIPS_PEXTUH: // case MIPS_PADDUB: // case MIPS_PSUBUB: - case MIPS_PEXTUB: - case MIPS_QFSRV: + // case MIPS_PEXTUB: + // case MIPS_QFSRV: case MIPS_PMADDW: case MIPS_PSLLVW: case MIPS_PSRLVW: @@ -2755,11 +3754,11 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu case MIPS_PINTH: case MIPS_PMULTW: case MIPS_PDIVW: - case MIPS_PCPYLD: + // case MIPS_PCPYLD: case MIPS_PMADDH: case MIPS_PHMADH: - case MIPS_PAND: - case MIPS_PXOR: + // case MIPS_PAND: + // case MIPS_PXOR: case MIPS_PMSUBH: case MIPS_PHMSBH: case MIPS_PEXEH: @@ -2775,17 +3774,482 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu case MIPS_PINTEH: case MIPS_PMULTUW: case MIPS_PDIVUW: - case MIPS_PCPYUD: - case MIPS_POR: - case MIPS_PNOR: + // case MIPS_PCPYUD: + // case MIPS_POR: + // case MIPS_PNOR: case MIPS_PEXCH: - case MIPS_PCPYH: + // 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()); + il.AddInstruction(il.Unimplemented()); + break; + + 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_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_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, 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_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 + REG_VF0_Y))))); + 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 + REG_VF0_Z))))); + 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 + 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_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_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_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_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_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_Z))))); + 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: + + // case MIPS_VDIV: + case MIPS_VIADD: + case MIPS_VIOR: + // 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_VCALLMS: + case MIPS_VCALLMSR: + + case MIPS_VFTOI0: + case MIPS_VFTOI15: + case MIPS_VFTOI4: + case MIPS_VITOF0: + case MIPS_VITOF15: + case MIPS_VITOF4: + + case MIPS_VLQI: + case MIPS_VSQI: + 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 5ed63ce3af..2db32ee14a 100644 --- a/arch/mips/il.h +++ b/arch/mips/il.h @@ -79,6 +79,8 @@ enum MipsIntrinsic : uint32_t CNMIPS_INTRIN_HWR31, CNMIPS_INTRIN_POP, CNMIPS_INTRIN_DPOP, + + MIPS_INTRIN_R5900_VWAITQ, MIPS_INTRIN_INVALID=0xFFFFFFFF, }; @@ -114,19 +116,40 @@ static inline const size_t get_register_width(size_t reg, MipsVersion version, s case MIPS_R5900: switch (reg) { - case REG_LO: - case REG_HI: - width = 64; - break; - case REG_LO1: - case REG_HI1: - width = 128; + case REG_LO: + case REG_HI: + width = 128; break; - default: - if (REG_ZERO <= reg && reg < REG_GP) - width = 128; // 64; // 128 - else if (FPREG_F0 <= reg && reg <= FPREG_F31) + 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; diff --git a/arch/mips/mips/mips.c b/arch/mips/mips/mips.c index b7d6cc4a36..069094ce55 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 @@ -1043,7 +1044,11 @@ static const char* const OperationStrings[] = { "max.s", "min.s", "qmfc2", + "qmfc2.i", + "qmfc2.ni", "qmtc2", + "qmtc2.i", + "qmtc2.ni", "vaddx", "vaddy", "vaddz", @@ -1164,6 +1169,13 @@ static const char* const OperationStrings[] = { "vrget", "vrinit", "vrxor", + + "mmi0", + "mmi1", + "mmi2", + "mmi3", + "lqc2", + "sqc2", }; static const char * const RegisterStrings[] = { @@ -1513,10 +1525,90 @@ static const char * const RegisterStrings[] = { "CVMX_HSH_STARTSHA512", "CVMX_GFM_XORMUL1", - "sa", + "$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[] = { @@ -1667,6 +1759,8 @@ uint32_t mips_decompose_instruction( 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]; @@ -2082,6 +2176,7 @@ uint32_t mips_decompose_instruction( } } + 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) { @@ -2419,13 +2514,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; @@ -2505,6 +2605,8 @@ 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: @@ -2555,8 +2657,9 @@ uint32_t mips_decompose_instruction( instruction->operands[0].reg = ins.i.rt; instruction->operands[1].reg = ins.i.rs; instruction->operands[1].immediate = ins.i.immediate; - if (instruction->operation == MIPS_SQ) - instruction->operands[1].immediate = MIPS_SQ; + // 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: @@ -2586,31 +2689,79 @@ 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 = version != MIPS_R5900 ? ins.i.rt : (FPREG_F0 + ins.f.ft); - // 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); 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_DIV1: - case MIPS_DIVU1: case MIPS_MADDU1: { if (ins.r.sa != 0) @@ -2783,8 +2934,8 @@ uint32_t mips_decompose_instruction( 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: @@ -2831,9 +2982,17 @@ uint32_t mips_decompose_instruction( 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: @@ -2943,6 +3102,484 @@ uint32_t mips_decompose_instruction( instruction->operands[0].immediate = 0; 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_VNOP: + case MIPS_VWAITQ: + break; + + // .dest ft.dest, (is++).dest + case MIPS_VLQI: + instruction->operands[i].reg = ins.v.ft + REG_VF0; + 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 + REG_VF0; + 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 + REG_VF0; + 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 + REG_VF0; + 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_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_VMINIx: + case MIPS_VMINIy: + case MIPS_VMINIz: + case MIPS_VMINIw: + 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: + // Fall through + + // .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; } @@ -2955,7 +3592,10 @@ uint32_t mips_disassemble( uint32_t outBufferSize) { char operands[MAX_OPERANDS][64] = {{0},{0},{0},{0}}; + char operation[64] = {0}; char* operandPtr = NULL; + char dest[5] = {0}; + strlcpy(operation, OperationStrings[instruction->operation], sizeof(operation)); for (uint32_t i = 0; i < MAX_OPERANDS && instruction->operands[i].operandClass != NONE; i++) { @@ -3008,12 +3648,44 @@ uint32_t mips_disassemble( RegisterStrings[instruction->operands[i].immediate], RegisterStrings[instruction->operands[i].reg]); 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], + // OperationStrings[instruction->operation], + operation, operands[0], operands[1], operands[2], diff --git a/arch/mips/mips/mips.h b/arch/mips/mips/mips.h index 0e07095ef9..1009f74596 100644 --- a/arch/mips/mips/mips.h +++ b/arch/mips/mips/mips.h @@ -630,7 +630,13 @@ namespace mips 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, @@ -758,6 +764,9 @@ namespace mips MIPS_MMI2, MIPS_MMI3, + MIPS_LQC2, + MIPS_SQC2, + MIPS_OPERATION_END }; @@ -1167,6 +1176,89 @@ namespace mips 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 }; @@ -1191,7 +1283,10 @@ namespace mips LABEL, MEM_IMM, MEM_REG, - HINT + HINT, + V_REG, + V_DEST, + V_REG_FIELD, }; enum Hint { @@ -1266,6 +1361,17 @@ 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 ttype { uint32_t function:6; uint32_t code:10; @@ -1286,6 +1392,7 @@ namespace mips struct jtype j; struct rtype r; struct ftype f; + struct vtype v; struct ttype t; struct stype s; uint32_t value; From 3b4ad5b803b466c1ac6d9f8121cd986e3de757bb Mon Sep 17 00:00:00 2001 From: Galen Williamson Date: Tue, 4 Mar 2025 18:32:18 -0500 Subject: [PATCH 10/16] WIP [mips] Fixing PR for r5900: lots more lifting and fixes --- arch/mips/arch_mips.cpp | 54 +++++++++++ arch/mips/il.cpp | 198 ++++++++++++++++++++++++++++++++++++---- arch/mips/il.h | 7 ++ arch/mips/mips/mips.c | 87 ++++++++++++++---- arch/mips/mips/mips.h | 11 +++ 5 files changed, 319 insertions(+), 38 deletions(-) diff --git a/arch/mips/arch_mips.cpp b/arch/mips/arch_mips.cpp index d1836a8324..c17d12076d 100644 --- a/arch/mips/arch_mips.cpp +++ b/arch/mips/arch_mips.cpp @@ -228,6 +228,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: @@ -380,6 +384,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: @@ -1136,6 +1144,18 @@ class MipsArchitecture: public Architecture 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 ""; } @@ -1199,6 +1219,10 @@ class MipsArchitecture: public Architecture { 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)); } @@ -1360,6 +1384,27 @@ class MipsArchitecture: public Architecture 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(); @@ -1417,6 +1462,15 @@ 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>>(); diff --git a/arch/mips/il.cpp b/arch/mips/il.cpp index e5ce140188..a9a88640f5 100644 --- a/arch/mips/il.cpp +++ b/arch/mips/il.cpp @@ -1,6 +1,7 @@ #include "il.h" #include "mips.h" +#include "arch/powerpc/capstone/arch/AArch64/AArch64GenRegisterInfo.inc" using namespace BinaryNinja; using namespace mips; @@ -529,6 +530,18 @@ ExprId GetConditionForInstruction(LowLevelILFunction& il, Instruction& instr, st 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(op1), il.And(registerSize(op1), @@ -1322,6 +1335,58 @@ 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)); @@ -3134,7 +3199,7 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu if (op2.operandClass == V_REG && reg < REG_VF0) reg += REG_VF0; il.AddInstruction( - SetRegisterOrNop(il,4, 4, op1.reg, il.Register(4, reg))); + SetRegisterOrNop(il,16, 16, op1.reg, il.Register(16, reg))); break; } case MIPS_QMTC2: @@ -3145,7 +3210,7 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu if (op2.operandClass == V_REG && reg < REG_VF0) reg += REG_VF0; il.AddInstruction( - il.SetRegister(4, reg, il.Register(4, op1.reg))); + il.SetRegister(16, reg, il.Register(16, op1.reg))); break; } @@ -3640,6 +3705,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: @@ -3780,14 +3850,14 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu case MIPS_PEXCH: // case MIPS_PCPYH: case MIPS_PEXCW: - case MIPS_BC0F: - case MIPS_BC0T: - case MIPS_BC0FL: - case MIPS_BC0TL: + // 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_MAX_S: + // case MIPS_MIN_S: case MIPS_MMI0: case MIPS_MMI1: case MIPS_MMI2: @@ -3795,6 +3865,33 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu 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; @@ -3815,6 +3912,19 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu 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; @@ -4170,19 +4280,73 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu { 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))))); + 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_Y), il.Register(4, op4.reg + REG_VF0_Y))))); + 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_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_Z))))); + 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_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)})); + break; + } + case MIPS_VCALLMSR: + { + il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_R5900_VU0_CALLMSR, {})); + break; + } + // case MIPS_VDIV: case MIPS_VIADD: @@ -4237,9 +4401,6 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu // case MIPS_VRSQRT: // case MIPS_VSQRT: - case MIPS_VCALLMS: - case MIPS_VCALLMSR: - case MIPS_VFTOI0: case MIPS_VFTOI15: case MIPS_VFTOI4: @@ -4247,10 +4408,7 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu case MIPS_VITOF15: case MIPS_VITOF4: - case MIPS_VLQI: - case MIPS_VSQI: - il.AddInstruction(il.Unimplemented()); - break; + // instructions that are just internal placeholders for other // decode tables; these will never be implemented because they're diff --git a/arch/mips/il.h b/arch/mips/il.h index 2db32ee14a..b67596070f 100644 --- a/arch/mips/il.h +++ b/arch/mips/il.h @@ -81,6 +81,13 @@ enum MipsIntrinsic : uint32_t 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, }; diff --git a/arch/mips/mips/mips.c b/arch/mips/mips/mips.c index 069094ce55..a6badcf64a 100644 --- a/arch/mips/mips/mips.c +++ b/arch/mips/mips/mips.c @@ -198,7 +198,7 @@ static Operation mips_special_table[7][8][8] = { },{ //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_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, + {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}, @@ -1619,7 +1619,9 @@ static const char * const FlagStrings[] = { "$fcc4", "$fcc5", "$fcc6", - "$fcc7" + "$fcc7", + "$coc0", + "$coc2", }; static const char * const HintStrings[] = { @@ -1868,11 +1870,13 @@ uint32_t mips_decompose_instruction( 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; + 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: @@ -2214,7 +2218,8 @@ uint32_t mips_decompose_instruction( case MIPS_BC0FL: case MIPS_BC0T: case MIPS_BC0TL: - INS_1(IMM, (ins.i.immediate << 2)) + // 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)) @@ -2312,6 +2317,19 @@ 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) @@ -2327,13 +2345,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: @@ -2342,7 +2365,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: @@ -2862,7 +2885,7 @@ uint32_t mips_decompose_instruction( 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; @@ -2872,7 +2895,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; @@ -3102,6 +3125,11 @@ 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: @@ -3155,8 +3183,8 @@ uint32_t mips_decompose_instruction( // case MIPS_VIADDI: // case MIPS_VIAND: // case MIPS_VIOR: - case MIPS_VCALLMS: - case MIPS_VCALLMSR: + // case MIPS_VCALLMS: + // case MIPS_VCALLMSR: // case MIPS_VADDAx: // case MIPS_VADDAy: // case MIPS_VADDAz: @@ -3224,6 +3252,16 @@ uint32_t mips_decompose_instruction( // case MIPS_VRXOR: break; + case MIPS_VCALLMS: + instruction->operands[0].immediate = ins.vi.imm15; + 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: @@ -3231,7 +3269,8 @@ uint32_t mips_decompose_instruction( // .dest ft.dest, (is++).dest case MIPS_VLQI: - instruction->operands[i].reg = ins.v.ft + REG_VF0; + // instruction->operands[i].reg = ins.v.ft + REG_VF0; + 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; @@ -3242,7 +3281,8 @@ uint32_t mips_decompose_instruction( break; // .dest fs.dest, (it++).dest case MIPS_VSQI: - instruction->operands[i].reg = ins.v.fs + REG_VF0; + // instruction->operands[i].reg = ins.v.fs + REG_VF0; + 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; @@ -3253,7 +3293,8 @@ uint32_t mips_decompose_instruction( break; // .dest ft.dest, (--is).dest case MIPS_VLQD: - instruction->operands[i].reg = ins.v.ft + REG_VF0; + // instruction->operands[i].reg = ins.v.ft + REG_VF0; + 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; @@ -3265,7 +3306,8 @@ uint32_t mips_decompose_instruction( // .dest fs.dest, (--it).dest case MIPS_VSQD: - instruction->operands[i].reg = ins.v.fs + REG_VF0; + // instruction->operands[i].reg = ins.v.fs + REG_VF0; + 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; @@ -3454,7 +3496,16 @@ uint32_t mips_decompose_instruction( // VOPMULA.xyz ACC.xyz, fs.xyz, ft.xyz case MIPS_VOPMULA: - // Fall through + 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: diff --git a/arch/mips/mips/mips.h b/arch/mips/mips/mips.h index 1009f74596..a7a1820cc0 100644 --- a/arch/mips/mips/mips.h +++ b/arch/mips/mips/mips.h @@ -1272,6 +1272,8 @@ namespace mips FPCCREG_FCC5, FPCCREG_FCC6, FPCCREG_FCC7, + CCREG_COC0, + CCREG_COC2, END_FLAG }; @@ -1372,6 +1374,14 @@ namespace mips 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; @@ -1393,6 +1403,7 @@ namespace mips struct rtype r; struct ftype f; struct vtype v; + struct vitype vi; struct ttype t; struct stype s; uint32_t value; From f5ab4fa89164731873dc20c3359575cc4de3a6ce Mon Sep 17 00:00:00 2001 From: Galen Williamson Date: Wed, 5 Mar 2025 11:13:17 -0500 Subject: [PATCH 11/16] WIP [mips] Fixing PR for r5900: lots more lifting and fixes --- arch/mips/arch_mips.cpp | 9 + arch/mips/mips/mips.c | 1518 ++++++++++++++++++++------------------- arch/mips/mips/mips.h | 32 + 3 files changed, 821 insertions(+), 738 deletions(-) diff --git a/arch/mips/arch_mips.cpp b/arch/mips/arch_mips.cpp index c17d12076d..2f97fbb897 100644 --- a/arch/mips/arch_mips.cpp +++ b/arch/mips/arch_mips.cpp @@ -1656,6 +1656,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 @@ -2000,6 +2004,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, diff --git a/arch/mips/mips/mips.c b/arch/mips/mips/mips.c index a6badcf64a..7c282c3cfa 100644 --- a/arch/mips/mips/mips.c +++ b/arch/mips/mips/mips.c @@ -449,733 +449,733 @@ static Operation mips_r5900_cop1_S_table[8][8] = { }; 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", + "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[] = { @@ -1275,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", @@ -1722,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]; @@ -2451,14 +2485,19 @@ uint32_t mips_decompose_instruction( case MIPS_DIVU: case MIPS_DMULT: case MIPS_DMULTU: - case MIPS_MULTU: 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: if (ins.r.sa != 0 @@ -2521,11 +2560,14 @@ uint32_t mips_decompose_instruction( 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: @@ -2783,15 +2825,15 @@ uint32_t mips_decompose_instruction( 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_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: diff --git a/arch/mips/mips/mips.h b/arch/mips/mips/mips.h index a7a1820cc0..d65a72aaa5 100644 --- a/arch/mips/mips/mips.h +++ b/arch/mips/mips/mips.h @@ -873,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, From 1e95433aadb11773f83a149c1fa2daf1fb035348 Mon Sep 17 00:00:00 2001 From: Galen Williamson Date: Thu, 6 Mar 2025 14:45:52 -0500 Subject: [PATCH 12/16] WIP [mips] Fixing PR for r5900: lots more lifting of v* instructions --- arch/mips/il.cpp | 119 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 108 insertions(+), 11 deletions(-) diff --git a/arch/mips/il.cpp b/arch/mips/il.cpp index a9a88640f5..55393d84ab 100644 --- a/arch/mips/il.cpp +++ b/arch/mips/il.cpp @@ -3647,13 +3647,46 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, LLIL_TEMP(0)))); break; } - /* - Opcode "pcgth" is unimplemented (LLIL) - Opcode "ppacb" is unimplemented (LLIL) - Opcode "psllh" is unimplemented (LLIL) - Opcode "psrah" is unimplemented (LLIL) - Opcode "psrlh" is unimplemented (LLIL) - */ + + // 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_CTC1: @@ -3835,7 +3868,7 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu case MIPS_PREVH: case MIPS_PMULTH: case MIPS_PDIVBW: - case MIPS_PEXEW: + // case MIPS_PEXEW: case MIPS_PROT3W: case MIPS_PMADDUW: case MIPS_PSRAVW: @@ -3847,9 +3880,9 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu // case MIPS_PCPYUD: // case MIPS_POR: // case MIPS_PNOR: - case MIPS_PEXCH: + // case MIPS_PEXCH: // case MIPS_PCPYH: - case MIPS_PEXCW: + // case MIPS_PEXCW: // case MIPS_BC0F: // case MIPS_BC0T: // case MIPS_BC0FL: @@ -4208,6 +4241,32 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu 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, 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_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 + REG_VF0_Y))))); + 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 + REG_VF0_Z))))); + 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 + 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: @@ -4242,6 +4301,23 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu 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: { @@ -4256,6 +4332,20 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu 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)))); @@ -4347,9 +4437,16 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu 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_VDIV: - case MIPS_VIADD: + // case MIPS_VIADD: + // case MIPS_VIADDI: case MIPS_VIOR: // case MIPS_VMADD: // case MIPS_VMADDAx: From b87d00d2225d9178c14750c19a866b5247e15cee Mon Sep 17 00:00:00 2001 From: Galen Williamson Date: Mon, 10 Mar 2025 13:31:54 -0400 Subject: [PATCH 13/16] WIP [mips] Fixing PR for r5900: lots more lifting of v* instructions --- arch/mips/arch_mips.cpp | 23 ++++- arch/mips/il.cpp | 136 +++++++++++++++++++++++++---- arch/mips/mips/mips.c | 187 ++++++++++++++++++++++++++++++++-------- arch/mips/mips/test.c | 34 ++++++-- 4 files changed, 316 insertions(+), 64 deletions(-) diff --git a/arch/mips/arch_mips.cpp b/arch/mips/arch_mips.cpp index 2f97fbb897..fea611c970 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"}, @@ -932,11 +934,19 @@ class MipsArchitecture: public Architecture 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) { - char reg_tmp[sizeof(operand)] = {0}; 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); @@ -951,6 +961,10 @@ class MipsArchitecture: public Architecture 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) @@ -3381,6 +3395,7 @@ class MipsElfRelocationHandler: public RelocationHandler dest64[0] = swap64(originalValue + displacement); break; } + case R_MIPS_LITERAL: case R_MIPS_GPREL32: { if (!GetGpAddr(view, gpAddr)) @@ -3389,6 +3404,8 @@ class MipsElfRelocationHandler: public RelocationHandler dest32[0] = swap(vRel32); break; } + case R_MIPS_VCALLMS: + break; default: break; } @@ -3468,6 +3485,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, diff --git a/arch/mips/il.cpp b/arch/mips/il.cpp index 55393d84ab..c29b9952c2 100644 --- a/arch/mips/il.cpp +++ b/arch/mips/il.cpp @@ -3687,7 +3687,47 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu )))); 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: @@ -3859,7 +3899,7 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu case MIPS_PDIVW: // case MIPS_PCPYLD: case MIPS_PMADDH: - case MIPS_PHMADH: + // case MIPS_PHMADH: // case MIPS_PAND: // case MIPS_PXOR: case MIPS_PMSUBH: @@ -4219,13 +4259,13 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu { 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 + REG_VF0_X))))); + 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, 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))))); + 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, 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))))); + 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, 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))))); + 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: @@ -4245,13 +4285,13 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu { 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 + REG_VF0_X))))); + 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, 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))))); + 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, 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))))); + 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, 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))))); + 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: @@ -4392,6 +4432,34 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu 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: { @@ -4428,7 +4496,7 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu case MIPS_VCALLMS: { - il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_R5900_VU0_CALLMS, {il.Const(4, op1.immediate)})); + il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_R5900_VU0_CALLMS, {il.Const(4, op1.immediate << 3)})); break; } case MIPS_VCALLMSR: @@ -4443,11 +4511,40 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu 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_VIOR: + { + il.AddInstruction(il.SetRegister(2, op1.reg, il.Or(2, il.Register(2, op2.reg), il.Register(2, op3.reg)))); + break; + } // case MIPS_VDIV: // case MIPS_VIADD: // case MIPS_VIADDI: - case MIPS_VIOR: // case MIPS_VMADD: // case MIPS_VMADDAx: // case MIPS_VMADDAy: @@ -4498,14 +4595,15 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu // case MIPS_VRSQRT: // case MIPS_VSQRT: - case MIPS_VFTOI0: - case MIPS_VFTOI15: + case MIPS_VFTOI4: - case MIPS_VITOF0: - case MIPS_VITOF15: + 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 // decode tables; these will never be implemented because they're diff --git a/arch/mips/mips/mips.c b/arch/mips/mips/mips.c index 7c282c3cfa..98eb7d12cc 100644 --- a/arch/mips/mips/mips.c +++ b/arch/mips/mips/mips.c @@ -3286,16 +3286,28 @@ uint32_t mips_decompose_instruction( // case MIPS_VWAITQ: // case MIPS_VMTIR: // case MIPS_VMFIR: - case MIPS_VILWR: - case MIPS_VISWR: + // 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; + instruction->operands[0].immediate = ins.vi.imm15; // << 3; instruction->operands[0].operandClass = IMM; break; @@ -3311,7 +3323,6 @@ uint32_t mips_decompose_instruction( // .dest ft.dest, (is++).dest case MIPS_VLQI: - // instruction->operands[i].reg = ins.v.ft + REG_VF0; instruction->operands[i].reg = ins.v.ft; instruction->operands[i++].operandClass = V_REG; instruction->operands[i].reg = ins.v.fs + REG_VI0; @@ -3323,7 +3334,6 @@ uint32_t mips_decompose_instruction( break; // .dest fs.dest, (it++).dest case MIPS_VSQI: - // instruction->operands[i].reg = ins.v.fs + REG_VF0; instruction->operands[i].reg = ins.v.fs; instruction->operands[i++].operandClass = V_REG; instruction->operands[i].reg = ins.v.ft + REG_VI0; @@ -3335,7 +3345,6 @@ uint32_t mips_decompose_instruction( break; // .dest ft.dest, (--is).dest case MIPS_VLQD: - // instruction->operands[i].reg = ins.v.ft + REG_VF0; instruction->operands[i].reg = ins.v.ft; instruction->operands[i++].operandClass = V_REG; instruction->operands[i].reg = ins.v.fs + REG_VI0; @@ -3345,10 +3354,8 @@ uint32_t mips_decompose_instruction( 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 + REG_VF0; instruction->operands[i].reg = ins.v.fs; instruction->operands[i++].operandClass = V_REG; instruction->operands[i].reg = ins.v.ft + REG_VI0; @@ -3684,16 +3691,37 @@ 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; char dest[5] = {0}; + int first_operand = 0; + const char* reg = NULL; + int max_oplen = 0; + strlcpy(operation, OperationStrings[instruction->operation], sizeof(operation)); - for (uint32_t i = 0; + 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++; + } + size_t n = strnlen(operation, sizeof(operation)); + 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++ = ' '; @@ -3742,47 +3770,136 @@ uint32_t mips_disassemble( RegisterStrings[instruction->operands[i].reg]); break; case V_REG: - strcpy(operandPtr, RegisterStrings[instruction->operands[i].reg + FPREG_F0]); - if (dest[0]) + // #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) { - strcat(operandPtr, "_"); - strcat(operandPtr, dest); + char reg_tmp[64] = {0}; + 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 (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); + // 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: { - char *p = operandPtr; - *p++ = "xyzw"[instruction->operands[i].reg]; - *p = '\0'; + 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", + snprintf(outBuffer, outBufferSize, "%-13s\t%s%s%s%s", // OperationStrings[instruction->operation], operation, - operands[0], - operands[1], - operands[2], - operands[3]); + 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/test.c b/arch/mips/mips/test.c index d15086fea6..ba028802cd 100644 --- a/arch/mips/mips/test.c +++ b/arch/mips/mips/test.c @@ -162,18 +162,34 @@ 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}; + int n; + // while (p && *p && (n = strnlen(p, 9)) >= 8) + 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++; } From 00239e1e6d3066aa5a0c170e7707b6520c700046 Mon Sep 17 00:00:00 2001 From: Galen Williamson Date: Tue, 18 Mar 2025 13:30:00 -0400 Subject: [PATCH 14/16] WIP [mips] added PS2 calling convention --- arch/mips/arch_mips.cpp | 87 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 82 insertions(+), 5 deletions(-) diff --git a/arch/mips/arch_mips.cpp b/arch/mips/arch_mips.cpp index fea611c970..a00275b58a 100644 --- a/arch/mips/arch_mips.cpp +++ b/arch/mips/arch_mips.cpp @@ -2726,6 +2726,9 @@ class MipsArchitecture: public Architecture return registers; } + MipsVersion GetMIPSVersion() { + return m_version; + } }; class MipsO32CallingConvention: public CallingConvention @@ -2789,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: @@ -3331,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, m_version, 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; @@ -3611,15 +3686,13 @@ 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); mipsel->RegisterCallingConvention(o32LE); mipsel->SetDefaultCallingConvention(o32LE); - r5900l->RegisterCallingConvention(o32LE); - r5900l->SetDefaultCallingConvention(o32LE); - r5900b->RegisterCallingConvention(o32BE); - r5900b->SetDefaultCallingConvention(o32BE); mips3->RegisterCallingConvention(o32BE); mips3->SetDefaultCallingConvention(o32BE); mips3el->RegisterCallingConvention(o32LE); @@ -3630,6 +3703,10 @@ extern "C" mips64eb->SetDefaultCallingConvention(n64BE); cnmips64eb->RegisterCallingConvention(n64BEc); cnmips64eb->SetDefaultCallingConvention(n64BEc); + r5900l->RegisterCallingConvention(ps2LE); + r5900l->SetDefaultCallingConvention(ps2LE); + r5900b->RegisterCallingConvention(ps2BE); + r5900b->SetDefaultCallingConvention(ps2BE); MipsLinuxSyscallCallingConvention* linuxSyscallBE = new MipsLinuxSyscallCallingConvention(mipseb); MipsLinuxSyscallCallingConvention* linuxSyscallLE = new MipsLinuxSyscallCallingConvention(mipsel); From f23a12f69c22168b53673f64a60d087901722cbc Mon Sep 17 00:00:00 2001 From: Galen Williamson Date: Tue, 18 Mar 2025 13:31:57 -0400 Subject: [PATCH 15/16] WIP [mips] Fixing PR for r5900: more lifting of p* instructions; improvements to standalone/test disassembler --- arch/mips/il.cpp | 369 ++++++++++++++++++++++++++++++++++++++---- arch/mips/mips/mips.c | 12 +- arch/mips/mips/test.c | 2 - 3 files changed, 347 insertions(+), 36 deletions(-) diff --git a/arch/mips/il.cpp b/arch/mips/il.cpp index c29b9952c2..50c7e07742 100644 --- a/arch/mips/il.cpp +++ b/arch/mips/il.cpp @@ -1869,7 +1869,7 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu { il.AddInstruction( il.Store(4, GetILOperandMemoryAddress(il, op2, addrSize), - il.LowPart(4, il.Register(8, op1.reg)))); + il.Register(4, op1.reg))); } else { @@ -2052,7 +2052,7 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu // preferred way to sign extend the lower 32 bits of an register is to shift // it left by 0 // if (registerSize(op1) == 8 && op2.reg != 0 && op3.immediate == 0) - if (version == MIPS_64 && op2.reg != REG_ZERO) + if ((version == MIPS_R5900 || version == MIPS_64) && op2.reg != REG_ZERO) { if (op3.immediate == 0) { @@ -2363,6 +2363,17 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu il.AddInstruction(il.SetRegister(4, op1.reg, il.FloatConvert(4, il.RegisterSplit(4, op2.reg | 1, op2.reg & (~1))))); break; + case MIPS_C_F_S: + case MIPS_C_F_D: + if (op1.operandClass == FLAG) + { + il.AddInstruction(il.SetFlag(op1.reg, il.Const(0, 0))); + } + else + { + il.AddInstruction(il.SetFlag(FPCCREG_FCC0, il.Const(0, 0))); + } + break; case MIPS_C_EQ_S: if (op1.operandClass == FLAG) { @@ -2950,13 +2961,36 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu { // TODO: this really requires indexed vector registers // il.AddInstruction(il.Unimplemented()); - 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)))))); + 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), @@ -3076,6 +3110,29 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu 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: @@ -3687,6 +3744,62 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu )))); 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++) @@ -3868,7 +3981,7 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu // case MIPS_PSUBSB: // case MIPS_PEXTLB: // case MIPS_PPACB: - case MIPS_PEXT5: + // case MIPS_PEXT5: case MIPS_PPAC5: case MIPS_PABSW: case MIPS_PCEQW: @@ -3909,7 +4022,7 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu case MIPS_PMULTH: case MIPS_PDIVBW: // case MIPS_PEXEW: - case MIPS_PROT3W: + // case MIPS_PROT3W: case MIPS_PMADDUW: case MIPS_PSRAVW: case MIPS_PMTHI: @@ -4224,6 +4337,21 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu 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: @@ -4324,6 +4452,23 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu 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: @@ -4537,11 +4682,181 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu 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: @@ -4570,16 +4885,16 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu // 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: + // 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 @@ -4596,12 +4911,12 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu // case MIPS_VSQRT: - case MIPS_VFTOI4: - case MIPS_VFTOI12: - case MIPS_VFTOI15: - case MIPS_VITOF4: - case MIPS_VITOF12: - case MIPS_VITOF15: + // case MIPS_VFTOI4: + // case MIPS_VFTOI12: + // case MIPS_VFTOI15: + // case MIPS_VITOF4: + // case MIPS_VITOF12: + // case MIPS_VITOF15: il.AddInstruction(il.Unimplemented()); break; diff --git a/arch/mips/mips/mips.c b/arch/mips/mips/mips.c index 98eb7d12cc..b03a2f014f 100644 --- a/arch/mips/mips/mips.c +++ b/arch/mips/mips/mips.c @@ -3424,6 +3424,11 @@ uint32_t mips_decompose_instruction( 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: @@ -3481,10 +3486,6 @@ uint32_t mips_decompose_instruction( break; // i.dest fd.dest, fs.dest, I - case MIPS_VMINIx: - case MIPS_VMINIy: - case MIPS_VMINIz: - case MIPS_VMINIw: case MIPS_VMAXi: case MIPS_VMULi: case MIPS_VMINIi: @@ -3697,7 +3698,6 @@ uint32_t mips_disassemble( char dest[5] = {0}; int first_operand = 0; const char* reg = NULL; - int max_oplen = 0; strlcpy(operation, OperationStrings[instruction->operation], sizeof(operation)); if (instruction->operands[0].operandClass == V_DEST) @@ -3716,7 +3716,6 @@ uint32_t mips_disassemble( strcat(operation, dest); first_operand++; } - size_t n = strnlen(operation, sizeof(operation)); for (uint32_t i = first_operand; i < MAX_OPERANDS && instruction->operands[i].operandClass != NONE; i++) { @@ -3777,7 +3776,6 @@ uint32_t mips_disassemble( reg = get_register((Reg)instruction->operands[i].reg); if (reg != NULL) { - char reg_tmp[64] = {0}; if (instruction->operands[i].reg >= REG_VI0 && instruction->operands[i].reg <= REG_VI15) { switch (instruction->operation) diff --git a/arch/mips/mips/test.c b/arch/mips/mips/test.c index ba028802cd..2a90df4858 100644 --- a/arch/mips/mips/test.c +++ b/arch/mips/mips/test.c @@ -164,8 +164,6 @@ int main(int ac, char **av) { char *p = av[instindex]; char buf[9] = {0}; - int n; - // while (p && *p && (n = strnlen(p, 9)) >= 8) while (strnlen(p, 8) > 0 && strlen(strncpy(buf, p, 8)) <= 8) { char *endptr; From 61242eee12c7c26797896afddd4cb5985edda6fc Mon Sep 17 00:00:00 2001 From: Galen Williamson Date: Thu, 10 Apr 2025 14:31:25 -0400 Subject: [PATCH 16/16] WIP [mips] Fixing PR for r5900: fix size argument to MultDoublePrec* calls --- arch/mips/il.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/mips/il.cpp b/arch/mips/il.cpp index 50c7e07742..d0e14ee79b 100644 --- a/arch/mips/il.cpp +++ b/arch/mips/il.cpp @@ -1,7 +1,6 @@ #include "il.h" #include "mips.h" -#include "arch/powerpc/capstone/arch/AArch64/AArch64GenRegisterInfo.inc" using namespace BinaryNinja; using namespace mips;