return ret;
}
-/* Do a endian load of a 32-bit word, regardless of the
- endianness of the underlying host. */
+/* ---------------- MIPS32 DSP ASE(r2) accumulators ---------------- */
+
+static UInt accumulatorGuestRegOffset(UInt acNo)
+{
+ vassert(!mode64);
+ vassert(acNo <= 3);
+ UInt ret;
+ switch (acNo) {
+ case 0:
+ ret = offsetof(VexGuestMIPS32State, guest_ac0); break;
+ case 1:
+ ret = offsetof(VexGuestMIPS32State, guest_ac1); break;
+ case 2:
+ ret = offsetof(VexGuestMIPS32State, guest_ac2); break;
+ case 3:
+ ret = offsetof(VexGuestMIPS32State, guest_ac3); break;
+ default:
+ vassert(0);
+ break;
+ }
+ return ret;
+}
+
+/* Do a endian load of a 32-bit word, regardless of the endianness of the
+ underlying host. */
static inline UInt getUInt(UChar * p)
{
UInt w = 0;
t4 = newTemp(Ity_I32); \
assign(t4, mkNarrowTo32( ty, binop(Iop_And64, \
mkexpr(t1), mkU64(0x3))));
-
+
#define LWX_SWX_PATTERN64_1 \
t2 = newTemp(Ity_I64); \
assign(t2, binop(Iop_And64, mkexpr(t1), mkU64(0xFFFFFFFFFFFFFFF8ULL))); \
return (0x00000007 & mipsins);
}
+/* Get acc number for all MIPS32 DSP ASE(r2) instructions that use them,
+ except for MFHI and MFLO. */
+static UInt get_acNo(UInt mipsins)
+{
+ return (0x00001800 & mipsins) >> 11;
+}
+
+/* Get accumulator number for MIPS32 DSP ASEr2 MFHI and MFLO instructions. */
+static UInt get_acNo_mfhilo(UInt mipsins)
+{
+ return (0x00600000 & mipsins) >> 21;
+}
+
+/* Get mask field (helper function for wrdsp instruction). */
+static UInt get_wrdspMask(UInt mipsins)
+{
+ return (0x001ff800 & mipsins) >> 11;
+}
+
+/* Get mask field (helper function for rddsp instruction). */
+static UInt get_rddspMask(UInt mipsins)
+{
+ return (0x03ff0000 & mipsins) >> 16;
+}
+
+/* Get shift field (helper function for DSP ASE instructions). */
+static UInt get_shift(UInt mipsins)
+{
+ return (0x03f00000 & mipsins) >> 20;
+}
+
+/* Get immediate field for DSP ASE instructions. */
+static UInt get_dspImm(UInt mipsins)
+{
+ return (0x03ff0000 & mipsins) >> 16;
+}
+
static Bool branch_or_jump(UChar * addr)
{
UInt fmt;
UInt function = get_function(cins);
/* bgtz, blez, bne, beq, jal */
- if (opcode == 0x07 || opcode == 0x06 || opcode == 0x05 || opcode == 0x04
+ if (opcode == 0x07 || opcode == 0x06 || opcode == 0x05 || opcode == 0x04
|| opcode == 0x03 || opcode == 0x02) {
return True;
}
}
}
+ /* bposge32 */
+ if (opcode == 0x01 && rt == 0x1c) {
+ return True;
+ }
+
return False;
}
return IRExpr_Const(IRConst_U8((UChar) i));
}
-/* Create an expression node for a 32-bit integer constant */
+/* Create an expression node for a 16-bit integer constant. */
+static IRExpr *mkU16(UInt i)
+{
+ return IRExpr_Const(IRConst_U16(i));
+}
+
+/* Create an expression node for a 32-bit integer constant. */
static IRExpr *mkU32(UInt i)
{
return IRExpr_Const(IRConst_U32(i));
}
-/* Create an expression node for a 64-bit integer constant */
+/* Create an expression node for a 64-bit integer constant. */
static IRExpr *mkU64(ULong i)
{
return IRExpr_Const(IRConst_U64(i));
binop(Iop_Shr32, src, mkexpr(t0)));
}
+static UShort extend_s_10to16(UInt x)
+{
+ return (UShort) ((((Int) x) << 22) >> 22);
+}
+
static UInt extend_s_16to32(UInt x)
{
return (UInt) ((((Int) x) << 16) >> 16);
stmt(IRStmt_Put(OFFB_PC, mkU64(d64)));
}
+/* Get value from accumulator (helper function for MIPS32 DSP ASE instructions).
+ This function should be called before any other operation if widening
+ multiplications are used. */
+static IRExpr *getAcc(UInt acNo)
+{
+ vassert(!mode64);
+ vassert(acNo <= 3);
+ return IRExpr_Get(accumulatorGuestRegOffset(acNo), Ity_I64);
+}
+
+/* Get value from DSPControl register (helper function for MIPS32 DSP ASE
+ instructions). */
+static IRExpr *getDSPControl(void)
+{
+ vassert(!mode64);
+ return IRExpr_Get(offsetof(VexGuestMIPS32State, guest_DSPControl), Ity_I32);
+}
+
+/* Put value to DSPControl register. Expression e is written to DSPControl as
+ is. If only certain bits of DSPControl need to be changed, it should be done
+ before calling putDSPControl(). It could be done by reading DSPControl and
+ ORing it with appropriate mask. */
+static void putDSPControl(IRExpr * e)
+{
+ vassert(!mode64);
+ stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_DSPControl), e));
+}
+
/* Fetch a byte from the guest insn stream. */
static UChar getIByte(Int delta)
{
static void putLO(IRExpr * e)
{
- if (mode64)
+ if (mode64) {
stmt(IRStmt_Put(offsetof(VexGuestMIPS64State, guest_LO), e));
- else
+ } else {
stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_LO), e));
+ /* Add value to lower 32 bits of ac0 to maintain compatibility between
+ regular MIPS32 instruction set and MIPS DSP ASE. Keep higher 32bits
+ unchanged. */
+ IRTemp t_lo = newTemp(Ity_I32);
+ IRTemp t_hi = newTemp(Ity_I32);
+ assign(t_lo, e);
+ assign(t_hi, unop(Iop_64HIto32, getAcc(0)));
+ stmt(IRStmt_Put(accumulatorGuestRegOffset(0),
+ binop(Iop_32HLto64, mkexpr(t_hi), mkexpr(t_lo))));
+ }
}
static void putHI(IRExpr * e)
{
- if (mode64)
+ if (mode64) {
stmt(IRStmt_Put(offsetof(VexGuestMIPS64State, guest_HI), e));
- else
+ } else {
stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_HI), e));
+ /* Add value to higher 32 bits of ac0 to maintain compatibility between
+ regular MIPS32 instruction set and MIPS DSP ASE. Keep lower 32bits
+ unchanged. */
+ IRTemp t_lo = newTemp(Ity_I32);
+ IRTemp t_hi = newTemp(Ity_I32);
+ assign(t_hi, e);
+ assign(t_lo, unop(Iop_64to32, getAcc(0)));
+ stmt(IRStmt_Put(accumulatorGuestRegOffset(0),
+ binop(Iop_32HLto64, mkexpr(t_hi), mkexpr(t_lo))));
+ }
+}
+
+/* Put value to accumulator(helper function for MIPS32 DSP ASE instructions). */
+static void putAcc(UInt acNo, IRExpr * e)
+{
+ vassert(!mode64);
+ vassert(acNo <= 3);
+ vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I64);
+ stmt(IRStmt_Put(accumulatorGuestRegOffset(acNo), e));
+/* If acNo = 0, split value to HI and LO regs in order to maintain compatibility
+ between MIPS32 and MIPS DSP ASE insn sets. */
+ if (0 == acNo) {
+ putLO(unop(Iop_64to32, e));
+ putHI(unop(Iop_64HIto32, e));
+ }
}
static IRExpr *mkNarrowTo8 ( IRType ty, IRExpr * src )
IRTemp t0;
/* PC = PC + (SignExtend(signed_immed_24) << 2)
- An 18-bit signed offset (the 16-bit offset field shifted left 2 bits)
+ An 18-bit signed offset (the 16-bit offset field shifted left 2 bits)
is added to the address of the instruction following
- the branch (not the branch itself), in the branch delay slot, to form
+ the branch (not the branch itself), in the branch delay slot, to form
a PC-relative effective target address. */
if (mode64)
branch_offset = extend_s_18to64(imm << 2);
stmt(IRStmt_Exit(mkexpr(t0), Ijk_Boring,
IRConst_U64(guest_PC_curr_instr + 8), OFFB_PC));
else
- stmt(IRStmt_Exit(mkexpr(t0), Ijk_Boring,
+ stmt(IRStmt_Exit(mkexpr(t0), Ijk_Boring,
IRConst_U32(guest_PC_curr_instr + 8), OFFB_PC));
irsb->jumpkind = Ijk_Boring;
}
/* PC = PC + (SignExtend(signed_immed_24) << 2)
- An 18-bit signed offset (the 16-bit offset field shifted left 2 bits)
+ An 18-bit signed offset (the 16-bit offset field shifted left 2 bits)
is added to the address of the instruction following
- the branch (not the branch itself), in the branch delay slot, to form
+ the branch (not the branch itself), in the branch delay slot, to form
a PC-relative effective target address. */
if (mode64)
putFCSR(binop(Iop_And32, getFCSR(), mkU32(0xFF7FFFFF)));
putFCSR(binop(Iop_Or32, getFCSR(), binop(Iop_Shl32, e, mkU8(23))));
} else {
- putFCSR(binop(Iop_And32, getFCSR(), unop(Iop_Not32,
+ putFCSR(binop(Iop_And32, getFCSR(), unop(Iop_Not32,
binop(Iop_Shl32, mkU32(0x01000000), mkU8(cc)))));
putFCSR(binop(Iop_Or32, getFCSR(), binop(Iop_Shl32, e, mkU8(24 + cc))));
}
static IRExpr* get_IR_roundingmode ( void )
{
-/*
+/*
rounding mode | MIPS | IR
------------------------
to nearest | 00 | 00
static Addr64 mkSzAddr ( IRType ty, Addr64 addr )
{
vassert(ty == Ity_I32 || ty == Ity_I64);
- return (ty == Ity_I64 ? (Addr64) addr :
+ return (ty == Ity_I64 ? (Addr64) addr :
(Addr64) extend_s_32to64(toUInt(addr)));
}
*/
/* ccMIPS = Shl(1, (~(ccIR>>5) & 2) | ((ccIR ^ (ccIR>>6)) & 1) */
- assign(ccMIPS, binop(Iop_Shl32, mkU32(1), unop(Iop_32to8,
+ assign(ccMIPS, binop(Iop_Shl32, mkU32(1), unop(Iop_32to8,
binop(Iop_Or32, binop(Iop_And32, unop(Iop_Not32,
binop(Iop_Shr32, mkexpr(ccIR),mkU8(5))),mkU32(2)),
binop(Iop_And32, binop(Iop_Xor32, mkexpr(ccIR),
- binop(Iop_Shr32, mkexpr(ccIR), mkU8(6))),
+ binop(Iop_Shr32, mkexpr(ccIR), mkU8(6))),
mkU32(1))))));
putLO(mkWidenFrom32(Ity_I64, mkexpr(ccMIPS), True));
case 0xF:
setFPUCondCode(mkexpr(t2), fpc_cc);
break;
-
+
default:
return False;
}
*/
/* ccMIPS = Shl(1, (~(ccIR>>5) & 2) | ((ccIR ^ (ccIR>>6)) & 1) */
- assign(ccMIPS, binop(Iop_Shl32, mkU32(1), unop(Iop_32to8,
+ assign(ccMIPS, binop(Iop_Shl32, mkU32(1), unop(Iop_32to8,
binop(Iop_Or32, binop(Iop_And32, unop(Iop_Not32,
binop(Iop_Shr32, mkexpr(ccIR), mkU8(5))),
mkU32(2)), binop(Iop_And32,
binop(Iop_Xor32, mkexpr(ccIR),
- binop(Iop_Shr32, mkexpr(ccIR), mkU8(6))),
+ binop(Iop_Shr32, mkexpr(ccIR), mkU8(6))),
mkU32(1))))));
/* UN */
assign(t0, binop(Iop_And32, mkexpr(ccMIPS), mkU32(0x1)));
case 0xF:
setFPUCondCode(mkexpr(t2), fpc_cc);
break;
-
+
default:
return False;
}
binop(Iop_And32, binop(Iop_Xor32, mkexpr(ccIR),
binop(Iop_Shr32, mkexpr(ccIR), mkU8(6))),
mkU32(1))))));
-
+
/* UN */
assign(t0, binop(Iop_And32, mkexpr(ccMIPS), mkU32(0x1)));
/* EQ */
jmpKind = Ijk_Call;
break;
}
-
+
+ }
+ break;
+ default:
+ return False;
+ }
+ *set = IRStmt_Exit(eCond, jmpKind, mkSzConst(ty, addrTgt), OFFB_PC);
+ return True;
+}
+
+/*------------------------------------------------------------*/
+/*--- Disassemble a single DSP ASE instruction ---*/
+/*------------------------------------------------------------*/
+
+static UInt disDSPInstr_MIPS_WRK ( UInt cins )
+{
+ IRTemp t0, t1 = 0, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14,
+ t15, t16, t17, t18;
+ UInt opcode, rs, rt, rd, sa, function, ac, ac_mfhilo, rddsp_mask,
+ wrdsp_mask, dsp_imm, shift;
+
+ opcode = get_opcode(cins);
+ rs = get_rs(cins);
+ rt = get_rt(cins);
+ rd = get_rd(cins);
+ sa = get_sa(cins);
+ function = get_function(cins);
+ ac = get_acNo(cins);
+ ac_mfhilo = get_acNo_mfhilo(cins);
+ rddsp_mask = get_rddspMask(cins);
+ wrdsp_mask = get_wrdspMask(cins);
+ dsp_imm = get_dspImm(cins);
+ shift = get_shift(cins);
+
+ switch (opcode) {
+ case 0x00: { /* Special */
+ switch (function) {
+ case 0x10: { /* MFHI */
+ DIP("mfhi ac%d r%d", ac_mfhilo, rd);
+ putIReg(rd, unop(Iop_64HIto32, getAcc(ac_mfhilo)));
+ break;
+ }
+
+ case 0x11: { /* MTHI */
+ DIP("mthi ac%d r%d", ac, rs);
+ t1 = newTemp(Ity_I32);
+ assign(t1, unop(Iop_64to32, getAcc(ac)));
+ putAcc(ac, binop(Iop_32HLto64, getIReg(rs), mkexpr(t1)));
+ break;
+ }
+
+ case 0x12: { /* MFLO */
+ DIP("mflo ac%d r%d", ac_mfhilo, rd);
+ putIReg(rd, unop(Iop_64to32, getAcc(ac_mfhilo)));
+ break;
+ }
+
+ case 0x13: { /* MTLO */
+ DIP("mtlo ac%d r%d", ac, rs);
+ t1 = newTemp(Ity_I32);
+ assign(t1, unop(Iop_64HIto32, getAcc(ac)));
+ putAcc(ac, binop(Iop_32HLto64, mkexpr(t1), getIReg(rs)));
+ break;
+ }
+
+ case 0x18: { /* MULT */
+ DIP("mult ac%d r%d, r%d", ac, rs, rt);
+ t1 = newTemp(Ity_I64);
+ assign(t1, binop(Iop_MullS32, mkNarrowTo32(Ity_I32, getIReg(rs)),
+ mkNarrowTo32(Ity_I32, getIReg(rt))));
+ putAcc(ac, mkexpr(t1));
+ break;
+ }
+
+ case 0x19: { /* MULTU */
+ DIP("multu ac%d r%d, r%d", ac, rs, rt);
+ t1 = newTemp(Ity_I64);
+ assign(t1, binop(Iop_MullU32, mkNarrowTo32(Ity_I32, getIReg(rs)),
+ mkNarrowTo32(Ity_I32,
+ getIReg(rt))));
+ putAcc(ac, mkexpr(t1));
+ break;
+ }
+ }
+ break;
+ }
+ case 0x1C: { /* Special2 */
+ switch (function) {
+ case 0x00: { /* MADD */
+ DIP("madd ac%d, r%d, r%d", ac, rs, rt);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I64);
+ t3 = newTemp(Ity_I64);
+
+ assign(t1, getAcc(ac));
+ assign(t2, binop(Iop_MullS32, getIReg(rs), getIReg(rt)));
+ assign(t3, binop(Iop_Add64, mkexpr(t1), mkexpr(t2)));
+
+ putAcc(ac, mkexpr(t3));
+ break;
+ }
+ case 0x01: { /* MADDU */
+ DIP("maddu ac%d r%d, r%d", ac, rs, rt);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I64);
+ t3 = newTemp(Ity_I64);
+
+ assign(t1, getAcc(ac));
+ assign(t2, binop(Iop_MullU32, getIReg(rs), getIReg(rt)));
+ assign(t3, binop(Iop_Add64, mkexpr(t2), mkexpr(t1)));
+
+ putAcc(ac, mkexpr(t3));
+ break;
+ }
+ case 0x04: { /* MSUB */
+ DIP("msub ac%d r%d, r%d", ac, rs, rt);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I64);
+ t3 = newTemp(Ity_I64);
+
+ assign(t1, getAcc(ac));
+ assign(t2, binop(Iop_MullS32, getIReg(rs), getIReg(rt)));
+ assign(t3, binop(Iop_Sub64, mkexpr(t1), mkexpr(t2)));
+
+ putAcc(ac, mkexpr(t3));
+ break;
+ }
+ case 0x05: { /* MSUBU */
+ DIP("msubu ac%d r%d, r%d", ac, rs, rt);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I64);
+ t3 = newTemp(Ity_I64);
+
+ assign(t1, getAcc(ac));
+ assign(t2, binop(Iop_MullU32, getIReg(rs), getIReg(rt)));
+ assign(t3, binop(Iop_Sub64, mkexpr(t1), mkexpr(t2)));
+
+ putAcc(ac, mkexpr(t3));
+ break;
+ }
+ }
+ break;
+ }
+ case 0x1F: { /* Special3 */
+ switch (function) {
+ case 0x12: { /* ABSQ_S.PH */
+ switch (sa) {
+ case 0x1: { /* ABSQ_S.QB */
+ DIP("absq_s.qb r%d, r%d", rd, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I8);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I1);
+ t3 = newTemp(Ity_I8);
+ t4 = newTemp(Ity_I8);
+ t5 = newTemp(Ity_I1);
+ t6 = newTemp(Ity_I1);
+ t7 = newTemp(Ity_I8);
+ t8 = newTemp(Ity_I8);
+ t9 = newTemp(Ity_I1);
+ t10 = newTemp(Ity_I1);
+ t11 = newTemp(Ity_I8);
+ t12 = newTemp(Ity_I8);
+ t13 = newTemp(Ity_I1);
+ t14 = newTemp(Ity_I1);
+ t15 = newTemp(Ity_I8);
+ t16 = newTemp(Ity_I32);
+ t17 = newTemp(Ity_I32);
+
+ /* Absolute value of the rightmost byte (bits 7-0). */
+ /* t0 - rightmost byte. */
+ assign(t0, unop(Iop_16to8, unop(Iop_32to16, getIReg(rt))));
+ /* t1 holds 1 if t0 is equal to 0x80, or 0 otherwise. */
+ assign(t1, binop(Iop_CmpEQ32,
+ unop(Iop_8Uto32, mkexpr(t0)),
+ mkU32(0x00000080)));
+ /* t2 holds 1 if value in t0 is negative, 0 otherwise. */
+ assign(t2, unop(Iop_32to1,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x00000080)),
+ mkU8(0x7))));
+ /* t3 holds abs(t0). */
+ assign(t3, IRExpr_ITE(mkexpr(t1),
+ mkU8(0x7F),
+ IRExpr_ITE(mkexpr(t2),
+ binop(Iop_Add8,
+ unop(Iop_Not8,
+ mkexpr(t0)),
+ mkU8(0x1)),
+ mkexpr(t0))));
+
+ /* Absolute value of bits 15-8. */
+ /* t4 - input byte. */
+ assign(t4,
+ unop(Iop_16HIto8, unop(Iop_32to16, getIReg(rt))));
+ /* t5 holds 1 if t4 is equal to 0x80, or 0 otherwise. */
+ assign(t5, binop(Iop_CmpEQ32,
+ unop(Iop_8Uto32, mkexpr(t4)),
+ mkU32(0x00000080)));
+ /* t6 holds 1 if value in t4 is negative, 0 otherwise. */
+ assign(t6, unop(Iop_32to1,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x00008000)),
+ mkU8(15))));
+ /* t3 holds abs(t4). */
+ assign(t7, IRExpr_ITE(mkexpr(t5),
+ mkU8(0x7F),
+ IRExpr_ITE(mkexpr(t6),
+ binop(Iop_Add8,
+ unop(Iop_Not8,
+ mkexpr(t4)),
+ mkU8(0x1)),
+ mkexpr(t4))));
+
+ /* Absolute value of bits 23-15. */
+ /* t8 - input byte. */
+ assign(t8,
+ unop(Iop_16to8, unop(Iop_32HIto16, getIReg(rt))));
+ /* t9 holds 1 if t8 is equal to 0x80, or 0 otherwise. */
+ assign(t9, binop(Iop_CmpEQ32,
+ unop(Iop_8Uto32, mkexpr(t8)),
+ mkU32(0x00000080)));
+ /* t6 holds 1 if value in t8 is negative, 0 otherwise. */
+ assign(t10, unop(Iop_32to1,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x00800000)),
+ mkU8(23))));
+ /* t3 holds abs(t8). */
+ assign(t11, IRExpr_ITE(mkexpr(t9),
+ mkU8(0x7F),
+ IRExpr_ITE(mkexpr(t10),
+ binop(Iop_Add8,
+ unop(Iop_Not8,
+ mkexpr(t8)),
+ mkU8(0x1)),
+ mkexpr(t8))));
+
+ /* Absolute value of bits 31-24. */
+ /* t12 - input byte. */
+ assign(t12,
+ unop(Iop_16HIto8, unop(Iop_32HIto16, getIReg(rt))));
+ /* t13 holds 1 if t12 is equal to 0x80, or 0 otherwise. */
+ assign(t13, binop(Iop_CmpEQ32,
+ unop(Iop_8Uto32, mkexpr(t12)),
+ mkU32(0x00000080)));
+ /* t14 holds 1 if value in t12 is negative, 0 otherwise. */
+ assign(t14, unop(Iop_32to1,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x80000000)),
+ mkU8(31))));
+ /* t15 holds abs(t12). */
+ assign(t15, IRExpr_ITE(mkexpr(t13),
+ mkU8(0x7F),
+ IRExpr_ITE(mkexpr(t14),
+ binop(Iop_Add8,
+ unop(Iop_Not8,
+ mkexpr(t12)),
+ mkU8(0x1)),
+ mkexpr(t12))));
+
+ /* t16 holds !0 if any of input bytes is 0x80 or 0
+ otherwise. */
+ assign(t16,
+ binop(Iop_Or32,
+ binop(Iop_Or32,
+ binop(Iop_Or32,
+ unop(Iop_1Sto32, mkexpr(t13)),
+ unop(Iop_1Sto32, mkexpr(t9))),
+ unop(Iop_1Sto32, mkexpr(t5))),
+ unop(Iop_1Sto32, mkexpr(t1))));
+
+ putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32,
+ mkexpr(t16),
+ mkU32(0x0)),
+ getDSPControl(),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00100000))));
+
+ /* t17 = t15|t11|t7|t3 */
+ assign(t17,
+ binop(Iop_16HLto32,
+ binop(Iop_8HLto16, mkexpr(t15), mkexpr(t11)),
+ binop(Iop_8HLto16, mkexpr(t7), mkexpr(t3))));
+
+ putIReg(rd, mkexpr(t17));
+ break;
+ }
+ case 0x2: { /* REPL.QB */
+ DIP("repl.qb r%d, %d", rd, dsp_imm);
+ vassert(!mode64);
+
+ putIReg(rd, mkU32((dsp_imm << 24) | (dsp_imm << 16) |
+ (dsp_imm << 8) | (dsp_imm)));
+ break;
+ }
+ case 0x3: { /* REPLV.QB */
+ DIP("replv.qb r%d, r%d", rd, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I8);
+
+ assign(t0, unop(Iop_32to8,
+ binop(Iop_And32, getIReg(rt), mkU32(0xff))));
+ putIReg(rd,
+ binop(Iop_16HLto32,
+ binop(Iop_8HLto16, mkexpr(t0), mkexpr(t0)),
+ binop(Iop_8HLto16, mkexpr(t0), mkexpr(t0))));
+ break;
+ }
+ case 0x4: { /* PRECEQU.PH.QBL */
+ DIP("precequ.ph.qbl r%d, r%d", rd, rt);
+ vassert(!mode64);
+
+ putIReg(rd, binop(Iop_Or32,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0xff000000)),
+ mkU8(1)),
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x00ff0000)),
+ mkU8(9))));
+ break;
+ }
+ case 0x5: { /* PRECEQU.PH.QBR */
+ DIP("precequ.ph.qbr r%d, r%d", rd, rt);
+ vassert(!mode64);
+
+ putIReg(rd, binop(Iop_Or32,
+ binop(Iop_Shl32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x0000ff00)),
+ mkU8(15)),
+ binop(Iop_Shl32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x000000ff)),
+ mkU8(7))));
+ break;
+ }
+ case 0x6: { /* PRECEQU.PH.QBLA */
+ DIP("precequ.ph.qbla r%d, r%d", rd, rt);
+ vassert(!mode64);
+
+ putIReg(rd, binop(Iop_Or32,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0xff000000)),
+ mkU8(1)),
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x0000ff00)),
+ mkU8(1))));
+ break;
+ }
+ case 0x7: { /* PRECEQU.PH.QBRA */
+ DIP("precequ.ph.qbra r%d, r%d", rd, rt);
+ vassert(!mode64);
+
+ putIReg(rd, binop(Iop_Or32,
+ binop(Iop_Shl32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x00ff0000)),
+ mkU8(7)),
+ binop(Iop_Shl32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x000000ff)),
+ mkU8(7))));
+ break;
+ }
+ case 0x9: { /* ABSQ_S.PH */
+ DIP("absq_s.ph r%d, r%d", rd, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I16);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I1);
+ t3 = newTemp(Ity_I16);
+ t4 = newTemp(Ity_I16);
+ t5 = newTemp(Ity_I1);
+ t6 = newTemp(Ity_I1);
+ t7 = newTemp(Ity_I16);
+ t8 = newTemp(Ity_I32);
+ t9 = newTemp(Ity_I32);
+
+ /* t0 holds lower 16 bits of value in rt. */
+ assign(t0, unop(Iop_32to16, getIReg(rt)));
+ /* t1 holds 1 if t0 is equal to 0x8000. */
+ assign(t1, binop(Iop_CmpEQ32,
+ unop(Iop_16Uto32, mkexpr(t0)),
+ mkU32(0x00008000)));
+ /* t2 holds 1 if value in t0 is negative, 0 otherwise. */
+ assign(t2, unop(Iop_32to1,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x00008000)),
+ mkU8(15))));
+ /* t3 holds abs(t0). */
+ assign(t3, IRExpr_ITE(mkexpr(t1),
+ mkU16(0x7FFF),
+ IRExpr_ITE(mkexpr(t2),
+ binop(Iop_Add16,
+ unop(Iop_Not16,
+ mkexpr(t0)),
+ mkU16(0x1)),
+ mkexpr(t0))));
+
+ /* t4 holds lower 16 bits of value in rt. */
+ assign(t4, unop(Iop_32HIto16, getIReg(rt)));
+ /* t5 holds 1 if t4 is equal to 0x8000. */
+ assign(t5, binop(Iop_CmpEQ32,
+ unop(Iop_16Uto32, mkexpr(t4)),
+ mkU32(0x00008000)));
+ /* t6 holds 1 if value in t4 is negative, 0 otherwise. */
+ assign(t6, unop(Iop_32to1,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x80000000)),
+ mkU8(31))));
+ /* t7 holds abs(t4). */
+ assign(t7, IRExpr_ITE(mkexpr(t5),
+ mkU16(0x7FFF),
+ IRExpr_ITE(mkexpr(t6),
+ binop(Iop_Add16,
+ unop(Iop_Not16,
+ mkexpr(t4)),
+ mkU16(0x1)),
+ mkexpr(t4))));
+ /* If any of the two input halfwords is equal 0x8000,
+ set bit 20 in DSPControl register. */
+ assign(t8, binop(Iop_Or32,
+ unop(Iop_1Sto32, mkexpr(t5)),
+ unop(Iop_1Sto32, mkexpr(t1))));
+
+ putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32,
+ mkexpr(t8),
+ mkU32(0x0)),
+ getDSPControl(),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00100000))));
+
+ /* t9 = t7|t3 */
+ assign(t9, binop(Iop_16HLto32, mkexpr(t7), mkexpr(t3)));
+
+ putIReg(rd, mkexpr(t9));
+ break;
+ }
+ case 0xA: { /* REPL.PH */
+ DIP("repl.ph r%d, %d", rd, dsp_imm);
+ vassert(!mode64);
+ UShort immediate = extend_s_10to16(dsp_imm);
+
+ putIReg(rd, mkU32(immediate << 16 | immediate));
+ break;
+ }
+ case 0xB: { /* REPLV.PH */
+ DIP("replv.ph r%d, r%d", rd, rt);
+ vassert(!mode64);
+
+ putIReg(rd, binop(Iop_16HLto32,
+ unop(Iop_32to16, getIReg(rt)),
+ unop(Iop_32to16, getIReg(rt))));
+ break;
+ }
+ case 0xC: { /* PRECEQ.W.PHL */
+ DIP("preceq.w.phl r%d, r%d", rd, rt);
+ vassert(!mode64);
+ putIReg(rd, binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0xffff0000)));
+ break;
+ }
+ case 0xD: { /* PRECEQ.W.PHR */
+ DIP("preceq.w.phr r%d, r%d", rd, rt);
+ vassert(!mode64);
+ putIReg(rd, binop(Iop_16HLto32,
+ unop(Iop_32to16, getIReg(rt)),
+ mkU16(0x0)));
+ break;
+ }
+ case 0x11: { /* ABSQ_S.W */
+ DIP("absq_s.w r%d, r%d", rd, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I1);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I32);
+
+ assign(t0,
+ binop(Iop_CmpEQ32, getIReg(rt), mkU32(0x80000000)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t0),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00100000)),
+ getDSPControl()));
+
+ assign(t1, binop(Iop_CmpLT32S, getIReg(rt), mkU32(0x0)));
+
+ assign(t2, IRExpr_ITE(mkexpr(t0),
+ mkU32(0x7FFFFFFF),
+ IRExpr_ITE(mkexpr(t1),
+ binop(Iop_Add32,
+ unop(Iop_Not32,
+ getIReg(rt)),
+ mkU32(0x1)),
+ getIReg(rt))));
+ putIReg(rd, mkexpr(t2));
+ break;
+ }
+ case 0x1B: { /* BITREV */
+ DIP("bitrev r%d, r%d", rd, rt);
+ vassert(!mode64);
+ /* 32bit reversal as seen on Bit Twiddling Hacks site
+ http://graphics.stanford.edu/~seander/bithacks.html
+ section ReverseParallel */
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I32);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I32);
+
+ assign(t1, binop(Iop_Or32,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0xaaaaaaaa)),
+ mkU8(0x1)),
+ binop(Iop_Shl32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x55555555)),
+ mkU8(0x1))));
+ assign(t2, binop(Iop_Or32,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ mkexpr(t1),
+ mkU32(0xcccccccc)),
+ mkU8(0x2)),
+ binop(Iop_Shl32,
+ binop(Iop_And32,
+ mkexpr(t1),
+ mkU32(0x33333333)),
+ mkU8(0x2))));
+ assign(t3, binop(Iop_Or32,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ mkexpr(t2),
+ mkU32(0xf0f0f0f0)),
+ mkU8(0x4)),
+ binop(Iop_Shl32,
+ binop(Iop_And32,
+ mkexpr(t2),
+ mkU32(0x0f0f0f0f)),
+ mkU8(0x4))));
+ assign(t4, binop(Iop_Or32,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ mkexpr(t3),
+ mkU32(0xff00ff00)),
+ mkU8(0x8)),
+ binop(Iop_Shl32,
+ binop(Iop_And32,
+ mkexpr(t3),
+ mkU32(0x00ff00ff)),
+ mkU8(0x8))));
+ assign(t5, binop(Iop_Or32,
+ binop(Iop_Shr32,
+ mkexpr(t4),
+ mkU8(0x10)),
+ binop(Iop_Shl32,
+ mkexpr(t4),
+ mkU8(0x10))));
+ putIReg(rd, binop(Iop_Shr32,
+ mkexpr(t5),
+ mkU8(16)));
+ break;
+ }
+ case 0x1C: { /* PRECEU.PH.QBL */
+ DIP("preceu.ph.qbl r%d, r%d", rd, rt);
+ vassert(!mode64);
+
+ putIReg(rd, binop(Iop_Or32,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0xff000000)),
+ mkU8(8)),
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x00ff0000)),
+ mkU8(16))));
+ break;
+ }
+ case 0x1E: { /* PRECEU.PH.QBLA */
+ DIP("preceu.ph.qbla r%d, r%d", rd, rt);
+ vassert(!mode64);
+
+ putIReg(rd, binop(Iop_Or32,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0xff000000)),
+ mkU8(8)),
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x0000ff00)),
+ mkU8(8))));
+ break;
+ }
+ case 0x1D: { /* PRECEU.PH.QBR */
+ DIP("preceu.ph.qbr r%d, r%d", rd, rt);
+ vassert(!mode64);
+
+ putIReg(rd, binop(Iop_Or32,
+ binop(Iop_Shl32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x0000ff00)),
+ mkU8(8)),
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x000000ff))));
+ break;
+ }
+ case 0x1F: { /* PRECEU.PH.QBRA */
+ DIP("preceu.ph.qbra r%d, r%d", rd, rt);
+ vassert(!mode64);
+
+ putIReg(rd, binop(Iop_Or32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x00ff0000)),
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x000000ff))));
+ break;
+ }
+ default:
+ return -1;
+ }
+ break; /* end of ABSQ_S.PH */
+ }
+ case 0x38: { /* EXTR.W */
+ switch(sa) {
+ case 0x0: { /* EXTR.W */
+ DIP("extr.w r%d, ac%d, %d", rt, ac, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I32);
+ t4 = newTemp(Ity_I32);
+
+ assign(t0, getAcc(ac));
+ assign(t1, binop(Iop_Sar64, mkexpr(t0), mkU8(rs)));
+ putIReg(rt, unop(Iop_64to32, mkexpr(t1)));
+
+ assign(t2, binop(Iop_Or32,
+ getDSPControl(), mkU32(0x00800000)));
+
+ /* Check if signOut == signIn */
+ assign(t3, IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ unop(Iop_64HIto32,
+ mkexpr(t0)),
+ mkU32(0x80000000)),
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x80000000))),
+ getDSPControl(),
+ mkexpr(t2)));
+
+ assign(t4, IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_64HIto32,
+ mkexpr(t1)),
+ mkU32(0x0)),
+ IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_64HIto32,
+ mkexpr(t1)),
+ mkU32(0xffffffff)),
+ mkexpr(t2),
+ mkexpr(t3)),
+ mkexpr(t3)));
+ putDSPControl(mkexpr(t4));
+ break;
+ }
+ case 0x1: { /* EXTRV.W */
+ DIP("extrv.w r%d, ac%d, r%d", rt, ac, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I32);
+ t4 = newTemp(Ity_I1);
+
+ assign(t0, getAcc(ac));
+ assign(t1, binop(Iop_Sar64,
+ mkexpr(t0),
+ unop(Iop_32to8,
+ binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x1f)))));
+ putIReg(rt, unop(Iop_64to32, mkexpr(t1)));
+
+ assign(t2, binop(Iop_Or32,
+ getDSPControl(), mkU32(0x00800000)));
+
+ /* Check if signOut == signIn */
+ assign(t3, IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ unop(Iop_64HIto32,
+ mkexpr(t0)),
+ mkU32(0x80000000)),
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x80000000))),
+ getDSPControl(),
+ mkexpr(t2)));
+ assign(t4, binop(Iop_CmpNE32,
+ unop(Iop_64HIto32, mkexpr(t1)),
+ mkU32(0xffffffff)));
+ putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_64HIto32,
+ mkexpr(t1)),
+ mkU32(0x0)),
+ IRExpr_ITE(mkexpr(t4),
+ mkexpr(t2),
+ mkexpr(t3)),
+ mkexpr(t3)));
+ break;
+ }
+ case 0x2: { /* EXTP */
+ DIP("extp r%d, ac%d, %d", rt, ac, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I1);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I8);
+ t5 = newTemp(Ity_I64);
+ t6 = newTemp(Ity_I64);
+ t7 = newTemp(Ity_I32);
+
+ assign(t0, getAcc(ac));
+ /* Extract pos field of DSPControl register. */
+ assign(t1, binop(Iop_And32, getDSPControl(), mkU32(0x3f)));
+
+ /* Check if (pos - size) >= 0 [size <= pos]
+ if (pos < size)
+ put 1 to EFI field of DSPControl register
+ else
+ extract bits from acc and put 0 to EFI field of
+ DSPCtrl */
+ assign(t2, binop(Iop_CmpLT32U, mkexpr(t1), mkU32(rs)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t2),
+ binop(Iop_Or32,
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xffffbfff)),
+ mkU32(0x4000)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xffffbfff))));
+
+ /* If pos <= 31, shift right the value from the acc
+ (pos-size) times and take (size+1) bits from the least
+ significant positions. Otherwise, shift left the value
+ (63-pos) times, take (size+1) bits from the most
+ significant positions and shift right (31-size) times.*/
+ assign(t3, binop(Iop_CmpLE32U, mkexpr(t1), mkU32(31)));
+
+ assign(t4,
+ IRExpr_ITE(mkexpr(t3),
+ unop(Iop_32to8,
+ binop(Iop_Sub32,
+ mkexpr(t1), mkU32(rs))),
+ unop(Iop_32to8,
+ binop(Iop_Sub32,
+ mkU32(63), mkexpr(t1)))));
+
+ assign(t5, IRExpr_ITE(mkexpr(t3),
+ binop(Iop_Shr64,
+ mkexpr(t0), mkexpr(t4)),
+ binop(Iop_Shl64,
+ mkexpr(t0), mkexpr(t4))));
+
+ /* t6 holds a mask for bit extraction */
+ assign(t6,
+ IRExpr_ITE(mkexpr(t3),
+ unop(Iop_Not64,
+ binop(Iop_Shl64,
+ mkU64(0xffffffffffffffffULL),
+ mkU8(rs+1))),
+ unop(Iop_Not64,
+ binop(Iop_Shr64,
+ mkU64(0xffffffffffffffffULL),
+ mkU8(rs+1)))));
+
+ assign(t7, IRExpr_ITE(mkexpr(t3),
+ unop(Iop_64to32,
+ binop(Iop_And64,
+ mkexpr(t5),
+ mkexpr(t6))),
+ binop(Iop_Shr32,
+ unop(Iop_64HIto32,
+ binop(Iop_And64,
+ mkexpr(t5),
+ mkexpr(t6))),
+ mkU8(31-rs))));
+
+ putIReg(rt, mkexpr(t7));
+ break;
+ }
+ case 0x3: { /* EXTPV */
+ DIP("extpv r%d, ac%d, r%d", rt, ac, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I1);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I8);
+ t5 = newTemp(Ity_I64);
+ t6 = newTemp(Ity_I64);
+ t7 = newTemp(Ity_I32);
+ t8 = newTemp(Ity_I32);
+
+ assign(t8, binop(Iop_And32, getIReg(rs), mkU32(0x1f)));
+ assign(t0, getAcc(ac));
+ /* Extract pos field of DSPControl register. */
+ assign(t1, binop(Iop_And32, getDSPControl(), mkU32(0x3f)));
+
+ /* Check if (pos - size) >= 0 [size <= pos]
+ if (pos < size)
+ put 1 to EFI field of DSPControl register
+ else
+ extract bits from acc and put 0 to EFI field of
+ DSPCtrl */
+ assign(t2, binop(Iop_CmpLT32U, mkexpr(t1), mkexpr(t8)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t2),
+ binop(Iop_Or32,
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xffffbfff)),
+ mkU32(0x4000)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xffffbfff))));
+
+ /* If pos <= 31, shift right the value from the acc
+ (pos-size) times and take (size+1) bits from the least
+ significant positions. Otherwise, shift left the value
+ (63-pos) times, take (size+1) bits from the most
+ significant positions and shift right (31-size)
+ times. */
+ assign(t3, binop(Iop_CmpLE32U, mkexpr(t1), mkU32(31)));
+
+ assign(t4,
+ IRExpr_ITE(mkexpr(t3),
+ unop(Iop_32to8,
+ binop(Iop_Sub32,
+ mkexpr(t1), mkexpr(t8))),
+ unop(Iop_32to8,
+ binop(Iop_Sub32,
+ mkU32(63), mkexpr(t1)))));
+
+ assign(t5, IRExpr_ITE(mkexpr(t3),
+ binop(Iop_Shr64,
+ mkexpr(t0), mkexpr(t4)),
+ binop(Iop_Shl64,
+ mkexpr(t0), mkexpr(t4))));
+
+ /* t6 holds a mask for bit extraction. */
+ assign(t6,
+ IRExpr_ITE(mkexpr(t3),
+ unop(Iop_Not64,
+ binop(Iop_Shl64,
+ mkU64(0xffffffffffffffffULL),
+ unop(Iop_32to8,
+ binop(Iop_Add32,
+ mkexpr(t8),
+ mkU32(1))))),
+ unop(Iop_Not64,
+ binop(Iop_Shr64,
+ mkU64(0xffffffffffffffffULL),
+ unop(Iop_32to8,
+ binop(Iop_Add32,
+ mkexpr(t8),
+ mkU32(1)))))));
+
+ assign(t7, IRExpr_ITE(mkexpr(t3),
+ unop(Iop_64to32,
+ binop(Iop_And64,
+ mkexpr(t5),
+ mkexpr(t6))),
+ binop(Iop_Shr32,
+ unop(Iop_64HIto32,
+ binop(Iop_And64,
+ mkexpr(t5),
+ mkexpr(t6))),
+ unop(Iop_32to8,
+ binop(Iop_Sub32,
+ mkU32(31),
+ mkexpr(t8))))));
+
+ putIReg(rt, mkexpr(t7));
+ break;
+ }
+ case 0x4: { /* EXTR_R.W */
+ DIP("extr_r.w r%d, ac%d, %d", rt, ac, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I32);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I64);
+ t6 = newTemp(Ity_I64);
+
+ assign(t0, getAcc(ac));
+ if (0 == rs) {
+ putIReg(rt, unop(Iop_64to32, mkexpr(t0)));
+ } else {
+ assign(t1, binop(Iop_Sar64, mkexpr(t0), mkU8(rs)));
+
+ assign(t2, binop(Iop_Or32,
+ getDSPControl(), mkU32(0x800000)));
+
+ putDSPControl(IRExpr_ITE(
+ binop(Iop_CmpNE32,
+ unop(Iop_64HIto32, mkexpr(t1)),
+ mkU32(0x0)),
+ IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_64HIto32,
+ mkexpr(t1)),
+ mkU32(0xffffffff)),
+ mkexpr(t2),
+ getDSPControl()),
+ getDSPControl()));
+
+ assign(t4, binop(Iop_Or32,
+ getDSPControl(), mkU32(0x800000)));
+ /* If the last discarded bit is 1, there would be carry
+ when rounding, otherwise there wouldn't. We use that
+ fact and just add the value of the last discarded bit
+ to the least sifgnificant bit of the shifted value
+ from acc. */
+ assign(t5, binop(Iop_Shr64,
+ binop(Iop_And64,
+ mkexpr(t0),
+ binop(Iop_Shl64,
+ mkU64(0x1ULL),
+ mkU8(rs-1))),
+ mkU8(rs-1)));
+
+ assign(t6, binop(Iop_Add64, mkexpr(t1), mkexpr(t5)));
+
+ putDSPControl(IRExpr_ITE(
+ binop(Iop_CmpNE32,
+ unop(Iop_64HIto32, mkexpr(t6)),
+ mkU32(0x0)),
+ IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_64HIto32,
+ mkexpr(t6)),
+ mkU32(0xffffffff)),
+ mkexpr(t4),
+ getDSPControl()),
+ getDSPControl()));
+ putIReg(rt, unop(Iop_64to32, mkexpr(t6)));
+ }
+ break;
+ }
+ case 0x5: { /* EXTRV_R.W */
+ DIP("extrv_r.w r%d, ac%d, r%d", rt, ac, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I32);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I64);
+ t6 = newTemp(Ity_I64);
+
+ assign(t0, getAcc(ac));
+
+ assign(t1, binop(Iop_Sar64,
+ mkexpr(t0),
+ unop(Iop_32to8,
+ binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x1f)))));
+
+ assign(t2, binop(Iop_Or32,
+ getDSPControl(), mkU32(0x00800000)));
+
+ putDSPControl(IRExpr_ITE(
+ binop(Iop_CmpNE32,
+ unop(Iop_64HIto32, mkexpr(t1)),
+ mkU32(0x0)),
+ IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_64HIto32,
+ mkexpr(t1)),
+ mkU32(0xffffffff)),
+ mkexpr(t2),
+ getDSPControl()),
+ getDSPControl()));
+
+ assign(t4, binop(Iop_Or32,
+ getDSPControl(), mkU32(0x00800000)));
+ /* If the last discarded bit is 1, there would be carry
+ when rounding, otherwise there wouldn't. We use that
+ fact and just add the value of the last discarded bit to
+ the least sifgnificant bit of the shifted value from
+ acc. */
+ assign(t5, binop(Iop_Shr64,
+ binop(Iop_And64,
+ mkexpr(t0),
+ binop(Iop_Shl64,
+ mkU64(0x1ULL),
+ unop(Iop_32to8,
+ binop(Iop_Sub32,
+ binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x1f)),
+ mkU32(0x1))))),
+ unop(Iop_32to8,
+ binop(Iop_Sub32,
+ binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x1f)),
+ mkU32(0x1)))));
+
+ assign(t6, binop(Iop_Add64, mkexpr(t1), mkexpr(t5)));
+
+ putDSPControl(IRExpr_ITE(
+ binop(Iop_CmpNE32,
+ unop(Iop_64HIto32, mkexpr(t6)),
+ mkU32(0x0)),
+ IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_64HIto32,
+ mkexpr(t6)),
+ mkU32(0xffffffff)),
+ mkexpr(t4),
+ getDSPControl()),
+ getDSPControl()));
+ putIReg(rt, IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x1f)),
+ mkU32(0x0)),
+ unop(Iop_64to32, mkexpr(t0)),
+ unop(Iop_64to32, mkexpr(t6))));
+ break;
+ }
+ case 0x6: { /* EXTR_RS.W */
+ DIP("extr_rs.w r%d, ac%d, %d", rt, ac, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I64);
+ t3 = newTemp(Ity_I32);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I32);
+ t6 = newTemp(Ity_I32);
+
+ if (0 != rs) {
+ assign(t0, getAcc(ac));
+ assign(t1, binop(Iop_Sar64, mkexpr(t0), mkU8(rs)));
+ putDSPControl(IRExpr_ITE(
+ binop(Iop_CmpNE32,
+ unop(Iop_64HIto32, mkexpr(t1)),
+ mkU32(0x0)),
+ IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_64HIto32,
+ mkexpr(t1)),
+ mkU32(0xffffffff)),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00800000)),
+ getDSPControl()),
+ getDSPControl()));
+ /* If the last discarded bit is 1, there would be carry
+ when rounding, otherwise there wouldn't. We use that
+ fact and just add the value of the last discarded bit
+ to the least sifgnificant bit of the shifted value
+ from acc. */
+ assign(t2, binop(Iop_Add64,
+ mkexpr(t1),
+ binop(Iop_Shr64,
+ binop(Iop_And64,
+ mkexpr(t0),
+ binop(Iop_Shl64,
+ mkU64(0x1ULL),
+ unop(Iop_32to8,
+ mkU32(rs-1)))),
+ unop(Iop_32to8, mkU32(rs-1)))));
+ assign(t6, IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_64HIto32,
+ mkexpr(t2)),
+ mkU32(0xffffffff)),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00800000)),
+ getDSPControl()));
+ putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_64HIto32,
+ mkexpr(t2)),
+ mkU32(0x0)),
+ mkexpr(t6),
+ getDSPControl()));
+ assign(t3, IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ unop(Iop_64HIto32,
+ mkexpr(t2)),
+ mkU32(0x80000000)),
+ mkU32(0x0)),
+ mkU32(0x7fffffff),
+ mkU32(0x80000000)));
+ assign(t4, IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_64HIto32,
+ mkexpr(t2)),
+ mkU32(0xffffffff)),
+ mkexpr(t3),
+ unop(Iop_64to32, mkexpr(t2))));
+ assign(t5, IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_64HIto32,
+ mkexpr(t2)),
+ mkU32(0x0)),
+ mkexpr(t4),
+ unop(Iop_64to32, mkexpr(t2))));
+ putIReg(rt, mkexpr(t5));
+ } else {
+ putIReg(rt, unop(Iop_64to32, getAcc(ac)));
+ }
+ break;
+ }
+ case 0x7: { /* EXTRV_RS.W */
+ DIP("extrv_rs.w r%d, ac%d, r%d", rt, ac, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I32);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I64);
+ t6 = newTemp(Ity_I64);
+ t7 = newTemp(Ity_I32);
+ t8 = newTemp(Ity_I32);
+ t9 = newTemp(Ity_I32);
+ t10 = newTemp(Ity_I32);
+
+ assign(t0, getAcc(ac));
+
+ assign(t1, binop(Iop_Sar64,
+ mkexpr(t0),
+ unop(Iop_32to8, binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x1f)))));
+
+ assign(t2, binop(Iop_Or32,
+ getDSPControl(), mkU32(0x00800000)));
+
+ assign(t10, IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_64HIto32,
+ mkexpr(t1)),
+ mkU32(0x0)),
+ IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_64HIto32,
+ mkexpr(t1)),
+ mkU32(0xffffffff)),
+ mkexpr(t2),
+ getDSPControl()),
+ getDSPControl()));
+
+ putDSPControl(mkexpr(t10));
+
+ assign(t4, binop(Iop_Or32,
+ getDSPControl(), mkU32(0x00800000)));
+ /* If the last discarded bit is 1, there would be carry
+ when rounding, otherwise there wouldn't. We use that
+ fact and just add the value of the last discarded bit to
+ the least sifgnificant bit of the shifted value from
+ acc. */
+ assign(t5, binop(Iop_Shr64,
+ binop(Iop_And64,
+ mkexpr(t0),
+ binop(Iop_Shl64,
+ mkU64(0x1ULL),
+ unop(Iop_32to8,
+ binop(Iop_Sub32,
+ binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x1f)),
+ mkU32(0x1))))),
+ unop(Iop_32to8,
+ binop(Iop_Sub32,
+ binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x1f)),
+ mkU32(0x1)))));
+
+ assign(t6, binop(Iop_Add64, mkexpr(t1), mkexpr(t5)));
+
+ assign(t8, IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_64HIto32,
+ mkexpr(t6)),
+ mkU32(0xffffffff)),
+ mkexpr(t4),
+ getDSPControl()));
+ putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_64HIto32,
+ mkexpr(t6)),
+ mkU32(0x0)),
+ mkexpr(t8),
+ getDSPControl()));
+ assign(t9, IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ unop(Iop_64HIto32,
+ mkexpr(t6)),
+ mkU32(0x80000000)),
+ mkU32(0x0)),
+ mkU32(0x7fffffff),
+ mkU32(0x80000000)));
+ assign(t7, IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_64HIto32, mkexpr(t6)),
+ mkU32(0x0)),
+ IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_64HIto32,
+ mkexpr(t6)),
+ mkU32(0xffffffff)),
+ mkexpr(t9),
+ unop(Iop_64to32,
+ mkexpr(t6))),
+ unop(Iop_64to32, mkexpr(t6))));
+ putIReg(rt, IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x1f)),
+ mkU32(0x0)),
+ unop(Iop_64to32, mkexpr(t0)),
+ mkexpr(t7)));
+ break;
+ }
+ case 0xA: { /* EXTPDP */
+ DIP("extpdp r%d, ac%d, %d", rt, ac, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I1);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I8);
+ t5 = newTemp(Ity_I64);
+ t6 = newTemp(Ity_I64);
+ t7 = newTemp(Ity_I32);
+ t8 = newTemp(Ity_I32);
+
+ assign(t0, getAcc(ac));
+ /* Extract pos field of DSPControl register. */
+ assign(t1, binop(Iop_And32, getDSPControl(), mkU32(0x3f)));
+
+ /* Check if (pos - size) >= 0 [size <= pos]
+ if (pos < size)
+ put 1 to EFI field of DSPControl register
+ else
+ extract bits from acc and put 0 to EFI field of
+ DSPCtrl */
+ assign(t2, binop(Iop_CmpLT32U, mkexpr(t1), mkU32(rs)));
+
+ assign(t8, binop(Iop_Or32,
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xffffbfc0)),
+ binop(Iop_And32,
+ binop(Iop_Sub32,
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0x3f)),
+ mkU32(rs+1)),
+ mkU32(0x3f))));
+ putDSPControl(IRExpr_ITE(mkexpr(t2),
+ binop(Iop_Or32,
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xffffbfff)),
+ mkU32(0x4000)),
+ mkexpr(t8)));
+
+ /* If pos <= 31, shift right the value from the acc
+ (pos-size) times and take (size+1) bits from the least
+ significant positions. Otherwise, shift left the value
+ (63-pos) times, take (size+1) bits from the most
+ significant positions and shift right (31-size) times.
+ */
+ assign(t3, binop(Iop_CmpLE32U, mkexpr(t1), mkU32(31)));
+
+ assign(t4,
+ IRExpr_ITE(mkexpr(t3),
+ unop(Iop_32to8,
+ binop(Iop_Sub32,
+ mkexpr(t1), mkU32(rs))),
+ unop(Iop_32to8,
+ binop(Iop_Sub32,
+ mkU32(63), mkexpr(t1)))));
+
+ assign(t5, IRExpr_ITE(mkexpr(t3),
+ binop(Iop_Shr64,
+ mkexpr(t0), mkexpr(t4)),
+ binop(Iop_Shl64,
+ mkexpr(t0), mkexpr(t4))));
+
+ /* t6 holds a mask for bit extraction. */
+ assign(t6,
+ IRExpr_ITE(mkexpr(t3),
+ unop(Iop_Not64,
+ binop(Iop_Shl64,
+ mkU64(0xffffffffffffffffULL),
+ mkU8(rs+1))),
+ unop(Iop_Not64,
+ binop(Iop_Shr64,
+ mkU64(0xffffffffffffffffULL),
+ mkU8(rs+1)))));
+
+ assign(t7, IRExpr_ITE(mkexpr(t3),
+ unop(Iop_64to32,
+ binop(Iop_And64,
+ mkexpr(t5),
+ mkexpr(t6))),
+ binop(Iop_Shr32,
+ unop(Iop_64HIto32,
+ binop(Iop_And64,
+ mkexpr(t5),
+ mkexpr(t6))),
+ mkU8(31-rs))));
+
+ putIReg(rt, mkexpr(t7));
+ break;
+ }
+ case 0xB: { /* EXTPDPV */
+ DIP("extpdpv r%d, ac%d, r%d", rt, ac, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I1);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I8);
+ t5 = newTemp(Ity_I64);
+ t6 = newTemp(Ity_I64);
+ t7 = newTemp(Ity_I32);
+ t8 = newTemp(Ity_I32);
+ t9 = newTemp(Ity_I32);
+
+ assign(t8, binop(Iop_And32, getIReg(rs), mkU32(0x1f)));
+ assign(t0, getAcc(ac));
+ /* Extract pos field of DSPControl register. */
+ assign(t1, binop(Iop_And32, getDSPControl(), mkU32(0x3f)));
+
+ /* Check if (pos - size) >= 0 [size <= pos]
+ if (pos < size)
+ put 1 to EFI field of DSPControl register
+ else
+ extract bits from acc and put 0 to EFI field of
+ DSPCtrl */
+ assign(t2, binop(Iop_CmpLT32U, mkexpr(t1), mkexpr(t8)));
+
+ assign(t9, binop(Iop_Or32,
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xffffbfc0)),
+ binop(Iop_And32,
+ binop(Iop_Sub32,
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0x3f)),
+ binop(Iop_Add32,
+ mkexpr(t8),
+ mkU32(0x1))),
+ mkU32(0x3f))));
+ putDSPControl(IRExpr_ITE(mkexpr(t2),
+ binop(Iop_Or32,
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xffffbfff)),
+ mkU32(0x4000)),
+ mkexpr(t9)));
+
+ /* If pos <= 31, shift right the value from the acc
+ (pos-size) times and take (size+1) bits from the least
+ significant positions. Otherwise, shift left the value
+ (63-pos) times, take (size+1) bits from the most
+ significant positions and shift right (31-size) times.
+ */
+ assign(t3, binop(Iop_CmpLE32U, mkexpr(t1), mkU32(31)));
+
+ assign(t4,
+ IRExpr_ITE(mkexpr(t3),
+ unop(Iop_32to8,
+ binop(Iop_Sub32,
+ mkexpr(t1), mkexpr(t8))),
+ unop(Iop_32to8,
+ binop(Iop_Sub32,
+ mkU32(63), mkexpr(t1)))));
+
+ assign(t5, IRExpr_ITE(mkexpr(t3),
+ binop(Iop_Shr64,
+ mkexpr(t0), mkexpr(t4)),
+ binop(Iop_Shl64,
+ mkexpr(t0), mkexpr(t4))));
+
+ /* t6 holds a mask for bit extraction. */
+ assign(t6,
+ IRExpr_ITE(mkexpr(t3),
+ unop(Iop_Not64,
+ binop(Iop_Shl64,
+ mkU64(0xffffffffffffffffULL),
+ unop(Iop_32to8,
+ binop(Iop_Add32,
+ mkexpr(t8),
+ mkU32(1))))),
+ unop(Iop_Not64,
+ binop(Iop_Shr64,
+ mkU64(0xffffffffffffffffULL),
+ unop(Iop_32to8,
+ binop(Iop_Add32,
+ mkexpr(t8),
+ mkU32(1)))))));
+
+ assign(t7, IRExpr_ITE(mkexpr(t3),
+ unop(Iop_64to32,
+ binop(Iop_And64,
+ mkexpr(t5),
+ mkexpr(t6))),
+ binop(Iop_Shr32,
+ unop(Iop_64HIto32,
+ binop(Iop_And64,
+ mkexpr(t5),
+ mkexpr(t6))),
+ unop(Iop_32to8,
+ binop(Iop_Sub32,
+ mkU32(31),
+ mkexpr(t8))))));
+
+ putIReg(rt, mkexpr(t7));
+ break;
+ }
+ case 0xE: { /* EXTR_S.H */
+ DIP("extr_s.h r%d, ac%d, %d", rt, ac, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I64);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I32);
+ t6 = newTemp(Ity_I64);
+ t7 = newTemp(Ity_I32);
+ t8 = newTemp(Ity_I32);
+ t9 = newTemp(Ity_I32);
+ t10 = newTemp(Ity_I1);
+
+ assign(t0, getAcc(ac));
+
+ assign(t1, binop(Iop_Sar64, mkexpr(t0), mkU8(rs)));
+
+ assign(t2, binop(Iop_Or32,
+ getDSPControl(), mkU32(0x00800000)));
+
+ assign(t9, binop(Iop_Shl32,
+ binop(Iop_And32,
+ unop(Iop_64to32,
+ mkexpr(t1)),
+ mkU32(0x00008000)),
+ mkU8(16)));
+ putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
+ mkexpr(t9),
+ binop(Iop_And32,
+ unop(Iop_64HIto32,
+ mkexpr(t0)),
+ mkU32(0x80000000))),
+ mkexpr(t2),
+ getDSPControl()));
+
+ /* Check if t1 > 0x7fff ((t1 - 0x7fff) > 0)
+ 1. subtract 0x7fff from t1
+ 2. if the resulting number is positive (sign bit = 0)
+ and any of the other bits is 1, the value is > 0. */
+ assign(t3, binop(Iop_Sub64,
+ mkexpr(t1),
+ mkU64(0x0000000000007fffULL)));
+ assign(t4, binop(Iop_Or32,
+ unop(Iop_1Uto32,
+ binop(Iop_CmpNE32,
+ mkU32(0),
+ binop(Iop_And32,
+ unop(Iop_64HIto32,
+ mkexpr(t3)),
+ mkU32(0x7fffffff)))),
+ unop(Iop_1Uto32,
+ binop(Iop_CmpNE32,
+ mkU32(0),
+ binop(Iop_And32,
+ unop(Iop_64to32,
+ mkexpr(t3)),
+ mkU32(0xffffffff))))));
+
+ assign(t5, IRExpr_ITE(unop(Iop_32to1,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ unop(Iop_64HIto32,
+ mkexpr(t3)),
+ mkU32(0x80000000)),
+ mkU8(31))),
+ unop(Iop_64to32, mkexpr(t1)),
+ IRExpr_ITE(binop(Iop_CmpNE32,
+ mkexpr(t4),
+ mkU32(0x0)),
+ mkU32(0x7fff),
+ unop(Iop_64to32,
+ mkexpr(t1)))));
+
+ assign(t10, unop(Iop_32to1,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ unop(Iop_64HIto32,
+ mkexpr(t3)),
+ mkU32(0x80000000)),
+ mkU8(31))));
+ putDSPControl(IRExpr_ITE(mkexpr(t10),
+ getDSPControl(),
+ IRExpr_ITE(binop(Iop_CmpNE32,
+ mkexpr(t4),
+ mkU32(0x0)),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00800000)),
+ getDSPControl())));
+
+ /* Check if t1<0xffffffffffff8000 (0xffffffffffff8000-t1)>0
+ 1. subtract t1 from 0x7fff
+ 2. if the resulting number is positive (sign bit = 0)
+ and any of the other bits is 1, the value is > 0 */
+ assign(t6, binop(Iop_Sub64,
+ mkU64(0xffffffffffff8000ULL),
+ mkexpr(t1)));
+
+ assign(t7, binop(Iop_Or32,
+ unop(Iop_1Uto32,
+ binop(Iop_CmpNE32,
+ mkU32(0),
+ binop(Iop_And32,
+ unop(Iop_64HIto32,
+ mkexpr(t6)),
+ mkU32(0x7fffffff)))),
+ unop(Iop_1Uto32,
+ binop(Iop_CmpNE32,
+ mkU32(0),
+ binop(Iop_And32,
+ unop(Iop_64to32,
+ mkexpr(t6)),
+ mkU32(0xffffffff))))));
+
+ assign(t8, IRExpr_ITE(unop(Iop_32to1,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ unop(Iop_64HIto32,
+ mkexpr(t6)),
+ mkU32(0x80000000)),
+ mkU8(31))),
+ unop(Iop_64to32, mkexpr(t1)),
+ IRExpr_ITE(binop(Iop_CmpNE32,
+ mkexpr(t7),
+ mkU32(0x0)),
+ mkU32(0xffff8000),
+ unop(Iop_64to32,
+ mkexpr(t1)))));
+ putDSPControl(IRExpr_ITE(unop(Iop_32to1,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ unop(Iop_64HIto32,
+ mkexpr(t6)),
+ mkU32(0x80000000)),
+ mkU8(31))),
+ getDSPControl(),
+ IRExpr_ITE(binop(Iop_CmpNE32,
+ mkexpr(t7),
+ mkU32(0x0)),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00800000)),
+ getDSPControl())));
+
+ /* If the shifted value is positive, it can only be >0x7fff
+ and the final result is the value stored in t5,
+ otherwise, the final result is in t8. */
+ putIReg(rt, IRExpr_ITE(unop(Iop_32to1,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ unop(Iop_64HIto32,
+ mkexpr(t1)),
+ mkU32(0x80000000)),
+ mkU8(31))),
+ mkexpr(t8),
+ mkexpr(t5)));
+ break;
+ }
+ case 0xF: { /* EXTRV_S.H */
+ DIP("extrv_s.h r%d, ac%d, %d", rt, ac, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I64);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I32);
+ t6 = newTemp(Ity_I64);
+ t7 = newTemp(Ity_I32);
+ t8 = newTemp(Ity_I32);
+ t9 = newTemp(Ity_I32);
+ t10 = newTemp(Ity_I32);
+ t11 = newTemp(Ity_I32);
+
+ assign(t0, getAcc(ac));
+
+ assign(t1, binop(Iop_Sar64,
+ mkexpr(t0),
+ unop(Iop_32to8,
+ binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x1f)))));
+
+ assign(t2, binop(Iop_Or32,
+ getDSPControl(), mkU32(0x00800000)));
+
+ assign(t9, binop(Iop_Shl32,
+ binop(Iop_And32,
+ unop(Iop_64to32,
+ mkexpr(t1)),
+ mkU32(0x00008000)),
+ mkU8(16)));
+ putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
+ mkexpr(t9),
+ binop(Iop_And32,
+ unop(Iop_64HIto32,
+ mkexpr(t0)),
+ mkU32(0x80000000))),
+ mkexpr(t2),
+ getDSPControl()));
+
+ /* Check if t1 > 0x7fff ((t1 - 0x7fff) > 0)
+ 1. subtract 0x7fff from t1
+ 2. if the resulting number is positive (sign bit = 0)
+ and any of the other bits is 1, the value is > 0 */
+ assign(t3, binop(Iop_Sub64,
+ mkexpr(t1),
+ mkU64(0x0000000000007fffULL)));
+ assign(t4, binop(Iop_Or32,
+ unop(Iop_1Uto32,
+ binop(Iop_CmpNE32,
+ mkU32(0),
+ binop(Iop_And32,
+ unop(Iop_64HIto32,
+ mkexpr(t3)),
+ mkU32(0x7fffffff)))),
+ unop(Iop_1Uto32,
+ binop(Iop_CmpNE32,
+ mkU32(0),
+ binop(Iop_And32,
+ unop(Iop_64to32,
+ mkexpr(t3)),
+ mkU32(0xffffffff))))));
+
+ assign(t5, IRExpr_ITE(unop(Iop_32to1,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ unop(Iop_64HIto32,
+ mkexpr(t3)),
+ mkU32(0x80000000)),
+ mkU8(31))),
+ unop(Iop_64to32, mkexpr(t1)),
+ IRExpr_ITE(binop(Iop_CmpNE32,
+ mkexpr(t4),
+ mkU32(0x0)),
+ mkU32(0x7fff),
+ unop(Iop_64to32,
+ mkexpr(t1)))));
+
+ assign(t10, binop(Iop_Shr32,
+ binop(Iop_And32,
+ unop(Iop_64HIto32,
+ mkexpr(t3)),
+ mkU32(0x80000000)),
+ mkU8(31)));
+ assign(t11, IRExpr_ITE(binop(Iop_CmpNE32,
+ mkexpr(t4),
+ mkU32(0x0)),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00800000)),
+ getDSPControl()));
+ putDSPControl(IRExpr_ITE(unop(Iop_32to1,
+ mkexpr(t10)),
+ getDSPControl(),
+ mkexpr(t11)));
+
+ /* Check if t1<0xffffffffffff8000
+ 1. subtract t1 from 0x7fff
+ 2. if the resulting number is positive (sign bit == 0)
+ and any of the other bits is 1, the value is > 0 */
+ assign(t6, binop(Iop_Sub64,
+ mkU64(0xffffffffffff8000ULL),
+ mkexpr(t1)));
+
+ assign(t7, binop(Iop_Or32,
+ unop(Iop_1Uto32,
+ binop(Iop_CmpNE32,
+ mkU32(0),
+ binop(Iop_And32,
+ unop(Iop_64HIto32,
+ mkexpr(t6)),
+ mkU32(0x7fffffff)))),
+ unop(Iop_1Uto32,
+ binop(Iop_CmpNE32,
+ mkU32(0),
+ binop(Iop_And32,
+ unop(Iop_64to32,
+ mkexpr(t6)),
+ mkU32(0xffffffff))))));
+
+ assign(t8, IRExpr_ITE(unop(Iop_32to1,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ unop(Iop_64HIto32,
+ mkexpr(t6)),
+ mkU32(0x80000000)),
+ mkU8(31))),
+ unop(Iop_64to32, mkexpr(t1)),
+ IRExpr_ITE(binop(Iop_CmpNE32,
+ mkexpr(t7),
+ mkU32(0x0)),
+ mkU32(0xffff8000),
+ unop(Iop_64to32,
+ mkexpr(t1)))));
+ putDSPControl(IRExpr_ITE(unop(Iop_32to1,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ unop(Iop_64HIto32,
+ mkexpr(t6)),
+ mkU32(0x80000000)
+ ),
+ mkU8(31))),
+ getDSPControl(),
+ IRExpr_ITE(binop(Iop_CmpNE32,
+ mkexpr(t7),
+ mkU32(0x0)),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00800000)
+ ),
+ getDSPControl())));
+
+ /* If the shifted value is positive, it can only be >0x7fff
+ and the final result is the value stored in t5,
+ otherwise, the final result is in t8. */
+ putIReg(rt, IRExpr_ITE(unop(Iop_32to1,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ unop(Iop_64HIto32,
+ mkexpr(t1)),
+ mkU32(0x80000000)),
+ mkU8(31))),
+ mkexpr(t8),
+ mkexpr(t5)));
+ break;
+ }
+ case 0x12: { /* RDDSP*/
+ DIP("rddsp r%d, mask 0x%x", rd, rddsp_mask);
+ vassert(!mode64);
+
+ putIReg(rd, mkU32(0x0));
+
+ if ((rddsp_mask & 0b000001) == 0b000001) {
+ /* Read pos field (bits 5-0) of DSPControl register. */
+ putIReg(rd, binop(Iop_Or32,
+ getIReg(rd),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0x0000003F))));
+ }
+
+ if ((rddsp_mask & 0b000010) == 0b000010) {
+ /* Read scount field (bits 12-7) of DSPControl
+ register. */
+ putIReg(rd, binop(Iop_Or32,
+ getIReg(rd),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0x00001F80))));
+ }
+
+ if ((rddsp_mask & 0b000100) == 0b000100) {
+ /* Read C field (bit 13) of DSPControl register. */
+ putIReg(rd, binop(Iop_Or32,
+ getIReg(rd),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0x00002000))));
+ }
+
+ if ((rddsp_mask & 0b001000) == 0b001000) {
+ /* Read outflag field (bit s 23-16) of DSPControl
+ register. */
+ putIReg(rd, binop(Iop_Or32,
+ getIReg(rd),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0x00FF0000))));
+ }
+
+ if ((rddsp_mask & 0b010000) == 0b010000) {
+ /* Read ccond field (bits 31-24) of DSPControl
+ register. */
+ putIReg(rd, binop(Iop_Or32,
+ getIReg(rd),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xFF000000))));
+ }
+
+ if ((rddsp_mask & 0b100000) == 0b100000) {
+ /* Read EFI field (bit 14) of DSPControl register. */
+ putIReg(rd, binop(Iop_Or32,
+ getIReg(rd),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0x00004000))));
+ }
+
+ if ((rddsp_mask & 0b111111) == 0b111111) {
+ /* Read all fields of DSPControl register. */
+ putIReg(rd, getDSPControl());
+ }
+ break;
+ }
+ case 0x13: { /* WRDSP */
+ DIP("wrdsp r%d, mask 0x%x", rs, wrdsp_mask);
+ vassert(!mode64);
+
+ if ((wrdsp_mask & 0b111111) == 0b111111) {
+ /* If mips64 put all fields of rs, except bit 15 and bit
+ 6, to DSPControl register, otherwise put all except
+ bits 15, 6 and bits 31..28. */
+ putDSPControl(mode64 ?
+ binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0xffff7fbf)) :
+ binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x0fff7fbf)));
+ } else {
+ if ((wrdsp_mask & 0b000001) == 0b000001) {
+ /* Put bits 5-0 of rs to DSPControl register pos
+ field. */
+ putDSPControl(binop(Iop_Or32,
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xFFFF7F40)),
+ binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x0000003F))));
+ }
+
+ if ((wrdsp_mask & 0b000010) == 0b000010) {
+ /* Put bits 12-7 of rs to DSPControl scount field. */
+ putDSPControl(binop(Iop_Or32,
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xFFFFE03F)),
+ binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x00001F80))));
+ }
+
+ if ((wrdsp_mask & 0b000100) == 0b000100) {
+ /* Put bit 13 of rs to DSPControl register C
+ field. */
+ putDSPControl(binop(Iop_Or32,
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xFFFF5FBF)),
+ binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x00002000))));
+ }
+
+ if ((wrdsp_mask & 0b001000) == 0b001000) {
+ /* Put bits 23-16 of rs to DSPControl reg outflag
+ field. */
+ putDSPControl(binop(Iop_Or32,
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xFF007FBF)),
+ binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x00FF0000))));
+ }
+
+ if ((wrdsp_mask & 0b010000) == 0b010000) {
+ /* Put bits 31-24 of rs to DSPControl reg ccond
+ field. */
+ putDSPControl(binop(Iop_Or32,
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0x00FF7FBF)),
+ binop(Iop_And32,
+ getIReg(rs),
+ mode64 ? mkU32(0xFF000000)
+ : mkU32(0x0F000000))
+ )
+ );
+ }
+
+ if ((wrdsp_mask & 0b100000) == 0b100000) {
+ /* Put bit 14 of rs to DSPControl register EFI
+ field. */
+ putDSPControl(binop(Iop_Or32,
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xFFFF3FBF)),
+ binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x00004000))));
+ }
+ }
+ break;
+ }
+ case 0x1A: { /* SHILO */
+ DIP("shilo ac%d, %d", ac, shift);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I64);
+
+ assign(t0, getAcc(ac));
+
+ putAcc(ac, mkexpr(t0));
+
+ if (0b100000 == (shift & 0x3f)) {
+ putAcc(ac, binop(Iop_32HLto64,
+ unop(Iop_64to32, mkexpr(t0)),
+ mkU32(0x0)));
+ } else if (0b100000 == (shift & 0x20)) {
+ assign(t1, binop(Iop_Shl64,
+ mkexpr(t0),
+ unop(Iop_32to8,
+ binop(Iop_Add32,
+ unop(Iop_Not32,
+ mkU32(shift)),
+ mkU32(0x1)))));
+
+ putAcc(ac, mkexpr(t1));
+ } else {
+ assign(t1, binop(Iop_Shr64, mkexpr(t0), mkU8(shift)));
+
+ putAcc(ac, mkexpr(t1));
+ }
+ break;
+ }
+ case 0x1B: { /* SHILOV */
+ DIP("shilov ac%d, r%d", ac, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I64);
+ t5 = newTemp(Ity_I64);
+
+ assign(t0, getAcc(ac));
+ assign(t2, binop(Iop_And32, getIReg(rs), mkU32(0x3f)));
+ assign(t3, binop(Iop_CmpEQ32, mkexpr(t2), mkU32(0x20)));
+
+ assign(t4, binop(Iop_Shl64,
+ mkexpr(t0),
+ unop(Iop_32to8,
+ binop(Iop_Add32,
+ unop(Iop_Not32,
+ mkexpr(t2)),
+ mkU32(0x1)))));
+ assign(t5, binop(Iop_Shr64,
+ mkexpr(t0),
+ unop(Iop_32to8,
+ mkexpr(t2))));
+ putAcc(ac, IRExpr_ITE(mkexpr(t3),
+ binop(Iop_32HLto64,
+ unop(Iop_64to32, mkexpr(t0)),
+ mkU32(0x0)),
+ IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkexpr(t2),
+ mkU32(0x20)),
+ mkU32(0x20)),
+ mkexpr(t4),
+ mkexpr(t5))));
+ break;
+ }
+ case 0x1F: { /* MTHLIP */
+ DIP("mthlip r%d, ac%d", rs, ac);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I1);
+
+ assign(t0, getAcc(ac));
+ putAcc(ac, binop(Iop_32HLto64,
+ unop(Iop_64to32, mkexpr(t0)),
+ getIReg(rs)));
+ assign(t1, binop(Iop_And32, getDSPControl(), mkU32(0x3f)));
+ putDSPControl(IRExpr_ITE(binop(Iop_CmpLE32U,
+ mkU32(32),
+ mkexpr(t1)),
+ binop(Iop_Or32,
+ binop(Iop_Sub32,
+ mkexpr(t1),
+ mkU32(32)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xffffffc0))),
+ binop(Iop_Or32,
+ binop(Iop_Add32,
+ mkexpr(t1),
+ mkU32(32)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xffffffc0)))));
+ break;
+ }
+ default:
+ return -1;
+ }
+ break; /* end of EXTR.W */
+ }
+ case 0xA: { /* LX */
+ switch(sa) {
+ case 0x0: { /* LWX */
+ DIP("lwx r%d, r%d(r%d)", rd, rt, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+
+ assign(t0, binop(Iop_Add32, getIReg(rt), getIReg(rs)));
+
+ putIReg(rd, load(Ity_I32, mkexpr(t0)));
+ break;
+ }
+ case 0x4: { /* LHX */
+ DIP("lhx r%d, r%d(r%d)", rd, rt, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+
+ assign(t0, binop(Iop_Add32, getIReg(rt), getIReg(rs)));
+
+ putIReg(rd, unop(Iop_16Sto32, load(Ity_I16, mkexpr(t0))));
+ break;
+ }
+ case 0x6: { /* LBUX */
+ DIP("lbux r%d, r%d(r%d)", rd, rt, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+
+ assign(t0, binop(Iop_Add32, getIReg(rt), getIReg(rs)));
+
+ putIReg(rd, unop(Iop_8Uto32, load(Ity_I8, mkexpr(t0))));
+ break;
+ }
+ default:
+ return -1;
+ }
+ break; /* end of LX */
+ }
+ case 0xC: { /* INSV */
+ switch(sa) {
+ case 0x0: { /* INSV */
+ DIP("insv r%d, r%d", rt, rs);
+ vassert(!mode64);
+
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I8);
+ t3 = newTemp(Ity_I8);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I1);
+ t6 = newTemp(Ity_I32);
+ t7 = newTemp(Ity_I32);
+ t8 = newTemp(Ity_I32);
+ t9 = newTemp(Ity_I32);
+
+ /* t0 <- pos field of DSPControl register. */
+ assign(t0, binop(Iop_And32, getDSPControl(), mkU32(0x3f)));
+ /* t1 <- scount field of DSPControl register. */
+ assign(t1, binop(Iop_Shr32,
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0x1f80)),
+ mkU8(7)));
+
+ assign(t2, unop(Iop_32to8,
+ binop(Iop_Add32,
+ mkexpr(t1),
+ mkexpr(t0))));
+
+ /* 32-(pos+size) most significant bits of rt. */
+ assign(t6, binop(Iop_Shl32,
+ binop(Iop_Shr32,
+ getIReg(rt),
+ mkexpr(t2)),
+ mkexpr(t2)));
+
+ assign(t3, unop(Iop_32to8,
+ binop(Iop_Sub32,
+ mkU32(32),
+ mkexpr(t0))));
+ /* Pos least significant bits of rt. */
+ assign(t7, binop(Iop_Shr32,
+ binop(Iop_Shl32,
+ getIReg(rt),
+ mkexpr(t3)),
+ mkexpr(t3)));
+
+ /* Size least significant bits of rs,
+ shifted to appropriate position. */
+ assign(t8, binop(Iop_Shl32,
+ binop(Iop_And32,
+ getIReg(rs),
+ unop(Iop_Not32,
+ binop(Iop_Shl32,
+ mkU32(0xffffffff),
+ unop(Iop_32to8,
+ mkexpr(t1))))),
+ unop(Iop_32to8,
+ mkexpr(t0))));
+
+ putIReg(rt, IRExpr_ITE(binop(Iop_CmpEQ32,
+ mkexpr(t0),
+ mkU32(0)),
+ IRExpr_ITE(binop(Iop_CmpEQ32,
+ mkexpr(t1),
+ mkU32(32)),
+ getIReg(rs),
+ binop(Iop_Or32,
+ mkexpr(t6),
+ mkexpr(t8))),
+ IRExpr_ITE(binop(Iop_CmpEQ32,
+ unop(Iop_8Uto32,
+ mkexpr(t2)),
+ mkU32(32)),
+ binop(Iop_Or32,
+ mkexpr(t7),
+ mkexpr(t8)),
+ binop(Iop_Or32,
+ binop(Iop_Or32,
+ mkexpr(t6),
+ mkexpr(t7)),
+ mkexpr(t8)))));
+ break;
+ }
+ default:
+ return -1;
+ }
+ break; /* enf of INSV */
+ }
+ case 0x10: { /* ADDU.QB */
+ switch(sa) {
+ case 0x00: { /* ADDU.QB */
+ DIP("addu.qb r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I1);
+ t6 = newTemp(Ity_I32);
+ t7 = newTemp(Ity_I1);
+ t8 = newTemp(Ity_I32);
+
+ /* Add rightmost bytes of rs and rt. */
+ assign(t0,
+ binop(Iop_Add32,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16, getIReg(rt))))));
+ /* t1 will be 1 if there is overflow, 0 otherwise. */
+ assign(t1, binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkexpr(t0),
+ mkU32(0x00000100)),
+ mkU32(0x00000100)));
+
+ /* Add bits 15-8 of rs and rt. */
+ assign(t2,
+ binop(Iop_Add32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, getIReg(rt))))));
+ /* t3 will be 1 if there is overflow, 0 otherwise. */
+ assign(t3, binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkexpr(t2),
+ mkU32(0x00000100)),
+ mkU32(0x00000100)));
+
+ /* Add bits 15-8 of rs and rt. */
+ assign(t4,
+ binop(Iop_Add32,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16, getIReg(rt))))));
+ /* t5 will be 1 if there is overflow, 0 otherwise. */
+ assign(t5, binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkexpr(t4),
+ mkU32(0x00000100)),
+ mkU32(0x00000100)));
+
+ /* Add bits 15-8 of rs and rt. */
+ assign(t6,
+ binop(Iop_Add32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16, getIReg(rt))))));
+ /* t7 will be 1 if there is overflow, 0 otherwise. */
+ assign(t7, binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkexpr(t6),
+ mkU32(0x00000100)),
+ mkU32(0x00000100)));
+
+ assign(t8,
+ binop(Iop_Or32,
+ binop(Iop_Or32,
+ binop(Iop_Or32,
+ unop(Iop_1Sto32, mkexpr(t7)),
+ unop(Iop_1Sto32, mkexpr(t5))),
+ unop(Iop_1Sto32, mkexpr(t3))),
+ unop(Iop_1Sto32, mkexpr(t1))));
+
+ putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32,
+ mkexpr(t8),
+ mkU32(0x0)),
+ getDSPControl(),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00100000))));
+
+ putIReg(rd, binop(Iop_16HLto32,
+ binop(Iop_8HLto16,
+ unop(Iop_32to8, mkexpr(t6)),
+ unop(Iop_32to8, mkexpr(t4))),
+ binop(Iop_8HLto16,
+ unop(Iop_32to8, mkexpr(t2)),
+ unop(Iop_32to8, mkexpr(t0)))));
+ break;
+ }
+ case 0x1: { /* SUBU.QB */
+ DIP("subu.qb r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I1);
+ t6 = newTemp(Ity_I32);
+ t7 = newTemp(Ity_I1);
+ t8 = newTemp(Ity_I32);
+
+ /* Subtract rightmost bytes of rs and rt. */
+ assign(t0,
+ binop(Iop_Sub32,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16, getIReg(rt))))));
+ /* t1 will be 1 if there is overflow, 0 otherwise. */
+ assign(t1, binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkexpr(t0),
+ mkU32(0x00000100)),
+ mkU32(0x00000100)));
+
+ /* Subtract bits 15-8 of rs and rt. */
+ assign(t2,
+ binop(Iop_Sub32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, getIReg(rt))))));
+ /* t3 will be 1 if there is overflow, 0 otherwise. */
+ assign(t3, binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkexpr(t2),
+ mkU32(0x00000100)),
+ mkU32(0x00000100)));
+
+ /* Subtract bits 15-8 of rs and rt. */
+ assign(t4,
+ binop(Iop_Sub32,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16, getIReg(rt))))));
+ /* t5 will be 1 if there is overflow, 0 otherwise. */
+ assign(t5, binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkexpr(t4),
+ mkU32(0x00000100)),
+ mkU32(0x00000100)));
+
+ /* Subtract bits 15-8 of rs and rt. */
+ assign(t6,
+ binop(Iop_Sub32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16, getIReg(rt))))));
+ /* t7 will be 1 if there is overflow, 0 otherwise. */
+ assign(t7, binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkexpr(t6),
+ mkU32(0x00000100)),
+ mkU32(0x00000100)));
+
+ assign(t8, binop(Iop_Or32,
+ binop(Iop_Or32,
+ binop(Iop_Or32,
+ unop(Iop_1Sto32, mkexpr(t7)),
+ unop(Iop_1Sto32, mkexpr(t5))),
+ unop(Iop_1Sto32, mkexpr(t3))),
+ unop(Iop_1Sto32, mkexpr(t1))));
+
+ putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32,
+ mkexpr(t8),
+ mkU32(0x0)),
+ getDSPControl(),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00100000))));
+
+ putIReg(rd, binop(Iop_16HLto32,
+ binop(Iop_8HLto16,
+ unop(Iop_32to8, mkexpr(t6)),
+ unop(Iop_32to8, mkexpr(t4))),
+ binop(Iop_8HLto16,
+ unop(Iop_32to8, mkexpr(t2)),
+ unop(Iop_32to8, mkexpr(t0)))));
+ break;
+ }
+ case 0x04: { /* ADDU_S.QB */
+ DIP("addu_s.qb r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I8);
+ t3 = newTemp(Ity_I32);
+ t4 = newTemp(Ity_I1);
+ t5 = newTemp(Ity_I8);
+ t6 = newTemp(Ity_I32);
+ t7 = newTemp(Ity_I1);
+ t8 = newTemp(Ity_I8);
+ t9 = newTemp(Ity_I32);
+ t10 = newTemp(Ity_I1);
+ t11 = newTemp(Ity_I8);
+ t12 = newTemp(Ity_I32);
+
+ /* Add rightmost bytes of rs and rt. */
+ assign(t0,
+ binop(Iop_Add32,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16, getIReg(rt))))));
+ /* t1 will be 1 if there is overflow, 0 otherwise. */
+ assign(t1, binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkexpr(t0),
+ mkU32(0x00000100)),
+ mkU32(0x00000100)));
+ /* Saturate if necessary. */
+ assign(t2, IRExpr_ITE(mkexpr(t1),
+ mkU8(0xff),
+ unop(Iop_32to8, mkexpr(t0))));
+
+ /* Add bits 15-8 of rs and rt. */
+ assign(t3,
+ binop(Iop_Add32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, getIReg(rt))))));
+ /* t4 will be 1 if there is overflow, 0 otherwise. */
+ assign(t4, binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkexpr(t3),
+ mkU32(0x00000100)),
+ mkU32(0x00000100)));
+ /* Saturate if necessary. */
+ assign(t5, IRExpr_ITE(mkexpr(t4),
+ mkU8(0xff),
+ unop(Iop_32to8, mkexpr(t3))));
+
+ /* Add bits 15-8 of rs and rt. */
+ assign(t6,
+ binop(Iop_Add32,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16, getIReg(rt))))));
+ /* t7 will be 1 if there is overflow, 0 otherwise. */
+ assign(t7, binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkexpr(t6),
+ mkU32(0x00000100)),
+ mkU32(0x00000100)));
+ /* Saturate if necessary. */
+ assign(t8, IRExpr_ITE(mkexpr(t7),
+ mkU8(0xff),
+ unop(Iop_32to8, mkexpr(t6))));
+
+ /* Add bits 15-8 of rs and rt. */
+ assign(t9,
+ binop(Iop_Add32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16, getIReg(rt))))));
+ /* t10 will be 1 if there is overflow, 0 otherwise. */
+ assign(t10, binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkexpr(t9),
+ mkU32(0x00000100)),
+ mkU32(0x00000100)));
+ /* Saturate if necessary. */
+ assign(t11, IRExpr_ITE(mkexpr(t10),
+ mkU8(0xff),
+ unop(Iop_32to8, mkexpr(t9))));
+
+ assign(t12,
+ binop(Iop_Or32,
+ binop(Iop_Or32,
+ binop(Iop_Or32,
+ unop(Iop_1Sto32, mkexpr(t10)),
+ unop(Iop_1Sto32, mkexpr(t7))),
+ unop(Iop_1Sto32, mkexpr(t4))),
+ unop(Iop_1Sto32, mkexpr(t1))));
+
+ putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32,
+ mkexpr(t12),
+ mkU32(0x0)),
+ getDSPControl(),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00100000))));
+
+ putIReg(rd,
+ binop(Iop_16HLto32,
+ binop(Iop_8HLto16, mkexpr(t11), mkexpr(t8)),
+ binop(Iop_8HLto16, mkexpr(t5), mkexpr(t2))));
+ break;
+ }
+ case 0x05: { /* SUBU_S.QB */
+ DIP("subu_s.qb r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I1);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I1);
+ t5 = newTemp(Ity_I1);
+ t6 = newTemp(Ity_I32);
+ t7 = newTemp(Ity_I32);
+ t8 = newTemp(Ity_I32);
+ t9 = newTemp(Ity_I32);
+
+ /* Use C function to easily calculate the result
+ and write it in the register more conveniently
+ Underflow is checked using step by step subtraction. */
+ assign(t1, binop(Iop_QSub8Ux4, getIReg(rs), getIReg(rt)));
+
+ /* Subtract each byte of rs and rt. */
+ assign(t6,
+ binop(Iop_Sub32,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16, getIReg(rt))))));
+ assign(t7,
+ binop(Iop_Sub32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, getIReg(rt))))));
+ assign(t8,
+ binop(Iop_Sub32,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16, getIReg(rt))))));
+ assign(t9,
+ binop(Iop_Sub32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16, getIReg(rt))))));
+
+ /* Put 1 to bit 20 in DSPControl if there is underflow
+ in either byte. */
+ assign(t2, binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkexpr(t6),
+ mkU32(0x00000100)),
+ mkU32(0x00000100)));
+ putDSPControl(IRExpr_ITE(mkexpr(t2),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00100000)),
+ getDSPControl()));
+ assign(t3, binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkexpr(t7),
+ mkU32(0x00000100)),
+ mkU32(0x00000100)));
+ putDSPControl(IRExpr_ITE(mkexpr(t3),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00100000)),
+ getDSPControl()));
+ assign(t4, binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkexpr(t8),
+ mkU32(0x00000100)),
+ mkU32(0x00000100)));
+ putDSPControl(IRExpr_ITE(mkexpr(t4),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00100000)),
+ getDSPControl()));
+ assign(t5, binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkexpr(t9),
+ mkU32(0x00000100)),
+ mkU32(0x00000100)));
+ putDSPControl(IRExpr_ITE(mkexpr(t5),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00100000)),
+ getDSPControl()));
+ putIReg(rd, mkexpr(t1));
+ break;
+ }
+ case 0x6: { /* MULEU_S.PH.QBL */
+ DIP("muleu_s.ph.qbl r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I1);
+ t3 = newTemp(Ity_I1);
+
+ assign(t0,
+ unop(Iop_64to32,
+ binop(Iop_MullU32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ getIReg(rs)))),
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16, getIReg(rt))))));
+ assign(t1,
+ unop(Iop_64to32,
+ binop(Iop_MullU32,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16,
+ getIReg(rs)))),
+ unop(Iop_16Uto32,
+ unop(Iop_32to16, getIReg(rt))))));
+
+ assign(t2, binop(Iop_CmpNE32,
+ mkU32(0x0),
+ binop(Iop_And32,
+ mkexpr(t0),
+ mkU32(0x03ff0000))));
+ assign(t3, binop(Iop_CmpNE32,
+ mkU32(0x0),
+ binop(Iop_And32,
+ mkexpr(t1),
+ mkU32(0x03ff0000))));
+ putDSPControl(IRExpr_ITE(mkexpr(t2),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x200000)),
+ IRExpr_ITE(mkexpr(t3),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x200000)),
+ getDSPControl())));
+ putIReg(rd,
+ binop(Iop_16HLto32,
+ IRExpr_ITE(mkexpr(t2),
+ mkU16(0xffff),
+ unop(Iop_32to16, mkexpr(t0))),
+ IRExpr_ITE(mkexpr(t3),
+ mkU16(0xffff),
+ unop(Iop_32to16, mkexpr(t1)))));
+ break;
+ }
+ case 0x7: { /* MULEU_S.PH.QBR */
+ DIP("muleu_s.ph.qbr r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I1);
+ t3 = newTemp(Ity_I1);
+
+ assign(t0, unop(Iop_64to32,
+ binop(Iop_MullU32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ getIReg(rs)))),
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16,
+ getIReg(rt))))));
+ assign(t1, unop(Iop_64to32,
+ binop(Iop_MullU32,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16,
+ getIReg(rs)))),
+ unop(Iop_16Uto32,
+ unop(Iop_32to16,
+ getIReg(rt))))));
+
+ assign(t2, binop(Iop_CmpNE32,
+ mkU32(0x0),
+ binop(Iop_And32,
+ mkexpr(t0),
+ mkU32(0x03ff0000))));
+ assign(t3, binop(Iop_CmpNE32,
+ mkU32(0x0),
+ binop(Iop_And32,
+ mkexpr(t1),
+ mkU32(0x03ff0000))));
+ putDSPControl(IRExpr_ITE(mkexpr(t2),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x200000)),
+ IRExpr_ITE(mkexpr(t3),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x200000)),
+ getDSPControl())));
+ putIReg(rd, binop(Iop_16HLto32,
+ IRExpr_ITE(mkexpr(t2),
+ mkU16(0xffff),
+ unop(Iop_32to16,
+ mkexpr(t0))),
+ IRExpr_ITE(mkexpr(t3),
+ mkU16(0xffff),
+ unop(Iop_32to16,
+ mkexpr(t1)))));
+ break;
+ }
+ case 0x08: { /* ADDU.PH */
+ DIP("addu.ph r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I1);
+
+ /* Add lower halves. */
+ assign(t0, binop(Iop_Add32,
+ unop(Iop_16Uto32,
+ unop(Iop_32to16, getIReg(rs))),
+ unop(Iop_16Uto32,
+ unop(Iop_32to16, getIReg(rt)))));
+
+ /* Detect overflow. */
+ assign(t1, binop(Iop_CmpLT32U,
+ unop(Iop_16Uto32,
+ unop(Iop_32to16, mkexpr(t0))),
+ unop(Iop_16Uto32,
+ unop(Iop_32to16, getIReg(rs)))));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t1),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00100000)),
+ getDSPControl()));
+
+ /* Add higher halves. */
+ assign(t2, binop(Iop_Add32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16, getIReg(rs))),
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16, getIReg(rt)))));
+
+ /* Detect overflow. */
+ assign(t3, binop(Iop_CmpLT32U,
+ unop(Iop_16Uto32,
+ unop(Iop_32to16, mkexpr(t2))),
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16,
+ getIReg(rs)))));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t3),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00100000)),
+ getDSPControl()));
+
+ putIReg(rd, binop(Iop_16HLto32,
+ unop(Iop_32to16, mkexpr(t2)),
+ unop(Iop_32to16, mkexpr(t0))));
+ break;
+ }
+ case 0x9: { /* SUBU.PH */
+ DIP("subu.ph r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I1);
+
+ /* Substract lower halves. */
+ assign(t0, binop(Iop_Sub32,
+ unop(Iop_16Uto32,
+ unop(Iop_32to16, getIReg(rs))),
+ unop(Iop_16Uto32,
+ unop(Iop_32to16, getIReg(rt)))));
+
+ /* Detect underflow. */
+ assign(t1, binop(Iop_CmpNE32,
+ binop(Iop_And32,
+ mkexpr(t0),
+ mkU32(0x00010000)),
+ mkU32(0x0)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t1),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00100000)),
+ getDSPControl()));
+
+ /* Subtract higher halves. */
+ assign(t2, binop(Iop_Sub32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16, getIReg(rs))),
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16, getIReg(rt)))));
+
+ /* Detect underflow. */
+ assign(t3, binop(Iop_CmpNE32,
+ binop(Iop_And32,
+ mkexpr(t2),
+ mkU32(0x00010000)),
+ mkU32(0x0)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t3),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00100000)),
+ getDSPControl()));
+
+ putIReg(rd, binop(Iop_16HLto32,
+ unop(Iop_32to16, mkexpr(t2)),
+ unop(Iop_32to16, mkexpr(t0))));
+ break;
+ }
+ case 0xA: { /* ADDQ.PH */
+ DIP("addq.ph r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I1);
+ t6 = newTemp(Ity_I32);
+ t7 = newTemp(Ity_I32);
+
+ /* Add lower halves. */
+ assign(t0, binop(Iop_Add32,
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rt)))));
+
+ /* Bit 16 of the result. */
+ assign(t6, binop(Iop_And32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16, mkexpr(t0))),
+ mkU32(0x1)));
+ /* Detect overflow. */
+ assign(t1, binop(Iop_CmpNE32,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ mkexpr(t0),
+ mkU32(0x8000)),
+ mkU8(15)),
+ mkexpr(t6)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t1),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00100000)),
+ getDSPControl()));
+
+ /* Add higher halves. */
+ assign(t2, binop(Iop_Add32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rt)))));
+
+ /* Bit 16 of the result. */
+ assign(t7, binop(Iop_And32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16, mkexpr(t2))),
+ mkU32(0x1)));
+ /* Detect overflow. */
+ assign(t3, binop(Iop_CmpNE32,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ mkexpr(t2),
+ mkU32(0x00008000)),
+ mkU8(15)),
+ mkexpr(t7)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t3),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00100000)),
+ getDSPControl()));
+
+ putIReg(rd, binop(Iop_16HLto32,
+ unop(Iop_32to16, mkexpr(t2)),
+ unop(Iop_32to16, mkexpr(t0))));
+ break;
+ }
+ case 0xB: { /* SUBQ.PH */
+ DIP("subq.ph r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I1);
+ t6 = newTemp(Ity_I32);
+ t7 = newTemp(Ity_I32);
+
+ /* Subtract lower halves. */
+ assign(t0, binop(Iop_Sub32,
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rt)))));
+
+ /* Bit 16 of the result. */
+ assign(t6, binop(Iop_And32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16, mkexpr(t0))),
+ mkU32(0x1)));
+ /* Compare the signs of input value and the result. */
+ assign(t1, binop(Iop_CmpNE32,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ mkexpr(t0),
+ mkU32(0x8000)),
+ mkU8(15)),
+ mkexpr(t6)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t1),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00100000)),
+ getDSPControl()));
+
+ /* Subtract higher halves. */
+ assign(t2, binop(Iop_Sub32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rt)))));
+
+ /* Bit 16 of the result. */
+ assign(t7, binop(Iop_And32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16, mkexpr(t2))),
+ mkU32(0x1)));
+ /* Compare the signs of input value and the result. */
+ assign(t3, binop(Iop_CmpNE32,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ mkexpr(t2),
+ mkU32(0x00008000)),
+ mkU8(15)),
+ mkexpr(t7)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t3),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00100000)),
+ getDSPControl()));
+
+ putIReg(rd, binop(Iop_16HLto32,
+ unop(Iop_32to16, mkexpr(t2)),
+ unop(Iop_32to16, mkexpr(t0))));
+ break;
+ }
+ case 0xC: { /* ADDU_S.PH */
+ DIP("addu_s.ph r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I1);
+
+ /* Add lower halves. */
+ assign(t0, binop(Iop_Add32,
+ unop(Iop_16Uto32,
+ unop(Iop_32to16, getIReg(rs))),
+ unop(Iop_16Uto32,
+ unop(Iop_32to16, getIReg(rt)))));
+
+ /* Detect overflow. */
+ assign(t1, binop(Iop_CmpLT32U,
+ unop(Iop_16Uto32,
+ unop(Iop_32to16, mkexpr(t0))),
+ unop(Iop_16Uto32,
+ unop(Iop_32to16, getIReg(rs)))));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t1),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00100000)),
+ getDSPControl()));
+
+ /* Add higher halves. */
+ assign(t2, binop(Iop_Add32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16, getIReg(rs))),
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16, getIReg(rt)))));
+
+ /* Detect overflow. */
+ assign(t3, binop(Iop_CmpLT32U,
+ unop(Iop_16Uto32,
+ unop(Iop_32to16, mkexpr(t2))),
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16, getIReg(rs)))));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t3),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00100000)),
+ getDSPControl()));
+
+ putIReg(rd, binop(Iop_16HLto32,
+ IRExpr_ITE(mkexpr(t3),
+ mkU16(0xffff),
+ unop(Iop_32to16,
+ mkexpr(t2))),
+ IRExpr_ITE(mkexpr(t1),
+ mkU16(0xffff),
+ unop(Iop_32to16,
+ mkexpr(t0)))));
+ break;
+ }
+ case 0xD: { /* SUBU_S.PH */
+ DIP("subu_s.ph r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I1);
+
+ /* Subtract lower halves. */
+ assign(t0, binop(Iop_Sub32,
+ unop(Iop_16Uto32,
+ unop(Iop_32to16, getIReg(rs))),
+ unop(Iop_16Uto32,
+ unop(Iop_32to16, getIReg(rt)))));
+
+ /* Detect underflow. */
+ assign(t1, binop(Iop_CmpNE32,
+ binop(Iop_And32,
+ mkexpr(t0), mkU32(0x00010000)),
+ mkU32(0x0)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t1),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00100000)),
+ getDSPControl()));
+
+ /* Subtract higher halves. */
+ assign(t2, binop(Iop_Sub32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16, getIReg(rs))),
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16, getIReg(rt)))));
+
+ /* Detect underflow. */
+ assign(t3, binop(Iop_CmpNE32,
+ binop(Iop_And32,
+ mkexpr(t2), mkU32(0x00010000)),
+ mkU32(0x0)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t3),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00100000)),
+ getDSPControl()));
+
+ putIReg(rd,
+ binop(Iop_16HLto32,
+ IRExpr_ITE(mkexpr(t3),
+ mkU16(0x0000),
+ unop(Iop_32to16, mkexpr(t2))),
+ IRExpr_ITE(mkexpr(t1),
+ mkU16(0x0000),
+ unop(Iop_32to16, mkexpr(t0)))));
+ break;
+ }
+ case 0xE: { /* ADDQ_S.PH */
+ DIP("addq_s.ph r%d r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I16);
+ t5 = newTemp(Ity_I16);
+ t6 = newTemp(Ity_I32);
+ t7 = newTemp(Ity_I32);
+
+ /* Add lower halves. */
+ assign(t0, binop(Iop_Add32,
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rt)))));
+
+ /* Bit 16 of the result. */
+ assign(t6, binop(Iop_And32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16, mkexpr(t0))),
+ mkU32(0x1)));
+ /* Detect overflow. */
+ assign(t1, binop(Iop_CmpNE32,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ mkexpr(t0),
+ mkU32(0x8000)),
+ mkU8(15)),
+ mkexpr(t6)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t1),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00100000)),
+ getDSPControl()));
+ /* Saturate if needed. */
+ assign(t4, IRExpr_ITE(mkexpr(t1),
+ IRExpr_ITE(binop(Iop_CmpEQ32,
+ mkexpr(t6),
+ mkU32(0x0)),
+ mkU16(0x7fff),
+ mkU16(0x8000)),
+ unop(Iop_32to16, mkexpr(t0))));
+
+ /* Add higher halves. */
+ assign(t2, binop(Iop_Add32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rt)))));
+
+ /* Bit 16 of the result. */
+ assign(t7, binop(Iop_And32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16, mkexpr(t2))),
+ mkU32(0x1)));
+ /* Detect overflow. */
+ assign(t3, binop(Iop_CmpNE32,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ mkexpr(t2),
+ mkU32(0x00008000)),
+ mkU8(15)),
+ mkexpr(t7)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t3),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00100000)),
+ getDSPControl()));
+ /* Saturate if needed. */
+ assign(t5, IRExpr_ITE(mkexpr(t3),
+ IRExpr_ITE(binop(Iop_CmpEQ32,
+ mkexpr(t7),
+ mkU32(0x0)),
+ mkU16(0x7fff),
+ mkU16(0x8000)),
+ unop(Iop_32to16, mkexpr(t2))));
+
+ putIReg(rd, binop(Iop_16HLto32, mkexpr(t5), mkexpr(t4)));
+ break;
+ }
+ case 0xF: { /* SUBQ_S.PH */
+ DIP("subq_s.ph r%d r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I16);
+ t5 = newTemp(Ity_I16);
+ t6 = newTemp(Ity_I32);
+ t7 = newTemp(Ity_I32);
+
+ /* Subtract lower halves. */
+ assign(t0, binop(Iop_Sub32,
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rt)))));
+
+ /* Bit 16 of the result. */
+ assign(t6, binop(Iop_And32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16, mkexpr(t0))),
+ mkU32(0x1)));
+ /* Detect overflow or underflow. */
+ assign(t1, binop(Iop_CmpNE32,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ mkexpr(t0),
+ mkU32(0x8000)),
+ mkU8(15)),
+ mkexpr(t6)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t1),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00100000)),
+ getDSPControl()));
+ /* Saturate if needed. */
+ assign(t4, IRExpr_ITE(mkexpr(t1),
+ IRExpr_ITE(binop(Iop_CmpEQ32,
+ mkexpr(t6),
+ mkU32(0x0)),
+ mkU16(0x7fff),
+ mkU16(0x8000)),
+ unop(Iop_32to16, mkexpr(t0))));
+
+ /* Subtract higher halves. */
+ assign(t2, binop(Iop_Sub32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rt)))));
+
+ /* Bit 16 of the result. */
+ assign(t7, binop(Iop_And32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16, mkexpr(t2))),
+ mkU32(0x1)));
+ /* Detect overflow or underflow. */
+ assign(t3, binop(Iop_CmpNE32,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ mkexpr(t2),
+ mkU32(0x00008000)),
+ mkU8(15)),
+ mkexpr(t7)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t3),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00100000)),
+ getDSPControl()));
+ /* Saturate if needed. */
+ assign(t5, IRExpr_ITE(mkexpr(t3),
+ IRExpr_ITE(binop(Iop_CmpEQ32,
+ mkexpr(t7),
+ mkU32(0x0)),
+ mkU16(0x7fff),
+ mkU16(0x8000)),
+ unop(Iop_32to16, mkexpr(t2))));
+
+ putIReg(rd, binop(Iop_16HLto32, mkexpr(t5), mkexpr(t4)));
+ break;
+ }
+ case 0x10: { /* ADDSC */
+ DIP("addsc r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I1);
+
+ /* The carry bit result out of the addition operation is
+ written to bit 13(the c field) of the DSPControl reg. */
+ assign(t0, binop(Iop_Add64,
+ unop(Iop_32Uto64, getIReg(rs)),
+ unop(Iop_32Uto64, getIReg(rt))));
+
+ assign(t1, binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ unop(Iop_64HIto32, mkexpr(t0)),
+ mkU32(0x1)),
+ mkU32(0x1)));
+ putDSPControl(IRExpr_ITE(mkexpr(t1),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x2000)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xffffdfff))));
+
+ putIReg(rd, unop(Iop_64to32, mkexpr(t0)));
+ break;
+ }
+ case 0x11: { /* ADDWC */
+ DIP("addwc r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I32);
+ t4 = newTemp(Ity_I1);
+
+ /* Get carry bit from DSPControl register. */
+ assign(t0, binop(Iop_Shr32,
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0x2000)),
+ mkU8(0xd)));
+ assign(t1, binop(Iop_Add64,
+ unop(Iop_32Sto64, getIReg(rs)),
+ unop(Iop_32Sto64,
+ binop(Iop_Add32,
+ getIReg(rt),
+ mkexpr(t0)))));
+
+ /* Extract bits 32 and 31. */
+ assign(t2, binop(Iop_And32,
+ unop(Iop_64HIto32, mkexpr(t1)),
+ mkU32(0x1)));
+ assign(t3, binop(Iop_Shr32,
+ binop(Iop_And32,
+ unop(Iop_64to32, mkexpr(t1)),
+ mkU32(0x80000000)),
+ mkU8(31)));
+ assign(t4, binop(Iop_CmpNE32, mkexpr(t2), mkexpr(t3)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t4),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00100000)),
+ getDSPControl()));
+ putIReg(rd, unop(Iop_64to32, mkexpr(t1)));
+ break;
+ }
+ case 0x12: { /* MODSUB */
+ DIP("modsub r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+
+ /* decr_7..0 */
+ assign(t0,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16, getIReg(rt)))));
+
+ /* lastindex_15..0 */
+ assign(t1,
+ unop(Iop_16Uto32,
+ binop(Iop_8HLto16,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16, getIReg(rt))),
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, getIReg(rt))))));
+ /* temp_15..0 */
+ assign(t2,
+ IRExpr_ITE(binop(Iop_CmpEQ32,
+ getIReg(rs),
+ mkU32(0x00000000)),
+ mkexpr(t1),
+ binop(Iop_Sub32,
+ getIReg(rs), mkexpr(t0))));
+ putIReg(rd, mkexpr(t2));
+ break;
+ }
+ case 0x14: { /* RADDU.W.QB */
+ DIP("raddu.w.qb r%d, r%d", rd, rs);
+ vassert(!mode64);
+ putIReg(rd, binop(Iop_Add32,
+ binop(Iop_Add32,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16,
+ getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ getIReg(rs))))),
+ binop(Iop_Add32,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16,
+ getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ getIReg(rs)))))));
+ break;
+ }
+ case 0x16: { /* ADDQ_S.W */
+ DIP("addq_s.w r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I32);
+
+ assign(t0, binop(Iop_Add64,
+ unop(Iop_32Sto64, getIReg(rs)),
+ unop(Iop_32Sto64, getIReg(rt))));
+
+ assign(t3, binop(Iop_And32,
+ unop(Iop_64HIto32, mkexpr(t0)),
+ mkU32(0x1)));
+ assign(t1, binop(Iop_CmpNE32,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ unop(Iop_64to32, mkexpr(t0)),
+ mkU32(0x80000000)),
+ mkU8(31)),
+ mkexpr(t3)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t1),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00100000)),
+ getDSPControl()));
+
+ putIReg(rd, IRExpr_ITE(mkexpr(t1),
+ IRExpr_ITE(binop(Iop_CmpEQ32,
+ mkexpr(t3),
+ mkU32(0x0)),
+ mkU32(0x7fffffff),
+ mkU32(0x80000000)),
+ unop(Iop_64to32, mkexpr(t0))));
+ break;
+ }
+ case 0x17: { /* SUBQ_S.W */
+ DIP("subq_s.w r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I32);
+
+ assign(t0, binop(Iop_Sub64,
+ unop(Iop_32Sto64, getIReg(rs)),
+ unop(Iop_32Sto64, getIReg(rt))));
+
+ assign(t3, binop(Iop_And32,
+ unop(Iop_64HIto32, mkexpr(t0)),
+ mkU32(0x1)));
+ assign(t1, binop(Iop_CmpNE32,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ unop(Iop_64to32, mkexpr(t0)),
+ mkU32(0x80000000)),
+ mkU8(31)),
+ mkexpr(t3)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t1),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00100000)),
+ getDSPControl()));
+
+ putIReg(rd, IRExpr_ITE(mkexpr(t1),
+ IRExpr_ITE(binop(Iop_CmpEQ32,
+ mkexpr(t3),
+ mkU32(0x0)),
+ mkU32(0x7fffffff),
+ mkU32(0x80000000)),
+ unop(Iop_64to32, mkexpr(t0))));
+ break;
+ }
+ case 0x1C: { /* MULEQ_S.W.PHL */
+ DIP("muleq_s.w.phl r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I1);
+ t3 = newTemp(Ity_I32);
+
+ assign(t0,
+ binop(Iop_Shl32,
+ binop(Iop_Mul32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rt))),
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rs)))),
+ mkU8(0x1)));
+ assign(t1, binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0xffff0000)),
+ mkU32(0x80000000)));
+ assign(t2, binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0xffff0000)),
+ mkU32(0x80000000)));
+ assign(t3, IRExpr_ITE(mkexpr(t1),
+ IRExpr_ITE(mkexpr(t2),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00200000)),
+ getDSPControl()),
+ getDSPControl()));
+ putDSPControl(mkexpr(t3));
+
+ putIReg(rd, IRExpr_ITE(mkexpr(t1),
+ IRExpr_ITE(mkexpr(t2),
+ mkU32(0x7fffffff),
+ mkexpr(t0)),
+ mkexpr(t0)));
+ break;
+ }
+ case 0x1D: { /* MULEQ_S.W.PHR */
+ DIP("muleq_s.w.phr r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I1);
+
+ assign(t0,
+ binop(Iop_Shl32,
+ binop(Iop_Mul32,
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rt))),
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rs)))),
+ mkU8(0x1)));
+ assign(t1, binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0xffff)),
+ mkU32(0x8000)));
+ assign(t2, binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0xffff)),
+ mkU32(0x8000)));
+ putDSPControl(IRExpr_ITE(mkexpr(t1),
+ IRExpr_ITE(mkexpr(t2),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00200000)
+ ),
+ getDSPControl()),
+ getDSPControl()));
+ putIReg(rd, IRExpr_ITE(mkexpr(t1),
+ IRExpr_ITE(mkexpr(t2),
+ mkU32(0x7fffffff),
+ mkexpr(t0)),
+ mkexpr(t0)));
+ break;
+ }
+ case 0x1E: { /* MULQ_S.PH */
+ DIP("mulq_s.ph r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I16);
+ t3 = newTemp(Ity_I16);
+ t5 = newTemp(Ity_I32);
+ t6 = newTemp(Ity_I32);
+ t7 = newTemp(Ity_I32);
+ t8 = newTemp(Ity_I32);
+
+ assign(t5,
+ unop(Iop_16Sto32, unop(Iop_32to16, getIReg(rs))));
+ assign(t6,
+ unop(Iop_16Sto32, unop(Iop_32to16, getIReg(rt))));
+
+ assign(t7,
+ unop(Iop_16Sto32, unop(Iop_32HIto16, getIReg(rs))));
+ assign(t8,
+ unop(Iop_16Sto32, unop(Iop_32HIto16, getIReg(rt))));
+
+ assign(t0, binop(Iop_And32,
+ unop(Iop_1Sto32,
+ binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkexpr(t5),
+ mkU32(0xffff)),
+ mkU32(0x8000))),
+ unop(Iop_1Sto32,
+ binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkexpr(t6),
+ mkU32(0xffff)),
+ mkU32(0x8000)))));
+ assign(t1, binop(Iop_And32,
+ unop(Iop_1Sto32,
+ binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkexpr(t7),
+ mkU32(0xffff)),
+ mkU32(0x8000))),
+ unop(Iop_1Sto32,
+ binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkexpr(t8),
+ mkU32(0xffff)),
+ mkU32(0x8000)))));
+
+ putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_Or32,
+ mkexpr(t0),
+ mkexpr(t1)),
+ mkU32(0x0)),
+ getDSPControl(),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x200000))));
+
+ assign(t2, unop(Iop_32HIto16,
+ binop(Iop_Shl32,
+ unop(Iop_64to32,
+ binop(Iop_MullS32,
+ mkexpr(t7),
+ mkexpr(t8))),
+ mkU8(0x1))));
+ assign(t3, unop(Iop_32HIto16,
+ binop(Iop_Shl32,
+ unop(Iop_64to32,
+ binop(Iop_MullS32,
+ mkexpr(t5),
+ mkexpr(t6))),
+ mkU8(0x1))));
+ putIReg(rd, binop(Iop_16HLto32,
+ IRExpr_ITE(binop(Iop_CmpEQ32,
+ mkexpr(t1),
+ mkU32(0x0)),
+ mkexpr(t2),
+ mkU16(0x7fff)),
+ IRExpr_ITE(binop(Iop_CmpEQ32,
+ mkexpr(t0),
+ mkU32(0x0)),
+ mkexpr(t3),
+ mkU16(0x7fff))));
+ break;
+ }
+ case 0x1F: { /* MULQ_RS.PH */
+ DIP("mulq_rs.ph r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I1);
+ t3 = newTemp(Ity_I16);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I1);
+ t6 = newTemp(Ity_I1);
+ t7 = newTemp(Ity_I16);
+
+ /* Multiply and round lower halfwords. */
+ assign(t0, binop(Iop_Add32,
+ binop(Iop_Shl32,
+ binop(Iop_Mul32,
+ unop(Iop_16Sto32,
+ unop(Iop_32to16,
+ getIReg(rt))),
+ unop(Iop_16Sto32,
+ unop(Iop_32to16,
+ getIReg(rs)))),
+ mkU8(0x1)),
+ mkU32(0x00008000)));
+ assign(t1, binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ getIReg(rt), mkU32(0xffff)),
+ mkU32(0x8000)));
+ assign(t2, binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ getIReg(rs), mkU32(0xffff)),
+ mkU32(0x8000)));
+ putDSPControl(IRExpr_ITE(mkexpr(t1),
+ IRExpr_ITE(mkexpr(t2),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00200000)
+ ),
+ getDSPControl()),
+ getDSPControl()));
+ assign(t3, IRExpr_ITE(mkexpr(t1),
+ IRExpr_ITE(mkexpr(t2),
+ mkU16(0x7fff),
+ unop(Iop_32HIto16,
+ mkexpr(t0))),
+ unop(Iop_32HIto16, mkexpr(t0))));
+
+ /* Multiply and round higher halfwords. */
+ assign(t4, binop(Iop_Add32,
+ binop(Iop_Shl32,
+ binop(Iop_Mul32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16,
+ getIReg(rt))),
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16,
+ getIReg(rs)))),
+ mkU8(0x1)),
+ mkU32(0x00008000)));
+ assign(t5, binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0xffff0000)),
+ mkU32(0x80000000)));
+ assign(t6, binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0xffff0000)),
+ mkU32(0x80000000)));
+ putDSPControl(IRExpr_ITE(mkexpr(t5),
+ IRExpr_ITE(mkexpr(t6),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00200000)),
+ getDSPControl()),
+ getDSPControl()));
+ assign(t7, IRExpr_ITE(mkexpr(t5),
+ IRExpr_ITE(mkexpr(t6),
+ mkU16(0x7fff),
+ unop(Iop_32HIto16,
+ mkexpr(t4))),
+ unop(Iop_32HIto16, mkexpr(t4))));
+
+ putIReg(rd, binop(Iop_16HLto32, mkexpr(t7), mkexpr(t3)));
+ break;
+ }
+ default:
+ return -1;
+ }
+ break; /* end of ADDU.QB */
+ }
+ case 0x11: { /* CMPU.EQ.QB */
+ switch(sa) {
+ case 0x0: { /* CMPU.EQ.QB */
+ DIP("cmpu.eq.qb r%d, r%d", rs, rt);
+ vassert(!mode64);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I1);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I1);
+
+ assign(t1,
+ binop(Iop_CmpEQ32,
+ binop(Iop_And32, getIReg(rs), mkU32(0xff)),
+ binop(Iop_And32, getIReg(rt), mkU32(0xff))));
+ putDSPControl(IRExpr_ITE(mkexpr(t1),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x01000000)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xfeffffff))));
+
+ assign(t2, binop(Iop_CmpEQ32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ getIReg(rt))))));
+ putDSPControl(IRExpr_ITE(mkexpr(t2),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x02000000)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xfdffffff))));
+
+ assign(t3, binop(Iop_CmpEQ32,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16,
+ getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16,
+ getIReg(rt))))));
+ putDSPControl(IRExpr_ITE(mkexpr(t3),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x04000000)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xfbffffff))));
+
+ assign(t4, binop(Iop_CmpEQ32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ getIReg(rt))))));
+ putDSPControl(IRExpr_ITE(mkexpr(t4),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x08000000)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xf7ffffff))));
+ break;
+ }
+ case 0x1: { /* CMPU.LT.QB */
+ DIP("cmpu.lt.qb r%d, r%d", rs, rt);
+ vassert(!mode64);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I1);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I1);
+
+ assign(t1, binop(Iop_CmpLT32U,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16,
+ getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16,
+ getIReg(rt))))));
+ putDSPControl(IRExpr_ITE(mkexpr(t1),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x01000000)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xfeffffff))));
+
+ assign(t2, binop(Iop_CmpLT32U,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ getIReg(rt))))));
+ putDSPControl(IRExpr_ITE(mkexpr(t2),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x02000000)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xfdffffff))));
+
+ assign(t3, binop(Iop_CmpLT32U,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16,
+ getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16,
+ getIReg(rt))))));
+ putDSPControl(IRExpr_ITE(mkexpr(t3),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x04000000)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xfbffffff))));
+
+ assign(t4, binop(Iop_CmpLT32U,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ getIReg(rt))))));
+ putDSPControl(IRExpr_ITE(mkexpr(t4),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x08000000)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xf7ffffff))));
+ break;
+ }
+ case 0x2: { /* CMPU.LE.QB */
+ DIP("cmpu.le.qb r%d, r%d", rs, rt);
+ vassert(!mode64);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I1);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I1);
+
+ assign(t1, binop(Iop_CmpLE32U,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16,
+ getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16,
+ getIReg(rt))))));
+ putDSPControl(IRExpr_ITE(mkexpr(t1),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x01000000)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xfeffffff))));
+
+ assign(t2, binop(Iop_CmpLE32U,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ getIReg(rt))))));
+ putDSPControl(IRExpr_ITE(mkexpr(t2),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x02000000)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xfdffffff))));
+
+ assign(t3, binop(Iop_CmpLE32U,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16,
+ getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16,
+ getIReg(rt))))));
+ putDSPControl(IRExpr_ITE(mkexpr(t3),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x04000000)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xfbffffff))));
+
+ assign(t4, binop(Iop_CmpLE32U,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ getIReg(rt))))));
+ putDSPControl(IRExpr_ITE(mkexpr(t4),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x08000000)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xf7ffffff))));
+ break;
+ }
+ case 0x3: { /* PICK.QB */
+ DIP("pick.qb r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I8);
+ t2 = newTemp(Ity_I8);
+ t3 = newTemp(Ity_I8);
+ t4 = newTemp(Ity_I8);
+
+ assign(t0, getDSPControl());
+ assign(t1, IRExpr_ITE(binop(Iop_CmpNE32,
+ binop(Iop_And32,
+ mkexpr(t0),
+ mkU32(0x01000000)),
+ mkU32(0x0)),
+ unop(Iop_16to8,
+ unop(Iop_32to16,
+ getIReg(rs))),
+ unop(Iop_16to8,
+ unop(Iop_32to16,
+ getIReg(rt)))));
+ assign(t2, IRExpr_ITE(binop(Iop_CmpNE32,
+ binop(Iop_And32,
+ mkexpr(t0),
+ mkU32(0x02000000)),
+ mkU32(0x0)),
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, getIReg(rs))),
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ getIReg(rt)))));
+ assign(t3, IRExpr_ITE(binop(Iop_CmpNE32,
+ binop(Iop_And32,
+ mkexpr(t0),
+ mkU32(0x04000000)),
+ mkU32(0x0)),
+ unop(Iop_16to8,
+ unop(Iop_32HIto16,
+ getIReg(rs))),
+ unop(Iop_16to8,
+ unop(Iop_32HIto16,
+ getIReg(rt)))));
+ assign(t4, IRExpr_ITE(binop(Iop_CmpNE32,
+ binop(Iop_And32,
+ mkexpr(t0),
+ mkU32(0x08000000)),
+ mkU32(0x0)),
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ getIReg(rs))),
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ getIReg(rt)))));
+ putIReg(rd,
+ binop(Iop_16HLto32,
+ binop(Iop_8HLto16, mkexpr(t4), mkexpr(t3)),
+ binop(Iop_8HLto16, mkexpr(t2), mkexpr(t1))));
+ break;
+ }
+ case 0x4: { /* CMPGU.EQ.QB */
+ DIP("cmpgu.eq.qb r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I1);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I1);
+ t5 = newTemp(Ity_I32);
+ t6 = newTemp(Ity_I32);
+ t7 = newTemp(Ity_I32);
+ t8 = newTemp(Ity_I32);
+
+ assign(t1, binop(Iop_CmpEQ32,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16,
+ getIReg(rt))))));
+ assign(t5, IRExpr_ITE(mkexpr(t1),
+ mkU32(0x00000001), mkU32(0)));
+
+ assign(t2, binop(Iop_CmpEQ32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ getIReg(rt))))));
+ assign(t6, IRExpr_ITE(mkexpr(t2),
+ mkU32(0x00000002), mkU32(0)));
+
+ assign(t3, binop(Iop_CmpEQ32,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16,
+ getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16,
+ getIReg(rt))))));
+ assign(t7, IRExpr_ITE(mkexpr(t3),
+ mkU32(0x00000004), mkU32(0)));
+
+ assign(t4, binop(Iop_CmpEQ32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ getIReg(rt))))));
+ assign(t8, IRExpr_ITE(mkexpr(t4),
+ mkU32(0x00000008), mkU32(0)));
+
+ putIReg(rd, binop(Iop_Or32,
+ binop(Iop_Or32,
+ binop(Iop_Or32,
+ mkexpr(t5), mkexpr(t6)),
+ mkexpr(t7)),
+ mkexpr(t8)));
+ break;
+ }
+ case 0x5: { /* CMPGU.LT.QB */
+ DIP("cmpgu.lt.qb r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I1);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I1);
+ t5 = newTemp(Ity_I32);
+ t6 = newTemp(Ity_I32);
+ t7 = newTemp(Ity_I32);
+ t8 = newTemp(Ity_I32);
+
+ assign(t1, binop(Iop_CmpLT32U,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16,
+ getIReg(rt))))));
+ assign(t5, IRExpr_ITE(mkexpr(t1),
+ mkU32(0x00000001), mkU32(0)));
+
+ assign(t2, binop(Iop_CmpLT32U,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ getIReg(rt))))));
+ assign(t6, IRExpr_ITE(mkexpr(t2),
+ mkU32(0x00000002), mkU32(0)));
+
+ assign(t3, binop(Iop_CmpLT32U,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16,
+ getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16,
+ getIReg(rt))))));
+ assign(t7, IRExpr_ITE(mkexpr(t3),
+ mkU32(0x00000004), mkU32(0)));
+
+ assign(t4, binop(Iop_CmpLT32U,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ getIReg(rt))))));
+ assign(t8, IRExpr_ITE(mkexpr(t4),
+ mkU32(0x00000008), mkU32(0)));
+ putIReg(rd, binop(Iop_Or32,
+ binop(Iop_Or32,
+ binop(Iop_Or32,
+ mkexpr(t5), mkexpr(t6)),
+ mkexpr(t7)),
+ mkexpr(t8)));
+ break;
+ }
+ case 0x6: { /* CMPGU.LE.QB */
+ DIP("cmpgu.le.qb r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I1);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I1);
+ t5 = newTemp(Ity_I32);
+ t6 = newTemp(Ity_I32);
+ t7 = newTemp(Ity_I32);
+ t8 = newTemp(Ity_I32);
+
+ assign(t1, binop(Iop_CmpLE32U,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16,
+ getIReg(rt))))));
+ assign(t5, IRExpr_ITE(mkexpr(t1),
+ mkU32(0x00000001), mkU32(0)));
+
+ assign(t2, binop(Iop_CmpLE32U,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ getIReg(rt))))));
+ assign(t6, IRExpr_ITE(mkexpr(t2),
+ mkU32(0x00000002), mkU32(0)));
+
+ assign(t3, binop(Iop_CmpLE32U,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16,
+ getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16,
+ getIReg(rt))))));
+ assign(t7, IRExpr_ITE(mkexpr(t3),
+ mkU32(0x00000004), mkU32(0)));
+
+ assign(t4, binop(Iop_CmpLE32U,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ getIReg(rt))))));
+ assign(t8, IRExpr_ITE(mkexpr(t4),
+ mkU32(0x00000008), mkU32(0)));
+ putIReg(rd, binop(Iop_Or32,
+ binop(Iop_Or32,
+ binop(Iop_Or32,
+ mkexpr(t5), mkexpr(t6)),
+ mkexpr(t7)),
+ mkexpr(t8)));
+ break;
+ }
+ case 0x8: { /* CMP.EQ.PH */
+ DIP("cmp.eq.ph r%d, r%d", rs, rt);
+ vassert(!mode64);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I1);
+
+ assign(t1, binop(Iop_CmpEQ16,
+ unop(Iop_32to16, getIReg(rs)),
+ unop(Iop_32to16, getIReg(rt))));
+ putDSPControl(IRExpr_ITE(mkexpr(t1),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x01000000)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xfeffffff))));
+ assign(t2, binop(Iop_CmpEQ16,
+ unop(Iop_32HIto16, getIReg(rs)),
+ unop(Iop_32HIto16, getIReg(rt))));
+ putDSPControl(IRExpr_ITE(mkexpr(t2),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x02000000)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xfdffffff))));
+ break;
+ }
+ case 0x9: { /* CMP.LT.PH */
+ DIP("cmp.lt.ph r%d, r%d", rs, rt);
+ vassert(!mode64);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I1);
+
+ assign(t1, binop(Iop_CmpLT32S,
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rt)))));
+ putDSPControl(IRExpr_ITE(mkexpr(t1),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x01000000)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xfeffffff))));
+
+ assign(t2, binop(Iop_CmpLT32S,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rt)))));
+ putDSPControl(IRExpr_ITE(mkexpr(t2),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x02000000)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xfdffffff))));
+ break;
+ }
+ case 0xA: { /* CMP.LE.PH */
+ DIP("cmp.le.ph r%d, r%d", rs, rt);
+ vassert(!mode64);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I1);
+
+ assign(t1, binop(Iop_CmpLE32S,
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rt)))));
+ putDSPControl(IRExpr_ITE(mkexpr(t1),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x01000000)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xfeffffff))));
+
+ assign(t2, binop(Iop_CmpLE32S,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rt)))));
+ putDSPControl(IRExpr_ITE(mkexpr(t2),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x02000000)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xfdffffff))));
+ break;
+ }
+ case 0xB: { /* PICK.PH */
+ DIP("pick.qb r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I16);
+ t2 = newTemp(Ity_I16);
+
+ assign(t0, getDSPControl());
+
+ assign(t1, IRExpr_ITE(binop(Iop_CmpNE32,
+ binop(Iop_And32,
+ mkexpr(t0),
+ mkU32(0x01000000)),
+ mkU32(0x0)),
+ unop(Iop_32to16, getIReg(rs)),
+ unop(Iop_32to16, getIReg(rt))));
+
+ assign(t2, IRExpr_ITE(binop(Iop_CmpNE32,
+ binop(Iop_And32,
+ mkexpr(t0),
+ mkU32(0x02000000)),
+ mkU32(0x0)),
+ unop(Iop_32HIto16, getIReg(rs)),
+ unop(Iop_32HIto16, getIReg(rt))));
+
+ putIReg(rd, binop(Iop_16HLto32, mkexpr(t2), mkexpr(t1)));
+ break;
+ }
+ case 0xC: { /* PRECRQ.QB.PH */
+ DIP("precrq.qb.ph r%d, r%d, %d", rd, rs, rt);
+ vassert(!mode64);
+ putIReg(rd,
+ binop(Iop_16HLto32,
+ binop(Iop_8HLto16,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16, getIReg(rs))),
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, getIReg(rs)))),
+ binop(Iop_8HLto16,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16, getIReg(rt))),
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, getIReg(rt))))));
+ break;
+ }
+ case 0xD: { /* PRECR.QB.PH */
+ DIP("precr.qb.ph r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+
+ putIReg(rd,
+ binop(Iop_16HLto32,
+ binop(Iop_8HLto16,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16, getIReg(rs))),
+ unop(Iop_16to8,
+ unop(Iop_32to16, getIReg(rs)))),
+ binop(Iop_8HLto16,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16, getIReg(rt))),
+ unop(Iop_16to8,
+ unop(Iop_32to16, getIReg(rt))))));
+ break;
+ }
+ case 0xF: { /* PRECRQU_S.QB.PH */
+ DIP("precrqu_s.qb.ph r%d, r%d, %d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I8);
+ t1 = newTemp(Ity_I8);
+ t2 = newTemp(Ity_I8);
+ t3 = newTemp(Ity_I8);
+ t4 = newTemp(Ity_I8);
+ t5 = newTemp(Ity_I32);
+ t6 = newTemp(Ity_I1);
+ t7 = newTemp(Ity_I8);
+ t8 = newTemp(Ity_I1);
+ t9 = newTemp(Ity_I32);
+ t10 = newTemp(Ity_I8);
+ t11 = newTemp(Ity_I1);
+ t12 = newTemp(Ity_I32);
+ t13 = newTemp(Ity_I8);
+ t14 = newTemp(Ity_I1);
+ t15 = newTemp(Ity_I32);
+
+ assign(t4, IRExpr_ITE(binop(Iop_CmpLT32U,
+ mkU32(0x7f80),
+ binop(Iop_And32,
+ unop(Iop_16Uto32,
+ unop(Iop_32to16,
+ getIReg(rs))),
+ mkU32(0x7fff))),
+ mkU8(0xff),
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ binop(Iop_Shl32,
+ getIReg(rs),
+ mkU8(1))))));
+ assign(t0, IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ unop(Iop_16Uto32,
+ unop(Iop_32to16,
+ getIReg(rs))),
+ mkU32(0x00008000)),
+ mkU32(0x0)),
+ mkexpr(t4),
+ mkU8(0x0)));
+ assign(t5, binop(Iop_And32,
+ unop(Iop_16Uto32,
+ unop(Iop_32to16,
+ getIReg(rs))),
+ mkU32(0x00008000)));
+ assign(t6, binop(Iop_CmpLT32U,
+ mkU32(0x7f80),
+ binop(Iop_And32,
+ unop(Iop_16Uto32,
+ unop(Iop_32to16,
+ getIReg(rs))),
+ mkU32(0x7fff))));
+ putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32,
+ mkexpr(t5),
+ mkU32(0x0)),
+ IRExpr_ITE(mkexpr(t6),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00400000)
+ ),
+ getDSPControl()),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00400000))));
+
+ assign(t7, IRExpr_ITE(binop(Iop_CmpLT32U,
+ mkU32(0x7f80),
+ binop(Iop_And32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16,
+ getIReg(rs))),
+ mkU32(0x7fff))),
+ mkU8(0xff),
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ binop(Iop_Shl32,
+ getIReg(rs),
+ mkU8(1))))));
+ assign(t1, IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16,
+ getIReg(rs))),
+ mkU32(0x00008000)),
+ mkU32(0x0)),
+ mkexpr(t7),
+ mkU8(0x0)));
+ assign(t8, binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16,
+ getIReg(rs))),
+ mkU32(0x00008000)),
+ mkU32(0x0)));
+ assign(t9, IRExpr_ITE(binop(Iop_CmpLT32U,
+ mkU32(0x7f80),
+ binop(Iop_And32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16,
+ getIReg(rs))),
+ mkU32(0x7fff))),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00400000)),
+ getDSPControl()));
+ putDSPControl(IRExpr_ITE(mkexpr(t8),
+ mkexpr(t9),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00400000))));
+
+ assign(t10, IRExpr_ITE(binop(Iop_CmpLT32U,
+ mkU32(0x7f80),
+ binop(Iop_And32,
+ unop(Iop_16Uto32,
+ unop(Iop_32to16,
+ getIReg(rt))),
+ mkU32(0x7fff))),
+ mkU8(0xff),
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ binop(Iop_Shl32,
+ getIReg(rt),
+ mkU8(1))))));
+ assign(t2, IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ unop(Iop_16Uto32,
+ unop(Iop_32to16,
+ getIReg(rt))),
+ mkU32(0x00008000)),
+ mkU32(0x0)),
+ mkexpr(t10),
+ mkU8(0x0)));
+ assign(t11, binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ unop(Iop_16Uto32,
+ unop(Iop_32to16,
+ getIReg(rt))),
+ mkU32(0x00008000)),
+ mkU32(0x0)));
+ assign(t12, IRExpr_ITE(binop(Iop_CmpLT32U,
+ mkU32(0x7f80),
+ binop(Iop_And32,
+ unop(Iop_16Uto32,
+ unop(Iop_32to16,
+ getIReg(rt))),
+ mkU32(0x7fff))),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00400000)),
+ getDSPControl()));
+ putDSPControl(IRExpr_ITE(mkexpr(t11),
+ mkexpr(t12),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00400000))));
+
+ assign(t13, IRExpr_ITE(binop(Iop_CmpLT32U,
+ mkU32(0x7f80),
+ binop(Iop_And32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16,
+ getIReg(rt))),
+ mkU32(0x7fff))),
+ mkU8(0xff),
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ binop(Iop_Shl32,
+ getIReg(rt),
+ mkU8(1))))));
+ assign(t3, IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16,
+ getIReg(rt))),
+ mkU32(0x00008000)),
+ mkU32(0x0)),
+ mkexpr(t13),
+ mkU8(0x0)));
+ assign(t14, binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16,
+ getIReg(rt))),
+ mkU32(0x00008000)),
+ mkU32(0x0)));
+ assign(t15, IRExpr_ITE(binop(Iop_CmpLT32U,
+ mkU32(0x7f80),
+ binop(Iop_And32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16,
+ getIReg(rt))),
+ mkU32(0x7fff))),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00400000)),
+ getDSPControl()));
+ putDSPControl(IRExpr_ITE(mkexpr(t14),
+ mkexpr(t15),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00400000))));
+
+ putIReg(rd, binop(Iop_16HLto32,
+ binop(Iop_8HLto16,
+ mkexpr(t1), mkexpr(t0)),
+ binop(Iop_8HLto16,
+ mkexpr(t3), mkexpr(t2))));
+ break;
+ }
+ case 0x14: { /* PRECRQ.PH.W */
+ DIP("precrq.ph.w r%d, r%d, %d", rd, rs, rt);
+ vassert(!mode64);
+ putIReg(rd, binop(Iop_16HLto32,
+ unop(Iop_32HIto16, getIReg(rs)),
+ unop(Iop_32HIto16, getIReg(rt))));
+ break;
+ }
+ case 0x15: { /* PRECRQ_RS.PH.W */
+ DIP("precrq_rs.ph.w r%d, r%d, %d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I64);
+ t4 = newTemp(Ity_I1);
+ t5 = newTemp(Ity_I32);
+
+ assign(t0, binop(Iop_Add64,
+ binop(Iop_32HLto64,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x80000000)),
+ mkU8(31)),
+ getIReg(rs)),
+ mkU64(0x0000000000008000ULL)));
+ assign(t1, binop(Iop_CmpNE32,
+ binop(Iop_And32,
+ unop(Iop_64HIto32, mkexpr(t0)),
+ mkU32(0x1)),
+ binop(Iop_And32,
+ binop(Iop_Shr32,
+ unop(Iop_64to32, mkexpr(t0)),
+ mkU8(31)),
+ mkU32(0x1))));
+ assign(t2, IRExpr_ITE(mkexpr(t1),
+ mkU32(0x7fffffff),
+ unop(Iop_64to32, mkexpr(t0))));
+ putDSPControl(IRExpr_ITE(mkexpr(t1),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x400000)),
+ getDSPControl()));
+ assign(t3, binop(Iop_Add64,
+ binop(Iop_32HLto64,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x80000000)),
+ mkU8(31)),
+ getIReg(rt)),
+ mkU64(0x0000000000008000ULL)));
+ assign(t4, binop(Iop_CmpNE32,
+ binop(Iop_And32,
+ unop(Iop_64HIto32, mkexpr(t3)),
+ mkU32(0x1)),
+ binop(Iop_And32,
+ binop(Iop_Shr32,
+ unop(Iop_64to32, mkexpr(t3)),
+ mkU8(31)),
+ mkU32(0x1))));
+ assign(t5, IRExpr_ITE(mkexpr(t4),
+ mkU32(0x7fffffff),
+ unop(Iop_64to32, mkexpr(t3))));
+ putDSPControl(IRExpr_ITE(mkexpr(t4),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x400000)),
+ getDSPControl()));
+ putIReg(rd, binop(Iop_16HLto32,
+ unop(Iop_32HIto16, mkexpr(t2)),
+ unop(Iop_32HIto16, mkexpr(t5))));
+ break;
+ }
+ case 0x1E: { /* PRECR_SRA.PH.W */
+ DIP("precr_sra.ph.w r%d, r%d, %d", rt, rs, rd);
+ vassert(!mode64);
+
+ if (0 == rd) {
+ putIReg(rt, binop(Iop_16HLto32,
+ unop(Iop_32to16, getIReg(rt)),
+ unop(Iop_32to16, getIReg(rs))));
+ } else {
+ putIReg(rt, binop(Iop_16HLto32,
+ unop(Iop_32to16, binop(Iop_Sar32,
+ getIReg(rt),
+ mkU8(rd))),
+ unop(Iop_32to16, binop(Iop_Sar32,
+ getIReg(rs),
+ mkU8(rd)))));
+ }
+ break;
+ }
+ case 0x1F: { /* PRECR_SRA_R.PH.W */
+ DIP("precr_sra_r.ph.w r%d, r%d, %d", rt, rs, rd);
+ vassert(!mode64);
+
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I32);
+
+ if (0 == rd) {
+ putIReg(rt, binop(Iop_16HLto32,
+ unop(Iop_32to16, getIReg(rt)),
+ unop(Iop_32to16, getIReg(rs))));
+ } else {
+ assign(t0, binop(Iop_Shr32,
+ binop(Iop_Add32,
+ binop(Iop_Sar32,
+ getIReg(rt),
+ mkU8(rd-1)),
+ mkU32(0x1)),
+ mkU8(0x1)));
+ assign(t1, binop(Iop_Shr32,
+ binop(Iop_Add32,
+ binop(Iop_Sar32,
+ getIReg(rs),
+ mkU8(rd-1)),
+ mkU32(0x1)),
+ mkU8(0x1)));
+ putIReg(rt, binop(Iop_16HLto32,
+ unop(Iop_32to16, mkexpr(t0)),
+ unop(Iop_32to16, mkexpr(t1))));
+ };
+ break;
+ }
+ case 0xE: { /* PACKRL.PH */
+ DIP("packrl.ph r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+
+ putIReg(rd, binop(Iop_16HLto32,
+ unop(Iop_32to16, getIReg(rs)),
+ unop(Iop_32HIto16, getIReg(rt))));
+ break;
+ }
+ case 0x18: { /* CMPGDU.EQ.QB */
+ DIP("cmpgdu.eq.qb r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I1);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I1);
+ t5 = newTemp(Ity_I32);
+ t6 = newTemp(Ity_I32);
+ t7 = newTemp(Ity_I32);
+ t8 = newTemp(Ity_I32);
+
+ assign(t1,
+ binop(Iop_CmpEQ32,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16, getIReg(rt))))));
+ assign(t5, IRExpr_ITE(mkexpr(t1),
+ mkU32(0x00000001), mkU32(0)));
+ putDSPControl(IRExpr_ITE(mkexpr(t1),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x01000000)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xfeffffff))));
+
+ assign(t2, binop(Iop_CmpEQ32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ getIReg(rt))))));
+ assign(t6, IRExpr_ITE(mkexpr(t2),
+ mkU32(0x00000002), mkU32(0)));
+ putDSPControl(IRExpr_ITE(mkexpr(t2),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x02000000)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xfdffffff))));
+
+ assign(t3, binop(Iop_CmpEQ32,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16,
+ getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16,
+ getIReg(rt))))));
+ assign(t7, IRExpr_ITE(mkexpr(t3),
+ mkU32(0x00000004), mkU32(0)));
+ putDSPControl(IRExpr_ITE(mkexpr(t3),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x04000000)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xfbffffff))));
+
+ assign(t4, binop(Iop_CmpEQ32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ getIReg(rt))))));
+ assign(t8, IRExpr_ITE(mkexpr(t4),
+ mkU32(0x00000008), mkU32(0)));
+ putDSPControl(IRExpr_ITE(mkexpr(t4),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x08000000)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xf7ffffff))));
+
+ putIReg(rd, binop(Iop_Or32,
+ binop(Iop_Or32,
+ binop(Iop_Or32,
+ mkexpr(t5), mkexpr(t6)),
+ mkexpr(t7)),
+ mkexpr(t8)));
+ break;
+ }
+ case 0x19: { /* CMPGDU.LT.QB */
+ DIP("cmpgdu.lt.qb r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I1);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I1);
+ t5 = newTemp(Ity_I32);
+ t6 = newTemp(Ity_I32);
+ t7 = newTemp(Ity_I32);
+ t8 = newTemp(Ity_I32);
+
+ assign(t1, binop(Iop_CmpLT32U,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16,
+ getIReg(rt))))));
+ assign(t5, IRExpr_ITE(mkexpr(t1),
+ mkU32(0x00000001), mkU32(0)));
+ putDSPControl(IRExpr_ITE(mkexpr(t1),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x01000000)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xfeffffff))));
+
+ assign(t2, binop(Iop_CmpLT32U,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ getIReg(rt))))));
+ assign(t6, IRExpr_ITE(mkexpr(t2),
+ mkU32(0x00000002), mkU32(0)));
+ putDSPControl(IRExpr_ITE(mkexpr(t2),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x02000000)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xfdffffff))));
+
+ assign(t3, binop(Iop_CmpLT32U,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16,
+ getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16,
+ getIReg(rt))))));
+ assign(t7, IRExpr_ITE(mkexpr(t3),
+ mkU32(0x00000004), mkU32(0)));
+ putDSPControl(IRExpr_ITE(mkexpr(t3),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x04000000)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xfbffffff))));
+
+ assign(t4, binop(Iop_CmpLT32U,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ getIReg(rt))))));
+ assign(t8, IRExpr_ITE(mkexpr(t4),
+ mkU32(0x00000008), mkU32(0)));
+ putDSPControl(IRExpr_ITE(mkexpr(t4),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x08000000)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xf7ffffff))));
+
+ putIReg(rd, binop(Iop_Or32,
+ binop(Iop_Or32,
+ binop(Iop_Or32,
+ mkexpr(t5), mkexpr(t6)),
+ mkexpr(t7)),
+ mkexpr(t8)));
+ break;
+ }
+ case 0x1A: { /* CMPGDU.LE.QB */
+ DIP("cmpgdu.le.qb r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I1);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I1);
+ t5 = newTemp(Ity_I32);
+ t6 = newTemp(Ity_I32);
+ t7 = newTemp(Ity_I32);
+ t8 = newTemp(Ity_I32);
+
+ assign(t1, binop(Iop_CmpLE32U,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16,
+ getIReg(rt))))));
+ assign(t5, IRExpr_ITE(mkexpr(t1),
+ mkU32(0x00000001),
+ mkU32(0)));
+ putDSPControl(IRExpr_ITE(mkexpr(t1),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x01000000)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xfeffffff))));
+
+ assign(t2, binop(Iop_CmpLE32U,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ getIReg(rt))))));
+ assign(t6, IRExpr_ITE(mkexpr(t2),
+ mkU32(0x00000002), mkU32(0)));
+ putDSPControl(IRExpr_ITE(mkexpr(t2),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x02000000)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xfdffffff))));
+
+ assign(t3, binop(Iop_CmpLE32U,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16,
+ getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16,
+ getIReg(rt))))));
+ assign(t7, IRExpr_ITE(mkexpr(t3),
+ mkU32(0x00000004), mkU32(0)));
+ putDSPControl(IRExpr_ITE(mkexpr(t3),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x04000000)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xfbffffff))));
+
+ assign(t4, binop(Iop_CmpLE32U,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ getIReg(rt))))));
+ assign(t8, IRExpr_ITE(mkexpr(t4),
+ mkU32(0x00000008), mkU32(0)));
+ putDSPControl(IRExpr_ITE(mkexpr(t4),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x08000000)),
+ binop(Iop_And32,
+ getDSPControl(),
+ mkU32(0xf7ffffff))));
+
+ putIReg(rd, binop(Iop_Or32,
+ binop(Iop_Or32,
+ binop(Iop_Or32,
+ mkexpr(t5), mkexpr(t6)),
+ mkexpr(t7)),
+ mkexpr(t8)));
+ break;
+ }
+ default:
+ return -1;
+ }
+ break; /* end of CMPU.EQ.QB */
+ }
+ case 0x13: { /* SHLL.QB */
+ switch(sa) {
+ case 0x0: { /* SHLL.QB */
+ DIP("shll.qb r%d, r%d, %d", rd, rt, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I1);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I32);
+ t6 = newTemp(Ity_I1);
+ t7 = newTemp(Ity_I1);
+ t8 = newTemp(Ity_I1);
+ t9 = newTemp(Ity_I32);
+ t10 = newTemp(Ity_I32);
+ t11 = newTemp(Ity_I1);
+ t12 = newTemp(Ity_I1);
+ t13 = newTemp(Ity_I1);
+ t14 = newTemp(Ity_I32);
+ t15 = newTemp(Ity_I32);
+ t16 = newTemp(Ity_I1);
+ t17 = newTemp(Ity_I1);
+ t18 = newTemp(Ity_I32);
+
+ if (0 == rs) {
+ putIReg(rd, getIReg(rt));
+ } else {
+ /* Shift bits 7..0. */
+ assign(t0, binop(Iop_Shl32,
+ unop(Iop_8Uto32,
+ unop(Iop_32to8, getIReg(rt))),
+ unop(Iop_32to8,
+ binop(Iop_And32,
+ mkU32(rs),
+ mkU32(0x7)))));
+ /* Check if discard isn't 0x0 and 0xffffffff. */
+ assign(t1, binop(Iop_CmpNE32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ mkexpr(t0)))),
+ mkU32(0x00000000)));
+ assign(t2, binop(Iop_CmpNE32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ mkexpr(t0)))),
+ mkU32(0x000000ff)));
+ assign(t4, binop(Iop_Or32,
+ getDSPControl(), mkU32(0x400000)));
+ putDSPControl(IRExpr_ITE(mkexpr(t1),
+ IRExpr_ITE(mkexpr(t2),
+ mkexpr(t4),
+ getDSPControl()),
+ getDSPControl()));
+
+ /* Shift bits 15..8. */
+ assign(t5, binop(Iop_Shl32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ getIReg(rt)))),
+ unop(Iop_32to8,
+ binop(Iop_And32,
+ mkU32(rs),
+ mkU32(0x7)))));
+ /* Check if discard isn't 0x0 and 0xffffffff. */
+ assign(t6, binop(Iop_CmpNE32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ mkexpr(t5)))),
+ mkU32(0x00000000)));
+ assign(t7, binop(Iop_CmpNE32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ mkexpr(t5)))),
+ mkU32(0x000000ff)));
+ assign(t9, binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x400000)));
+ putDSPControl(IRExpr_ITE(mkexpr(t6),
+ IRExpr_ITE(mkexpr(t7),
+ mkexpr(t9),
+ getDSPControl()),
+ getDSPControl()));
+
+ /* Shift bits 23..16. */
+ assign(t10, binop(Iop_Shl32,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16,
+ getIReg(rt)))),
+ unop(Iop_32to8,
+ binop(Iop_And32,
+ mkU32(rs),
+ mkU32(0x7)))));
+ /* Check if discard isn't 0x0 and 0xffffffff. */
+ assign(t11, binop(Iop_CmpNE32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ mkexpr(t10)))),
+ mkU32(0x00000000)));
+ assign(t12, binop(Iop_CmpNE32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ mkexpr(t10)))),
+ mkU32(0x000000ff)));
+
+ assign(t14, binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x400000)));
+ putDSPControl(IRExpr_ITE(mkexpr(t11),
+ IRExpr_ITE(mkexpr(t12),
+ mkexpr(t14),
+ getDSPControl()),
+ getDSPControl()));
+
+ /* Shift bits 31..24. */
+ assign(t15, binop(Iop_Shl32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ getIReg(rt)))),
+ unop(Iop_32to8,
+ binop(Iop_And32,
+ mkU32(rs),
+ mkU32(0x7)))));
+ /* Check if discard isn't 0x0 and 0xffffffff. */
+ assign(t16, binop(Iop_CmpNE32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ mkexpr(t15)))),
+ mkU32(0x00000000)));
+ assign(t17, binop(Iop_CmpNE32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ mkexpr(t15)))),
+ mkU32(0x000000ff)));
+
+ assign(t18, binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x400000)));
+ putDSPControl(IRExpr_ITE(mkexpr(t16),
+ IRExpr_ITE(mkexpr(t17),
+ mkexpr(t18),
+ getDSPControl()),
+ getDSPControl()));
+
+ putIReg(rd, binop(Iop_16HLto32,
+ binop(Iop_8HLto16,
+ unop(Iop_32to8, mkexpr(t15)),
+ unop(Iop_32to8, mkexpr(t10))),
+ binop(Iop_8HLto16,
+ unop(Iop_32to8, mkexpr(t5)),
+ unop(Iop_32to8, mkexpr(t0)))));
+ }
+ break;
+ }
+ case 0x3: { /* SHRL.QB */
+ DIP("shrl.qb r%d, r%d, %d", rd, rt, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I8);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I8);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I8);
+ t6 = newTemp(Ity_I32);
+ t7 = newTemp(Ity_I8);
+ t9 = newTemp(Ity_I32);
+
+ assign(t9, binop(Iop_And32, getIReg(rs), mkU32(0x7)));
+ assign(t0, unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16, getIReg(rt)))));
+ assign(t1, unop(Iop_32to8,
+ binop(Iop_Shr32,
+ mkexpr(t0),
+ unop(Iop_32to8, mkexpr(t9)))));
+
+ assign(t2, unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, getIReg(rt)))));
+ assign(t3, unop(Iop_32to8,
+ binop(Iop_Shr32,
+ mkexpr(t2),
+ unop(Iop_32to8, mkexpr(t9)))));
+
+ assign(t4, unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16, getIReg(rt)))));
+ assign(t5, unop(Iop_32to8,
+ binop(Iop_Shr32,
+ mkexpr(t4),
+ unop(Iop_32to8, mkexpr(t9)))));
+
+ assign(t6, unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16, getIReg(rt)))));
+ assign(t7, unop(Iop_32to8,
+ binop(Iop_Shr32,
+ mkexpr(t6),
+ unop(Iop_32to8, mkexpr(t9)))));
+ putIReg(rd, IRExpr_ITE(binop(Iop_CmpEQ32,
+ mkexpr(t9),
+ mkU32(0x0)),
+ getIReg(rt),
+ binop(Iop_16HLto32,
+ binop(Iop_8HLto16,
+ mkexpr(t7),
+ mkexpr(t5)),
+ binop(Iop_8HLto16,
+ mkexpr(t3),
+ mkexpr(t1)))));
+ break;
+ }
+ case 0x2: { /* SHLLV.QB */
+ DIP("shllv.qb r%d, r%d, r%d", rd, rt, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I1);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I32);
+ t6 = newTemp(Ity_I1);
+ t7 = newTemp(Ity_I1);
+ t8 = newTemp(Ity_I1);
+ t9 = newTemp(Ity_I32);
+ t10 = newTemp(Ity_I32);
+ t11 = newTemp(Ity_I1);
+ t12 = newTemp(Ity_I1);
+ t13 = newTemp(Ity_I1);
+ t14 = newTemp(Ity_I32);
+ t15 = newTemp(Ity_I32);
+ t16 = newTemp(Ity_I1);
+ t17 = newTemp(Ity_I1);
+ t18 = newTemp(Ity_I32);
+
+ /* Shift bits 7..0. */
+ assign(t0, binop(Iop_Shl32,
+ unop(Iop_8Uto32,
+ unop(Iop_32to8, getIReg(rt))),
+ unop(Iop_32to8,
+ binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x7)))));
+ /* Check if discard isn't 0x0 and 0xffffffff. */
+ assign(t1, binop(Iop_CmpNE32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, mkexpr(t0)))),
+ mkU32(0x00000000)));
+ assign(t2, binop(Iop_CmpNE32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, mkexpr(t0)))),
+ mkU32(0x000000ff)));
+
+ assign(t4, binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x400000)));
+ putDSPControl(IRExpr_ITE(mkexpr(t1),
+ IRExpr_ITE(mkexpr(t2),
+ mkexpr(t4),
+ getDSPControl()),
+ getDSPControl()));
+
+ /* Shift bits 15..8. */
+ assign(t5, binop(Iop_Shl32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, getIReg(rt)))),
+ unop(Iop_32to8,
+ binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x7)))));
+ /* Check if discard isn't 0x0 and 0xffffffff. */
+ assign(t6, binop(Iop_CmpNE32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, mkexpr(t5)))),
+ mkU32(0x00000000)));
+ assign(t7, binop(Iop_CmpNE32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, mkexpr(t5)))),
+ mkU32(0x000000ff)));
+
+ assign(t9, binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x400000)));
+ putDSPControl(IRExpr_ITE(mkexpr(t6),
+ IRExpr_ITE(mkexpr(t7),
+ mkexpr(t9),
+ getDSPControl()),
+ getDSPControl()));
+
+ /* Shift bits 23..16. */
+ assign(t10, binop(Iop_Shl32,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16,
+ getIReg(rt)))),
+ unop(Iop_32to8,
+ binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x7)))));
+ /* Check if discard isn't 0x0 and 0xffffffff. */
+ assign(t11, binop(Iop_CmpNE32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ mkexpr(t10)))),
+ mkU32(0x00000000)));
+ assign(t12, binop(Iop_CmpNE32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ mkexpr(t10)))),
+ mkU32(0x000000ff)));
+
+ assign(t14, binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x400000)));
+ putDSPControl(IRExpr_ITE(mkexpr(t11),
+ IRExpr_ITE(mkexpr(t12),
+ mkexpr(t14),
+ getDSPControl()),
+ getDSPControl()));
+
+ /* Shift bits 31..24. */
+ assign(t15, binop(Iop_Shl32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ getIReg(rt)))),
+ unop(Iop_32to8,
+ binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x7)))));
+ /* Check if discard isn't 0x0 and 0xffffffff. */
+ assign(t16, binop(Iop_CmpNE32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ mkexpr(t15)))),
+ mkU32(0x00000000)));
+ assign(t17, binop(Iop_CmpNE32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ mkexpr(t15)))),
+ mkU32(0x000000ff)));
+
+ assign(t18, binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x400000)));
+ putDSPControl(IRExpr_ITE(mkexpr(t16),
+ IRExpr_ITE(mkexpr(t17),
+ mkexpr(t18),
+ getDSPControl()),
+ getDSPControl()));
+
+ putIReg(rd, IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x7)),
+ mkU32(0x0)),
+ getIReg(rt),
+ binop(Iop_16HLto32,
+ binop(Iop_8HLto16,
+ unop(Iop_32to8,
+ mkexpr(t15)),
+ unop(Iop_32to8,
+ mkexpr(t10))),
+ binop(Iop_8HLto16,
+ unop(Iop_32to8,
+ mkexpr(t5)),
+ unop(Iop_32to8,
+ mkexpr(t0))))));
+ break;
+ }
+ case 0x1: { /* SHRLV.QB */
+ DIP("shrlv.qb r%d, r%d, r%d", rd, rt, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I8);
+ t1 = newTemp(Ity_I8);
+ t2 = newTemp(Ity_I8);
+ t3 = newTemp(Ity_I8);
+
+ assign(t0, unop(Iop_32to8,
+ binop(Iop_Shr32,
+ unop(Iop_8Uto32,
+ unop(Iop_32to8, getIReg(rt))),
+ mkU8(rs))));
+ assign(t1, unop(Iop_32to8,
+ binop(Iop_Shr32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16,
+ getIReg(rt)))),
+ mkU8(rs))));
+ assign(t2, unop(Iop_32to8,
+ binop(Iop_Shr32,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16,
+ getIReg(rt)))),
+ mkU8(rs))));
+ assign(t3, unop(Iop_32to8,
+ binop(Iop_Shr32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16,
+ getIReg(rt)))),
+ mkU8(rs))));
+ putIReg(rd,
+ binop(Iop_16HLto32,
+ binop(Iop_8HLto16, mkexpr(t3), mkexpr(t2)),
+ binop(Iop_8HLto16, mkexpr(t1), mkexpr(t0))));
+ break;
+ }
+ case 0x4: { /* SHRA.QB */
+ DIP("shra.qb r%d, r%d, %d", rd, rt, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I32);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I32);
+ t6 = newTemp(Ity_I32);
+ t7 = newTemp(Ity_I32);
+ t8 = newTemp(Ity_I32);
+ t9 = newTemp(Ity_I32);
+ t10 = newTemp(Ity_I32);
+ t11 = newTemp(Ity_I32);
+
+ /* ========== GPR[rt]_31..24 ========== */
+ assign(t1,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16, getIReg(rt)))));
+ assign(t2,
+ binop(Iop_Shr32, mkexpr(t1), mkU8(rs)));
+ /* tempD_7..0 */
+ assign(t0,
+ binop(Iop_Or32,
+ mkexpr(t2),
+ binop(Iop_Shl32,
+ IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkexpr(t1),
+ mkU32(0x00000080)
+ ),
+ mkU32(0x00000080)),
+ mkU32(0xFFFFFFFF),
+ mkU32(0x00000000)),
+ binop(Iop_Sub8, mkU8(0x8), mkU8(rs)))));
+
+ /* ========== GPR[rt]_23..16 ========== */
+ assign(t4,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16, getIReg(rt)))));
+ assign(t5, binop(Iop_Shr32, mkexpr(t4), mkU8(rs)));
+ /* tempC_7..0 */
+ assign(t3,
+ binop(Iop_Or32,
+ mkexpr(t5),
+ binop(Iop_Shl32,
+ IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkexpr(t4),
+ mkU32(0x00000080)
+ ),
+ mkU32(0x00000080)),
+ mkU32(0xFFFFFFFF),
+ mkU32(0x00000000)),
+ binop(Iop_Sub8, mkU8(0x8), mkU8(rs)))));
+
+ /* ========== GPR[rt]_15..8 ========== */
+ assign(t7,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, getIReg(rt)))));
+ assign(t8, binop(Iop_Shr32, mkexpr(t7), mkU8(rs)));
+ /* tempB_7..0 */
+ assign(t6,
+ binop(Iop_Or32,
+ mkexpr(t8),
+ binop(Iop_Shl32,
+ IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkexpr(t7),
+ mkU32(0x00000080)
+ ),
+ mkU32(0x00000080)),
+ mkU32(0xFFFFFFFF),
+ mkU32(0x00000000)),
+ binop(Iop_Sub8, mkU8(0x8), mkU8(rs)))));
+
+ /* ========== GPR[rt]_7..0 ========== */
+ assign(t10,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16, getIReg(rt)))));
+ assign(t11, binop(Iop_Shr32, mkexpr(t10), mkU8(rs)));
+ /* tempB_7..0 */
+ assign(t9,
+ binop(Iop_Or32,
+ mkexpr(t11),
+ binop(Iop_Shl32,
+ IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkexpr(t10),
+ mkU32(0x00000080)
+ ),
+ mkU32(0x00000080)),
+ mkU32(0xFFFFFFFF),
+ mkU32(0x00000000)),
+ binop(Iop_Sub8, mkU8(0x8), mkU8(rs)))));
+
+ putIReg(rd,
+ binop(Iop_16HLto32,
+ binop(Iop_8HLto16,
+ unop(Iop_32to8, mkexpr(t0)),
+ unop(Iop_32to8, mkexpr(t3))),
+ binop(Iop_8HLto16,
+ unop(Iop_32to8, mkexpr(t6)),
+ unop(Iop_32to8, mkexpr(t9)))));
+ break;
+ }
+ case 0x5: { /* SHRA_R.QB */
+ DIP("shra_r.qb r%d, r%d, %d", rd, rt, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I8);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I8);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I8);
+ t6 = newTemp(Ity_I32);
+ t7 = newTemp(Ity_I8);
+
+ if (0 == rs) {
+ putIReg(rd, getIReg(rt));
+ } else {
+ assign(t0, unop(Iop_8Sto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16, getIReg(rt)))));
+ assign(t1, unop(Iop_32to8,
+ binop(Iop_Sar32,
+ binop(Iop_Add32,
+ mkexpr(t0),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkU8(rs-1))),
+ mkU8(rs))));
+
+ assign(t2, unop(Iop_8Sto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, getIReg(rt)))));
+ assign(t3, unop(Iop_32to8,
+ binop(Iop_Sar32,
+ binop(Iop_Add32,
+ mkexpr(t2),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkU8(rs-1))),
+ mkU8(rs))));
+
+ assign(t4, unop(Iop_8Sto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16, getIReg(rt)))));
+ assign(t5, unop(Iop_32to8,
+ binop(Iop_Sar32,
+ binop(Iop_Add32,
+ mkexpr(t4),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkU8(rs-1))),
+ mkU8(rs))));
+
+ assign(t6, unop(Iop_8Sto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16, getIReg(rt)))));
+ assign(t7, unop(Iop_32to8,
+ binop(Iop_Sar32,
+ binop(Iop_Add32,
+ mkexpr(t6),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkU8(rs-1))),
+ mkU8(rs))));
+ putIReg(rd, binop(Iop_16HLto32,
+ binop(Iop_8HLto16,
+ mkexpr(t7), mkexpr(t5)),
+ binop(Iop_8HLto16,
+ mkexpr(t3), mkexpr(t1))));
+ }
+ break;
+ }
+ case 0x6: { /* SHRAV.QB */
+ DIP("shrav.qb r%d, r%d, %d", rd, rt, rs);
+ vassert(!mode64);
+
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+
+ t3 = newTemp(Ity_I32);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I32);
+
+ t6 = newTemp(Ity_I32);
+ t7 = newTemp(Ity_I32);
+ t8 = newTemp(Ity_I32);
+
+ t9 = newTemp(Ity_I32);
+ t10 = newTemp(Ity_I32);
+ t11 = newTemp(Ity_I32);
+
+ /* ========== GPR[rt]_31..24 ========== */
+ assign(t1,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16, getIReg(rt)))));
+ assign(t2,
+ binop(Iop_Shr32,
+ mkexpr(t1),
+ unop(Iop_32to8, binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x7)))));
+ /* tempD_7..0 */
+ assign(t0,
+ binop(Iop_Or32,
+ mkexpr(t2),
+ binop(Iop_Shl32,
+ IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkexpr(t1),
+ mkU32(0x00000080)
+ ),
+ mkU32(0x00000080)),
+ mkU32(0xFFFFFFFF),
+ mkU32(0x00000000)),
+ binop(Iop_Sub8,
+ mkU8(0x8),
+ unop(Iop_32to8, binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x7)))
+ ))));
+
+ /* ========== GPR[rt]_23..16 ========== */
+ assign(t4,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16, getIReg(rt)))));
+ assign(t5,
+ binop(Iop_Shr32,
+ mkexpr(t4),
+ unop(Iop_32to8, binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x7)))));
+ /* tempC_7..0 */
+ assign(t3,
+ binop(Iop_Or32,
+ mkexpr(t5),
+ binop(Iop_Shl32,
+ IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkexpr(t4),
+ mkU32(0x00000080)
+ ),
+ mkU32(0x00000080)),
+ mkU32(0xFFFFFFFF),
+ mkU32(0x00000000)),
+ binop(Iop_Sub8,
+ mkU8(0x8),
+ unop(Iop_32to8, binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x7)))
+ ))));
+
+ /* ========== GPR[rt]_15..8 ========== */
+ assign(t7,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, getIReg(rt)))));
+ assign(t8,
+ binop(Iop_Shr32,
+ mkexpr(t7),
+ unop(Iop_32to8, binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x7)))));
+ /* tempB_7..0 */
+ assign(t6,
+ binop(Iop_Or32,
+ mkexpr(t8),
+ binop(Iop_Shl32,
+ IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkexpr(t7),
+ mkU32(0x00000080)
+ ),
+ mkU32(0x00000080)),
+ mkU32(0xFFFFFFFF),
+ mkU32(0x00000000)),
+ binop(Iop_Sub8,
+ mkU8(0x8),
+ unop(Iop_32to8, binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x7)))
+ ))));
+
+ /* ========== GPR[rt]_7..0 ========== */
+ assign(t10,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16, getIReg(rt)))));
+ assign(t11,
+ binop(Iop_Shr32,
+ mkexpr(t10),
+ unop(Iop_32to8, binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x7)))));
+ /* tempB_7..0 */
+ assign(t9,
+ binop(Iop_Or32,
+ mkexpr(t11),
+ binop(Iop_Shl32,
+ IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkexpr(t10),
+ mkU32(0x00000080)
+ ),
+ mkU32(0x00000080)),
+ mkU32(0xFFFFFFFF),
+ mkU32(0x00000000)),
+ binop(Iop_Sub8,
+ mkU8(0x8),
+ unop(Iop_32to8, binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x7)))
+ ))));
+
+ putIReg(rd,
+ binop(Iop_16HLto32,
+ binop(Iop_8HLto16,
+ unop(Iop_32to8,
+ IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkU32(rs),
+ mkU32(0x7)
+ ),
+ mkU32(0x0)),
+ mkexpr(t1),
+ mkexpr(t0))),
+ unop(Iop_32to8,
+ IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkU32(rs),
+ mkU32(0x7)
+ ),
+ mkU32(0x0)),
+ mkexpr(t2),
+ mkexpr(t3)))),
+ binop(Iop_8HLto16,
+ unop(Iop_32to8,
+ IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkU32(rs),
+ mkU32(0x7)
+ ),
+ mkU32(0x0)),
+ mkexpr(t5),
+ mkexpr(t6))),
+ unop(Iop_32to8,
+ IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkU32(rs),
+ mkU32(0x7)
+ ),
+ mkU32(0x0)),
+ mkexpr(t8),
+ mkexpr(t9))))));
+ break;
+ }
+ case 0x7: { /* SHRAV_R.QB */
+ DIP("shrav_r.qb r%d, r%d, r%d", rd, rt, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I8);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I8);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I8);
+ t6 = newTemp(Ity_I32);
+ t7 = newTemp(Ity_I8);
+ t8 = newTemp(Ity_I8);
+ t9 = newTemp(Ity_I32);
+
+ assign(t9, binop(Iop_And32, getIReg(rs), mkU32(0x7)));
+ assign(t8, unop(Iop_32to8,
+ binop(Iop_Sub32, mkexpr(t9), mkU32(0x1))));
+ assign(t0, unop(Iop_8Sto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16, getIReg(rt)))));
+ assign(t1, unop(Iop_32to8,
+ binop(Iop_Sar32,
+ binop(Iop_Add32,
+ mkexpr(t0),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkexpr(t8))),
+ unop(Iop_32to8,
+ mkexpr(t9)))));
+
+ assign(t2, unop(Iop_8Sto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, getIReg(rt)))));
+ assign(t3, unop(Iop_32to8,
+ binop(Iop_Sar32,
+ binop(Iop_Add32,
+ mkexpr(t2),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkexpr(t8))),
+ unop(Iop_32to8, mkexpr(t9)))));
+
+ assign(t4, unop(Iop_8Sto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16, getIReg(rt)))));
+ assign(t5, unop(Iop_32to8,
+ binop(Iop_Sar32,
+ binop(Iop_Add32,
+ mkexpr(t4),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkexpr(t8))),
+ unop(Iop_32to8, mkexpr(t9)))));
+
+ assign(t6, unop(Iop_8Sto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16, getIReg(rt)))));
+ assign(t7, unop(Iop_32to8,
+ binop(Iop_Sar32,
+ binop(Iop_Add32,
+ mkexpr(t6),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkexpr(t8))),
+ unop(Iop_32to8, mkexpr(t9)))));
+ putIReg(rd, IRExpr_ITE(binop(Iop_CmpEQ32,
+ mkexpr(t9),
+ mkU32(0x0)),
+ getIReg(rt),
+ binop(Iop_16HLto32,
+ binop(Iop_8HLto16,
+ mkexpr(t7),
+ mkexpr(t5)),
+ binop(Iop_8HLto16,
+ mkexpr(t3),
+ mkexpr(t1)))));
+ break;
+ }
+ case 0x8: { /* SHLL.PH */
+ DIP("shll.ph r%d, r%d, %d", rd, rt, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I32);
+ t4 = newTemp(Ity_I1);
+
+ if (0 == rs) {
+ putIReg(rd, getIReg(rt));
+ } else {
+ /* Shift lower 16 bits. */
+ assign(t0, binop(Iop_Shl32,
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rt))),
+ mkU8(rs)));
+
+ assign(t2, IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16,
+ mkexpr(t0))),
+ mkU32(0xffffffff)),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x400000)),
+ getDSPControl()));
+ putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16,
+ mkexpr(t0))),
+ mkU32(0x00000000)),
+ mkexpr(t2),
+ getDSPControl()));
+ putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x00008000)),
+ binop(Iop_And32,
+ mkexpr(t0),
+ mkU32(0x00008000))
+ ),
+ getDSPControl(),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x400000))));
+ /* Shift higher 16 bits. */
+ assign(t1, binop(Iop_Shl32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rt))),
+ mkU8(rs)));
+
+ assign(t3, IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16,
+ mkexpr(t1))),
+ mkU32(0xffffffff)),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x400000)),
+ getDSPControl()));
+ putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16,
+ mkexpr(t1))),
+ mkU32(0x00000000)),
+ mkexpr(t3),
+ getDSPControl()));
+ assign(t4, binop(Iop_CmpEQ32,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x80000000)),
+ mkU8(31)),
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ mkexpr(t1),
+ mkU32(0x00008000)),
+ mkU8(15))));
+ putDSPControl(IRExpr_ITE(mkexpr(t4),
+ getDSPControl(),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x400000))));
+
+ putIReg(rd, binop(Iop_16HLto32,
+ unop(Iop_32to16, mkexpr(t1)),
+ unop(Iop_32to16, mkexpr(t0))));
+ }
+ break;
+ }
+ case 0x9: { /* SHRA.PH */
+ DIP("shra.ph r%d, r%d, %d", rd, rt, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I32);
+ if (0 == rs) {
+ putIReg(rd, getIReg(rt));
+ } else {
+ assign(t0, binop(Iop_Sar32,
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rt))),
+ mkU8(rs)));
+ assign(t1, binop(Iop_Sar32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rt))),
+ mkU8(rs)));
+ putIReg(rd, binop(Iop_16HLto32,
+ unop(Iop_32to16, mkexpr(t1)),
+ unop(Iop_32to16, mkexpr(t0))));
+ }
+ break;
+ }
+ case 0xA: { /* SHLLV.PH */
+ DIP("shllv.ph r%d, r%d, r%d", rd, rt, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I1);
+ t5 = newTemp(Ity_I32);
+ t6 = newTemp(Ity_I32);
+ t7 = newTemp(Ity_I1);
+ t8 = newTemp(Ity_I1);
+ t9 = newTemp(Ity_I32);
+ t10 = newTemp(Ity_I32);
+ t11 = newTemp(Ity_I32);
+ t12 = newTemp(Ity_I1);
+ t13 = newTemp(Ity_I1);
+
+ assign(t0, binop(Iop_And32, getIReg(rs), mkU32(0x0f)));
+
+ /* Shift lower 16 bits. */
+ assign(t2, binop(Iop_Shl32,
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rt))),
+ unop(Iop_32to8, mkexpr(t0))));
+
+ assign(t3, binop(Iop_CmpNE32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, mkexpr(t2))),
+ mkU32(0x00000000)));
+ assign(t4, binop(Iop_CmpNE32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, mkexpr(t2))),
+ mkU32(0xffffffff)));
+ assign(t10, binop(Iop_And32,
+ unop(Iop_1Sto32, mkexpr(t3)),
+ unop(Iop_1Sto32, mkexpr(t4))));
+ assign(t5, binop(Iop_Shr32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x00008000)),
+ mkU8(15)));
+ assign(t12, binop(Iop_CmpEQ32,
+ mkexpr(t5),
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ mkexpr(t2),
+ mkU32(0x00008000)),
+ mkU8(15))));
+
+ putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
+ mkexpr(t10),
+ mkU32(0x0)),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x400000)),
+ IRExpr_ITE(mkexpr(t12),
+ getDSPControl(),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x400000)))
+ ));
+ /* Shift higher 16 bits. */
+ assign(t6, binop(Iop_Shl32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rt))),
+ unop(Iop_32to8, mkexpr(t0))));
+
+ assign(t7, binop(Iop_CmpNE32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, mkexpr(t6))),
+ mkU32(0x00000000)));
+ assign(t8, binop(Iop_CmpNE32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, mkexpr(t6))),
+ mkU32(0xffffffff)));
+ assign(t11, binop(Iop_And32,
+ unop(Iop_1Sto32, mkexpr(t7)),
+ unop(Iop_1Sto32, mkexpr(t8))));
+
+ assign(t9, binop(Iop_Shr32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x80000000)),
+ mkU8(31)));
+ assign(t13, binop(Iop_CmpEQ32,
+ mkexpr(t9),
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ mkexpr(t6),
+ mkU32(0x00008000)),
+ mkU8(15))));
+
+ putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
+ mkexpr(t11),
+ mkU32(0x0)),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x400000)),
+ IRExpr_ITE(mkexpr(t13),
+ getDSPControl(),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x400000)))
+ ));
+
+ putIReg(rd, binop(Iop_16HLto32,
+ unop(Iop_32to16, mkexpr(t6)),
+ unop(Iop_32to16, mkexpr(t2))));
+ break;
+ }
+ case 0xB: { /* SHRAV.PH */
+ DIP("shrav.ph r%d, r%d, r%d", rd, rt, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I32);
+
+ assign(t0, binop(Iop_And32, getIReg(rs), mkU32(0x0f)));
+ assign(t1, binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x0)));
+ assign(t2, binop(Iop_Sar32,
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rt))),
+ unop(Iop_32to8, mkexpr(t0))));
+ assign(t3, binop(Iop_Sar32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rt))),
+ unop(Iop_32to8, mkexpr(t0))));
+ putIReg(rd,
+ binop(Iop_16HLto32,
+ IRExpr_ITE(mkexpr(t1),
+ unop(Iop_32HIto16, getIReg(rt)),
+ unop(Iop_32to16, mkexpr(t3))),
+ IRExpr_ITE(mkexpr(t1),
+ unop(Iop_32to16, getIReg(rt)),
+ unop(Iop_32to16, mkexpr(t2)))));
+ break;
+ }
+ case 0xC: { /* SHLL_S.PH */
+ DIP("shll_s.ph r%d, r%d, %d", rd, rt, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I16);
+ t2 = newTemp(Ity_I16);
+ t3 = newTemp(Ity_I16);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I16);
+ t6 = newTemp(Ity_I16);
+ t7 = newTemp(Ity_I16);
+ t8 = newTemp(Ity_I32);
+ t9 = newTemp(Ity_I32);
+ t10 = newTemp(Ity_I1);
+ t11 = newTemp(Ity_I32);
+ t12 = newTemp(Ity_I32);
+
+ if (0 == rs) {
+ putIReg(rd, getIReg(rt));
+ } else {
+ /* Shift lower 16 bits. */
+ assign(t0, binop(Iop_Shl32,
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rt))),
+ mkU8(rs)));
+
+ assign(t1, IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x00008000)),
+ mkU32(0x0)),
+ mkU16(0x7fff),
+ mkU16(0x8000)));
+ assign(t2,
+ IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x00008000)),
+ mkU8(15)),
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ mkexpr(t0),
+ mkU32(0x00008000)),
+ mkU8(15))),
+ unop(Iop_32to16, mkexpr(t0)),
+ mkexpr(t1)));
+ assign(t11, IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16,
+ mkexpr(t0))),
+ mkU32(0xffffffff)),
+ mkexpr(t1),
+ mkexpr(t2)));
+ assign(t3,
+ IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16,
+ mkexpr(t0))),
+ mkU32(0x00000000)),
+ mkexpr(t11),
+ mkexpr(t2)));
+ assign(t8, IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16,
+ mkexpr(t0))),
+ mkU32(0xffffffff)),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x400000)),
+ getDSPControl()));
+ putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16,
+ mkexpr(t0))),
+ mkU32(0x00000000)),
+ mkexpr(t8),
+ getDSPControl()));
+ putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x00008000)),
+ binop(Iop_And32,
+ mkexpr(t0),
+ mkU32(0x00008000))),
+ getDSPControl(),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x400000))));
+ /* Shift higher 16 bits. */
+ assign(t4, binop(Iop_Shl32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rt))),
+ mkU8(rs)));
+
+ assign(t5, IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x80000000)),
+ mkU32(0x0)),
+ mkU16(0x7fff),
+ mkU16(0x8000)));
+ assign(t6,
+ IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x80000000)),
+ mkU8(31)),
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ mkexpr(t4),
+ mkU32(0x00008000)),
+ mkU8(15))),
+ unop(Iop_32to16, mkexpr(t4)),
+ mkexpr(t5)));
+ assign(t12, IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16,
+ mkexpr(t4))),
+ mkU32(0xffffffff)),
+ mkexpr(t5),
+ mkexpr(t6)));
+ assign(t7,
+ IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16,
+ mkexpr(t4))),
+ mkU32(0x00000000)),
+ mkexpr(t12),
+ mkexpr(t6)));
+ assign(t9, IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16,
+ mkexpr(t4))),
+ mkU32(0xffffffff)),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x400000)),
+ getDSPControl()));
+ putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16,
+ mkexpr(t4))),
+ mkU32(0x00000000)),
+ mkexpr(t9),
+ getDSPControl()));
+ assign(t10, binop(Iop_CmpEQ32,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x80000000)),
+ mkU8(31)),
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ mkexpr(t4),
+ mkU32(0x00008000)),
+ mkU8(15))));
+ putDSPControl(IRExpr_ITE(mkexpr(t10),
+ getDSPControl(),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x400000))));
+
+ putIReg(rd, binop(Iop_16HLto32,
+ mkexpr(t7), mkexpr(t3)));
+ }
+ break;
+ }
+ case 0xD: { /* SHRA_R.PH */
+ DIP("shra.ph r%d, r%d, %d", rd, rt, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I32);
+ if (0 == rs) {
+ putIReg(rd, getIReg(rt));
+ } else {
+ assign(t0, binop(Iop_Sar32,
+ binop(Iop_Add32,
+ unop(Iop_16Sto32,
+ unop(Iop_32to16,
+ getIReg(rt))),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkU8(rs-1))),
+ mkU8(rs)));
+ assign(t1, binop(Iop_Sar32,
+ binop(Iop_Add32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16,
+ getIReg(rt))),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkU8(rs-1))),
+ mkU8(rs)));
+ putIReg(rd, binop(Iop_16HLto32,
+ unop(Iop_32to16, mkexpr(t1)),
+ unop(Iop_32to16, mkexpr(t0))));
+ }
+ break;
+ }
+ case 0xE: { /* SHLLV_S.PH */
+ DIP("shllv_s.ph r%d, r%d, r%d", rd, rt, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I1);
+ t5 = newTemp(Ity_I32);
+ t6 = newTemp(Ity_I32);
+ t7 = newTemp(Ity_I1);
+ t8 = newTemp(Ity_I1);
+ t9 = newTemp(Ity_I32);
+ t10 = newTemp(Ity_I32);
+ t11 = newTemp(Ity_I32);
+ t12 = newTemp(Ity_I1);
+ t13 = newTemp(Ity_I1);
+ t14 = newTemp(Ity_I16);
+ t15 = newTemp(Ity_I16);
+ t16 = newTemp(Ity_I16);
+ t17 = newTemp(Ity_I16);
+
+ assign(t0, binop(Iop_And32, getIReg(rs), mkU32(0x0f)));
+
+ /* Shift lower 16 bits. */
+ assign(t2, binop(Iop_Shl32,
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rt))),
+ unop(Iop_32to8, mkexpr(t0))));
+
+ assign(t3, binop(Iop_CmpNE32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, mkexpr(t2))),
+ mkU32(0x00000000)));
+ assign(t4, binop(Iop_CmpNE32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, mkexpr(t2))),
+ mkU32(0xffffffff)));
+ assign(t10, binop(Iop_And32,
+ unop(Iop_1Sto32, mkexpr(t3)),
+ unop(Iop_1Sto32, mkexpr(t4))));
+ assign(t5, binop(Iop_Shr32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x00008000)),
+ mkU8(15)));
+ assign(t12, binop(Iop_CmpEQ32,
+ mkexpr(t5),
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ mkexpr(t2),
+ mkU32(0x00008000)),
+ mkU8(15))));
+
+ putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
+ mkexpr(t10),
+ mkU32(0x0)),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x400000)),
+ IRExpr_ITE(mkexpr(t12),
+ getDSPControl(),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x400000)))
+ ));
+ assign(t14, IRExpr_ITE(binop(Iop_CmpNE32,
+ mkexpr(t5),
+ mkU32(0x0)),
+ mkU16(0x8000),
+ mkU16(0x7fff)));
+ assign(t15, IRExpr_ITE(binop(Iop_CmpNE32,
+ mkexpr(t10),
+ mkU32(0x0)),
+ mkexpr(t14),
+ IRExpr_ITE(mkexpr(t12),
+ unop(Iop_32to16,
+ mkexpr(t2)),
+ mkexpr(t14))));
+ /* Shift higher 16 bits. */
+ assign(t6, binop(Iop_Shl32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rt))),
+ unop(Iop_32to8, mkexpr(t0))));
+
+ assign(t7, binop(Iop_CmpNE32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, mkexpr(t6))),
+ mkU32(0x00000000)));
+ assign(t8, binop(Iop_CmpNE32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, mkexpr(t6))),
+ mkU32(0xffffffff)));
+ assign(t11, binop(Iop_And32,
+ unop(Iop_1Sto32, mkexpr(t7)),
+ unop(Iop_1Sto32, mkexpr(t8))));
+
+ assign(t9, binop(Iop_Shr32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x80000000)),
+ mkU8(31)));
+ assign(t13, binop(Iop_CmpEQ32,
+ mkexpr(t9),
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ mkexpr(t6),
+ mkU32(0x00008000)),
+ mkU8(15))));
+
+ putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
+ mkexpr(t11),
+ mkU32(0x0)),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x400000)),
+ IRExpr_ITE(mkexpr(t13),
+ getDSPControl(),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x400000)))
+ ));
+
+ assign(t16, IRExpr_ITE(binop(Iop_CmpNE32,
+ mkexpr(t9),
+ mkU32(0x0)),
+ mkU16(0x8000),
+ mkU16(0x7fff)));
+ assign(t17, IRExpr_ITE(binop(Iop_CmpNE32,
+ mkexpr(t11),
+ mkU32(0x0)),
+ mkexpr(t16),
+ IRExpr_ITE(mkexpr(t13),
+ unop(Iop_32to16,
+ mkexpr(t6)),
+ mkexpr(t16))));
+
+ putIReg(rd, binop(Iop_16HLto32, mkexpr(t17), mkexpr(t15)));
+ break;
+ }
+ case 0xF: { /* SHRAV_R.PH */
+ DIP("shrav_r.ph r%d, r%d, r%d", rd, rt, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I8);
+ t3 = newTemp(Ity_I32);
+ t4 = newTemp(Ity_I32);
+
+ assign(t0, binop(Iop_And32, getIReg(rs), mkU32(0x0f)));
+ assign(t1, binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x0)));
+ assign(t2, unop(Iop_32to8,
+ binop(Iop_Sub32, mkexpr(t0), mkU32(1))));
+
+ assign(t3, binop(Iop_Sar32,
+ binop(Iop_Add32,
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rt))),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkexpr(t2))),
+ unop(Iop_32to8, mkexpr(t0))));
+ assign(t4, binop(Iop_Sar32,
+ binop(Iop_Add32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16,
+ getIReg(rt))),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkexpr(t2))),
+ unop(Iop_32to8, mkexpr(t0))));
+
+ putIReg(rd, binop(Iop_16HLto32,
+ IRExpr_ITE(mkexpr(t1),
+ unop(Iop_32HIto16,
+ getIReg(rt)),
+ unop(Iop_32to16,
+ mkexpr(t4))),
+ IRExpr_ITE(mkexpr(t1),
+ unop(Iop_32to16, getIReg(rt)),
+ unop(Iop_32to16,
+ mkexpr(t3)))));
+ break;
+ }
+ case 0x14: { /* SHLL_S.W */
+ DIP("shll_s.w r%d, r%d, %d", rd, rt, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I32);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I32);
+
+ if (0 == rs) {
+ putIReg(rd, getIReg(rt));
+ } else {
+ /* t0-bits that will be discarded, sign extended to
+ 32bits. */
+ assign(t0, binop(Iop_Sar32,
+ binop(Iop_And32,
+ getIReg(rt),
+ binop(Iop_Sar32,
+ mkU32(0x80000000),
+ mkU8(rs-1))),
+ mkU8(32-rs)));
+
+ assign(t1, IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x80000000)),
+ mkU32(0x0)),
+ mkU32(0x7fffffff),
+ mkU32(0x80000000)));
+
+ assign(t2, binop(Iop_Shl32, getIReg(rt), mkU8(rs)));
+ assign(t3, IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x80000000)),
+ binop(Iop_And32,
+ mkexpr(t2),
+ mkU32(0x80000000))),
+ mkexpr(t2),
+ mkexpr(t1)));
+
+ assign(t4, IRExpr_ITE(binop(Iop_CmpNE32,
+ mkexpr(t0),
+ mkU32(0x0)),
+ IRExpr_ITE(binop(Iop_CmpNE32,
+ mkexpr(t0),
+ mkU32(0xffffffff)
+ ),
+ mkexpr(t1),
+ mkexpr(t3)),
+ mkexpr(t3)));
+ assign(t5, IRExpr_ITE(binop(Iop_CmpNE32,
+ mkexpr(t0),
+ mkU32(0xffffffff)),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x400000)),
+ getDSPControl()));
+ putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
+ mkexpr(t0),
+ mkU32(0x0)),
+ mkexpr(t5),
+ getDSPControl()));
+ putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x80000000)),
+ binop(Iop_And32,
+ mkexpr(t2),
+ mkU32(0x80000000))
+ ),
+ getDSPControl(),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x400000))));
+ putIReg(rd, mkexpr(t4));
+ }
+ break;
+ }
+ case 0x15: { /* SHRA_R.W */
+ DIP("shra_r.w r%d, r%d, %d", rd, rt, rs);
+ vassert(!mode64);
+ if (0 == rs) {
+ putIReg(rd, getIReg(rt));
+ } else {
+ putIReg(rd, binop(Iop_Add32,
+ binop(Iop_Sar32,
+ getIReg(rt), mkU8(rs)),
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ getIReg(rt),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkU8(rs-1))),
+ mkU8(rs-1))));
+ }
+ break;
+ }
+ case 0x16: { /* SHLLV_S.W */
+ DIP("shllv_s.w r%d, r%d, r%d", rd, rt, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I64);
+ t4 = newTemp(Ity_I1);
+ t5 = newTemp(Ity_I1);
+ t6 = newTemp(Ity_I32);
+ t7 = newTemp(Ity_I1);
+ t8 = newTemp(Ity_I32);
+
+ /* Check if shift amount is zero. */
+ assign(t0, binop(Iop_And32, getIReg(rs), mkU32(0x1f)));
+ assign(t1, binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x0)));
+
+ /* t2 = sign of the input value. */
+ assign(t2, binop(Iop_Shr32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x80000000)),
+ mkU8(31)));
+ /* Shift left input value and check for overflow. */
+ assign(t3, binop(Iop_Shl64,
+ unop(Iop_32Sto64, getIReg(rt)),
+ unop(Iop_32to8, mkexpr(t0))));
+ assign(t4, binop(Iop_CmpNE32,
+ unop(Iop_64HIto32, mkexpr(t3)),
+ mkU32(0x00000000)));
+ assign(t5, binop(Iop_CmpNE32,
+ unop(Iop_64HIto32, mkexpr(t3)),
+ mkU32(0xffffffff)));
+ assign(t6, binop(Iop_And32,
+ unop(Iop_1Uto32, mkexpr(t4)),
+ unop(Iop_1Uto32, mkexpr(t5))));
+ assign(t7, binop(Iop_CmpEQ32,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0x80000000)),
+ mkU8(31)),
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ unop(Iop_64to32, mkexpr(t3)),
+ mkU32(0x80000000)),
+ mkU8(31))));
+
+ putDSPControl(IRExpr_ITE(unop(Iop_32to1, mkexpr(t6)),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x400000)),
+ IRExpr_ITE(mkexpr(t7),
+ getDSPControl(),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x400000)))
+ ));
+
+ assign(t8, IRExpr_ITE(unop(Iop_32to1,
+ mkexpr(t2)),
+ mkU32(0x80000000),
+ mkU32(0x7fffffff)));
+ putIReg(rd, IRExpr_ITE(unop(Iop_32to1, mkexpr(t6)),
+ IRExpr_ITE(unop(Iop_32to1,
+ mkexpr(t2)),
+ mkU32(0x80000000),
+ mkU32(0x7fffffff)),
+ IRExpr_ITE(mkexpr(t7),
+ unop(Iop_64to32,
+ mkexpr(t3)),
+ mkexpr(t8))));
+ break;
+ }
+ case 0x17: { /* SHRAV_R.W */
+ DIP("shrav_r.w r%d, r%d, r%d", rd, rt, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I8);
+ t3 = newTemp(Ity_I32);
+
+ assign(t0, binop(Iop_And32, getIReg(rs), mkU32(0x1f)));
+ assign(t1, binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x0)));
+ assign(t2, unop(Iop_32to8,
+ binop(Iop_Sub32, mkexpr(t0), mkU32(1))));
+
+ putIReg(rd, IRExpr_ITE(mkexpr(t1),
+ getIReg(rt),
+ binop(Iop_Sar32,
+ binop(Iop_Add32,
+ binop(Iop_Sar32,
+ getIReg(rt),
+ mkexpr(t2)),
+ mkU32(0x1)),
+ mkU8(1))));
+ break;
+ }
+ case 0x19: { /* SHRL.PH */
+ DIP("shrl.ph r%d, r%d, %d", rd, rt, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I32);
+ assign(t0, binop(Iop_Shr32,
+ unop(Iop_16Uto32,
+ unop(Iop_32to16, getIReg(rt))),
+ mkU8(rs)));
+ assign(t1, binop(Iop_Shr32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16, getIReg(rt))),
+ mkU8(rs)));
+ putIReg(rd, binop(Iop_16HLto32,
+ unop(Iop_32to16, mkexpr(t1)),
+ unop(Iop_32to16, mkexpr(t0))));
+ break;
+ }
+ case 0x1B: { /* SHRLV.PH */
+ DIP("shrlv.ph r%d, r%d, r%d", rd, rt, rs);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I32);
+ t4 = newTemp(Ity_I16);
+ t5 = newTemp(Ity_I16);
+
+ /* Get shift amount from lower 5 bits of rs
+ and check if it is zero. */
+ assign(t0, binop(Iop_And32, getIReg(rs), mkU32(0x0f)));
+ assign(t1, binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x0)));
+
+ assign(t2, binop(Iop_Shr32,
+ unop(Iop_16Uto32,
+ unop(Iop_32to16, getIReg(rt))),
+ unop(Iop_32to8, mkexpr(t0))));
+ assign(t3, binop(Iop_Shr32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16, getIReg(rt))),
+ unop(Iop_32to8, mkexpr(t0))));
+
+ assign(t4, IRExpr_ITE(mkexpr(t1),
+ unop(Iop_32HIto16, getIReg(rt)),
+ unop(Iop_32to16, mkexpr(t3))));
+ assign(t5, IRExpr_ITE(mkexpr(t1),
+ unop(Iop_32to16, getIReg(rt)),
+ unop(Iop_32to16, mkexpr(t2))));
+ putIReg(rd, binop(Iop_16HLto32, mkexpr(t4), mkexpr(t5)));
+ break;
+ }
+ default:
+ return -1;
+ }
+ break; /* end of SHLL.QB */
+ }
+ case 0x18: { /* ADDUH.QB/MUL.PH */
+ switch(sa) {
+ case 0x00: { /* ADDUH.QB */
+ DIP("adduh.qb r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+
+ assign(t0, binop(Iop_HAdd8Ux4, getIReg(rs), getIReg(rt)));
+
+ putIReg(rd, mkexpr(t0));
+ break;
+ }
+ case 0x1: { /* SUBUH.QB */
+ DIP("subuh.qb r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+
+ assign(t0, binop(Iop_HSub8Ux4, getIReg(rs), getIReg(rt)));
+
+ putIReg(rd, mkexpr(t0));
+ break;
+ }
+ case 0x02: { /* ADDUH_R.QB */
+ DIP("adduh_r.qb r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I8);
+ t3 = newTemp(Ity_I32);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I8);
+ t6 = newTemp(Ity_I32);
+ t7 = newTemp(Ity_I32);
+ t8 = newTemp(Ity_I8);
+ t9 = newTemp(Ity_I32);
+ t10 = newTemp(Ity_I32);
+ t11 = newTemp(Ity_I8);
+
+ /* Extract input bytes, add values, add 1 and half the
+ result. */
+ assign(t0, unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16, getIReg(rs)))));
+ assign(t1, unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16, getIReg(rt)))));
+ assign(t2, unop(Iop_16to8,
+ unop(Iop_32to16,
+ binop(Iop_Shr32,
+ binop(Iop_Add32,
+ binop(Iop_Add32,
+ mkexpr(t0),
+ mkexpr(t1)),
+ mkU32(0x00000001)),
+ mkU8(0x01)))));
+
+ assign(t3, unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, getIReg(rs)))));
+ assign(t4, unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, getIReg(rt)))));
+ assign(t5, unop(Iop_16to8,
+ unop(Iop_32to16,
+ binop(Iop_Shr32,
+ binop(Iop_Add32,
+ binop(Iop_Add32,
+ mkexpr(t3),
+ mkexpr(t4)),
+ mkU32(0x00000001)),
+ mkU8(0x01)))));
+
+ assign(t6, unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16, getIReg(rs)))));
+ assign(t7, unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16, getIReg(rt)))));
+ assign(t8, unop(Iop_16to8,
+ unop(Iop_32to16,
+ binop(Iop_Shr32,
+ binop(Iop_Add32,
+ binop(Iop_Add32,
+ mkexpr(t7),
+ mkexpr(t6)),
+ mkU32(0x00000001)),
+ mkU8(0x01)))));
+
+ assign(t9, unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16, getIReg(rs)))));
+ assign(t10, unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16, getIReg(rt)))));
+ assign(t11, unop(Iop_16to8,
+ unop(Iop_32to16,
+ binop(Iop_Shr32,
+ binop(Iop_Add32,
+ binop(Iop_Add32,
+ mkexpr(t9),
+ mkexpr(t10)),
+ mkU32(0x00000001)),
+ mkU8(0x01)))));
+
+ putIReg(rd, binop(Iop_16HLto32,
+ binop(Iop_8HLto16,
+ mkexpr(t11), mkexpr(t8)),
+ binop(Iop_8HLto16,
+ mkexpr(t5), mkexpr(t2))));
+ break;
+ }
+ case 0x3: { /* SUBUH_R.QB */
+ DIP("subuh_r.qb r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I32);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I32);
+ t6 = newTemp(Ity_I32);
+ t7 = newTemp(Ity_I32);
+ t8 = newTemp(Ity_I32);
+ t9 = newTemp(Ity_I8);
+ t10 = newTemp(Ity_I8);
+ t11 = newTemp(Ity_I8);
+ t12 = newTemp(Ity_I8);
+
+ /* Extract each byte of rs and rt. */
+ assign(t1, unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16, getIReg(rs)))));
+ assign(t2, unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, getIReg(rs)))));
+ assign(t3, unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16, getIReg(rs)))));
+ assign(t4, unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16, getIReg(rs)))));
+
+ assign(t5, unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16, getIReg(rt)))));
+ assign(t6, unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, getIReg(rt)))));
+ assign(t7, unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16, getIReg(rt)))));
+ assign(t8, unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16, getIReg(rt)))));
+
+ /* Add 1 to each resulting byte and half the results. */
+ assign(t9, unop(Iop_16to8,
+ unop(Iop_32to16,
+ binop(Iop_Shr32,
+ binop(Iop_Add32,
+ binop(Iop_Sub32,
+ mkexpr(t1),
+ mkexpr(t5)),
+ mkU32(0x00000001)),
+ mkU8(0x01)))));
+ assign(t10, unop(Iop_16to8,
+ unop(Iop_32to16,
+ binop(Iop_Shr32,
+ binop(Iop_Add32,
+ binop(Iop_Sub32,
+ mkexpr(t2),
+ mkexpr(t6)),
+ mkU32(0x00000001)),
+ mkU8(0x01)))));
+ assign(t11, unop(Iop_16to8,
+ unop(Iop_32to16,
+ binop(Iop_Shr32,
+ binop(Iop_Add32,
+ binop(Iop_Sub32,
+ mkexpr(t3),
+ mkexpr(t7)),
+ mkU32(0x00000001)),
+ mkU8(0x01)))));
+ assign(t12, unop(Iop_16to8,
+ unop(Iop_32to16,
+ binop(Iop_Shr32,
+ binop(Iop_Add32,
+ binop(Iop_Sub32,
+ mkexpr(t4),
+ mkexpr(t8)),
+ mkU32(0x00000001)),
+ mkU8(0x01)))));
+
+ putIReg(rd, binop(Iop_16HLto32,
+ binop(Iop_8HLto16,
+ mkexpr(t12), mkexpr(t11)),
+ binop(Iop_8HLto16,
+ mkexpr(t10), mkexpr(t9))));
+ break;
+ }
+ case 0x8: { /* ADDQH.PH */
+ DIP("addqh.ph r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I16);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I16);
+
+ /* Add lower halfs of rs and rt
+ and right shift the result by 1. */
+ assign(t0, binop(Iop_Add32,
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rt)))));
+ assign(t1, unop(Iop_32to16,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ mkexpr(t0),
+ mkU32(0x0001fffe)),
+ mkU8(0x1))));
+ /* Add higher halfs of rs and rt
+ and right shift the result by 1. */
+ assign(t2, binop(Iop_Add32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rt)))));
+ assign(t3, unop(Iop_32to16,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ mkexpr(t2),
+ mkU32(0x0001fffe)),
+ mkU8(0x1))));
+ putIReg(rd, binop(Iop_16HLto32, mkexpr(t3), mkexpr(t1)));
+ break;
+ }
+ case 0x9: { /* SUBQH.PH */
+ DIP("subqh.ph r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+
+ putIReg(rd, binop(Iop_HSub16Sx2,
+ getIReg(rs), getIReg(rt)));
+ break;
+ }
+ case 0xA: {/* ADDQH_R.PH */
+ DIP("addqh_r.ph r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I16);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I16);
+
+ /* Add lower halfs of rs and rt, add 1
+ and right shift the result by 1. */
+ assign(t0, binop(Iop_Add32,
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rt)))));
+ assign(t1, unop(Iop_32to16,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ binop(Iop_Add32,
+ mkexpr(t0),
+ mkU32(0x1)),
+ mkU32(0x0001fffe)),
+ mkU8(0x1))));
+ /* Add higher halfs of rs and rt, add 1
+ and right shift the result by 1. */
+ assign(t2, binop(Iop_Add32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rt)))));
+ assign(t3, unop(Iop_32to16,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ binop(Iop_Add32,
+ mkexpr(t2),
+ mkU32(0x1)),
+ mkU32(0x0001fffe)),
+ mkU8(0x1))));
+
+ putIReg(rd, binop(Iop_16HLto32, mkexpr(t3), mkexpr(t1)));
+ break;
+ }
+ case 0xB: { /* SUBQH_R.PH */
+ DIP("subqh_r.ph r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I16);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I16);
+
+ /* Sub lower halfs of rs and rt, add 1
+ and right shift the result by 1. */
+ assign(t0, binop(Iop_Sub32,
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rt)))));
+ assign(t1, unop(Iop_32to16,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ binop(Iop_Add32,
+ mkexpr(t0),
+ mkU32(0x1)),
+ mkU32(0x0001fffe)),
+ mkU8(0x1))));
+ /* Sub higher halfs of rs and rt, add 1
+ and right shift the result by 1. */
+ assign(t2, binop(Iop_Sub32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rt)))));
+ assign(t3, unop(Iop_32to16,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ binop(Iop_Add32,
+ mkexpr(t2),
+ mkU32(0x1)),
+ mkU32(0x0001fffe)),
+ mkU8(0x1))));
+
+ putIReg(rd, binop(Iop_16HLto32, mkexpr(t3), mkexpr(t1)));
+ break;
+ }
+ case 0xC: { /* MUL.PH */
+ DIP("mul.ph r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+
+ assign(t0,
+ binop(Iop_Mul32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rt)))));
+ /* DSP Control flag. */
+ putDSPControl(IRExpr_ITE(unop(Iop_Not1,
+ binop(Iop_CmpLE32S,
+ mkexpr(t0),
+ mkU32(0x7FFF))),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00200000)),
+ IRExpr_ITE(binop(Iop_CmpLT32S,
+ mkexpr(t0),
+ mkU32(0xFFFF8000)
+ ),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00200000)
+ ),
+ getDSPControl())));
+
+ assign(t1,
+ binop(Iop_Mul32,
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rt)))));
+ /* DSP Control flag. */
+ putDSPControl(IRExpr_ITE(unop(Iop_Not1,
+ binop(Iop_CmpLE32S,
+ mkexpr(t1),
+ mkU32(0x7FFF))),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00200000)),
+ IRExpr_ITE(binop(Iop_CmpLT32S,
+ mkexpr(t1),
+ mkU32(0xFFFF8000)
+ ),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00200000)
+ ),
+ getDSPControl())));
+
+ assign(t2, binop(Iop_16HLto32,
+ unop(Iop_32to16, mkexpr(t0)),
+ unop(Iop_32to16, mkexpr(t1))));
+ putIReg(rd, mkexpr(t2));
+ break;
+ }
+ case 0xE: { /* MUL_S.PH */
+ DIP("mul_s.ph r%d r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I32);
+ t4 = newTemp(Ity_I32);
+
+ /* t0 - signed intermediate result. */
+ assign(t0,
+ binop(Iop_Mul32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rt)))));
+
+ assign(t1,
+ IRExpr_ITE(unop(Iop_Not1,
+ binop(Iop_CmpLE32S,
+ mkexpr(t0),
+ mkU32(0x7FFF))),
+ mkU32(0x00007FFF),
+ IRExpr_ITE(binop(Iop_CmpLT32S,
+ mkexpr(t0),
+ mkU32(0xFFFF8000)),
+ mkU32(0xFFFF8000),
+ mkexpr(t0))));
+
+ /* DSP Control flag. */
+ putDSPControl(IRExpr_ITE(unop(Iop_Not1,
+ binop(Iop_CmpLE32S,
+ mkexpr(t0),
+ mkU32(0x7FFF))),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00200000)),
+ IRExpr_ITE(binop(Iop_CmpLT32S,
+ mkexpr(t0),
+ mkU32(0xFFFF8000)
+ ),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00200000)
+ ),
+ getDSPControl())));
+
+ /* t2 - signed intermediate result. */
+ assign(t2, binop(Iop_Mul32,
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rt)))));
+
+ assign(t3, IRExpr_ITE(unop(Iop_Not1,
+ binop(Iop_CmpLE32S,
+ mkexpr(t2),
+ mkU32(0x7FFF))),
+ mkU32(0x00007FFF),
+ IRExpr_ITE(binop(Iop_CmpLT32S,
+ mkexpr(t2),
+ mkU32(0xFFFF8000)),
+ mkU32(0xFFFF8000),
+ mkexpr(t2))));
+
+ /* DSP Control flag. */
+ putDSPControl(IRExpr_ITE(unop(Iop_Not1,
+ binop(Iop_CmpLE32S,
+ mkexpr(t2),
+ mkU32(0x7FFF))),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00200000)),
+ IRExpr_ITE(binop(Iop_CmpLT32S,
+ mkexpr(t2),
+ mkU32(0xFFFF8000)
+ ),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00200000)
+ ),
+ getDSPControl())));
+
+ assign(t4, binop(Iop_16HLto32,
+ unop(Iop_32to16, mkexpr(t1)),
+ unop(Iop_32to16, mkexpr(t3))));
+ putIReg(rd, mkexpr(t4));
+ break;
+ }
+ case 0x10: { /* ADDQH.W */
+ DIP("addqh.w r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I64);
+
+ assign(t0, binop(Iop_Add64,
+ unop(Iop_32Sto64, getIReg(rs)),
+ unop(Iop_32Sto64, getIReg(rt))));
+ assign(t1, binop(Iop_And64,
+ mkexpr(t0),
+ mkU64(0x00000001fffffffeULL)));
+ putIReg(rd, unop(Iop_64to32,
+ binop(Iop_Shr64, mkexpr(t1), mkU8(0x1))));
+ break;
+ }
+ case 0x11: { /* SUBQH.W */
+ DIP("subqh.w r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I64);
+
+ assign(t0, binop(Iop_Sub64,
+ unop(Iop_32Sto64, getIReg(rs)),
+ unop(Iop_32Sto64, getIReg(rt))));
+ assign(t1, binop(Iop_And64,
+ mkexpr(t0),
+ mkU64(0x00000001fffffffeULL)));
+ putIReg(rd, unop(Iop_64to32,
+ binop(Iop_Shr64, mkexpr(t1), mkU8(0x1))));
+ break;
+ }
+ case 0x12: { /* ADDQH_R.W */
+ DIP("addqh_r.w r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I64);
+
+ assign(t0, binop(Iop_Add64,
+ unop(Iop_32Sto64, getIReg(rs)),
+ unop(Iop_32Sto64, getIReg(rt))));
+ assign(t1, binop(Iop_Add64,
+ mkexpr(t0),
+ mkU64(0x0000000000000001ULL)));
+ assign(t2, binop(Iop_And64,
+ mkexpr(t1),
+ mkU64(0x00000001fffffffeULL)));
+ putIReg(rd, unop(Iop_64to32,
+ binop(Iop_Shr64, mkexpr(t2), mkU8(0x1))));
+ break;
+ }
+ case 0x13: { /* SUBQH_R.W */
+ DIP("subqh_r.w r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I64);
+
+ assign(t0, binop(Iop_Sub64,
+ unop(Iop_32Sto64, getIReg(rs)),
+ unop(Iop_32Sto64, getIReg(rt))));
+ assign(t1, binop(Iop_Add64,
+ mkexpr(t0),
+ mkU64(0x0000000000000001ULL)));
+ assign(t2, binop(Iop_And64,
+ mkexpr(t1),
+ mkU64(0x00000001fffffffeULL)));
+ putIReg(rd, unop(Iop_64to32,
+ binop(Iop_Shr64, mkexpr(t2), mkU8(0x1))));
+ break;
+ }
+ case 0x16: { /* MULQ_S.W */
+ DIP("mulq_s.w r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I1);
+
+ assign(t0, binop(Iop_Shl64,
+ binop(Iop_MullS32,
+ getIReg(rt), getIReg(rs)),
+ mkU8(0x1)));
+ assign(t1, binop(Iop_CmpEQ32,
+ getIReg(rt), mkU32(0x80000000)));
+ assign(t2, binop(Iop_CmpEQ32,
+ getIReg(rs), mkU32(0x80000000)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t1),
+ IRExpr_ITE(mkexpr(t2),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00200000)
+ ),
+ getDSPControl()),
+ getDSPControl()));
+ putIReg(rd, IRExpr_ITE(mkexpr(t1),
+ IRExpr_ITE(mkexpr(t2),
+ mkU32(0x7fffffff),
+ unop(Iop_64HIto32,
+ mkexpr(t0))),
+ unop(Iop_64HIto32, mkexpr(t0))));
+ break;
+ }
+ case 0x17: { /* MULQ_RS.W */
+ DIP("mulq_rs.w r%d, r%d, r%d", rd, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I1);
+ t2 = newTemp(Ity_I1);
+
+ assign(t0, binop(Iop_Add64,
+ binop(Iop_Shl64,
+ binop(Iop_MullS32,
+ getIReg(rt),
+ getIReg(rs)),
+ mkU8(0x1)),
+ mkU64(0x0000000080000000ULL)));
+ assign(t1,
+ binop(Iop_CmpEQ32, getIReg(rt), mkU32(0x80000000)));
+ assign(t2,
+ binop(Iop_CmpEQ32, getIReg(rs), mkU32(0x80000000)));
+ putDSPControl(IRExpr_ITE(mkexpr(t1),
+ IRExpr_ITE(mkexpr(t2),
+ binop(Iop_Or32,
+ getDSPControl(),
+ mkU32(0x00200000)
+ ),
+ getDSPControl()),
+ getDSPControl()));
+ putIReg(rd, IRExpr_ITE(mkexpr(t1),
+ IRExpr_ITE(mkexpr(t2),
+ mkU32(0x7fffffff),
+ unop(Iop_64HIto32,
+ mkexpr(t0))),
+ unop(Iop_64HIto32, mkexpr(t0))));
+ break;
+ }
+ default:
+ return -1;
+ }
+ break; /* end of ADDUH.QB/MUL.PH */
+ }
+ case 0x30: { /* DPAQ.W.PH */
+ switch(sa) {
+ case 0x0: { /* DPA.W.PH */
+ DIP("dpa.w.ph ac%d, r%d, r%d", ac, rs, rt);
+ vassert(!mode64);
+
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I64);
+
+ assign(t0,
+ unop(Iop_32Sto64,
+ binop(Iop_Mul32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rt))))));
+ assign(t1,
+ unop(Iop_32Sto64,
+ binop(Iop_Mul32,
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rt))))));
+ assign(t2,
+ binop(Iop_Add64,
+ getAcc(ac),
+ binop(Iop_Add64, mkexpr(t0), mkexpr(t1))));
+ putAcc(ac, mkexpr(t2));
+ break;
+ }
+ case 0x1: { /* DPS.W.PH */
+ DIP("dps.w.ph ac%d, r%d, r%d", ac, rs, rt);
+ vassert(!mode64);
+
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I64);
+
+ assign(t0,
+ unop(Iop_32Sto64,
+ binop(Iop_Mul32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rt))))));
+ assign(t1,
+ unop(Iop_32Sto64,
+ binop(Iop_Mul32,
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rt))))));
+ assign(t2,
+ binop(Iop_Sub64,
+ getAcc(ac),
+ binop(Iop_Add64, mkexpr(t0), mkexpr(t1))));
+ putAcc(ac, mkexpr(t2));
+ break;
+ }
+ case 0x2: { /* MULSA.W.PH */
+ DIP("mulsa.w.ph ac%d, r%d, r%d", ac, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I64);
+
+ assign(t4, getAcc(ac));
+ assign(t0, binop(Iop_Mul32,
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rt))),
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rs)))));
+ assign(t1, binop(Iop_Mul32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rt))),
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rs)))));
+ assign(t2, binop(Iop_Sub32, mkexpr(t1), mkexpr(t0)));
+ putAcc(ac, binop(Iop_Add64,
+ mkexpr(t4),
+ unop(Iop_32Sto64, mkexpr(t2))));
+ break;
+ }
+ case 0x3: { /* DPAU.H.QBL */
+ DIP("dpau.h.qbl ac%d, r%d, r%d", ac, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I64);
+ t3 = newTemp(Ity_I64);
+
+ assign(t0,
+ binop(Iop_Mul32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16, getIReg(rt))))));
+ assign(t1,
+ binop(Iop_Mul32,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16, getIReg(rt))))));
+ assign(t2,
+ unop(Iop_32Uto64,
+ binop(Iop_Add32,
+ mkexpr(t0),
+ mkexpr(t1))));
+ assign(t3,
+ binop(Iop_Add64, getAcc(ac), mkexpr(t2)));
+ putAcc(ac, mkexpr(t3));
+ break;
+ }
+ case 0x4: { /* DPAQ_S.W.PH */
+ DIP("dpaq_s.w.ph ac%d, r%d, r%d", ac, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I1);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I64);
+ t5 = newTemp(Ity_I64);
+ t6 = newTemp(Ity_I1);
+ t7 = newTemp(Ity_I1);
+ t8 = newTemp(Ity_I64);
+ t9 = newTemp(Ity_I64);
+
+ assign(t0, getAcc(ac));
+
+ assign(t1, binop(Iop_Shl64,
+ binop(Iop_MullS32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16,
+ getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16,
+ getIReg(rt)))),
+ mkU8(0x1)));
+ assign(t2, binop(Iop_CmpEQ32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16, getIReg(rs))),
+ mkU32(0x00008000)));
+ assign(t3, binop(Iop_CmpEQ32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16, getIReg(rt))),
+ mkU32(0x00008000)));
+ assign(t4,
+ IRExpr_ITE(mkexpr(t2),
+ IRExpr_ITE(mkexpr(t3),
+ mkU64(0x000000007fffffffULL),
+ mkexpr(t1)),
+ mkexpr(t1)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t2),
+ IRExpr_ITE(mkexpr(t3),
+ binop(Iop_Or32,
+ getDSPControl(),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkU8(ac+16)
+ )
+ ),
+ getDSPControl()),
+ getDSPControl()));
+
+ assign(t5, binop(Iop_Shl64,
+ binop(Iop_MullS32,
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rt)))
+ ),
+ mkU8(0x1)));
+ assign(t6, binop(Iop_CmpEQ32,
+ unop(Iop_16Uto32,
+ unop(Iop_32to16, getIReg(rs))),
+ mkU32(0x00008000)));
+ assign(t7, binop(Iop_CmpEQ32,
+ unop(Iop_16Uto32,
+ unop(Iop_32to16, getIReg(rt))),
+ mkU32(0x00008000)));
+ assign(t8,
+ IRExpr_ITE(mkexpr(t6),
+ IRExpr_ITE(mkexpr(t7),
+ mkU64(0x000000007fffffffULL),
+ mkexpr(t5)),
+ mkexpr(t5)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t6),
+ IRExpr_ITE(mkexpr(t7),
+ binop(Iop_Or32,
+ getDSPControl(),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkU8(ac+16)
+ )
+ ),
+ getDSPControl()),
+ getDSPControl()));
+
+ assign(t9, binop(Iop_Add64,
+ binop(Iop_Add64, mkexpr(t4), mkexpr(t8)),
+ mkexpr(t0)));
+ putAcc(ac, mkexpr(t9));
+ break;
+ }
+ case 0x5: { /* DPSQ_S.W.PH */
+ DIP("dpsq_s.w.ph ac%d r%d, r%d", ac, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I1);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I64);
+ t5 = newTemp(Ity_I64);
+ t6 = newTemp(Ity_I1);
+ t7 = newTemp(Ity_I1);
+ t8 = newTemp(Ity_I64);
+ t9 = newTemp(Ity_I64);
+
+ assign(t0, getAcc(ac));
+
+ assign(t1, binop(Iop_Shl64,
+ binop(Iop_MullS32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16,
+ getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16,
+ getIReg(rt)))),
+ mkU8(0x1)));
+ assign(t2, binop(Iop_CmpEQ32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16, getIReg(rs))),
+ mkU32(0x00008000)));
+ assign(t3, binop(Iop_CmpEQ32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16, getIReg(rt))),
+ mkU32(0x00008000)));
+ assign(t4,
+ IRExpr_ITE(mkexpr(t2),
+ IRExpr_ITE(mkexpr(t3),
+ mkU64(0x000000007fffffffULL),
+ mkexpr(t1)),
+ mkexpr(t1)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t2),
+ IRExpr_ITE(mkexpr(t3),
+ binop(Iop_Or32,
+ getDSPControl(),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkU8(ac+16)
+ )
+ ),
+ getDSPControl()),
+ getDSPControl()));
+
+ assign(t5,
+ binop(Iop_Shl64,
+ binop(Iop_MullS32,
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rt)))),
+ mkU8(0x1)));
+ assign(t6, binop(Iop_CmpEQ32,
+ unop(Iop_16Uto32,
+ unop(Iop_32to16, getIReg(rs))),
+ mkU32(0x00008000)));
+ assign(t7, binop(Iop_CmpEQ32,
+ unop(Iop_16Uto32,
+ unop(Iop_32to16, getIReg(rt))),
+ mkU32(0x00008000)));
+ assign(t8,
+ IRExpr_ITE(mkexpr(t6),
+ IRExpr_ITE(mkexpr(t7),
+ mkU64(0x000000007fffffffULL),
+ mkexpr(t5)),
+ mkexpr(t5)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t6),
+ IRExpr_ITE(mkexpr(t7),
+ binop(Iop_Or32,
+ getDSPControl(),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkU8(ac+16)
+ )
+ ),
+ getDSPControl()),
+ getDSPControl()));
+
+ assign(t9,
+ binop(Iop_Sub64,
+ mkexpr(t0),
+ binop(Iop_Add64, mkexpr(t4), mkexpr(t8))));
+ putAcc(ac, mkexpr(t9));
+ break;
+ }
+ case 0x6: { /* MULSAQ_S.W.PH */
+ DIP("mulsaq_s.w.ph ac%d r%d, r%d", ac, rs, rt);
+ vassert(!mode64);
+
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I32);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I32);
+ t6 = newTemp(Ity_I64);
+ t7 = newTemp(Ity_I64);
+ t8 = newTemp(Ity_I32);
+ t9 = newTemp(Ity_I32);
+
+ assign(t0, unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rs))));
+ assign(t1, unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rt))));
+
+ assign(t8, binop(Iop_And32,
+ unop(Iop_1Sto32,
+ binop(Iop_CmpEQ32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16,
+ getIReg(rs))),
+ mkU32(0x8000))),
+ unop(Iop_1Sto32,
+ binop(Iop_CmpEQ32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16,
+ getIReg(rt))),
+ mkU32(0x8000)))));
+ /* DSPControl_outflag:16+acc <- 1 */
+ putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
+ mkexpr(t8),
+ mkU32(0x0)),
+ binop(Iop_Or32,
+ getDSPControl(),
+ binop(Iop_Shl32,
+ mkU32(0x00010000),
+ mkU8(ac))),
+ getDSPControl()));
+
+ /* tempB_31..0 */
+ assign(t2,
+ IRExpr_ITE(binop(Iop_CmpNE32,
+ mkexpr(t8), mkU32(0x0)),
+ mkU32(0x7FFFFFFF),
+ binop(Iop_Shl32,
+ binop(Iop_Mul32,
+ mkexpr(t0), mkexpr(t1)),
+ mkU8(1))));
+
+ assign(t3, unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rs))));
+ assign(t4, unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rt))));
+
+ assign(t9, binop(Iop_And32,
+ unop(Iop_1Sto32,
+ binop(Iop_CmpEQ32,
+ unop(Iop_16Uto32,
+ unop(Iop_32to16,
+ getIReg(rs))),
+ mkU32(0x8000))),
+ unop(Iop_1Sto32,
+ binop(Iop_CmpEQ32,
+ unop(Iop_16Uto32,
+ unop(Iop_32to16,
+ getIReg(rt))),
+ mkU32(0x8000)))));
+ /* DSPControl_outflag:16+acc <- 1 */
+ putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
+ mkexpr(t9),
+ mkU32(0x0)),
+ binop(Iop_Or32,
+ getDSPControl(),
+ binop(Iop_Shl32,
+ mkU32(0x00010000),
+ mkU8(ac))),
+ getDSPControl()));
+ /* tempA_31..0 */
+ assign(t5,
+ IRExpr_ITE(binop(Iop_CmpNE32,
+ mkexpr(t9),
+ mkU32(0x0)),
+ mkU32(0x7FFFFFFF),
+ binop(Iop_Shl32,
+ binop(Iop_Mul32,
+ mkexpr(t3),
+ mkexpr(t4)),
+ mkU8(1))));
+ /* dotp_63..0 */
+ assign(t6,
+ binop(Iop_Sub64,
+ unop(Iop_32Sto64, mkexpr(t2)),
+ unop(Iop_32Sto64, mkexpr(t5))));
+ /* tempC_63..0 */
+ assign(t7, binop(Iop_Add64, getAcc(ac), mkexpr(t6)));
+
+ putAcc(ac, mkexpr(t7));
+ break;
+ }
+ case 0x7: { /* DPAU.H.QBR */
+ DIP("dpau.h.qbr ac%d, r%d, r%d", ac, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I64);
+ t3 = newTemp(Ity_I64);
+
+ assign(t0,
+ binop(Iop_Mul32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, getIReg(rt))))));
+ assign(t1,
+ binop(Iop_Mul32,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16, getIReg(rt))))));
+ assign(t2, unop(Iop_32Uto64,
+ binop(Iop_Add32, mkexpr(t0), mkexpr(t1))));
+ assign(t3, binop(Iop_Add64, getAcc(ac), mkexpr(t2)));
+ putAcc(ac, mkexpr(t3));
+ break;
+ }
+ case 0x8: { /* DPAX.W.PH */
+ DIP("dpax.w.ph ac%d, r%d, r%d", ac, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I64);
+
+ assign(t0,
+ unop(Iop_32Sto64,
+ binop(Iop_Mul32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rt))))));
+ assign(t1,
+ unop(Iop_32Sto64,
+ binop(Iop_Mul32,
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rt))))));
+ assign(t2,
+ binop(Iop_Add64,
+ getAcc(ac),
+ binop(Iop_Add64, mkexpr(t0), mkexpr(t1))));
+ putAcc(ac, mkexpr(t2));
+ break;
+ }
+ case 0x9: { /* DPSX.W.PH */
+ DIP("dpsx.w.ph ac%d r%d, r%d", ac, rs, rt);
+ vassert(!mode64);
+
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I64);
+
+ assign(t0,
+ unop(Iop_32Sto64,
+ binop(Iop_Mul32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rt))))));
+ assign(t1,
+ unop(Iop_32Sto64,
+ binop(Iop_Mul32,
+ unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rt))))));
+ assign(t2,
+ binop(Iop_Sub64,
+ getAcc(ac),
+ binop(Iop_Add64, mkexpr(t0), mkexpr(t1))));
+ putAcc(ac, mkexpr(t2));
+ break;
+ }
+ case 0xB: { /* DPSU.H.QBL */
+ DIP("dpsu.h.qbl ac%d, r%d, r%d", ac, rs, rt);
+ vassert(!mode64);
+
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I64);
+ t3 = newTemp(Ity_I64);
+
+ assign(t0,
+ binop(Iop_Mul32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32HIto16, getIReg(rt))))));
+ assign(t1,
+ binop(Iop_Mul32,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32HIto16, getIReg(rt))))));
+ assign(t2,
+ unop(Iop_32Uto64,
+ binop(Iop_Add32, mkexpr(t0), mkexpr(t1))));
+ assign(t3,
+ binop(Iop_Sub64, getAcc(ac), mkexpr(t2)));
+ putAcc(ac, mkexpr(t3));
+ break;
+ }
+ case 0xC: { /* DPAQ_SA.L.W */
+ DIP("dpaq_sa.l.w ac%d, r%d, r%d", ac, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I1);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I64);
+ t5 = newTemp(Ity_I64);
+ t6 = newTemp(Ity_I64);
+ t7 = newTemp(Ity_I64);
+ t8 = newTemp(Ity_I1);
+ t9 = newTemp(Ity_I1);
+
+ assign(t0, getAcc(ac));
+
+ assign(t1, binop(Iop_Shl64,
+ binop(Iop_MullS32,
+ getIReg(rs), getIReg(rt)),
+ mkU8(0x1)));
+
+ assign(t2, binop(Iop_CmpEQ32,
+ getIReg(rs),
+ mkU32(0x80000000)));
+ assign(t3, binop(Iop_CmpEQ32,
+ getIReg(rt),
+ mkU32(0x80000000)));
+
+ assign(t4,
+ IRExpr_ITE(mkexpr(t2),
+ IRExpr_ITE(mkexpr(t3),
+ mkU64(0x7fffffffffffffffULL),
+ mkexpr(t1)),
+ mkexpr(t1)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t2),
+ IRExpr_ITE(mkexpr(t3),
+ binop(Iop_Or32,
+ getDSPControl(),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkU8(ac+16)
+ )
+ ),
+ getDSPControl()),
+ getDSPControl()));
+
+ assign(t5, binop(Iop_Add64,
+ unop(Iop_32Uto64,
+ unop(Iop_64to32, mkexpr(t0))),
+ unop(Iop_32Uto64,
+ unop(Iop_64to32, mkexpr(t4)))));
+ assign(t6,
+ binop(Iop_Add64,
+ binop(Iop_Add64,
+ unop(Iop_32Sto64,
+ unop(Iop_64HIto32, mkexpr(t0))),
+ unop(Iop_32Sto64,
+ unop(Iop_64HIto32, mkexpr(t4)))),
+ unop(Iop_32Uto64,
+ binop(Iop_And32,
+ unop(Iop_64HIto32, mkexpr(t5)),
+ mkU32(0x1)))));
+ assign(t7, binop(Iop_32HLto64,
+ unop(Iop_64to32, mkexpr(t6)),
+ unop(Iop_64to32, mkexpr(t5))));
+ assign(t8, binop(Iop_CmpEQ32,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ unop(Iop_64to32, mkexpr(t6)),
+ mkU32(0x80000000)),
+ mkU8(31)),
+ binop(Iop_And32,
+ unop(Iop_64HIto32, mkexpr(t6)),
+ mkU32(0x00000001))));
+ assign(t9, binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ unop(Iop_64HIto32,
+ mkexpr(t6)),
+ mkU32(0x00000001)),
+ mkU32(0x1)));
+ putDSPControl(IRExpr_ITE(mkexpr(t8),
+ getDSPControl(),
+ binop(Iop_Or32,
+ getDSPControl(),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkU8(ac+16)))));
+ putAcc(ac,
+ IRExpr_ITE(mkexpr(t8),
+ mkexpr(t7),
+ IRExpr_ITE(mkexpr(t9),
+ mkU64(0x8000000000000000ULL),
+ mkU64(0x7fffffffffffffffULL)))
+ );
+ break;
+ }
+ case 0xD: { /* DPSQ_SA.L.W */
+ DIP("dpsq_sa.l.w ac%d, r%d, r%d", ac, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I1);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I64);
+ t5 = newTemp(Ity_I64);
+ t6 = newTemp(Ity_I64);
+ t7 = newTemp(Ity_I64);
+ t8 = newTemp(Ity_I1);
+ t9 = newTemp(Ity_I1);
+
+ assign(t0, getAcc(ac));
+
+ assign(t1, binop(Iop_Shl64,
+ binop(Iop_MullS32,
+ getIReg(rs), getIReg(rt)),
+ mkU8(0x1)));
+
+ assign(t2, binop(Iop_CmpEQ32,
+ getIReg(rs),
+ mkU32(0x80000000)));
+ assign(t3, binop(Iop_CmpEQ32,
+ getIReg(rt),
+ mkU32(0x80000000)));
+
+ assign(t4,
+ IRExpr_ITE(mkexpr(t2),
+ IRExpr_ITE(mkexpr(t3),
+ mkU64(0x7fffffffffffffffULL),
+ mkexpr(t1)),
+ mkexpr(t1)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t2),
+ IRExpr_ITE(mkexpr(t3),
+ binop(Iop_Or32,
+ getDSPControl(),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkU8(ac+16)
+ )
+ ),
+ getDSPControl()),
+ getDSPControl()));
+
+ assign(t5, binop(Iop_Sub64,
+ unop(Iop_32Uto64,
+ unop(Iop_64to32, mkexpr(t0))),
+ unop(Iop_32Uto64,
+ unop(Iop_64to32, mkexpr(t4)))));
+ assign(t6, binop(Iop_Sub64,
+ binop(Iop_Add64,
+ unop(Iop_32Sto64,
+ unop(Iop_64HIto32, mkexpr(t0))
+ ),
+ unop(Iop_32Sto64,
+ unop(Iop_1Sto32,
+ binop(Iop_CmpLT32U,
+ unop(Iop_64to32,
+ mkexpr(t0)),
+ unop(Iop_64to32,
+ mkexpr(t4)))))),
+ unop(Iop_32Sto64,
+ unop(Iop_64HIto32, mkexpr(t4)))));
+ assign(t7, binop(Iop_32HLto64,
+ unop(Iop_64to32, mkexpr(t6)),
+ unop(Iop_64to32, mkexpr(t5))));
+ assign(t8, binop(Iop_CmpEQ32,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ unop(Iop_64to32, mkexpr(t6)),
+ mkU32(0x80000000)),
+ mkU8(31)),
+ binop(Iop_And32,
+ unop(Iop_64HIto32, mkexpr(t6)),
+ mkU32(0x00000001))));
+ assign(t9, binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ unop(Iop_64HIto32, mkexpr(t6)),
+ mkU32(0x00000001)),
+ mkU32(0x1)));
+ putDSPControl(IRExpr_ITE(mkexpr(t8),
+ getDSPControl(),
+ binop(Iop_Or32,
+ getDSPControl(),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkU8(ac+16)))));
+ putAcc(ac,
+ IRExpr_ITE(mkexpr(t8),
+ mkexpr(t7),
+ IRExpr_ITE(mkexpr(t9),
+ mkU64(0x8000000000000000ULL),
+ mkU64(0x7fffffffffffffffULL)))
+ );
+ break;
+ }
+ case 0xF: { /* DPSU.H.QBR */
+ DIP("dpsu.h.qbr ac%d r%d, r%d", ac, rs, rt);
+ vassert(!mode64);
+
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I64);
+ t3 = newTemp(Ity_I64);
+
+ assign(t0,
+ binop(Iop_Mul32,
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16HIto8,
+ unop(Iop_32to16, getIReg(rt))))));
+ assign(t1,
+ binop(Iop_Mul32,
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16, getIReg(rs)))),
+ unop(Iop_8Uto32,
+ unop(Iop_16to8,
+ unop(Iop_32to16, getIReg(rt))))));
+ assign(t2, unop(Iop_32Uto64,
+ binop(Iop_Add32, mkexpr(t0), mkexpr(t1))));
+ assign(t3, binop(Iop_Sub64, getAcc(ac), mkexpr(t2)));
+ putAcc(ac, mkexpr(t3));
+
+ break;
+ }
+ case 0x10: { /* MAQ_SA.W.PHL */
+ DIP("maq_sa.w.phl ac%d, r%d, r%d", ac, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I1);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I64);
+ t5 = newTemp(Ity_I64);
+ t6 = newTemp(Ity_I1);
+ t7 = newTemp(Ity_I64);
+
+ assign(t0, getAcc(ac));
+ assign(t1, unop(Iop_32Sto64,
+ binop(Iop_Shl32,
+ binop(Iop_Mul32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16,
+ getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16,
+ getIReg(rt)))),
+ mkU8(0x1))));
+
+ /* If both input arguments are equal 0x8000, saturate
+ intermediate product and write to DSPControl register.
+ */
+ assign(t2, binop(Iop_CmpEQ32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16, getIReg(rs))),
+ mkU32(0x00008000)));
+ assign(t3, binop(Iop_CmpEQ32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16, getIReg(rt))),
+ mkU32(0x00008000)));
+
+ assign(t4,
+ IRExpr_ITE(mkexpr(t2),
+ IRExpr_ITE(mkexpr(t3),
+ mkU64(0x000000007fffffffULL),
+ mkexpr(t1)),
+ mkexpr(t1)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t2),
+ IRExpr_ITE(mkexpr(t3),
+ binop(Iop_Or32,
+ getDSPControl(),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkU8(ac+16)
+ )
+ ),
+ getDSPControl()),
+ getDSPControl()));
+ /* Add intermediate product and value in the
+ accumulator. */
+ assign(t5, binop(Iop_Add64, mkexpr(t0), mkexpr(t4)));
+
+ /* Compare bits 31 and 32 of the value in t5. */
+ assign(t6, binop(Iop_CmpEQ32,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ unop(Iop_64to32, mkexpr(t5)),
+ mkU32(0x80000000)),
+ mkU8(31)),
+ binop(Iop_And32,
+ unop(Iop_64HIto32, mkexpr(t5)),
+ mkU32(1))));
+ putDSPControl(IRExpr_ITE(mkexpr(t6),
+ getDSPControl(),
+ binop(Iop_Or32,
+ getDSPControl(),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkU8(ac+16)))));
+ assign(t7,
+ IRExpr_ITE(mkexpr(t6),
+ mkexpr(t5),
+ IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ unop(Iop_64HIto32,
+ mkexpr(t5)),
+ mkU32(1)),
+ mkU32(0x0)),
+ mkU64(0x000000007fffffffULL),
+ mkU64(0xffffffff80000000ULL)))
+ );
+ putAcc(ac, mkexpr(t7));
+ break;
+ }
+ case 0x12: { /* MAQ_SA.W.PHR */
+ DIP("maq_sa.w.phr ac%d, r%d, r%d", ac, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I1);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I64);
+ t5 = newTemp(Ity_I64);
+ t6 = newTemp(Ity_I1);
+ t7 = newTemp(Ity_I64);
+
+ assign(t0, getAcc(ac));
+ assign(t1, unop(Iop_32Sto64,
+ binop(Iop_Shl32,
+ binop(Iop_Mul32,
+ unop(Iop_16Sto32,
+ unop(Iop_32to16,
+ getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32to16,
+ getIReg(rt)))),
+ mkU8(0x1))));
+
+ /* If both input arguments are equal 0x8000, saturate
+ intermediate product and write to DSPControl
+ register. */
+ assign(t2, binop(Iop_CmpEQ32,
+ unop(Iop_16Uto32,
+ unop(Iop_32to16, getIReg(rs))),
+ mkU32(0x00008000)));
+ assign(t3, binop(Iop_CmpEQ32,
+ unop(Iop_16Uto32,
+ unop(Iop_32to16, getIReg(rt))),
+ mkU32(0x00008000)));
+
+ assign(t4,
+ IRExpr_ITE(mkexpr(t2),
+ IRExpr_ITE(mkexpr(t3),
+ mkU64(0x000000007fffffffULL),
+ mkexpr(t1)),
+ mkexpr(t1)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t2),
+ IRExpr_ITE(mkexpr(t3),
+ binop(Iop_Or32,
+ getDSPControl(),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkU8(ac+16)
+ )
+ ),
+ getDSPControl()),
+ getDSPControl()));
+ /* Add intermediate product and value in the
+ accumulator. */
+ assign(t5, binop(Iop_Add64, mkexpr(t0), mkexpr(t4)));
+
+ /* Compare bits 31 and 32 of the value in t5. */
+ assign(t6, binop(Iop_CmpEQ32,
+ binop(Iop_Shr32,
+ binop(Iop_And32,
+ unop(Iop_64to32, mkexpr(t5)),
+ mkU32(0x80000000)),
+ mkU8(31)),
+ binop(Iop_And32,
+ unop(Iop_64HIto32, mkexpr(t5)),
+ mkU32(1))));
+ putDSPControl(IRExpr_ITE(mkexpr(t6),
+ getDSPControl(),
+ binop(Iop_Or32,
+ getDSPControl(),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkU8(ac+16)))));
+ assign(t7,
+ IRExpr_ITE(mkexpr(t6),
+ mkexpr(t5),
+ IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ unop(Iop_64HIto32,
+ mkexpr(t5)),
+ mkU32(1)),
+ mkU32(0x0)),
+ mkU64(0x000000007fffffffULL),
+ mkU64(0xffffffff80000000ULL)))
+ );
+ putAcc(ac, mkexpr(t7));
+ break;
+ }
+ case 0x14: { /* MAQ_S.W.PHL */
+ DIP("maq_s.w.phl ac%d, r%d, r%d", ac, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I64);
+
+ assign(t5, getAcc(ac));
+
+ assign(t0, unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rs))));
+ assign(t1, unop(Iop_16Sto32,
+ unop(Iop_32HIto16, getIReg(rt))));
+
+ assign(t2, binop(Iop_And32,
+ unop(Iop_1Sto32,
+ binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkexpr(t0),
+ mkU32(0xffff)),
+ mkU32(0x8000))),
+ unop(Iop_1Sto32,
+ binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkexpr(t1),
+ mkU32(0xffff)),
+ mkU32(0x8000)))));
+
+ assign(t3, binop(Iop_CmpEQ32, mkexpr(t2), mkU32(0x0)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t3),
+ getDSPControl(),
+ binop(Iop_Or32,
+ getDSPControl(),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkU8(ac+16)))));
+
+ assign(t4, unop(Iop_64to32,
+ binop(Iop_MullS32,
+ mkexpr(t0), mkexpr(t1))));
+ putAcc(ac, IRExpr_ITE(mkexpr(t3),
+ binop(Iop_Add64,
+ unop(Iop_32Sto64,
+ binop(Iop_Shl32,
+ mkexpr(t4),
+ mkU8(0x1))),
+ mkexpr(t5)),
+ binop(Iop_Add64,
+ mkexpr(t5),
+ unop(Iop_32Sto64,
+ mkU32(0x7fffffff)))));
+ break;
+ }
+ case 0x16: { /* MAQ_S.W.PHR */
+ DIP("maq_s.w.phr ac%d, r%d, r%d", ac, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I64);
+
+ assign(t5, getAcc(ac));
+
+ assign(t0, unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rs))));
+ assign(t1, unop(Iop_16Sto32,
+ unop(Iop_32to16, getIReg(rt))));
+
+ assign(t2, binop(Iop_And32,
+ unop(Iop_1Sto32,
+ binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkexpr(t0),
+ mkU32(0xffff)),
+ mkU32(0x8000))),
+ unop(Iop_1Sto32,
+ binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ mkexpr(t1),
+ mkU32(0xffff)),
+ mkU32(0x8000)))));
+
+ assign(t3, binop(Iop_CmpEQ32, mkexpr(t2), mkU32(0x0)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t3),
+ getDSPControl(),
+ binop(Iop_Or32,
+ getDSPControl(),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkU8(ac+16)))));
+
+ assign(t4, unop(Iop_64to32,
+ binop(Iop_MullS32,
+ mkexpr(t0), mkexpr(t1))));
+ putAcc(ac, IRExpr_ITE(mkexpr(t3),
+ binop(Iop_Add64,
+ unop(Iop_32Sto64,
+ binop(Iop_Shl32,
+ mkexpr(t4),
+ mkU8(0x1))),
+ mkexpr(t5)),
+ binop(Iop_Add64,
+ mkexpr(t5),
+ unop(Iop_32Sto64,
+ mkU32(0x7fffffff)))));
+ break;
+ }
+ case 0x18: { /* DPAQX_S.W.PH */
+ DIP("dpaqx_s.w.ph ac%d, r%d, r%d", ac, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I1);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I64);
+ t5 = newTemp(Ity_I64);
+ t6 = newTemp(Ity_I1);
+ t7 = newTemp(Ity_I1);
+ t8 = newTemp(Ity_I64);
+ t9 = newTemp(Ity_I64);
+
+ assign(t0, getAcc(ac));
+
+ assign(t1, binop(Iop_Shl64,
+ binop(Iop_MullS32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16,
+ getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32to16,
+ getIReg(rt)))),
+ mkU8(0x1)));
+ assign(t2, binop(Iop_CmpEQ32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16, getIReg(rs))),
+ mkU32(0x00008000)));
+ assign(t3, binop(Iop_CmpEQ32,
+ unop(Iop_16Uto32,
+ unop(Iop_32to16, getIReg(rt))),
+ mkU32(0x00008000)));
+ assign(t4,
+ IRExpr_ITE(mkexpr(t2),
+ IRExpr_ITE(mkexpr(t3),
+ mkU64(0x000000007fffffffULL),
+ mkexpr(t1)),
+ mkexpr(t1)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t2),
+ IRExpr_ITE(mkexpr(t3),
+ binop(Iop_Or32,
+ getDSPControl(),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkU8(ac+16))),
+ getDSPControl()),
+ getDSPControl()));
+
+ assign(t5, binop(Iop_Shl64,
+ binop(Iop_MullS32,
+ unop(Iop_16Sto32,
+ unop(Iop_32to16,
+ getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16,
+ getIReg(rt)))),
+ mkU8(0x1)));
+ assign(t6, binop(Iop_CmpEQ32,
+ unop(Iop_16Uto32,
+ unop(Iop_32to16, getIReg(rs))),
+ mkU32(0x00008000)));
+ assign(t7, binop(Iop_CmpEQ32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16, getIReg(rt))),
+ mkU32(0x00008000)));
+ assign(t8,
+ IRExpr_ITE(mkexpr(t6),
+ IRExpr_ITE(mkexpr(t7),
+ mkU64(0x000000007fffffffULL),
+ mkexpr(t5)),
+ mkexpr(t5)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t6),
+ IRExpr_ITE(mkexpr(t7),
+ binop(Iop_Or32,
+ getDSPControl(),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkU8(ac+16)
+ )
+ ),
+ getDSPControl()),
+ getDSPControl()));
+
+ assign(t9, binop(Iop_Add64,
+ binop(Iop_Add64, mkexpr(t4), mkexpr(t8)),
+ mkexpr(t0)));
+ putAcc(ac, mkexpr(t9));
+ break;
+ }
+ case 0x19: { /* DPSQX_S.W.PH */
+ DIP("dpsqx_s.w.ph ac%d, r%d, r%d", ac, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I1);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I64);
+ t5 = newTemp(Ity_I64);
+ t6 = newTemp(Ity_I1);
+ t7 = newTemp(Ity_I1);
+ t8 = newTemp(Ity_I64);
+ t9 = newTemp(Ity_I64);
+
+ assign(t0, getAcc(ac));
+
+ assign(t1, binop(Iop_Shl64,
+ binop(Iop_MullS32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16,
+ getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32to16,
+ getIReg(rt)))),
+ mkU8(0x1)));
+ assign(t2, binop(Iop_CmpEQ32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16, getIReg(rs))),
+ mkU32(0x00008000)));
+ assign(t3, binop(Iop_CmpEQ32,
+ unop(Iop_16Uto32,
+ unop(Iop_32to16, getIReg(rt))),
+ mkU32(0x00008000)));
+ assign(t4,
+ IRExpr_ITE(mkexpr(t2),
+ IRExpr_ITE(mkexpr(t3),
+ mkU64(0x000000007fffffffULL),
+ mkexpr(t1)),
+ mkexpr(t1)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t2),
+ IRExpr_ITE(mkexpr(t3),
+ binop(Iop_Or32,
+ getDSPControl(),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkU8(ac+16)
+ )
+ ),
+ getDSPControl()),
+ getDSPControl()));
+
+ assign(t5, binop(Iop_Shl64,
+ binop(Iop_MullS32,
+ unop(Iop_16Sto32,
+ unop(Iop_32to16,
+ getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16,
+ getIReg(rt)))),
+ mkU8(0x1)));
+ assign(t6, binop(Iop_CmpEQ32,
+ unop(Iop_16Uto32,
+ unop(Iop_32to16, getIReg(rs))),
+ mkU32(0x00008000)));
+ assign(t7, binop(Iop_CmpEQ32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16, getIReg(rt))),
+ mkU32(0x00008000)));
+ assign(t8,
+ IRExpr_ITE(mkexpr(t6),
+ IRExpr_ITE(mkexpr(t7),
+ mkU64(0x000000007fffffffULL),
+ mkexpr(t5)),
+ mkexpr(t5)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t6),
+ IRExpr_ITE(mkexpr(t7),
+ binop(Iop_Or32,
+ getDSPControl(),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkU8(ac+16)
+ )
+ ),
+ getDSPControl()),
+ getDSPControl()));
+
+ assign(t9, binop(Iop_Sub64,
+ mkexpr(t0),
+ binop(Iop_Add64, mkexpr(t4), mkexpr(t8))));
+ putAcc(ac, mkexpr(t9));
+ break;
+ }
+ case 0x1A: { /* DPAQX_SA.W.PH */
+ DIP("dpaqx_sa.w.ph ac%d, r%d, r%d", ac, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I1);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I64);
+ t5 = newTemp(Ity_I64);
+ t6 = newTemp(Ity_I1);
+ t7 = newTemp(Ity_I1);
+ t8 = newTemp(Ity_I64);
+ t9 = newTemp(Ity_I64);
+ t10 = newTemp(Ity_I32);
+ t11 = newTemp(Ity_I32);
+
+ assign(t0, getAcc(ac));
+ /* Calculate first cross dot product and saturate if
+ needed. */
+ assign(t1, unop(Iop_32Sto64,
+ binop(Iop_Shl32,
+ binop(Iop_Mul32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16,
+ getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32to16,
+ getIReg(rt)))),
+ mkU8(0x1))));
+
+ /* If both input arguments are equal 0x8000, saturate
+ intermediate product and write to DSPControl
+ register. */
+ assign(t2, binop(Iop_CmpEQ32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16, getIReg(rs))),
+ mkU32(0x00008000)));
+ assign(t3, binop(Iop_CmpEQ32,
+ unop(Iop_16Uto32,
+ unop(Iop_32to16, getIReg(rt))),
+ mkU32(0x00008000)));
+
+ assign(t4,
+ IRExpr_ITE(mkexpr(t2),
+ IRExpr_ITE(mkexpr(t3),
+ mkU64(0x000000007fffffffULL),
+ mkexpr(t1)),
+ mkexpr(t1)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t2),
+ IRExpr_ITE(mkexpr(t3),
+ binop(Iop_Or32,
+ getDSPControl(),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkU8(ac+16)
+ )
+ ),
+ getDSPControl()),
+ getDSPControl()));
+ /* Calculate second cross dot product and saturate if
+ needed. */
+ assign(t5, unop(Iop_32Sto64,
+ binop(Iop_Shl32,
+ binop(Iop_Mul32,
+ unop(Iop_16Sto32,
+ unop(Iop_32to16,
+ getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16,
+ getIReg(rt)))),
+ mkU8(0x1))));
+
+ /* If both input arguments are equal 0x8000, saturate
+ intermediate product and write to DSPControl
+ register. */
+ assign(t6, binop(Iop_CmpEQ32,
+ unop(Iop_16Uto32,
+ unop(Iop_32to16, getIReg(rs))),
+ mkU32(0x00008000)));
+ assign(t7, binop(Iop_CmpEQ32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16, getIReg(rt))),
+ mkU32(0x00008000)));
+
+ assign(t8,
+ IRExpr_ITE(mkexpr(t6),
+ IRExpr_ITE(mkexpr(t7),
+ mkU64(0x000000007fffffffULL),
+ mkexpr(t5)),
+ mkexpr(t5)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t6),
+ IRExpr_ITE(mkexpr(t7),
+ binop(Iop_Or32,
+ getDSPControl(),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkU8(ac+16)
+ )
+ ),
+ getDSPControl()),
+ getDSPControl()));
+ /* Add intermediate products with value in the
+ accumulator. */
+ assign(t9, binop(Iop_Add64,
+ mkexpr(t0),
+ binop(Iop_Add64, mkexpr(t8), mkexpr(t4))));
+
+ putAcc(ac,
+ IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ unop(Iop_64HIto32,
+ mkexpr(t9)),
+ mkU32(0x80000000)),
+ mkU32(0x0)),
+ IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_64HIto32,
+ binop(Iop_Shl64,
+ mkexpr(t9),
+ mkU8(1))),
+ mkU32(0x0)),
+ mkU64(0x000000007fffffffULL),
+ mkexpr(t9)),
+ IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_64HIto32,
+ binop(Iop_Shl64,
+ mkexpr(t9),
+ mkU8(1))),
+ mkU32(0xffffffff)),
+ mkU64(0xffffffff80000000ULL),
+ mkexpr(t9))));
+ assign(t10, IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_64HIto32,
+ binop(Iop_Shl64,
+ mkexpr(t9),
+ mkU8(1))),
+ mkU32(0x0)),
+ binop(Iop_Or32,
+ getDSPControl(),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkU8(ac+16))),
+ getDSPControl()));
+ assign(t11, IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_64HIto32,
+ binop(Iop_Shl64,
+ mkexpr(t9),
+ mkU8(1))),
+ mkU32(0xffffffff)),
+ binop(Iop_Or32,
+ getDSPControl(),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkU8(ac+16))),
+ getDSPControl()));
+ putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ unop(Iop_64HIto32,
+ mkexpr(t9)),
+ mkU32(0x80000000)),
+ mkU32(0x0)),
+ mkexpr(t10),
+ mkexpr(t11)));
+ break;
+ }
+ case 0x1B: { /* DPSQX_SA.W.PH */
+ DIP("dpsqx_sa.w.ph ac%d, r%d, r%d", ac, rs, rt);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I1);
+ t3 = newTemp(Ity_I1);
+ t4 = newTemp(Ity_I64);
+ t5 = newTemp(Ity_I64);
+ t6 = newTemp(Ity_I1);
+ t7 = newTemp(Ity_I1);
+ t8 = newTemp(Ity_I64);
+ t9 = newTemp(Ity_I64);
+ t10 = newTemp(Ity_I32);
+ t11 = newTemp(Ity_I32);
+
+ assign(t0, getAcc(ac));
+ /* Calculate first cross dot product and saturate if
+ needed. */
+ assign(t1, unop(Iop_32Sto64,
+ binop(Iop_Shl32,
+ binop(Iop_Mul32,
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16,
+ getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32to16,
+ getIReg(rt)))),
+ mkU8(0x1))));
+
+ /* If both input arguments are equal 0x8000, saturate
+ intermediate product and write to DSPControl
+ register. */
+ assign(t2, binop(Iop_CmpEQ32,
+ unop(Iop_16Uto32,
+ unop(Iop_32HIto16, getIReg(rs))),
+ mkU32(0x00008000)));
+ assign(t3, binop(Iop_CmpEQ32,
+ unop(Iop_16Uto32,
+ unop(Iop_32to16, getIReg(rt))),
+ mkU32(0x00008000)));
+
+ assign(t4,
+ IRExpr_ITE(mkexpr(t2),
+ IRExpr_ITE(mkexpr(t3),
+ mkU64(0x000000007fffffffULL),
+ mkexpr(t1)),
+ mkexpr(t1)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t2),
+ IRExpr_ITE(mkexpr(t3),
+ binop(Iop_Or32,
+ getDSPControl(),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkU8(ac+16)
+ )
+ ),
+ getDSPControl()),
+ getDSPControl()));
+ /* Calculate second cross dot product and saturate if
+ needed. */
+ assign(t5, unop(Iop_32Sto64,
+ binop(Iop_Shl32,
+ binop(Iop_Mul32,
+ unop(Iop_16Sto32,
+ unop(Iop_32to16,
+ getIReg(rs))),
+ unop(Iop_16Sto32,
+ unop(Iop_32HIto16,
+ getIReg(rt)))),
+ mkU8(0x1))));
+
+ /* If both input arguments are equal 0x8000, saturate
+ intermediate product and write to DSPControl
+ register. */
+ assign(t6, binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x0000ffff)),
+ mkU32(0x00008000)));
+ assign(t7, binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ getIReg(rt),
+ mkU32(0xffff0000)),
+ mkU32(0x80000000)));
+
+ assign(t8,
+ IRExpr_ITE(mkexpr(t6),
+ IRExpr_ITE(mkexpr(t7),
+ mkU64(0x000000007fffffffULL),
+ mkexpr(t5)),
+ mkexpr(t5)));
+
+ putDSPControl(IRExpr_ITE(mkexpr(t6),
+ IRExpr_ITE(mkexpr(t7),
+ binop(Iop_Or32,
+ getDSPControl(),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkU8(ac+16))),
+ getDSPControl()),
+ getDSPControl()));
+ /* Subtract intermediate products from value in the
+ accumulator. */
+ assign(t9,
+ binop(Iop_Sub64,
+ mkexpr(t0),
+ binop(Iop_Add64, mkexpr(t8), mkexpr(t4))));
+
+ putAcc(ac,
+ IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ unop(Iop_64HIto32,
+ mkexpr(t9)),
+ mkU32(0x80000000)),
+ mkU32(0x0)),
+ IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_64HIto32,
+ binop(Iop_Shl64,
+ mkexpr(t9),
+ mkU8(1))),
+ mkU32(0x0)),
+ mkU64(0x000000007fffffffULL),
+ mkexpr(t9)),
+ IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_64HIto32,
+ binop(Iop_Shl64,
+ mkexpr(t9),
+ mkU8(1))),
+ mkU32(0xffffffff)),
+ mkU64(0xffffffff80000000ULL),
+ mkexpr(t9))));
+ assign(t10, IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_64HIto32,
+ binop(Iop_Shl64,
+ mkexpr(t9),
+ mkU8(1))),
+ mkU32(0x0)),
+ binop(Iop_Or32,
+ getDSPControl(),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkU8(ac+16))),
+ getDSPControl()));
+ assign(t11, IRExpr_ITE(binop(Iop_CmpNE32,
+ unop(Iop_64HIto32,
+ binop(Iop_Shl64,
+ mkexpr(t9),
+ mkU8(1))),
+ mkU32(0xffffffff)),
+ binop(Iop_Or32,
+ getDSPControl(),
+ binop(Iop_Shl32,
+ mkU32(0x1),
+ mkU8(ac+16))),
+ getDSPControl()));
+ putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32,
+ binop(Iop_And32,
+ unop(Iop_64HIto32,
+ mkexpr(t9)),
+ mkU32(0x80000000)),
+ mkU32(0x0)),
+ mkexpr(t10),
+ mkexpr(t11)));
+ break;
+ }
+ default:
+ return -1;
+ }
+ break; /* end of DPAQ.W.PH */
+ }
+ case 0x31: { /* APPEND */
+ switch(sa) {
+ case 0x0: { /* APPEND */
+ DIP("append r%d, r%d, %d", rt, rs, rd);
+ vassert(!mode64);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I32);
+
+ assign(t1, binop(Iop_Shl32, getIReg(rt), mkU8(rd)));
+
+ if (31 == rd) {
+ putIReg(rt, binop(Iop_Or32,
+ mkexpr(t1),
+ binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x7fffffff))));
+ } else if (1 == rd) {
+ putIReg(rt,
+ binop(Iop_Or32,
+ mkexpr(t1),
+ binop(Iop_And32,
+ getIReg(rs), mkU32(0x1))));
+ } else {
+ assign(t2,
+ unop(Iop_Not32,
+ binop(Iop_Shl32,
+ mkU32(0xffffffff), mkU8(rd))));
+
+ putIReg(rt, binop(Iop_Or32,
+ mkexpr(t1),
+ binop(Iop_And32,
+ getIReg(rs), mkexpr(t2))));
+ }
+ break;
+ }
+ case 0x1: { /* PREPEND */
+ DIP("prepend r%d, r%d, %d", rt, rs, rd);
+ vassert(!mode64);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I32);
+
+ if (0 != rd) {
+ assign(t1, binop(Iop_Shr32, getIReg(rt), mkU8(rd)));
+
+ if (31 == rd) {
+ putIReg(rt, binop(Iop_Or32,
+ mkexpr(t1),
+ binop(Iop_Shl32,
+ binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x7fffffff)),
+ mkU8(1))));
+ } else if (1 == rd) {
+ putIReg(rt, binop(Iop_Or32,
+ mkexpr(t1),
+ binop(Iop_Shl32,
+ binop(Iop_And32,
+ getIReg(rs),
+ mkU32(0x1)),
+ mkU8(31))));
+ } else {
+ assign(t2, binop(Iop_Add32, mkU32(rd), mkU32(0x1)));
+
+ assign(t3, unop(Iop_Not32,
+ binop(Iop_Shl32,
+ mkU32(0xffffffff),
+ unop(Iop_32to8, mkexpr(t2)))));
+
+ putIReg(rt, binop(Iop_Or32,
+ mkexpr(t1),
+ binop(Iop_Shl32,
+ binop(Iop_And32,
+ getIReg(rs),
+ mkexpr(t3)),
+ mkU8(32-rd))));
+ }
+ }
+ break;
+ }
+ case 0x10: { /* BALIGN */
+ DIP("balign r%d, r%d, %d", rt, rs, rd);
+ vassert(!mode64);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I32);
+
+ if ((2 != rd) && (0 != rd)) {
+ assign(t1, binop(Iop_Shl32,
+ binop(Iop_And32,
+ mkU32(rd), mkU32(0x3)),
+ mkU8(0x3)));
+ assign(t2, binop(Iop_Shl32,
+ getIReg(rt),
+ unop(Iop_32to8, mkexpr(t1))));
+ assign(t3, binop(Iop_Shr32,
+ getIReg(rs),
+ unop(Iop_32to8,
+ binop(Iop_Shl32,
+ binop(Iop_Sub32,
+ mkU32(0x4),
+ binop(Iop_And32,
+ mkU32(rd),
+ mkU32(0x3))),
+ mkU8(0x3)))));
+ putIReg(rt, binop(Iop_Or32, mkexpr(t2), mkexpr(t3)));
+ }
+ break;
+ }
+ default:
+ return -1;
+ }
+ break; /* end of APPEND */
+ }
+ default:
+ return -1;
}
break;
- default:
- return False;
}
- *set = IRStmt_Exit(eCond, jmpKind, mkSzConst(ty, addrTgt), OFFB_PC);
- return True;
+ default:
+ return -1;
+ }
+ return 0;
}
/*------------------------------------------------------------*/
Bool sigill_diag )
{
IRTemp t0, t1 = 0, t2, t3, t4, t5, t6, t7;
+
UInt opcode, cins, rs, rt, rd, sa, ft, fs, fd, fmt, tf, nd, function,
trap_code, imm, instr_index, p, msb, lsb, size, rot, sel;
+ /* Additional variables for instruction fields in DSP ASE insructions */
+ UInt ac;
DisResult dres;
/* Spot "Special" instructions (see comment at top of file). */
{
- /* Spot the 16-byte preamble:
+ /* Spot the 16-byte preamble:
****mips32****
"srl $0, $0, 13
"srl $0, $0, 29
IRType ty = mode64 ? Ity_I64 : Ity_I32;
IRType tyF = mode64 ? Ity_F64 : Ity_F32;
+ ac = get_acNo(cins);
+
switch (opcode) {
case 0x03: /* JAL */
}
case 0x1: { /* LDXC1 */
- /* Load Doubleword Indexed to Floating Point
+ /* Load Doubleword Indexed to Floating Point
LDXC1 (MIPS32r2 and MIPS64) */
if (mode64) {
DIP("ldxc1 f%d, r%d(r%d)", fd, rt, rs);
}
break;
}
- case 0xD: /* Store Doubleword Indexed Unaligned from Floating Point -
+ case 0xD: /* Store Doubleword Indexed Unaligned from Floating Point -
SUXC1; MIPS64 MIPS32r2 */
DIP("suxc1 f%d, r%d(r%d)", fd, rt, rs);
t0 = newTemp(Ity_I64);
assign(E_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkexpr(t3), mkU64(0x4)),
mkU64(0x4),
mkU64(0x0)));
-
+
assign(F_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkexpr(t3), mkU64(0x3)),
mkU64(0x5),
mkU64(0x0)));
break;
}
- case 0x00: { /* MADD */
- DIP("madd r%d, r%d", rs, rt);
- if (mode64) {
- t1 = newTemp(Ity_I32);
- t2 = newTemp(Ity_I32);
- t3 = newTemp(Ity_I64);
- t4 = newTemp(Ity_I64);
- t5 = newTemp(Ity_I64);
- t6 = newTemp(Ity_I32);
+ case 0x00: { /* MADD */
+ if (mode64) {
+ DIP("madd r%d, r%d", rs, rt);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I64);
+ t4 = newTemp(Ity_I64);
+ t5 = newTemp(Ity_I64);
+ t6 = newTemp(Ity_I32);
- assign(t1, mkNarrowTo32(ty, getHI()));
- assign(t2, mkNarrowTo32(ty, getLO()));
+ assign(t1, mkNarrowTo32(ty, getHI()));
+ assign(t2, mkNarrowTo32(ty, getLO()));
- assign(t3, binop(Iop_MullS32, mkNarrowTo32(ty, getIReg(rs)),
- mkNarrowTo32(ty, getIReg(rt))));
+ assign(t3, binop(Iop_MullS32, mkNarrowTo32(ty, getIReg(rs)),
+ mkNarrowTo32(ty, getIReg(rt))));
- assign(t4, binop(Iop_32HLto64, mkexpr(t1), mkexpr(t2)));
- assign(t5, binop(Iop_Add64, mkexpr(t3), mkexpr(t4)));
+ assign(t4, binop(Iop_32HLto64, mkexpr(t1), mkexpr(t2)));
+ assign(t5, binop(Iop_Add64, mkexpr(t3), mkexpr(t4)));
- putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t5)), True));
- putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t5)), True));
- } else {
- t1 = newTemp(Ity_I32);
- t2 = newTemp(Ity_I32);
- t3 = newTemp(Ity_I64);
- t4 = newTemp(Ity_I32);
- t5 = newTemp(Ity_I32);
- t6 = newTemp(Ity_I32);
+ putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t5)), True));
+ putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t5)), True));
+ } else {
+ if ( (1 <= ac) && ( 3 >= ac) ) {
+ if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP)) {
+ /* If DSP is present -> DSP ASE MADD */
+ UInt retVal = disDSPInstr_MIPS_WRK ( cins );
+ if (0 != retVal ) {
+ goto decode_failure_dsp;
+ }
+ break;
+ } else {
+ goto decode_failure_dsp;
+ }
+ } else {
+ DIP("madd r%d, r%d", rs, rt);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I64);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I32);
+ t6 = newTemp(Ity_I32);
- assign(t1, getHI());
- assign(t2, getLO());
+ assign(t1, getHI());
+ assign(t2, getLO());
- assign(t3, binop(Iop_MullS32, getIReg(rs), getIReg(rt)));
+ assign(t3, binop(Iop_MullS32, getIReg(rs), getIReg(rt)));
- assign(t4, binop(Iop_Add32, mkexpr(t2), unop(Iop_64to32,
- mkexpr(t3))));
+ assign(t4, binop(Iop_Add32, mkexpr(t2), unop(Iop_64to32,
+ mkexpr(t3))));
- assign(t5, unop(Iop_1Uto32, binop(Iop_CmpLT32U, mkexpr(t4),
- unop(Iop_64to32, mkexpr(t3)))));
- assign(t6, binop(Iop_Add32, mkexpr(t5), mkexpr(t1)));
+ assign(t5, unop(Iop_1Uto32, binop(Iop_CmpLT32U, mkexpr(t4),
+ unop(Iop_64to32, mkexpr(t3)))));
+ assign(t6, binop(Iop_Add32, mkexpr(t5), mkexpr(t1)));
- putHI(binop(Iop_Add32, mkexpr(t6), unop(Iop_64HIto32, mkexpr(t3))));
- putLO(mkexpr(t4));
+ putHI(binop(Iop_Add32, mkexpr(t6), unop(Iop_64HIto32,
+ mkexpr(t3))));
+ putLO(mkexpr(t4));
+ break;
+ }
+ }
+ break;
}
- break;
- }
case 0x01: { /* MADDU */
- DIP("maddu r%d, r%d", rs, rt);
if (mode64) {
+ DIP("maddu r%d, r%d", rs, rt);
t1 = newTemp(Ity_I32);
t2 = newTemp(Ity_I32);
t3 = newTemp(Ity_I64);
putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t5)), True));
putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t5)), True));
} else {
- t1 = newTemp(Ity_I32);
- t2 = newTemp(Ity_I32);
- t3 = newTemp(Ity_I64);
- t4 = newTemp(Ity_I32);
- t5 = newTemp(Ity_I32);
- t6 = newTemp(Ity_I32);
+ if ( (1 <= ac) && ( 3 >= ac) ) {
+ if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP)) {
+ /* If DSP is present -> DSP ASE MADDU */
+ UInt retVal = disDSPInstr_MIPS_WRK ( cins );
+ if (0 != retVal ) {
+ goto decode_failure_dsp;
+ }
+ break;
+ } else {
+ goto decode_failure_dsp;
+ }
+ } else {
+ DIP("maddu r%d, r%d", rs, rt);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I64);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I32);
+ t6 = newTemp(Ity_I32);
- assign(t1, getHI());
- assign(t2, getLO());
+ assign(t1, getHI());
+ assign(t2, getLO());
- assign(t3, binop(Iop_MullU32, getIReg(rs), getIReg(rt)));
+ assign(t3, binop(Iop_MullU32, getIReg(rs), getIReg(rt)));
- assign(t4, binop(Iop_Add32, mkexpr(t2), unop(Iop_64to32,
- mkexpr(t3))));
- assign(t5, unop(Iop_1Uto32, binop(Iop_CmpLT32U, mkexpr(t4),
- unop(Iop_64to32, mkexpr(t3)))));
- assign(t6, binop(Iop_Add32, mkexpr(t5), mkexpr(t1)));
+ assign(t4, binop(Iop_Add32, mkexpr(t2), unop(Iop_64to32,
+ mkexpr(t3))));
+ assign(t5, unop(Iop_1Uto32, binop(Iop_CmpLT32U, mkexpr(t4),
+ unop(Iop_64to32, mkexpr(t3)))));
+ assign(t6, binop(Iop_Add32, mkexpr(t5), mkexpr(t1)));
- putHI(binop(Iop_Add32, mkexpr(t6), unop(Iop_64HIto32, mkexpr(t3))));
- putLO(mkexpr(t4));
+ putHI(binop(Iop_Add32, mkexpr(t6), unop(Iop_64HIto32,
+ mkexpr(t3))));
+ putLO(mkexpr(t4));
+ break;
+ }
}
break;
}
case 0x04: { /* MSUB */
- DIP("msub r%d, r%d", rs, rt);
if (mode64) {
+ DIP("msub r%d, r%d", rs, rt);
t1 = newTemp(Ity_I32);
t2 = newTemp(Ity_I32);
t3 = newTemp(Ity_I64);
putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t5)), True));
putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t5)), True));
} else {
- t1 = newTemp(Ity_I32);
- t2 = newTemp(Ity_I32);
- t3 = newTemp(Ity_I64);
- t4 = newTemp(Ity_I32);
- t5 = newTemp(Ity_I1);
- t6 = newTemp(Ity_I32);
+ if ( (1 <= ac) && ( 3 >= ac) ) {
+ if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP)) {
+ /* If DSP is present -> DSP ASE MSUB */
+ UInt retVal = disDSPInstr_MIPS_WRK ( cins );
+ if (0 != retVal ) {
+ goto decode_failure_dsp;
+ }
+ break;
+ } else {
+ goto decode_failure_dsp;
+ }
+ } else {
+ DIP("msub r%d, r%d", rs, rt);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I64);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I1);
+ t6 = newTemp(Ity_I32);
- assign(t1, getHI());
- assign(t2, getLO());
+ assign(t1, getHI());
+ assign(t2, getLO());
- assign(t3, binop(Iop_MullS32, getIReg(rs), getIReg(rt)));
- assign(t4, unop(Iop_64to32, mkexpr(t3))); /* new lo */
+ assign(t3, binop(Iop_MullS32, getIReg(rs), getIReg(rt)));
+ assign(t4, unop(Iop_64to32, mkexpr(t3))); /* new lo */
- /* if lo<lo(mul) hi = hi - 1 */
- assign(t5, binop(Iop_CmpLT32U, mkexpr(t2), mkexpr(t4)));
+ /* if lo<lo(mul) hi = hi - 1 */
+ assign(t5, binop(Iop_CmpLT32U,
+ mkexpr(t2),
+ mkexpr(t4)));
- assign(t6, IRExpr_ITE(mkexpr(t5),
- binop(Iop_Sub32, mkexpr(t1), mkU32(0x1)),
- mkexpr(t1)));
+ assign(t6, IRExpr_ITE(mkexpr(t5),
+ binop(Iop_Sub32, mkexpr(t1), mkU32(0x1)),
+ mkexpr(t1)));
- putHI(binop(Iop_Sub32, mkexpr(t6), unop(Iop_64HIto32, mkexpr(t3))));
- putLO(binop(Iop_Sub32, mkexpr(t2), mkexpr(t4)));
+ putHI(binop(Iop_Sub32, mkexpr(t6), unop(Iop_64HIto32,
+ mkexpr(t3))));
+ putLO(binop(Iop_Sub32, mkexpr(t2), mkexpr(t4)));
+ break;
+ }
}
break;
}
- case 0x05: { /* MSUBU */
- DIP("msubu r%d, r%d", rs, rt);
+ case 0x05: { /* MSUBU */
if (mode64) {
+ DIP("msubu r%d, r%d", rs, rt);
t1 = newTemp(Ity_I32);
t2 = newTemp(Ity_I32);
t3 = newTemp(Ity_I64);
putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t5)), True));
putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t5)), True));
} else {
- t1 = newTemp(Ity_I32);
- t2 = newTemp(Ity_I32);
- t3 = newTemp(Ity_I64);
- t4 = newTemp(Ity_I32);
- t5 = newTemp(Ity_I1);
- t6 = newTemp(Ity_I32);
+ if ( (1 <= ac) && ( 3 >= ac) ) {
+ if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP)) {
+ /* If DSP is present -> DSP ASE MSUBU */
+ UInt retVal = disDSPInstr_MIPS_WRK ( cins );
+ if (0 != retVal ) {
+ goto decode_failure_dsp;
+ }
+ break;
+ } else {
+ goto decode_failure_dsp;
+ }
+ } else {
+ DIP("msubu r%d, r%d", rs, rt);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I64);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I1);
+ t6 = newTemp(Ity_I32);
- assign(t1, getHI());
- assign(t2, getLO());
+ assign(t1, getHI());
+ assign(t2, getLO());
- assign(t3, binop(Iop_MullU32, getIReg(rs), getIReg(rt)));
- assign(t4, unop(Iop_64to32, mkexpr(t3))); /* new lo */
+ assign(t3, binop(Iop_MullU32, getIReg(rs), getIReg(rt)));
+ assign(t4, unop(Iop_64to32, mkexpr(t3))); /* new lo */
- /* if lo<lo(mul) hi = hi - 1 */
- assign(t5, binop(Iop_CmpLT32U, mkexpr(t2), mkexpr(t4)));
+ /* if lo<lo(mul) hi = hi - 1 */
+ assign(t5, binop(Iop_CmpLT32U,
+ mkexpr(t2),
+ mkexpr(t4)));
- assign(t6, IRExpr_ITE(mkexpr(t5),
- binop(Iop_Sub32, mkexpr(t1), mkU32(0x1)),
- mkexpr(t1)));
+ assign(t6, IRExpr_ITE(mkexpr(t5),
+ binop(Iop_Sub32,
+ mkexpr(t1),
+ mkU32(0x1)),
+ mkexpr(t1)));
- putHI(binop(Iop_Sub32, mkexpr(t6), unop(Iop_64HIto32, mkexpr(t3))));
- putLO(binop(Iop_Sub32, mkexpr(t2), mkexpr(t4)));
+ putHI(binop(Iop_Sub32, mkexpr(t6), unop(Iop_64HIto32,
+ mkexpr(t3))));
+ putLO(binop(Iop_Sub32, mkexpr(t2), mkexpr(t4)));
+ break;
+ }
}
break;
}
assign(t2, binop(Iop_Shl32, mkNarrowTo32(ty, getIReg(rt)),
mkU8(32 - lsb)));
assign(t3, binop(Iop_Shr32, mkexpr(t2), mkU8(32 - lsb)));
- } else
+ } else
assign(t3, mkU32(0));
if (msb < 31) {
}
break; /* BSHFL */
- default:
- goto decode_failure;
+ /* -------- MIPS32(r2) DSP ASE(r2) instructions -------- */
+ case 0xA: /* LX */
+ case 0xC: /* INSV */
+ case 0x38: { /* EXTR.W */
+ if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP)) {
+ UInt retVal = disDSPInstr_MIPS_WRK ( cins );
+ if (0 != retVal ) {
+ goto decode_failure_dsp;
+ }
+ break;
+ } else {
+ goto decode_failure_dsp;
+ }
+ break;
+ }
+ case 0x10: { /* ADDU.QB */
+ switch(sa) {
+ case 0xC: /* SUBU_S.PH */
+ case 0xD: /* ADDU_S.PH */
+ case 0x1E: { /* MULQ_S.PH */
+ if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP2P)) {
+ UInt retVal = disDSPInstr_MIPS_WRK ( cins );
+ if (0 != retVal ) {
+ goto decode_failure_dsp;
+ }
+ break;
+ } else {
+ goto decode_failure_dsp;
+ }
+ break;
+ }
+ default: {
+ if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP)) {
+ UInt retVal = disDSPInstr_MIPS_WRK ( cins );
+ if (0 != retVal ) {
+ goto decode_failure_dsp;
+ }
+ break;
+ } else {
+ goto decode_failure_dsp;
+ }
+ break;
+ }
+ }
+ break;
}
+ case 0x11: { /* CMPU.EQ.QB */
+ switch(sa) {
+ case 0x18: /* CMPGDU.EQ.QB */
+ case 0x19: /* CMPGDU.LT.QB */
+ case 0x1A: /* CMPGDU.LE.QB */
+ case 0x0D: /* PRECR.QB.PH */
+ case 0x1E: /* PRECR_SRA.PH.W */
+ case 0x1F: { /* PRECR_SRA_R.PH.W */
+ if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP2P)) {
+ UInt retVal = disDSPInstr_MIPS_WRK ( cins );
+ if (0 != retVal ) {
+ goto decode_failure_dsp;
+ }
+ break;
+ } else {
+ goto decode_failure_dsp;
+ }
+ break;
+ }
+ default: {
+ if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP)) {
+ UInt retVal = disDSPInstr_MIPS_WRK ( cins );
+ if (0 != retVal ) {
+ goto decode_failure_dsp;
+ }
+ break;
+ } else {
+ goto decode_failure_dsp;
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case 0x12: { /* ABSQ_S.PH */
+ switch(sa){
+ case 0x1: { /* ABSQ_S.QB */
+ if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP2P)) {
+ UInt retVal = disDSPInstr_MIPS_WRK ( cins );
+ if (0 != retVal ) {
+ goto decode_failure_dsp;
+ }
+ break;
+ } else {
+ goto decode_failure_dsp;
+ }
+ break;
+ }
+ default: {
+ if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP)) {
+ UInt retVal = disDSPInstr_MIPS_WRK ( cins );
+ if (0 != retVal ) {
+ goto decode_failure_dsp;
+ }
+ break;
+ } else {
+ goto decode_failure_dsp;
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case 0x13: { /* SHLL.QB */
+ switch(sa) {
+ case 0x04: /* SHRA.QB */
+ case 0x05: /* SHRA_R.QB */
+ case 0x06: /* SHRAV.QB */
+ case 0x07: /* SHRAV_R.QB */
+ case 0x19: /* SHLR.PH */
+ case 0x1B: { /* SHLRV.PH */
+ if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP2P)) {
+ UInt retVal = disDSPInstr_MIPS_WRK ( cins );
+ if (0 != retVal ) {
+ goto decode_failure_dsp;
+ }
+ break;
+ } else {
+ goto decode_failure_dsp;
+ }
+ break;
+ }
+ default: {
+ if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP)) {
+ UInt retVal = disDSPInstr_MIPS_WRK ( cins );
+ if (0 != retVal ) {
+ goto decode_failure_dsp;
+ }
+ break;
+ } else {
+ goto decode_failure_dsp;
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case 0x30: { /* DPAQ.W.PH */
+ switch(sa) {
+ case 0x0: /* DPA.W.PH */
+ case 0x18: /* DPAQX_S.W.PH */
+ case 0x1A: /* DPAQX_SA.W.PH */
+ case 0x8: /* DPAX.W.PH */
+ case 0x1: /* DPS.W.PH */
+ case 0x19: /* DPSQX_S.W.PH */
+ case 0x1B: /* DPSQX_SA.W.PH */
+ case 0x9: /* DPSX.W.PH */
+ case 0x2: { /* MULSA.W.PH */
+ if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP2P)) {
+ UInt retVal = disDSPInstr_MIPS_WRK ( cins );
+ if (0 != retVal ) {
+ goto decode_failure_dsp;
+ }
+ break;
+ } else {
+ goto decode_failure_dsp;
+ }
+ break;
+ }
+ default: {
+ if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP)) {
+ UInt retVal = disDSPInstr_MIPS_WRK ( cins );
+ if (0 != retVal ) {
+ goto decode_failure_dsp;
+ }
+ break;
+ } else {
+ goto decode_failure_dsp;
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case 0x18: /* ADDUH.QB/MUL.PH */
+ case 0x31: { /* APPEND */
+ if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP2P)) {
+ UInt retVal = disDSPInstr_MIPS_WRK ( cins );
+ if (0 != retVal ) {
+ goto decode_failure_dsp;
+ }
+ break;
+ } else {
+ goto decode_failure_dsp;
+ }
+ }
+ default:
+ goto decode_failure;
+
+ }
break; /* Special3 */
case 0x3B:
break;
}
- case 0x18: /* MULT */
- DIP("mult r%d, r%d", rs, rt);
- t2 = newTemp(Ity_I64);
-
- assign(t2, binop(Iop_MullS32, mkNarrowTo32(ty, getIReg(rs)),
- mkNarrowTo32(ty, getIReg(rt))));
-
- putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t2)), True));
- putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t2)), True));
- break;
+ case 0x18: { /* MULT */
+ if ( (1 <= ac) && ( 3 >= ac) ) {
+ if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP)) {
+ /* If DSP is present -> DSP ASE MULT */
+ UInt retVal = disDSPInstr_MIPS_WRK ( cins );
+ if (0 != retVal ) {
+ goto decode_failure_dsp;
+ }
+ break;
+ } else {
+ goto decode_failure_dsp;
+ }
+ } else {
+ DIP("mult r%d, r%d", rs, rt);
+ t2 = newTemp(Ity_I64);
- case 0x19: /* MULTU */
- DIP("multu r%d, r%d", rs, rt);
- t2 = newTemp(Ity_I64);
+ assign(t2, binop(Iop_MullS32, mkNarrowTo32(ty, getIReg(rs)),
+ mkNarrowTo32(ty, getIReg(rt))));
- assign(t2, binop(Iop_MullU32, mkNarrowTo32(ty, getIReg(rs)),
- mkNarrowTo32(ty, getIReg(rt))));
+ putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t2)), True));
+ putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t2)), True));
+ break;
+ }
+ }
+ case 0x19: { /* MULTU */
+ if ( (1 <= ac) && ( 3 >= ac) ) {
+ if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP)) {
+ /* If DSP is present -> DSP ASE MULTU */
+ UInt retVal = disDSPInstr_MIPS_WRK ( cins );
+ if (0 != retVal ) {
+ goto decode_failure_dsp;
+ }
+ break;
+ } else {
+ goto decode_failure_dsp;
+ }
+ } else {
+ DIP("multu r%d, r%d", rs, rt);
+ t2 = newTemp(Ity_I64);
- putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t2)), True));
- putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t2)), True));
- break;
+ assign(t2, binop(Iop_MullU32, mkNarrowTo32(ty, getIReg(rs)),
+ mkNarrowTo32(ty, getIReg(rt))));
+ putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t2)), True));
+ putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t2)), True));
+ break;
+ }
+ }
case 0x20: { /* ADD */
DIP("add r%d, r%d, r%d", rd, rs, rt);
IRTemp tmpRs32 = newTemp(Ity_I32);
t3 = newTemp(Ity_I32);
t4 = newTemp(Ity_I32);
/* dst = src0 + src1
- if(sign(src0 ) != sign(src1 ))
+ if (sign(src0 ) != sign(src1 ))
goto no overflow;
- if(sign(dst) == sign(src0 ))
+ if (sign(dst) == sign(src0 ))
goto no overflow;
we have overflow! */
putLO(unop(Iop_128to64, mkexpr(t2)));
break;
- case 0x10: /* MFHI */
- DIP("mfhi r%d", rd);
- putIReg(rd, getHI());
- break;
+ case 0x10: { /* MFHI */
+ if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP)) {
+ /* If DSP is present -> DSP ASE MFHI */
+ UInt retVal = disDSPInstr_MIPS_WRK ( cins );
+ if (0 != retVal ) {
+ goto decode_failure;
+ }
+ break;
+ } else {
+ DIP("mfhi r%d", rd);
+ putIReg(rd, getHI());
+ break;
+ }
+ }
- case 0x11: /* MTHI */
- DIP("mthi r%d", rs);
- putHI(getIReg(rs));
- break;
+ case 0x11: { /* MTHI */
+ if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP)) {
+ /* If DSP is present -> DSP ASE MTHI */
+ UInt retVal = disDSPInstr_MIPS_WRK ( cins );
+ if (0 != retVal ) {
+ goto decode_failure;
+ }
+ break;
+ } else {
+ DIP("mthi r%d", rs);
+ putHI(getIReg(rs));
+ break;
+ }
+ }
- case 0x12: /* MFLO */
- DIP("mflo r%d", rd);
- putIReg(rd, getLO());
- break;
+ case 0x12: { /* MFLO */
+ if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP)) {
+ /* If DSP is present -> DSP ASE MFLO */
+ UInt retVal = disDSPInstr_MIPS_WRK ( cins );
+ if (0 != retVal ) {
+ goto decode_failure;
+ }
+ break;
+ } else {
+ DIP("mflo r%d", rd);
+ putIReg(rd, getLO());
+ break;
+ }
+ }
- case 0x13: /* MTLO */
- DIP("mtlo r%d", rs);
- putLO(getIReg(rs));
- break;
+ case 0x13: { /* MTLO */
+ if ((archinfo->hwcaps & VEX_MIPS_ASE_DSP)) {
+ /* If DSP is present -> DSP ASE MTLO */
+ UInt retVal = disDSPInstr_MIPS_WRK ( cins );
+ if (0 != retVal ) {
+ goto decode_failure;
+ }
+ break;
+ } else {
+ DIP("mtlo r%d", rs);
+ putLO(getIReg(rs));
+ break;
+ }
+ }
case 0x21: /* ADDU */
DIP("addu r%d, r%d, r%d", rd, rs, rt);
}
break;
}
- }
+ }
case 0x0D: /* BREAK */
DIP("break 0x%x", trap_code);
}
break;
}
- case 0x0A: { /* TLTI */
+ case 0x0A: { /* TLTI */
DIP("tlti r%d, %d %d", rs, imm, trap_code);
if (mode64) {
stmt (IRStmt_Exit (binop (Iop_CmpLT64S, getIReg (rs),
}
break;
}
+ case 0x1C: { /* BPOSGE32 */
+ DIP("bposge32 %d", imm);
+ vassert(!mode64);
+ t0 = newTemp(Ity_I32);
+ /* Get pos field from DSPControl register. */
+ assign(t0, binop(Iop_And32, getDSPControl(), mkU32(0x3f)));
+ dis_branch(False, unop(Iop_Not1, binop(Iop_CmpLT32U, mkexpr(t0),
+ mkU32(32))), imm, &bstmt);
+ }
case 0x1F:
/* SYNCI */
/* Just ignore it */
store(mkexpr(t1), getIReg(rt));
break;
+ decode_failure_dsp:
+ vex_printf("Error occured while trying to decode MIPS32 DSP "
+ "instruction.\nYour platform probably doesn't support "
+ "MIPS32 DSP ASE.\n");
decode_failure:
/* All decode failures end up here. */
if (sigill_diag)
break;
}
- /* On MIPS we need to check if the last instruction
- in block is branch or jump. */
+ /* On MIPS we need to check if the last instruction in block is branch or
+ jump. */
if (((vex_control.guest_max_insns - 1) == (delta + 4) / 4)
&& (dres.whatNext != Dis_StopHere))
if (branch_or_jump(guest_code + delta + 4)) {