|
From: <sv...@va...> - 2013-07-25 09:08:15
|
dejanj 2013-07-25 10:08:03 +0100 (Thu, 25 Jul 2013)
New Revision: 2732
Log:
mips32: Add support for mips32 DSP instruction set.
Add support for mips32 DSP and DSP revision 2 ASE.
More details about the mips32 DSP(r2) ASE:
http://www.mips.com/media/files/MD00566-2B-MIPSDSP-QRC-01.00.pdf
Applied patch provided by Maja Gagic <maj...@rt...>
Modified files:
trunk/priv/guest_mips_helpers.c
trunk/priv/guest_mips_toIR.c
trunk/priv/host_mips_defs.c
trunk/priv/host_mips_defs.h
trunk/priv/host_mips_isel.c
trunk/priv/main_main.c
trunk/pub/libvex.h
trunk/pub/libvex_guest_mips32.h
Modified: trunk/pub/libvex_guest_mips32.h (+10 -0)
===================================================================
--- trunk/pub/libvex_guest_mips32.h 2013-07-04 21:35:42 +01:00 (rev 2731)
+++ trunk/pub/libvex_guest_mips32.h 2013-07-25 10:08:03 +01:00 (rev 2732)
@@ -139,6 +139,16 @@
UInt host_EvC_FAILADDR; /* 308 */
UInt host_EvC_COUNTER; /* 312 */
UInt guest_COND; /* 316 */
+
+ UInt padding1;
+ /* MIPS32 DSP ASE(r2) specific registers. */
+ UInt guest_DSPControl; /* 324 */
+ ULong guest_ac0; /* 328 */
+ ULong guest_ac1; /* 336 */
+ ULong guest_ac2; /* 344 */
+ ULong guest_ac3; /* 352 */
+
+ UInt padding[6];
} VexGuestMIPS32State;
/*---------------------------------------------------------------*/
/*--- Utility functions for MIPS32 guest stuff. ---*/
Modified: trunk/pub/libvex.h (+4 -0)
===================================================================
--- trunk/pub/libvex.h 2013-07-04 21:35:42 +01:00 (rev 2731)
+++ trunk/pub/libvex.h 2013-07-25 10:08:03 +01:00 (rev 2732)
@@ -185,6 +185,10 @@
#define VEX_PRID_COMP_BROADCOM 0x00020000
#define VEX_PRID_COMP_NETLOGIC 0x000c0000
+/* MIPS additional capabilities */
+#define VEX_MIPS_ASE_DSP 0x00000010 /* Signal Processing ASE */
+#define VEX_MIPS_ASE_DSP2P 0x00000040 /* Signal Processing ASE Rev 2 */
+
/* These return statically allocated strings. */
extern const HChar* LibVEX_ppVexArch ( VexArch );
Modified: trunk/priv/guest_mips_toIR.c (+9713 -162)
===================================================================
--- trunk/priv/guest_mips_toIR.c 2013-07-04 21:35:42 +01:00 (rev 2731)
+++ trunk/priv/guest_mips_toIR.c 2013-07-25 10:08:03 +01:00 (rev 2732)
@@ -395,8 +395,31 @@
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;
@@ -449,7 +472,7 @@
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))); \
@@ -641,6 +664,43 @@
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;
@@ -651,7 +711,7 @@
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;
}
@@ -694,6 +754,11 @@
}
}
+ /* bposge32 */
+ if (opcode == 0x01 && rt == 0x1c) {
+ return True;
+ }
+
return False;
}
@@ -767,13 +832,19 @@
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));
@@ -864,6 +935,11 @@
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);
@@ -911,6 +987,34 @@
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)
{
@@ -993,20 +1097,55 @@
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 )
{
vassert(ty == Ity_I32 || ty == Ity_I64);
@@ -1088,9 +1227,9 @@
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);
@@ -1104,7 +1243,7 @@
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;
@@ -1128,9 +1267,9 @@
}
/* 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)
@@ -1221,7 +1360,7 @@
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))));
}
@@ -1229,7 +1368,7 @@
static IRExpr* get_IR_roundingmode ( void )
{
-/*
+/*
rounding mode | MIPS | IR
------------------------
to nearest | 00 | 00
@@ -1270,7 +1409,7 @@
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)));
}
@@ -1515,11 +1654,11 @@
*/
/* 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));
@@ -1589,7 +1728,7 @@
case 0xF:
setFPUCondCode(mkexpr(t2), fpc_cc);
break;
-
+
default:
return False;
}
@@ -1612,12 +1751,12 @@
*/
/* 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)));
@@ -1686,7 +1825,7 @@
case 0xF:
setFPUCondCode(mkexpr(t2), fpc_cc);
break;
-
+
default:
return False;
}
@@ -1717,7 +1856,7 @@
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 */
@@ -1915,6 +2054,9071 @@
}
/*------------------------------------------------------------*/
+/*--- 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,
+ ...
[truncated message content] |