summaryrefslogtreecommitdiff
path: root/arch/mips/il.cpp
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 /arch/mips/il.cpp
parent8303adc8095926ad8e4f3758f5e2677fa20450ce (diff)
[mips] Merges PR https://github.com/Vector35/binaryninja-api/pull/6311: MIPS r5900 (PS2 EE) support
Diffstat (limited to 'arch/mips/il.cpp')
-rw-r--r--arch/mips/il.cpp4399
1 files changed, 3423 insertions, 976 deletions
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;