summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkat <kat@vector35.com>2025-01-12 16:54:50 -0500
committerGalen Williamson <galen@vector35.com>2025-07-02 02:11:30 -0400
commitda9df164ea310ee6aab900fa940b63d20839c2dc (patch)
tree590a3bfc40c2e17ba7337c3bd5ff1d16cdf113f7
parent8303adc8095926ad8e4f3758f5e2677fa20450ce (diff)
[mips] Merges PR https://github.com/Vector35/binaryninja-api/pull/6311: MIPS r5900 (PS2 EE) support
-rw-r--r--arch/mips/arch_mips.cpp517
-rw-r--r--arch/mips/il.cpp4399
-rw-r--r--arch/mips/il.h86
-rw-r--r--arch/mips/mips/mips.c2365
-rw-r--r--arch/mips/mips/mips.h411
-rw-r--r--arch/mips/mips/test.c36
6 files changed, 6249 insertions, 1565 deletions
diff --git a/arch/mips/arch_mips.cpp b/arch/mips/arch_mips.cpp
index 4cd8b26c..692679ec 100644
--- a/arch/mips/arch_mips.cpp
+++ b/arch/mips/arch_mips.cpp
@@ -19,6 +19,8 @@ using namespace std;
#define snprintf _snprintf
#endif
+#define E_MIPS_MACH_5900 0x00920000
+
uint32_t bswap32(uint32_t x)
{
return ((x << 24) & 0xff000000 ) |
@@ -102,6 +104,7 @@ enum ElfMipsRelocationType : uint32_t
// This range is reserved for vendor specific relocations.
R_MIPS_LOVENDOR = 100,
+ R_MIPS_VCALLMS = 119, // MIPS R5900-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 +168,7 @@ static const char* GetRelocationString(ElfMipsRelocationType rel)
{ R_MIPS_TLS_TPREL_LO16, "R_MIPS_TLS_TPREL_LO16"},
{ R_MIPS_GLOB_DAT, "R_MIPS_GLOB_DAT"},
{ R_MIPS_LOVENDOR, "R_MIPS_LOVENDOR"},
+ { R_MIPS_VCALLMS, "R_MIPS_VCALLMS"},
{ R_MIPS64_COPY, "R_MIPS64_COPY"},
{ R_MIPS_COPY, "R_MIPS_COPY"},
{ R_MIPS_JUMP_SLOT, "R_MIPS_JUMP_SLOT"},
@@ -179,27 +183,24 @@ static const char* GetRelocationString(ElfMipsRelocationType rel)
class MipsArchitecture: public Architecture
{
protected:
+ bool m_userWarnedAboutDelaySlots = false;
+ MipsVersion m_version;
size_t m_bits;
BNEndianness m_endian;
- MipsVersion version_overwrite;
uint32_t m_decomposeFlags;
virtual bool Disassemble(const uint8_t* data, uint64_t addr, size_t maxLen, Instruction& result)
{
- MipsVersion version = version_overwrite;
-
memset(&result, 0, sizeof(result));
- if (m_bits == 64)
- {
- version = MIPS_64;
- }
-
- if (mips_decompose((uint32_t*)data, maxLen, &result, version, addr, m_endian, m_decomposeFlags) != 0)
+ if (mips_decompose((uint32_t*)data, maxLen, &result, m_version, addr, m_endian, m_decomposeFlags) != 0)
return false;
return true;
}
- virtual size_t GetAddressSize() const override { return m_bits / 8; }
+ virtual size_t GetAddressSize() const override
+ {
+ return m_bits / 8;
+ }
size_t InstructionHasBranchDelay(const Instruction& instr)
{
@@ -231,6 +232,10 @@ protected:
case MIPS_JAL:
case MIPS_JALR:
case MIPS_JALR_HB:
+ case MIPS_BC0F:
+ case MIPS_BC0FL:
+ case MIPS_BC0T:
+ case MIPS_BC0TL:
case MIPS_BC1F:
case MIPS_BC1FL:
case MIPS_BC1T:
@@ -383,6 +388,10 @@ protected:
else
result.AddBranch(UnresolvedBranch, 0, nullptr, hasBranchDelay);
break;
+ case MIPS_BC0F:
+ case MIPS_BC0FL:
+ case MIPS_BC0T:
+ case MIPS_BC0TL:
case MIPS_BC1F:
case MIPS_BC1FL:
case MIPS_BC1T:
@@ -407,8 +416,8 @@ protected:
}
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 = Settings::Instance();
uint32_t flag_pseudo_ops = settings->Get<bool>("arch.mips.disassembly.pseudoOps") ? DECOMPOSE_FLAGS_PSEUDO_OP : 0;
@@ -508,7 +517,16 @@ public:
{
if (len < 8)
{
- LogWarn("Can not lift instruction with delay slot @ 0x%08" PRIx64, addr);
+ if (!m_userWarnedAboutDelaySlots)
+ {
+
+ LogWarn("Can not lift instruction with delay slot @ 0x%08" PRIx64 "\n"
+ "Any future delay slot errors will be printed as debug logs\n"
+ "and can be viewed by setting the log capture level to debug.", addr);
+ m_userWarnedAboutDelaySlots = true;
+ }
+ else
+ LogDebug("Can not lift instruction with delay slot @ 0x%08" PRIx64, addr);
return false;
}
@@ -524,11 +542,16 @@ public:
{
InstructionInfo instrInfo;
LowLevelILLabel trueCode, falseCode;
+ auto registerSize = [this](const InstructionOperand& op) -> size_t const
+ {
+ return get_register_width(Reg(op.reg), m_version);
+ };
+
SetInstructionInfoForInstruction(addr, instr, instrInfo);
- il.AddInstruction(il.If(GetConditionForInstruction(il, instr, GetAddressSize()), trueCode, falseCode));
+ il.AddInstruction(il.If(GetConditionForInstruction(il, instr, registerSize), trueCode, falseCode));
il.MarkLabel(trueCode);
il.SetCurrentAddress(this, addr + instr.size);
- GetLowLevelILForInstruction(this, addr + instr.size, il, secondInstr, GetAddressSize(), m_decomposeFlags);
+ GetLowLevelILForInstruction(this, addr + instr.size, il, secondInstr, GetAddressSize(), m_decomposeFlags, m_version);
for (size_t i = 0; i < instrInfo.branchCount; i++)
{
if (instrInfo.branchType[i] == TrueBranch)
@@ -554,7 +577,7 @@ public:
nop = il.Nop();
il.AddInstruction(nop);
- GetLowLevelILForInstruction(this, addr + instr.size, il, secondInstr, GetAddressSize(), m_decomposeFlags);
+ GetLowLevelILForInstruction(this, addr + instr.size, il, secondInstr, GetAddressSize(), m_decomposeFlags, m_version);
LowLevelILInstruction delayed;
uint32_t clobbered = BN_INVALID_REGISTER;
@@ -581,7 +604,7 @@ public:
}
else
{
- status = GetLowLevelILForInstruction(this, addr, il, instr, GetAddressSize(), m_decomposeFlags);
+ status = GetLowLevelILForInstruction(this, addr, il, instr, GetAddressSize(), m_decomposeFlags, m_version);
}
if (clobbered != BN_INVALID_REGISTER)
@@ -732,7 +755,8 @@ public:
else
{
proceed = proceed && (left->operands[1].immediate == (right->operands[1].immediate + 7));
- addrToUse = (uint32_t)addr + ((&instr == right) ? 0 : 8);
+ // addrToUse = (uint32_t)addr + ((&instr == right) ? 0 : 8);
+ addrToUse = (uint32_t)addr + ((&instr == right) ? 0 : 4);
}
base = right;
}
@@ -746,12 +770,12 @@ public:
else
base->operation = is32bit ? MIPS_LW : MIPS_LD;
- return GetLowLevelILForInstruction(this, addrToUse, il, *base, GetAddressSize(), m_decomposeFlags);
+ return GetLowLevelILForInstruction(this, addrToUse, il, *base, GetAddressSize(), m_decomposeFlags, m_version);
}
}
len = instr.size;
- return GetLowLevelILForInstruction(this, addr, il, instr, GetAddressSize(), m_decomposeFlags);
+ return GetLowLevelILForInstruction(this, addr, il, instr, GetAddressSize(), m_decomposeFlags, m_version);
}
virtual bool GetInstructionInfo(const uint8_t* data, uint64_t addr, size_t maxLen, InstructionInfo& result) override
@@ -770,17 +794,38 @@ public:
virtual bool GetInstructionText(const uint8_t* data, uint64_t addr, size_t& len, vector<InstructionTextToken>& 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;
+ strncpy(operation, operation_name, sizeof(operation));
+
+ if (instr.operands[0].operandClass == V_DEST)
+ {
+ char* p = dest;
+ if (instr.operands[0].reg & 8)
+ *p++ = 'x';
+ if (instr.operands[0].reg & 4)
+ *p++ = 'y';
+ if (instr.operands[0].reg & 2)
+ *p++ = 'z';
+ if (instr.operands[0].reg & 1)
+ *p++ = 'w';
+ *p = '\0';
+ strcat(operation, ".");
+ strcat(operation, dest);
+ first_operand++;
+ }
size_t operationLen = strlen(operation);
if (operationLen < 8)
@@ -792,15 +837,17 @@ public:
result.emplace_back(InstructionToken, operation);
result.emplace_back(TextToken, padding);
- for (size_t i = 0; i < MAX_OPERANDS; i++)
+ for (size_t i = first_operand; i < MAX_OPERANDS; i++)
{
if (instr.operands[i].operandClass == NONE)
return true;
+ operand[0] = '\0';
+
int32_t imm = instr.operands[i].immediate;
uint64_t label_imm = instr.operands[i].immediate;
- if (i != 0)
+ if (i != first_operand)
result.emplace_back(OperandSeparatorToken, ", ");
switch (instr.operands[i].operandClass)
@@ -881,6 +928,114 @@ public:
result.emplace_back(BraceToken, ")");
result.emplace_back(EndMemoryOperandToken, "");
break;
+ case V_REG:
+ // #define V_FMT "$vf%02d" // Use this if leading zeroes are preferred
+ #define V_FMT "$vf%d"
+ reg = NULL;
+ if (instr.operands[i].reg >= REG_VP)
+ reg = get_register((Reg)instr.operands[i].reg);
+ if (reg != NULL)
+ {
+ char reg_tmp[sizeof(operand)] = {0};
+ if (instr.operands[i].reg >= REG_VI0 && instr.operands[i].reg <= REG_VI15)
+ {
+ switch (instr.operation)
+ {
+ case MIPS_VISWR:
+ case MIPS_VILWR:
+ if (i == 2)
+ {
+ snprintf(reg_tmp, sizeof(reg_tmp), "(%s).%s", reg, dest);
+ reg = reg_tmp;
+ }
+ break;
+ case MIPS_VLQI:
+ case MIPS_VSQI:
+ snprintf(reg_tmp, sizeof(reg_tmp), "(%s++)", reg);
+ reg = reg_tmp;
+ break;
+ case MIPS_VLQD:
+ case MIPS_VSQD:
+ snprintf(reg_tmp, sizeof(reg_tmp), "(--%s)", reg);
+ reg = reg_tmp;
+ break;
+ default:
+ break;
+ }
+ }
+ if (reg == reg_tmp)
+ {
+ // Done
+ }
+ else if (instr.operands[i].reg >= REG_VF0 && instr.operands[i].reg <= REG_VF31)
+ {
+ if (instr.operands[i].immediate > 0 && instr.operands[i].immediate <= 4)
+ snprintf(operand, sizeof(operand), "%s.%c",
+ reg,
+ "xyzw"[instr.operands[i].immediate-1]);
+ else if (dest[0])
+ snprintf(operand, sizeof(operand), "%s.%s", reg, dest);
+ }
+ if (!operand[0])
+ snprintf(operand, sizeof(operand), "%s", reg);
+ }
+ // else if ((instr.operands[i].reg >= REG_VACC && instr.operands[i].reg <= REG_VI15) &&
+ // (reg = get_register((Reg)instr.operands[i].reg)) != NULL)
+ // {
+ // // if (instr.operands[i].reg == REG_VACC && dest[0])
+ // // snprintf(operand, sizeof(operand), "%s.%s", reg, dest);
+ // // else
+ // snprintf(operand, sizeof(operand), "%s", reg);
+ // }
+ else if (instr.operands[i].immediate > 0 && instr.operands[i].immediate <= 4)
+ snprintf(operand, sizeof(operand), V_FMT ".%c",
+ instr.operands[i].reg,
+ "xyzw"[instr.operands[i].immediate-1]);
+ else if (instr.operands[i].immediate == 'A')
+ {
+ if (dest[0])
+ snprintf(operand, sizeof(operand), "ACC.%s", dest);
+ else
+ snprintf(operand, sizeof(operand), "ACC");
+ }
+ else if (instr.operands[i].immediate > 'A' && instr.operands[i].immediate <= 'Z')
+ snprintf(operand, sizeof(operand), "%c",
+ (char) instr.operands[i].immediate);
+ else if (dest[0])
+ snprintf(operand, sizeof(operand), V_FMT ".%s",
+ instr.operands[i].reg, dest);
+ else
+ snprintf(operand, sizeof(operand), V_FMT, instr.operands[i].reg);
+ result.emplace_back(RegisterToken, operand);
+ break;
+ case V_DEST:
+ {
+ char* p = dest;
+ if (*p == '\0' && (instr.operands[i].reg & 0xF) != 0)
+ {
+ if (instr.operands[i].reg & 8)
+ *p++ = 'x';
+ if (instr.operands[i].reg & 4)
+ *p++ = 'y';
+ if (instr.operands[i].reg & 2)
+ *p++ = 'z';
+ if (instr.operands[i].reg & 1)
+ *p++ = 'w';
+ *p = '\0';
+ }
+ break;
+ }
+ case V_REG_FIELD:
+ {
+ snprintf(operand, sizeof(operand), V_FMT ".%c",
+ instr.operands[i].reg,
+ "xyzw"[instr.operands[i].immediate]);
+ // char *p = operand;
+ // *p++ = "xyzw"[instr.operands[i].reg];
+ // *p = '\0';
+ result.emplace_back(RegisterToken, operand);
+ break;
+ }
default:
LogError("operandClass %x\n", instr.operands[i].operandClass);
return false;
@@ -1002,6 +1157,21 @@ public:
return "_countOnes32";
case CNMIPS_INTRIN_DPOP:
return "_countOnes64";
+
+ case MIPS_INTRIN_R5900_VWAITQ:
+ return "__vwaitq";
+ case MIPS_INTRIN_R5900_VU_MEM_LOAD:
+ return "__vu_mem_load";
+ case MIPS_INTRIN_R5900_VU_MEM_STORE:
+ return "__vu_mem_store";
+ case MIPS_INTRIN_R5900_VU0_CALLMS:
+ return "__vu0_callms";
+ case MIPS_INTRIN_R5900_VU0_CALLMSR:
+ return "__vu0_callmsr";
+
+ case MIPS_INTRIN_COP0_CONDITION:
+ return "__COP0Condition";
+
default:
return "";
}
@@ -1009,7 +1179,7 @@ public:
virtual vector<uint32_t> GetAllIntrinsics() override
{
- return vector<uint32_t>{
+ auto intrinsics = vector<uint32_t>{
MIPS_INTRIN_WSBH,
MIPS_INTRIN_DSBH,
MIPS_INTRIN_DSHD,
@@ -1061,6 +1231,18 @@ public:
CNMIPS_INTRIN_POP,
CNMIPS_INTRIN_DPOP,
};
+ if (m_version == MIPS_R5900)
+ {
+ auto r5900_intrinsics = {
+ MIPS_INTRIN_R5900_VWAITQ,
+ MIPS_INTRIN_R5900_VU_MEM_LOAD,
+ MIPS_INTRIN_R5900_VU_MEM_STORE,
+ MIPS_INTRIN_R5900_VU0_CALLMS,
+ MIPS_INTRIN_R5900_VU0_CALLMSR,
+ };
+ intrinsics.insert(intrinsics.end(), std::begin(r5900_intrinsics), std::end(r5900_intrinsics));
+ }
+ return intrinsics;
}
virtual vector<NameAndType> GetIntrinsicInputs(uint32_t intrinsic) override
@@ -1217,6 +1399,29 @@ public:
return {
NameAndType("index", Type::IntegerType(8, false)),
};
+
+ case MIPS_INTRIN_R5900_VU_MEM_LOAD:
+ return {
+ NameAndType("offset", Type::IntegerType(4, false)),
+ NameAndType("field", Type::IntegerType(2, false)),
+ };
+ case MIPS_INTRIN_R5900_VU_MEM_STORE:
+ return {
+ NameAndType("offset", Type::IntegerType(4, false)),
+ NameAndType("field", Type::IntegerType(2, false)),
+ NameAndType("value", Type::FloatType(4)),
+ };
+ case MIPS_INTRIN_R5900_VU0_CALLMS:
+ return {
+ NameAndType("address", Type::IntegerType(4, false)),
+ };
+ case MIPS_INTRIN_R5900_VU0_CALLMSR:
+ // return {
+ // NameAndType("reg", Type::IntegerType(4, false)),
+ // };
+
+ case MIPS_INTRIN_COP0_CONDITION:
+ case MIPS_INTRIN_R5900_VWAITQ:
default:
return vector<NameAndType>();
}
@@ -1273,6 +1478,16 @@ public:
};
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<Confidence<Ref<Type>>>();
}
@@ -1457,6 +1672,10 @@ public:
FPREG_F8, FPREG_F9, FPREG_F10, FPREG_F11, FPREG_F12, FPREG_F13, FPREG_F14, FPREG_F15,
FPREG_F16, FPREG_F17, FPREG_F18, FPREG_F19, FPREG_F20, FPREG_F21, FPREG_F22, FPREG_F23,
FPREG_F24, FPREG_F25, FPREG_F26, FPREG_F27, FPREG_F28, FPREG_F29, FPREG_F30, FPREG_F31,
+ FPREG_FCR0, FPREG_FCR1, FPREG_FCR2, FPREG_FCR3, FPREG_FCR4, FPREG_FCR5, FPREG_FCR6, FPREG_FCR7,
+ FPREG_FCR8, FPREG_FCR9, FPREG_FCR10, FPREG_FCR11, FPREG_FCR12, FPREG_FCR13, FPREG_FCR14, FPREG_FCR15,
+ FPREG_FCR16, FPREG_FCR17, FPREG_FCR18, FPREG_FCR19, FPREG_FCR20, FPREG_FCR21, FPREG_FCR22, FPREG_FCR23,
+ FPREG_FCR24, FPREG_FCR25, FPREG_FCR26, FPREG_FCR27, FPREG_FCR28, FPREG_FCR29, FPREG_FCR30, FPREG_FCR31,
FPCCREG_FCC0, FPCCREG_FCC1, FPCCREG_FCC2, FPCCREG_FCC3, FPCCREG_FCC4, FPCCREG_FCC5, FPCCREG_FCC6, FPCCREG_FCC7,
REG_LO, REG_HI,
// Coprocessor 0 register 0
@@ -1561,7 +1780,32 @@ public:
REG_DESAVE,
};
- if ((m_decomposeFlags & DECOMPOSE_FLAGS_CAVIUM) != 0)
+ if (m_version == MIPS_R5900) {
+ // Note: R5900 has 128-bit wide GPRs, $lo and $hi are 128-bit, and $lo1 and $hi1 are the upper 64 bits of $lo and $hi
+ uint32_t r5900_registers[] = {
+ R5900_SA,
+ REG_LO1, REG_HI1,
+
+ REG_VP,
+
+ REG_VI0, REG_VI1, REG_VI2, REG_VI3, REG_VI4, REG_VI5, REG_VI6, REG_VI7, REG_VI8, REG_VI9,
+ REG_VI10, REG_VI11, REG_VI12, REG_VI13, REG_VI14, REG_VI15,
+ REG_VCCR_STATUS, REG_VCCR_MAC, REG_VCCR_CLIPPING, REG_VCCR_19,
+ REG_VR, // CCR[2,20]
+ REG_VI, // CCR[2,21]
+ REG_VQ, // CCR[2,22]
+ REG_VCCR_23, REG_VCCR_24, REG_VCCR_25, REG_VCCR_TPC, REG_VCCR_CMSAR0,
+ REG_VCCR_FBRST, REG_VCCR_VPU_STAT, REG_VCCR_30, REG_VCCR_CMSAR1,
+
+ REG_VACC,
+ REG_VF0, REG_VF1, REG_VF2, REG_VF3, REG_VF4, REG_VF5, REG_VF6, REG_VF7, REG_VF8, REG_VF9,
+ REG_VF10, REG_VF11, REG_VF12, REG_VF13, REG_VF14, REG_VF15, REG_VF16, REG_VF17, REG_VF18, REG_VF19,
+ REG_VF20, REG_VF21, REG_VF22, REG_VF23, REG_VF24, REG_VF25, REG_VF26, REG_VF27, REG_VF28, REG_VF29,
+ REG_VF30, REG_VF31,
+ };
+ registers.insert(registers.end(), std::begin(r5900_registers), std::end(r5900_registers));
+ }
+ else if ((m_decomposeFlags & DECOMPOSE_FLAGS_CAVIUM) != 0)
{
uint32_t cavium_registers[] =
{
@@ -1776,6 +2020,11 @@ public:
FPREG_F8, FPREG_F9, FPREG_F10, FPREG_F11, FPREG_F12, FPREG_F13, FPREG_F14, FPREG_F15,
FPREG_F16, FPREG_F17, FPREG_F18, FPREG_F19, FPREG_F20, FPREG_F21, FPREG_F22, FPREG_F23,
FPREG_F24, FPREG_F25, FPREG_F26, FPREG_F27, FPREG_F28, FPREG_F29, FPREG_F30, FPREG_F31,
+ FPREG_FCR0, FPREG_FCR1, FPREG_FCR2, FPREG_FCR3, FPREG_FCR4, FPREG_FCR5, FPREG_FCR6, FPREG_FCR7,
+ FPREG_FCR8, FPREG_FCR9, FPREG_FCR10, FPREG_FCR11, FPREG_FCR12, FPREG_FCR13, FPREG_FCR14, FPREG_FCR15,
+ FPREG_FCR16, FPREG_FCR17, FPREG_FCR18, FPREG_FCR19, FPREG_FCR20, FPREG_FCR21, FPREG_FCR22, FPREG_FCR23,
+ FPREG_FCR24, FPREG_FCR25, FPREG_FCR26, FPREG_FCR27, FPREG_FCR28, FPREG_FCR29, FPREG_FCR30, FPREG_FCR31,
+
REG_LO, REG_HI,
// Coprocessor 0 register 0
REG_INDEX,
@@ -1879,7 +2128,39 @@ public:
REG_DESAVE,
};
- if ((m_decomposeFlags & DECOMPOSE_FLAGS_CAVIUM) != 0)
+ if (m_version == MIPS_R5900) {
+ // TODO: R5900 has 128-bit wide GPRs, $lo and $hi are 128-bit, and $lo1 and $hi1 are the upper 64 bits of $lo and $hi
+ uint32_t r5900_registers[] = {
+ R5900_SA,
+ REG_LO1, REG_HI1,
+ REG_VP,
+
+ REG_VI0, REG_VI1, REG_VI2, REG_VI3, REG_VI4, REG_VI5, REG_VI6, REG_VI7, REG_VI8, REG_VI9,
+ REG_VI10, REG_VI11, REG_VI12, REG_VI13, REG_VI14, REG_VI15,
+ REG_VCCR_STATUS, REG_VCCR_MAC, REG_VCCR_CLIPPING, REG_VCCR_19,
+ REG_VR, // CCR[2,20]
+ REG_VI, // CCR[2,21]
+ REG_VQ, // CCR[2,22]
+ REG_VCCR_23, REG_VCCR_24, REG_VCCR_25, REG_VCCR_TPC, REG_VCCR_CMSAR0,
+ REG_VCCR_FBRST, REG_VCCR_VPU_STAT, REG_VCCR_30, REG_VCCR_CMSAR1,
+
+ REG_VACC,
+ REG_VF0, REG_VF1, REG_VF2, REG_VF3, REG_VF4, REG_VF5, REG_VF6, REG_VF7, REG_VF8, REG_VF9,
+ REG_VF10, REG_VF11, REG_VF12, REG_VF13, REG_VF14, REG_VF15, REG_VF16, REG_VF17, REG_VF18, REG_VF19,
+ REG_VF20, REG_VF21, REG_VF22, REG_VF23, REG_VF24, REG_VF25, REG_VF26, REG_VF27, REG_VF28, REG_VF29,
+ REG_VF30, REG_VF31,
+ };
+ registers.insert(registers.end(), std::begin(r5900_registers), std::end(r5900_registers));
+ constexpr auto _r5900_registers_vpu = []() {
+ vector<Reg> registers;
+ for (uint32_t i = REG_VACC_X; i < REG_VF31_XYZW; i++)
+ registers.push_back((Reg) i);
+ return registers;
+ };
+ auto r5900_registers_vpu = _r5900_registers_vpu();
+ registers.insert(registers.end(), r5900_registers_vpu.begin(), r5900_registers_vpu.end());
+ }
+ else if ((m_decomposeFlags & DECOMPOSE_FLAGS_CAVIUM) != 0)
{
uint32_t cavium_registers[] =
{
@@ -2089,6 +2370,45 @@ public:
virtual BNRegisterInfo GetRegisterInfo(uint32_t reg) override
{
BNRegisterInfo result = {reg, 0, m_bits / 8, NoExtend};
+ if (m_version == MIPS_R5900) {
+ result.size = get_register_width(reg, m_version, 16);
+ switch (reg) {
+ // case REG_LO:
+ // case REG_HI:
+ // result.size = 64 / 8;
+ // break;
+ case REG_LO1:
+ case REG_HI1:
+ // result.size = (128 / 2);
+ result.offset = 8;
+ if (reg == REG_LO1)
+ result.fullWidthRegister = REG_LO;
+ else if (reg == REG_HI1)
+ result.fullWidthRegister = REG_HI;
+ break;
+ default:
+ if (reg >= REG_VACC_X && reg <= REG_VF31_XYZW)
+ {
+ result.fullWidthRegister = REG_VACC + ((reg - REG_VACC_X) % 33);
+ if (reg >= REG_VACC_Y && reg <= REG_VF31_Y)
+ result.offset = 4;
+ else if (reg >= REG_VACC_Z && reg <= REG_VF31_Z)
+ result.offset = 8;
+ else if (reg >= REG_VACC_W && reg <= REG_VF31_W)
+ result.offset = 12;
+
+ else if (reg >= REG_VACC_YZ && reg <= REG_VF31_YZ)
+ result.offset = 4;
+ else if (reg >= REG_VACC_ZW && reg <= REG_VF31_ZW)
+ result.offset = 12;
+
+ else if (reg >= REG_VACC_YZW && reg <= REG_VF31_YZW)
+ result.offset = 4;
+
+ // XXX: offsets are just wrong for discontinuous registers: XZ, XW, YW, XYW, XZW
+ }
+ }
+ }
return result;
}
@@ -2408,6 +2728,9 @@ public:
return registers;
}
+ MipsVersion GetMIPSVersion() {
+ return m_version;
+ }
};
class MipsO32CallingConvention: public CallingConvention
@@ -2471,6 +2794,77 @@ public:
}
};
+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<uint32_t> GetIntegerArgumentRegisters() override
+ {
+ return vector<uint32_t>{ REG_A0, REG_A1, REG_A2, REG_A3, REG_T0, REG_T1, REG_T2, REG_T3 };
+ }
+
+ virtual vector<uint32_t> GetFloatArgumentRegisters() override
+ {
+ return vector<uint32_t>{ 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<uint32_t> GetCallerSavedRegisters() override
+ {
+ return vector<uint32_t> { 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<uint32_t> GetCalleeSavedRegisters() override
+ {
+ return vector<uint32_t> { 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<uint32_t> GetImplicitlyDefinedRegisters() override
+ {
+ return vector<uint32_t> { 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:
@@ -3018,7 +3412,8 @@ public:
uint32_t inst2 = *(uint32_t*)(cur->relocationDataCache);
Instruction instruction;
memset(&instruction, 0, sizeof(instruction));
- if (mips_decompose(&inst2, sizeof(uint32_t), &instruction, arch->GetAddressSize() == 8 ? MIPS_64 : MIPS_32, cur->address, arch->GetEndianness(), DECOMPOSE_FLAGS_PSEUDO_OP))
+ MipsArchitecture& march = dynamic_cast<MipsArchitecture&>(*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;
@@ -3082,6 +3477,7 @@ public:
dest64[0] = swap64(originalValue + displacement);
break;
}
+ case R_MIPS_LITERAL:
case R_MIPS_GPREL32:
{
if (!GetGpAddr(view, gpAddr))
@@ -3090,6 +3486,8 @@ public:
dest32[0] = swap(vRel32);
break;
}
+ case R_MIPS_VCALLMS:
+ break;
default:
break;
}
@@ -3169,6 +3567,10 @@ public:
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,
@@ -3246,6 +3648,9 @@ static Ref<Platform> ElfFlagsRecognize(BinaryView* view, Metadata* metadata)
case 0x8e: // EF_MIPS_MACH_OCTEON3
LogInfo("ELF flags 0x%08" PRIx64 " machine variant 0x%02x: using cavium architecture", flagsValue, machineVariant);
return Platform::GetByName("linux-cnmips64");
+ case 0x92: // E_MIPS_MACH_5900
+ LogInfo("ELF flags 0x%08" PRIx64 " machine variant 0x%02x: using R5900 architecture", flagsValue, machineVariant);
+ return Platform::GetByName("r5900l");
default:
return nullptr;
}
@@ -3267,16 +3672,21 @@ 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);
+ // R5900 should only be Little-Endian, so until someone complains, I'm leaving the Big-Endian variant disabled.
+ // 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,6 +3699,8 @@ extern "C"
MipsN64CallingConvention* n64LE = new MipsN64CallingConvention(mips64el);
MipsN64CallingConvention* n64BE = new MipsN64CallingConvention(mips64eb);
MipsN64CallingConvention* n64BEc = new MipsN64CallingConvention(cnmips64eb);
+ MipsPS2CallingConvention* ps2LE = new MipsPS2CallingConvention(r5900l);
+ // MipsPS2CallingConvention* ps2BE = new MipsPS2CallingConvention(r5900b);
mipseb->RegisterCallingConvention(o32BE);
mipseb->SetDefaultCallingConvention(o32BE);
@@ -3296,24 +3708,36 @@ extern "C"
mipsel->SetDefaultCallingConvention(o32LE);
mips3->RegisterCallingConvention(o32BE);
mips3->SetDefaultCallingConvention(o32BE);
- mips3->RegisterCallingConvention(o32LE);
- mips3->SetDefaultCallingConvention(o32LE);
+ mips3el->RegisterCallingConvention(o32LE);
+ mips3el->SetDefaultCallingConvention(o32LE);
mips64el->RegisterCallingConvention(n64LE);
mips64el->SetDefaultCallingConvention(n64LE);
mips64eb->RegisterCallingConvention(n64BE);
mips64eb->SetDefaultCallingConvention(n64BE);
cnmips64eb->RegisterCallingConvention(n64BEc);
cnmips64eb->SetDefaultCallingConvention(n64BEc);
+ r5900l->RegisterCallingConvention(ps2LE);
+ r5900l->SetDefaultCallingConvention(ps2LE);
+ // r5900b->RegisterCallingConvention(ps2BE);
+ // r5900b->SetDefaultCallingConvention(ps2BE);
- MipsLinuxSyscallCallingConvention* linuxSyscallLE = new MipsLinuxSyscallCallingConvention(mipsel);
MipsLinuxSyscallCallingConvention* linuxSyscallBE = new MipsLinuxSyscallCallingConvention(mipseb);
+ MipsLinuxSyscallCallingConvention* linuxSyscallLE = new MipsLinuxSyscallCallingConvention(mipsel);
mipseb->RegisterCallingConvention(linuxSyscallBE);
mipsel->RegisterCallingConvention(linuxSyscallLE);
- mips3->RegisterCallingConvention(linuxSyscallBE);
- mips3el->RegisterCallingConvention(linuxSyscallLE);
+ MipsLinuxSyscallCallingConvention* linuxSyscallBE3 = new MipsLinuxSyscallCallingConvention(mips3);
+ MipsLinuxSyscallCallingConvention* linuxSyscallLE3 = new MipsLinuxSyscallCallingConvention(mips3el);
+ mips3->RegisterCallingConvention(linuxSyscallBE3);
+ mips3el->RegisterCallingConvention(linuxSyscallLE3);
+ 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));
@@ -3321,8 +3745,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());
@@ -3330,8 +3754,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
@@ -3354,6 +3780,7 @@ extern "C"
{
elf->RegisterPlatformRecognizer(ARCH_ID_MIPS64, LittleEndian, ElfFlagsRecognize);
elf->RegisterPlatformRecognizer(ARCH_ID_MIPS64, BigEndian, ElfFlagsRecognize);
+ elf->RegisterPlatformRecognizer(ARCH_ID_MIPS32, LittleEndian, ElfFlagsRecognize); // R5900
}
BinaryViewType::RegisterArchitecture("PE", 0x166, LittleEndian, mipsel);
diff --git a/arch/mips/il.cpp b/arch/mips/il.cpp
index 331d3d13..bfbfeeed 100644
--- a/arch/mips/il.cpp
+++ b/arch/mips/il.cpp
@@ -1,10 +1,18 @@
#include "il.h"
+#include "mips.h"
+
using namespace BinaryNinja;
using namespace mips;
#define INVALID_EXPRID ((uint32_t)-1)
+#define INVALID_OPERATION \
+ default: \
+ LogWarn("Invalid operation"); \
+ il.AddInstruction(il.Unimplemented()); \
+ return false
+
typedef enum {
ZeroExtend,
SignExtend,
@@ -61,6 +69,260 @@ 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
+ {
+ uint64_t clamp_overflow = 0x7FFFFFFF >> (32 - (8 * bytes));
+ uint64_t clamp_under_lower_bound = 0x100000000 >> (32 - (8 * bytes));
+ uint64_t clamp_under_upper_bound = 0x180000000 >> (32 - (8 * bytes));
+ // uint64_t clamp4 = 0x80000000 >> (32 - (8 * bytes)); // clamp3 - clamp2
+ uint64_t clamp_underflow = clamp_under_upper_bound - clamp_under_lower_bound;
+
+ // Note: the Operation definition shows the overflow check before the underflow check, but
+ // that would mean an underflow would be detected as an overflow, and the underflow clamp
+ // would never be applied. So we do the underflow check first, under the assumption the
+ // reference manual is incorrect but the implementation in hardware would be correct.
+
+ auto comparison_underflow = il.And(1,
+ il.CompareSignedGreaterThan(2 * bytes,
+ il.Register(2 * bytes, LLIL_TEMP(1)),
+ il.Const(2 * bytes, clamp_under_lower_bound)),
+ il.CompareSignedLessThan(bytes,
+ il.Register(2 * bytes, LLIL_TEMP(1)),
+ il.Const(2 * bytes, clamp_under_upper_bound)));
+ auto comparison_overflow = il.CompareSignedGreaterThan(bytes,
+ il.Register(2 * bytes, LLIL_TEMP(1)),
+ il.Const(2 * bytes, clamp_overflow));
+
+ LowLevelILLabel trueCase1, trueCase2, falseCase1, falseCase2, done;
+ il.AddInstruction(il.If(comparison_underflow, trueCase1, falseCase1));
+
+ il.MarkLabel(trueCase1);
+ il.AddInstruction(il.SetRegister(bytes, LLIL_TEMP(1), il.Const(bytes, clamp_underflow)));
+ il.AddInstruction(il.Goto(done));
+
+ il.MarkLabel(falseCase1);
+ il.AddInstruction(il.If(comparison_overflow, trueCase2, done));
+
+ il.MarkLabel(trueCase2);
+ il.AddInstruction(il.SetRegister(bytes, LLIL_TEMP(1), il.Const(bytes, clamp_overflow)));
+
+ il.MarkLabel(done);
+
+ sum = il.Register(bytes, LLIL_TEMP(1));
+
+ }
+ }
+
+ auto shifted_sum = i == 0 ? sum : il.ShiftLeft(16, sum, il.Const(1, shift));
+ if (i == 0)
+ {
+ il.AddInstruction(il.SetRegister(16, op1.reg, shifted_sum));
+ }
+ else
+ {
+ il.AddInstruction(il.SetRegister(16, op1.reg, il.Or(16, il.Register(16, op1.reg), shifted_sum)));
+ }
+ }
+ }
+}
+
+static void ParallelMinMax(LowLevelILFunction& il, Instruction& instr, size_t bytes, bool max=false)
+{
+ // Perform saturating addition by applying the optimizations from https://web.archive.org/web/20190213215419/https://locklessinc.com/articles/sat_arithmetic/
+ // TODO: optimize signed case by applying above link
+ InstructionOperand& op1 = instr.operands[0]; // rd
+ InstructionOperand& op2 = instr.operands[1]; // rs
+ InstructionOperand& op3 = instr.operands[2]; // rt
+
+ // Simple case: if either rs or rt is $zero, then it's equivalent to a 128-bit move
+ if (op3.reg == REG_ZERO && op2.reg == REG_ZERO)
+ il.AddInstruction(il.SetRegister(16, op1.reg, il.Const(16, 0)));
+ else
+ {
+ // Mask of the appropriate size for the pieces of rs and rd
+ const uint64_t mask = 0xFFFFFFFFFFFFFFFF >> (64 - (8 * bytes));
+
+ // Perform the appropriate number of piecewise additions, saturating if needed, then combine into the rd register
+ for (int i = 0; i < 16 / bytes; i++)
+ {
+ // How much to shift the piece
+ size_t shift = i * 8 * bytes;
+ ExprId rs_shifted = op2.reg != REG_ZERO ? il.Register(16, op2.reg) : il.Const(bytes, 0);
+ ExprId rt_shifted = op3.reg != REG_ZERO ? il.Register(16, op3.reg) : il.Const(bytes, 0);
+
+ // Only need to shift if it's not the lowest-order piece
+ if (i > 0)
+ {
+ if (op2.reg != REG_ZERO)
+ rs_shifted = il.LogicalShiftRight( 16, rs_shifted, il.Const(1, shift));
+ if (op3.reg != REG_ZERO)
+ rt_shifted = il.LogicalShiftRight( 16, rt_shifted, il.Const(1, shift));
+ }
+
+ // Mask the (shifted) piece to the appropriate size
+ if (op2.reg != REG_ZERO)
+ rs_shifted = il.And(bytes, rs_shifted, il.Const(128, mask));
+ if (op3.reg != REG_ZERO)
+ rt_shifted = il.And(bytes, rt_shifted, il.Const(128, mask));
+
+ if (i == 0)
+ il.AddInstruction(il.SetRegister(16, LLIL_TEMP(2), il.Const(bytes, 0)));
+
+ ExprId lhs = op2.reg != REG_ZERO ? il.Register(bytes, LLIL_TEMP(0)) : il.Const(bytes, 0);
+ ExprId rhs = op3.reg != REG_ZERO ? il.Register(bytes, LLIL_TEMP(1)) : il.Const(bytes, 0);
+ // if (op2.reg != REG_ZERO)
+ il.AddInstruction(il.SetRegister(bytes, LLIL_TEMP(0), rs_shifted));
+ // if (op3.reg != REG_ZERO)
+ il.AddInstruction(il.SetRegister(bytes, LLIL_TEMP(1), rt_shifted));
+ if (!max)
+ ConditionExecute(il,
+ il.CompareSignedLessThan(bytes,
+ lhs, rhs),
+ il.SetRegister(bytes, LLIL_TEMP(1), lhs));
+ else
+ ConditionExecute(il,
+ il.CompareSignedGreaterThan(bytes,
+ lhs, rhs),
+ il.SetRegister(bytes, LLIL_TEMP(1), lhs));
+ ExprId sum = il.Register(bytes, LLIL_TEMP(1));
+
+ auto shifted_sum = i == 0 ? sum : il.ShiftLeft(16, sum, il.Const(1, shift));
+ if (i == 0)
+ {
+ il.AddInstruction(il.SetRegister(16, LLIL_TEMP(2), shifted_sum));
+ }
+ else
+ {
+ il.AddInstruction(il.SetRegister(16, LLIL_TEMP(2), il.Or(16, il.Register(16, LLIL_TEMP(2)), shifted_sum)));
+ }
+ }
+ il.AddInstruction(il.SetRegister(16, op1.reg, il.Register(16, LLIL_TEMP(2))));
+ }
+}
static size_t GetILOperandMemoryAddress(LowLevelILFunction& il, InstructionOperand& operand, size_t addrSize, int32_t delta=0)
{
@@ -188,34 +450,42 @@ 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<size_t(InstructionOperand&)> 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));
+ case MIPS_BGEZALL:
+ 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));
+ case MIPS_BLTZALL:
+ return il.CompareSignedLessThan(registerSize(op1), ReadILOperand(il, instr, 1, registerSize(op1)), il.Const(registerSize(op1), 0));
case MIPS_BC1F:
case MIPS_BC1FL:
if (instr.operands[0].operandClass == FLAG)
@@ -226,37 +496,49 @@ ExprId GetConditionForInstruction(LowLevelILFunction& il, Instruction& instr, si
if (instr.operands[0].operandClass == FLAG)
return il.Flag(instr.operands[0].reg);
return il.Flag(FPCCREG_FCC0);
+ case MIPS_BC0F:
+ case MIPS_BC0FL:
+ return il.Not(0, il.Flag(CCREG_COC0));
+ case MIPS_BC0T:
+ case MIPS_BC0TL:
+ return il.Flag(CCREG_COC0);
+ case MIPS_BC2F:
+ case MIPS_BC2FL:
+ return il.Not(0, il.Flag(CCREG_COC2));
+ case MIPS_BC2T:
+ case MIPS_BC2TL:
+ return il.Flag(CCREG_COC2);
case CNMIPS_BBIT0:
- return il.CompareEqual(registerSize,
- il.And(registerSize,
- ReadILOperand(il, instr, 1, registerSize),
- il.Const(registerSize, 1 << instr.operands[1].immediate)
+ return il.CompareEqual(registerSize(op1),
+ il.And(registerSize(op1),
+ ReadILOperand(il, instr, 1, registerSize(op1)),
+ il.Const(registerSize(op1), 1 << instr.operands[1].immediate)
),
- il.Const(registerSize, 0)
+ il.Const(registerSize(op1), 0)
);
case CNMIPS_BBIT032:
- return il.CompareEqual(registerSize,
- il.And(registerSize,
- ReadILOperand(il, instr, 1, registerSize),
- il.Const(registerSize, ((uint64_t)1) << (instr.operands[1].immediate + 32))
+ return il.CompareEqual(registerSize(op1),
+ il.And(registerSize(op1),
+ ReadILOperand(il, instr, 1, registerSize(op1)),
+ il.Const(registerSize(op1), ((uint64_t)1) << (instr.operands[1].immediate + 32))
),
- il.Const(registerSize, 0)
+ il.Const(registerSize(op1), 0)
);
case CNMIPS_BBIT1:
- return il.CompareNotEqual(registerSize,
- il.And(registerSize,
- ReadILOperand(il, instr, 1, registerSize),
- il.Const(registerSize, 1 << instr.operands[1].immediate)
+ return il.CompareNotEqual(registerSize(op1),
+ il.And(registerSize(op1),
+ ReadILOperand(il, instr, 1, registerSize(op1)),
+ il.Const(registerSize(op1), 1 << instr.operands[1].immediate)
),
- il.Const(registerSize, 0)
+ il.Const(registerSize(op1), 0)
);
case CNMIPS_BBIT132:
- return il.CompareNotEqual(registerSize,
- il.And(registerSize,
- ReadILOperand(il, instr, 1, registerSize),
- il.Const(registerSize, ((uint64_t)1) << (instr.operands[1].immediate + 32))
+ return il.CompareNotEqual(registerSize(op1),
+ il.And(registerSize(op1),
+ ReadILOperand(il, instr, 1, registerSize(op1)),
+ il.Const(registerSize(op1), ((uint64_t)1) << (instr.operands[1].immediate + 32))
),
- il.Const(registerSize, 0)
+ il.Const(registerSize(op1), 0)
);
default:
@@ -796,7 +1078,16 @@ static void SignExtendHiLo(LowLevelILFunction& il, size_t registerSize)
}
}
-bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFunction& il, Instruction& instr, size_t addrSize, uint32_t decomposeFlags)
+#define DEFINE_HILO1(op) \
+ auto hi = REG_HI; \
+ auto lo = REG_LO; \
+ if (instr.operation == op) \
+ { \
+ hi = REG_HI1; \
+ lo = REG_LO1; \
+ }
+
+bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFunction& il, Instruction& instr, size_t addrSize, uint32_t decomposeFlags, MipsVersion version)
{
LowLevelILLabel trueLabel, falseLabel, doneLabel, dirFlagSet, dirFlagClear, dirFlagDone;
InstructionOperand& op1 = instr.operands[0];
@@ -804,939 +1095,1264 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu
InstructionOperand& op3 = instr.operands[2];
InstructionOperand& op4 = instr.operands[3];
LowLevelILLabel trueCode, falseCode, again;
- size_t registerSize = addrSize;
+ size_t bytes = 4;
+ bool signedFlag = false;
+ ExtendType extendType = 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)
{
- case MIPS_ADD:
- case MIPS_ADDU:
- 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)));
- else
- il.AddInstruction(
- SetRegisterOrNop(il, 4, registerSize, op1.reg,
- il.Add(4,
- ReadILOperand(il, instr, 2, registerSize, 4),
- ReadILOperand(il, instr, 3, registerSize, 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)));
- else
- il.AddInstruction(
- SetRegisterOrNop(il, 8, registerSize, op1.reg,
- il.Add(8,
- ReadILOperand(il, instr, 2, registerSize),
- ReadILOperand(il, instr, 3, registerSize))));
- break;
- case MIPS_SUB:
- case MIPS_SUBU:
- il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg,
- il.Sub(4,
- ReadILOperand(il, instr, 2, registerSize, 4),
- ReadILOperand(il, instr, 3, registerSize, 4))));
- break;
- case MIPS_DSUB:
- case MIPS_DSUBU:
- il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg,
- il.Sub(8,
- ReadILOperand(il, instr, 2, registerSize, 8),
- ReadILOperand(il, instr, 3, registerSize, 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))));
- break;
- case MIPS_ANDI:
- il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg,
- il.And(registerSize,
- ReadILOperand(il, instr, 2, registerSize),
- il.Operand(1, il.Const(4, 0x0000ffff & op3.immediate)))));
- 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.ModSigned(4,
- ReadILOperand(il, instr, 1, registerSize, 4),
- ReadILOperand(il, instr, 2, registerSize, 4))));
- SignExtendHiLo(il, registerSize);
- break;
- case MIPS_DIVU:
- il.AddInstruction(il.SetRegister(4, REG_LO,
- il.DivUnsigned(4,
- ReadILOperand(il, instr, 1, registerSize, 4),
- ReadILOperand(il, instr, 2, registerSize, 4))));
- il.AddInstruction(il.SetRegister(4, REG_HI,
- il.ModUnsigned(4,
- ReadILOperand(il, instr, 1, registerSize, 4),
- ReadILOperand(il, instr, 2, registerSize, 4))));
- SignExtendHiLo(il, registerSize);
- break;
- case MIPS_DDIV:
- il.AddInstruction(il.SetRegister(8, REG_LO,
- il.DivSigned(8,
- ReadILOperand(il, instr, 1, registerSize, 8),
- ReadILOperand(il, instr, 2, registerSize, 8))));
- il.AddInstruction(il.SetRegister(8, REG_HI,
- il.ModSigned(8,
- ReadILOperand(il, instr, 1, registerSize, 8),
- ReadILOperand(il, instr, 2, registerSize, 8))));
- break;
- case MIPS_DDIVU:
- il.AddInstruction(il.SetRegister(8, REG_LO,
- il.DivUnsigned(8,
- ReadILOperand(il, instr, 1, registerSize, 8),
- ReadILOperand(il, instr, 2, registerSize, 8))));
- il.AddInstruction(il.SetRegister(8, REG_HI,
- il.ModUnsigned(8,
- ReadILOperand(il, instr, 1, registerSize, 8),
- ReadILOperand(il, instr, 2, registerSize, 8))));
- break;
- case MIPS_MUL:
- il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg,
- il.Mult(4,
- ReadILOperand(il, instr, 2, registerSize, 4),
- ReadILOperand(il, instr, 3, registerSize, 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))));
- break;
- case MIPS_XORI:
- il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg,
- il.Xor(registerSize,
- ReadILOperand(il, instr, 2, registerSize),
- il.Operand(1,il.Const(4, 0x0000ffff & op3.immediate)))));
- break;
- case MIPS_B:
- case MIPS_J:
- il.AddInstruction(DirectJump(arch, il, op1.immediate, addrSize));
- break;
- case MIPS_JAL:
- case MIPS_BAL:
- if (op1.immediate == (addr + 8)) // Get PC construct
- il.AddInstruction(il.SetRegister(addrSize, REG_RA, il.ConstPointer(addrSize ,addr + 8)));
- else
- il.AddInstruction(il.Call(il.ConstPointer(addrSize, op1.immediate)));
+ 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:
+ extendType = ZeroExtend;
+ case MIPS_ADD:
+ case MIPS_ADDI:
+ if (op2.reg == REG_ZERO)
+ il.AddInstruction(SetRegisterOrNop(il, 4, registerSize(op1), op1.reg, ReadILOperand(il, instr, 3, registerSize(op3), 4), extendType));
+ else
+ il.AddInstruction(
+ SetRegisterOrNop(il, 4, registerSize(op1), op1.reg,
+ il.Add(4,
+ ReadILOperand(il, instr, 2, registerSize(op2), 4),
+ ReadILOperand(il, instr, 3, registerSize(op3), 4)), extendType));
+ break;
+ case MIPS_DADDU:
+ case MIPS_DADDIU:
+ extendType = ZeroExtend;
+ 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)), extendType));
+ else
+ il.AddInstruction(
+ SetRegisterOrNop(il, 8, registerSize(op1), op1.reg,
+ il.Add(8,
+ ReadILOperand(il, instr, 2, registerSize(op2)),
+ ReadILOperand(il, instr, 3, registerSize(op3))), extendType));
+ break;
+ case MIPS_SUBU:
+ extendType = ZeroExtend;
+ 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)), extendType));
+ break;
+ case MIPS_DSUBU:
+ extendType = ZeroExtend;
+ case MIPS_DSUB:
+ il.AddInstruction(SetRegisterOrNop(il, 8, registerSize(op1), op1.reg,
+ il.Sub(8,
+ ReadILOperand(il, instr, 2, registerSize(op2), 8),
+ ReadILOperand(il, instr, 3, registerSize(op3), 8)), extendType));
+ break;
+ case MIPS_AND:
+ il.AddInstruction(SetRegisterOrNop(il, registerSize(op2), registerSize(op1), op1.reg,
+ il.And(registerSize(op2),
+ ReadILOperand(il, instr, 2, registerSize(op2)),
+ ReadILOperand(il, instr, 3, registerSize(op3))), ZeroExtend));
+ break;
+ case MIPS_ANDI:
+ il.AddInstruction(SetRegisterOrNop(il, registerSize(op2), registerSize(op1), op1.reg,
+ il.And(registerSize(op2),
+ ReadILOperand(il, instr, 2, registerSize(op2)),
+ il.Operand(1, il.Const(4, 0x0000ffff & op3.immediate))), ZeroExtend));
+ break;
+ case MIPS_DIV:
+ il.AddInstruction(il.SetRegister(get_register_width(REG_LO, version), REG_LO,
+ 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, 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:
+ {
+ DEFINE_HILO1(MIPS_DIVU1);
+ il.AddInstruction(il.SetRegister(get_register_width(lo, version), lo,
+ il.DivUnsigned(4,
+ 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, 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,
+ 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(op1), 8),
+ ReadILOperand(il, instr, 2, registerSize(op2), 8))));
+ break;
+ case MIPS_DDIVU:
+ il.AddInstruction(il.SetRegister(get_register_width(REG_LO, version), REG_LO,
+ il.DivUnsigned(8,
+ 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(op1), 8),
+ ReadILOperand(il, instr, 2, registerSize(op2), 8))));
+ break;
+ case MIPS_MUL:
+ il.AddInstruction(SetRegisterOrNop(il, 4, registerSize(op1), op1.reg,
+ il.Mult(4,
+ ReadILOperand(il, instr, 2, registerSize(op2), 4),
+ ReadILOperand(il, instr, 3, registerSize(op3), 4))));
+ break;
+ case MIPS_XOR:
+ il.AddInstruction(SetRegisterOrNop(il, registerSize(op1), registerSize(op1), op1.reg,
+ il.Xor(registerSize(op2),
+ ReadILOperand(il, instr, 2, registerSize(op2)),
+ ReadILOperand(il, instr, 3, registerSize(op3))), ZeroExtend));
+ break;
+ case MIPS_XORI:
+ il.AddInstruction(SetRegisterOrNop(il, registerSize(op1), registerSize(op1), op1.reg,
+ il.Xor(registerSize(op2),
+ ReadILOperand(il, instr, 2, registerSize(op2)),
+ il.Operand(1,il.Const(registerSize(op2), 0x0000ffff & op3.immediate))), ZeroExtend));
+ break;
+ case MIPS_B:
+ case MIPS_J:
+ il.AddInstruction(DirectJump(arch, il, op1.immediate, addrSize));
+ break;
+ case MIPS_JAL:
+ case MIPS_BAL:
+ if (op1.immediate == (addr + 8)) // Get PC construct
+ il.AddInstruction(il.SetRegister(addrSize, REG_RA, il.ConstPointer(addrSize ,addr + 8)));
+ else
+ il.AddInstruction(il.Call(il.ConstPointer(addrSize, op1.immediate)));
+ break;
- case MIPS_BEQ:
- case MIPS_BNE:
- case MIPS_BEQL: //Branch likely
- case MIPS_BNEL:
- ConditionalJump(arch, il, GetConditionForInstruction(il, instr, registerSize), addrSize, op3.immediate, addr + 8);
- return false;
+ case MIPS_BEQ:
+ case MIPS_BNE:
+ case MIPS_BEQL: //Branch likely
+ case MIPS_BNEL:
+ ConditionalJump(arch, il, GetConditionForInstruction(il, instr, registerSize), addrSize, op3.immediate, addr + 8);
+ return false;
+
+ case MIPS_BEQZ:
+ case MIPS_BGEZ:
+ case MIPS_BGTZ:
+ case MIPS_BLEZ:
+ case MIPS_BLTZ:
+ case MIPS_BNEZ:
+ case MIPS_BGEZL: //Branch likely
+ case MIPS_BGTZL:
+ case MIPS_BLEZL:
+ case MIPS_BLTZL:
+ ConditionalJump(arch, il, GetConditionForInstruction(il, instr, registerSize), addrSize, op2.immediate, addr + 8);
+ return false;
- case MIPS_BEQZ:
- case MIPS_BGEZ:
- case MIPS_BGTZ:
- case MIPS_BLEZ:
- case MIPS_BLTZ:
- case MIPS_BNEZ:
- case MIPS_BGEZL: //Branch likely
- case MIPS_BGTZL:
- case MIPS_BLEZL:
- case MIPS_BLTZL:
- ConditionalJump(arch, il, GetConditionForInstruction(il, instr, registerSize), addrSize, op2.immediate, addr + 8);
- return false;
+ case MIPS_BC1F:
+ case MIPS_BC1FL:
+ 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(FPCCREG_FCC0)), addrSize, op1.immediate, addr + 8);
+ return false;
- case MIPS_BC1F:
- case MIPS_BC1FL:
- 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(FPCCREG_FCC0)), addrSize, op1.immediate, addr + 8);
- return false;
+ case MIPS_BC1T:
+ case MIPS_BC1TL:
+ if (op1.operandClass == FLAG)
+ ConditionalJump(arch, il, il.Flag(op1.reg), addrSize, op2.immediate, addr + 8);
+ else
+ ConditionalJump(arch, il, il.Flag(FPCCREG_FCC0), addrSize, op1.immediate, addr + 8);
+ return false;
- case MIPS_BC1T:
- case MIPS_BC1TL:
- if (op1.operandClass == FLAG)
- ConditionalJump(arch, il, il.Flag(op1.reg), addrSize, op2.immediate, addr + 8);
- else
- 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_BGEZAL:
- case MIPS_BLTZAL:
- il.AddInstruction(il.If(GetConditionForInstruction(il, instr, registerSize), trueCode, falseCode));
- il.MarkLabel(trueCode);
- il.AddInstruction(il.Call(ReadILOperand(il, instr, 2, registerSize)));
- il.MarkLabel(falseCode);
- break;
+ 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_BREAK:
- il.AddInstruction(il.Breakpoint());
- break;
- case MIPS_CLO:
- //count leading ones
- //algorithm is as follows
- //
- //tmp0 = 0;
- //again:
- //if (((op2 << tmp) & 0x80000000) != 0)
- //{
- // tmp0 += 1;
- // goto again;
- //}
- //
- 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.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)))));
- il.AddInstruction(il.Goto(again));
- il.MarkLabel(falseCode);
- break;
- case MIPS_DCLO:
- //count leading ones
- //algorithm is as follows
- //
- //tmp0 = 0;
- //again:
- //if (((op2 << tmp) & 0x80000000_00000000) != 0)
- //{
- // tmp0 += 1;
- // goto again;
- //}
- //
- 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.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)))));
- il.AddInstruction(il.Goto(again));
- il.MarkLabel(falseCode);
- break;
- case MIPS_CLZ:
- //count leading zeroes
- //algorithm is as follows
- //
- //tmp0 = 0;
- //again:
- //if (((op2 << tmp) & 0x80000000) == 0)
- //{
- // tmp0 += 1;
- // goto again;
- //}
- //
- 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.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)))));
- il.AddInstruction(il.Goto(again));
- il.MarkLabel(falseCode);
- break;
- case MIPS_DCLZ:
- //count leading zeroes
- //algorithm is as follows
- //
- //tmp0 = 0;
- //again:
- //if (((op2 << tmp) & 0x80000000_00000000) == 0)
- //{
- // tmp0 += 1;
- // goto again;
- //}
- //
- 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.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)))));
- il.AddInstruction(il.Goto(again));
- il.MarkLabel(falseCode);
- break;
- case MIPS_JALR:
- case MIPS_JALR_HB:
- {
- uint32_t operand = 1;
- if (instr.operands[1].operandClass != NONE)
- {
- operand = 2;
- }
- il.AddInstruction(il.Call(ReadILOperand(il, instr, operand, registerSize, addrSize, true)));
- }
- break;
- case MIPS_JR:
- case MIPS_JR_HB:
- if (op1.reg == REG_RA)
- il.AddInstruction(il.Return(ReadILOperand(il, instr, 1, registerSize)));
- else
- il.AddInstruction(il.Jump(ReadILOperand(il, instr, 1, registerSize)));
- return false;
- case MIPS_ERET:
- il.AddInstruction(il.Return(il.Register(registerSize, 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))));
- break;
- case MIPS_LB:
- il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.SignExtend(registerSize, ReadILOperand(il, instr, 2, registerSize, 1))));
- break;
- case MIPS_MFHI:
- il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.Register(registerSize, REG_HI)));
- break;
- case MIPS_MFLO:
- il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.Register(registerSize, REG_LO)));
- break;
- case MIPS_MTHI:
- il.AddInstruction(il.SetRegister(registerSize, REG_HI, ReadILOperand(il, instr, 1, registerSize)));
- break;
- case MIPS_MTLO:
- il.AddInstruction(il.SetRegister(registerSize, REG_LO, ReadILOperand(il, instr, 1, registerSize)));
- break;
- case MIPS_DMFC0:
- il.AddInstruction(MoveFromCoprocessor(0, il, 8, op1.reg, op2.immediate, op3.immediate, decomposeFlags));
- break;
- case MIPS_MFC0:
- 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));
- break;
- case MIPS_DMFC2:
- il.AddInstruction(MoveFromCoprocessor(2, il, 8, op1.reg, op2.immediate, 0, decomposeFlags));
- break;
- case MIPS_MFC2:
- 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));
- break;
- case MIPS_MTC0:
- il.AddInstruction(MoveToCoprocessor(0, il, 4, op2.immediate, op3.immediate, ReadILOperand(il, instr, 1, registerSize), decomposeFlags));
- break;
- case MIPS_MTC1:
- il.AddInstruction(MoveToCoprocessor(1, il, 4, op2.immediate, op3.immediate, ReadILOperand(il, instr, 1, registerSize), decomposeFlags));
- break;
- case MIPS_DMTC2:
- il.AddInstruction(MoveToCoprocessor(2, il, 8, op2.immediate, 0, ReadILOperand(il, instr, 1, registerSize), decomposeFlags));
- break;
- case MIPS_MTC2:
- il.AddInstruction(MoveToCoprocessor(2, il, 4, op2.immediate, 0, ReadILOperand(il, instr, 1, registerSize), decomposeFlags));
- break;
- case MIPS_MOVE:
- il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, ReadILOperand(il, instr, 2, registerSize)));
- break;
- case MIPS_MOVN:
- il.AddInstruction(il.If(il.CompareNotEqual(registerSize, ReadILOperand(il, instr, 3, registerSize), il.Const(registerSize, 0)), trueCode, falseCode));
- il.MarkLabel(trueCode);
- il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, ReadILOperand(il, instr, 2, registerSize)));
- 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.MarkLabel(trueCode);
- il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, ReadILOperand(il, instr, 2, registerSize)));
- il.MarkLabel(falseCode);
- break;
- case MIPS_MSUB:
- //(HI,LO) = (HI,LO) - (GPR[rs] x GPR[rt])
- //
- //tmp0 = REG_HI << 32 | REG_LO
- //(HI,LO) = tmp0 - (op1 * op2)
- il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0),
- 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)))));
+ case MIPS_BC0F:
+ case MIPS_BC0FL:
+ il.AddInstruction(il.Intrinsic({RegisterOrFlag(true, CCREG_COC0)}, MIPS_INTRIN_COP0_CONDITION, {}));
+ ConditionalJump(arch, il, GetConditionForInstruction(il, instr, registerSize), addrSize, op1.immediate, addr + 8);
+ return false;
- SignExtendHiLo(il, registerSize);
- break;
- case MIPS_MSUBU:
- //(HI,LO) = (HI,LO) - (GPR[rs] x GPR[rt])
- //
- //tmp0 = REG_HI << 32 | REG_LO
- //(HI,LO) = tmp0 - (op1 * op2)
- il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0),
- 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)))));
+ case MIPS_BC0T:
+ case MIPS_BC0TL:
+ il.AddInstruction(il.Intrinsic({RegisterOrFlag(true, CCREG_COC0)}, MIPS_INTRIN_COP0_CONDITION, {}));
+ ConditionalJump(arch, il, GetConditionForInstruction(il, instr, registerSize), addrSize, op1.immediate, addr + 8);
+ return false;
- 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);
- 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);
- 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))));
- 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))));
- break;
- case MIPS_NEG:
- case MIPS_NEGU:
- il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg,
- il.Neg(4, ReadILOperand(il, instr, 2, registerSize))));
- break;
- case MIPS_NOT:
- il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg,
- il.Not(registerSize, ReadILOperand(il, instr, 2, registerSize))));
- 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)))));
- 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))));
- 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))));
- else
- il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg,
- il.Or(registerSize,
- ReadILOperand(il, instr, 2, registerSize),
- il.Operand(1, il.Const(4, 0x0000ffff & op3.immediate)))));
- break;
- case MIPS_RDHWR:
- {
- MipsIntrinsic intrinsic;
- switch (op2.immediate)
- {
- case 0: intrinsic = MIPS_INTRIN_HWR0; break;
- case 1: intrinsic = MIPS_INTRIN_HWR1; break;
- case 2: intrinsic = MIPS_INTRIN_HWR2; break;
- case 3: intrinsic = MIPS_INTRIN_HWR3; break;
- default: intrinsic = MIPS_INTRIN_HWR_UNKNOWN;
- }
+ case MIPS_BGEZAL:
+ case MIPS_BLTZAL:
+ il.AddInstruction(il.If(GetConditionForInstruction(il, instr, registerSize), trueCode, falseCode));
+ il.MarkLabel(trueCode);
+ il.AddInstruction(il.Call(ReadILOperand(il, instr, 2, registerSize(op2))));
+ il.MarkLabel(falseCode);
+ break;
- if (intrinsic != MIPS_INTRIN_HWR_UNKNOWN)
- {
- il.AddInstruction(
- il.Intrinsic({RegisterOrFlag::Register(op1.reg)}, intrinsic, {})
- );
- }
- else
- {
- il.AddInstruction(
- il.Intrinsic({RegisterOrFlag::Register(op1.reg)}, MIPS_INTRIN_HWR_UNKNOWN, {il.Const(1, op2.immediate)})
- );
- }
- break;
+ case MIPS_BREAK:
+ il.AddInstruction(il.Breakpoint());
+ break;
+ case MIPS_CLO:
+ //count leading ones
+ //algorithm is as follows
+ //
+ //tmp0 = 0;
+ //again:
+ //if (((op2 << tmp) & 0x80000000) != 0)
+ //{
+ // tmp0 += 1;
+ // goto again;
+ //}
+ //
+ 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(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)))));
+ il.AddInstruction(il.Goto(again));
+ il.MarkLabel(falseCode);
+ break;
+ case MIPS_DCLO:
+ //count leading ones
+ //algorithm is as follows
+ //
+ //tmp0 = 0;
+ //again:
+ //if (((op2 << tmp) & 0x80000000_00000000) != 0)
+ //{
+ // tmp0 += 1;
+ // goto again;
+ //}
+ //
+ 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(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)))));
+ il.AddInstruction(il.Goto(again));
+ il.MarkLabel(falseCode);
+ break;
+ case MIPS_CLZ:
+ //count leading zeroes
+ //algorithm is as follows
+ //
+ //tmp0 = 0;
+ //again:
+ //if (((op2 << tmp) & 0x80000000) == 0)
+ //{
+ // tmp0 += 1;
+ // goto again;
+ //}
+ //
+ 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(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)))));
+ il.AddInstruction(il.Goto(again));
+ il.MarkLabel(falseCode);
+ break;
+ case MIPS_DCLZ:
+ //count leading zeroes
+ //algorithm is as follows
+ //
+ //tmp0 = 0;
+ //again:
+ //if (((op2 << tmp) & 0x80000000_00000000) == 0)
+ //{
+ // tmp0 += 1;
+ // goto again;
+ //}
+ //
+ 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(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)))));
+ il.AddInstruction(il.Goto(again));
+ il.MarkLabel(falseCode);
+ break;
+ case MIPS_JALR:
+ case MIPS_JALR_HB:
+ {
+ uint32_t operand = 1;
+ if (instr.operands[1].operandClass != NONE)
+ {
+ operand = 2;
}
- case MIPS_SW:
- il.AddInstruction(il.Store(4, GetILOperandMemoryAddress(il, op2, addrSize), ReadILOperand(il, instr, 1, registerSize, 4)));
+ 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(op1), addrSize)));
+ else
+ il.AddInstruction(il.Jump(ReadILOperand(il, instr, 1, registerSize(op1), addrSize)));
+ return false;
+ case MIPS_ERET:
+ il.AddInstruction(il.Return(il.Register(addrSize, REG_ERROR_EPC)));
+ break;
+ case MIPS_LBUX:
+ case MIPS_LBU:
+ 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, 1, registerSize(op1), op1.reg, ReadILOperand(il, instr, 2, registerSize(op2), 1), SignExtend));
+ break;
+ case MIPS_MFHI:
+ il.AddInstruction(SetRegisterOrNop(il, get_register_width(REG_HI, version), registerSize(op1), op1.reg, il.Register(get_register_width(REG_HI, version), REG_HI)));
+ break;
+ case MIPS_MFHI1:
+ il.AddInstruction(SetRegisterOrNop(il, get_register_width(REG_HI1, version), registerSize(op1), op1.reg, il.Register(get_register_width(REG_HI1, version), REG_HI1)));
+ break;
+ case MIPS_MFLO:
+ il.AddInstruction(SetRegisterOrNop(il, get_register_width(REG_LO, version), registerSize(op1), op1.reg, il.Register(get_register_width(REG_LO, version), REG_LO)));
+ break;
+ case MIPS_MFLO1:
+ il.AddInstruction(SetRegisterOrNop(il, get_register_width(REG_LO1, version), registerSize(op1), op1.reg, il.Register(get_register_width(REG_LO1, version), REG_LO1)));
+ break;
+ case MIPS_MTHI:
+ il.AddInstruction(il.SetRegister(get_register_width(REG_HI, version), REG_HI, ReadILOperand(il, instr, 1, registerSize(op1))));
+ break;
+ case MIPS_MTHI1:
+ il.AddInstruction(il.SetRegister(get_register_width(REG_HI1, version), REG_HI1, ReadILOperand(il, instr, 1, registerSize(op1))));
+ break;
+ case MIPS_MTLO:
+ il.AddInstruction(il.SetRegister(get_register_width(REG_LO, version), REG_LO, ReadILOperand(il, instr, 1, registerSize(op1))));
+ break;
+ case MIPS_MTLO1:
+ il.AddInstruction(il.SetRegister(get_register_width(REG_LO1, version), REG_LO1, ReadILOperand(il, instr, 1, registerSize(op1))));
+ break;
+ case MIPS_DMFC0:
+ il.AddInstruction(MoveFromCoprocessor(0, il, 8, op1.reg, op2.immediate, op3.immediate, decomposeFlags));
+ break;
+ case MIPS_MFC0:
+ il.AddInstruction(MoveFromCoprocessor(0, il, 4, op1.reg, op2.immediate, op3.immediate, decomposeFlags));
+ break;
+ case MIPS_MFC1:
+ if (version == MIPS_R5900)
+ {
+ il.AddInstruction(
+ SetRegisterOrNop(il, 4, 8, op1.reg, il.Register(4, op2.reg)));
break;
- case MIPS_SWL:
+ }
+ 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));
+ break;
+ case MIPS_MFC2:
+ 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(op1)), decomposeFlags));
+ break;
+ case MIPS_MTC0:
+ il.AddInstruction(MoveToCoprocessor(0, il, 4, op2.immediate, op3.immediate, ReadILOperand(il, instr, 1, registerSize(op1)), decomposeFlags));
+ break;
+ case MIPS_MTC1:
+ if (version == MIPS_R5900)
{
- 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.Store(4,
- GetILOperandMemoryAddress(il, op2, addrSize, delta),
- il.Register(4, LLIL_TEMP(0))
- ));
-
+ 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));
+ break;
+ case MIPS_MTC2:
+ 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(op1), registerSize(op1), op1.reg, ReadILOperand(il, instr, 2, registerSize(op2))));
+ break;
+ case MIPS_MOVN:
+ 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(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(op3), ReadILOperand(il, instr, 3, registerSize(op3)), il.Const(registerSize(op3), 0)), trueCode, falseCode));
+ il.MarkLabel(trueCode);
+ il.AddInstruction(SetRegisterOrNop(il, registerSize(op1), registerSize(op1), op1.reg, ReadILOperand(il, instr, 2, registerSize(op2))));
+ il.MarkLabel(falseCode);
+ break;
+ case MIPS_MSUB:
+ //(HI,LO) = (HI,LO) - (GPR[rs] x GPR[rt])
+ //
+ //tmp0 = REG_HI << 32 | REG_LO
+ //(HI,LO) = tmp0 - (op1 * op2)
+ il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0),
+ 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(op1)), ReadILOperand(il, instr, 2, registerSize(op2))))));
- 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.Store(8,
- GetILOperandMemoryAddress(il, op2, addrSize, delta),
- il.Register(8, LLIL_TEMP(0))
- ));
+ SignExtendHiLo(il, registerSize(op1));
+ break;
+ case MIPS_MSUBU:
+ //(HI,LO) = (HI,LO) - (GPR[rs] x GPR[rt])
+ //
+ //tmp0 = REG_HI << 32 | REG_LO
+ //(HI,LO) = tmp0 - (op1 * op2)
+ il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0),
+ 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(op1)), ReadILOperand(il, instr, 2, registerSize(op2))))));
- break;
+ SignExtendHiLo(il, registerSize(op1));
+ break;
+ case MIPS_MULT1:
+ case MIPS_MULT:
+ if (version == MIPS_R5900 && instr.numOperands == 3) {
+ 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))));
+ if (lo == REG_LO)
+ SignExtendHiLo(il, 4);
+ auto rd = op1.reg;
+ if (rd != REG_ZERO)
+ il.AddInstruction(SetRegisterOrNop(il, 4, 8, rd, il.Register(4, LLIL_TEMP(0))));
}
- case MIPS_SWR:
+ else
{
- 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.Store(4,
- GetILOperandMemoryAddress(il, op2, addrSize, delta),
- il.Register(4, LLIL_TEMP(0))
- ));
-
- break;
+ 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) {
+ DEFINE_HILO1(MIPS_MULTU1);
- case MIPS_SDR:
+ il.AddInstruction(il.SetRegisterSplit(4, hi, lo,
+ il.MultDoublePrecUnsigned(4,
+ ReadILOperand(il, instr, 2, 4),
+ ReadILOperand(il, instr, 3, 4))));
+ if (lo == REG_LO)
+ SignExtendHiLo(il, 4);
+ auto rd = op1.reg;
+ if (rd != REG_ZERO)
+ il.AddInstruction(SetRegisterOrNop(il, 4, 8, rd, il.Register(get_register_width(lo, version), lo)));
+ }
+ else
{
- 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.Store(8,
- GetILOperandMemoryAddress(il, op2, addrSize, delta),
- il.Register(8, LLIL_TEMP(0))
- ));
-
- break;
+ DEFINE_HILO1(MIPS_MULTU1);
+ il.AddInstruction(il.SetRegisterSplit(4, hi, lo,
+ il.MultDoublePrecUnsigned(4,
+ ReadILOperand(il, instr, 1, 4),
+ ReadILOperand(il, instr, 2, 4))));
+ if (lo == REG_LO)
+ SignExtendHiLo(il, 4);
+ }
+ break;
+ case MIPS_DMULT:
+ il.AddInstruction(il.SetRegisterSplit(8, REG_HI, REG_LO, il.MultDoublePrecSigned(8, ReadILOperand(il, instr, 1, registerSize(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(op1)), ReadILOperand(il, instr, 2, registerSize(op2)))));
+ break;
+ case MIPS_NEGU:
+ // Also, turns out neg and negu are both pseudo instructions for sub/subu
+ case MIPS_NEG:
+ il.AddInstruction(SetRegisterOrNop(il, 4, registerSize(op1), op1.reg,
+ il.Neg(4, ReadILOperand(il, instr, 2, registerSize(op2)))));
+ break;
+ case MIPS_NOT:
+ il.AddInstruction(SetRegisterOrNop(il, registerSize(op2), registerSize(op1), op1.reg,
+ il.Not(registerSize(op2), ReadILOperand(il, instr, 2, registerSize(op2)))));
+ break;
+ case MIPS_NOR:
+ 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(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), op1.reg, il.Operand(1, il.Const(4, 0x0000ffff & op3.immediate))));
+ else
+ 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:
+ {
+ MipsIntrinsic intrinsic;
+ switch (op2.immediate)
+ {
+ case 0: intrinsic = MIPS_INTRIN_HWR0; break;
+ case 1: intrinsic = MIPS_INTRIN_HWR1; break;
+ case 2: intrinsic = MIPS_INTRIN_HWR2; break;
+ case 3: intrinsic = MIPS_INTRIN_HWR3; break;
+ default: intrinsic = MIPS_INTRIN_HWR_UNKNOWN;
}
- case MIPS_SC:
+ if (intrinsic != MIPS_INTRIN_HWR_UNKNOWN)
{
- 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));
- il.MarkLabel(trueCode);
+ il.AddInstruction(
+ il.Intrinsic({RegisterOrFlag::Register(op1.reg)}, intrinsic, {})
+ );
+ }
+ else
+ {
+ il.AddInstruction(
+ il.Intrinsic({RegisterOrFlag::Register(op1.reg)}, MIPS_INTRIN_HWR_UNKNOWN, {il.Const(1, op2.immediate)})
+ );
+ }
+ break;
+ }
+ case MIPS_SW:
+ 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(op1), 4) }));
+ il.AddInstruction(il.Store(4,
+ GetILOperandMemoryAddress(il, op2, addrSize, delta),
+ il.Register(4, LLIL_TEMP(0))
+ ));
- 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.Goto(doneCode));
+ break;
+ }
- il.MarkLabel(falseCode);
- il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.Const(0, 0)));
+ 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(op1), 8) }));
+ il.AddInstruction(il.Store(8,
+ GetILOperandMemoryAddress(il, op2, addrSize, delta),
+ il.Register(8, LLIL_TEMP(0))
+ ));
- il.MarkLabel(doneCode);
- break;
- }
- case MIPS_SD:
- il.AddInstruction(il.Store(8, GetILOperandMemoryAddress(il, op2, addrSize), ReadILOperand(il, instr, 1, registerSize)));
- break;
- case MIPS_SCD:
- {
- LowLevelILLabel trueCode, falseCode, doneCode;
- il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(LLIL_TEMP(0)) }, MIPS_INTRIN_LLBIT_CHECK, {}));
- il.AddInstruction(il.If(il.CompareEqual(0, il.Register(0, LLIL_TEMP(0)), il.Const(0, 1)),
- trueCode, falseCode));
- il.MarkLabel(trueCode);
+ break;
+ }
+ 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(op1), 4) }));
+ il.AddInstruction(il.Store(4,
+ GetILOperandMemoryAddress(il, op2, addrSize, delta),
+ il.Register(4, LLIL_TEMP(0))
+ ));
- 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.Goto(doneCode));
+ break;
+ }
- il.MarkLabel(falseCode);
- il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.Const(0, 0)));
+ 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(op1), 8) }));
+ il.AddInstruction(il.Store(8,
+ GetILOperandMemoryAddress(il, op2, addrSize, delta),
+ il.Register(8, LLIL_TEMP(0))
+ ));
- il.MarkLabel(doneCode);
- break;
+ break;
+ }
+
+ case MIPS_SC:
+ {
+ 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));
+ il.MarkLabel(trueCode);
+
+ 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(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(op1))));
+ break;
+ case MIPS_SQ:
+ // Technically, the store address should be automagically aligned by masking off the low 4 bits...
+ // il.AddInstruction(il.Store(16,
+ // il.And(addrSize, il.Const(addrSize, ~0x0F), GetILOperandMemoryAddress(il, op2, addrSize)),
+ // ReadILOperand(il, instr, 1, 16)));
+ // ...but that makes the IL ugly, so don't bother:
+ il.AddInstruction(il.Store(16, GetILOperandMemoryAddress(il, op2, addrSize), ReadILOperand(il, instr, 1, 16)));
+ break;
+ case MIPS_SCD:
+ {
+ LowLevelILLabel trueCode, falseCode, doneCode;
+ il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(LLIL_TEMP(0)) }, MIPS_INTRIN_LLBIT_CHECK, {}));
+ il.AddInstruction(il.If(il.CompareEqual(0, il.Register(0, LLIL_TEMP(0)), il.Const(0, 1)),
+ trueCode, falseCode));
+ il.MarkLabel(trueCode);
+
+ 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(op1), registerSize(op1), op1.reg, il.Const(0, 0)));
+
+ il.MarkLabel(doneCode);
+ break;
+ }
+ case MIPS_SWC1:
+ if (version == MIPS_R5900)
+ {
+ il.AddInstruction(
+ il.Store(4, GetILOperandMemoryAddress(il, op2, addrSize),
+ il.Register(4, op1.reg)));
}
- case MIPS_SWC1:
+ 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_SWC2:
- il.AddInstruction(MoveFromCoprocessor(2, 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_SWC3:
- il.AddInstruction(MoveFromCoprocessor(3, 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_SYSCALL:
- il.AddInstruction(il.SystemCall());
- 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.Const(1, op3.immediate)
- ),
- il.Const(registerSize, (1<<op4.immediate)-1)
- )));
- break;
- case MIPS_DEXT:
- case MIPS_DEXTM:
- case MIPS_DEXTU:
- //op1 = op4.imm bits in op2.reg at bit offset op3.imm
- il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg,
- il.And(8,
- il.LogicalShiftRight(8,
- ReadILOperand(il, instr, 2, registerSize),
- il.Const(1, op3.immediate)
- ),
- il.Const(8, (((uint64_t)1)<<op4.immediate)-1)
- )));
- break;
- case MIPS_INS:
- // recall: pos = op3, size = op4
- il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg,
- il.Or(registerSize,
- il.And(registerSize,
- ReadILOperand(il, instr, 1, registerSize),
- il.Const(registerSize, ~(((1<<op4.immediate)-1)<<op3.immediate))
+ }
+ break;
+ case MIPS_SDC1:
+ il.AddInstruction(
+ il.Store(4, GetILOperandMemoryAddress(il, op2, addrSize),
+ il.LowPart(4, il.Register(8, op1.reg))));
+ il.AddInstruction(
+ il.Store(4, GetILOperandMemoryAddress(il, op2, addrSize, 4),
+ il.LogicalShiftRight(4, il.Register(8, op1.reg), il.Const(4, 32))));
+ break;
+ case MIPS_SDXC1:
+ il.AddInstruction(
+ il.Store(4, GetILOperandMemoryAddress(il, op2, addrSize),
+ il.LowPart(4, il.Register(8, op1.reg))));
+ il.AddInstruction(
+ il.Store(4, il.Add(addrSize, GetILOperandMemoryAddress(il, op2, addrSize), il.Const(addrSize, 4)),
+ il.LogicalShiftRight(4, il.Register(8, op1.reg), il.Const(4, 32))));
+ break;
+ case MIPS_SWXC1:
+ il.AddInstruction(
+ il.Store(4, GetILOperandMemoryAddress(il, op2, addrSize),
+ il.Register(4, op1.reg)));
+ break;
+ case MIPS_SWC2:
+ il.AddInstruction(MoveFromCoprocessor(2, 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_SDC2:
+ il.AddInstruction(MoveFromCoprocessor(2, il, 8, LLIL_TEMP(0), op1.immediate, 0, decomposeFlags));
+ il.AddInstruction(WriteILOperand(il, instr, 1, addrSize, il.Register(8, LLIL_TEMP(0))));
+ break;
+ case MIPS_SWC3:
+ il.AddInstruction(MoveFromCoprocessor(3, 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_SDC3:
+ il.AddInstruction(MoveFromCoprocessor(3, il, 8, LLIL_TEMP(0), op1.immediate, 0, decomposeFlags));
+ il.AddInstruction(WriteILOperand(il, instr, 1, addrSize, il.Register(8, LLIL_TEMP(0))));
+ break;
+ case MIPS_SYSCALL:
+ il.AddInstruction(il.SystemCall());
+ break;
+ case MIPS_EXT:
+ //op1 = op4.imm bits in op2.reg at bit offset op3.imm
+ 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(op1), (1<<op4.immediate)-1)
+ )));
+ break;
+ case MIPS_DEXT:
+ case MIPS_DEXTM:
+ case MIPS_DEXTU:
+ //op1 = op4.imm bits in op2.reg at bit offset op3.imm
+ il.AddInstruction(SetRegisterOrNop(il, 8, registerSize(op1), op1.reg,
+ il.And(8,
+ il.LogicalShiftRight(8,
+ ReadILOperand(il, instr, 2, registerSize(op2)),
+ il.Const(1, op3.immediate)
+ ),
+ il.Const(8, (((uint64_t)1)<<op4.immediate)-1)
+ )));
+ break;
+ case MIPS_INS:
+ // recall: pos = op3, size = op4
+ il.AddInstruction(SetRegisterOrNop(il, registerSize(op1), registerSize(op1), op1.reg,
+ il.Or(registerSize(op1),
+ il.And(registerSize(op1),
+ ReadILOperand(il, instr, 1, registerSize(op1)),
+ il.Const(registerSize(op1), ~(((1<<op4.immediate)-1)<<op3.immediate))
+ ),
+ il.ShiftLeft(registerSize(op1),
+ il.And(registerSize(op1),
+ ReadILOperand(il, instr, 2, registerSize(op2)),
+ il.Const(registerSize(op1), (1<<op4.immediate)-1)
),
- il.ShiftLeft(registerSize,
- il.And(registerSize,
- ReadILOperand(il, instr, 2, registerSize),
- il.Const(registerSize, (1<<op4.immediate)-1)
- ),
- il.Const(registerSize, op3.immediate)
- )
- )));
- break;
- case MIPS_DINS:
- case MIPS_DINSM:
- case MIPS_DINSU:
- // recall: pos = op3, size = op4
- il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg,
- il.Or(8,
- il.And(8,
- ReadILOperand(il, instr, 1, registerSize),
- il.Const(registerSize, ~(((((uint64_t)1)<<op4.immediate)-1)<<op3.immediate))
+ il.Const(registerSize(op1), op3.immediate)
+ )
+ )));
+ break;
+ case MIPS_DINS:
+ case MIPS_DINSM:
+ case MIPS_DINSU:
+ // recall: pos = op3, size = op4
+ il.AddInstruction(SetRegisterOrNop(il, registerSize(op1), registerSize(op1), op1.reg,
+ il.Or(registerSize(op1),
+ il.And(registerSize(op1),
+ ReadILOperand(il, instr, 1, registerSize(op1)),
+ il.Const(registerSize(op1), ~(((((uint64_t)1)<<op4.immediate)-1)<<op3.immediate))
+ ),
+ il.ShiftLeft(registerSize(op1),
+ il.And(registerSize(op1),
+ ReadILOperand(il, instr, 2, registerSize(op2)),
+ il.Const(registerSize(op1), (((uint64_t)1)<<op4.immediate)-1)
),
- il.ShiftLeft(8,
- il.And(8,
- ReadILOperand(il, instr, 2, registerSize),
- il.Const(8, (((uint64_t)1)<<op4.immediate)-1)
- ),
- il.Const(8, op3.immediate)
- )
- )));
- break;
- case MIPS_LUI:
- il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, il.Const(4, op2.immediate << 16)));
- break;
- case MIPS_LI:
- case MIPS_LW:
- case MIPS_LWX:
- il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, ReadILOperand(il, instr, 2, registerSize, 4)));
- break;
- case MIPS_LWU:
- il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, il.ZeroExtend(8, ReadILOperand(il, instr, 2, registerSize, 4))));
- break;
- case MIPS_LD:
- il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, ReadILOperand(il, instr, 2, registerSize)));
- break;
- case MIPS_LWL:
- {
- int32_t delta = endian == LittleEndian ? -3 : 0;
- il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, MIPS_INTRIN_SET_LEFT_PART32,
- {
- il.Load(4, GetILOperandMemoryAddress(il, op2, addrSize, delta))
- }
- ));
-
- break;
- }
- case MIPS_LDL:
- {
- int32_t delta = endian == LittleEndian ? -7 : 0;
- il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, MIPS_INTRIN_SET_LEFT_PART64,
- {
- il.Load(8, GetILOperandMemoryAddress(il, op2, addrSize, delta))
- }
- ));
+ il.Const(registerSize(op1), op3.immediate)
+ )
+ )));
+ break;
+ case MIPS_LUI:
+ il.AddInstruction(SetRegisterOrNop(il, 4, registerSize(op1), op1.reg, il.Const(4, op2.immediate << 16)));
+ break;
+ case MIPS_LI:
+ case MIPS_LW:
+ case MIPS_LWX:
+ il.AddInstruction(SetRegisterOrNop(il, 4, registerSize(op1), op1.reg, ReadILOperand(il, instr, 2, registerSize(op2), 4)));
+ break;
+ case MIPS_LWU:
+ il.AddInstruction(SetRegisterOrNop(il, 8, registerSize(op1), op1.reg, il.ZeroExtend(8, ReadILOperand(il, instr, 2, registerSize(op2), 4))));
+ break;
+ case MIPS_LD:
+ 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, addrSize, 16)));
+ break;
+ case MIPS_LWL:
+ {
+ int32_t delta = endian == LittleEndian ? -3 : 0;
+ il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, MIPS_INTRIN_SET_LEFT_PART32,
+ {
+ il.Load(4, GetILOperandMemoryAddress(il, op2, addrSize, delta))
+ }
+ ));
- break;
- }
- case MIPS_LWR:
- {
- int32_t delta = endian == BigEndian ? -3 : 0;
- il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, MIPS_INTRIN_SET_RIGHT_PART32,
- {
- il.Load(4, GetILOperandMemoryAddress(il, op2, addrSize, delta))
- }
- ));
+ break;
+ }
+ case MIPS_LDL:
+ {
+ int32_t delta = endian == LittleEndian ? -7 : 0;
+ il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, MIPS_INTRIN_SET_LEFT_PART64,
+ {
+ il.Load(8, GetILOperandMemoryAddress(il, op2, addrSize, delta))
+ }
+ ));
- break;
- }
- case MIPS_LDR:
- {
- int32_t delta = endian == BigEndian ? -7 : 0;
- il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, MIPS_INTRIN_SET_RIGHT_PART64,
- {
- il.Load(8, GetILOperandMemoryAddress(il, op2, addrSize, delta))
- }
- ));
+ break;
+ }
+ case MIPS_LWR:
+ {
+ int32_t delta = endian == BigEndian ? -3 : 0;
+ il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, MIPS_INTRIN_SET_RIGHT_PART32,
+ {
+ il.Load(4, GetILOperandMemoryAddress(il, op2, addrSize, delta))
+ }
+ ));
- break;
- }
- case MIPS_LL:
- il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, ReadILOperand(il, instr, 2, registerSize, 4)));
- il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_LLBIT_SET, {il.Const(0, 1)}));
- break;
- case MIPS_LLD:
- il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, ReadILOperand(il, instr, 2, registerSize)));
- il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_LLBIT_SET, {il.Const(0, 1)}));
- break;
- case MIPS_SRA:
- il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, il.ArithShiftRight(4, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize))));
- break;
- case MIPS_SRAV:
- il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, il.ArithShiftRight(4, ReadILOperand(il, instr, 2, registerSize), il.And(4, ReadILOperand(il, instr, 3, registerSize), il.Const(4, 0x1f)))));
- break;
- case MIPS_SLT:
- il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.BoolToInt(registerSize,
- il.CompareSignedLessThan(registerSize, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize)))));
- break;
- case MIPS_SLTI:
- il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.BoolToInt(registerSize,
- il.CompareSignedLessThan(registerSize, ReadILOperand(il, instr, 2, registerSize), il.Const(registerSize, op3.immediate)))));
- break;
- case MIPS_SLTIU:
- il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.BoolToInt(registerSize,
- il.CompareUnsignedLessThan(registerSize, ReadILOperand(il, instr, 2, registerSize), il.Const(registerSize, op3.immediate)))));
- break;
- case MIPS_SLTU:
- il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.BoolToInt(registerSize,
- il.CompareUnsignedLessThan(registerSize, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize)))));
- break;
- case MIPS_SLL:
- // SLL is unique in that the input doesn't have to be sign extended, and the
- // preferred way to sign extend the lower 32 bits of an register is to shift
- // it left by 0
- if (registerSize == 8 && op2.reg != 0 && op3.immediate == 0)
+ break;
+ }
+ case MIPS_LDR:
+ {
+ int32_t delta = endian == BigEndian ? -7 : 0;
+ il.AddInstruction(il.Intrinsic({ RegisterOrFlag::Register(op1.reg) }, MIPS_INTRIN_SET_RIGHT_PART64,
{
- il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, il.SignExtend(8, il.LowPart(4, ReadILOperand(il, instr, 2, 8)))));
+ il.Load(8, GetILOperandMemoryAddress(il, op2, addrSize, delta))
+ }
+ ));
+ break;
+ }
+ case MIPS_LL:
+ il.AddInstruction(SetRegisterOrNop(il, 4, registerSize(op1), op1.reg, ReadILOperand(il, instr, 2, registerSize(op2), 4)));
+ il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_LLBIT_SET, {il.Const(0, 1)}));
+ break;
+ case MIPS_LLD:
+ il.AddInstruction(SetRegisterOrNop(il, 8, registerSize(op1), op1.reg, ReadILOperand(il, instr, 2, registerSize(op2))));
+ il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_LLBIT_SET, {il.Const(0, 1)}));
+ break;
+ case MIPS_SRA:
+ il.AddInstruction(SetRegisterOrNop(il, 4, registerSize(op1), op1.reg, il.ArithShiftRight(4, ReadILOperand(il, instr, 2, registerSize(op2)), ReadILOperand(il, instr, 3, registerSize(op3)))));
+ break;
+ case MIPS_SRAV:
+ il.AddInstruction(SetRegisterOrNop(il, 4, registerSize(op1), op1.reg, il.ArithShiftRight(4, ReadILOperand(il, instr, 2, registerSize(op2)), il.And(4, ReadILOperand(il, instr, 3, registerSize(op3)), il.Const(4, 0x1f)))));
+ break;
+ case MIPS_SLT:
+ il.AddInstruction(SetRegisterOrNop(il, registerSize(op1), registerSize(op1), op1.reg, il.BoolToInt(registerSize(op1),
+ il.CompareSignedLessThan(registerSize(op2), ReadILOperand(il, instr, 2, registerSize(op2)), ReadILOperand(il, instr, 3, registerSize(op3))))));
+ break;
+ case MIPS_SLTI:
+ il.AddInstruction(SetRegisterOrNop(il, registerSize(op1), registerSize(op1), op1.reg, il.BoolToInt(registerSize(op1),
+ il.CompareSignedLessThan(registerSize(op2), ReadILOperand(il, instr, 2, registerSize(op2)), il.Const(registerSize(op2), op3.immediate)))));
+ break;
+ case MIPS_SLTIU:
+ il.AddInstruction(SetRegisterOrNop(il, registerSize(op1), registerSize(op1), op1.reg, il.BoolToInt(registerSize(op1),
+ il.CompareUnsignedLessThan(registerSize(op2), ReadILOperand(il, instr, 2, registerSize(op2)),
+ il.Const(registerSize(op2), op3.immediate))), ZeroExtend));
+ break;
+ case MIPS_SLTU:
+ il.AddInstruction(SetRegisterOrNop(il, registerSize(op1), registerSize(op1), op1.reg, il.BoolToInt(registerSize(op1),
+ il.CompareUnsignedLessThan(registerSize(op2), ReadILOperand(il, instr, 2, registerSize(op2)),
+ ReadILOperand(il, instr, 3, registerSize(op3)))), ZeroExtend));
+ break;
+ case MIPS_SLL:
+ // SLL is unique in that the input doesn't have to be sign extended, and the
+ // preferred way to sign extend the lower 32 bits of an register is to shift
+ // it left by 0
+ if ((version == MIPS_R5900 || version == MIPS_64) && op2.reg != REG_ZERO)
+ {
+ if (op3.immediate == 0)
+ {
+ il.AddInstruction(SetRegisterOrNop(il, 4, registerSize(op1), op1.reg,
+ il.SignExtend(8,
+ il.LowPart(4,
+ ReadILOperand(il, instr, 2, 8)))));
}
else
{
- il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, il.ShiftLeft(4, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize))));
+ il.AddInstruction(SetRegisterOrNop(il, 4, registerSize(op1), op1.reg,
+ il.ShiftLeft(registerSize(op1),
+ il.SignExtend(registerSize(op1),
+ il.LowPart(4, ReadILOperand(il, instr, 2, registerSize(op2)))),
+ ReadILOperand(il, instr, 3, registerSize(op2)))));
}
- break;
- case MIPS_SLLV:
- il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, il.ShiftLeft(4, ReadILOperand(il, instr, 2, registerSize), il.And(4, ReadILOperand(il, instr, 3, registerSize), il.Const(4, 0x1f)))));
- break;
- case MIPS_DSLL32:
- op3.immediate += 32;
- // fall through
- case MIPS_DSLL:
- il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, il.ShiftLeft(8, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize))));
- break;
- case MIPS_DSLLV:
- il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, il.ShiftLeft(8, ReadILOperand(il, instr, 2, registerSize), il.And(8, ReadILOperand(il, instr, 3, registerSize), il.Const(8, 0x3f)))));
- break;
- case MIPS_DSRL32:
- op3.immediate += 32;
- // fall through
- case MIPS_DSRL:
- il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, il.LogicalShiftRight(8, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize))));
- break;
- case MIPS_DSRLV:
- il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, il.LogicalShiftRight(8, ReadILOperand(il, instr, 2, registerSize), il.And(8, ReadILOperand(il, instr, 3, registerSize), il.Const(8, 0x3f)))));
- break;
- case MIPS_DSRA32:
- op3.immediate += 32;
- // fall through
- case MIPS_DSRA:
- il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, il.ArithShiftRight(8, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize))));
- break;
- case MIPS_DSRAV:
- il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, il.ArithShiftRight(8, ReadILOperand(il, instr, 2, registerSize), il.And(8, ReadILOperand(il, instr, 3, registerSize), il.Const(8, 0x3f)))));
- break;
- case MIPS_SB:
- il.AddInstruction(il.Store(1, GetILOperandMemoryAddress(il, op2, addrSize), il.LowPart(1, ReadILOperand(il, instr, 1, registerSize))));
- break;
- case MIPS_TRAP:
- il.AddInstruction(il.Trap(0));
- break;
- case MIPS_TEQI:
- case MIPS_TEQ:
- ConditionExecute(il, il.CompareEqual(4, ReadILOperand(il, instr, 1, registerSize), ReadILOperand(il, instr, 2, registerSize)),il.Trap(0));
- break;
- case MIPS_TNE:
- case MIPS_TNEI:
- ConditionExecute(il, il.CompareNotEqual(4, ReadILOperand(il, instr, 1, registerSize), ReadILOperand(il, instr, 2, registerSize)),il.Trap(0));
- break;
- case MIPS_TGE:
- case MIPS_TGEI:
- ConditionExecute(il, il.CompareSignedGreaterEqual(4, ReadILOperand(il, instr, 1, registerSize), ReadILOperand(il, instr, 2, registerSize)),il.Trap(0));
- break;
- case MIPS_TGEIU:
- case MIPS_TGEU:
- ConditionExecute(il, il.CompareUnsignedGreaterEqual(4, ReadILOperand(il, instr, 1, registerSize), ReadILOperand(il, instr, 2, registerSize)),il.Trap(0));
- break;
- case MIPS_TLT:
- case MIPS_TLTI:
- ConditionExecute(il, il.CompareSignedLessThan(4, ReadILOperand(il, instr, 1, registerSize), ReadILOperand(il, instr, 2, registerSize)),il.Trap(0));
- break;
- case MIPS_TLTIU:
- case MIPS_TLTU:
- ConditionExecute(il, il.CompareUnsignedLessThan(4, ReadILOperand(il, instr, 1, registerSize), ReadILOperand(il, instr, 2, registerSize)),il.Trap(0));
- break;
- case MIPS_LH:
- case MIPS_LHX:
- case MIPS_LHI:
- il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, il.SignExtend(4, ReadILOperand(il, instr, 2, registerSize, 2))));
- break;
- case MIPS_LHU:
- il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.ZeroExtend(4, ReadILOperand(il, instr, 2, registerSize, 2))));
- break;
- case MIPS_MADD:
- il.AddInstruction(il.SetRegisterSplit(4, REG_HI, REG_LO,
+ }
+ else
+ {
+ il.AddInstruction(SetRegisterOrNop(il, 4, registerSize(op1), op1.reg,
+ il.ShiftLeft(4,
+ ReadILOperand(il, instr, 2, registerSize(op2)),
+ ReadILOperand(il, instr, 3, registerSize(op2)))));
+ }
+ break;
+ case MIPS_SLLV:
+ il.AddInstruction(SetRegisterOrNop(il, registerSize(op2), registerSize(op1), op1.reg,
+ il.ShiftLeft(registerSize(op2),
+ ReadILOperand(il, instr, 2, registerSize(op2)),
+ il.And(4,
+ ReadILOperand(il, instr, 3, registerSize(op3)),
+ il.Const(4, 0x1f)))));
+ break;
+ case MIPS_DSLL32:
+ op3.immediate += 32;
+ // fall through
+ case MIPS_DSLL:
+ il.AddInstruction(SetRegisterOrNop(il, 8, registerSize(op1), op1.reg,
+ il.ShiftLeft(8,
+ ReadILOperand(il, instr, 2, registerSize(op2)),
+ ReadILOperand(il, instr, 3, registerSize(op3)))));
+ break;
+ case MIPS_DSLLV:
+ il.AddInstruction(SetRegisterOrNop(il, 8, registerSize(op1), op1.reg,
+ il.ShiftLeft(8,
+ ReadILOperand(il, instr, 2, registerSize(op2)),
+ il.And(8,
+ ReadILOperand(il, instr, 3, registerSize(op3)),
+ il.Const(8, 0x3f)))));
+ break;
+ case MIPS_DSRL32:
+ op3.immediate += 32;
+ // fall through
+ case MIPS_DSRL:
+ il.AddInstruction(SetRegisterOrNop(il, 8, registerSize(op1), op1.reg, il.LogicalShiftRight(8, ReadILOperand(il, instr, 2, registerSize(op2)), ReadILOperand(il, instr, 3, registerSize(op3)))));
+ break;
+ case MIPS_DSRLV:
+ il.AddInstruction(SetRegisterOrNop(il, 8, registerSize(op1), op1.reg, il.LogicalShiftRight(8, ReadILOperand(il, instr, 2, registerSize(op2)), il.And(8, ReadILOperand(il, instr, 3, registerSize(op3)), il.Const(8, 0x3f)))));
+ break;
+ case MIPS_DSRA32:
+ op3.immediate += 32;
+ // fall through
+ case MIPS_DSRA:
+ il.AddInstruction(SetRegisterOrNop(il, 8, registerSize(op1), op1.reg, il.ArithShiftRight(8, ReadILOperand(il, instr, 2, registerSize(op2)), ReadILOperand(il, instr, 3, registerSize(op3)))));
+ break;
+ case MIPS_DSRAV:
+ il.AddInstruction(SetRegisterOrNop(il, 8, registerSize(op1), op1.reg, il.ArithShiftRight(8, ReadILOperand(il, instr, 2, registerSize(op2)), il.And(8, ReadILOperand(il, instr, 3, registerSize(op3)), il.Const(8, 0x3f)))));
+ break;
+ case MIPS_SB:
+ il.AddInstruction(il.Store(1,
+ GetILOperandMemoryAddress(il, op2, addrSize),
+ il.LowPart(1,
+ ReadILOperand(il, instr, 1, registerSize(op1)))));
+ break;
+ case MIPS_TRAP:
+ il.AddInstruction(il.Trap(0));
+ break;
+ case MIPS_TEQI:
+ case MIPS_TEQ:
+ ConditionExecute(il, il.CompareEqual(4, ReadILOperand(il, instr, 1, registerSize(op1)), ReadILOperand(il, instr, 2, registerSize(op2))),il.Trap(0));
+ break;
+ case MIPS_TNE:
+ case MIPS_TNEI:
+ ConditionExecute(il, il.CompareNotEqual(4, ReadILOperand(il, instr, 1, registerSize(op1)), ReadILOperand(il, instr, 2, registerSize(op2))),il.Trap(0));
+ break;
+ case MIPS_TGE:
+ case MIPS_TGEI:
+ ConditionExecute(il, il.CompareSignedGreaterEqual(4, ReadILOperand(il, instr, 1, registerSize(op1)), ReadILOperand(il, instr, 2, registerSize(op2))),il.Trap(0));
+ break;
+ case MIPS_TGEIU:
+ case MIPS_TGEU:
+ ConditionExecute(il, il.CompareUnsignedGreaterEqual(4, ReadILOperand(il, instr, 1, registerSize(op1)), ReadILOperand(il, instr, 2, registerSize(op2))),il.Trap(0));
+ break;
+ case MIPS_TLT:
+ case MIPS_TLTI:
+ ConditionExecute(il, il.CompareSignedLessThan(4, ReadILOperand(il, instr, 1, registerSize(op1)), ReadILOperand(il, instr, 2, registerSize(op2))),il.Trap(0));
+ break;
+ case MIPS_TLTIU:
+ case MIPS_TLTU:
+ ConditionExecute(il, il.CompareUnsignedLessThan(4, ReadILOperand(il, instr, 1, registerSize(op1)), ReadILOperand(il, instr, 2, registerSize(op2))),il.Trap(0));
+ break;
+ case MIPS_LH:
+ case MIPS_LHX:
+ case MIPS_LHI:
+ il.AddInstruction(SetRegisterOrNop(il, 2, registerSize(op1), op1.reg,
+ ReadILOperand(il, instr, 2, registerSize(op2), 2), SignExtend));
+ break;
+ case MIPS_LHU:
+ il.AddInstruction(SetRegisterOrNop(il, 2, registerSize(op1), op1.reg,
+ ReadILOperand(il, instr, 2, registerSize(op2), 2),
+ ZeroExtend));
+ break;
+ case MIPS_MADD1:
+ case MIPS_MADD:
+ if (version == MIPS_R5900 && instr.numOperands == 3) {
+ DEFINE_HILO1(MIPS_MADD1);
+ il.AddInstruction(il.SetRegisterSplit(4, hi, lo,
il.Add(8,
- il.RegisterSplit(4, REG_HI, REG_LO),
- il.MultDoublePrecSigned(4,
- ReadILOperand(il, instr, 1, registerSize, 4),
- ReadILOperand(il, instr, 2, registerSize, 4)
+ il.RegisterSplit(4, hi, lo),
+ il.MultDoublePrecSigned(8,
+ ReadILOperand(il, instr, 2, 4, 4),
+ ReadILOperand(il, instr, 3, 4, 4)
)
)
));
-
- SignExtendHiLo(il, registerSize);
- break;
- case MIPS_MADDU:
- il.AddInstruction(il.SetRegisterSplit(4, REG_HI, REG_LO,
+ if (lo == REG_LO)
+ SignExtendHiLo(il, 4);
+ auto rd = op1.reg;
+ if (rd != REG_ZERO)
+ il.AddInstruction(SetRegisterOrNop(il, 4, 8, rd, il.Register(get_register_width(lo, version), lo)));
+ }
+ else
+ {
+ DEFINE_HILO1(MIPS_MADD1);
+ il.AddInstruction(il.SetRegisterSplit(4, hi, lo,
il.Add(8,
- il.RegisterSplit(4, REG_HI, REG_LO),
- il.MultDoublePrecUnsigned(4,
- ReadILOperand(il, instr, 1, registerSize, 4),
- ReadILOperand(il, instr, 2, registerSize, 4)
+ il.RegisterSplit(4, hi, lo),
+ il.MultDoublePrecSigned(4,
+ ReadILOperand(il, instr, 1, 4, 4),
+ ReadILOperand(il, instr, 2, 4, 4)
)
)
));
-
- SignExtendHiLo(il, registerSize);
- break;
- case MIPS_DROTR32:
- op3.immediate += 32;
- // fall through
- case MIPS_DROTR:
- case MIPS_DROTRV:
- il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg, il.RotateRight(8, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize))));
- break;
- case MIPS_ROTR:
- case MIPS_ROTRV:
- il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, il.RotateRight(4, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize))));
- break;
- case MIPS_SDBBP:
- il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_SDBBP, { il.Const(1, op1.immediate )}));
- break;
- case MIPS_SEB:
- il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.SignExtend(registerSize, il.LowPart(1, ReadILOperand(il, instr, 2, registerSize)))));
- break;
- case MIPS_SEH:
- il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.SignExtend(registerSize, il.LowPart(2, ReadILOperand(il, instr, 2, registerSize)))));
- break;
- case MIPS_SH:
- il.AddInstruction(il.Store(2, GetILOperandMemoryAddress(il, op2, addrSize), il.LowPart(2, ReadILOperand(il, instr, 1, registerSize))));
- break;
- case MIPS_SRL:
- il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, il.LogicalShiftRight(4, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize))));
- break;
- case MIPS_SRLV:
- il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, il.LogicalShiftRight(4, ReadILOperand(il, instr, 2, registerSize), il.And(4, ReadILOperand(il, instr, 3, registerSize), il.Const(4, 0x1f)))));
- break;
- case MIPS_SSNOP:
- case MIPS_NOP:
- il.AddInstruction(il.Nop());
- break;
- case MIPS_WSBH:
- il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(op1.reg)}, MIPS_INTRIN_WSBH, {ReadILOperand(il, instr, 2, registerSize)}));
- break;
- case MIPS_DSBH:
- il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(op1.reg)}, MIPS_INTRIN_DSBH, {ReadILOperand(il, instr, 2, registerSize)}));
- break;
- case MIPS_DSHD:
- il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(op1.reg)}, MIPS_INTRIN_DSHD, {ReadILOperand(il, instr, 2, registerSize)}));
- break;
- 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))));
- break;
- case MIPS_ADD_D:
+ if (lo == REG_LO)
+ SignExtendHiLo(il, 4);
+ }
+ break;
+ case MIPS_MADDU1:
+ case MIPS_MADDU:
+ if (version == MIPS_R5900 && instr.numOperands == 3) {
+ DEFINE_HILO1(MIPS_MADDU1);
+ il.AddInstruction(il.SetRegisterSplit(4, hi, lo,
+ il.Add(8,
+ il.RegisterSplit(4, hi, lo),
+ il.MultDoublePrecUnsigned(4,
+ ReadILOperand(il, instr, 2, 4, 4),
+ ReadILOperand(il, instr, 3, 4, 4)
+ ))));
+ if (lo == REG_LO)
+ SignExtendHiLo(il, 4);
+ auto rd = op1.reg;
+ if (rd != REG_ZERO)
+ il.AddInstruction(SetRegisterOrNop(il, 4, 8, rd, il.Register(get_register_width(lo, version), lo), ZeroExtend));
+ }
+ else {
+ DEFINE_HILO1(MIPS_MADDU1);
+ il.AddInstruction(il.SetRegisterSplit(4, hi, lo,
+ il.Add(8,
+ il.RegisterSplit(4, hi, lo),
+ il.MultDoublePrecUnsigned(4,
+ ReadILOperand(il, instr, 1, 4, 4),
+ ReadILOperand(il, instr, 2, 4, 4)
+ ))));
+ if (lo == REG_LO)
+ SignExtendHiLo(il, 4);
+ }
+ break;
+ case MIPS_DROTR32:
+ op3.immediate += 32;
+ // fall through
+ case MIPS_DROTR:
+ case MIPS_DROTRV:
+ il.AddInstruction(SetRegisterOrNop(il, 8, registerSize(op1), op1.reg, il.RotateRight(8, ReadILOperand(il, instr, 2, registerSize(op2)), ReadILOperand(il, instr, 3, registerSize(op3)))));
+ break;
+ case MIPS_ROTR:
+ case MIPS_ROTRV:
+ il.AddInstruction(SetRegisterOrNop(il, 4, registerSize(op1), op1.reg, il.RotateRight(4, ReadILOperand(il, instr, 2, registerSize(op2)), ReadILOperand(il, instr, 3, registerSize(op3)))));
+ break;
+ case MIPS_SDBBP:
+ il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_SDBBP, { il.Const(1, op1.immediate )}));
+ break;
+ case MIPS_SEB:
+ il.AddInstruction(SetRegisterOrNop(il, 1, registerSize(op1), op1.reg, il.LowPart(1, ReadILOperand(il, instr, 2, registerSize(op2))), SignExtend));
+ break;
+ case MIPS_SEH:
+ il.AddInstruction(SetRegisterOrNop(il, 2, registerSize(op1), op1.reg, il.LowPart(2, ReadILOperand(il, instr, 2, registerSize(op2))), SignExtend));
+ break;
+ case MIPS_SH:
+ il.AddInstruction(il.Store(2, GetILOperandMemoryAddress(il, op2, addrSize), il.LowPart(2, ReadILOperand(il, instr, 1, registerSize(op1)))));
+ break;
+ case MIPS_SRL:
+ il.AddInstruction(SetRegisterOrNop(il, 4, registerSize(op1), op1.reg, il.LogicalShiftRight(4, ReadILOperand(il, instr, 2, registerSize(op2)), ReadILOperand(il, instr, 3, registerSize(op3)))));
+ break;
+ case MIPS_SRLV:
+ il.AddInstruction(SetRegisterOrNop(il, 4, registerSize(op1), op1.reg, il.LogicalShiftRight(4, ReadILOperand(il, instr, 2, registerSize(op2)), il.And(4, ReadILOperand(il, instr, 3, registerSize(op3)), il.Const(4, 0x1f)))));
+ break;
+ case MIPS_SSNOP:
+ case MIPS_NOP:
+ il.AddInstruction(il.Nop());
+ break;
+ case MIPS_WSBH:
+ il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(op1.reg)}, MIPS_INTRIN_WSBH, {ReadILOperand(il, instr, 2, registerSize(op2))}));
+ break;
+ case MIPS_DSBH:
+ il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(op1.reg)}, MIPS_INTRIN_DSBH, {ReadILOperand(il, instr, 2, registerSize(op2))}));
+ break;
+ case MIPS_DSHD:
+ il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(op1.reg)}, MIPS_INTRIN_DSHD, {ReadILOperand(il, instr, 2, registerSize(op2))}));
+ break;
+ case MIPS_BGEZALL:
+ case MIPS_BLTZALL:
+ break;
+ 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_S:
+ il.AddInstruction(il.SetRegister(4, op1.reg, il.FloatAdd(4, il.Register(4, op2.reg), il.Register(4, op3.reg))));
+ break;
+ case MIPS_ADD_D:
+ if (registerSize(op1) < 8)
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;
- case MIPS_SUB_S:
- il.AddInstruction(il.SetRegister(4, op1.reg, il.FloatSub(4, il.Register(4, op2.reg), il.Register(4, op3.reg))));
- break;
- case MIPS_SUB_D:
+ il.FloatAdd(8, il.RegisterSplit(4, op2.reg | 1, op2.reg & (~1)),
+ il.RegisterSplit(4, op3.reg + 1, op3.reg))));
+ else
+ 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))));
+ break;
+ case MIPS_SUB_D:
+ if (registerSize(op1) < 8)
il.AddInstruction(il.SetRegisterSplit(4, op1.reg | 1, op1.reg & (~1),
il.FloatSub(8, il.RegisterSplit(4, op2.reg | 1, op2.reg & (~1)),
il.RegisterSplit(4, op3.reg + 1, op3.reg))));
- break;
- case MIPS_MUL_S:
- il.AddInstruction(il.SetRegister(4, op1.reg, il.FloatMult(4, il.Register(4, op2.reg), il.Register(4, op3.reg))));
- break;
- case MIPS_MUL_D:
+ else
+ il.AddInstruction(il.SetRegister(registerSize(op1), op1.reg, il.FloatSub(registerSize(op2),
+ il.Register(registerSize(op2), op2.reg), il.Register(registerSize(op3), op3.reg))));
+ break;
+ case MIPS_MUL_S:
+ il.AddInstruction(il.SetRegister(4, op1.reg, il.FloatMult(4, il.Register(4, op2.reg), il.Register(4, op3.reg))));
+ break;
+ case MIPS_MUL_D:
+ if (registerSize(op1) < 8)
il.AddInstruction(il.SetRegisterSplit(4, op1.reg | 1, op1.reg & (~1),
il.FloatMult(8, il.RegisterSplit(4, op2.reg | 1, op2.reg & (~1)),
il.RegisterSplit(4, op3.reg + 1, op3.reg))));
- break;
- case MIPS_DIV_S:
- il.AddInstruction(il.SetRegister(4, op1.reg, il.FloatDiv(4, il.Register(4, op2.reg), il.Register(4, op3.reg))));
- break;
- case MIPS_DIV_D:
+ else
+ il.AddInstruction(il.SetRegister(registerSize(op1), op1.reg, il.FloatMult(registerSize(op2),
+ il.Register(registerSize(op2), op2.reg), il.Register(registerSize(op3), op3.reg))));
+ break;
+ case MIPS_DIV_S:
+ il.AddInstruction(il.SetRegister(4, op1.reg, il.FloatDiv(4, il.Register(4, op2.reg), il.Register(4, op3.reg))));
+ break;
+ case MIPS_DIV_D:
+ if (registerSize(op1) < 8)
il.AddInstruction(il.SetRegisterSplit(4, op1.reg | 1, op1.reg & (~1),
il.FloatDiv(8, il.RegisterSplit(4, op2.reg | 1, op2.reg & (~1)),
il.RegisterSplit(4, op3.reg + 1, op3.reg))));
- break;
- case MIPS_SQRT_S:
- il.AddInstruction(il.SetRegister(4, op1.reg, il.FloatSqrt(4, il.Register(4, op2.reg))));
- break;
- case MIPS_SQRT_D:
+ else
+ il.AddInstruction(il.SetRegister(registerSize(op1), op1.reg, il.FloatDiv(registerSize(op2),
+ il.Register(registerSize(op2), op2.reg), il.Register(registerSize(op3), op3.reg))));
+ break;
+ case MIPS_SQRT_S:
+ il.AddInstruction(il.SetRegister(4, op1.reg, il.FloatSqrt(4, il.Register(4, op2.reg))));
+ break;
+ case MIPS_SQRT_D:
+ if (registerSize(op1) < 8)
il.AddInstruction(il.SetRegisterSplit(4, op1.reg | 1, op1.reg & (~1),
il.FloatSqrt(8, il.RegisterSplit(4, op2.reg | 1, op2.reg & (~1)))));
- break;
- case MIPS_CVT_S_W:
- il.AddInstruction(il.SetRegister(4, op1.reg, il.IntToFloat(4, ReadILOperand(il, instr, 2, registerSize))));
- break;
- case MIPS_CVT_D_W:
+ else
+ il.AddInstruction(il.SetRegister(registerSize(op1), op1.reg, il.FloatSqrt(registerSize(op2),
+ il.Register(registerSize(op2), op2.reg), il.Register(registerSize(op3), op3.reg))));
+ break;
+ case MIPS_CVT_S_W:
+ il.AddInstruction(il.SetRegister(4, op1.reg, il.IntToFloat(4, ReadILOperand(il, instr, 2, 4))));
+ break;
+ case MIPS_CVT_D_W:
+ if (registerSize(op2) < 8)
il.AddInstruction(il.SetRegisterSplit(4, op1.reg | 1, op1.reg & (~1),
- il.IntToFloat(8, ReadILOperand(il, instr, 2, registerSize))));
- break;
- case MIPS_CVT_W_S:
- il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, il.FloatToInt(4, il.Register(4, op2.reg))));
- break;
- case MIPS_CVT_W_D:
- il.AddInstruction(SetRegisterOrNop(il, 4, registerSize, op1.reg, il.FloatToInt(4,
+ il.IntToFloat(8, ReadILOperand(il, instr, 2, 4))));
+ else
+ il.AddInstruction(SetRegisterOrNop(il, 8, registerSize(op1), op1.reg, il.IntToFloat(8, il.Register(4, op2.reg))));
+ break;
+ case MIPS_CVT_W_S:
+ il.AddInstruction(SetRegisterOrNop(il, 4, registerSize(op1), op1.reg, il.FloatToInt(4, il.Register(4, op2.reg))));
+ break;
+ case MIPS_CVT_W_D:
+ if (registerSize(op2) < 8)
+ il.AddInstruction(SetRegisterOrNop(il, 4, registerSize(op1), op1.reg, il.FloatToInt(4,
il.RegisterSplit(4, op2.reg | 1, op2.reg & (~1)))));
- break;
- case MIPS_CVT_D_S:
+ else
+ il.AddInstruction(SetRegisterOrNop(il, 4, registerSize(op1), op1.reg, il.FloatToInt(4, il.Register(registerSize(op2), op2.reg))));
+ break;
+ case MIPS_CVT_D_S:
+ if (registerSize(op2) < 8)
il.AddInstruction(il.SetRegisterSplit(4, op1.reg | 1, op1.reg & (~1),
il.FloatConvert(8, il.Register(4, op2.reg))));
- break;
- case MIPS_CVT_S_D:
+ else
+ il.AddInstruction(SetRegisterOrNop(il, 8, registerSize(op1), op1.reg, il.FloatConvert(8, il.Register(4, op2.reg))));
+ break;
+ case MIPS_CVT_S_D:
+ if (registerSize(op2) < 8)
il.AddInstruction(il.SetRegister(4, op1.reg, il.FloatConvert(4,
- il.RegisterSplit(4, op2.reg | 1, op2.reg & (~1)))));
- break;
- case MIPS_C_EQ_S:
- if (op1.operandClass == FLAG)
- {
- il.AddInstruction(il.SetFlag(op1.reg, il.FloatCompareEqual(4,
- il.Register(4, op2.reg), il.Register(4, op3.reg))));
- }
- else
- {
- il.AddInstruction(il.SetFlag(FPCCREG_FCC0, il.FloatCompareEqual(4,
- il.Register(4, op1.reg), il.Register(4, op2.reg))));
- }
- break;
- case MIPS_C_EQ_D:
- if (op1.operandClass == FLAG)
- {
+ il.RegisterSplit(4, op2.reg | 1, op2.reg & (~1)))));
+ else
+ il.AddInstruction(SetRegisterOrNop(il, 8, registerSize(op1), op1.reg, il.FloatConvert(4, il.Register(registerSize(op2), op2.reg))));
+ break;
+ case MIPS_C_F_S:
+ case MIPS_C_F_D:
+ case MIPS_C_SF_S:
+ case MIPS_C_SF_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:
+ case MIPS_C_SEQ_S:
+ if (op1.operandClass == FLAG)
+ {
+ il.AddInstruction(il.SetFlag(op1.reg, il.FloatCompareEqual(4,
+ il.Register(4, op2.reg), il.Register(4, op3.reg))));
+ }
+ else
+ {
+ il.AddInstruction(il.SetFlag(FPCCREG_FCC0, il.FloatCompareEqual(4,
+ il.Register(4, op1.reg), il.Register(4, op2.reg))));
+ }
+ break;
+ case MIPS_C_EQ_D:
+ case MIPS_C_SEQ_D:
+ if (op1.operandClass == FLAG)
+ {
+ if (registerSize(op2) < 8)
il.AddInstruction(il.SetFlag(op1.reg, il.FloatCompareEqual(8,
il.RegisterSplit(4, op2.reg | 1, op2.reg & (~1)),
il.RegisterSplit(4, op3.reg | 1, op3.reg & (~1)))));
- }
else
- {
+ il.AddInstruction(il.SetFlag(op1.reg, il.FloatCompareEqual(8,
+ il.Register(8, op2.reg), il.Register(8, op3.reg))));
+ }
+ else
+ {
+ if (registerSize(op2) < 8)
il.AddInstruction(il.SetFlag(FPCCREG_FCC0, il.FloatCompareEqual(8,
il.RegisterSplit(4, op1.reg | 1, op1.reg & (~1)),
il.RegisterSplit(4, op2.reg | 1, op2.reg & (~1)))));
- }
- break;
- case MIPS_C_LE_S:
+ else
+ il.AddInstruction(il.SetFlag(FPCCREG_FCC0, il.FloatCompareEqual(8,
+ il.Register(8, op1.reg), il.Register(8, op2.reg))));
+ }
+ break;
+ case MIPS_C_LE_S:
if (op1.operandClass == FLAG)
{
il.AddInstruction(il.SetFlag(op1.reg, il.FloatCompareLessEqual(4,
@@ -1751,15 +2367,23 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu
case MIPS_C_LE_D:
if (op1.operandClass == FLAG)
{
- il.AddInstruction(il.SetFlag(op1.reg, il.FloatCompareLessEqual(8,
- il.RegisterSplit(4, op2.reg | 1, op2.reg & (~1)),
- il.RegisterSplit(4, op3.reg | 1, op3.reg & (~1)))));
+ if (registerSize(op2) < 8)
+ il.AddInstruction(il.SetFlag(op1.reg, il.FloatCompareLessEqual(8,
+ il.RegisterSplit(4, op2.reg | 1, op2.reg & (~1)),
+ il.RegisterSplit(4, op3.reg | 1, op3.reg & (~1)))));
+ else
+ il.AddInstruction(il.SetFlag(op1.reg, il.FloatCompareLessEqual(8,
+ il.Register(8, op2.reg), il.Register(8, op3.reg))));
}
else
{
- il.AddInstruction(il.SetFlag(FPCCREG_FCC0, il.FloatCompareLessEqual(8,
- il.RegisterSplit(4, op1.reg | 1, op1.reg & (~1)),
- il.RegisterSplit(4, op2.reg | 1, op2.reg & (~1)))));
+ if (registerSize(op2) < 8)
+ il.AddInstruction(il.SetFlag(FPCCREG_FCC0, il.FloatCompareLessEqual(8,
+ il.RegisterSplit(4, op1.reg | 1, op1.reg & (~1)),
+ il.RegisterSplit(4, op2.reg | 1, op2.reg & (~1)))));
+ else
+ il.AddInstruction(il.SetFlag(FPCCREG_FCC0, il.FloatCompareLessEqual(8,
+ il.Register(8, op1.reg), il.Register(8, op2.reg))));
}
break;
case MIPS_C_LT_S:
@@ -1777,15 +2401,23 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu
case MIPS_C_LT_D:
if (op1.operandClass == FLAG)
{
- il.AddInstruction(il.SetFlag(op1.reg, il.FloatCompareLessThan(8,
- il.RegisterSplit(4, op2.reg | 1, op2.reg & (~1)),
- il.RegisterSplit(4, op3.reg | 1, op3.reg & (~1)))));
+ if (registerSize(op2) < 8)
+ il.AddInstruction(il.SetFlag(op1.reg, il.FloatCompareLessThan(8,
+ il.RegisterSplit(4, op2.reg | 1, op2.reg & (~1)),
+ il.RegisterSplit(4, op3.reg | 1, op3.reg & (~1)))));
+ else
+ il.AddInstruction(il.SetFlag(op1.reg, il.FloatCompareLessThan(8,
+ il.Register(8, op2.reg), il.Register(8, op3.reg))));
}
else
{
- il.AddInstruction(il.SetFlag(FPCCREG_FCC0, il.FloatCompareLessThan(8,
- il.RegisterSplit(4, op1.reg | 1, op1.reg & (~1)),
- il.RegisterSplit(4, op2.reg | 1, op2.reg & (~1)))));
+ if (registerSize(op2) < 8)
+ il.AddInstruction(il.SetFlag(FPCCREG_FCC0, il.FloatCompareLessThan(8,
+ il.RegisterSplit(4, op1.reg | 1, op1.reg & (~1)),
+ il.RegisterSplit(4, op2.reg | 1, op2.reg & (~1)))));
+ else
+ il.AddInstruction(il.SetFlag(FPCCREG_FCC0, il.FloatCompareLessThan(8,
+ il.Register(8, op1.reg), il.Register(8, op2.reg))));
}
break;
case MIPS_C_UN_S:
@@ -1803,18 +2435,93 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu
case MIPS_C_UN_D:
if (op1.operandClass == FLAG)
{
- il.AddInstruction(il.SetFlag(op1.reg, il.FloatCompareUnordered(8,
- il.RegisterSplit(4, op2.reg | 1, op2.reg & (~1)),
- il.RegisterSplit(4, op3.reg | 1, op3.reg & (~1)))));
+ if (registerSize(op2) < 8)
+ il.AddInstruction(il.SetFlag(op1.reg, il.FloatCompareUnordered(8,
+ il.RegisterSplit(4, op2.reg | 1, op2.reg & (~1)),
+ il.RegisterSplit(4, op3.reg | 1, op3.reg & (~1)))));
+ else
+ il.AddInstruction(il.SetFlag(op1.reg, il.FloatCompareUnordered(8,
+ il.Register(8, op2.reg), il.Register(8, op3.reg))));
}
else
{
- il.AddInstruction(il.SetFlag(FPCCREG_FCC0, il.FloatCompareUnordered(8,
- il.RegisterSplit(4, op1.reg | 1, op1.reg & (~1)),
- il.RegisterSplit(4, op2.reg | 1, op2.reg & (~1)))));
+ if (registerSize(op2) < 8)
+ il.AddInstruction(il.SetFlag(FPCCREG_FCC0, il.FloatCompareUnordered(8,
+ il.RegisterSplit(4, op1.reg | 1, op1.reg & (~1)),
+ il.RegisterSplit(4, op2.reg | 1, op2.reg & (~1)))));
+ else
+ il.AddInstruction(il.SetFlag(FPCCREG_FCC0, il.FloatCompareUnordered(8,
+ il.Register(8, op1.reg), il.Register(8, op2.reg))));
+ }
+ break;
+ case MIPS_C_NGE_S:
+ if (op1.operandClass == FLAG)
+ {
+ il.AddInstruction(il.SetFlag(op1.reg, il.Not(4, il.FloatCompareGreaterEqual(4,
+ il.Register(4, op2.reg), il.Register(4, op3.reg)))));
+ }
+ else
+ {
+ il.AddInstruction(il.SetFlag(FPCCREG_FCC0, il.Not(4, il.FloatCompareGreaterEqual(4,
+ il.Register(4, op1.reg), il.Register(4, op2.reg)))));
+ }
+ break;
+ case MIPS_C_NGE_D:
+ if (op1.operandClass == FLAG)
+ {
+ if (registerSize(op2) < 8)
+ il.AddInstruction(il.SetFlag(op1.reg, il.Not(8, il.FloatCompareGreaterEqual(8,
+ il.RegisterSplit(4, op2.reg | 1, op2.reg & (~1)),
+ il.RegisterSplit(4, op3.reg | 1, op3.reg & (~1))))));
+ else
+ il.AddInstruction(il.SetFlag(op1.reg, il.Not(8, il.FloatCompareGreaterEqual(8,
+ il.Register(8, op2.reg), il.Register(8, op3.reg)))));
+ }
+ else
+ {
+ if (registerSize(op2) < 8)
+ il.AddInstruction(il.SetFlag(FPCCREG_FCC0, il.Not(8, il.FloatCompareGreaterEqual(8,
+ il.RegisterSplit(4, op1.reg | 1, op1.reg & (~1)),
+ il.RegisterSplit(4, op2.reg | 1, op2.reg & (~1))))));
+ else
+ il.AddInstruction(il.SetFlag(FPCCREG_FCC0, il.Not(8, il.FloatCompareGreaterEqual(8,
+ il.Register(8, op1.reg), il.Register(8, op2.reg)))));
+ }
+ break;
+ case MIPS_C_NGT_S:
+ if (op1.operandClass == FLAG)
+ {
+ il.AddInstruction(il.SetFlag(op1.reg, il.Not(4, il.FloatCompareGreaterThan(4,
+ il.Register(4, op2.reg), il.Register(4, op3.reg)))));
+ }
+ else
+ {
+ il.AddInstruction(il.SetFlag(FPCCREG_FCC0, il.Not(4, il.FloatCompareGreaterThan(4,
+ il.Register(4, op1.reg), il.Register(4, op2.reg)))));
+ }
+ break;
+ case MIPS_C_NGT_D:
+ if (op1.operandClass == FLAG)
+ {
+ if (registerSize(op2) < 8)
+ il.AddInstruction(il.SetFlag(op1.reg, il.Not(8, il.FloatCompareGreaterThan(8,
+ il.RegisterSplit(4, op2.reg | 1, op2.reg & (~1)),
+ il.RegisterSplit(4, op3.reg | 1, op3.reg & (~1))))));
+ else
+ il.AddInstruction(il.SetFlag(op1.reg, il.Not(8, il.FloatCompareGreaterThan(8,
+ il.Register(8, op2.reg), il.Register(8, op3.reg)))));
+ }
+ else
+ {
+ if (registerSize(op2) < 8)
+ il.AddInstruction(il.SetFlag(FPCCREG_FCC0, il.Not(8, il.FloatCompareGreaterEqual(8,
+ il.RegisterSplit(4, op1.reg | 1, op1.reg & (~1)),
+ il.RegisterSplit(4, op2.reg | 1, op2.reg & (~1))))));
+ else
+ il.AddInstruction(il.SetFlag(FPCCREG_FCC0, il.Not(8, il.FloatCompareGreaterEqual(8,
+ il.Register(8, op1.reg), il.Register(8, op2.reg)))));
}
break;
-
case MIPS_SYNC:
{
uint64_t stype = 0;
@@ -1860,7 +2567,7 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu
break;
case MIPS_TLBP:
- il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(REG_INDEX)}, MIPS_INTRIN_TLBSEARCH, {il.Register(registerSize, REG_ENTRY_HI)}));
+ il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(REG_INDEX)}, MIPS_INTRIN_TLBSEARCH, {il.Register(addrSize, REG_ENTRY_HI)}));
break;
case MIPS_TLBR:
il.AddInstruction(il.Intrinsic({
@@ -1868,49 +2575,46 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu
RegisterOrFlag::Register(REG_ENTRY_HI),
RegisterOrFlag::Register(REG_ENTRY_LO1),
RegisterOrFlag::Register(REG_ENTRY_LO0)
- }, MIPS_INTRIN_TLBGET, { il.Register(registerSize, REG_INDEX) }));
+ }, MIPS_INTRIN_TLBGET, { il.Register(addrSize, REG_INDEX) }));
break;
case MIPS_TLBWI:
il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_TLBSET, {
- il.Register(registerSize, REG_INDEX),
- il.Register(registerSize, REG_PAGE_MASK),
- il.Register(registerSize, REG_ENTRY_HI),
- il.Register(registerSize, REG_ENTRY_LO1),
- il.Register(registerSize, REG_ENTRY_LO0)
+ il.Register(addrSize, REG_INDEX),
+ il.Register(addrSize, REG_PAGE_MASK),
+ il.Register(addrSize, REG_ENTRY_HI),
+ il.Register(addrSize, REG_ENTRY_LO1),
+ il.Register(addrSize, REG_ENTRY_LO0)
}));
break;
case MIPS_TLBWR:
il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_TLBSET, {
- il.Register(registerSize, REG_RANDOM),
- il.Register(registerSize, REG_PAGE_MASK),
- il.Register(registerSize, REG_ENTRY_HI),
- il.Register(registerSize, REG_ENTRY_LO1),
- il.Register(registerSize, REG_ENTRY_LO0)
+ il.Register(addrSize, REG_RANDOM),
+ il.Register(addrSize, REG_PAGE_MASK),
+ il.Register(addrSize, REG_ENTRY_HI),
+ il.Register(addrSize, REG_ENTRY_LO1),
+ il.Register(addrSize, REG_ENTRY_LO0)
}));
break;
case MIPS_TLBINV:
il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_TLBINV, {
- il.Register(registerSize, REG_INDEX),
- il.Register(registerSize, REG_ENTRY_HI)
+ il.Register(addrSize, REG_INDEX),
+ il.Register(addrSize, REG_ENTRY_HI)
}));
break;
case MIPS_TLBINVF:
il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_TLBINVF, {
- il.Register(registerSize, REG_INDEX),
+ il.Register(addrSize, REG_INDEX),
}));
break;
case CNMIPS_BADDU:
- il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg,
- il.ZeroExtend(registerSize,
+ il.AddInstruction(SetRegisterOrNop(il, 1, registerSize(op1), op1.reg,
il.Add(1,
- il.LowPart(1, ReadILOperand(il, instr, 2, registerSize, 8)),
- il.LowPart(1, ReadILOperand(il, instr, 3, registerSize, 8))
- )
- )
- ));
+ il.LowPart(1, ReadILOperand(il, instr, 2, registerSize(op2), 8)),
+ il.LowPart(1, ReadILOperand(il, instr, 3, registerSize(op3), 8))
+ ), ZeroExtend));
break;
case CNMIPS_BBIT0:
@@ -1921,10 +2625,10 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu
break;
case CNMIPS_CINS:
- il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg,
+ il.AddInstruction(SetRegisterOrNop(il, 8, registerSize(op1), op1.reg,
il.ShiftLeft(8,
il.And(8,
- ReadILOperand(il, instr, 2, registerSize),
+ ReadILOperand(il, instr, 2, registerSize(op2)),
il.Const(8, (((uint64_t)1) << (op4.immediate + 1)) - 1)),
il.Const(8, op3.immediate)
)
@@ -1932,10 +2636,10 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu
break;
case CNMIPS_CINS32:
- il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg,
+ il.AddInstruction(SetRegisterOrNop(il, 8, registerSize(op1), op1.reg,
il.ShiftLeft(8,
il.And(8,
- ReadILOperand(il, instr, 2, registerSize),
+ ReadILOperand(il, instr, 2, registerSize(op2)),
il.Const(8, (((uint64_t)1) << (op4.immediate + 1)) - 1)),
il.Const(8, op3.immediate + 32)
)
@@ -1943,38 +2647,38 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu
break;
case CNMIPS_DMUL:
- il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg,
+ il.AddInstruction(SetRegisterOrNop(il, 8, registerSize(op1), op1.reg,
il.Mult(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 CNMIPS_EXTS:
// recall: p = op3.immediate, lenm1 = op4.immediate
if (op3.immediate == 0 && op4.immediate == 7)
{
- il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg,
- il.SignExtend(8, il.LowPart(1, ReadILOperand(il, instr, 2, registerSize, registerSize)))
+ il.AddInstruction(SetRegisterOrNop(il, 8, registerSize(op1), op1.reg,
+ il.SignExtend(8, il.LowPart(1, ReadILOperand(il, instr, 2, registerSize(op2), 1))) // XXX: 1 => registerSize
));
}
else if (op3.immediate == 0 && op4.immediate == 0xf)
{
- il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg,
- il.SignExtend(8, il.LowPart(2, ReadILOperand(il, instr, 2, registerSize, registerSize)))
+ il.AddInstruction(SetRegisterOrNop(il, 8, registerSize(op1), op1.reg,
+ il.SignExtend(8, il.LowPart(2, ReadILOperand(il, instr, 2, registerSize(op2), 2))) // XXX: 2 => registerSize
));
}
else if (op3.immediate == 0 && op4.immediate == 0x1f)
{
- il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg,
- il.SignExtend(8, il.LowPart(4, ReadILOperand(il, instr, 2, registerSize, registerSize)))
+ il.AddInstruction(SetRegisterOrNop(il, 8, registerSize(op1), op1.reg,
+ il.SignExtend(8, il.LowPart(4, ReadILOperand(il, instr, 2, registerSize(op2), 4))) // XXX: 4 => registerSize
));
}
else
{
- il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg,
+ il.AddInstruction(SetRegisterOrNop(il, 8, registerSize(op1), op1.reg,
il.ArithShiftRight(8,
il.ShiftLeft(8,
- ReadILOperand(il, instr, 2, registerSize, 8),
+ ReadILOperand(il, instr, 2, registerSize(op2), 8),
il.Const(8, 63 - (op3.immediate + op4.immediate))
),
il.Const(8, 63 - op4.immediate)
@@ -1991,10 +2695,10 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu
}
else
{
- il.AddInstruction(SetRegisterOrNop(il, 8, registerSize, op1.reg,
+ il.AddInstruction(SetRegisterOrNop(il, 8, registerSize(op1), op1.reg,
il.ArithShiftRight(8,
il.ShiftLeft(8,
- ReadILOperand(il, instr, 2, registerSize, 8),
+ ReadILOperand(il, instr, 2, registerSize(op2), 8),
il.Const(8, 63 - (32 + op3.immediate + op4.immediate))
),
il.Const(8, 63 - op4.immediate)
@@ -2004,28 +2708,28 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu
break;
case CNMIPS_POP:
- il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(op1.reg)}, CNMIPS_INTRIN_POP, {ReadILOperand(il, instr, 2, registerSize)}));
+ il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(op1.reg)}, CNMIPS_INTRIN_POP, {ReadILOperand(il, instr, 2, registerSize(op2))}));
break;
case CNMIPS_DPOP:
- il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(op1.reg)}, CNMIPS_INTRIN_DPOP, {ReadILOperand(il, instr, 2, registerSize)}));
+ il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(op1.reg)}, CNMIPS_INTRIN_DPOP, {ReadILOperand(il, instr, 2, registerSize(op2))}));
break;
case CNMIPS_MTM0:
- il.AddInstruction(il.SetRegister(registerSize, CNREG_MPL0, ReadILOperand(il, instr, 1, registerSize)));
+ il.AddInstruction(il.SetRegister(registerSize(op1), CNREG_MPL0, ReadILOperand(il, instr, 1, registerSize(op1))));
break;
case CNMIPS_MTM1:
- il.AddInstruction(il.SetRegister(registerSize, CNREG_MPL1, ReadILOperand(il, instr, 1, registerSize)));
+ il.AddInstruction(il.SetRegister(registerSize(op1), CNREG_MPL1, ReadILOperand(il, instr, 1, registerSize(op1))));
break;
case CNMIPS_MTM2:
- il.AddInstruction(il.SetRegister(registerSize, CNREG_MPL2, ReadILOperand(il, instr, 1, registerSize)));
+ il.AddInstruction(il.SetRegister(registerSize(op1), CNREG_MPL2, ReadILOperand(il, instr, 1, registerSize(op1))));
break;
case CNMIPS_MTP0:
- il.AddInstruction(il.SetRegister(registerSize, CNREG_P0, ReadILOperand(il, instr, 1, registerSize)));
+ il.AddInstruction(il.SetRegister(registerSize(op1), CNREG_P0, ReadILOperand(il, instr, 1, registerSize(op1))));
break;
case CNMIPS_MTP1:
- il.AddInstruction(il.SetRegister(registerSize, CNREG_P1, ReadILOperand(il, instr, 1, registerSize)));
+ il.AddInstruction(il.SetRegister(8, CNREG_P1, ReadILOperand(il, instr, 1, 8)));
break;
case CNMIPS_MTP2:
- il.AddInstruction(il.SetRegister(registerSize, CNREG_P2, ReadILOperand(il, instr, 1, registerSize)));
+ il.AddInstruction(il.SetRegister(8, CNREG_P2, ReadILOperand(il, instr, 1, 8)));
break;
case CNMIPS_RDHWR:
{
@@ -2057,7 +2761,7 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu
GetILOperandMemoryAddress(il, op2, addrSize),
il.Add(4,
il.Load(4, GetILOperandMemoryAddress(il, op2, addrSize)),
- ReadILOperand(il, instr, 1, registerSize, 4)
+ ReadILOperand(il, instr, 1, registerSize(op1), 4)
)
)
);
@@ -2069,30 +2773,30 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu
GetILOperandMemoryAddress(il, op2, addrSize),
il.Add(8,
il.Load(8, GetILOperandMemoryAddress(il, op2, addrSize)),
- ReadILOperand(il, instr, 1, registerSize, 8)
+ ReadILOperand(il, instr, 1, registerSize(op1), 8)
)
)
);
break;
case CNMIPS_SEQ:
- il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.BoolToInt(registerSize,
- il.CompareEqual(registerSize, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize)))));
+ il.AddInstruction(SetRegisterOrNop(il, 1, registerSize(op1), op1.reg, il.BoolToInt(1,
+ il.CompareEqual(registerSize(op2), ReadILOperand(il, instr, 2, registerSize(op2)), ReadILOperand(il, instr, 3, registerSize(op3))))));
break;
case CNMIPS_SEQI:
- il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.BoolToInt(registerSize,
- il.CompareEqual(registerSize, ReadILOperand(il, instr, 2, registerSize), il.Const(registerSize, op3.immediate)))));
+ il.AddInstruction(SetRegisterOrNop(il, 1, registerSize(op1), op1.reg, il.BoolToInt(1,
+ il.CompareEqual(registerSize(op2), ReadILOperand(il, instr, 2, registerSize(op2)), il.Const(registerSize(op2), op3.immediate)))));
break;
case CNMIPS_SNE:
- il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.BoolToInt(registerSize,
- il.CompareNotEqual(registerSize, ReadILOperand(il, instr, 2, registerSize), ReadILOperand(il, instr, 3, registerSize)))));
+ il.AddInstruction(SetRegisterOrNop(il, 1, registerSize(op1), op1.reg, il.BoolToInt(1,
+ il.CompareNotEqual(registerSize(op2), ReadILOperand(il, instr, 2, registerSize(op2)), ReadILOperand(il, instr, 3, registerSize(op3))))));
break;
case CNMIPS_SNEI:
- il.AddInstruction(SetRegisterOrNop(il, registerSize, registerSize, op1.reg, il.BoolToInt(registerSize,
- il.CompareNotEqual(registerSize, ReadILOperand(il, instr, 2, registerSize), il.Const(registerSize, op3.immediate)))));
+ il.AddInstruction(SetRegisterOrNop(il, 1, registerSize(op1), op1.reg, il.BoolToInt(1,
+ il.CompareNotEqual(1, ReadILOperand(il, instr, 2, registerSize(op2)), il.Const(registerSize(op2), op3.immediate)))));
break;
case CNMIPS_SYNCIOBDMA:
@@ -2159,36 +2863,931 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu
break;
- case MIPS_ADDR:
+ case MIPS_MTSAB:
+ {
+ ExprId shiftAmount;
+ if (op1.reg == REG_ZERO)
+ {
+ shiftAmount = il.Const(4,(op2.immediate & 0xF) << 3);
+ }
+ else
+ {
+ auto gprValue = il.Register(4, op1.reg);
+ auto gprLS4 = il.And(4, gprValue, il.Const(4, 0xF));
+ ExprId xorResult;
+ if (op2.immediate & 0xF)
+ {
+ // Extract least-significant 4 bits of immediate value
+ // auto immLS4 = il.And(4, il.Const(4, op2.immediate), il.Const(4, 0xF));
+ auto immLS4 = il.Const(4, op2.immediate & 0xF);
+
+ // Perform XOR operation between GPR[rs][3:0] and immediate[3:0]
+ xorResult = il.Xor(4, gprLS4, immLS4);
+ }
+ else
+ xorResult = gprLS4;
+
+ // Multiply result by 8 (equivalent to left shift by 3)
+ shiftAmount = il.ShiftLeft(4, xorResult, il.Const(4, 3));
+ }
+
+ // Write the result to the SA register
+ il.AddInstruction(il.SetRegister(4, R5900_SA, shiftAmount));
+
+ break;
+ }
+ case MIPS_MTSAH:
+ {
+ auto rsVal = il.And(4, il.Register(4, op1.reg), il.Const(4, 0b111));
+ auto immVal = il.Const(4, op2.immediate & 0b111);
+
+ // Perform XOR
+ auto xorVal = il.Xor(4, rsVal, immVal);
+
+ // Multiply by 16
+ auto shiftAmount = il.Mult(4, xorVal, il.Const(4, 16));
+
+ // Set the SA register
+ il.AddInstruction(il.SetRegister(4, R5900_SA, shiftAmount));
+
+ break;
+ }
+ case MIPS_QFSRV:
+ {
+ if (op2.reg == REG_ZERO)
+ {
+ if (op3.reg == REG_ZERO)
+ il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Const(16, 0)));
+ else
+ il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg,
+ il.LogicalShiftRight(16,
+ il.Register(16, op3.reg),
+ il.Register(1, R5900_SA))));
+ }
+ else if (op3.reg == REG_ZERO)
+ il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg,
+ il.ShiftLeft(16,
+ il.Register(16, op2.reg),
+ il.Register(1, R5900_SA))));
+ else
+ il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg,
+ il.Or(16,
+ il.ShiftLeft(16,
+ il.Register(16, op2.reg),
+ il.Register(1, R5900_SA)),
+ il.LogicalShiftRight(16,
+ il.Register(16, op3.reg),
+ il.Register(1, R5900_SA)))));
+ break;
+ }
+ case MIPS_PADDSB:
+ signedFlag = true;
+ case MIPS_PADDUB:
+ saturate = true;
+ case MIPS_PADDB:
+ {
+ SaturatingAddSub(il, instr, saturate, signedFlag, 1);
+ break;
+ }
+ case MIPS_PADDSH:
+ signedFlag = true;
+ case MIPS_PADDUH:
+ saturate = true;
+ case MIPS_PADDH:
+ {
+ SaturatingAddSub(il, instr, saturate, signedFlag, 2);
+ break;
+ }
+ case MIPS_PADDSW:
+ signedFlag = true;
+ case MIPS_PADDUW:
+ saturate = true;
+ case MIPS_PADDW:
+ {
+ SaturatingAddSub(il, instr, saturate, signedFlag, 4);
+ break;
+ }
+ case MIPS_PSUBSB:
+ signedFlag = true;
+ case MIPS_PSUBUB:
+ saturate = true;
+ case MIPS_PSUBB:
+ {
+ SaturatingAddSub(il, instr, saturate, signedFlag, 1, true);
+ break;
+ }
+ case MIPS_PSUBSH:
+ signedFlag = true;
+ case MIPS_PSUBUH:
+ saturate = true;
+ case MIPS_PSUBH:
+ {
+ SaturatingAddSub(il, instr, saturate, signedFlag, 2, true);
+ break;
+ }
+ case MIPS_PSUBSW:
+ signedFlag = true;
+ case MIPS_PSUBUW:
+ saturate = true;
+ case MIPS_PSUBW:
+ {
+ SaturatingAddSub(il, instr, saturate, signedFlag, 4, true);
+ break;
+ }
+
+ case MIPS_PCPYUD:
+ {
+ // TODO: this really requires indexed vector registers
+ // il.AddInstruction(il.Unimplemented());
+ if (op3.reg == REG_ZERO)
+ {
+ if (op2.reg == REG_ZERO)
+ {
+ il.AddInstruction(il.SetRegister(16, op1.reg, il.Const(16, 0)));
+ }
+ else
+ {
+ il.AddInstruction(il.SetRegister(16, op1.reg,
+ il.LogicalShiftRight(16,
+ il.Register(16, op2.reg),
+ il.Const(1, 64))));
+ }
+ }
+ else if (op2.reg == REG_ZERO)
+ {
+ il.AddInstruction(il.SetRegister(16, op1.reg,
+ il.And(16, il.Register(16, op3.reg),
+ il.ShiftLeft(16, il.Const(8, 0xFFFFFFFFFFFFFFFF), il.Const(1, 64)))));
+ }
+ else
+ {
+ il.AddInstruction(il.SetRegister(16, op1.reg,
+ il.Or(16,
+ il.LogicalShiftRight(16,
+ il.Register(16, op2.reg),
+ il.Const(1, 64)),
+ il.And(16, il.Register(16, op3.reg),
+ il.ShiftLeft(16, il.Const(8, 0xFFFFFFFFFFFFFFFF), il.Const(1, 64))))));
+ }
+ break;
+ }
+ case MIPS_PCPYLD:
+ {
+ 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.Register(2, op2.reg)));
+ il.AddInstruction(il.SetRegister(8, LLIL_TEMP(1), il.LogicalShiftRight(2, il.Register(16, op2.reg), il.Const(1, 64))));
+ for (int i = 0; i < 4; i++)
+ {
+ il.AddInstruction(il.SetRegister(8, LLIL_TEMP(0),
+ il.Or(8,
+ il.Register(8, LLIL_TEMP(0)),
+ il.ShiftLeft(8,
+ il.Register(8, LLIL_TEMP(0)),
+ il.Const(1, 16)))));
+ il.AddInstruction(il.SetRegister(8, LLIL_TEMP(1),
+ il.Or(8,
+ il.Register(8, LLIL_TEMP(1)),
+ il.ShiftLeft(8,
+ il.Register(8, LLIL_TEMP(1)),
+ il.Const(1, 16)))));
+ }
+ il.AddInstruction(il.SetRegister(16, op1.reg,
+ il.Or(16, il.Register(8, LLIL_TEMP(0)), il.ShiftLeft(16, il.Register(8, LLIL_TEMP(1)), il.Const(1, 64)))));
+ break;
+ }
+ case MIPS_PAND:
+ {
+ il.AddInstruction(il.SetRegister(16, op1.reg,
+ il.And(16,
+ il.Register(16, op2.reg),
+ il.Register(16, op3.reg))));
+ break;
+ }
+ case MIPS_PXOR:
+ {
+ il.AddInstruction(il.SetRegister(16, op1.reg,
+ il.Xor(16,
+ il.Register(16, op2.reg),
+ il.Register(16, op3.reg))));
+ break;
+ }
+ case MIPS_POR:
+ {
+ il.AddInstruction(il.SetRegister(16, op1.reg,
+ il.Xor(16,
+ il.Register(16, op2.reg),
+ il.Register(16, op3.reg))));
+ break;
+ }
+ case MIPS_PNOR:
+ {
+ if (op2.reg == REG_ZERO)
+ {
+ if (op3.reg == REG_ZERO)
+ il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Const(16, -1), ZeroExtend));
+ else
+ il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Not(16, il.Register(16, op3.reg)), ZeroExtend));
+ }
+ else if (op3.reg == REG_ZERO)
+ il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Not(16, il.Register(16, op2.reg)), ZeroExtend));
+ else
+ il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg,
+ il.Not(16,
+ il.Or(16,
+ il.Register(16, op2.reg),
+ il.Register(16, op3.reg))), ZeroExtend));
+ break;
+ }
+ case MIPS_PMINH:
+ bytes = 2;
+ case MIPS_PMINW:
+ {
+ ParallelMinMax(il, instr, bytes);
+ break;
+ }
+ case MIPS_PMAXH:
+ bytes = 2;
+ case MIPS_PMAXW:
+ {
+ ParallelMinMax(il, instr, bytes, true);
+ break;
+ }
+ case MIPS_PROT3W:
+ {
+ il.AddInstruction(il.SetRegister(16,
+ LLIL_TEMP(0),
+ il.ShiftLeft(16, il.LogicalShiftRight(16, il.Register(16, op2.reg), il.Const(1, 96)), il.Const(1, 96))));
+ il.AddInstruction(il.SetRegister(16,
+ LLIL_TEMP(0),
+ il.Or(16,
+ il.Register(16, LLIL_TEMP(0)),
+ il.ShiftLeft(16, il.And(16, il.Register(16, op2.reg), il.Const(4, 0xFFFFFFFF)), il.Const(1, 64)))));
+ il.AddInstruction(il.SetRegister(16,
+ LLIL_TEMP(0),
+ il.Or(16,
+ il.Register(16, LLIL_TEMP(0)),
+ il.ShiftLeft(16, il.And(16, il.LogicalShiftRight(16, il.Register(16, op2.reg), il.Const(1, 64)), il.Const(4, 0xFFFFFFFF)), il.Const(1, 32)))));
+ il.AddInstruction(il.SetRegister(16,
+ LLIL_TEMP(0),
+ il.Or(16,
+ il.Register(16, LLIL_TEMP(0)),
+ il.And(16, il.LogicalShiftRight(16, il.Register(16, op2.reg), il.Const(1, 32)), il.Const(4, 0xFFFFFFFF)))));
+ il.AddInstruction(il.SetRegister(16, op1.reg, il.Register(16, LLIL_TEMP(0))));
+ break;
+ }
+
+ case MIPS_LWXC1:
+ il.AddInstruction(
+ il.SetRegister(4, op1.reg,
+ il.Load(4 , GetILOperandMemoryAddress(il, op2, addrSize))));
+ break;
case MIPS_LDXC1:
- case MIPS_LLO:
case MIPS_LUXC1:
+ // TODO: For LUXC1, this needs verification that it really does the right thing with unaligned addresses in both endiannesses
+ il.AddInstruction(
+ il.SetRegister(8, op1.reg,
+ il.Load(8, GetILOperandMemoryAddress(il, op2, addrSize))));
+ break;
+ case MIPS_ADDR:
+ case MIPS_LLO:
case MIPS_LWC1:
+ il.AddInstruction(
+ il.SetRegister(4, op1.reg,
+ il.Load(4, GetILOperandMemoryAddress(il, op2, addrSize))));
+ break;
case MIPS_LWC2:
case MIPS_LWC3:
- case MIPS_LWXC1:
+ il.AddInstruction(MoveToCoprocessor(instr.operation == MIPS_LWC2 ? 2 : 3, il, 4, op1.reg, op1.immediate,
+ ReadILOperand(il, instr, 2, registerSize(op2)), decomposeFlags));
+ break;
+ case MIPS_LDC1:
+ case MIPS_LDC2:
+ case MIPS_LDC3:
+ {
+ unsigned cop;
+ switch (instr.operation)
+ {
+ case MIPS_LDC1: cop = 1; break;
+ case MIPS_LDC2: cop = 2; break;
+ case MIPS_LDC3: cop = 3; break;
+ // default: il.Fail("Unhandled LDC1/2/3 instruction");
+ default: break;
+ }
+ if (version == MIPS_R5900 && instr.operation == MIPS_LDC1)
+ il.AddInstruction(
+ il.SetRegister(8, op1.reg,
+ il.Load(8, GetILOperandMemoryAddress(il, op2, addrSize))));
+ else
+ il.AddInstruction(MoveToCoprocessor(cop, il, 8, op1.reg, op1.immediate,
+ ReadILOperand(il, instr, 2, registerSize(op2)), decomposeFlags));
+ break;
+ }
+ case MIPS_MFSA:
+ il.AddInstruction(SetRegisterOrNop(il, 8, registerSize(op1), op1.reg, il.Register(8, R5900_SA), ZeroExtend));
+ break;
+ case MIPS_MTSA:
+ il.AddInstruction(SetRegisterOrNop(il, registerSize(op1), 8, R5900_SA, il.Register(8, op1.reg), ZeroExtend));
+ break;
+
+ case MIPS_ADDA_S:
+ if (version == MIPS_R5900)
+ {
+ il.AddInstruction(il.SetRegister(4, REG_VACC, il.FloatAdd(4, il.Register(4, op1.reg), il.Register(4, op2.reg))));
+ break;
+ }
+ case MIPS_SUBA_S:
+ if (version == MIPS_R5900)
+ {
+ il.AddInstruction(il.SetRegister(4, REG_VACC, il.FloatSub(4, il.Register(4, op1.reg), il.Register(4, op2.reg))));
+ break;
+ }
+ case MIPS_MULA_S:
+ if (version == MIPS_R5900)
+ {
+ il.AddInstruction(il.SetRegister(4, REG_VACC, il.FloatMult(4, il.Register(4, op1.reg), il.Register(4, op2.reg))));
+ break;
+ }
+ case MIPS_MADDA_S:
+ if (version == MIPS_R5900)
+ {
+ il.AddInstruction(il.SetRegister(4, REG_VACC,
+ il.FloatAdd(4, il.Register(4, REG_VACC),
+ il.FloatMult(4, il.Register(4, op1.reg), il.Register(4, op2.reg)))));
+ break;
+ }
+ case MIPS_MSUBA_S:
+ if (version == MIPS_R5900)
+ {
+ il.AddInstruction(il.SetRegister(4, REG_VACC,
+ il.FloatAdd(4, il.Register(4, REG_VACC),
+ il.FloatMult(4, il.Register(4, op1.reg), il.Register(4, op2.reg)))));
+ break;
+ }
+ case MIPS_MADD_S:
+ if (version == MIPS_R5900)
+ {
+ il.AddInstruction(il.SetRegister(4, op1.reg,
+ il.FloatAdd(4, il.Register(4, REG_VACC),
+ il.FloatMult(4, il.Register(4, op2.reg), il.Register(4, op3.reg)))));
+ break;
+ }
+ case MIPS_MSUB_S:
+ if (version == MIPS_R5900)
+ {
+ il.AddInstruction(il.SetRegister(4, op1.reg,
+ il.FloatAdd(4, il.Register(4, REG_VACC),
+ il.FloatMult(4, il.Register(4, op2.reg), il.Register(4, op3.reg)))));
+ break;
+ }
+
+ case MIPS_LQC2:
+ if (version == MIPS_R5900)
+ {
+ auto reg = op1.reg;
+ if (op2.operandClass == V_REG && reg < REG_VF0)
+ reg += REG_VF0;
+ il.AddInstruction(il.SetRegister(16, reg,
+ ReadILOperand(il, instr, 2, addrSize, 16)));
+ break;
+ }
+ case MIPS_SQC2:
+ if (version == MIPS_R5900)
+ {
+ auto reg = op1.reg;
+ if (op2.operandClass == V_REG && reg < REG_VF0)
+ reg += REG_VF0;
+ il.AddInstruction(
+ WriteILOperand(il, instr, 2, 16, il.Register(16, reg)));
+ break;
+ }
+ case MIPS_QMFC2:
+ case MIPS_QMFC2_I:
+ if (version == MIPS_R5900)
+ {
+ auto reg = op2.reg;
+ if (op2.operandClass == V_REG && reg < REG_VF0)
+ reg += REG_VF0;
+ il.AddInstruction(
+ SetRegisterOrNop(il,16, 16, op1.reg, il.Register(16, reg)));
+ break;
+ }
+ case MIPS_QMTC2:
+ case MIPS_QMTC2_I:
+ if (version == MIPS_R5900)
+ {
+ auto reg = op2.reg;
+ if (op2.operandClass == V_REG && reg < REG_VF0)
+ reg += REG_VF0;
+ il.AddInstruction(
+ il.SetRegister(16, reg, il.Register(16, op1.reg)));
+ break;
+ }
+
+ case MIPS_PEXTLW:
+ case MIPS_PEXTLH:
+ case MIPS_PEXTLB:
+ {
+ switch (instr.operation)
+ {
+ case MIPS_PEXTLW: bytes = 4; break;
+ case MIPS_PEXTLH: bytes = 2; break;
+ case MIPS_PEXTLB: bytes = 1; break;
+ default: bytes = 0;
+ }
+ if (bytes == 0)
+ {
+ il.AddInstruction((il.Unimplemented()));
+ break;
+ }
+ const uint64_t mask = 0xFFFFFFFFFFFFFFFF >> (64 - (8 * bytes));
+ for (int i = 0; i < 8 / bytes; i++)
+ {
+ if (op2.reg != REG_ZERO)
+ {
+ if (i == 0)
+ il.AddInstruction(il.SetRegister(16, LLIL_TEMP(0),
+ il.ShiftLeft(16,
+ il.And(2 * bytes,
+ il.Register(16, op2.reg),
+ il.Const(8, mask)),
+ il.Const(1, 2 * bytes))));
+ else
+ il.AddInstruction(il.SetRegister(16, LLIL_TEMP(0),
+ il.Or(16, il.Register(16, LLIL_TEMP(0)),
+ il.ShiftLeft(16,
+ il.And(2 * bytes,
+ il.LogicalShiftRight(16,
+ il.Register(16, op2.reg),
+ il.Const(1, i * (bytes * 8))), il.Const(bytes, mask)),
+ il.Const(1, i * (16 * bytes + 1))))));
+ }
+ if (op3.reg != REG_ZERO)
+ {
+ if (i == 0)
+ il.AddInstruction(il.SetRegister(16, LLIL_TEMP(1),
+ il.And(2 * bytes,
+ il.Register(16, op3.reg),
+ il.Const(bytes, mask))));
+ else
+ il.AddInstruction(il.SetRegister(16, LLIL_TEMP(1),
+ il.Or(16, il.Register(16, LLIL_TEMP(1)),
+ il.ShiftLeft(16,
+ il.And(2 * bytes,
+ il.LogicalShiftRight(16,
+ il.Register(16, op3.reg),
+ il.Const(1, i * (bytes * 8))), il.Const(bytes, mask)),
+ il.Const(1, i * (16 * bytes))))));
+ }
+ }
+ if (op2.reg == REG_ZERO)
+ {
+ if (op3.reg == REG_ZERO)
+ il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Const(16, 0)));
+ else
+ il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, LLIL_TEMP(1))));
+ }
+ else if (op3.reg == REG_ZERO)
+ il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, LLIL_TEMP(0))));
+ else
+ il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Or(16, il.Register(16, LLIL_TEMP(0)), il.Register(16, LLIL_TEMP(1)))));
+ break;
+ }
+ case MIPS_PEXTUW:
+ case MIPS_PEXTUH:
+ case MIPS_PEXTUB:
+ {
+ switch (instr.operation)
+ {
+ case MIPS_PEXTUW: bytes = 4; break;
+ case MIPS_PEXTUH: bytes = 2; break;
+ case MIPS_PEXTUB: bytes = 1; break;
+ default: bytes = 0;
+ }
+ if (bytes == 0)
+ {
+ il.AddInstruction((il.Unimplemented()));
+ break;
+ }
+ const uint64_t mask = 0xFFFFFFFFFFFFFFFF >> (64 - (8 * bytes));
+ for (int i = 0; i < 8 / bytes; i++)
+ {
+ if (op2.reg != REG_ZERO)
+ {
+ 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))))));
+ }
+ }
+ 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)))));
+ }
+ il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, LLIL_TEMP(0))));
+ break;
+ }
+
+ case MIPS_PSRAH:
+ bytes = 2;
+ case MIPS_PSRAW:
+ {
+ if (bytes == 0)
+ {
+ il.AddInstruction((il.Unimplemented()));
+ break;
+ }
+ const uint64_t mask = 0xFFFFFFFFFFFFFFFF >> (64 - (8 * bytes));
+ const uint64_t shift_amount = op3.immediate;
+ for (int i = 0; i < 16 / bytes; i++)
+ {
+ if (i == 0)
+ il.AddInstruction(il.SetRegister(16, LLIL_TEMP(0),
+ il.SignExtend(bytes,
+ il.And(16,
+ il.ArithShiftRight(16,
+ il.Register(16, op2.reg),
+ il.Const(1, i * 16 + shift_amount)),
+ il.Const(16, mask)))));
+ else
+ il.AddInstruction(il.SetRegister(16, LLIL_TEMP(0),
+ il.Or(16, il.Register(16, LLIL_TEMP(0)),
+ il.ShiftLeft(16,
+ il.SignExtend(bytes,
+ il.And(16,
+ il.ArithShiftRight(16,
+ il.Register(16, op2.reg),
+ il.Const(1, i * 16 + shift_amount)),
+ il.Const(16, mask))),
+ il.Const(1, i * 16)))));
+ }
+ il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, LLIL_TEMP(0))));
+ break;
+ }
+
+ case MIPS_PSLLH:
+ bytes = 2;
+ case MIPS_PSLLW:
+ {
+ if (bytes == 0)
+ {
+ il.AddInstruction((il.Unimplemented()));
+ break;
+ }
+ const uint64_t mask = 0xFFFFFFFFFFFFFFFF >> (64 - (8 * bytes));
+ const uint64_t shift_amount = op3.immediate;
+ for (int i = 0; i < 16 / bytes; i++)
+ {
+ if (i == 0)
+ il.AddInstruction(il.SetRegister(16, LLIL_TEMP(0),
+ il.ShiftLeft(16,
+ il.And(16,
+ il.Register(16, op2.reg),
+ il.Const(16, mask)),
+ il.Const(1, shift_amount))));
+ else
+ il.AddInstruction(il.SetRegister(16, LLIL_TEMP(0),
+ il.Or(16, il.Register(16, LLIL_TEMP(0)),
+ il.ShiftLeft(16,
+ il.And(16,
+ il.LogicalShiftRight(16,
+ il.Register(16, op2.reg),
+ il.Const(1, i * 16)),
+ il.Const(16, mask)),
+ il.Const(1, i * 16 + shift_amount)))));
+ }
+ il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, LLIL_TEMP(0))));
+ break;
+ }
+
+ case MIPS_PCGTB:
+ case MIPS_PCGTH:
+ case MIPS_PCGTW:
+ {
+ if (op2.reg == REG_ZERO && op3.reg == REG_ZERO)
+ {
+ il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Const(16, 0)));
+ break;
+ }
+ switch (instr.operation)
+ {
+ case MIPS_PCGTW: bytes = 4; break;
+ case MIPS_PCGTH: bytes = 2; break;
+ case MIPS_PCGTB: bytes = 1; break;
+ default: bytes = 0;
+ }
+ if (bytes == 0)
+ {
+ il.AddInstruction((il.Unimplemented()));
+ break;
+ }
+ const uint64_t mask = 0xFFFFFFFFFFFFFFFF >> (64 - (8 * bytes));
+ for (int i = 0; i < 16 / bytes; i++)
+ {
+ if (i == 0)
+ il.AddInstruction(il.SetRegister(16, LLIL_TEMP(0),
+ il.BoolToInt(bytes,
+ il.CompareSignedGreaterThan(bytes,
+ op2.reg == REG_ZERO ?
+ il.Const(bytes, 0) :
+ il.And(bytes,
+ il.Register(16, op2.reg),
+ il.Const(bytes, mask)),
+ op3.reg == REG_ZERO ?
+ il.Const(bytes, 0) :
+ il.And(bytes,
+ il.Register(16, op3.reg),
+ il.Const(bytes, mask))))));
+ else
+ il.AddInstruction(il.SetRegister(16, LLIL_TEMP(0),
+ il.Or(16, il.Register(16, LLIL_TEMP(0)),
+ il.ShiftLeft(16,
+ il.BoolToInt(bytes,
+ il.CompareSignedGreaterThan(bytes,
+ op2.reg == REG_ZERO ?
+ il.Const(bytes, 0) :
+ il.And(bytes,
+ il.LogicalShiftRight(16,
+ il.Register(16, op2.reg),
+ il.Const(1, i * bytes * 8)),
+ il.Const(bytes, mask)),
+ op3.reg == REG_ZERO ?
+ il.Const(bytes, 0) :
+ il.And(bytes,
+ il.LogicalShiftRight(16,
+ il.Register(16, op3.reg),
+ il.Const(1, i * bytes * 8)),
+ il.Const(bytes, mask)))),
+ il.Const(1, i * bytes * 8)))));
+ }
+ il.AddInstruction(SetRegisterOrNop(il, 16, 16, op1.reg, il.Register(16, LLIL_TEMP(0))));
+ break;
+ }
+
+ // case MIPS_PEXCH:
+ case MIPS_PEXCW:
+ {
+ il.AddInstruction(il.SetRegister(16, op1.reg,
+ il.Or(16,
+ il.Xor(16, il.Register(16, op2.reg),
+ il.And(16, il.Register(16, op2.reg),
+ il.ShiftLeft(16, il.Const(16, 0xFFFFFFFFFFFFFFFF), il.Const(16, 32)))),
+ il.Or(16,
+ il.ShiftLeft(16,
+ il.And(16, il.LogicalShiftRight(64, il.Register(16, op2.reg), il.Const(16, 64)),
+ il.Const(16, 0xFFFFFFFF)),
+ il.Const(16, 32)),
+ il.ShiftLeft(16,
+ il.And(16, il.LogicalShiftRight(64, il.Register(16, op2.reg), il.Const(16, 32)),
+ il.Const(16, 0xFFFFFFFF)),
+ il.Const(16, 64))
+ ))));
+ break;
+ }
+ case MIPS_PEXEW:
+ {
+ il.AddInstruction(il.SetRegister(16, op1.reg,
+ il.Or(16,
+ il.Xor(16, il.Register(16, op2.reg),
+ il.And(16, il.Register(16, op2.reg),
+ il.ShiftLeft(16, il.Const(16, 0xFFFFFFFFFFFFFFFF), il.Const(16, 32)))),
+ il.Or(16,
+ il.ShiftLeft(16,
+ il.And(16, il.LogicalShiftRight(64, il.Register(16, op2.reg), il.Const(16, 64)),
+ il.Const(16, 0xFFFFFFFF)),
+ il.Const(16, 32)),
+ il.ShiftLeft(16,
+ il.And(16, il.LogicalShiftRight(64, il.Register(16, op2.reg), il.Const(16, 32)),
+ il.Const(16, 0xFFFFFFFF)),
+ il.Const(16, 64))
+ ))));
+ break;
+ }
+ case MIPS_PEXT5:
+ {
+ for (int i = 0; i < 4; i++)
+ {
+ int shift = i * 32;
+ il.AddInstruction(il.SetRegister(4, LLIL_TEMP(i),
+ il.And(4,
+ il.LogicalShiftRight(16,
+ il.Register(16, op2.reg),
+ il.Const(1, shift)),
+ il.Const(2, 0xFFFF))));
+ il.AddInstruction(il.SetRegister(4, LLIL_TEMP(i),
+ il.ShiftLeft(16,
+ il.Or(4,
+ il.Or(4,
+ il.ShiftLeft(4, il.And(4, il.Register(4, LLIL_TEMP(i)), il.Const(4, 1 << 15)), il.Const(1, 31-15)),
+ il.ShiftLeft(4, il.And(4, il.Register(4, LLIL_TEMP(i)), il.Const(4, 0x1f << 10)), il.Const(1, 19-10))),
+ il.Or(4,
+ il.ShiftLeft(4, il.And(4, il.Register(4, LLIL_TEMP(i)), il.Const(4, 0x1f << 5)), il.Const(1, 11-5)),
+ il.ShiftLeft(4, il.And(4, il.Register(4, LLIL_TEMP(i)), il.Const(4, 0x1f)), il.Const(1, 3)))),
+ il.Const(1, shift))));
+
+ }
+ il.AddInstruction(il.SetRegister(16, op1.reg,
+ il.Or(16,
+ il.Or(16, il.Register(16, LLIL_TEMP(0)), il.Register(16, LLIL_TEMP(1))),
+ il.Or(16, il.Register(16, LLIL_TEMP(2)), il.Register(16, LLIL_TEMP(3))))));
+
+ break;
+ }
+ case MIPS_PHMADH:
+ {
+ for (int i = 0; i < 4; i++)
+ {
+ if (i == 0)
+ il.AddInstruction(il.SetRegister(4, LLIL_TEMP(i),
+ il.Add(4,
+ il.Mult(4,
+ il.And(4, il.Register(16, op2.reg), il.Const(2, 0xFFFF)),
+ il.And(4, il.Register(16, op3.reg), il.Const(2, 0xFFFF))),
+ il.Mult(4,
+ il.And(4, il.LogicalShiftRight(16, il.Register(16, op2.reg), il.Const(1, i * 32 + 16)), il.Const(2, 0xFFFF)),
+ il.And(4, il.LogicalShiftRight(16, il.Register(16, op3.reg), il.Const(1, i * 32 + 16)), il.Const(2, 0xFFFF)))
+ )));
+ else
+ il.AddInstruction(il.SetRegister(4, LLIL_TEMP(i),
+ il.Add(4,
+ il.Mult(4,
+ il.And(4, il.LogicalShiftRight(16, il.Register(16, op2.reg), il.Const(1, i * 32)), il.Const(2, 0xFFFF)),
+ il.And(4, il.LogicalShiftRight(16, il.Register(16, op3.reg), il.Const(1, i * 32)), il.Const(2, 0xFFFF))),
+ il.Mult(4,
+ il.And(4, il.LogicalShiftRight(16, il.Register(16, op2.reg), il.Const(1, i * 32 + 16)), il.Const(2, 0xFFFF)),
+ il.And(4, il.LogicalShiftRight(16, il.Register(16, op3.reg), il.Const(1, i * 32 + 16)), il.Const(2, 0xFFFF)))
+ )));
+ }
+ il.AddInstruction(il.SetRegister(16, REG_LO, il.Or(16,
+ il.LowPart(4, il.Register(4, LLIL_TEMP(0))),
+ il.ShiftLeft(16, il.LowPart(4, il.Register(4, LLIL_TEMP(2))), il.Const(1, 64)))));
+ il.AddInstruction(il.SetRegister(16, REG_HI, il.Or(16,
+ il.LowPart(4, il.Register(4, LLIL_TEMP(1))),
+ il.ShiftLeft(16, il.LowPart(4, il.Register(4, LLIL_TEMP(3))), il.Const(1, 64)))));
+ il.AddInstruction(il.SetRegister(16, op1.reg,
+ il.Or(16,
+ il.Or(16,
+ il.LowPart(4, il.Register(4, LLIL_TEMP(0))),
+ il.ShiftLeft(4, il.LowPart(4, il.Register(4, LLIL_TEMP(1))), il.Const(1, 32))),
+ il.Or(16,
+ il.ShiftLeft(4, il.LowPart(4, il.Register(4, LLIL_TEMP(2))), il.Const(1, 64)),
+ il.ShiftLeft(4, il.LowPart(4, il.Register(4, LLIL_TEMP(3))), il.Const(1, 96))))));
+ break;
+ }
+
+ case MIPS_CTC1:
+ case MIPS_CTC2:
+ if (version == MIPS_R5900)
+ {
+ il.AddInstruction(il.SetRegister(4, op2.reg, il.Register(4, op1.reg)));
+ break;
+ }
+ case MIPS_CFC1:
+ case MIPS_CFC2:
+ if (version == MIPS_R5900)
+ {
+ il.AddInstruction(il.SetRegister(4, op1.reg, il.Register(4, op2.reg)));
+ break;
+ }
+
case MIPS_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_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
@@ -2198,10 +3797,14 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu
case MIPS_WRPGPR:
case MIPS_RDPGPR:
case MIPS_SUXC1:
- case MIPS_SWXC1:
// Floating point instructions
case MIPS_RSQRT_D:
case MIPS_RSQRT_S:
+ if (version == MIPS_R5900)
+ {
+ il.AddInstruction(il.SetRegister(4, op1.reg, il.FloatDiv(4, il.Register(4, op3.reg), il.FloatSqrt(4, il.Register(4, op3.reg)))));
+ break;
+ }
case MIPS_RSQRT:
case MIPS_RSQRT1:
case MIPS_RSQRT2:
@@ -2216,11 +3819,851 @@ 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_MADDF_D:
case MIPS_MADDF_S:
- il.AddInstruction(il.Unimplemented());
+ // Unimplemented R5900 instructions
+ case MIPS_DSLRV:
+ case MIPS_PMFHL:
+ case MIPS_PMTHL:
+ case MIPS_PPAC5:
+ case MIPS_PABSW:
+ case MIPS_PCEQW:
+ case MIPS_PADSBH:
+ case MIPS_PABSH:
+ case MIPS_PCEQH:
+ case MIPS_PCEQB:
+ 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_PMADDH:
+ case MIPS_PMSUBH:
+ case MIPS_PHMSBH:
+ case MIPS_PEXEH:
+ case MIPS_PREVH:
+ case MIPS_PMULTH:
+ case MIPS_PDIVBW:
+ case MIPS_PMADDUW:
+ case MIPS_PSRAVW:
+ case MIPS_PMTHI:
+ case MIPS_PMTLO:
+ case MIPS_PINTEH:
+ case MIPS_PMULTUW:
+ case MIPS_PDIVUW:
+ 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.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.SetRegister(4, op1.reg, il.Register(4, op2.reg)),
+ il.SetRegister(4, op1.reg, il.Register(4, op3.reg)));
+ break;
+ }
+
+
+ // R5900 VPU0 (macro) instructions
+ case MIPS_VNOP:
+ il.AddInstruction(il.Nop());
+ break;
+ case MIPS_VWAITQ:
+ il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_R5900_VWAITQ, {}));
+ break;
+
+ case MIPS_VMR32:
+ {
+ unsigned char dest = op1.reg;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.Register(4, op3.reg + REG_VF0_Y)));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.Register(4, op3.reg + REG_VF0_Z)));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.Register(4, op3.reg + REG_VF0_W)));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.Register(4, op3.reg + REG_VF0_X)));
+ break;
+ }
+ case MIPS_VABS:
+ {
+ unsigned char dest = op1.reg;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatAbs(4, il.Register(4, op3.reg + REG_VF0_Y))));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatAbs(4, il.Register(4, op3.reg + REG_VF0_Z))));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatAbs(4, il.Register(4, op3.reg + REG_VF0_W))));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatAbs(4, il.Register(4, op3.reg + REG_VF0_X))));
+ break;
+ }
+ case MIPS_VMOVE:
+ {
+ unsigned char dest = op1.reg;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.Register(4, op3.reg + REG_VF0_X)));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.Register(4, op3.reg + REG_VF0_Y)));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.Register(4, op3.reg + REG_VF0_Z)));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.Register(4, op3.reg + REG_VF0_W)));
+ break;
+ }
+ case MIPS_VMFIR:
+ {
+ unsigned char dest = op1.reg;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.SignExtend(4,il.Register(2, op3.reg))));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.SignExtend(4,il.Register(2, op3.reg))));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.SignExtend(4,il.Register(2, op3.reg))));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.SignExtend(4,il.Register(2, op3.reg))));
+ break;
+ }
+ case MIPS_VMTIR:
+ {
+ il.AddInstruction(il.SetRegister(2, op1.reg, il.Register(4, op2.reg + REG_VF0_X + (op2.immediate - 1) * 33)));
+ break;
+ }
+
+ case MIPS_VADD:
+ {
+ unsigned char dest = op1.reg;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + REG_VF0_X))));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + REG_VF0_Y))));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + REG_VF0_Z))));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + REG_VF0_W))));
+ break;
+ }
+ case MIPS_VADDA:
+ {
+ unsigned char dest = op1.reg;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_X - REG_VACC, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + REG_VF0_X))));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Y - REG_VACC, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + REG_VF0_Y))));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Z - REG_VACC, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + REG_VF0_Z))));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_W - REG_VACC, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + REG_VF0_W))));
+ break;
+ }
+ case MIPS_VADDAx:
+ case MIPS_VADDAy:
+ case MIPS_VADDAz:
+ case MIPS_VADDAw:
+ {
+ unsigned char dest = op1.reg;
+ auto bc = REG_VF0_X + (op4.immediate - 1) * 33;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_X - REG_VACC, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + bc))));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Y - REG_VACC, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + bc))));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Z - REG_VACC, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + bc))));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_W - REG_VACC, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + bc))));
+ break;
+ }
+ case MIPS_VADDx:
+ case MIPS_VADDy:
+ case MIPS_VADDz:
+ case MIPS_VADDw:
+ {
+ unsigned char dest = op1.reg;
+ auto bc = REG_VF0_X + (op4.immediate - 1) * 33;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + bc))));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + bc))));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + bc))));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + bc))));
+ break;
+ }
+ case MIPS_VADDq:
+ case MIPS_VADDi:
+ {
+ unsigned char dest = op1.reg;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg))));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg))));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg))));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatAdd(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg))));
+ break;
+ }
+
+ // VSUB
+ case MIPS_VSUB:
+ {
+ unsigned char dest = op1.reg;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + REG_VF0_X))));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + REG_VF0_Y))));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + REG_VF0_Z))));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + REG_VF0_W))));
+ break;
+ }
+ case MIPS_VSUBA:
+ {
+ unsigned char dest = op1.reg;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_X - REG_VACC, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + REG_VF0_X))));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Y - REG_VACC, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + REG_VF0_Y))));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Z - REG_VACC, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + REG_VF0_Z))));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_W - REG_VACC, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + REG_VF0_W))));
+ break;
+ }
+ case MIPS_VSUBAx:
+ case MIPS_VSUBAy:
+ case MIPS_VSUBAz:
+ case MIPS_VSUBAw:
+ {
+ unsigned char dest = op1.reg;
+ auto bc = REG_VF0_X + (op4.immediate - 1) * 33;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_X - REG_VACC, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + bc))));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Y - REG_VACC, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + bc))));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Z - REG_VACC, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + bc))));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_W - REG_VACC, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + bc))));
+ break;
+ }
+ case MIPS_VSUBx:
+ case MIPS_VSUBy:
+ case MIPS_VSUBz:
+ case MIPS_VSUBw:
+ {
+ unsigned char dest = op1.reg;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg))));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg))));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg))));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg))));
+ break;
+ }
+ case MIPS_VSUBq:
+ case MIPS_VSUBi:
+ {
+ unsigned char dest = op1.reg;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg))));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg))));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg))));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatSub(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg))));
+ break;
+ }
+
+ // VMUL
+ case MIPS_VMUL:
+ {
+ unsigned char dest = op1.reg;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + REG_VF0_X))));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + REG_VF0_Y))));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + REG_VF0_Z))));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + REG_VF0_W))));
+ break;
+ }
+ case MIPS_VMULA:
+ {
+ unsigned char dest = op1.reg;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_X - REG_VACC, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + REG_VF0_X))));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Y - REG_VACC, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + REG_VF0_Y))));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Z - REG_VACC, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + REG_VF0_Z))));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_W - REG_VACC, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + REG_VF0_W))));
+ break;
+ }
+ case MIPS_VMULAx:
+ case MIPS_VMULAy:
+ case MIPS_VMULAz:
+ case MIPS_VMULAw:
+ {
+ unsigned char dest = op1.reg;
+ auto bc = REG_VF0_X + (op4.immediate - 1) * 33;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_X - REG_VACC, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + bc))));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Y - REG_VACC, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + bc))));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Z - REG_VACC, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + bc))));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_W - REG_VACC, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + bc))));
+ break;
+ }
+ case MIPS_VMULAq:
+ case MIPS_VMULAi:
+ {
+ unsigned char dest = op1.reg;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_X - REG_VACC, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg))));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Y - REG_VACC, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg))));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Z - REG_VACC, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg))));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_W - REG_VACC, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg))));
+ break;
+ }
+
+ case MIPS_VMULx:
+ case MIPS_VMULy:
+ case MIPS_VMULz:
+ case MIPS_VMULw:
+ {
+ unsigned char dest = op1.reg;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg))));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg))));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg))));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg))));
break;
+ }
+ case MIPS_VMULq:
+ case MIPS_VMULi:
+ {
+ unsigned char dest = op1.reg;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg))));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg))));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg))));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg))));
+ break;
+ }
+
+ case MIPS_VMADD:
+ {
+ unsigned char dest = op1.reg;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatAdd(4, il.Register(4, REG_VACC_X), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + REG_VF0_X)))));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatAdd(4, il.Register(4, REG_VACC_Y), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + REG_VF0_Y)))));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatAdd(4, il.Register(4, REG_VACC_Z), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + REG_VF0_Z)))));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatAdd(4, il.Register(4, REG_VACC_W), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + REG_VF0_W)))));
+ break;
+ }
+ case MIPS_VMADDA:
+ {
+ unsigned char dest = op1.reg;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_X - REG_VACC, il.FloatAdd(4, il.Register(4, op2.reg + REG_VACC_X - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + REG_VF0_X)))));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Y - REG_VACC, il.FloatAdd(4, il.Register(4, op2.reg + REG_VACC_Y - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + REG_VF0_Y)))));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Z - REG_VACC, il.FloatAdd(4, il.Register(4, op2.reg + REG_VACC_Z - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + REG_VF0_Z)))));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_W - REG_VACC, il.FloatAdd(4, il.Register(4, op2.reg + REG_VACC_W - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + REG_VF0_W)))));
+ break;
+ }
+ case MIPS_VMSUB:
+ {
+ unsigned char dest = op1.reg;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatSub(4, il.Register(4, REG_VACC_X), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + REG_VF0_X)))));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatSub(4, il.Register(4, REG_VACC_Y), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + REG_VF0_Y)))));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatSub(4, il.Register(4, REG_VACC_Z), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + REG_VF0_Z)))));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatSub(4, il.Register(4, REG_VACC_W), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + REG_VF0_W)))));
+ break;
+ }
+ case MIPS_VMSUBA:
+ {
+ unsigned char dest = op1.reg;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_X - REG_VACC, il.FloatSub(4, il.Register(4, op2.reg + REG_VACC_X - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + REG_VF0_X)))));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Y - REG_VACC, il.FloatSub(4, il.Register(4, op2.reg + REG_VACC_Y - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + REG_VF0_Y)))));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Z - REG_VACC, il.FloatSub(4, il.Register(4, op2.reg + REG_VACC_Z - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + REG_VF0_Z)))));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_W - REG_VACC, il.FloatSub(4, il.Register(4, op2.reg + REG_VACC_W - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + REG_VF0_W)))));
+ break;
+ }
+ case MIPS_VMADDAx:
+ case MIPS_VMADDAy:
+ case MIPS_VMADDAz:
+ case MIPS_VMADDAw:
+ {
+ unsigned char dest = op1.reg;
+ auto bc = REG_VF0_X + (op4.immediate - 1) * 33;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_X - REG_VACC, il.FloatAdd(4, il.Register(4, op2.reg + REG_VACC_X - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + bc)))));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Y - REG_VACC, il.FloatAdd(4, il.Register(4, op2.reg + REG_VACC_Y - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + bc)))));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Z - REG_VACC, il.FloatAdd(4, il.Register(4, op2.reg + REG_VACC_Z - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + bc)))));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_W - REG_VACC, il.FloatAdd(4, il.Register(4, op2.reg + REG_VACC_W - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + bc)))));
+ break;
+ }
+ case MIPS_VMSUBAx:
+ case MIPS_VMSUBAy:
+ case MIPS_VMSUBAz:
+ case MIPS_VMSUBAw:
+ {
+ unsigned char dest = op1.reg;
+ auto bc = REG_VF0_X + (op4.immediate - 1) * 33;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_X - REG_VACC, il.FloatSub(4, il.Register(4, op2.reg + REG_VACC_X - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + bc)))));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Y - REG_VACC, il.FloatSub(4, il.Register(4, op2.reg + REG_VACC_Y - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + bc)))));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_Z - REG_VACC, il.FloatSub(4, il.Register(4, op2.reg + REG_VACC_Z - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + bc)))));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VACC_W - REG_VACC, il.FloatSub(4, il.Register(4, op2.reg + REG_VACC_W - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + bc)))));
+ break;
+ }
+ case MIPS_VMADDx:
+ case MIPS_VMADDy:
+ case MIPS_VMADDz:
+ case MIPS_VMADDw:
+ {
+ unsigned char dest = op1.reg;
+ auto bc = REG_VF0_X + (op4.immediate - 1) * 33;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatAdd(4, il.Register(4, REG_VACC_X), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + bc)))));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatAdd(4, il.Register(4, REG_VACC_Y), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + bc)))));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatAdd(4, il.Register(4, REG_VACC_Z), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + bc)))));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatAdd(4, il.Register(4, REG_VACC_W), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + bc)))));
+ break;
+ }
+ case MIPS_VMSUBx:
+ case MIPS_VMSUBy:
+ case MIPS_VMSUBz:
+ case MIPS_VMSUBw:
+ {
+ unsigned char dest = op1.reg;
+ auto bc = REG_VF0_X + (op4.immediate - 1) * 33;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatSub(4, il.Register(4, REG_VACC_X), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + bc)))));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatSub(4, il.Register(4, REG_VACC_Y), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + bc)))));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatSub(4, il.Register(4, REG_VACC_Z), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + bc)))));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatSub(4, il.Register(4, REG_VACC_W), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg + bc)))));
+ break;
+ }
+ case MIPS_VMADDq:
+ case MIPS_VMADDi:
+ {
+ unsigned char dest = op1.reg;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatAdd(4, il.Register(4, op2.reg + REG_VACC_X - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg)))));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatAdd(4, il.Register(4, op2.reg + REG_VACC_Y - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg)))));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatAdd(4, il.Register(4, op2.reg + REG_VACC_Z - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg)))));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatAdd(4, il.Register(4, op2.reg + REG_VACC_W - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg)))));
+ break;
+ }
+ case MIPS_VMSUBq:
+ case MIPS_VMSUBi:
+ {
+ unsigned char dest = op1.reg;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatSub(4, il.Register(4, op2.reg + REG_VACC_X - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg)))));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatSub(4, il.Register(4, op2.reg + REG_VACC_Y - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg)))));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatSub(4, il.Register(4, op2.reg + REG_VACC_Z - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg)))));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatSub(4, il.Register(4, op2.reg + REG_VACC_W - REG_VACC), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_W), il.Register(4, op4.reg)))));
+ break;
+ }
+ case MIPS_VDIV:
+ {
+ il.AddInstruction(il.SetRegister(4, op1.reg, il.FloatDiv(4, il.Register(4, op2.reg + REG_VF0_X + (op2.immediate) * 33), il.Register(4, op3.reg + REG_VF0_X + (op3.immediate) * 33))));
+ break;
+ }
+
+ case MIPS_VSQRT:
+ {
+ il.AddInstruction(il.SetRegister(4, op1.reg, il.FloatSqrt(4, il.Register(4, op2.reg + REG_VF0_X + (op2.immediate) * 33))));
+ break;
+ }
+ case MIPS_VRSQRT:
+ {
+ il.AddInstruction(il.SetRegister(4, op1.reg, il.FloatDiv(4, il.Register(4, op2.reg + REG_VF0_X + (op2.immediate) * 33), il.FloatSqrt(4, il.Register(4, op3.reg + REG_VF0_X + (op3.immediate) * 33)))));
+ break;
+ }
+
+ // VF[fd]x = ACCx - VF[fs]y × VF[ft]z
+ // VF[fd]y = ACCy - VF[fs]z × VF[ft]x
+ // VF[fd]z = ACCz - VF[fs]x × VF[ft]y
+ case MIPS_VOPMSUB:
+ {
+ unsigned char dest = op1.reg;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatSub(4, il.Register(4, REG_VACC_X), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Y), il.Register(4, op4.reg + REG_VF0_Z)))));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatSub(4, il.Register(4, REG_VACC_Y), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_Z), il.Register(4, op4.reg + REG_VF0_X)))));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatSub(4, il.Register(4, REG_VACC_Z), il.FloatMult(4, il.Register(4, op3.reg + REG_VF0_X), il.Register(4, op4.reg + REG_VF0_Y)))));
+ break;
+ }
+ // ACCx = VF[fs]y × VF[ft]z
+ // ACCy = VF[fs]z × VF[ft]x
+ // ACCz = VF[fs]x × VF[ft]y
+ case MIPS_VOPMULA:
+ {
+ unsigned char dest = op1.reg;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, REG_VACC_X, il.FloatMult(4, il.Register(4, op2.reg + REG_VF0_Y), il.Register(4, op3.reg + REG_VF0_Z))));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, REG_VACC_Y, il.FloatMult(4, il.Register(4, op2.reg + REG_VF0_Z), il.Register(4, op3.reg + REG_VF0_X))));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, REG_VACC_Z, il.FloatMult(4, il.Register(4, op2.reg + REG_VF0_X), il.Register(4, op3.reg + REG_VF0_Y))));
+ break;
+ }
+
+ case MIPS_VILWR:
+ {
+ unsigned char dest = op1.reg;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(op2.reg)}, MIPS_INTRIN_R5900_VU_MEM_LOAD, {il.Mult(4, il.Register(4, op3.reg), il.Const(4, 16)), il.Const(2, 0)}));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(op2.reg)}, MIPS_INTRIN_R5900_VU_MEM_LOAD, {il.Mult(4, il.Register(4, op3.reg), il.Const(4, 16)), il.Const(2, 1)}));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(op2.reg)}, MIPS_INTRIN_R5900_VU_MEM_LOAD, {il.Mult(4, il.Register(4, op3.reg), il.Const(4, 16)), il.Const(2, 2)}));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.Intrinsic({RegisterOrFlag::Register(op2.reg)}, MIPS_INTRIN_R5900_VU_MEM_LOAD, {il.Mult(4, il.Register(4, op3.reg), il.Const(4, 16)), il.Const(2, 3)}));
+ break;
+ }
+
+ case MIPS_VISWR:
+ {
+ unsigned char dest = op1.reg;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_R5900_VU_MEM_STORE, {il.Mult(4, il.Register(4, op3.reg), il.Const(4, 16)), il.Const(2, 0), il.Register(4, op2.reg)}));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_R5900_VU_MEM_STORE, {il.Mult(4, il.Register(4, op3.reg), il.Const(4, 16)), il.Const(2, 1), il.Register(4, op2.reg)}));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_R5900_VU_MEM_STORE, {il.Mult(4, il.Register(4, op3.reg), il.Const(4, 16)), il.Const(2, 2), il.Register(4, op2.reg)}));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_R5900_VU_MEM_STORE, {il.Mult(4, il.Register(4, op3.reg), il.Const(4, 16)), il.Const(2, 3), il.Register(4, op2.reg)}));
+ break;
+ }
+
+ case MIPS_VLQI:
+ case MIPS_VLQD:
+ {
+ 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:
+ {
+ unsigned char dest = op1.reg;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_R5900_VU_MEM_STORE, {il.Mult(4, il.Register(4, op3.reg), il.Const(4, 16)), il.Const(2, 0), il.Register(4, op2.reg + REG_VF0_X)}));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_R5900_VU_MEM_STORE, {il.Mult(4, il.Register(4, op3.reg), il.Const(4, 16)), il.Const(2, 1), il.Register(4, op2.reg + REG_VF0_Y)}));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_R5900_VU_MEM_STORE, {il.Mult(4, il.Register(4, op3.reg), il.Const(4, 16)), il.Const(2, 2), il.Register(4, op2.reg + REG_VF0_Z)}));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_R5900_VU_MEM_STORE, {il.Mult(4, il.Register(4, op3.reg), il.Const(4, 16)), il.Const(2, 3), il.Register(4, op2.reg + REG_VF0_W)}));
+ il.AddInstruction(il.SetRegister(2, op3.reg, il.Add(2, il.Register(2, op3.reg), il.Const(2, op1.immediate))));
+ break;
+ }
+
+ case MIPS_VCALLMS:
+ {
+ il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_R5900_VU0_CALLMS, {il.Const(4, op1.immediate << 3)}));
+ break;
+ }
+ case MIPS_VCALLMSR:
+ {
+ il.AddInstruction(il.Intrinsic({}, MIPS_INTRIN_R5900_VU0_CALLMSR, {}));
+ break;
+ }
+
+ case MIPS_VIADD:
+ case MIPS_VIADDI:
+ {
+ il.AddInstruction(il.SetRegister(2, op1.reg, il.Add(2, il.Register(2, op2.reg), ReadILOperand(il, instr, 3, 2, 1))));
+ break;
+ }
+ case MIPS_VFTOI0:
+ {
+ unsigned char dest = op1.reg;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.FloatToInt(4, il.Register(4, op3.reg + REG_VF0_X))));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.FloatToInt(4, il.Register(4, op3.reg + REG_VF0_Y))));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.FloatToInt(4, il.Register(4, op3.reg + REG_VF0_Z))));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.FloatToInt(4, il.Register(4, op3.reg + REG_VF0_W))));
+ break;
+ }
+ case MIPS_VITOF0:
+ {
+ unsigned char dest = op1.reg;
+ if (dest & (1 << 3))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_X, il.IntToFloat(4, il.Register(4, op3.reg + REG_VF0_X))));
+ if (dest & (1 << 2))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Y, il.IntToFloat(4, il.Register(4, op3.reg + REG_VF0_Y))));
+ if (dest & (1 << 1))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_Z, il.IntToFloat(4, il.Register(4, op3.reg + REG_VF0_Z))));
+ if (dest & (1 << 0))
+ il.AddInstruction(il.SetRegister(4, op2.reg + REG_VF0_W, il.IntToFloat(4, il.Register(4, op3.reg + REG_VF0_W))));
+ break;
+ }
+ case MIPS_VFTOI15:
+ case MIPS_VFTOI12:
+ case MIPS_VFTOI4:
+ {
+ int shift = 4;
+ switch (instr.operation)
+ {
+ case MIPS_VFTOI15: shift = 15; break;
+ case MIPS_VFTOI12: shift = 12; break;
+ case MIPS_VFTOI4: shift = 4; break;
+ default: shift = 0;
+ }
+ if (shift == 0)
+ {
+ il.AddInstruction((il.Unimplemented()));
+ 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;
+ default: shift = 0;
+ }
+ if (shift == 0)
+ {
+ il.AddInstruction((il.Unimplemented()));
+ 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;
+ }
// instructions that are just internal placeholders for other
// decode tables; these will never be implemented because they're
@@ -2229,6 +4672,10 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu
case MIPS_COP0:
case MIPS_COP1:
case MIPS_COP1X:
+ case MIPS_MMI0:
+ case MIPS_MMI1:
+ case MIPS_MMI2:
+ case MIPS_MMI3:
il.AddInstruction(il.Undefined());
break;
diff --git a/arch/mips/il.h b/arch/mips/il.h
index df84f4a6..2c7d0413 100644
--- a/arch/mips/il.h
+++ b/arch/mips/il.h
@@ -79,6 +79,15 @@ enum MipsIntrinsic : uint32_t
CNMIPS_INTRIN_HWR31,
CNMIPS_INTRIN_POP,
CNMIPS_INTRIN_DPOP,
+
+ MIPS_INTRIN_R5900_VWAITQ,
+ MIPS_INTRIN_R5900_VU_MEM_LOAD,
+ MIPS_INTRIN_R5900_VU_MEM_STORE,
+ MIPS_INTRIN_R5900_VU0_CALLMS,
+ MIPS_INTRIN_R5900_VU0_CALLMSR,
+
+ MIPS_INTRIN_COP0_CONDITION,
+
MIPS_INTRIN_INVALID=0xFFFFFFFF,
};
@@ -88,6 +97,79 @@ bool GetLowLevelILForInstruction(
BinaryNinja::LowLevelILFunction& il,
mips::Instruction& instr,
size_t addrSize,
- uint32_t decomposeFlags);
+ uint32_t decomposeFlags,
+ mips::MipsVersion version);
+
+BinaryNinja::ExprId GetConditionForInstruction(BinaryNinja::LowLevelILFunction& il, mips::Instruction& instr, std::function<size_t(mips::InstructionOperand&)> registerSize);
+#ifdef __cplusplus
+extern "C" {
+ namespace mips {
+#endif
-BinaryNinja::ExprId GetConditionForInstruction(BinaryNinja::LowLevelILFunction& il, mips::Instruction& instr, size_t registerSize);
+static inline const size_t get_register_width(size_t reg, MipsVersion version, size_t maxWidth=8) {
+ size_t width = 32;
+ switch (version)
+ {
+ case MIPS_1:
+ width = 32;
+ break;
+ case MIPS_2:
+ case MIPS_3:
+ case MIPS_4:
+ case MIPS_32:
+ if (reg < FPREG_F0 || reg > FPREG_F31)
+ {
+ width = 32;
+ break;
+ }
+ case MIPS_64:
+ width = 64;
+ break;
+ case MIPS_R5900:
+ switch (reg)
+ {
+ case REG_LO:
+ case REG_HI:
+ width = 128;
+ break;
+ case REG_LO1:
+ case REG_HI1:
+ width = 64;
+ break;
+ case R5900_SA:
+ case REG_VI:
+ case REG_VQ:
+ case REG_VR: // Technically 23-bit
+ case REG_VP:
+ width = 32;
+ break;
+ default:
+ if (reg >= REG_VI0 && reg <= REG_VI15)
+ width = 16;
+ else if (reg >= REG_VCCR_STATUS && reg <= REG_VCCR_CMSAR1)
+ width = 32;
+ else if (REG_ZERO <= reg && reg <= REG_RA)
+ width = 128; // 64; // 128
+ else if (FPREG_F0 <= reg && reg <= FPREG_F31)
+ width = 32;
+ else if (reg >= REG_VACC && reg <= REG_VF31)
+ width = 128;
+ else if (reg >= REG_VACC_X && reg <= REG_VF31_W)
+ width = 32;
+ else if (reg >= REG_VACC_XY && reg <= REG_VF31_ZW)
+ width = 64;
+ else if (reg >= REG_VACC_XYZ && reg <= REG_VF31_YZW)
+ width = 96;
+ else if (reg >= REG_VACC_XYZW && reg <= REG_VF31_XYZW)
+ width = 128;
+ }
+ default:
+ break;
+ }
+ width /= 8;
+ return width <= maxWidth ? width : maxWidth;
+}
+#ifdef __cplusplus
+}
+}//end namespace
+#endif \ No newline at end of file
diff --git a/arch/mips/mips/mips.c b/arch/mips/mips/mips.c
index e046d795..ee323f9d 100644
--- a/arch/mips/mips/mips.c
+++ b/arch/mips/mips/mips.c
@@ -10,6 +10,7 @@ using namespace mips;
#endif
#define REG_ reg
+#define V_REG_ reg
#define FLAG_ reg
#define FPREG_ reg
#define FPCCREG_ reg
@@ -22,6 +23,7 @@ using namespace mips;
do { \
instruction->operands[0].operandClass = A;\
instruction->operands[0].VAR(A) = a;\
+ instruction->numOperands = 1;\
} while (0);
#define INS_2(A,a,B,b)\
@@ -30,6 +32,7 @@ using namespace mips;
instruction->operands[0].VAR(A) = a;\
instruction->operands[1].operandClass = B;\
instruction->operands[1].VAR(B) = b;\
+ instruction->numOperands = 2;\
} while (0);
#define INS_3(A,a,B,b,C,c)\
@@ -40,6 +43,7 @@ using namespace mips;
instruction->operands[1].VAR(B) = b;\
instruction->operands[2].operandClass = C;\
instruction->operands[2].VAR(C) = c;\
+ instruction->numOperands = 3;\
} while (0);
#define INS_4(A,a,B,b,C,c,D,d)\
@@ -52,6 +56,7 @@ using namespace mips;
instruction->operands[2].VAR(C) = c;\
instruction->operands[3].operandClass = D;\
instruction->operands[3].VAR(D) = d;\
+ instruction->numOperands = 4;\
} while (0);
@@ -67,7 +72,7 @@ static Operation cavium_mips_base_table[8][8] = {
};
//Fields are: [Version][opcode_high][opcode_low]
-static Operation mips_base_table[6][8][8] = {
+static Operation mips_base_table[7][8][8] = {
{ //MIPS version 1
{MIPS_INVALID, MIPS_INVALID, MIPS_J, MIPS_JAL, MIPS_BEQ, MIPS_BNE, MIPS_BLEZ, MIPS_BGTZ},
{MIPS_ADDI, MIPS_ADDIU, MIPS_SLTI, MIPS_SLTIU, MIPS_ANDI, MIPS_ORI, MIPS_XORI, MIPS_LUI},
@@ -122,11 +127,20 @@ static Operation mips_base_table[6][8][8] = {
{MIPS_SB, MIPS_SH, MIPS_SWL, MIPS_SW, MIPS_SDL, MIPS_SDR, MIPS_SWR, MIPS_CACHE},
{MIPS_LL, MIPS_LWC1, MIPS_LWC2, MIPS_PREF, MIPS_LLD, MIPS_LDC1, MIPS_LDC2, MIPS_LD},
{MIPS_SC, MIPS_SWC1, MIPS_SWC2, MIPS_INVALID, MIPS_SCD, MIPS_SDC1, MIPS_SDC2, MIPS_SD}
+ },{ // MIPS r5900
+ {MIPS_INVALID, MIPS_INVALID, MIPS_J, MIPS_JAL, MIPS_BEQ, MIPS_BNE, MIPS_BLEZ, MIPS_BGTZ},
+ {MIPS_ADDI, MIPS_ADDIU, MIPS_SLTI, MIPS_SLTIU, MIPS_ANDI, MIPS_ORI, MIPS_XORI, MIPS_LUI},
+ {MIPS_COP0, MIPS_COP1, MIPS_COP2, MIPS_COP1X, 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_LDC1, MIPS_LDC2, MIPS_LD},
+ {MIPS_INVALID, MIPS_SWC1, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_SDC1, MIPS_SDC2, MIPS_SD}
}
};
//Fields are: [Version][function_high][function_low]
-static Operation mips_special_table[6][8][8] = {
+static Operation mips_special_table[7][8][8] = {
{ //MIPS version 1
{MIPS_SLL, MIPS_INVALID, MIPS_SRL, MIPS_SRA, MIPS_SLLV, MIPS_INVALID, MIPS_SRLV, MIPS_SRAV},
{MIPS_JR, MIPS_JALR, MIPS_INVALID, MIPS_INVALID, MIPS_SYSCALL, MIPS_BREAK, MIPS_INVALID, MIPS_INVALID},
@@ -181,10 +195,19 @@ static Operation mips_special_table[6][8][8] = {
{MIPS_INVALID, MIPS_INVALID, MIPS_SLT, MIPS_SLTU, MIPS_DADD, MIPS_DADDU, MIPS_DSUB, MIPS_DSUBU},
{MIPS_TGE, MIPS_TGEU, MIPS_TLT, MIPS_TLTU, MIPS_TEQ, MIPS_INVALID, MIPS_TNE, MIPS_INVALID},
{MIPS_DSLL, MIPS_INVALID, MIPS_DSRL, MIPS_DSRA, MIPS_DSLL32, MIPS_INVALID, MIPS_DSRL32, MIPS_DSRA32}
+ },{ //MIPS r5900
+ {MIPS_SLL, MIPS_MOVCI, MIPS_SRL, MIPS_SRA, MIPS_SLLV, MIPS_INVALID, MIPS_SRLV, MIPS_SRAV},
+ {MIPS_JR, MIPS_JALR, MIPS_MOVZ, MIPS_MOVN, MIPS_SYSCALL, MIPS_BREAK, MIPS_INVALID, MIPS_SYNC},
+ {MIPS_MFHI, MIPS_MTHI, MIPS_MFLO, MIPS_MTLO, MIPS_DSLLV, MIPS_INVALID, MIPS_DSRLV, MIPS_DSRAV},
+ {MIPS_MULT, MIPS_MULTU, MIPS_DIV, MIPS_DIVU, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID},
+ {MIPS_ADD, MIPS_ADDU, MIPS_SUB, MIPS_SUBU, MIPS_AND, MIPS_OR, MIPS_XOR, MIPS_NOR},
+ {MIPS_INVALID, MIPS_INVALID, MIPS_SLT, MIPS_SLTU, MIPS_DADD, MIPS_DADDU, MIPS_DSUB, MIPS_DSUBU},
+ {MIPS_TGE, MIPS_TGEU, MIPS_TLT, MIPS_TLTU, MIPS_TEQ, MIPS_INVALID, MIPS_TNE, MIPS_INVALID},
+ {MIPS_DSLL, MIPS_INVALID, MIPS_DSRL, MIPS_DSRA, MIPS_DSLL32, MIPS_INVALID, MIPS_DSRL32, MIPS_DSRA32}
}
};
-static Operation mips_regimm_table[6][4][8] = {
+static Operation mips_regimm_table[7][4][8] = {
{ //MIPS version 1
{MIPS_BLTZ, MIPS_BGEZ, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID},
{MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID},
@@ -215,6 +238,11 @@ static Operation mips_regimm_table[6][4][8] = {
{MIPS_TGEI, MIPS_TGEIU, MIPS_TLTI, MIPS_TLTIU, MIPS_TEQI, MIPS_INVALID, MIPS_TNEI, MIPS_INVALID},
{MIPS_BLTZAL, MIPS_BGEZAL, MIPS_BLTZALL, MIPS_BGEZALL, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID},
{MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_SYNCI}
+ },{ //MIPS r5900
+ {MIPS_BLTZ, MIPS_BGEZ, MIPS_BLTZL, MIPS_BGEZL, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID},
+ {MIPS_TGEI, MIPS_TGEIU, MIPS_TLTI, MIPS_TLTIU, MIPS_TEQI, MIPS_INVALID, MIPS_TNEI, MIPS_INVALID},
+ {MIPS_BLTZAL, MIPS_BGEZAL, MIPS_BLTZALL, MIPS_BGEZALL, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID},
+ {MIPS_MTSAB, MIPS_MTSAH, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}
}
};
@@ -325,487 +353,829 @@ static Operation mips_v5_cop1x_table[8][8] = {
{MIPS_NMSUB_S, MIPS_NMSUB_D, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_NMSUB_PS, MIPS_INVALID},
};
+static Operation mips_mmi_r5900_table[8][8] = { // 0x1c
+ {MIPS_MADD, MIPS_MADDU, MIPS_INVALID, MIPS_INVALID, MIPS_PLZCW},
+ {MIPS_MMI0 /* MMI0 */, MIPS_MMI2 /* MMI2 */, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID},
+ {MIPS_MFHI1, MIPS_MTHI1, MIPS_MFLO1, MIPS_MTLO1, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID},
+ {MIPS_MULT1, MIPS_MULTU1, MIPS_DIV1, MIPS_DIVU1, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID},
+ {MIPS_MADD1, MIPS_MADDU1, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID},
+ {MIPS_MMI1 /* MMI1 */, MIPS_MMI3 /* MMI3 */, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID},
+ {MIPS_PMFHL, MIPS_PMTHL, MIPS_INVALID, MIPS_INVALID, MIPS_PSLLH, MIPS_INVALID, MIPS_PSRLH, MIPS_PSRAH},
+ {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_PSLLW, MIPS_INVALID, MIPS_PSRLW, MIPS_PSRAW}
+};
+
+static Operation mips_r5900_mmi0_table[8][4] = {
+ {MIPS_PADDW, MIPS_PSUBW, MIPS_PCGTW, MIPS_PMAXW},
+ {MIPS_PADDH, MIPS_PSUBH, MIPS_PCGTH, MIPS_PMAXH},
+ {MIPS_PADDB, MIPS_PSUBB, MIPS_PCGTB, MIPS_INVALID},
+ {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID},
+ {MIPS_PADDSW, MIPS_PSUBSW, MIPS_PEXTLW, MIPS_PPACW},
+ {MIPS_PADDSH, MIPS_PSUBSH, MIPS_PEXTLH, MIPS_PPACH},
+ {MIPS_PADDSB, MIPS_PSUBSB, MIPS_PEXTLB, MIPS_PPACB},
+ {MIPS_INVALID, MIPS_INVALID, MIPS_PEXT5, MIPS_PPAC5},
+};
+
+static Operation mips_r5900_mmi1_table[8][4] = {
+ {MIPS_INVALID, MIPS_PABSW, MIPS_PCEQW, MIPS_PMINW},
+ {MIPS_PADSBH, MIPS_PABSH, MIPS_PCEQH, MIPS_PMINH},
+ {MIPS_INVALID, MIPS_INVALID, MIPS_PCEQB, MIPS_INVALID},
+ {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID},
+ {MIPS_PADDUW, MIPS_PSUBUW, MIPS_PEXTUW, MIPS_INVALID},
+ {MIPS_PADDUH, MIPS_PSUBUH, MIPS_PEXTUH, MIPS_INVALID},
+ {MIPS_PADDUB, MIPS_PSUBUB, MIPS_PEXTUB, MIPS_QFSRV},
+ {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID},
+};
+
+static Operation mips_r5900_mmi2_table[8][4] = {
+ {MIPS_PMADDW, MIPS_INVALID, MIPS_PSLLVW, MIPS_PSRLVW}, // 000
+ {MIPS_PMSUBW, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, // 001
+ {MIPS_PMFHI, MIPS_PMFLO, MIPS_PINTH, MIPS_INVALID}, // 010
+ {MIPS_PMULTW, MIPS_PDIVW, MIPS_PCPYLD, MIPS_INVALID}, // 011
+ {MIPS_PMADDH, MIPS_PHMADH, MIPS_PAND, MIPS_PXOR}, // 100
+ {MIPS_PMSUBH, MIPS_PHMSBH, MIPS_INVALID, MIPS_INVALID}, // 101
+ {MIPS_INVALID, MIPS_INVALID, MIPS_PEXEH, MIPS_PREVH}, // 110
+ {MIPS_PMULTH, MIPS_PDIVBW, MIPS_PEXEW, MIPS_PROT3W}, // 111
+};
+static Operation mips_r5900_mmi3_table[8][4] = {
+ {MIPS_PMADDUW, MIPS_INVALID, MIPS_INVALID, MIPS_PSRAVW}, // 000
+ {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, // 001
+ {MIPS_PMTHI, MIPS_PMTLO, MIPS_PINTEH, MIPS_INVALID}, // 010
+ {MIPS_PMULTUW, MIPS_PDIVUW, MIPS_PCPYUD, MIPS_INVALID}, // 011
+ {MIPS_INVALID, MIPS_INVALID, MIPS_POR, MIPS_PNOR}, // 100
+ {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID}, // 101
+ {MIPS_INVALID, MIPS_INVALID, MIPS_PEXCH, MIPS_PCPYH}, // 110
+ {MIPS_INVALID, MIPS_INVALID, MIPS_PEXCW, MIPS_INVALID}, // 111
+};
+
+static Operation mips_r5900_cop2_special1_table[8][8] = {
+ {MIPS_VADDx, MIPS_VADDy, MIPS_VADDz, MIPS_VADDw, MIPS_VSUBx, MIPS_VSUBy, MIPS_VSUBz, MIPS_VSUBw},
+ {MIPS_VMADDx, MIPS_VMADDy, MIPS_VMADDz, MIPS_VMADDw, MIPS_VMSUBx, MIPS_VMSUBy, MIPS_VMSUBz, MIPS_VMSUBw},
+ {MIPS_VMAXx, MIPS_VMAXy, MIPS_VMAXz, MIPS_VMAXw, MIPS_VMINIx, MIPS_VMINIy, MIPS_VMINIz, MIPS_VMINIw},
+ {MIPS_VMULx, MIPS_VMULy, MIPS_VMULz, MIPS_VMULw, MIPS_VMULq, MIPS_VMAXi, MIPS_VMULi, MIPS_VMINIi},
+ {MIPS_VADDq, MIPS_VMADDq, MIPS_VADDi, MIPS_VMADDi, MIPS_VSUBq, MIPS_VMSUBq, MIPS_VSUBi, MIPS_VMSUBi},
+ {MIPS_VADD, MIPS_VMADD, MIPS_VMUL, MIPS_VMAX, MIPS_VSUB, MIPS_VMSUB, MIPS_VOPMSUB, MIPS_VMINI},
+ {MIPS_VIADD, MIPS_VISUB, MIPS_VIADDI, MIPS_INVALID, MIPS_VIAND, MIPS_VIOR, MIPS_INVALID, MIPS_INVALID},
+ {MIPS_VCALLMS, MIPS_VCALLMSR, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID},
+};
+
+static Operation mips_r5900_cop2_special2_table[16][8] = {
+ {MIPS_VADDAx, MIPS_VADDAy, MIPS_VADDAz, MIPS_VADDAw, MIPS_VSUBAx, MIPS_VSUBAy, MIPS_VSUBAz, MIPS_VSUBAw},
+ {MIPS_VMADDAx, MIPS_VMADDAy, MIPS_VMADDAz, MIPS_VMADDAw, MIPS_VMSUBAx, MIPS_VMSUBAy, MIPS_VMSUBAz, MIPS_VMSUBAw},
+ {MIPS_VITOF0, MIPS_VITOF4, MIPS_VITOF12, MIPS_VITOF15, MIPS_VFTOI0, MIPS_VFTOI4, MIPS_VFTOI12, MIPS_VFTOI15},
+ {MIPS_VMULAx, MIPS_VMULAy, MIPS_VMULAz, MIPS_VMULAw, MIPS_VMULAq, MIPS_VABS, MIPS_VMULAi, MIPS_VCLIPw},
+ {MIPS_VADDAq, MIPS_VMADDAq, MIPS_VADDAi, MIPS_VMADDAi, MIPS_VSUBAq, MIPS_VMSUBAq, MIPS_VSUBAi, MIPS_VMSUBAi},
+ {MIPS_VADDA, MIPS_VMADDA, MIPS_VMULA, MIPS_INVALID, MIPS_VSUBA, MIPS_VMSUBA, MIPS_VOPMULA, MIPS_VNOP},
+ {MIPS_VMOVE, MIPS_VMR32, MIPS_INVALID, MIPS_INVALID, MIPS_VLQI, MIPS_VSQI, MIPS_VLQD, MIPS_VSQD},
+ {MIPS_VDIV, MIPS_VSQRT, MIPS_VRSQRT, MIPS_VWAITQ, MIPS_VMTIR, MIPS_VMFIR, MIPS_VILWR, MIPS_VISWR},
+ {MIPS_VRNEXT, MIPS_VRGET, MIPS_VRINIT, MIPS_VRXOR, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID},
+ {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID},
+ {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID},
+ {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID},
+ {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID},
+ {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID},
+ {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID},
+ {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID},
+};
+
+static Operation mips_r5900_cop1_S_table[8][8] = {
+ {MIPS_ADD_S, MIPS_SUB_S, MIPS_MUL_S, MIPS_DIV_S, MIPS_SQRT_S, MIPS_ABS_S, MIPS_MOV_S, MIPS_NEG_S},
+ {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID},
+ {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_RSQRT_S, MIPS_INVALID},
+ {MIPS_ADDA_S, MIPS_SUBA_S, MIPS_MULA_S, MIPS_INVALID, MIPS_MADD_S, MIPS_MSUB_S, MIPS_MADDA_S, MIPS_MSUBA_S},
+ {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_CVT_W_S, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID},
+ {MIPS_MAX_S, MIPS_MIN_S, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID},
+ {MIPS_C_F_S, MIPS_INVALID, MIPS_C_EQ_S, MIPS_INVALID, MIPS_C_LT_S, MIPS_INVALID, MIPS_C_LE_S, MIPS_INVALID},
+ {MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID, MIPS_INVALID},
+};
static const char* const OperationStrings[] = {
- "INVALID",
- "abs.d",
- "abs.ps",
- "abs.s",
- "add.d",
- "add.ps",
- "add.s",
- "add",
- "addi",
- "addiu",
- "addr",
- "addu",
- "align",
- "alnv.ps",
- "and",
- "andi",
- "b",
- "bal",
- "bc1any2",
- "bc1any4",
- "bc1eqz",
- "bc1f",
- "bc1fl",
- "bc1nez",
- "bc1t",
- "bc1tl",
- "bc2eqz",
- "bc2f",
- "bc2fl",
- "bc2nez",
- "bc2t",
- "bc2tl",
- "bcnez",
- "beq",
- "beql",
- "beqz",
- "bgez",
- "bgezal",
- "bgezall",
- "bgezl",
- "bgtz",
- "bgtzl",
- "bitswap",
- "blez",
- "blezl",
- "bltz",
- "bltzal",
- "bltzall",
- "bltzl",
- "bne",
- "bnel",
- "bnez",
- "bnz.b",
- "bnz.d",
- "bnz.h",
- "bnz.w",
- "break",
- "bshfl",
- "bz.b",
- "bz.d",
- "bz.h",
- "bz.w",
- "c.df.d",
- "c.eq.d",
- "c.eq.ps",
- "c.eq.s",
- "c.eq",
- "c.f.d",
- "c.f.ps",
- "c.f.s",
- "c.f",
- "c.le.d",
- "c.le.ps",
- "c.le.s",
- "c.le",
- "c.lt.d",
- "c.lt.ps",
- "c.lt.s",
- "c.lt",
- "c.nge.d",
- "c.nge.ps",
- "c.nge.s",
- "c.nge",
- "c.ngl.d",
- "c.ngl.ps",
- "c.ngl.s",
- "c.ngl",
- "c.ngle.d",
- "c.ngle.ps",
- "c.ngle.s",
- "c.ngle",
- "c.ngt.d",
- "c.ngt.ps",
- "c.ngt.s",
- "c.ngt",
- "c.ole.d",
- "c.ole.ps",
- "c.ole.s",
- "c.ole",
- "c.olt.d",
- "c.olt.ps",
- "c.olt.s",
- "c.olt",
- "c.seq.d",
- "c.seq.ps",
- "c.seq.s",
- "c.seq",
- "c.sf.d",
- "c.sf.ps",
- "c.sf.s",
- "c.sf",
- "c.ueq.d",
- "c.ueq.ps",
- "c.ueq.s",
- "c.ueq",
- "c.ule.d",
- "c.ule.ps",
- "c.ule.s",
- "c.ule",
- "c.ult.d",
- "c.ult.ps",
- "c.ult.s",
- "c.ult",
- "c.un.d",
- "c.un.ps",
- "c.un.s",
- "c.un",
- "c1",
- "c2",
- "cache",
- "ceil.l.d",
- "ceil.l.s",
- "ceil.l",
- "ceil.w.d",
- "ceil.w.s",
- "ceil.w",
- "cfc0",
- "cfc1",
- "cfc2",
- "class.d",
- "class.s",
- "clo",
- "clz",
- "cop0",
- "cop1",
- "cop1x",
- "cop2",
- "cop3",
- "ctc0",
- "ctc1",
- "ctc2",
- "cvt.d.s",
- "cvt.d.w",
- "cvt.l.d",
- "cvt.l.s",
- "cvt.l",
- "cvt.ps.pw",
- "cvt.ps.s",
- "cvt.ps",
- "cvt.pw.ps",
- "cvt.s.d",
- "cvt.s.l",
- "cvt.s.pl",
- "cvt.s.pu",
- "cvt.s.w",
- "cvt.w.d",
- "cvt.w.s",
- "cvt.w",
- "dadd",
- "daddi",
- "daddiu",
- "daddu",
- "dbshfl",
- "dclo",
- "dclz",
- "ddiv",
- "ddivu",
- "deret",
- "dext",
- "dextm",
- "dextu",
- "di",
- "dins",
- "dinsm",
- "dinsu",
- "div.d",
- "div.ps",
- "div.s",
- "div",
- "divu",
- "dmfc0",
- "dmfc1",
- "dmfc2",
- "dmult",
- "dmultu",
- "dmtc0",
- "dmtc1",
- "dmtc2",
- "dret",
- "drotr",
- "drotr32",
- "drotrv",
- "dsbh",
- "dshd",
- "dsll",
- "dsll32",
- "dsllv",
- "dsra",
- "dsra32",
- "dsrav",
- "dsrl",
- "dsrl32",
- "dsrlv",
- "dsub",
- "dsubu",
- "ehb",
- "ei",
- "eret",
- "ext",
- "floor.l.d",
- "floor.l.s",
- "floor.l",
- "floor.w.d",
- "floor.w.s",
- "floor.w",
- "ins",
- "j",
- "jal",
- "jalr.hb",
- "jalr",
- "jalx",
- "jr.hb",
- "jr",
- "lb",
- "lbu",
- "lbux",
- "ld",
- "ldc1",
- "ldc2",
- "ldc3",
- "ldl",
- "ldr",
- "ldxc1",
- "lh",
- "lhi",
- "lhu",
- "lhx",
- "li",
- "ll",
- "lld",
- "llo",
- "lui",
- "luxc1",
- "lw",
- "lwc1",
- "lwc2",
- "lwc3",
- "lwl",
- "lwr",
- "lwu",
- "lwx",
- "lwxc1",
- "lx",
- "madd.d",
- "madd.ps",
- "madd.s",
- "madd",
- "maddf.d",
- "maddf.s",
- "maddu",
- "mfc0",
- "mfc1",
- "mfc2",
- "mfhc1",
- "mfhc2",
- "mfhi",
- "mflo",
- "mov.d",
- "mov.ps",
- "mov.s",
- "movcf",
- "movci",
- "move",
- "movf.d",
- "movf.ps",
- "movf.s",
- "movf",
- "movn.d",
- "movn.ps",
- "movn.s",
- "movn",
- "movt.d",
- "movt.ps",
- "movt.s",
- "movt",
- "movz.d",
- "movz.ps",
- "movz.s",
- "movz",
- "msub.d",
- "msub.ps",
- "msub.s",
- "msub",
- "msubf.d",
- "msubf.s",
- "msubu",
- "mtc0",
- "mtc1",
- "mtc2",
- "mthc1",
- "mthc2",
- "mthi",
- "mtlo",
- "mul.d",
- "mul.ps",
- "mul.s",
- "mul",
- "mulr",
- "mult",
- "multu",
- "neg.d",
- "neg.ps",
- "neg.s",
- "neg",
- "negu",
- "nmadd.d",
- "nmadd.ps",
- "nmadd.s",
- "nmsub.d",
- "nmsub.ps",
- "nmsub.s",
- "nop",
- "nor",
- "not",
- "or",
- "ori",
- "pause",
- "pll.ps",
- "plu.ps",
- "pref",
- "prefx",
- "pul.ps",
- "puu.ps",
- "rdhwr",
- "rdpgpr",
- "recip.d",
- "recip.s",
- "recip",
- "recip1",
- "recip2",
- "rint.d",
- "rint.s",
- "rotr",
- "rotrv",
- "round.l.d",
- "round.l.s",
- "round.l",
- "round.w.d",
- "round.w.s",
- "round.w",
- "rsqrt.d",
- "rsqrt.s",
- "rsqrt",
- "rsqrt1",
- "rsqrt2",
- "sb",
- "sc",
- "scd",
- "sd",
- "sdbbp",
- "sdc1",
- "sdc2",
- "sdc3",
- "sdl",
- "sdr",
- "sdxc1",
- "seb",
- "seh",
- "sel.d",
- "sel.s",
- "sh",
- "sll",
- "sllv",
- "slt",
- "slti",
- "sltiu",
- "sltu",
- "sqrt.d",
- "sqrt.ps",
- "sqrt.s",
- "sra",
- "srav",
- "srl",
- "srlv",
- "ssnop",
- "sub.d",
- "sub.ps",
- "sub.s",
- "sub",
- "subu",
- "suxc1",
- "sw",
- "swc1",
- "swc2",
- "swc3",
- "swl",
- "swr",
- "swxc1",
- "sync",
- "synci",
- "syscall",
- "teq",
- "teqi",
- "tge",
- "tgei",
- "tgeiu",
- "tgeu",
- "tlbinv",
- "tlbinvf",
- "tlbp",
- "tlbr",
- "tlbwi",
- "tlbwr",
- "tlt",
- "tlti",
- "tltiu",
- "tltu",
- "tne",
- "tnei",
- "trap",
- "trunc.l.d",
- "trunc.l.s",
- "trunc.l",
- "trunc.w.d",
- "trunc.w.s",
- "trunc.w",
- "wait",
- "wrpgpr",
- "wsbh",
- "xor",
- "xori",
+ "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",
+ // cavium instructions
+ "baddu",
+ "bbit0",
+ "bbit032",
+ "bbit1",
+ "bbit132",
+ "cins",
+ "cins32",
+ "cvm",
+ "dmul",
+ "dpop",
+ "exts",
+ "exts32",
+ "mtm0",
+ "mtm1",
+ "mtm2",
+ "mtp0",
+ "mtp1",
+ "mtp2",
+ "pop",
+ "rdhwr",
+ "saa",
+ "saad",
+ "seq",
+ "seqi",
+ "sne",
+ "snei",
+ "synciobdma",
+ "syncs",
+ "syncw",
+ "syncws",
+ "v3mulu",
+ "vmm0",
+ "vmulu",
+ "zcb",
+ "zcbt",
+ // r5900 instructions
+ "lq",
+ "sq",
+ "dslrv",
+ "mfsa",
+ "mtsa",
+ "mtsab",
+ "mtsah",
+ "plzcw",
+ "mfhi1",
+ "mthi1",
+ "mflo1",
+ "mlto1",
+ "mult1",
+ "multu1",
+ "div1",
+ "divu1",
+ "madd1",
+ "maddu1",
+ "pmfhl",
+ "pmthl",
+ "psllh",
+ "psrlh",
+ "psrah",
+ "psllw",
+ "psrlw",
+ "psraw",
+ "paddw",
+ "psubw",
+ "pcgtw",
+ "pmaxw",
+ "paddh",
+ "psubh",
+ "pcgth",
+ "pmaxh",
+ "paddb",
+ "psubb",
+ "pcgtb",
+ "paddsw",
+ "psubsw",
+ "pextlw",
+ "ppacw",
+ "paddsh",
+ "psubsh",
+ "pextlh",
+ "ppach",
+ "paddsb",
+ "psubsb",
+ "pextlb",
+ "ppacb",
+ "pext5",
+ "ppac5",
+ "pabsw",
+ "pceqw",
+ "pminw",
+ "padsbh",
+ "pabsh",
+ "pceqh",
+ "pminh",
+ "pceqb",
+ "padduw",
+ "psubuw",
+ "pextuw",
+ "padduh",
+ "psubuh",
+ "pextuh",
+ "paddub",
+ "psubub",
+ "pextub",
+ "qfsrv",
+ "pmaddw",
+ "psllvw",
+ "psrlvw",
+ "pmsubw",
+ "pmfhi",
+ "pmflo",
+ "pinth",
+ "pmultw",
+ "pdivw",
+ "pcpyld",
+ "pmaddh",
+ "phmadh",
+ "pand",
+ "pxor",
+ "pmsubh",
+ "phmsbh",
+ "pexeh",
+ "prevh",
+ "pmulth",
+ "pdivbw",
+ "pexew",
+ "prot3w",
+ "pmadduw",
+ "psravw",
+ "pmthi",
+ "pmtlo",
+ "pinteh",
+ "pmultuw",
+ "pdivuw",
+ "pcpyud",
+ "por",
+ "pnor",
+ "pexch",
+ "pcpyh",
+ "pexcw",
+ "bc0f",
+ "bc0t",
+ "bc0fl",
+ "bc0tl",
+ "adda.s",
+ "suba.s",
+ "mula.s",
+ "madda.s",
+ "msuba.s",
+ "max.s",
+ "min.s",
+ "qmfc2",
+ "qmfc2.i",
+ "qmfc2.ni",
+ "qmtc2",
+ "qmtc2.i",
+ "qmtc2.ni",
+ "vaddx",
+ "vaddy",
+ "vaddz",
+ "vaddw",
+ "vsubx",
+ "vsuby",
+ "vsubz",
+ "vsubw",
+ "vmaddx",
+ "vmaddy",
+ "vmaddz",
+ "vmaddw",
+ "vmsubx",
+ "vmsuby",
+ "vmsubz",
+ "vmsubw",
+ "vmaxx",
+ "vmaxy",
+ "vmaxz",
+ "vmaxw",
+ "vminix",
+ "vminiy",
+ "vminiz",
+ "vminiw",
+ "vmulx",
+ "vmuly",
+ "vmulz",
+ "vmulw",
+ "vmulq",
+ "vmaxi",
+ "vmuli",
+ "vminii",
+ "vaddq",
+ "vmaddq",
+ "vaddi",
+ "vmaddi",
+ "vsubq",
+ "vmsubq",
+ "vsubi",
+ "vmsubi",
+ "vadd",
+ "vmadd",
+ "vmul",
+ "vmax",
+ "vsub",
+ "vmsub",
+ "vopmsub",
+ "vmini",
+ "viadd",
+ "visub",
+ "viaddi",
+ "viand",
+ "vior",
+ "vcallms",
+ "vcallmsr",
+ "vaddax",
+ "vadday",
+ "vaddaz",
+ "vaddaw",
+ "vsubax",
+ "vsubay",
+ "vsubaz",
+ "vsubaw",
+ "vmaddax",
+ "vmadday",
+ "vmaddaz",
+ "vmaddaw",
+ "vmsubax",
+ "vmsubay",
+ "vmsubaz",
+ "vmsubaw",
+ "vitof0",
+ "vitof4",
+ "vitof12",
+ "vitof15",
+ "vftoi0",
+ "vftoi4",
+ "vftoi12",
+ "vftoi15",
+ "vmulax",
+ "vmulay",
+ "vmulaz",
+ "vmulaw",
+ "vmulaq",
+ "vabs",
+ "vmulai",
+ "vclipw",
+ "vaddaq",
+ "vmaddaq",
+ "vaddai",
+ "vmaddai",
+ "vsubaq",
+ "vmsubaq",
+ "vsubai",
+ "vmsubai",
+ "vadda",
+ "vmadda",
+ "vmula",
+ "vsuba",
+ "vmsuba",
+ "vopmula",
+ "vnop",
+ "vmove",
+ "vmr32",
+ "vlqi",
+ "vsqi",
+ "vlqd",
+ "vsqd",
+ "vdiv",
+ "vsqrt",
+ "vrsqrt",
+ "vwaitq",
+ "vmtir",
+ "vmfir",
+ "vilwr",
+ "viswr",
+ "vrnext",
+ "vrget",
+ "vrinit",
+ "vrxor",
+ "mmi0",
+ "mmi1",
+ "mmi2",
+ "mmi3",
+ "lqc2",
+ "sqc2",
};
static const char * const RegisterStrings[] = {
@@ -905,6 +1275,38 @@ static const char * const RegisterStrings[] = {
"$f29",
"$f30",
"$f31",
+ "$fcr0",
+ "$fcr1",
+ "$fcr2",
+ "$fcr3",
+ "$fcr4",
+ "$fcr5",
+ "$fcr6",
+ "$fcr7",
+ "$fcr8",
+ "$fcr9",
+ "$fcr10",
+ "$fcr11",
+ "$fcr12",
+ "$fcr13",
+ "$fcr14",
+ "$fcr15",
+ "$fcr16",
+ "$fcr17",
+ "$fcr18",
+ "$fcr19",
+ "$fcr20",
+ "$fcr21",
+ "$fcr22",
+ "$fcr23",
+ "$fcr24",
+ "$fcr25",
+ "$fcr26",
+ "$fcr27",
+ "$fcr28",
+ "$fcr29",
+ "$fcr30",
+ "$fcr31",
"$lo",
"$hi",
"cop0_Index",
@@ -1154,6 +1556,91 @@ static const char * const RegisterStrings[] = {
"CVMX_HSH_STARTSHA512",
"CVMX_GFM_XORMUL1",
+
+ "$sa",
+
+ "$lo1",
+ "$hi1",
+
+ "$P",
+
+ "$vi0", "$vi1", "$vi2", "$vi3", "$vi4", "$vi5", "$vi6", "$vi7", "$vi8", "$vi9",
+ "$vi10", "$vi11", "$vi12", "$vi13", "$vi14", "$vi15",
+
+ "CCR_STATUS", "CCR_MAC", "CCR_CLIPPING", "CCR[2,19]",
+ "$R", "$I", "$Q",
+ "CCR[2,23]", "CCR[2,24]", "CCR[2,25]", "CCR_TPC", "CCR_CMSAR0",
+ "CCR_FBRST", "CCR_VPU_STAT", "CCR[2,30]", "CCR_CMSAR1",
+
+ "$acc",
+ "$vf0", "$vf1", "$vf2", "$vf3", "$vf4", "$vf5", "$vf6", "$vf7", "$vf8", "$vf9",
+ "$vf10", "$vf11", "$vf12", "$vf13", "$vf14", "$vf15", "$vf16", "$vf17", "$vf18", "$vf19",
+ "$vf20", "$vf21", "$vf22", "$vf23", "$vf24", "$vf25", "$vf26", "$vf27", "$vf28", "$vf29",
+ "$vf30", "$vf31",
+
+ "$acc.x", "$vf0.x", "$vf1.x", "$vf2.x", "$vf3.x", "$vf4.x", "$vf5.x", "$vf6.x",
+ "$vf7.x", "$vf8.x", "$vf9.x", "$vf10.x", "$vf11.x", "$vf12.x", "$vf13.x", "$vf14.x",
+ "$vf15.x", "$vf16.x", "$vf17.x", "$vf18.x", "$vf19.x", "$vf20.x", "$vf21.x", "$vf22.x",
+ "$vf23.x", "$vf24.x", "$vf25.x", "$vf26.x", "$vf27.x", "$vf28.x", "$vf29.x", "$vf30.x",
+ "$vf31.x", "$acc.y", "$vf0.y", "$vf1.y", "$vf2.y", "$vf3.y", "$vf4.y", "$vf5.y",
+ "$vf6.y", "$vf7.y", "$vf8.y", "$vf9.y", "$vf10.y", "$vf11.y", "$vf12.y", "$vf13.y",
+ "$vf14.y", "$vf15.y", "$vf16.y", "$vf17.y", "$vf18.y", "$vf19.y", "$vf20.y", "$vf21.y",
+ "$vf22.y", "$vf23.y", "$vf24.y", "$vf25.y", "$vf26.y", "$vf27.y", "$vf28.y", "$vf29.y",
+ "$vf30.y", "$vf31.y", "$acc.z", "$vf0.z", "$vf1.z", "$vf2.z", "$vf3.z", "$vf4.z",
+ "$vf5.z", "$vf6.z", "$vf7.z", "$vf8.z", "$vf9.z", "$vf10.z", "$vf11.z", "$vf12.z",
+ "$vf13.z", "$vf14.z", "$vf15.z", "$vf16.z", "$vf17.z", "$vf18.z", "$vf19.z", "$vf20.z",
+ "$vf21.z", "$vf22.z", "$vf23.z", "$vf24.z", "$vf25.z", "$vf26.z", "$vf27.z", "$vf28.z",
+ "$vf29.z", "$vf30.z", "$vf31.z", "$acc.w", "$vf0.w", "$vf1.w", "$vf2.w", "$vf3.w",
+ "$vf4.w", "$vf5.w", "$vf6.w", "$vf7.w", "$vf8.w", "$vf9.w", "$vf10.w", "$vf11.w",
+ "$vf12.w", "$vf13.w", "$vf14.w", "$vf15.w", "$vf16.w", "$vf17.w", "$vf18.w", "$vf19.w",
+ "$vf20.w", "$vf21.w", "$vf22.w", "$vf23.w", "$vf24.w", "$vf25.w", "$vf26.w", "$vf27.w",
+ "$vf28.w", "$vf29.w", "$vf30.w", "$vf31.w", "$acc.xy", "$vf0.xy", "$vf1.xy", "$vf2.xy",
+ "$vf3.xy", "$vf4.xy", "$vf5.xy", "$vf6.xy", "$vf7.xy", "$vf8.xy", "$vf9.xy", "$vf10.xy",
+ "$vf11.xy", "$vf12.xy", "$vf13.xy", "$vf14.xy", "$vf15.xy", "$vf16.xy", "$vf17.xy", "$vf18.xy",
+ "$vf19.xy", "$vf20.xy", "$vf21.xy", "$vf22.xy", "$vf23.xy", "$vf24.xy", "$vf25.xy", "$vf26.xy",
+ "$vf27.xy", "$vf28.xy", "$vf29.xy", "$vf30.xy", "$vf31.xy", "$acc.xz", "$vf0.xz", "$vf1.xz",
+ "$vf2.xz", "$vf3.xz", "$vf4.xz", "$vf5.xz", "$vf6.xz", "$vf7.xz", "$vf8.xz", "$vf9.xz",
+ "$vf10.xz", "$vf11.xz", "$vf12.xz", "$vf13.xz", "$vf14.xz", "$vf15.xz", "$vf16.xz", "$vf17.xz",
+ "$vf18.xz", "$vf19.xz", "$vf20.xz", "$vf21.xz", "$vf22.xz", "$vf23.xz", "$vf24.xz", "$vf25.xz",
+ "$vf26.xz", "$vf27.xz", "$vf28.xz", "$vf29.xz", "$vf30.xz", "$vf31.xz", "$acc.xw", "$vf0.xw",
+ "$vf1.xw", "$vf2.xw", "$vf3.xw", "$vf4.xw", "$vf5.xw", "$vf6.xw", "$vf7.xw", "$vf8.xw",
+ "$vf9.xw", "$vf10.xw", "$vf11.xw", "$vf12.xw", "$vf13.xw", "$vf14.xw", "$vf15.xw", "$vf16.xw",
+ "$vf17.xw", "$vf18.xw", "$vf19.xw", "$vf20.xw", "$vf21.xw", "$vf22.xw", "$vf23.xw", "$vf24.xw",
+ "$vf25.xw", "$vf26.xw", "$vf27.xw", "$vf28.xw", "$vf29.xw", "$vf30.xw", "$vf31.xw", "$acc.yz",
+ "$vf0.yz", "$vf1.yz", "$vf2.yz", "$vf3.yz", "$vf4.yz", "$vf5.yz", "$vf6.yz", "$vf7.yz",
+ "$vf8.yz", "$vf9.yz", "$vf10.yz", "$vf11.yz", "$vf12.yz", "$vf13.yz", "$vf14.yz", "$vf15.yz",
+ "$vf16.yz", "$vf17.yz", "$vf18.yz", "$vf19.yz", "$vf20.yz", "$vf21.yz", "$vf22.yz", "$vf23.yz",
+ "$vf24.yz", "$vf25.yz", "$vf26.yz", "$vf27.yz", "$vf28.yz", "$vf29.yz", "$vf30.yz", "$vf31.yz",
+ "$acc.yw", "$vf0.yw", "$vf1.yw", "$vf2.yw", "$vf3.yw", "$vf4.yw", "$vf5.yw", "$vf6.yw",
+ "$vf7.yw", "$vf8.yw", "$vf9.yw", "$vf10.yw", "$vf11.yw", "$vf12.yw", "$vf13.yw", "$vf14.yw",
+ "$vf15.yw", "$vf16.yw", "$vf17.yw", "$vf18.yw", "$vf19.yw", "$vf20.yw", "$vf21.yw", "$vf22.yw",
+ "$vf23.yw", "$vf24.yw", "$vf25.yw", "$vf26.yw", "$vf27.yw", "$vf28.yw", "$vf29.yw", "$vf30.yw",
+ "$vf31.yw", "$acc.zw", "$vf0.zw", "$vf1.zw", "$vf2.zw", "$vf3.zw", "$vf4.zw", "$vf5.zw",
+ "$vf6.zw", "$vf7.zw", "$vf8.zw", "$vf9.zw", "$vf10.zw", "$vf11.zw", "$vf12.zw", "$vf13.zw",
+ "$vf14.zw", "$vf15.zw", "$vf16.zw", "$vf17.zw", "$vf18.zw", "$vf19.zw", "$vf20.zw", "$vf21.zw",
+ "$vf22.zw", "$vf23.zw", "$vf24.zw", "$vf25.zw", "$vf26.zw", "$vf27.zw", "$vf28.zw", "$vf29.zw",
+ "$vf30.zw", "$vf31.zw", "$acc.xyz", "$vf0.xyz", "$vf1.xyz", "$vf2.xyz", "$vf3.xyz", "$vf4.xyz",
+ "$vf5.xyz", "$vf6.xyz", "$vf7.xyz", "$vf8.xyz", "$vf9.xyz", "$vf10.xyz", "$vf11.xyz", "$vf12.xyz",
+ "$vf13.xyz", "$vf14.xyz", "$vf15.xyz", "$vf16.xyz", "$vf17.xyz", "$vf18.xyz", "$vf19.xyz", "$vf20.xyz",
+ "$vf21.xyz", "$vf22.xyz", "$vf23.xyz", "$vf24.xyz", "$vf25.xyz", "$vf26.xyz", "$vf27.xyz", "$vf28.xyz",
+ "$vf29.xyz", "$vf30.xyz", "$vf31.xyz", "$acc.xyw", "$vf0.xyw", "$vf1.xyw", "$vf2.xyw", "$vf3.xyw",
+ "$vf4.xyw", "$vf5.xyw", "$vf6.xyw", "$vf7.xyw", "$vf8.xyw", "$vf9.xyw", "$vf10.xyw", "$vf11.xyw",
+ "$vf12.xyw", "$vf13.xyw", "$vf14.xyw", "$vf15.xyw", "$vf16.xyw", "$vf17.xyw", "$vf18.xyw", "$vf19.xyw",
+ "$vf20.xyw", "$vf21.xyw", "$vf22.xyw", "$vf23.xyw", "$vf24.xyw", "$vf25.xyw", "$vf26.xyw", "$vf27.xyw",
+ "$vf28.xyw", "$vf29.xyw", "$vf30.xyw", "$vf31.xyw", "$acc.xzw", "$vf0.xzw", "$vf1.xzw", "$vf2.xzw",
+ "$vf3.xzw", "$vf4.xzw", "$vf5.xzw", "$vf6.xzw", "$vf7.xzw", "$vf8.xzw", "$vf9.xzw", "$vf10.xzw",
+ "$vf11.xzw", "$vf12.xzw", "$vf13.xzw", "$vf14.xzw", "$vf15.xzw", "$vf16.xzw", "$vf17.xzw", "$vf18.xzw",
+ "$vf19.xzw", "$vf20.xzw", "$vf21.xzw", "$vf22.xzw", "$vf23.xzw", "$vf24.xzw", "$vf25.xzw", "$vf26.xzw",
+ "$vf27.xzw", "$vf28.xzw", "$vf29.xzw", "$vf30.xzw", "$vf31.xzw", "$acc.yzw", "$vf0.yzw", "$vf1.yzw",
+ "$vf2.yzw", "$vf3.yzw", "$vf4.yzw", "$vf5.yzw", "$vf6.yzw", "$vf7.yzw", "$vf8.yzw", "$vf9.yzw",
+ "$vf10.yzw", "$vf11.yzw", "$vf12.yzw", "$vf13.yzw", "$vf14.yzw", "$vf15.yzw", "$vf16.yzw", "$vf17.yzw",
+ "$vf18.yzw", "$vf19.yzw", "$vf20.yzw", "$vf21.yzw", "$vf22.yzw", "$vf23.yzw", "$vf24.yzw", "$vf25.yzw",
+ "$vf26.yzw", "$vf27.yzw", "$vf28.yzw", "$vf29.yzw", "$vf30.yzw", "$vf31.yzw", "$acc.xyzw", "$vf0.xyzw",
+ "$vf1.xyzw", "$vf2.xyzw", "$vf3.xyzw", "$vf4.xyzw", "$vf5.xyzw", "$vf6.xyzw", "$vf7.xyzw", "$vf8.xyzw",
+ "$vf9.xyzw", "$vf10.xyzw", "$vf11.xyzw", "$vf12.xyzw", "$vf13.xyzw", "$vf14.xyzw", "$vf15.xyzw", "$vf16.xyzw",
+ "$vf17.xyzw", "$vf18.xyzw", "$vf19.xyzw", "$vf20.xyzw", "$vf21.xyzw", "$vf22.xyzw", "$vf23.xyzw", "$vf24.xyzw",
+ "$vf25.xyzw", "$vf26.xyzw", "$vf27.xyzw", "$vf28.xyzw", "$vf29.xyzw", "$vf30.xyzw", "$vf31.xyzw"
+
};
static const char * const FlagStrings[] = {
@@ -1164,7 +1651,9 @@ static const char * const FlagStrings[] = {
"$fcc4",
"$fcc5",
"$fcc6",
- "$fcc7"
+ "$fcc7",
+ "$coc0",
+ "$coc2",
};
static const char * const HintStrings[] = {
@@ -1265,6 +1754,8 @@ uint32_t mips_decompose_instruction(
{
case 0:
instruction->operation = mips_special_table[version-1][ins.decode.func_hi][ins.decode.func_lo];
+ if (instruction->operation == MIPS_INVALID && version == MIPS_R5900)
+ instruction->operation = MIPS_ADDI;
break;
case 1:
instruction->operation = mips_regimm_table[version-1][ins.decode.rt_hi][ins.decode.rt_lo];
@@ -1293,12 +1784,16 @@ uint32_t mips_decompose_instruction(
}
}
+ else if (version == MIPS_R5900)
+ instruction->operation = mips_mmi_r5900_table[ins.decode.func_hi][ins.decode.func_lo];
break;
case 0x1f:
if (version == MIPS_32)
instruction->operation = mips32_special3_table[ins.decode.func_hi][ins.decode.func_lo];
else if (version == MIPS_64)
instruction->operation = mips64_special3_table[ins.decode.func_hi][ins.decode.func_lo];
+ else if (version == MIPS_R5900)
+ instruction->operation = mips_base_table[version-1][ins.decode.op_hi][ins.decode.op_lo];
break;
default:
if ((flags & DECOMPOSE_FLAGS_CAVIUM) == 0)
@@ -1308,7 +1803,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 +1863,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 +1896,20 @@ uint32_t mips_decompose_instruction(
instruction->operation = MIPS_DMTC0;
break;
case 6: instruction->operation = MIPS_CTC0; break;
+ case 8:
+ {
+ if (version != MIPS_R5900)
+ return 1;
+ switch (ins.decode.rt_lo)
+ {
+ case 0: instruction->operation = MIPS_BC0F; break;
+ case 1: instruction->operation = MIPS_BC0T; break;
+ case 2: instruction->operation = MIPS_BC0FL; break;
+ case 3: instruction->operation = MIPS_BC0TL; break;
+ default: return 1;
+ }
+ break;
+ }
case 10: instruction->operation = MIPS_RDPGPR; break;
case 11:
if (ins.bits.bit5 == 1)
@@ -1412,6 +1932,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 +1984,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 +2034,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 +2082,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 +2212,8 @@ uint32_t mips_decompose_instruction(
}
}
- //Now that we have the proper instructions aliased figure out what our operands are
+ int i = 1; // operand index counter for V* instructions
+ // Stage 3: Now that we have the proper instructions aliased figure out what our operands are
switch(instruction->operation)
{
//Zero operand instructions
@@ -1691,6 +2246,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(LABEL, (4 + address + (ins.i.immediate<<2)) & registerMask)
+ break;
case MIPS_COP2:
INS_1(IMM, (ins.value & 0x1ffffff))
break;
@@ -1707,11 +2268,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 +2298,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 +2348,23 @@ uint32_t mips_decompose_instruction(
INS_2(FLAG, (FPCCREG_FCC0 + ((ins.value >> 18) & 7)), LABEL, (4 + address + (ins.i.immediate<<2)) & registerMask);
}
break;
+ case MIPS_BC2F:
+ case MIPS_BC2FL:
+ case MIPS_BC2T:
+ case MIPS_BC2TL:
+ if (((ins.value >> 18) & 7) == 0)
+ {
+ INS_1(LABEL, (4 + address + (ins.i.immediate<<2)) & registerMask);
+ }
+ else
+ {
+ INS_2(FLAG, (CCREG_COC2 + ((ins.value >> 18) & 7)), LABEL, (4 + address + (ins.i.immediate<<2)) & registerMask);
+ }
+ break;
+ case MIPS_MTSAB:
+ case MIPS_MTSAH:
+ INS_2(REG, ins.i.rs, IMM, ins.i.immediate)
+ break;
case MIPS_CLO:
case MIPS_CLZ:
case MIPS_NOT:
@@ -1776,13 +2376,25 @@ 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:
+ if (version == MIPS_R5900)
+ {
+ INS_2(REG, ins.f.fd + FPREG_F0, REG, ins.f.ft + FPREG_F0);
+ if (ins.f.fs != 0)
+ return 1;
+ break;
+ }
case MIPS_SQRT_D:
- case MIPS_RSQRT_S:
case MIPS_RSQRT_D:
case MIPS_ROUND_W_S:
case MIPS_ROUND_W_D:
@@ -1790,9 +2402,9 @@ uint32_t mips_decompose_instruction(
case MIPS_ROUND_L_D:
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)
return 1;
+ INS_2(REG, ins.f.fd + FPREG_F0, REG, ins.f.fs + FPREG_F0);
break;
case MIPS_BC1EQZ:
case MIPS_BC1NEZ:
@@ -1877,13 +2489,33 @@ uint32_t mips_decompose_instruction(
case MIPS_DIVU:
case MIPS_DMULT:
case MIPS_DMULTU:
+ case MIPS_MSUB:
+ case MIPS_MSUBU:
+ if (ins.r.rd != 0 || ins.r.sa != 0)
+ return 1;
+ INS_2(REG, ins.r.rs, REG, ins.r.rt)
+ break;
+ case MIPS_MULT1:
+ case MIPS_MULTU1:
+ case MIPS_MADDU1:
+ if (version != MIPS_R5900)
+ return 1;
case MIPS_MULT:
case MIPS_MULTU:
case MIPS_MADD:
case MIPS_MADDU:
- case MIPS_MSUB:
- case MIPS_MSUBU:
- if (ins.r.rd != 0 || ins.r.sa != 0)
+ if (ins.r.sa != 0
+ || (version != MIPS_R5900 && ins.r.rd != 0))
+ return 1;
+ if (ins.r.rd != 0)
+ INS_3(REG, ins.r.rd, REG, ins.r.rs, REG, ins.r.rt)
+ else
+ INS_2(REG, ins.r.rs, REG, ins.r.rt)
+ break;
+ case MIPS_PDIVBW:
+ case MIPS_PDIVUW:
+ case MIPS_PDIVW:
+ if (ins.r.rd != 0)
return 1;
INS_2(REG, ins.r.rs, REG, ins.r.rt)
break;
@@ -1911,13 +2543,35 @@ uint32_t mips_decompose_instruction(
case MIPS_BITSWAP:
case MIPS_DSBH:
case MIPS_DSHD:
+ case MIPS_PABSH:
+ case MIPS_PABSW:
+ INS_2(REG, ins.r.rd, REG, ins.r.rt)
+ break;
+ case MIPS_PCPYH:
+ case MIPS_PEXCH:
+ case MIPS_PEXCW:
+ case MIPS_PEXEH:
+ case MIPS_PEXEW:
+ case MIPS_PEXT5:
+ case MIPS_PPAC5:
+ case MIPS_PREVH:
+ case MIPS_PROT3W:
+ if (ins.r.rs != 0)
+ return 1;
INS_2(REG, ins.r.rd, REG, ins.r.rt)
break;
+ case MIPS_PLZCW:
+ if (ins.r.rt != 0)
+ return 1;
+ INS_2(REG, ins.r.rd, REG, ins.r.rs)
+ break;
case MIPS_CFC0:
case MIPS_CTC0:
+ INS_2(REG, ins.r.rt, REG, ins.f.fs + CPREG_0)
+ break;
case MIPS_CFC1:
case MIPS_CTC1:
- INS_2(REG, ins.r.rt, REG, ins.f.fs + CPREG_0)
+ INS_2(REG, ins.r.rt, REG, ins.f.fs + FPREG_FCR0)
break;
case MIPS_DMFC1:
case MIPS_MFC1:
@@ -1929,13 +2583,18 @@ uint32_t mips_decompose_instruction(
if (ins.r.function + ins.r.sa != 0)
return 1;
break;
+ case MIPS_CTC2:
+ case MIPS_CFC2:
+ if (version == MIPS_R5900)
+ {
+ INS_2(REG, ins.r.rt, V_REG, ins.v.fs + REG_VI0);
+ break;
+ }
case MIPS_DMFC2:
case MIPS_MFC2:
case MIPS_DMTC2:
case MIPS_MTC2:
- case MIPS_CFC2:
case MIPS_MFHC2:
- case MIPS_CTC2:
case MIPS_MTHC2:
INS_2(REG, ins.i.rt, IMM, ins.i.immediate);
break;
@@ -2015,7 +2674,16 @@ uint32_t mips_decompose_instruction(
return 1;
INS_2(REG, ins.f.fd + FPREG_F0, REG, ins.f.fs + FPREG_F0)
break;
-
+ case MIPS_MADDA_S:
+ case MIPS_MSUBA_S:
+ case MIPS_ADDA_S:
+ case MIPS_SUBA_S:
+ case MIPS_MULA_S:
+ INS_2(REG, FPREG_F0 + ins.f.fs, REG, FPREG_F0 + ins.f.ft)
+ break;
+ case MIPS_SQRT_PS:
+ INS_2(REG, FPREG_F0 + ins.f.fd, REG, FPREG_F0 + ins.f.ft)
+ break;
case MIPS_LBUX:
case MIPS_LHX:
case MIPS_LWX:
@@ -2030,7 +2698,6 @@ uint32_t mips_decompose_instruction(
case MIPS_LB:
case MIPS_LBU:
case MIPS_LD:
- case MIPS_LDXC1:
case MIPS_LDL:
case MIPS_LDR:
case MIPS_LH:
@@ -2051,11 +2718,16 @@ uint32_t mips_decompose_instruction(
case MIPS_SW:
case MIPS_SWL:
case MIPS_SWR:
+ case MIPS_LQ:
+ case MIPS_SQ:
instruction->operands[0].operandClass = REG;
instruction->operands[1].operandClass = MEM_IMM;
instruction->operands[0].reg = ins.i.rt;
instruction->operands[1].reg = ins.i.rs;
instruction->operands[1].immediate = ins.i.immediate;
+ // These next two lines are suspect, so commenting them out
+ // if (instruction->operation == MIPS_SQ)
+ // instruction->operands[1].immediate = MIPS_SQ;
break;
case MIPS_PREF:
case MIPS_PREFX:
@@ -2069,6 +2741,8 @@ uint32_t mips_decompose_instruction(
case MIPS_SUXC1:
case MIPS_SWXC1:
case MIPS_SDXC1:
+ if (ins.f.fd != 0)
+ return 1;
instruction->operands[0].operandClass = REG;
instruction->operands[1].operandClass = MEM_REG;
instruction->operands[0].reg = ins.f.fs + FPREG_F0;
@@ -2077,7 +2751,8 @@ uint32_t mips_decompose_instruction(
break;
case MIPS_LUXC1:
case MIPS_LWXC1:
- if (ins.f.ft != 0)
+ case MIPS_LDXC1:
+ if (ins.f.fs != 0)
return 1;
instruction->operands[0].operandClass = REG;
instruction->operands[1].operandClass = MEM_REG;
@@ -2085,25 +2760,140 @@ 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[1].operandClass = MEM_IMM;
- instruction->operands[0].reg = ins.i.rt;
instruction->operands[1].reg = ins.i.rs;
instruction->operands[1].immediate = ins.i.immediate;
break;
+ case MIPS_DIV1:
+ case MIPS_DIVU1:
+ if (version == MIPS_R5900) {
+ if (ins.r.sa != 0)
+ return 1;
+ INS_2(REG, ins.r.rs, REG, ins.r.rt)
+ break;
+ }
//3 operand instructions
+ case MIPS_PADDB:
+ case MIPS_PADDH:
+ case MIPS_PADDW:
+ case MIPS_PADDSB:
+ case MIPS_PADDSH:
+ case MIPS_PADDSW:
+ case MIPS_PADDUB:
+ case MIPS_PADDUH:
+ case MIPS_PADDUW:
+ case MIPS_PADSBH:
+ case MIPS_PAND:
+ case MIPS_PCEQB:
+ case MIPS_PCEQH:
+ case MIPS_PCEQW:
+ case MIPS_PCGTB:
+ case MIPS_PCGTH:
+ case MIPS_PCGTW:
+ case MIPS_PCPYLD:
+ case MIPS_PCPYUD:
+ case MIPS_PEXTLB:
+ case MIPS_PEXTLH:
+ case MIPS_PEXTLW:
+ case MIPS_PEXTUB:
+ case MIPS_PEXTUH:
+ case MIPS_PEXTUW:
+ case MIPS_PHMADH:
+ case MIPS_PHMSBH:
+ case MIPS_PINTEH:
+ case MIPS_PINTH:
+ case MIPS_PMADDH:
+ case MIPS_PMADDUW:
+ case MIPS_PMADDW:
+ case MIPS_PMAXH:
+ case MIPS_PMAXW:
+ case MIPS_PMINH:
+ case MIPS_PMINW:
+ case MIPS_PMSUBH:
+ case MIPS_PMSUBW:
+ case MIPS_PMULTH:
+ case MIPS_PMULTUW:
+ case MIPS_PMULTW:
+ case MIPS_PNOR:
+ case MIPS_POR:
+ case MIPS_PPACB:
+ case MIPS_PPACH:
+ case MIPS_PPACW:
+ case MIPS_PSUBB:
+ case MIPS_PSUBH:
+ case MIPS_PSUBSB:
+ case MIPS_PSUBSH:
+ case MIPS_PSUBSW:
+ case MIPS_PSUBUB:
+ case MIPS_PSUBUH:
+ case MIPS_PSUBUW:
+ case MIPS_PSUBW:
+ case MIPS_PXOR:
+ case MIPS_QFSRV:
+ INS_3(REG, ins.r.rd, REG, ins.r.rs, REG, ins.r.rt)
+ break;
+ case MIPS_PSLLVW:
+ case MIPS_PSRAVW:
+ case MIPS_PSRLVW:
+ INS_3(REG, ins.r.rd, REG, ins.r.rt, REG, ins.r.rs)
+ break;
case MIPS_DIV_S:
case MIPS_DIV_D:
case MIPS_MUL_S:
@@ -2128,11 +2918,12 @@ uint32_t mips_decompose_instruction(
case MIPS_MADDF_S:
case MIPS_MSUBF_D:
case MIPS_MSUBF_S:
+ case MIPS_RSQRT:
INS_3(REG, ins.f.fd + FPREG_F0, REG, ins.f.fs + FPREG_F0, REG, ins.f.ft + FPREG_F0)
break;
case MIPS_MOVF:
case MIPS_MOVT:
- INS_3(REG, ins.r.rd, REG, ins.r.rs, FLAG, (ins.r.rt>>2) + FPCCREG_FCC0)
+ INS_3(REG, ins.r.rd, REG, ins.r.rs, FLAG, ((ins.r.rt>>2) & 7) + FPCCREG_FCC0)
if (ins.r.sa != 0 || ins.bits.bit17 != 0)
return 1;
break;
@@ -2142,7 +2933,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;
@@ -2201,6 +2992,16 @@ uint32_t mips_decompose_instruction(
if (ins.r.rs != 1)
return 1;
break;
+ 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 != 0)
+ return 1;
+ break;
case MIPS_DSLL:
case MIPS_DSRA:
case MIPS_DSRL:
@@ -2236,14 +3037,27 @@ uint32_t mips_decompose_instruction(
break;
case MIPS_DMFC0:
case MIPS_DMTC0:
+ INS_3(REG, ins.r.rt, IMM, ins.r.rd, IMM, (ins.r.function & 7))
+ break;
case MIPS_MFC0:
case MIPS_MTC0:
- INS_3(REG, ins.r.rt, IMM, ins.r.rd, IMM, (ins.r.function & 7))
+ if (version == MIPS_R5900)
+ INS_2(REG, ins.r.rt, REG, CPREG_0 + ins.r.rd)
+ else
+ INS_3(REG, ins.r.rt, IMM, ins.r.rd, IMM, (ins.r.function & 7))
break;
case MIPS_MADD_S:
+ case MIPS_MSUB_S:
+ if (version == MIPS_R5900)
+ {
+ INS_3(REG, ins.f.fd + FPREG_F0,
+ REG, ins.f.fs + FPREG_F0,
+ REG, ins.f.ft + FPREG_F0);
+ break;
+ }
+
case MIPS_MADD_D:
case MIPS_MADD_PS:
- case MIPS_MSUB_S:
case MIPS_MSUB_D:
case MIPS_MSUB_PS:
case MIPS_NMADD_S:
@@ -2353,6 +3167,399 @@ 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;
+
+ // R5900 VU operations
+ case MIPS_VILWR:
+ case MIPS_VISWR:
+ instruction->operands[i].reg = ins.v.ft + REG_VI0;
+ instruction->operands[i++].operandClass = V_REG;
+ instruction->operands[i].reg = ins.v.fs + REG_VI0;
+ instruction->operands[i++].operandClass = V_REG;
+
+ instruction->operands[0].reg = ins.v.dest;
+ instruction->operands[0].operandClass = V_DEST;
+ instruction->operands[0].immediate = 1;
+ break;
+
+ case MIPS_VCALLMS:
+ instruction->operands[0].immediate = ins.vi.imm15; // << 3;
+ instruction->operands[0].operandClass = IMM;
+ break;
+
+ case MIPS_VCALLMSR:
+ instruction->operands[0].reg = REG_VCCR_CMSAR0;
+ instruction->operands[0].operandClass = REG;
+ break;
+
+ // <OP>
+ case MIPS_VNOP:
+ case MIPS_VWAITQ:
+ break;
+
+ // <OP>.dest ft.dest, (is++).dest
+ case MIPS_VLQI:
+ instruction->operands[i].reg = ins.v.ft;
+ instruction->operands[i++].operandClass = V_REG;
+ instruction->operands[i].reg = ins.v.fs + REG_VI0;
+ instruction->operands[i++].operandClass = V_REG;
+
+ instruction->operands[0].reg = ins.v.dest;
+ instruction->operands[0].operandClass = V_DEST;
+ instruction->operands[0].immediate = 1;
+ break;
+ // <OP>.dest fs.dest, (it++).dest
+ case MIPS_VSQI:
+ instruction->operands[i].reg = ins.v.fs;
+ instruction->operands[i++].operandClass = V_REG;
+ instruction->operands[i].reg = ins.v.ft + REG_VI0;
+ instruction->operands[i++].operandClass = V_REG;
+
+ instruction->operands[0].reg = ins.v.dest;
+ instruction->operands[0].operandClass = V_DEST;
+ instruction->operands[0].immediate = 1;
+ break;
+ // <OP>.dest ft.dest, (--is).dest
+ case MIPS_VLQD:
+ instruction->operands[i].reg = ins.v.ft;
+ instruction->operands[i++].operandClass = V_REG;
+ instruction->operands[i].reg = ins.v.fs + REG_VI0;
+ instruction->operands[i++].operandClass = V_REG;
+
+ instruction->operands[0].reg = ins.v.dest;
+ instruction->operands[0].operandClass = V_DEST;
+ instruction->operands[0].immediate = -1;
+ break;
+ // <OP>.dest fs.dest, (--it).dest
+ case MIPS_VSQD:
+ instruction->operands[i].reg = ins.v.fs;
+ instruction->operands[i++].operandClass = V_REG;
+ instruction->operands[i].reg = ins.v.ft + REG_VI0;
+ instruction->operands[i++].operandClass = V_REG;
+
+ instruction->operands[0].reg = ins.v.dest;
+ instruction->operands[0].operandClass = V_DEST;
+ instruction->operands[0].immediate = -1;
+ break;
+
+ // <OP> 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;
+
+ // <OP> 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;
+
+ // <OP>.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;
+ // <OP>.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;
+
+ // <OP>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;
+
+ // <OP>bc.dest fd.dest, fs.dest, ft.bc
+ case MIPS_VMINIx:
+ case MIPS_VMINIy:
+ case MIPS_VMINIz:
+ case MIPS_VMINIw:
+
+ case MIPS_VADDx:
+ case MIPS_VADDy:
+ case MIPS_VADDz:
+ case MIPS_VADDw:
+
+ case MIPS_VSUBx:
+ case MIPS_VSUBy:
+ case MIPS_VSUBz:
+ case MIPS_VSUBw:
+
+ case MIPS_VMULx:
+ case MIPS_VMULy:
+ case MIPS_VMULz:
+ case MIPS_VMULw:
+
+ case MIPS_VMAXx:
+ case MIPS_VMAXy:
+ case MIPS_VMAXz:
+ case MIPS_VMAXw:
+
+ case MIPS_VMADDx:
+ case MIPS_VMADDy:
+ case MIPS_VMADDz:
+ case MIPS_VMADDw:
+
+ case MIPS_VMSUBx:
+ case MIPS_VMSUBy:
+ case MIPS_VMSUBz:
+ case MIPS_VMSUBw:
+ // The broadcast field if present will override the dest field
+ instruction->operands[3].immediate = ins.v.bc + 1;
+ // Fall through
+
+ // VOPMSUB.xyz ACC.xyz, fs.xyz, ft.xyz
+ case MIPS_VOPMSUB:
+ // Fall through
+
+ // <OP>.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;
+
+ // <OP>i.dest fd.dest, fs.dest, I
+ case MIPS_VMAXi:
+ case MIPS_VMULi:
+ case MIPS_VMINIi:
+ case MIPS_VADDi:
+ case MIPS_VMADDi:
+ case MIPS_VSUBi:
+ case MIPS_VMSUBi:
+ instruction->operands[i].reg = ins.v.fd;
+ instruction->operands[i++].operandClass = V_REG;
+ instruction->operands[i].reg = ins.v.fs;
+ instruction->operands[i++].operandClass = V_REG;
+ instruction->operands[i].reg = REG_VI;
+ instruction->operands[i++].operandClass = V_REG;
+
+ instruction->operands[0].reg = ins.v.dest;
+ instruction->operands[0].operandClass = V_DEST;
+ break;
+
+ // <OP>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;
+
+ // <OP>Abc.dest ACC.dest, fs.dest, ft.bc
+ case MIPS_VADDAx:
+ case MIPS_VADDAy:
+ case MIPS_VADDAz:
+ case MIPS_VADDAw:
+
+ case MIPS_VMULAx:
+ case MIPS_VMULAy:
+ case MIPS_VMULAz:
+ case MIPS_VMULAw:
+
+ case MIPS_VMADDAx:
+ case MIPS_VMADDAy:
+ case MIPS_VMADDAz:
+ case MIPS_VMADDAw:
+
+ case MIPS_VMSUBAx:
+ case MIPS_VMSUBAy:
+ case MIPS_VMSUBAz:
+ case MIPS_VMSUBAw:
+ instruction->operands[3].immediate = ins.v.bc + 1;
+ // Fall through
+
+ // VOPMULA.xyz ACC.xyz, fs.xyz, ft.xyz
+ case MIPS_VOPMULA:
+ instruction->operands[i].reg = REG_VACC;
+ instruction->operands[i++].operandClass = V_REG;
+ instruction->operands[i].reg = ins.v.fs;
+ instruction->operands[i++].operandClass = V_REG;
+ instruction->operands[i].reg = ins.v.ft;
+ instruction->operands[i++].operandClass = V_REG;
+
+ instruction->operands[0].reg = ins.v.dest;
+ instruction->operands[0].operandClass = V_DEST;
+ break;
+
+ // <OP>.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;
+
+ // <OP>.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;
+
+ // <OP>.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;
+
+ // <OP>.dest ft.dest, fs.dest
+ case MIPS_VFTOI0:
+ case MIPS_VFTOI4:
+ case MIPS_VFTOI12:
+ case MIPS_VFTOI15:
+ case MIPS_VITOF0:
+ case MIPS_VITOF4:
+ case MIPS_VITOF12:
+ case MIPS_VITOF15:
+ case MIPS_VMOVE:
+ case MIPS_VMR32:
+ case MIPS_VABS:
+ instruction->operands[i].reg = ins.v.ft;
+ instruction->operands[i++].operandClass = V_REG;
+ instruction->operands[i].reg = ins.v.fs;
+ instruction->operands[i++].operandClass = V_REG;
+
+ instruction->operands[0].reg = ins.v.dest;
+ instruction->operands[0].operandClass = V_DEST;
+ break;
default:
return 1;
}
@@ -2364,13 +3571,36 @@ uint32_t mips_disassemble(
char* outBuffer,
uint32_t outBufferSize)
{
- char operands[MAX_OPERANDS][64] = {{0},{0},{0},{0}};
+ // +1 to allow for V_DEST
+ char operands[MAX_OPERANDS+1][64] = {{0},{0},{0},{0}, {0}};
+ char operation[64] = {0};
char* operandPtr = NULL;
- for (uint32_t i = 0;
+ char dest[5] = {0};
+ int first_operand = 0;
+ const char* reg = NULL;
+
+ strncpy(operation, OperationStrings[instruction->operation], sizeof(operation));
+ if (instruction->operands[0].operandClass == V_DEST)
+ {
+ char* p = dest;
+ if (instruction->operands[0].reg & 8)
+ *p++ = 'x';
+ if (instruction->operands[0].reg & 4)
+ *p++ = 'y';
+ if (instruction->operands[0].reg & 2)
+ *p++ = 'z';
+ if (instruction->operands[0].reg & 1)
+ *p++ = 'w';
+ *p = '\0';
+ strcat(operation, ".");
+ strcat(operation, dest);
+ first_operand++;
+ }
+ for (uint32_t i = first_operand;
i < MAX_OPERANDS && instruction->operands[i].operandClass != NONE; i++)
{
operandPtr = operands[i];
- if (i != 0)
+ if (i != first_operand)
{
*operandPtr++ = ',';
*operandPtr++ = ' ';
@@ -2418,16 +3648,91 @@ uint32_t mips_disassemble(
RegisterStrings[instruction->operands[i].immediate],
RegisterStrings[instruction->operands[i].reg]);
break;
+ case V_REG:
+ #define V_FMT "$vf%d"
+ reg = NULL;
+ if (instruction->operands[i].reg >= REG_VP)
+ reg = get_register((Reg)instruction->operands[i].reg);
+ if (reg != NULL)
+ {
+ if (instruction->operands[i].reg >= REG_VI0 && instruction->operands[i].reg <= REG_VI15)
+ {
+ switch (instruction->operation)
+ {
+ case MIPS_VISWR:
+ case MIPS_VILWR:
+ if (i == 2)
+ {
+ snprintf(operandPtr, 64, "(%s).%s", reg, dest);
+ continue;
+ }
+ break;
+ case MIPS_VLQI:
+ case MIPS_VSQI:
+ snprintf(operandPtr, 64, "(%s++)", reg);
+ continue;
+ case MIPS_VLQD:
+ case MIPS_VSQD:
+ snprintf(operandPtr, 64, "(--%s)", reg);
+ continue;
+ default:
+ break;
+ }
+ }
+ if (instruction->operands[i].reg >= REG_VF0 && instruction->operands[i].reg <= REG_VF31)
+ {
+ if (instruction->operands[i].immediate > 0 && instruction->operands[i].immediate <= 4)
+ snprintf(operandPtr, 64, "%s.%c",
+ reg,
+ "xyzw"[instruction->operands[i].immediate-1]);
+ else if (dest[0])
+ snprintf(operandPtr, 64, "%s.%s", reg, dest);
+ }
+ else
+ snprintf(operandPtr, 64, "%s", reg);
+ }
+ else if (instruction->operands[i].immediate > 0 && instruction->operands[i].immediate <= 4)
+ snprintf(operandPtr, 64, V_FMT ".%c",
+ instruction->operands[i].reg,
+ "xyzw"[instruction->operands[i].immediate-1]);
+ else if (instruction->operands[i].immediate == 'A')
+ {
+ if (dest[0])
+ snprintf(operandPtr, 64, "ACC.%s", dest);
+ else
+ snprintf(operandPtr, 64, "ACC");
+ }
+ else if (instruction->operands[i].immediate > 'A' && instruction->operands[i].immediate <= 'Z')
+ snprintf(operandPtr, 64, "%c",
+ (char) instruction->operands[i].immediate);
+ else if (dest[0])
+ snprintf(operandPtr, 64, V_FMT ".%s",
+ instruction->operands[i].reg, dest);
+ else
+ snprintf(operandPtr, 64, V_FMT, instruction->operands[i].reg);
+ break;
+ case V_REG_FIELD:
+ {
+ snprintf(operandPtr, 64, V_FMT ".%c",
+ instruction->operands[i].reg,
+ "xyzw"[instruction->operands[i].immediate]);
+ break;
+ }
+ case V_DEST:
+ {
+ // Already handled above
+ break;
+ }
}
}
if (instruction->operation != MIPS_INVALID && instruction->operation < MIPS_OPERATION_END)
{
- snprintf(outBuffer, outBufferSize, "%s\t%s%s%s%s",
- OperationStrings[instruction->operation],
- operands[0],
- operands[1],
- operands[2],
- operands[3]);
+ snprintf(outBuffer, outBufferSize, "%-13s\t%s%s%s%s",
+ operation,
+ operands[first_operand],
+ operands[first_operand+1],
+ operands[first_operand+2],
+ operands[first_operand+3]);
return 0;
}
return 1;
diff --git a/arch/mips/mips/mips.h b/arch/mips/mips/mips.h
index 8725f97d..f2679e1f 100644
--- a/arch/mips/mips/mips.h
+++ b/arch/mips/mips/mips.h
@@ -513,6 +513,260 @@ namespace mips
CNMIPS_ZCB,
CNMIPS_ZCBT,
+ // r5900 Processor Specific Opcodes
+ MIPS_LQ,
+ MIPS_SQ,
+ MIPS_DSLRV,
+ MIPS_MFSA,
+ MIPS_MTSA,
+ MIPS_MTSAB,
+ MIPS_MTSAH,
+ MIPS_PLZCW,
+ MIPS_MFHI1,
+ MIPS_MTHI1,
+ MIPS_MFLO1,
+ MIPS_MTLO1,
+ MIPS_MULT1,
+ MIPS_MULTU1,
+ MIPS_DIV1,
+ MIPS_DIVU1,
+ MIPS_MADD1,
+ MIPS_MADDU1,
+ MIPS_PMFHL,
+ MIPS_PMTHL,
+ MIPS_PSLLH,
+ MIPS_PSRLH,
+ MIPS_PSRAH,
+ MIPS_PSLLW,
+ MIPS_PSRLW,
+ MIPS_PSRAW,
+ MIPS_PADDW,
+ MIPS_PSUBW,
+ MIPS_PCGTW,
+ MIPS_PMAXW,
+ MIPS_PADDH,
+ MIPS_PSUBH,
+ MIPS_PCGTH,
+ MIPS_PMAXH,
+ MIPS_PADDB,
+ MIPS_PSUBB,
+ MIPS_PCGTB,
+ MIPS_PADDSW,
+ MIPS_PSUBSW,
+ MIPS_PEXTLW,
+ MIPS_PPACW,
+ MIPS_PADDSH,
+ MIPS_PSUBSH,
+ MIPS_PEXTLH,
+ MIPS_PPACH,
+ MIPS_PADDSB,
+ MIPS_PSUBSB,
+ MIPS_PEXTLB,
+ MIPS_PPACB,
+ MIPS_PEXT5,
+ MIPS_PPAC5,
+ MIPS_PABSW,
+ MIPS_PCEQW,
+ MIPS_PMINW,
+ MIPS_PADSBH,
+ MIPS_PABSH,
+ MIPS_PCEQH,
+ MIPS_PMINH,
+ MIPS_PCEQB,
+ MIPS_PADDUW,
+ MIPS_PSUBUW,
+ MIPS_PEXTUW,
+ MIPS_PADDUH,
+ MIPS_PSUBUH,
+ MIPS_PEXTUH,
+ MIPS_PADDUB,
+ MIPS_PSUBUB,
+ MIPS_PEXTUB,
+ MIPS_QFSRV,
+ MIPS_PMADDW,
+ MIPS_PSLLVW,
+ MIPS_PSRLVW,
+ MIPS_PMSUBW,
+ MIPS_PMFHI,
+ MIPS_PMFLO,
+ MIPS_PINTH,
+ MIPS_PMULTW,
+ MIPS_PDIVW,
+ MIPS_PCPYLD,
+ MIPS_PMADDH,
+ MIPS_PHMADH,
+ MIPS_PAND,
+ MIPS_PXOR,
+ MIPS_PMSUBH,
+ MIPS_PHMSBH,
+ MIPS_PEXEH,
+ MIPS_PREVH,
+ MIPS_PMULTH,
+ MIPS_PDIVBW,
+ MIPS_PEXEW,
+ MIPS_PROT3W,
+ MIPS_PMADDUW,
+ MIPS_PSRAVW,
+ MIPS_PMTHI,
+ MIPS_PMTLO,
+ MIPS_PINTEH,
+ MIPS_PMULTUW,
+ MIPS_PDIVUW,
+ MIPS_PCPYUD,
+ MIPS_POR,
+ MIPS_PNOR,
+ MIPS_PEXCH,
+ MIPS_PCPYH,
+ MIPS_PEXCW,
+ MIPS_BC0F,
+ MIPS_BC0T,
+ MIPS_BC0FL,
+ MIPS_BC0TL,
+ MIPS_ADDA_S,
+ MIPS_SUBA_S,
+ MIPS_MULA_S,
+ MIPS_MADDA_S,
+ MIPS_MSUBA_S,
+ MIPS_MAX_S,
+ MIPS_MIN_S,
+ MIPS_QMFC2,
+ MIPS_QMFC2_I,
+ MIPS_QMFC2_NI,
+ MIPS_QMTC2,
+ MIPS_QMTC2_I,
+ MIPS_QMTC2_NI,
+
+ // R5900 VU operations
+ MIPS_VADDx,
+ MIPS_VADDy,
+ MIPS_VADDz,
+ MIPS_VADDw,
+ MIPS_VSUBx,
+ MIPS_VSUBy,
+ MIPS_VSUBz,
+ MIPS_VSUBw,
+ MIPS_VMADDx,
+ MIPS_VMADDy,
+ MIPS_VMADDz,
+ MIPS_VMADDw,
+ MIPS_VMSUBx,
+ MIPS_VMSUBy,
+ MIPS_VMSUBz,
+ MIPS_VMSUBw,
+ MIPS_VMAXx,
+ MIPS_VMAXy,
+ MIPS_VMAXz,
+ MIPS_VMAXw,
+ MIPS_VMINIx,
+ MIPS_VMINIy,
+ MIPS_VMINIz,
+ MIPS_VMINIw,
+ MIPS_VMULx,
+ MIPS_VMULy,
+ MIPS_VMULz,
+ MIPS_VMULw,
+ MIPS_VMULq,
+ MIPS_VMAXi,
+ MIPS_VMULi,
+ MIPS_VMINIi,
+ MIPS_VADDq,
+ MIPS_VMADDq,
+ MIPS_VADDi,
+ MIPS_VMADDi,
+ MIPS_VSUBq,
+ MIPS_VMSUBq,
+ MIPS_VSUBi,
+ MIPS_VMSUBi,
+ MIPS_VADD,
+ MIPS_VMADD,
+ MIPS_VMUL,
+ MIPS_VMAX,
+ MIPS_VSUB,
+ MIPS_VMSUB,
+ MIPS_VOPMSUB,
+ MIPS_VMINI,
+ MIPS_VIADD,
+ MIPS_VISUB,
+ MIPS_VIADDI,
+ MIPS_VIAND,
+ MIPS_VIOR,
+ MIPS_VCALLMS,
+ MIPS_VCALLMSR,
+ MIPS_VADDAx,
+ MIPS_VADDAy,
+ MIPS_VADDAz,
+ MIPS_VADDAw,
+ MIPS_VSUBAx,
+ MIPS_VSUBAy,
+ MIPS_VSUBAz,
+ MIPS_VSUBAw,
+ MIPS_VMADDAx,
+ MIPS_VMADDAy,
+ MIPS_VMADDAz,
+ MIPS_VMADDAw,
+ MIPS_VMSUBAx,
+ MIPS_VMSUBAy,
+ MIPS_VMSUBAz,
+ MIPS_VMSUBAw,
+ MIPS_VITOF0,
+ MIPS_VITOF4,
+ MIPS_VITOF12,
+ MIPS_VITOF15,
+ MIPS_VFTOI0,
+ MIPS_VFTOI4,
+ MIPS_VFTOI12,
+ MIPS_VFTOI15,
+ MIPS_VMULAx,
+ MIPS_VMULAy,
+ MIPS_VMULAz,
+ MIPS_VMULAw,
+ MIPS_VMULAq,
+ MIPS_VABS,
+ MIPS_VMULAi,
+ MIPS_VCLIPw,
+ MIPS_VADDAq,
+ MIPS_VMADDAq,
+ MIPS_VADDAi,
+ MIPS_VMADDAi,
+ MIPS_VSUBAq,
+ MIPS_VMSUBAq,
+ MIPS_VSUBAi,
+ MIPS_VMSUBAi,
+ MIPS_VADDA,
+ MIPS_VMADDA,
+ MIPS_VMULA,
+ MIPS_VSUBA,
+ MIPS_VMSUBA,
+ MIPS_VOPMULA,
+ MIPS_VNOP,
+ MIPS_VMOVE,
+ MIPS_VMR32,
+ MIPS_VLQI,
+ MIPS_VSQI,
+ MIPS_VLQD,
+ MIPS_VSQD,
+ MIPS_VDIV,
+ MIPS_VSQRT,
+ MIPS_VRSQRT,
+ MIPS_VWAITQ,
+ MIPS_VMTIR,
+ MIPS_VMFIR,
+ MIPS_VILWR,
+ MIPS_VISWR,
+ MIPS_VRNEXT,
+ MIPS_VRGET,
+ MIPS_VRINIT,
+ MIPS_VRXOR,
+
+ // r5900 tables
+ MIPS_MMI0,
+ MIPS_MMI1,
+ MIPS_MMI2,
+ MIPS_MMI3,
+
+ MIPS_LQC2,
+ MIPS_SQC2,
+
MIPS_OPERATION_END
};
@@ -554,7 +808,7 @@ namespace mips
REG_GP, // Global pointer
REG_SP, // Stack Pointer
REG_FP, // Frame Pointer
- REG_RA, // Return Adress
+ REG_RA, // Return Address
CPREG_0,
CPREG_1,
CPREG_2,
@@ -619,6 +873,38 @@ namespace mips
FPREG_F29,
FPREG_F30,
FPREG_F31,
+ FPREG_FCR0,
+ FPREG_FCR1,
+ FPREG_FCR2,
+ FPREG_FCR3,
+ FPREG_FCR4,
+ FPREG_FCR5,
+ FPREG_FCR6,
+ FPREG_FCR7,
+ FPREG_FCR8,
+ FPREG_FCR9,
+ FPREG_FCR10,
+ FPREG_FCR11,
+ FPREG_FCR12,
+ FPREG_FCR13,
+ FPREG_FCR14,
+ FPREG_FCR15,
+ FPREG_FCR16,
+ FPREG_FCR17,
+ FPREG_FCR18,
+ FPREG_FCR19,
+ FPREG_FCR20,
+ FPREG_FCR21,
+ FPREG_FCR22,
+ FPREG_FCR23,
+ FPREG_FCR24,
+ FPREG_FCR25,
+ FPREG_FCR26,
+ FPREG_FCR27,
+ FPREG_FCR28,
+ FPREG_FCR29,
+ FPREG_FCR30,
+ FPREG_FCR31,
REG_LO,
REG_HI,
@@ -916,6 +1202,95 @@ namespace mips
CNREG2_424F_HSH_STARTSHA512,
CNREG2_425D_GFM_XORMUL1,
+ R5900_SA,
+
+ // R5900 Special registers (upper 64 bits of $lo and $hi)
+ REG_LO1,
+ REG_HI1,
+
+ // R5900 VPU registers
+
+ REG_VP,
+
+ REG_VI0, REG_VI1, REG_VI2, REG_VI3, REG_VI4, REG_VI5, REG_VI6, REG_VI7, REG_VI8, REG_VI9,
+ REG_VI10, REG_VI11, REG_VI12, REG_VI13, REG_VI14, REG_VI15,
+ REG_VCCR_STATUS, REG_VCCR_MAC, REG_VCCR_CLIPPING, REG_VCCR_19,
+ // REG_VCCR_R, REG_VCCR_I, REG_VCCR_Q,
+ REG_VR,
+ REG_VI,
+ REG_VQ,
+ REG_VCCR_23, REG_VCCR_24, REG_VCCR_25, REG_VCCR_TPC, REG_VCCR_CMSAR0,
+ REG_VCCR_FBRST, REG_VCCR_VPU_STAT, REG_VCCR_30, REG_VCCR_CMSAR1,
+
+ REG_VACC, // R5900 FPU ACC register
+ REG_VF0, REG_VF1, REG_VF2, REG_VF3, REG_VF4, REG_VF5, REG_VF6, REG_VF7, REG_VF8, REG_VF9,
+ REG_VF10, REG_VF11, REG_VF12, REG_VF13, REG_VF14, REG_VF15, REG_VF16, REG_VF17, REG_VF18, REG_VF19,
+ REG_VF20, REG_VF21, REG_VF22, REG_VF23, REG_VF24, REG_VF25, REG_VF26, REG_VF27, REG_VF28, REG_VF29,
+ REG_VF30, REG_VF31,
+
+ REG_VACC_X, REG_VF0_X, REG_VF1_X, REG_VF2_X, REG_VF3_X, REG_VF4_X, REG_VF5_X, REG_VF6_X,
+ REG_VF7_X, REG_VF8_X, REG_VF9_X, REG_VF10_X, REG_VF11_X, REG_VF12_X, REG_VF13_X, REG_VF14_X,
+ REG_VF15_X, REG_VF16_X, REG_VF17_X, REG_VF18_X, REG_VF19_X, REG_VF20_X, REG_VF21_X, REG_VF22_X,
+ REG_VF23_X, REG_VF24_X, REG_VF25_X, REG_VF26_X, REG_VF27_X, REG_VF28_X, REG_VF29_X, REG_VF30_X,
+ REG_VF31_X, REG_VACC_Y, REG_VF0_Y, REG_VF1_Y, REG_VF2_Y, REG_VF3_Y, REG_VF4_Y, REG_VF5_Y,
+ REG_VF6_Y, REG_VF7_Y, REG_VF8_Y, REG_VF9_Y, REG_VF10_Y, REG_VF11_Y, REG_VF12_Y, REG_VF13_Y,
+ REG_VF14_Y, REG_VF15_Y, REG_VF16_Y, REG_VF17_Y, REG_VF18_Y, REG_VF19_Y, REG_VF20_Y, REG_VF21_Y,
+ REG_VF22_Y, REG_VF23_Y, REG_VF24_Y, REG_VF25_Y, REG_VF26_Y, REG_VF27_Y, REG_VF28_Y, REG_VF29_Y,
+ REG_VF30_Y, REG_VF31_Y, REG_VACC_Z, REG_VF0_Z, REG_VF1_Z, REG_VF2_Z, REG_VF3_Z, REG_VF4_Z,
+ REG_VF5_Z, REG_VF6_Z, REG_VF7_Z, REG_VF8_Z, REG_VF9_Z, REG_VF10_Z, REG_VF11_Z, REG_VF12_Z,
+ REG_VF13_Z, REG_VF14_Z, REG_VF15_Z, REG_VF16_Z, REG_VF17_Z, REG_VF18_Z, REG_VF19_Z, REG_VF20_Z,
+ REG_VF21_Z, REG_VF22_Z, REG_VF23_Z, REG_VF24_Z, REG_VF25_Z, REG_VF26_Z, REG_VF27_Z, REG_VF28_Z,
+ REG_VF29_Z, REG_VF30_Z, REG_VF31_Z, REG_VACC_W, REG_VF0_W, REG_VF1_W, REG_VF2_W, REG_VF3_W,
+ REG_VF4_W, REG_VF5_W, REG_VF6_W, REG_VF7_W, REG_VF8_W, REG_VF9_W, REG_VF10_W, REG_VF11_W,
+ REG_VF12_W, REG_VF13_W, REG_VF14_W, REG_VF15_W, REG_VF16_W, REG_VF17_W, REG_VF18_W, REG_VF19_W,
+ REG_VF20_W, REG_VF21_W, REG_VF22_W, REG_VF23_W, REG_VF24_W, REG_VF25_W, REG_VF26_W, REG_VF27_W,
+ REG_VF28_W, REG_VF29_W, REG_VF30_W, REG_VF31_W, REG_VACC_XY, REG_VF0_XY, REG_VF1_XY, REG_VF2_XY,
+ REG_VF3_XY, REG_VF4_XY, REG_VF5_XY, REG_VF6_XY, REG_VF7_XY, REG_VF8_XY, REG_VF9_XY, REG_VF10_XY,
+ REG_VF11_XY, REG_VF12_XY, REG_VF13_XY, REG_VF14_XY, REG_VF15_XY, REG_VF16_XY, REG_VF17_XY, REG_VF18_XY,
+ REG_VF19_XY, REG_VF20_XY, REG_VF21_XY, REG_VF22_XY, REG_VF23_XY, REG_VF24_XY, REG_VF25_XY, REG_VF26_XY,
+ REG_VF27_XY, REG_VF28_XY, REG_VF29_XY, REG_VF30_XY, REG_VF31_XY, REG_VACC_XZ, REG_VF0_XZ, REG_VF1_XZ,
+ REG_VF2_XZ, REG_VF3_XZ, REG_VF4_XZ, REG_VF5_XZ, REG_VF6_XZ, REG_VF7_XZ, REG_VF8_XZ, REG_VF9_XZ,
+ REG_VF10_XZ, REG_VF11_XZ, REG_VF12_XZ, REG_VF13_XZ, REG_VF14_XZ, REG_VF15_XZ, REG_VF16_XZ, REG_VF17_XZ,
+ REG_VF18_XZ, REG_VF19_XZ, REG_VF20_XZ, REG_VF21_XZ, REG_VF22_XZ, REG_VF23_XZ, REG_VF24_XZ, REG_VF25_XZ,
+ REG_VF26_XZ, REG_VF27_XZ, REG_VF28_XZ, REG_VF29_XZ, REG_VF30_XZ, REG_VF31_XZ, REG_VACC_XW, REG_VF0_XW,
+ REG_VF1_XW, REG_VF2_XW, REG_VF3_XW, REG_VF4_XW, REG_VF5_XW, REG_VF6_XW, REG_VF7_XW, REG_VF8_XW,
+ REG_VF9_XW, REG_VF10_XW, REG_VF11_XW, REG_VF12_XW, REG_VF13_XW, REG_VF14_XW, REG_VF15_XW, REG_VF16_XW,
+ REG_VF17_XW, REG_VF18_XW, REG_VF19_XW, REG_VF20_XW, REG_VF21_XW, REG_VF22_XW, REG_VF23_XW, REG_VF24_XW,
+ REG_VF25_XW, REG_VF26_XW, REG_VF27_XW, REG_VF28_XW, REG_VF29_XW, REG_VF30_XW, REG_VF31_XW, REG_VACC_YZ,
+ REG_VF0_YZ, REG_VF1_YZ, REG_VF2_YZ, REG_VF3_YZ, REG_VF4_YZ, REG_VF5_YZ, REG_VF6_YZ, REG_VF7_YZ,
+ REG_VF8_YZ, REG_VF9_YZ, REG_VF10_YZ, REG_VF11_YZ, REG_VF12_YZ, REG_VF13_YZ, REG_VF14_YZ, REG_VF15_YZ,
+ REG_VF16_YZ, REG_VF17_YZ, REG_VF18_YZ, REG_VF19_YZ, REG_VF20_YZ, REG_VF21_YZ, REG_VF22_YZ, REG_VF23_YZ,
+ REG_VF24_YZ, REG_VF25_YZ, REG_VF26_YZ, REG_VF27_YZ, REG_VF28_YZ, REG_VF29_YZ, REG_VF30_YZ, REG_VF31_YZ,
+ REG_VACC_YW, REG_VF0_YW, REG_VF1_YW, REG_VF2_YW, REG_VF3_YW, REG_VF4_YW, REG_VF5_YW, REG_VF6_YW,
+ REG_VF7_YW, REG_VF8_YW, REG_VF9_YW, REG_VF10_YW, REG_VF11_YW, REG_VF12_YW, REG_VF13_YW, REG_VF14_YW,
+ REG_VF15_YW, REG_VF16_YW, REG_VF17_YW, REG_VF18_YW, REG_VF19_YW, REG_VF20_YW, REG_VF21_YW, REG_VF22_YW,
+ REG_VF23_YW, REG_VF24_YW, REG_VF25_YW, REG_VF26_YW, REG_VF27_YW, REG_VF28_YW, REG_VF29_YW, REG_VF30_YW,
+ REG_VF31_YW, REG_VACC_ZW, REG_VF0_ZW, REG_VF1_ZW, REG_VF2_ZW, REG_VF3_ZW, REG_VF4_ZW, REG_VF5_ZW,
+ REG_VF6_ZW, REG_VF7_ZW, REG_VF8_ZW, REG_VF9_ZW, REG_VF10_ZW, REG_VF11_ZW, REG_VF12_ZW, REG_VF13_ZW,
+ REG_VF14_ZW, REG_VF15_ZW, REG_VF16_ZW, REG_VF17_ZW, REG_VF18_ZW, REG_VF19_ZW, REG_VF20_ZW, REG_VF21_ZW,
+ REG_VF22_ZW, REG_VF23_ZW, REG_VF24_ZW, REG_VF25_ZW, REG_VF26_ZW, REG_VF27_ZW, REG_VF28_ZW, REG_VF29_ZW,
+ REG_VF30_ZW, REG_VF31_ZW, REG_VACC_XYZ, REG_VF0_XYZ, REG_VF1_XYZ, REG_VF2_XYZ, REG_VF3_XYZ, REG_VF4_XYZ,
+ REG_VF5_XYZ, REG_VF6_XYZ, REG_VF7_XYZ, REG_VF8_XYZ, REG_VF9_XYZ, REG_VF10_XYZ, REG_VF11_XYZ, REG_VF12_XYZ,
+ REG_VF13_XYZ, REG_VF14_XYZ, REG_VF15_XYZ, REG_VF16_XYZ, REG_VF17_XYZ, REG_VF18_XYZ, REG_VF19_XYZ, REG_VF20_XYZ,
+ REG_VF21_XYZ, REG_VF22_XYZ, REG_VF23_XYZ, REG_VF24_XYZ, REG_VF25_XYZ, REG_VF26_XYZ, REG_VF27_XYZ, REG_VF28_XYZ,
+ REG_VF29_XYZ, REG_VF30_XYZ, REG_VF31_XYZ, REG_VACC_XYW, REG_VF0_XYW, REG_VF1_XYW, REG_VF2_XYW, REG_VF3_XYW,
+ REG_VF4_XYW, REG_VF5_XYW, REG_VF6_XYW, REG_VF7_XYW, REG_VF8_XYW, REG_VF9_XYW, REG_VF10_XYW, REG_VF11_XYW,
+ REG_VF12_XYW, REG_VF13_XYW, REG_VF14_XYW, REG_VF15_XYW, REG_VF16_XYW, REG_VF17_XYW, REG_VF18_XYW, REG_VF19_XYW,
+ REG_VF20_XYW, REG_VF21_XYW, REG_VF22_XYW, REG_VF23_XYW, REG_VF24_XYW, REG_VF25_XYW, REG_VF26_XYW, REG_VF27_XYW,
+ REG_VF28_XYW, REG_VF29_XYW, REG_VF30_XYW, REG_VF31_XYW, REG_VACC_XZW, REG_VF0_XZW, REG_VF1_XZW, REG_VF2_XZW,
+ REG_VF3_XZW, REG_VF4_XZW, REG_VF5_XZW, REG_VF6_XZW, REG_VF7_XZW, REG_VF8_XZW, REG_VF9_XZW, REG_VF10_XZW,
+ REG_VF11_XZW, REG_VF12_XZW, REG_VF13_XZW, REG_VF14_XZW, REG_VF15_XZW, REG_VF16_XZW, REG_VF17_XZW, REG_VF18_XZW,
+ REG_VF19_XZW, REG_VF20_XZW, REG_VF21_XZW, REG_VF22_XZW, REG_VF23_XZW, REG_VF24_XZW, REG_VF25_XZW, REG_VF26_XZW,
+ REG_VF27_XZW, REG_VF28_XZW, REG_VF29_XZW, REG_VF30_XZW, REG_VF31_XZW, REG_VACC_YZW, REG_VF0_YZW, REG_VF1_YZW,
+ REG_VF2_YZW, REG_VF3_YZW, REG_VF4_YZW, REG_VF5_YZW, REG_VF6_YZW, REG_VF7_YZW, REG_VF8_YZW, REG_VF9_YZW,
+ REG_VF10_YZW, REG_VF11_YZW, REG_VF12_YZW, REG_VF13_YZW, REG_VF14_YZW, REG_VF15_YZW, REG_VF16_YZW, REG_VF17_YZW,
+ REG_VF18_YZW, REG_VF19_YZW, REG_VF20_YZW, REG_VF21_YZW, REG_VF22_YZW, REG_VF23_YZW, REG_VF24_YZW, REG_VF25_YZW,
+ REG_VF26_YZW, REG_VF27_YZW, REG_VF28_YZW, REG_VF29_YZW, REG_VF30_YZW, REG_VF31_YZW, REG_VACC_XYZW, REG_VF0_XYZW,
+ REG_VF1_XYZW, REG_VF2_XYZW, REG_VF3_XYZW, REG_VF4_XYZW, REG_VF5_XYZW, REG_VF6_XYZW, REG_VF7_XYZW, REG_VF8_XYZW,
+ REG_VF9_XYZW, REG_VF10_XYZW, REG_VF11_XYZW, REG_VF12_XYZW, REG_VF13_XYZW, REG_VF14_XYZW, REG_VF15_XYZW, REG_VF16_XYZW,
+ REG_VF17_XYZW, REG_VF18_XYZW, REG_VF19_XYZW, REG_VF20_XYZW, REG_VF21_XYZW, REG_VF22_XYZW, REG_VF23_XYZW, REG_VF24_XYZW,
+ REG_VF25_XYZW, REG_VF26_XYZW, REG_VF27_XYZW, REG_VF28_XYZW, REG_VF29_XYZW, REG_VF30_XYZW, REG_VF31_XYZW,
+
// Last valid register
END_REG
};
@@ -929,6 +1304,8 @@ namespace mips
FPCCREG_FCC5,
FPCCREG_FCC6,
FPCCREG_FCC7,
+ CCREG_COC0,
+ CCREG_COC2,
END_FLAG
};
@@ -940,7 +1317,10 @@ namespace mips
LABEL,
MEM_IMM,
MEM_REG,
- HINT
+ HINT,
+ V_REG,
+ V_DEST,
+ V_REG_FIELD,
};
enum Hint {
@@ -962,7 +1342,8 @@ namespace mips
MIPS_4,
MIPS_32,
MIPS_64,
- MIPS_VERSION_END
+ MIPS_R5900,
+ MIPS_VERSION_END,
};
#ifndef __cplusplus
@@ -1014,6 +1395,25 @@ namespace mips
uint32_t opcode:6;
};
+ struct vtype {
+ uint32_t bc:2;
+ uint32_t op_4:4;
+ uint32_t fd:5;
+ uint32_t fs:5;
+ uint32_t ft:5;
+ uint32_t dest:4;
+ uint32_t co:1;
+ uint32_t opcode:6;
+ };
+
+ struct vitype {
+ uint32_t func:6;
+ uint32_t imm15:15;
+ uint32_t dest:4;
+ uint32_t co:1;
+ uint32_t opcode:6;
+ };
+
struct ttype {
uint32_t function:6;
uint32_t code:10;
@@ -1034,6 +1434,8 @@ namespace mips
struct jtype j;
struct rtype r;
struct ftype f;
+ struct vtype v;
+ struct vitype vi;
struct ttype t;
struct stype s;
uint32_t value;
@@ -1087,6 +1489,7 @@ namespace mips
Operation operation;
InstructionOperand operands[MAX_OPERANDS];
uint32_t size;
+ uint32_t numOperands;
};
#ifndef __cplusplus
@@ -1124,7 +1527,9 @@ namespace mips
const char* get_register(Reg reg);
const char* get_flag(enum Flag flag);
const char* get_hint(Hint hint);
+
#ifdef __cplusplus
}
}//end namespace
#endif
+
diff --git a/arch/mips/mips/test.c b/arch/mips/mips/test.c
index a682863d..d2f1d4c4 100644
--- a/arch/mips/mips/test.c
+++ b/arch/mips/mips/test.c
@@ -78,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;
@@ -160,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};
+ 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;
+ }
+#ifndef WIN32
+ if (version == MIPS_R5900)
+ insword = ntohl(insword);
+#endif
+ 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++;
}