mirror of
https://github.com/ioacademy-jikim/debugging
synced 2025-06-09 17:06:24 +00:00
17315 lines
791 KiB
C
17315 lines
791 KiB
C
|
|
/*--------------------------------------------------------------------*/
|
|
/*--- begin guest_mips_toIR.c ---*/
|
|
/*--------------------------------------------------------------------*/
|
|
|
|
/*
|
|
This file is part of Valgrind, a dynamic binary instrumentation
|
|
framework.
|
|
|
|
Copyright (C) 2010-2015 RT-RK
|
|
mips-valgrind@rt-rk.com
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of the
|
|
License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|
02111-1307, USA.
|
|
|
|
The GNU General Public License is contained in the file COPYING.
|
|
*/
|
|
|
|
/* Translates MIPS code to IR. */
|
|
|
|
#include "libvex_basictypes.h"
|
|
#include "libvex_ir.h"
|
|
#include "libvex.h"
|
|
#include "libvex_guest_mips32.h"
|
|
#include "libvex_guest_mips64.h"
|
|
|
|
#include "main_util.h"
|
|
#include "main_globals.h"
|
|
#include "guest_generic_bb_to_IR.h"
|
|
#include "guest_mips_defs.h"
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- Globals ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
/* These are set at the start of the translation of a instruction, so
|
|
that we don't have to pass them around endlessly. CONST means does
|
|
not change during translation of the instruction. */
|
|
|
|
/* CONST: what is the host's endianness? This has to do with float vs
|
|
double register accesses on VFP, but it's complex and not properly
|
|
thought out. */
|
|
static VexEndness host_endness;
|
|
|
|
/* Pointer to the guest code area. */
|
|
static const UChar *guest_code;
|
|
|
|
/* CONST: The guest address for the instruction currently being
|
|
translated. */
|
|
#if defined(VGP_mips32_linux)
|
|
static Addr32 guest_PC_curr_instr;
|
|
#else
|
|
static Addr64 guest_PC_curr_instr;
|
|
#endif
|
|
|
|
/* MOD: The IRSB* into which we're generating code. */
|
|
static IRSB *irsb;
|
|
|
|
/* Is our guest binary 32 or 64bit? Set at each call to
|
|
disInstr_MIPS below. */
|
|
static Bool mode64 = False;
|
|
|
|
/* CPU has FPU and 32 dbl. prec. FP registers. */
|
|
static Bool fp_mode64 = False;
|
|
|
|
/* Define 1.0 in single and double precision. */
|
|
#define ONE_SINGLE 0x3F800000
|
|
#define ONE_DOUBLE 0x3FF0000000000000ULL
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- Debugging output ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
#define DIP(format, args...) \
|
|
if (vex_traceflags & VEX_TRACE_FE) \
|
|
vex_printf(format, ## args)
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- Helper bits and pieces for deconstructing the ---*/
|
|
/*--- mips insn stream. ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
/* ---------------- Integer registers ---------------- */
|
|
|
|
static UInt integerGuestRegOffset(UInt iregNo)
|
|
{
|
|
/* Do we care about endianness here? We do if sub-parts of integer
|
|
registers are accessed, but I don't think that ever happens on
|
|
MIPS. */
|
|
UInt ret;
|
|
if (!mode64)
|
|
switch (iregNo) {
|
|
case 0:
|
|
ret = offsetof(VexGuestMIPS32State, guest_r0); break;
|
|
case 1:
|
|
ret = offsetof(VexGuestMIPS32State, guest_r1); break;
|
|
case 2:
|
|
ret = offsetof(VexGuestMIPS32State, guest_r2); break;
|
|
case 3:
|
|
ret = offsetof(VexGuestMIPS32State, guest_r3); break;
|
|
case 4:
|
|
ret = offsetof(VexGuestMIPS32State, guest_r4); break;
|
|
case 5:
|
|
ret = offsetof(VexGuestMIPS32State, guest_r5); break;
|
|
case 6:
|
|
ret = offsetof(VexGuestMIPS32State, guest_r6); break;
|
|
case 7:
|
|
ret = offsetof(VexGuestMIPS32State, guest_r7); break;
|
|
case 8:
|
|
ret = offsetof(VexGuestMIPS32State, guest_r8); break;
|
|
case 9:
|
|
ret = offsetof(VexGuestMIPS32State, guest_r9); break;
|
|
case 10:
|
|
ret = offsetof(VexGuestMIPS32State, guest_r10); break;
|
|
case 11:
|
|
ret = offsetof(VexGuestMIPS32State, guest_r11); break;
|
|
case 12:
|
|
ret = offsetof(VexGuestMIPS32State, guest_r12); break;
|
|
case 13:
|
|
ret = offsetof(VexGuestMIPS32State, guest_r13); break;
|
|
case 14:
|
|
ret = offsetof(VexGuestMIPS32State, guest_r14); break;
|
|
case 15:
|
|
ret = offsetof(VexGuestMIPS32State, guest_r15); break;
|
|
case 16:
|
|
ret = offsetof(VexGuestMIPS32State, guest_r16); break;
|
|
case 17:
|
|
ret = offsetof(VexGuestMIPS32State, guest_r17); break;
|
|
case 18:
|
|
ret = offsetof(VexGuestMIPS32State, guest_r18); break;
|
|
case 19:
|
|
ret = offsetof(VexGuestMIPS32State, guest_r19); break;
|
|
case 20:
|
|
ret = offsetof(VexGuestMIPS32State, guest_r20); break;
|
|
case 21:
|
|
ret = offsetof(VexGuestMIPS32State, guest_r21); break;
|
|
case 22:
|
|
ret = offsetof(VexGuestMIPS32State, guest_r22); break;
|
|
case 23:
|
|
ret = offsetof(VexGuestMIPS32State, guest_r23); break;
|
|
case 24:
|
|
ret = offsetof(VexGuestMIPS32State, guest_r24); break;
|
|
case 25:
|
|
ret = offsetof(VexGuestMIPS32State, guest_r25); break;
|
|
case 26:
|
|
ret = offsetof(VexGuestMIPS32State, guest_r26); break;
|
|
case 27:
|
|
ret = offsetof(VexGuestMIPS32State, guest_r27); break;
|
|
case 28:
|
|
ret = offsetof(VexGuestMIPS32State, guest_r28); break;
|
|
case 29:
|
|
ret = offsetof(VexGuestMIPS32State, guest_r29); break;
|
|
case 30:
|
|
ret = offsetof(VexGuestMIPS32State, guest_r30); break;
|
|
case 31:
|
|
ret = offsetof(VexGuestMIPS32State, guest_r31); break;
|
|
default:
|
|
vassert(0);
|
|
break;
|
|
}
|
|
else
|
|
switch (iregNo) {
|
|
case 0:
|
|
ret = offsetof(VexGuestMIPS64State, guest_r0); break;
|
|
case 1:
|
|
ret = offsetof(VexGuestMIPS64State, guest_r1); break;
|
|
case 2:
|
|
ret = offsetof(VexGuestMIPS64State, guest_r2); break;
|
|
case 3:
|
|
ret = offsetof(VexGuestMIPS64State, guest_r3); break;
|
|
case 4:
|
|
ret = offsetof(VexGuestMIPS64State, guest_r4); break;
|
|
case 5:
|
|
ret = offsetof(VexGuestMIPS64State, guest_r5); break;
|
|
case 6:
|
|
ret = offsetof(VexGuestMIPS64State, guest_r6); break;
|
|
case 7:
|
|
ret = offsetof(VexGuestMIPS64State, guest_r7); break;
|
|
case 8:
|
|
ret = offsetof(VexGuestMIPS64State, guest_r8); break;
|
|
case 9:
|
|
ret = offsetof(VexGuestMIPS64State, guest_r9); break;
|
|
case 10:
|
|
ret = offsetof(VexGuestMIPS64State, guest_r10); break;
|
|
case 11:
|
|
ret = offsetof(VexGuestMIPS64State, guest_r11); break;
|
|
case 12:
|
|
ret = offsetof(VexGuestMIPS64State, guest_r12); break;
|
|
case 13:
|
|
ret = offsetof(VexGuestMIPS64State, guest_r13); break;
|
|
case 14:
|
|
ret = offsetof(VexGuestMIPS64State, guest_r14); break;
|
|
case 15:
|
|
ret = offsetof(VexGuestMIPS64State, guest_r15); break;
|
|
case 16:
|
|
ret = offsetof(VexGuestMIPS64State, guest_r16); break;
|
|
case 17:
|
|
ret = offsetof(VexGuestMIPS64State, guest_r17); break;
|
|
case 18:
|
|
ret = offsetof(VexGuestMIPS64State, guest_r18); break;
|
|
case 19:
|
|
ret = offsetof(VexGuestMIPS64State, guest_r19); break;
|
|
case 20:
|
|
ret = offsetof(VexGuestMIPS64State, guest_r20); break;
|
|
case 21:
|
|
ret = offsetof(VexGuestMIPS64State, guest_r21); break;
|
|
case 22:
|
|
ret = offsetof(VexGuestMIPS64State, guest_r22); break;
|
|
case 23:
|
|
ret = offsetof(VexGuestMIPS64State, guest_r23); break;
|
|
case 24:
|
|
ret = offsetof(VexGuestMIPS64State, guest_r24); break;
|
|
case 25:
|
|
ret = offsetof(VexGuestMIPS64State, guest_r25); break;
|
|
case 26:
|
|
ret = offsetof(VexGuestMIPS64State, guest_r26); break;
|
|
case 27:
|
|
ret = offsetof(VexGuestMIPS64State, guest_r27); break;
|
|
case 28:
|
|
ret = offsetof(VexGuestMIPS64State, guest_r28); break;
|
|
case 29:
|
|
ret = offsetof(VexGuestMIPS64State, guest_r29); break;
|
|
case 30:
|
|
ret = offsetof(VexGuestMIPS64State, guest_r30); break;
|
|
case 31:
|
|
ret = offsetof(VexGuestMIPS64State, guest_r31); break;
|
|
default:
|
|
vassert(0);
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
#if defined(VGP_mips32_linux)
|
|
#define OFFB_PC offsetof(VexGuestMIPS32State, guest_PC)
|
|
#else
|
|
#define OFFB_PC offsetof(VexGuestMIPS64State, guest_PC)
|
|
#endif
|
|
|
|
/* ---------------- Floating point registers ---------------- */
|
|
|
|
static UInt floatGuestRegOffset(UInt fregNo)
|
|
{
|
|
vassert(fregNo < 32);
|
|
UInt ret;
|
|
if (!mode64)
|
|
switch (fregNo) {
|
|
case 0:
|
|
ret = offsetof(VexGuestMIPS32State, guest_f0); break;
|
|
case 1:
|
|
ret = offsetof(VexGuestMIPS32State, guest_f1); break;
|
|
case 2:
|
|
ret = offsetof(VexGuestMIPS32State, guest_f2); break;
|
|
case 3:
|
|
ret = offsetof(VexGuestMIPS32State, guest_f3); break;
|
|
case 4:
|
|
ret = offsetof(VexGuestMIPS32State, guest_f4); break;
|
|
case 5:
|
|
ret = offsetof(VexGuestMIPS32State, guest_f5); break;
|
|
case 6:
|
|
ret = offsetof(VexGuestMIPS32State, guest_f6); break;
|
|
case 7:
|
|
ret = offsetof(VexGuestMIPS32State, guest_f7); break;
|
|
case 8:
|
|
ret = offsetof(VexGuestMIPS32State, guest_f8); break;
|
|
case 9:
|
|
ret = offsetof(VexGuestMIPS32State, guest_f9); break;
|
|
case 10:
|
|
ret = offsetof(VexGuestMIPS32State, guest_f10); break;
|
|
case 11:
|
|
ret = offsetof(VexGuestMIPS32State, guest_f11); break;
|
|
case 12:
|
|
ret = offsetof(VexGuestMIPS32State, guest_f12); break;
|
|
case 13:
|
|
ret = offsetof(VexGuestMIPS32State, guest_f13); break;
|
|
case 14:
|
|
ret = offsetof(VexGuestMIPS32State, guest_f14); break;
|
|
case 15:
|
|
ret = offsetof(VexGuestMIPS32State, guest_f15); break;
|
|
case 16:
|
|
ret = offsetof(VexGuestMIPS32State, guest_f16); break;
|
|
case 17:
|
|
ret = offsetof(VexGuestMIPS32State, guest_f17); break;
|
|
case 18:
|
|
ret = offsetof(VexGuestMIPS32State, guest_f18); break;
|
|
case 19:
|
|
ret = offsetof(VexGuestMIPS32State, guest_f19); break;
|
|
case 20:
|
|
ret = offsetof(VexGuestMIPS32State, guest_f20); break;
|
|
case 21:
|
|
ret = offsetof(VexGuestMIPS32State, guest_f21); break;
|
|
case 22:
|
|
ret = offsetof(VexGuestMIPS32State, guest_f22); break;
|
|
case 23:
|
|
ret = offsetof(VexGuestMIPS32State, guest_f23); break;
|
|
case 24:
|
|
ret = offsetof(VexGuestMIPS32State, guest_f24); break;
|
|
case 25:
|
|
ret = offsetof(VexGuestMIPS32State, guest_f25); break;
|
|
case 26:
|
|
ret = offsetof(VexGuestMIPS32State, guest_f26); break;
|
|
case 27:
|
|
ret = offsetof(VexGuestMIPS32State, guest_f27); break;
|
|
case 28:
|
|
ret = offsetof(VexGuestMIPS32State, guest_f28); break;
|
|
case 29:
|
|
ret = offsetof(VexGuestMIPS32State, guest_f29); break;
|
|
case 30:
|
|
ret = offsetof(VexGuestMIPS32State, guest_f30); break;
|
|
case 31:
|
|
ret = offsetof(VexGuestMIPS32State, guest_f31); break;
|
|
default:
|
|
vassert(0);
|
|
break;
|
|
}
|
|
else
|
|
switch (fregNo) {
|
|
case 0:
|
|
ret = offsetof(VexGuestMIPS64State, guest_f0); break;
|
|
case 1:
|
|
ret = offsetof(VexGuestMIPS64State, guest_f1); break;
|
|
case 2:
|
|
ret = offsetof(VexGuestMIPS64State, guest_f2); break;
|
|
case 3:
|
|
ret = offsetof(VexGuestMIPS64State, guest_f3); break;
|
|
case 4:
|
|
ret = offsetof(VexGuestMIPS64State, guest_f4); break;
|
|
case 5:
|
|
ret = offsetof(VexGuestMIPS64State, guest_f5); break;
|
|
case 6:
|
|
ret = offsetof(VexGuestMIPS64State, guest_f6); break;
|
|
case 7:
|
|
ret = offsetof(VexGuestMIPS64State, guest_f7); break;
|
|
case 8:
|
|
ret = offsetof(VexGuestMIPS64State, guest_f8); break;
|
|
case 9:
|
|
ret = offsetof(VexGuestMIPS64State, guest_f9); break;
|
|
case 10:
|
|
ret = offsetof(VexGuestMIPS64State, guest_f10); break;
|
|
case 11:
|
|
ret = offsetof(VexGuestMIPS64State, guest_f11); break;
|
|
case 12:
|
|
ret = offsetof(VexGuestMIPS64State, guest_f12); break;
|
|
case 13:
|
|
ret = offsetof(VexGuestMIPS64State, guest_f13); break;
|
|
case 14:
|
|
ret = offsetof(VexGuestMIPS64State, guest_f14); break;
|
|
case 15:
|
|
ret = offsetof(VexGuestMIPS64State, guest_f15); break;
|
|
case 16:
|
|
ret = offsetof(VexGuestMIPS64State, guest_f16); break;
|
|
case 17:
|
|
ret = offsetof(VexGuestMIPS64State, guest_f17); break;
|
|
case 18:
|
|
ret = offsetof(VexGuestMIPS64State, guest_f18); break;
|
|
case 19:
|
|
ret = offsetof(VexGuestMIPS64State, guest_f19); break;
|
|
case 20:
|
|
ret = offsetof(VexGuestMIPS64State, guest_f20); break;
|
|
case 21:
|
|
ret = offsetof(VexGuestMIPS64State, guest_f21); break;
|
|
case 22:
|
|
ret = offsetof(VexGuestMIPS64State, guest_f22); break;
|
|
case 23:
|
|
ret = offsetof(VexGuestMIPS64State, guest_f23); break;
|
|
case 24:
|
|
ret = offsetof(VexGuestMIPS64State, guest_f24); break;
|
|
case 25:
|
|
ret = offsetof(VexGuestMIPS64State, guest_f25); break;
|
|
case 26:
|
|
ret = offsetof(VexGuestMIPS64State, guest_f26); break;
|
|
case 27:
|
|
ret = offsetof(VexGuestMIPS64State, guest_f27); break;
|
|
case 28:
|
|
ret = offsetof(VexGuestMIPS64State, guest_f28); break;
|
|
case 29:
|
|
ret = offsetof(VexGuestMIPS64State, guest_f29); break;
|
|
case 30:
|
|
ret = offsetof(VexGuestMIPS64State, guest_f30); break;
|
|
case 31:
|
|
ret = offsetof(VexGuestMIPS64State, guest_f31); break;
|
|
default:
|
|
vassert(0);
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/* ---------------- 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(const UChar * p)
|
|
{
|
|
UInt w = 0;
|
|
#if defined (_MIPSEL)
|
|
w = (w << 8) | p[3];
|
|
w = (w << 8) | p[2];
|
|
w = (w << 8) | p[1];
|
|
w = (w << 8) | p[0];
|
|
#elif defined (_MIPSEB)
|
|
w = (w << 8) | p[0];
|
|
w = (w << 8) | p[1];
|
|
w = (w << 8) | p[2];
|
|
w = (w << 8) | p[3];
|
|
#endif
|
|
return w;
|
|
}
|
|
|
|
#define BITS2(_b1,_b0) \
|
|
(((_b1) << 1) | (_b0))
|
|
|
|
#define BITS3(_b2,_b1,_b0) \
|
|
(((_b2) << 2) | ((_b1) << 1) | (_b0))
|
|
|
|
#define BITS4(_b3,_b2,_b1,_b0) \
|
|
(((_b3) << 3) | ((_b2) << 2) | ((_b1) << 1) | (_b0))
|
|
|
|
#define BITS5(_b4,_b3,_b2,_b1,_b0) \
|
|
(((_b4) << 4) | BITS4((_b3),(_b2),(_b1),(_b0)))
|
|
|
|
#define BITS6(_b5,_b4,_b3,_b2,_b1,_b0) \
|
|
((BITS2((_b5),(_b4)) << 4) \
|
|
| BITS4((_b3),(_b2),(_b1),(_b0)))
|
|
|
|
#define BITS8(_b7,_b6,_b5,_b4,_b3,_b2,_b1,_b0) \
|
|
((BITS4((_b7),(_b6),(_b5),(_b4)) << 4) \
|
|
| BITS4((_b3),(_b2),(_b1),(_b0)))
|
|
|
|
#define LOAD_STORE_PATTERN \
|
|
t1 = newTemp(mode64 ? Ity_I64 : Ity_I32); \
|
|
if(!mode64) \
|
|
assign(t1, binop(Iop_Add32, getIReg(rs), \
|
|
mkU32(extend_s_16to32(imm)))); \
|
|
else \
|
|
assign(t1, binop(Iop_Add64, getIReg(rs), \
|
|
mkU64(extend_s_16to64(imm)))); \
|
|
|
|
#define LOADX_STORE_PATTERN \
|
|
t1 = newTemp(mode64 ? Ity_I64 : Ity_I32); \
|
|
if(!mode64) \
|
|
assign(t1, binop(Iop_Add32, getIReg(regRs), getIReg(regRt))); \
|
|
else \
|
|
assign(t1, binop(Iop_Add64, getIReg(regRs), getIReg(regRt)));
|
|
|
|
#define LWX_SWX_PATTERN64 \
|
|
t2 = newTemp(Ity_I64); \
|
|
assign(t2, binop(Iop_And64, mkexpr(t1), mkU64(0xFFFFFFFFFFFFFFFCULL))); \
|
|
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))); \
|
|
t4 = newTemp(Ity_I64); \
|
|
assign(t4, binop(Iop_And64, mkexpr(t1), mkU64(0x7)));
|
|
|
|
#define LWX_SWX_PATTERN \
|
|
t2 = newTemp(Ity_I32); \
|
|
assign(t2, binop(Iop_And32, mkexpr(t1), mkU32(0xFFFFFFFC))); \
|
|
t4 = newTemp(Ity_I32); \
|
|
assign(t4, binop(Iop_And32, mkexpr(t1), mkU32(0x00000003)))
|
|
|
|
#define SXXV_PATTERN(op) \
|
|
putIReg(rd, binop(op, \
|
|
getIReg(rt), \
|
|
unop(Iop_32to8, \
|
|
binop(Iop_And32, \
|
|
getIReg(rs), \
|
|
mkU32(0x0000001F) \
|
|
) \
|
|
) \
|
|
) \
|
|
)
|
|
|
|
#define SXXV_PATTERN64(op) \
|
|
putIReg(rd, mkWidenFrom32(ty, binop(op, \
|
|
mkNarrowTo32(ty, getIReg(rt)), \
|
|
unop(Iop_32to8, \
|
|
binop(Iop_And32, \
|
|
mkNarrowTo32(ty, getIReg(rs)), \
|
|
mkU32(0x0000001F) \
|
|
) \
|
|
) \
|
|
), True \
|
|
))
|
|
|
|
#define SXX_PATTERN(op) \
|
|
putIReg(rd, binop(op, getIReg(rt), mkU8(sa)));
|
|
|
|
#define ALU_PATTERN(op) \
|
|
putIReg(rd, binop(op, getIReg(rs), getIReg(rt)));
|
|
|
|
#define ALUI_PATTERN(op) \
|
|
putIReg(rt, binop(op, getIReg(rs), mkU32(imm)));
|
|
|
|
#define ALUI_PATTERN64(op) \
|
|
putIReg(rt, binop(op, getIReg(rs), mkU64(imm)));
|
|
|
|
#define ALU_PATTERN64(op) \
|
|
putIReg(rd, mkWidenFrom32(ty, binop(op, \
|
|
mkNarrowTo32(ty, getIReg(rs)), \
|
|
mkNarrowTo32(ty, getIReg(rt))), True));
|
|
|
|
#define FP_CONDITIONAL_CODE \
|
|
t3 = newTemp(Ity_I32); \
|
|
assign(t3, binop(Iop_And32, \
|
|
IRExpr_ITE( binop(Iop_CmpEQ32, mkU32(cc), mkU32(0)), \
|
|
binop(Iop_Shr32, getFCSR(), mkU8(23)), \
|
|
binop(Iop_Shr32, getFCSR(), mkU8(24+cc))), \
|
|
mkU32(0x1)));
|
|
|
|
#define ILLEGAL_INSTRUCTON \
|
|
putPC(mkU32(guest_PC_curr_instr + 4)); \
|
|
dres.jk_StopHere = Ijk_SigILL; \
|
|
dres.whatNext = Dis_StopHere;
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- Field helpers ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
static UInt get_opcode(UInt mipsins)
|
|
{
|
|
return (0xFC000000 & mipsins) >> 26;
|
|
}
|
|
|
|
static UInt get_rs(UInt mipsins)
|
|
{
|
|
return (0x03E00000 & mipsins) >> 21;
|
|
}
|
|
|
|
static UInt get_rt(UInt mipsins)
|
|
{
|
|
return (0x001F0000 & mipsins) >> 16;
|
|
}
|
|
|
|
static UInt get_imm(UInt mipsins)
|
|
{
|
|
return (0x0000FFFF & mipsins);
|
|
}
|
|
|
|
static UInt get_instr_index(UInt mipsins)
|
|
{
|
|
return (0x03FFFFFF & mipsins);
|
|
}
|
|
|
|
static UInt get_rd(UInt mipsins)
|
|
{
|
|
return (0x0000F800 & mipsins) >> 11;
|
|
}
|
|
|
|
static UInt get_sa(UInt mipsins)
|
|
{
|
|
return (0x000007C0 & mipsins) >> 6;
|
|
}
|
|
|
|
static UInt get_function(UInt mipsins)
|
|
{
|
|
return (0x0000003F & mipsins);
|
|
}
|
|
|
|
static UInt get_ft(UInt mipsins)
|
|
{
|
|
return (0x001F0000 & mipsins) >> 16;
|
|
}
|
|
|
|
static UInt get_fs(UInt mipsins)
|
|
{
|
|
return (0x0000F800 & mipsins) >> 11;
|
|
}
|
|
|
|
static UInt get_fd(UInt mipsins)
|
|
{
|
|
return (0x000007C0 & mipsins) >> 6;
|
|
}
|
|
|
|
static UInt get_mov_cc(UInt mipsins)
|
|
{
|
|
return (0x001C0000 & mipsins) >> 18;
|
|
}
|
|
|
|
static UInt get_bc1_cc(UInt mipsins)
|
|
{
|
|
return (0x001C0000 & mipsins) >> 18;
|
|
}
|
|
|
|
static UInt get_fpc_cc(UInt mipsins)
|
|
{
|
|
return (0x00000700 & mipsins) >> 8;
|
|
}
|
|
|
|
static UInt get_tf(UInt mipsins)
|
|
{
|
|
return (0x00010000 & mipsins) >> 16;
|
|
}
|
|
|
|
static UInt get_nd(UInt mipsins)
|
|
{
|
|
return (0x00020000 & mipsins) >> 17;
|
|
}
|
|
|
|
static UInt get_fmt(UInt mipsins)
|
|
{
|
|
return (0x03E00000 & mipsins) >> 21;
|
|
}
|
|
|
|
static UInt get_FC(UInt mipsins)
|
|
{
|
|
return (0x000000F0 & mipsins) >> 4;
|
|
}
|
|
|
|
static UInt get_cond(UInt mipsins)
|
|
{
|
|
return (0x0000000F & mipsins);
|
|
}
|
|
|
|
/* for break & syscall */
|
|
static UInt get_code(UInt mipsins)
|
|
{
|
|
return (0xFFC0 & mipsins) >> 6;
|
|
}
|
|
|
|
static UInt get_lsb(UInt mipsins)
|
|
{
|
|
return (0x7C0 & mipsins) >> 6;
|
|
}
|
|
|
|
static UInt get_msb(UInt mipsins)
|
|
{
|
|
return (0x0000F800 & mipsins) >> 11;
|
|
}
|
|
|
|
static UInt get_rot(UInt mipsins)
|
|
{
|
|
return (0x00200000 & mipsins) >> 21;
|
|
}
|
|
|
|
static UInt get_rotv(UInt mipsins)
|
|
{
|
|
return (0x00000040 & mipsins) >> 6;
|
|
}
|
|
|
|
static UInt get_sel(UInt mipsins)
|
|
{
|
|
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(const UChar * addr)
|
|
{
|
|
UInt fmt;
|
|
UInt cins = getUInt(addr);
|
|
|
|
UInt opcode = get_opcode(cins);
|
|
UInt rt = get_rt(cins);
|
|
UInt function = get_function(cins);
|
|
|
|
/* bgtz, blez, bne, beq, jal */
|
|
if (opcode == 0x07 || opcode == 0x06 || opcode == 0x05 || opcode == 0x04
|
|
|| opcode == 0x03 || opcode == 0x02) {
|
|
return True;
|
|
}
|
|
|
|
/* bgez */
|
|
if (opcode == 0x01 && rt == 0x01) {
|
|
return True;
|
|
}
|
|
|
|
/* bgezal */
|
|
if (opcode == 0x01 && rt == 0x11) {
|
|
return True;
|
|
}
|
|
|
|
/* bltzal */
|
|
if (opcode == 0x01 && rt == 0x10) {
|
|
return True;
|
|
}
|
|
|
|
/* bltz */
|
|
if (opcode == 0x01 && rt == 0x00) {
|
|
return True;
|
|
}
|
|
|
|
/* jalr */
|
|
if (opcode == 0x00 && function == 0x09) {
|
|
return True;
|
|
}
|
|
|
|
/* jr */
|
|
if (opcode == 0x00 && function == 0x08) {
|
|
return True;
|
|
}
|
|
|
|
if (opcode == 0x11) {
|
|
/*bc1f & bc1t */
|
|
fmt = get_fmt(cins);
|
|
if (fmt == 0x08) {
|
|
return True;
|
|
}
|
|
}
|
|
|
|
/* bposge32 */
|
|
if (opcode == 0x01 && rt == 0x1c) {
|
|
return True;
|
|
}
|
|
|
|
/* Cavium Specific instructions. */
|
|
if (opcode == 0x32 || opcode == 0x3A || opcode == 0x36 || opcode == 0x3E) {
|
|
/* BBIT0, BBIT1, BBIT032, BBIT132 */
|
|
return True;
|
|
}
|
|
|
|
return False;
|
|
}
|
|
|
|
static Bool is_Branch_or_Jump_and_Link(const UChar * addr)
|
|
{
|
|
UInt cins = getUInt(addr);
|
|
|
|
UInt opcode = get_opcode(cins);
|
|
UInt rt = get_rt(cins);
|
|
UInt function = get_function(cins);
|
|
|
|
/* jal */
|
|
if (opcode == 0x02) {
|
|
return True;
|
|
}
|
|
|
|
/* bgezal */
|
|
if (opcode == 0x01 && rt == 0x11) {
|
|
return True;
|
|
}
|
|
|
|
/* bltzal */
|
|
if (opcode == 0x01 && rt == 0x10) {
|
|
return True;
|
|
}
|
|
|
|
/* jalr */
|
|
if (opcode == 0x00 && function == 0x09) {
|
|
return True;
|
|
}
|
|
|
|
return False;
|
|
}
|
|
|
|
static Bool branch_or_link_likely(const UChar * addr)
|
|
{
|
|
UInt cins = getUInt(addr);
|
|
UInt opcode = get_opcode(cins);
|
|
UInt rt = get_rt(cins);
|
|
|
|
/* bgtzl, blezl, bnel, beql */
|
|
if (opcode == 0x17 || opcode == 0x16 || opcode == 0x15 || opcode == 0x14)
|
|
return True;
|
|
|
|
/* bgezl */
|
|
if (opcode == 0x01 && rt == 0x03)
|
|
return True;
|
|
|
|
/* bgezall */
|
|
if (opcode == 0x01 && rt == 0x13)
|
|
return True;
|
|
|
|
/* bltzall */
|
|
if (opcode == 0x01 && rt == 0x12)
|
|
return True;
|
|
|
|
/* bltzl */
|
|
if (opcode == 0x01 && rt == 0x02)
|
|
return True;
|
|
|
|
return False;
|
|
}
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- Helper bits and pieces for creating IR fragments. ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
static IRExpr *mkU8(UInt i)
|
|
{
|
|
vassert(i < 256);
|
|
return IRExpr_Const(IRConst_U8((UChar) i));
|
|
}
|
|
|
|
/* 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. */
|
|
static IRExpr *mkU64(ULong i)
|
|
{
|
|
return IRExpr_Const(IRConst_U64(i));
|
|
}
|
|
|
|
static IRExpr *mkexpr(IRTemp tmp)
|
|
{
|
|
return IRExpr_RdTmp(tmp);
|
|
}
|
|
|
|
static IRExpr *unop(IROp op, IRExpr * a)
|
|
{
|
|
return IRExpr_Unop(op, a);
|
|
}
|
|
|
|
static IRExpr *binop(IROp op, IRExpr * a1, IRExpr * a2)
|
|
{
|
|
return IRExpr_Binop(op, a1, a2);
|
|
}
|
|
|
|
static IRExpr *triop(IROp op, IRExpr * a1, IRExpr * a2, IRExpr * a3)
|
|
{
|
|
return IRExpr_Triop(op, a1, a2, a3);
|
|
}
|
|
|
|
static IRExpr *qop ( IROp op, IRExpr * a1, IRExpr * a2, IRExpr * a3,
|
|
IRExpr * a4 )
|
|
{
|
|
return IRExpr_Qop(op, a1, a2, a3, a4);
|
|
}
|
|
|
|
static IRExpr *load(IRType ty, IRExpr * addr)
|
|
{
|
|
IRExpr *load1 = NULL;
|
|
#if defined (_MIPSEL)
|
|
load1 = IRExpr_Load(Iend_LE, ty, addr);
|
|
#elif defined (_MIPSEB)
|
|
load1 = IRExpr_Load(Iend_BE, ty, addr);
|
|
#endif
|
|
return load1;
|
|
}
|
|
|
|
/* Add a statement to the list held by "irsb". */
|
|
static void stmt(IRStmt * st)
|
|
{
|
|
addStmtToIRSB(irsb, st);
|
|
}
|
|
|
|
static void assign(IRTemp dst, IRExpr * e)
|
|
{
|
|
stmt(IRStmt_WrTmp(dst, e));
|
|
}
|
|
|
|
static void store(IRExpr * addr, IRExpr * data)
|
|
{
|
|
#if defined (_MIPSEL)
|
|
stmt(IRStmt_Store(Iend_LE, addr, data));
|
|
#elif defined (_MIPSEB)
|
|
stmt(IRStmt_Store(Iend_BE, addr, data));
|
|
#endif
|
|
}
|
|
|
|
/* Generate a new temporary of the given type. */
|
|
static IRTemp newTemp(IRType ty)
|
|
{
|
|
vassert(isPlausibleIRType(ty));
|
|
return newIRTemp(irsb->tyenv, ty);
|
|
}
|
|
|
|
/* Generate an expression for SRC rotated right by ROT. */
|
|
static IRExpr *genROR32(IRExpr * src, Int rot)
|
|
{
|
|
vassert(rot >= 0 && rot < 32);
|
|
if (rot == 0)
|
|
return src;
|
|
return binop(Iop_Or32, binop(Iop_Shl32, src, mkU8(32 - rot)),
|
|
binop(Iop_Shr32, src, mkU8(rot)));
|
|
}
|
|
|
|
static IRExpr *genRORV32(IRExpr * src, IRExpr * rs)
|
|
{
|
|
IRTemp t0 = newTemp(Ity_I8);
|
|
IRTemp t1 = newTemp(Ity_I8);
|
|
|
|
assign(t0, unop(Iop_32to8, binop(Iop_And32, rs, mkU32(0x0000001F))));
|
|
assign(t1, binop(Iop_Sub8, mkU8(32), mkexpr(t0)));
|
|
return binop(Iop_Or32, binop(Iop_Shl32, src, mkexpr(t1)),
|
|
binop(Iop_Shr32, src, mkexpr(t0)));
|
|
}
|
|
|
|
static UShort extend_s_10to16(UInt x)
|
|
{
|
|
return (UShort) ((((Int) x) << 22) >> 22);
|
|
}
|
|
|
|
static ULong extend_s_10to32(UInt x)
|
|
{
|
|
return (ULong)((((Long) x) << 22) >> 22);
|
|
}
|
|
|
|
static ULong extend_s_10to64(UInt x)
|
|
{
|
|
return (ULong)((((Long) x) << 54) >> 54);
|
|
}
|
|
|
|
static UInt extend_s_16to32(UInt x)
|
|
{
|
|
return (UInt) ((((Int) x) << 16) >> 16);
|
|
}
|
|
|
|
static UInt extend_s_18to32(UInt x)
|
|
{
|
|
return (UInt) ((((Int) x) << 14) >> 14);
|
|
}
|
|
|
|
static ULong extend_s_16to64 ( UInt x )
|
|
{
|
|
return (ULong) ((((Long) x) << 48) >> 48);
|
|
}
|
|
|
|
static ULong extend_s_18to64 ( UInt x )
|
|
{
|
|
return (ULong) ((((Long) x) << 46) >> 46);
|
|
}
|
|
|
|
static ULong extend_s_32to64 ( UInt x )
|
|
{
|
|
return (ULong) ((((Long) x) << 32) >> 32);
|
|
}
|
|
|
|
static void jmp_lit32 ( /*MOD*/ DisResult* dres, IRJumpKind kind, Addr32 d32 )
|
|
{
|
|
vassert(dres->whatNext == Dis_Continue);
|
|
vassert(dres->len == 0);
|
|
vassert(dres->continueAt == 0);
|
|
vassert(dres->jk_StopHere == Ijk_INVALID);
|
|
dres->whatNext = Dis_StopHere;
|
|
dres->jk_StopHere = kind;
|
|
stmt( IRStmt_Put( OFFB_PC, mkU32(d32) ) );
|
|
}
|
|
|
|
static void jmp_lit64 ( /*MOD*/ DisResult* dres, IRJumpKind kind, Addr64 d64 )
|
|
{
|
|
vassert(dres->whatNext == Dis_Continue);
|
|
vassert(dres->len == 0);
|
|
vassert(dres->continueAt == 0);
|
|
vassert(dres->jk_StopHere == Ijk_INVALID);
|
|
dres->whatNext = Dis_StopHere;
|
|
dres->jk_StopHere = kind;
|
|
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)
|
|
{
|
|
return guest_code[delta];
|
|
}
|
|
|
|
static IRExpr *getIReg(UInt iregNo)
|
|
{
|
|
if (0 == iregNo) {
|
|
return mode64 ? mkU64(0x0) : mkU32(0x0);
|
|
} else {
|
|
IRType ty = mode64 ? Ity_I64 : Ity_I32;
|
|
vassert(iregNo < 32);
|
|
return IRExpr_Get(integerGuestRegOffset(iregNo), ty);
|
|
}
|
|
}
|
|
|
|
static IRExpr *getHI(void)
|
|
{
|
|
if (mode64)
|
|
return IRExpr_Get(offsetof(VexGuestMIPS64State, guest_HI), Ity_I64);
|
|
else
|
|
return IRExpr_Get(offsetof(VexGuestMIPS32State, guest_HI), Ity_I32);
|
|
}
|
|
|
|
static IRExpr *getLO(void)
|
|
{
|
|
if (mode64)
|
|
return IRExpr_Get(offsetof(VexGuestMIPS64State, guest_LO), Ity_I64);
|
|
else
|
|
return IRExpr_Get(offsetof(VexGuestMIPS32State, guest_LO), Ity_I32);
|
|
}
|
|
|
|
static IRExpr *getFCSR(void)
|
|
{
|
|
if (mode64)
|
|
return IRExpr_Get(offsetof(VexGuestMIPS64State, guest_FCSR), Ity_I32);
|
|
else
|
|
return IRExpr_Get(offsetof(VexGuestMIPS32State, guest_FCSR), Ity_I32);
|
|
}
|
|
|
|
/* Get byte from register reg, byte pos from 0 to 3 (or 7 for MIPS64) . */
|
|
static IRExpr *getByteFromReg(UInt reg, UInt byte_pos)
|
|
{
|
|
UInt pos = byte_pos * 8;
|
|
if (mode64)
|
|
return unop(Iop_64to8, binop(Iop_And64,
|
|
binop(Iop_Shr64, getIReg(reg), mkU8(pos)),
|
|
mkU64(0xFF)));
|
|
else
|
|
return unop(Iop_32to8, binop(Iop_And32,
|
|
binop(Iop_Shr32, getIReg(reg), mkU8(pos)),
|
|
mkU32(0xFF)));
|
|
}
|
|
|
|
static void putFCSR(IRExpr * e)
|
|
{
|
|
if (mode64)
|
|
stmt(IRStmt_Put(offsetof(VexGuestMIPS64State, guest_FCSR), e));
|
|
else
|
|
stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_FCSR), e));
|
|
}
|
|
|
|
/* fs - fpu source register number.
|
|
inst - fpu instruction that needs to be executed.
|
|
sz32 - size of source register.
|
|
opN - number of operads:
|
|
1 - unary operation.
|
|
2 - binary operation. */
|
|
static void calculateFCSR(UInt fs, UInt ft, UInt inst, Bool sz32, UInt opN)
|
|
{
|
|
IRDirty *d;
|
|
IRTemp fcsr = newTemp(Ity_I32);
|
|
/* IRExpr_BBPTR() => Need to pass pointer to guest state to helper. */
|
|
if (fp_mode64)
|
|
d = unsafeIRDirty_1_N(fcsr, 0,
|
|
"mips_dirtyhelper_calculate_FCSR_fp64",
|
|
&mips_dirtyhelper_calculate_FCSR_fp64,
|
|
mkIRExprVec_4(IRExpr_BBPTR(),
|
|
mkU32(fs),
|
|
mkU32(ft),
|
|
mkU32(inst)));
|
|
else
|
|
d = unsafeIRDirty_1_N(fcsr, 0,
|
|
"mips_dirtyhelper_calculate_FCSR_fp32",
|
|
&mips_dirtyhelper_calculate_FCSR_fp32,
|
|
mkIRExprVec_4(IRExpr_BBPTR(),
|
|
mkU32(fs),
|
|
mkU32(ft),
|
|
mkU32(inst)));
|
|
|
|
if (opN == 1) { /* Unary operation. */
|
|
/* Declare we're reading guest state. */
|
|
if (sz32 || fp_mode64)
|
|
d->nFxState = 2;
|
|
else
|
|
d->nFxState = 3;
|
|
vex_bzero(&d->fxState, sizeof(d->fxState));
|
|
|
|
d->fxState[0].fx = Ifx_Read; /* read */
|
|
if (mode64)
|
|
d->fxState[0].offset = offsetof(VexGuestMIPS64State, guest_FCSR);
|
|
else
|
|
d->fxState[0].offset = offsetof(VexGuestMIPS32State, guest_FCSR);
|
|
d->fxState[0].size = sizeof(UInt);
|
|
d->fxState[1].fx = Ifx_Read; /* read */
|
|
d->fxState[1].offset = floatGuestRegOffset(fs);
|
|
d->fxState[1].size = sizeof(ULong);
|
|
|
|
if (!(sz32 || fp_mode64)) {
|
|
d->fxState[2].fx = Ifx_Read; /* read */
|
|
d->fxState[2].offset = floatGuestRegOffset(fs+1);
|
|
d->fxState[2].size = sizeof(ULong);
|
|
}
|
|
} else if (opN == 2) { /* Binary operation. */
|
|
/* Declare we're reading guest state. */
|
|
if (sz32 || fp_mode64)
|
|
d->nFxState = 3;
|
|
else
|
|
d->nFxState = 5;
|
|
vex_bzero(&d->fxState, sizeof(d->fxState));
|
|
|
|
d->fxState[0].fx = Ifx_Read; /* read */
|
|
if (mode64)
|
|
d->fxState[0].offset = offsetof(VexGuestMIPS64State, guest_FCSR);
|
|
else
|
|
d->fxState[0].offset = offsetof(VexGuestMIPS32State, guest_FCSR);
|
|
d->fxState[0].size = sizeof(UInt);
|
|
d->fxState[1].fx = Ifx_Read; /* read */
|
|
d->fxState[1].offset = floatGuestRegOffset(fs);
|
|
d->fxState[1].size = sizeof(ULong);
|
|
d->fxState[2].fx = Ifx_Read; /* read */
|
|
d->fxState[2].offset = floatGuestRegOffset(ft);
|
|
d->fxState[2].size = sizeof(ULong);
|
|
|
|
if (!(sz32 || fp_mode64)) {
|
|
d->fxState[3].fx = Ifx_Read; /* read */
|
|
d->fxState[3].offset = floatGuestRegOffset(fs+1);
|
|
d->fxState[3].size = sizeof(ULong);
|
|
d->fxState[4].fx = Ifx_Read; /* read */
|
|
d->fxState[4].offset = floatGuestRegOffset(ft+1);
|
|
d->fxState[4].size = sizeof(ULong);
|
|
}
|
|
}
|
|
|
|
stmt(IRStmt_Dirty(d));
|
|
|
|
putFCSR(mkexpr(fcsr));
|
|
}
|
|
|
|
static IRExpr *getULR(void)
|
|
{
|
|
if (mode64)
|
|
return IRExpr_Get(offsetof(VexGuestMIPS64State, guest_ULR), Ity_I64);
|
|
else
|
|
return IRExpr_Get(offsetof(VexGuestMIPS32State, guest_ULR), Ity_I32);
|
|
}
|
|
|
|
static void putIReg(UInt archreg, IRExpr * e)
|
|
{
|
|
IRType ty = mode64 ? Ity_I64 : Ity_I32;
|
|
vassert(archreg < 32);
|
|
vassert(typeOfIRExpr(irsb->tyenv, e) == ty);
|
|
if (archreg != 0)
|
|
stmt(IRStmt_Put(integerGuestRegOffset(archreg), e));
|
|
}
|
|
|
|
static IRExpr *mkNarrowTo32(IRType ty, IRExpr * src)
|
|
{
|
|
vassert(ty == Ity_I32 || ty == Ity_I64);
|
|
return ty == Ity_I64 ? unop(Iop_64to32, src) : src;
|
|
}
|
|
|
|
static void putLO(IRExpr * e)
|
|
{
|
|
if (mode64) {
|
|
stmt(IRStmt_Put(offsetof(VexGuestMIPS64State, guest_LO), e));
|
|
} 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) {
|
|
stmt(IRStmt_Put(offsetof(VexGuestMIPS64State, guest_HI), e));
|
|
} 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);
|
|
return ty == Ity_I64 ? unop(Iop_64to8, src) : unop(Iop_32to8, src);
|
|
}
|
|
|
|
static void putPC(IRExpr * e)
|
|
{
|
|
stmt(IRStmt_Put(OFFB_PC, e));
|
|
}
|
|
|
|
static IRExpr *mkWidenFrom32(IRType ty, IRExpr * src, Bool sined)
|
|
{
|
|
vassert(ty == Ity_I32 || ty == Ity_I64);
|
|
if (ty == Ity_I32)
|
|
return src;
|
|
return (sined) ? unop(Iop_32Sto64, src) : unop(Iop_32Uto64, src);
|
|
}
|
|
|
|
/* Narrow 8/16/32 bit int expr to 8/16/32. Clearly only some
|
|
of these combinations make sense. */
|
|
static IRExpr *narrowTo(IRType dst_ty, IRExpr * e)
|
|
{
|
|
IRType src_ty = typeOfIRExpr(irsb->tyenv, e);
|
|
if (src_ty == dst_ty)
|
|
return e;
|
|
if (src_ty == Ity_I32 && dst_ty == Ity_I16)
|
|
return unop(Iop_32to16, e);
|
|
if (src_ty == Ity_I32 && dst_ty == Ity_I8)
|
|
return unop(Iop_32to8, e);
|
|
if (src_ty == Ity_I64 && dst_ty == Ity_I8) {
|
|
vassert(mode64);
|
|
return unop(Iop_64to8, e);
|
|
}
|
|
if (src_ty == Ity_I64 && dst_ty == Ity_I16) {
|
|
vassert(mode64);
|
|
return unop(Iop_64to16, e);
|
|
}
|
|
vpanic("narrowTo(mips)");
|
|
return 0;
|
|
}
|
|
|
|
static IRExpr *getLoFromF64(IRType ty, IRExpr * src)
|
|
{
|
|
vassert(ty == Ity_F32 || ty == Ity_F64);
|
|
if (ty == Ity_F64) {
|
|
IRTemp t0, t1;
|
|
t0 = newTemp(Ity_I64);
|
|
t1 = newTemp(Ity_I32);
|
|
assign(t0, unop(Iop_ReinterpF64asI64, src));
|
|
assign(t1, unop(Iop_64to32, mkexpr(t0)));
|
|
return unop(Iop_ReinterpI32asF32, mkexpr(t1));
|
|
} else
|
|
return src;
|
|
}
|
|
|
|
static IRExpr *mkWidenFromF32(IRType ty, IRExpr * src)
|
|
{
|
|
vassert(ty == Ity_F32 || ty == Ity_F64);
|
|
if (ty == Ity_F64) {
|
|
IRTemp t0 = newTemp(Ity_I32);
|
|
IRTemp t1 = newTemp(Ity_I64);
|
|
assign(t0, unop(Iop_ReinterpF32asI32, src));
|
|
assign(t1, binop(Iop_32HLto64, mkU32(0x0), mkexpr(t0)));
|
|
return unop(Iop_ReinterpI64asF64, mkexpr(t1));
|
|
} else
|
|
return src;
|
|
}
|
|
|
|
static IRExpr *dis_branch_likely(IRExpr * guard, UInt imm)
|
|
{
|
|
ULong branch_offset;
|
|
IRTemp t0;
|
|
|
|
/* PC = PC + (SignExtend(signed_immed_24) << 2)
|
|
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
|
|
a PC-relative effective target address. */
|
|
if (mode64)
|
|
branch_offset = extend_s_18to64(imm << 2);
|
|
else
|
|
branch_offset = extend_s_18to32(imm << 2);
|
|
|
|
t0 = newTemp(Ity_I1);
|
|
assign(t0, guard);
|
|
|
|
if (mode64)
|
|
stmt(IRStmt_Exit(mkexpr(t0), Ijk_Boring,
|
|
IRConst_U64(guest_PC_curr_instr + 8), OFFB_PC));
|
|
else
|
|
stmt(IRStmt_Exit(mkexpr(t0), Ijk_Boring,
|
|
IRConst_U32(guest_PC_curr_instr + 8), OFFB_PC));
|
|
|
|
irsb->jumpkind = Ijk_Boring;
|
|
|
|
if (mode64)
|
|
return mkU64(guest_PC_curr_instr + 4 + branch_offset);
|
|
else
|
|
return mkU32(guest_PC_curr_instr + 4 + branch_offset);
|
|
}
|
|
|
|
static void dis_branch(Bool link, IRExpr * guard, UInt imm, IRStmt ** set)
|
|
{
|
|
ULong branch_offset;
|
|
IRTemp t0;
|
|
|
|
if (link) { /* LR (GPR31) = addr of the 2nd instr after branch instr */
|
|
if (mode64)
|
|
putIReg(31, mkU64(guest_PC_curr_instr + 8));
|
|
else
|
|
putIReg(31, mkU32(guest_PC_curr_instr + 8));
|
|
}
|
|
|
|
/* PC = PC + (SignExtend(signed_immed_24) << 2)
|
|
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
|
|
a PC-relative effective target address. */
|
|
|
|
if (mode64)
|
|
branch_offset = extend_s_18to64(imm << 2);
|
|
else
|
|
branch_offset = extend_s_18to32(imm << 2);
|
|
|
|
t0 = newTemp(Ity_I1);
|
|
assign(t0, guard);
|
|
if (mode64)
|
|
*set = IRStmt_Exit(mkexpr(t0), link ? Ijk_Call : Ijk_Boring,
|
|
IRConst_U64(guest_PC_curr_instr + 4 + branch_offset),
|
|
OFFB_PC);
|
|
else
|
|
*set = IRStmt_Exit(mkexpr(t0), link ? Ijk_Call : Ijk_Boring,
|
|
IRConst_U32(guest_PC_curr_instr + 4 +
|
|
(UInt) branch_offset), OFFB_PC);
|
|
}
|
|
|
|
static IRExpr *getFReg(UInt fregNo)
|
|
{
|
|
vassert(fregNo < 32);
|
|
IRType ty = fp_mode64 ? Ity_F64 : Ity_F32;
|
|
return IRExpr_Get(floatGuestRegOffset(fregNo), ty);
|
|
}
|
|
|
|
static IRExpr *getDReg(UInt dregNo)
|
|
{
|
|
vassert(dregNo < 32);
|
|
if (fp_mode64) {
|
|
return IRExpr_Get(floatGuestRegOffset(dregNo), Ity_F64);
|
|
} else {
|
|
/* Read a floating point register pair and combine their contents into a
|
|
64-bit value */
|
|
IRTemp t0 = newTemp(Ity_F32);
|
|
IRTemp t1 = newTemp(Ity_F32);
|
|
IRTemp t2 = newTemp(Ity_F64);
|
|
IRTemp t3 = newTemp(Ity_I32);
|
|
IRTemp t4 = newTemp(Ity_I32);
|
|
IRTemp t5 = newTemp(Ity_I64);
|
|
|
|
assign(t0, getFReg(dregNo));
|
|
assign(t1, getFReg(dregNo + 1));
|
|
|
|
assign(t3, unop(Iop_ReinterpF32asI32, mkexpr(t0)));
|
|
assign(t4, unop(Iop_ReinterpF32asI32, mkexpr(t1)));
|
|
assign(t5, binop(Iop_32HLto64, mkexpr(t4), mkexpr(t3)));
|
|
assign(t2, unop(Iop_ReinterpI64asF64, mkexpr(t5)));
|
|
|
|
return mkexpr(t2);
|
|
}
|
|
}
|
|
|
|
static void putFReg(UInt dregNo, IRExpr * e)
|
|
{
|
|
vassert(dregNo < 32);
|
|
IRType ty = fp_mode64 ? Ity_F64 : Ity_F32;
|
|
vassert(typeOfIRExpr(irsb->tyenv, e) == ty);
|
|
stmt(IRStmt_Put(floatGuestRegOffset(dregNo), e));
|
|
}
|
|
|
|
static void putDReg(UInt dregNo, IRExpr * e)
|
|
{
|
|
if (fp_mode64) {
|
|
vassert(dregNo < 32);
|
|
IRType ty = Ity_F64;
|
|
vassert(typeOfIRExpr(irsb->tyenv, e) == ty);
|
|
stmt(IRStmt_Put(floatGuestRegOffset(dregNo), e));
|
|
} else {
|
|
vassert(dregNo < 32);
|
|
vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_F64);
|
|
IRTemp t1 = newTemp(Ity_F64);
|
|
IRTemp t4 = newTemp(Ity_I32);
|
|
IRTemp t5 = newTemp(Ity_I32);
|
|
IRTemp t6 = newTemp(Ity_I64);
|
|
assign(t1, e);
|
|
assign(t6, unop(Iop_ReinterpF64asI64, mkexpr(t1)));
|
|
assign(t4, unop(Iop_64HIto32, mkexpr(t6))); /* hi */
|
|
assign(t5, unop(Iop_64to32, mkexpr(t6))); /* lo */
|
|
putFReg(dregNo, unop(Iop_ReinterpI32asF32, mkexpr(t5)));
|
|
putFReg(dregNo + 1, unop(Iop_ReinterpI32asF32, mkexpr(t4)));
|
|
}
|
|
}
|
|
|
|
static void setFPUCondCode(IRExpr * e, UInt cc)
|
|
{
|
|
if (cc == 0) {
|
|
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,
|
|
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
|
|
to zero | 01 | 11
|
|
to +infinity | 10 | 10
|
|
to -infinity | 11 | 01
|
|
*/
|
|
IRTemp rm_MIPS = newTemp(Ity_I32);
|
|
/* Last two bits in FCSR are rounding mode. */
|
|
|
|
if (mode64)
|
|
assign(rm_MIPS, binop(Iop_And32, IRExpr_Get(offsetof(VexGuestMIPS64State,
|
|
guest_FCSR), Ity_I32), mkU32(3)));
|
|
else
|
|
assign(rm_MIPS, binop(Iop_And32, IRExpr_Get(offsetof(VexGuestMIPS32State,
|
|
guest_FCSR), Ity_I32), mkU32(3)));
|
|
|
|
/* rm_IR = XOR( rm_MIPS32, (rm_MIPS32 << 1) & 2) */
|
|
|
|
return binop(Iop_Xor32, mkexpr(rm_MIPS), binop(Iop_And32,
|
|
binop(Iop_Shl32, mkexpr(rm_MIPS), mkU8(1)), mkU32(2)));
|
|
}
|
|
|
|
/* sz, ULong -> IRExpr */
|
|
static IRExpr *mkSzImm ( IRType ty, ULong imm64 )
|
|
{
|
|
vassert(ty == Ity_I32 || ty == Ity_I64);
|
|
return ty == Ity_I64 ? mkU64(imm64) : mkU32((UInt) imm64);
|
|
}
|
|
|
|
static IRConst *mkSzConst ( IRType ty, ULong imm64 )
|
|
{
|
|
vassert(ty == Ity_I32 || ty == Ity_I64);
|
|
return (ty == Ity_I64 ? IRConst_U64(imm64) : IRConst_U32((UInt) imm64));
|
|
}
|
|
|
|
/* Make sure we get valid 32 and 64bit addresses */
|
|
static Addr64 mkSzAddr ( IRType ty, Addr64 addr )
|
|
{
|
|
vassert(ty == Ity_I32 || ty == Ity_I64);
|
|
return (ty == Ity_I64 ? (Addr64) addr :
|
|
(Addr64) extend_s_32to64(toUInt(addr)));
|
|
}
|
|
|
|
/* Shift and Rotate instructions for MIPS64 */
|
|
static Bool dis_instr_shrt ( UInt theInstr )
|
|
{
|
|
UInt opc2 = get_function(theInstr);
|
|
UChar regRs = get_rs(theInstr);
|
|
UChar regRt = get_rt(theInstr);
|
|
UChar regRd = get_rd(theInstr);
|
|
UChar uImmsa = get_sa(theInstr);
|
|
Long sImmsa = extend_s_16to64(uImmsa);
|
|
IRType ty = mode64 ? Ity_I64 : Ity_I32;
|
|
IRTemp tmp = newTemp(ty);
|
|
IRTemp tmpOr = newTemp(ty);
|
|
IRTemp tmpRt = newTemp(ty);
|
|
IRTemp tmpRs = newTemp(ty);
|
|
IRTemp tmpRd = newTemp(ty);
|
|
|
|
assign(tmpRs, getIReg(regRs));
|
|
assign(tmpRt, getIReg(regRt));
|
|
|
|
switch (opc2) {
|
|
case 0x3A:
|
|
if ((regRs & 0x01) == 0) {
|
|
/* Doubleword Shift Right Logical - DSRL; MIPS64 */
|
|
DIP("dsrl r%u, r%u, %lld", regRd, regRt, sImmsa);
|
|
assign(tmpRd, binop(Iop_Shr64, mkexpr(tmpRt), mkU8(uImmsa)));
|
|
putIReg(regRd, mkexpr(tmpRd));
|
|
} else if ((regRs & 0x01) == 1) {
|
|
/* Doubleword Rotate Right - DROTR; MIPS64r2 */
|
|
vassert(mode64);
|
|
DIP("drotr r%u, r%u, %lld", regRd, regRt, sImmsa);
|
|
IRTemp tmpL = newTemp(ty);
|
|
IRTemp tmpR = newTemp(ty);
|
|
assign(tmpR, binop(Iop_Shr64, mkexpr(tmpRt), mkU8(uImmsa)));
|
|
assign(tmp, binop(Iop_Shl64, mkexpr(tmpRt), mkU8(63 - uImmsa)));
|
|
assign(tmpL, binop(Iop_Shl64, mkexpr(tmp), mkU8(1)));
|
|
assign(tmpRd, binop(Iop_Or64, mkexpr(tmpL), mkexpr(tmpR)));
|
|
putIReg(regRd, mkexpr(tmpRd));
|
|
} else
|
|
return False;
|
|
break;
|
|
|
|
case 0x3E:
|
|
if ((regRs & 0x01) == 0) {
|
|
/* Doubleword Shift Right Logical Plus 32 - DSRL32; MIPS64 */
|
|
DIP("dsrl32 r%u, r%u, %lld", regRd, regRt, sImmsa + 32);
|
|
assign(tmpRd, binop(Iop_Shr64, mkexpr(tmpRt), mkU8(uImmsa + 32)));
|
|
putIReg(regRd, mkexpr(tmpRd));
|
|
} else if ((regRs & 0x01) == 1) {
|
|
/* Doubleword Rotate Right Plus 32 - DROTR32; MIPS64r2 */
|
|
DIP("drotr32 r%u, r%u, %lld", regRd, regRt, sImmsa);
|
|
vassert(mode64);
|
|
IRTemp tmpL = newTemp(ty);
|
|
IRTemp tmpR = newTemp(ty);
|
|
/* (tmpRt >> sa) | (tmpRt << (64 - sa)) */
|
|
assign(tmpR, binop(Iop_Shr64, mkexpr(tmpRt), mkU8(uImmsa + 32)));
|
|
assign(tmp, binop(Iop_Shl64, mkexpr(tmpRt),
|
|
mkU8(63 - (uImmsa + 32))));
|
|
assign(tmpL, binop(Iop_Shl64, mkexpr(tmp), mkU8(1)));
|
|
assign(tmpRd, binop(Iop_Or64, mkexpr(tmpL), mkexpr(tmpR)));
|
|
putIReg(regRd, mkexpr(tmpRd));
|
|
} else
|
|
return False;
|
|
break;
|
|
|
|
case 0x16:
|
|
if ((uImmsa & 0x01) == 0) {
|
|
/* Doubleword Shift Right Logical Variable - DSRLV; MIPS64 */
|
|
DIP("dsrlv r%u, r%u, r%u", regRd, regRt, regRs);
|
|
IRTemp tmpRs8 = newTemp(Ity_I8);
|
|
/* s = tmpRs[5..0] */
|
|
assign(tmp, binop(Iop_And64, mkexpr(tmpRs), mkU64(63)));
|
|
assign(tmpRs8, mkNarrowTo8(ty, mkexpr(tmp)));
|
|
assign(tmpRd, binop(Iop_Shr64, mkexpr(tmpRt), mkexpr(tmpRs8)));
|
|
putIReg(regRd, mkexpr(tmpRd));
|
|
} else if ((uImmsa & 0x01) == 1) {
|
|
/* Doubleword Rotate Right Variable - DROTRV; MIPS64r2 */
|
|
DIP("drotrv r%u, r%u, r%u", regRd, regRt, regRs);
|
|
IRTemp tmpL = newTemp(ty);
|
|
IRTemp tmpR = newTemp(ty);
|
|
IRTemp tmpRs8 = newTemp(Ity_I8);
|
|
IRTemp tmpLs8 = newTemp(Ity_I8);
|
|
IRTemp tmp64 = newTemp(ty);
|
|
/* s = tmpRs[5...0]
|
|
m = 64 - s
|
|
(tmpRt << s) | (tmpRt >> m) */
|
|
|
|
assign(tmp64, binop(Iop_And64, mkexpr(tmpRs), mkSzImm(ty, 63)));
|
|
assign(tmp, binop(Iop_Sub64, mkU64(63), mkexpr(tmp64)));
|
|
|
|
assign(tmpLs8, mkNarrowTo8(ty, mkexpr(tmp)));
|
|
assign(tmpRs8, mkNarrowTo8(ty, mkexpr(tmp64)));
|
|
|
|
assign(tmpR, binop(Iop_Shr64, mkexpr(tmpRt), mkexpr(tmpRs8)));
|
|
assign(tmpL, binop(Iop_Shl64, mkexpr(tmpRt), mkexpr(tmpLs8)));
|
|
assign(tmpRd, binop(Iop_Shl64, mkexpr(tmpL), mkU8(1)));
|
|
assign(tmpOr, binop(Iop_Or64, mkexpr(tmpRd), mkexpr(tmpR)));
|
|
|
|
putIReg(regRd, mkexpr(tmpOr));
|
|
} else
|
|
return False;
|
|
break;
|
|
|
|
case 0x38: /* Doubleword Shift Left Logical - DSLL; MIPS64 */
|
|
DIP("dsll r%u, r%u, %lld", regRd, regRt, sImmsa);
|
|
vassert(mode64);
|
|
assign(tmpRd, binop(Iop_Shl64, mkexpr(tmpRt), mkU8(uImmsa)));
|
|
putIReg(regRd, mkexpr(tmpRd));
|
|
break;
|
|
|
|
case 0x3C: /* Doubleword Shift Left Logical Plus 32 - DSLL32; MIPS64 */
|
|
DIP("dsll32 r%u, r%u, %lld", regRd, regRt, sImmsa);
|
|
assign(tmpRd, binop(Iop_Shl64, mkexpr(tmpRt), mkU8(uImmsa + 32)));
|
|
putIReg(regRd, mkexpr(tmpRd));
|
|
break;
|
|
|
|
case 0x14: { /* Doubleword Shift Left Logical Variable - DSLLV; MIPS64 */
|
|
DIP("dsllv r%u, r%u, r%u", regRd, regRt, regRs);
|
|
IRTemp tmpRs8 = newTemp(Ity_I8);
|
|
|
|
assign(tmp, binop(Iop_And64, mkexpr(tmpRs), mkSzImm(ty, 63)));
|
|
assign(tmpRs8, mkNarrowTo8(ty, mkexpr(tmp)));
|
|
assign(tmpRd, binop(Iop_Shl64, mkexpr(tmpRt), mkexpr(tmpRs8)));
|
|
putIReg(regRd, mkexpr(tmpRd));
|
|
break;
|
|
}
|
|
|
|
case 0x3B: /* Doubleword Shift Right Arithmetic - DSRA; MIPS64 */
|
|
DIP("dsra r%u, r%u, %lld", regRd, regRt, sImmsa);
|
|
assign(tmpRd, binop(Iop_Sar64, mkexpr(tmpRt), mkU8(uImmsa)));
|
|
putIReg(regRd, mkexpr(tmpRd));
|
|
break;
|
|
|
|
case 0x3F: /* Doubleword Shift Right Arithmetic Plus 32 - DSRA32;
|
|
MIPS64 */
|
|
DIP("dsra32 r%u, r%u, %lld", regRd, regRt, sImmsa);
|
|
assign(tmpRd, binop(Iop_Sar64, mkexpr(tmpRt), mkU8(uImmsa + 32)));
|
|
putIReg(regRd, mkexpr(tmpRd));
|
|
break;
|
|
|
|
case 0x17: { /* Doubleword Shift Right Arithmetic Variable - DSRAV;
|
|
MIPS64 */
|
|
DIP("dsrav r%u, r%u, r%u", regRd, regRt, regRs);
|
|
IRTemp tmpRs8 = newTemp(Ity_I8);
|
|
assign(tmp, binop(Iop_And64, mkexpr(tmpRs), mkSzImm(ty, 63)));
|
|
assign(tmpRs8, mkNarrowTo8(ty, mkexpr(tmp)));
|
|
assign(tmpRd, binop(Iop_Sar64, mkexpr(tmpRt), mkexpr(tmpRs8)));
|
|
putIReg(regRd, mkexpr(tmpRd));
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
return False;
|
|
|
|
}
|
|
return True;
|
|
}
|
|
|
|
static IROp mkSzOp ( IRType ty, IROp op8 )
|
|
{
|
|
Int adj;
|
|
vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I64);
|
|
vassert(op8 == Iop_Add8 || op8 == Iop_Sub8 || op8 == Iop_Mul8
|
|
|| op8 == Iop_Or8 || op8 == Iop_And8 || op8 == Iop_Xor8
|
|
|| op8 == Iop_Shl8 || op8 == Iop_Shr8 || op8 == Iop_Sar8
|
|
|| op8 == Iop_CmpEQ8 || op8 == Iop_CmpNE8 || op8 == Iop_Not8);
|
|
adj = ty == Ity_I8 ? 0 : (ty == Ity_I16 ? 1 : (ty == Ity_I32 ? 2 : 3));
|
|
return adj + op8;
|
|
}
|
|
|
|
/*********************************************************/
|
|
/*--- Floating Point Compare ---*/
|
|
/*********************************************************/
|
|
/* Function that returns a string that represent mips cond
|
|
mnemonic for the input code. */
|
|
static const HChar* showCondCode(UInt code) {
|
|
const HChar* ret;
|
|
switch (code) {
|
|
case 0: ret = "f"; break;
|
|
case 1: ret = "un"; break;
|
|
case 2: ret = "eq"; break;
|
|
case 3: ret = "ueq"; break;
|
|
case 4: ret = "olt"; break;
|
|
case 5: ret = "ult"; break;
|
|
case 6: ret = "ole"; break;
|
|
case 7: ret = "ule"; break;
|
|
case 8: ret = "sf"; break;
|
|
case 9: ret = "ngle"; break;
|
|
case 10: ret = "seq"; break;
|
|
case 11: ret = "ngl"; break;
|
|
case 12: ret = "lt"; break;
|
|
case 13: ret = "nge"; break;
|
|
case 14: ret = "le"; break;
|
|
case 15: ret = "ngt"; break;
|
|
default: vpanic("showCondCode"); break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static Bool dis_instr_CCondFmt ( UInt cins )
|
|
{
|
|
IRTemp t0, t1, t2, t3, tmp5, tmp6;
|
|
IRTemp ccIR = newTemp(Ity_I32);
|
|
IRTemp ccMIPS = newTemp(Ity_I32);
|
|
UInt FC = get_FC(cins);
|
|
UInt fmt = get_fmt(cins);
|
|
UInt fs = get_fs(cins);
|
|
UInt ft = get_ft(cins);
|
|
UInt cond = get_cond(cins);
|
|
|
|
if (FC == 0x3) { /* C.cond.fmt */
|
|
UInt fpc_cc = get_fpc_cc(cins);
|
|
switch (fmt) {
|
|
case 0x10: { /* C.cond.S */
|
|
DIP("c.%s.s %u, f%u, f%u", showCondCode(cond), fpc_cc, fs, ft);
|
|
if (fp_mode64) {
|
|
t0 = newTemp(Ity_I32);
|
|
t1 = newTemp(Ity_I32);
|
|
t2 = newTemp(Ity_I32);
|
|
t3 = newTemp(Ity_I32);
|
|
|
|
tmp5 = newTemp(Ity_F64);
|
|
tmp6 = newTemp(Ity_F64);
|
|
|
|
assign(tmp5, unop(Iop_F32toF64, getLoFromF64(Ity_F64,
|
|
getFReg(fs))));
|
|
assign(tmp6, unop(Iop_F32toF64, getLoFromF64(Ity_F64,
|
|
getFReg(ft))));
|
|
|
|
assign(ccIR, binop(Iop_CmpF64, mkexpr(tmp5), mkexpr(tmp6)));
|
|
putHI(mkWidenFrom32(mode64 ? Ity_I64: Ity_I32,
|
|
mkexpr(ccIR), True));
|
|
/* Map compare result from IR to MIPS
|
|
FP cmp result | MIPS | IR
|
|
--------------------------
|
|
UN | 0x1 | 0x45
|
|
EQ | 0x2 | 0x40
|
|
GT | 0x4 | 0x00
|
|
LT | 0x8 | 0x01
|
|
*/
|
|
|
|
/* ccMIPS = Shl(1, (~(ccIR>>5) & 2) | ((ccIR ^ (ccIR>>6)) & 1) */
|
|
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))),
|
|
mkU32(1))))));
|
|
putLO(mkWidenFrom32(mode64 ? Ity_I64: Ity_I32,
|
|
mkexpr(ccMIPS), True));
|
|
|
|
/* UN */
|
|
assign(t0, binop(Iop_And32, mkexpr(ccMIPS), mkU32(0x1)));
|
|
/* EQ */
|
|
assign(t1, binop(Iop_And32, binop(Iop_Shr32, mkexpr(ccMIPS),
|
|
mkU8(0x1)), mkU32(0x1)));
|
|
/* NGT */
|
|
assign(t2, binop(Iop_And32, unop(Iop_Not32, binop(Iop_Shr32,
|
|
mkexpr(ccMIPS), mkU8(0x2))),mkU32(0x1)));
|
|
/* LT */
|
|
assign(t3, binop(Iop_And32, binop(Iop_Shr32, mkexpr(ccMIPS),
|
|
mkU8(0x3)), mkU32(0x1)));
|
|
switch (cond) {
|
|
case 0x0:
|
|
setFPUCondCode(mkU32(0), fpc_cc);
|
|
break;
|
|
case 0x1:
|
|
setFPUCondCode(mkexpr(t0), fpc_cc);
|
|
break;
|
|
case 0x2:
|
|
setFPUCondCode(mkexpr(t1), fpc_cc);
|
|
break;
|
|
case 0x3:
|
|
setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
|
|
fpc_cc);
|
|
break;
|
|
case 0x4:
|
|
setFPUCondCode(mkexpr(t3), fpc_cc);
|
|
break;
|
|
case 0x5:
|
|
setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t3)),
|
|
fpc_cc);
|
|
break;
|
|
case 0x6:
|
|
setFPUCondCode(binop(Iop_Or32, mkexpr(t3), mkexpr(t1)),
|
|
fpc_cc);
|
|
break;
|
|
case 0x7:
|
|
setFPUCondCode(mkexpr(t2), fpc_cc);
|
|
break;
|
|
case 0x8:
|
|
setFPUCondCode(mkU32(0), fpc_cc);
|
|
break;
|
|
case 0x9:
|
|
setFPUCondCode(mkexpr(t0), fpc_cc);
|
|
break;
|
|
case 0xA:
|
|
setFPUCondCode(mkexpr(t1), fpc_cc);
|
|
break;
|
|
case 0xB:
|
|
setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
|
|
fpc_cc);
|
|
break;
|
|
case 0xC:
|
|
setFPUCondCode(mkexpr(t3), fpc_cc);
|
|
break;
|
|
case 0xD:
|
|
setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t3)),
|
|
fpc_cc);
|
|
break;
|
|
case 0xE:
|
|
setFPUCondCode(binop(Iop_Or32, mkexpr(t3), mkexpr(t1)),
|
|
fpc_cc);
|
|
break;
|
|
case 0xF:
|
|
setFPUCondCode(mkexpr(t2), fpc_cc);
|
|
break;
|
|
|
|
default:
|
|
return False;
|
|
}
|
|
|
|
} else {
|
|
t0 = newTemp(Ity_I32);
|
|
t1 = newTemp(Ity_I32);
|
|
t2 = newTemp(Ity_I32);
|
|
t3 = newTemp(Ity_I32);
|
|
|
|
assign(ccIR, binop(Iop_CmpF64, unop(Iop_F32toF64, getFReg(fs)),
|
|
unop(Iop_F32toF64, getFReg(ft))));
|
|
/* Map compare result from IR to MIPS
|
|
FP cmp result | MIPS | IR
|
|
--------------------------
|
|
UN | 0x1 | 0x45
|
|
EQ | 0x2 | 0x40
|
|
GT | 0x4 | 0x00
|
|
LT | 0x8 | 0x01
|
|
*/
|
|
|
|
/* ccMIPS = Shl(1, (~(ccIR>>5) & 2) | ((ccIR ^ (ccIR>>6)) & 1) */
|
|
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))),
|
|
mkU32(1))))));
|
|
/* UN */
|
|
assign(t0, binop(Iop_And32, mkexpr(ccMIPS), mkU32(0x1)));
|
|
/* EQ */
|
|
assign(t1, binop(Iop_And32, binop(Iop_Shr32, mkexpr(ccMIPS),
|
|
mkU8(0x1)), mkU32(0x1)));
|
|
/* NGT */
|
|
assign(t2, binop(Iop_And32, unop(Iop_Not32, binop(Iop_Shr32,
|
|
mkexpr(ccMIPS), mkU8(0x2))), mkU32(0x1)));
|
|
/* LT */
|
|
assign(t3, binop(Iop_And32, binop(Iop_Shr32, mkexpr(ccMIPS),
|
|
mkU8(0x3)), mkU32(0x1)));
|
|
|
|
switch (cond) {
|
|
case 0x0:
|
|
setFPUCondCode(mkU32(0), fpc_cc);
|
|
break;
|
|
case 0x1:
|
|
setFPUCondCode(mkexpr(t0), fpc_cc);
|
|
break;
|
|
case 0x2:
|
|
setFPUCondCode(mkexpr(t1), fpc_cc);
|
|
break;
|
|
case 0x3:
|
|
setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
|
|
fpc_cc);
|
|
break;
|
|
case 0x4:
|
|
setFPUCondCode(mkexpr(t3), fpc_cc);
|
|
break;
|
|
case 0x5:
|
|
setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t3)),
|
|
fpc_cc);
|
|
break;
|
|
case 0x6:
|
|
setFPUCondCode(binop(Iop_Or32, mkexpr(t3), mkexpr(t1)),
|
|
fpc_cc);
|
|
break;
|
|
case 0x7:
|
|
setFPUCondCode(mkexpr(t2), fpc_cc);
|
|
break;
|
|
case 0x8:
|
|
setFPUCondCode(mkU32(0), fpc_cc);
|
|
break;
|
|
case 0x9:
|
|
setFPUCondCode(mkexpr(t0), fpc_cc);
|
|
break;
|
|
case 0xA:
|
|
setFPUCondCode(mkexpr(t1), fpc_cc);
|
|
break;
|
|
case 0xB:
|
|
setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
|
|
fpc_cc);
|
|
break;
|
|
case 0xC:
|
|
setFPUCondCode(mkexpr(t3), fpc_cc);
|
|
break;
|
|
case 0xD:
|
|
setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t3)),
|
|
fpc_cc);
|
|
break;
|
|
case 0xE:
|
|
setFPUCondCode(binop(Iop_Or32, mkexpr(t3), mkexpr(t1)),
|
|
fpc_cc);
|
|
break;
|
|
case 0xF:
|
|
setFPUCondCode(mkexpr(t2), fpc_cc);
|
|
break;
|
|
|
|
default:
|
|
return False;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 0x11: { /* C.cond.D */
|
|
DIP("c.%s.d %u, f%u, f%u", showCondCode(cond), fpc_cc, fs, ft);
|
|
t0 = newTemp(Ity_I32);
|
|
t1 = newTemp(Ity_I32);
|
|
t2 = newTemp(Ity_I32);
|
|
t3 = newTemp(Ity_I32);
|
|
assign(ccIR, binop(Iop_CmpF64, getDReg(fs), getDReg(ft)));
|
|
/* Map compare result from IR to MIPS
|
|
FP cmp result | MIPS | IR
|
|
--------------------------
|
|
UN | 0x1 | 0x45
|
|
EQ | 0x2 | 0x40
|
|
GT | 0x4 | 0x00
|
|
LT | 0x8 | 0x01
|
|
*/
|
|
|
|
/* ccMIPS = Shl(1, (~(ccIR>>5) & 2) | ((ccIR ^ (ccIR>>6)) & 1) */
|
|
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))),
|
|
mkU32(1))))));
|
|
|
|
/* UN */
|
|
assign(t0, binop(Iop_And32, mkexpr(ccMIPS), mkU32(0x1)));
|
|
/* EQ */
|
|
assign(t1, binop(Iop_And32, binop(Iop_Shr32, mkexpr(ccMIPS),
|
|
mkU8(0x1)), mkU32(0x1)));
|
|
/* NGT */
|
|
assign(t2, binop(Iop_And32, unop(Iop_Not32, binop(Iop_Shr32,
|
|
mkexpr(ccMIPS), mkU8(0x2))), mkU32(0x1)));
|
|
/* LT */
|
|
assign(t3, binop(Iop_And32, binop(Iop_Shr32, mkexpr(ccMIPS),
|
|
mkU8(0x3)), mkU32(0x1)));
|
|
|
|
switch (cond) {
|
|
case 0x0:
|
|
setFPUCondCode(mkU32(0), fpc_cc);
|
|
break;
|
|
case 0x1:
|
|
setFPUCondCode(mkexpr(t0), fpc_cc);
|
|
break;
|
|
case 0x2:
|
|
setFPUCondCode(mkexpr(t1), fpc_cc);
|
|
break;
|
|
case 0x3:
|
|
setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
|
|
fpc_cc);
|
|
break;
|
|
case 0x4:
|
|
setFPUCondCode(mkexpr(t3), fpc_cc);
|
|
break;
|
|
case 0x5:
|
|
setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t3)),
|
|
fpc_cc);
|
|
break;
|
|
case 0x6:
|
|
setFPUCondCode(binop(Iop_Or32, mkexpr(t3), mkexpr(t1)),
|
|
fpc_cc);
|
|
break;
|
|
case 0x7:
|
|
setFPUCondCode(mkexpr(t2), fpc_cc);
|
|
break;
|
|
case 0x8:
|
|
setFPUCondCode(mkU32(0), fpc_cc);
|
|
break;
|
|
case 0x9:
|
|
setFPUCondCode(mkexpr(t0), fpc_cc);
|
|
break;
|
|
case 0xA:
|
|
setFPUCondCode(mkexpr(t1), fpc_cc);
|
|
break;
|
|
case 0xB:
|
|
setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
|
|
fpc_cc);
|
|
break;
|
|
case 0xC:
|
|
setFPUCondCode(mkexpr(t3), fpc_cc);
|
|
break;
|
|
case 0xD:
|
|
setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t3)),
|
|
fpc_cc);
|
|
break;
|
|
case 0xE:
|
|
setFPUCondCode(binop(Iop_Or32, mkexpr(t3), mkexpr(t1)),
|
|
fpc_cc);
|
|
break;
|
|
case 0xF:
|
|
setFPUCondCode(mkexpr(t2), fpc_cc);
|
|
break;
|
|
default:
|
|
return False;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return False;
|
|
}
|
|
} else {
|
|
return False;
|
|
}
|
|
|
|
return True;
|
|
}
|
|
|
|
/*********************************************************/
|
|
/*--- Branch Instructions for mips64 ---*/
|
|
/*********************************************************/
|
|
static Bool dis_instr_branch ( UInt theInstr, DisResult * dres,
|
|
Bool(*resteerOkFn) (void *, Addr),
|
|
void *callback_opaque, IRStmt ** set )
|
|
{
|
|
UInt jmpKind = 0;
|
|
UChar opc1 = get_opcode(theInstr);
|
|
UChar regRs = get_rs(theInstr);
|
|
UChar regRt = get_rt(theInstr);
|
|
UInt offset = get_imm(theInstr);
|
|
Long sOffset = extend_s_16to64(offset);
|
|
IRType ty = mode64 ? Ity_I64 : Ity_I32;
|
|
IROp opSlt = mode64 ? Iop_CmpLT64S : Iop_CmpLT32S;
|
|
|
|
IRTemp tmp = newTemp(ty);
|
|
IRTemp tmpRs = newTemp(ty);
|
|
IRTemp tmpRt = newTemp(ty);
|
|
IRTemp tmpLt = newTemp(ty);
|
|
IRTemp tmpReg0 = newTemp(ty);
|
|
|
|
UChar regLnk = 31; /* reg 31 is link reg in MIPS */
|
|
Addr64 addrTgt = 0;
|
|
Addr64 cia = guest_PC_curr_instr;
|
|
|
|
IRExpr *eConst0 = mkSzImm(ty, (UInt) 0);
|
|
IRExpr *eNia = mkSzImm(ty, cia + 8);
|
|
IRExpr *eCond = NULL;
|
|
|
|
assign(tmpRs, getIReg(regRs));
|
|
assign(tmpRt, getIReg(regRt));
|
|
assign(tmpReg0, getIReg(0));
|
|
|
|
eCond = binop(mkSzOp(ty, Iop_CmpNE8), mkexpr(tmpReg0), mkexpr(tmpReg0));
|
|
|
|
switch (opc1) {
|
|
case 0x01:
|
|
switch (regRt) {
|
|
case 0x00: { /* BLTZ rs, offset */
|
|
addrTgt = mkSzAddr(ty, cia + 4 + (sOffset << 2));
|
|
IRTemp tmpLtRes = newTemp(Ity_I1);
|
|
|
|
assign(tmp, eConst0);
|
|
assign(tmpLtRes, binop(opSlt, mkexpr(tmpRs), mkexpr(tmp)));
|
|
assign(tmpLt, mode64 ? unop(Iop_1Uto64, mkexpr(tmpLtRes)) :
|
|
unop(Iop_1Uto32, mkexpr(tmpLtRes)));
|
|
|
|
eCond = binop(mkSzOp(ty, Iop_CmpNE8), mkexpr(tmpLt),
|
|
mkexpr(tmpReg0));
|
|
|
|
jmpKind = Ijk_Boring;
|
|
break;
|
|
}
|
|
|
|
case 0x01: { /* BGEZ rs, offset */
|
|
IRTemp tmpLtRes = newTemp(Ity_I1);
|
|
addrTgt = mkSzAddr(ty, cia + 4 + (sOffset << 2));
|
|
|
|
assign(tmp, eConst0);
|
|
assign(tmpLtRes, binop(opSlt, mkexpr(tmpRs), mkexpr(tmp)));
|
|
assign(tmpLt, mode64 ? unop(Iop_1Uto64, mkexpr(tmpLtRes)) :
|
|
unop(Iop_1Uto32, mkexpr(tmpLtRes)));
|
|
eCond = binop(mkSzOp(ty, Iop_CmpEQ8), mkexpr(tmpLt),
|
|
mkexpr(tmpReg0));
|
|
|
|
jmpKind = Ijk_Boring;
|
|
break;
|
|
}
|
|
|
|
case 0x11: { /* BGEZAL rs, offset */
|
|
addrTgt = mkSzAddr(ty, cia + 4 + (sOffset << 2));
|
|
putIReg(regLnk, eNia);
|
|
IRTemp tmpLtRes = newTemp(Ity_I1);
|
|
|
|
assign(tmpLtRes, binop(opSlt, mkexpr(tmpRs), eConst0));
|
|
assign(tmpLt, mode64 ? unop(Iop_1Uto64, mkexpr(tmpLtRes)) :
|
|
unop(Iop_1Uto32, mkexpr(tmpLtRes)));
|
|
|
|
eCond = binop(mkSzOp(ty, Iop_CmpEQ8), mkexpr(tmpLt),
|
|
mkexpr(tmpReg0));
|
|
|
|
jmpKind = Ijk_Call;
|
|
break;
|
|
}
|
|
|
|
case 0x10: { /* BLTZAL rs, offset */
|
|
IRTemp tmpLtRes = newTemp(Ity_I1);
|
|
IRTemp tmpRes = newTemp(ty);
|
|
|
|
addrTgt = mkSzAddr(ty, cia + 4 + (sOffset << 2));
|
|
putIReg(regLnk, eNia);
|
|
|
|
assign(tmp, eConst0);
|
|
assign(tmpLtRes, binop(opSlt, mkexpr(tmpRs), mkexpr(tmp)));
|
|
assign(tmpRes, mode64 ? unop(Iop_1Uto64,
|
|
mkexpr(tmpLtRes)) : unop(Iop_1Uto32, mkexpr(tmpLtRes)));
|
|
eCond = binop(mkSzOp(ty, Iop_CmpNE8), mkexpr(tmpRes),
|
|
mkexpr(tmpReg0));
|
|
|
|
jmpKind = Ijk_Call;
|
|
break;
|
|
}
|
|
|
|
}
|
|
break;
|
|
default:
|
|
return False;
|
|
}
|
|
*set = IRStmt_Exit(eCond, jmpKind, mkSzConst(ty, addrTgt), OFFB_PC);
|
|
return True;
|
|
}
|
|
|
|
/*********************************************************/
|
|
/*--- Cavium Specific Instructions ---*/
|
|
/*********************************************************/
|
|
|
|
/* Convenience function to yield to thread scheduler */
|
|
static void jump_back(IRExpr *condition)
|
|
{
|
|
stmt( IRStmt_Exit(condition,
|
|
Ijk_Yield,
|
|
IRConst_U64( guest_PC_curr_instr ),
|
|
OFFB_PC) );
|
|
}
|
|
|
|
/* Based on s390_irgen_load_and_add32. */
|
|
static void mips_irgen_load_and_add32(IRTemp op1addr, IRTemp new_val,
|
|
UChar rd, Bool putIntoRd)
|
|
{
|
|
IRCAS *cas;
|
|
IRTemp old_mem = newTemp(Ity_I32);
|
|
IRTemp expd = newTemp(Ity_I32);
|
|
|
|
assign(expd, load(Ity_I32, mkexpr(op1addr)));
|
|
|
|
cas = mkIRCAS(IRTemp_INVALID, old_mem,
|
|
Iend_LE, mkexpr(op1addr),
|
|
NULL, mkexpr(expd), /* expected value */
|
|
NULL, mkexpr(new_val) /* new value */);
|
|
stmt(IRStmt_CAS(cas));
|
|
|
|
/* If old_mem contains the expected value, then the CAS succeeded.
|
|
Otherwise, it did not */
|
|
jump_back(binop(Iop_CmpNE32, mkexpr(old_mem), mkexpr(expd)));
|
|
if (putIntoRd)
|
|
putIReg(rd, mkWidenFrom32(Ity_I64, mkexpr(old_mem), True));
|
|
}
|
|
|
|
/* Based on s390_irgen_load_and_add64. */
|
|
static void mips_irgen_load_and_add64(IRTemp op1addr, IRTemp new_val,
|
|
UChar rd, Bool putIntoRd)
|
|
{
|
|
IRCAS *cas;
|
|
IRTemp old_mem = newTemp(Ity_I64);
|
|
IRTemp expd = newTemp(Ity_I64);
|
|
|
|
assign(expd, load(Ity_I64, mkexpr(op1addr)));
|
|
|
|
cas = mkIRCAS(IRTemp_INVALID, old_mem,
|
|
Iend_LE, mkexpr(op1addr),
|
|
NULL, mkexpr(expd), /* expected value */
|
|
NULL, mkexpr(new_val) /* new value */);
|
|
stmt(IRStmt_CAS(cas));
|
|
|
|
/* If old_mem contains the expected value, then the CAS succeeded.
|
|
Otherwise, it did not */
|
|
jump_back(binop(Iop_CmpNE64, mkexpr(old_mem), mkexpr(expd)));
|
|
if (putIntoRd)
|
|
putIReg(rd, mkexpr(old_mem));
|
|
}
|
|
|
|
static Bool dis_instr_CVM ( UInt theInstr )
|
|
{
|
|
UChar opc2 = get_function(theInstr);
|
|
UChar opc1 = get_opcode(theInstr);
|
|
UChar regRs = get_rs(theInstr);
|
|
UChar regRt = get_rt(theInstr);
|
|
UChar regRd = get_rd(theInstr);
|
|
/* MIPS trap instructions extract code from theInstr[15:6].
|
|
Cavium OCTEON instructions SNEI, SEQI extract immediate operands
|
|
from the same bit field [15:6]. */
|
|
UInt imm = get_code(theInstr);
|
|
UChar lenM1 = get_msb(theInstr);
|
|
UChar p = get_lsb(theInstr);
|
|
IRType ty = mode64? Ity_I64 : Ity_I32;
|
|
IRTemp tmp = newTemp(ty);
|
|
IRTemp tmpRs = newTemp(ty);
|
|
IRTemp tmpRt = newTemp(ty);
|
|
IRTemp t1 = newTemp(ty);
|
|
UInt size;
|
|
assign(tmpRs, getIReg(regRs));
|
|
|
|
switch(opc1) {
|
|
case 0x1C: {
|
|
switch(opc2) {
|
|
case 0x03: { /* DMUL rd, rs, rt */
|
|
DIP("dmul r%u, r%u, r%u", regRd, regRs, regRt);
|
|
IRTemp t0 = newTemp(Ity_I128);
|
|
assign(t0, binop(Iop_MullU64, getIReg(regRs), getIReg(regRt)));
|
|
putIReg(regRd, unop(Iop_128to64, mkexpr(t0)));
|
|
break;
|
|
}
|
|
|
|
case 0x18: { /* Store Atomic Add Word - SAA; Cavium OCTEON */
|
|
DIP("saa r%u, (r%u)", regRt, regRs);
|
|
IRTemp addr = newTemp(Ity_I64);
|
|
IRTemp new = newTemp(Ity_I32);
|
|
assign (addr, getIReg(regRs));
|
|
assign(new, binop(Iop_Add32,
|
|
load(Ity_I32, mkexpr(addr)),
|
|
mkNarrowTo32(ty, getIReg(regRt))));
|
|
mips_irgen_load_and_add32(addr, new, 0, False);
|
|
break;
|
|
}
|
|
|
|
/* Store Atomic Add Doubleword - SAAD; Cavium OCTEON */
|
|
case 0x19: {
|
|
DIP( "saad r%u, (r%u)", regRt, regRs);
|
|
IRTemp addr = newTemp(Ity_I64);
|
|
IRTemp new = newTemp(Ity_I64);
|
|
assign (addr, getIReg(regRs));
|
|
assign(new, binop(Iop_Add64,
|
|
load(Ity_I64, mkexpr(addr)),
|
|
getIReg(regRt)));
|
|
mips_irgen_load_and_add64(addr, new, 0, False);
|
|
break;
|
|
}
|
|
|
|
/* LAI, LAID, LAD, LADD, LAS, LASD,
|
|
LAC, LACD, LAA, LAAD, LAW, LAWD */
|
|
case 0x1f: {
|
|
UInt opc3 = get_sa(theInstr);
|
|
IRTemp addr = newTemp(Ity_I64);
|
|
switch (opc3) {
|
|
/* Load Atomic Increment Word - LAI; Cavium OCTEON2 */
|
|
case 0x02: {
|
|
DIP("lai r%u,(r%u)\n", regRd, regRs);
|
|
IRTemp new = newTemp(Ity_I32);
|
|
assign(addr, getIReg(regRs));
|
|
assign(new, binop(Iop_Add32,
|
|
load(Ity_I32, mkexpr(addr)),
|
|
mkU32(1)));
|
|
mips_irgen_load_and_add32(addr, new, regRd, True);
|
|
break;
|
|
}
|
|
/* Load Atomic Increment Doubleword - LAID; Cavium OCTEON2 */
|
|
case 0x03: {
|
|
DIP("laid r%u,(r%u)\n", regRd, regRs);
|
|
IRTemp new = newTemp(Ity_I64);
|
|
assign(addr, getIReg(regRs));
|
|
assign(new, binop(Iop_Add64,
|
|
load(Ity_I64, mkexpr(addr)),
|
|
mkU64(1)));
|
|
mips_irgen_load_and_add64(addr, new, regRd, True);
|
|
break;
|
|
}
|
|
/* Load Atomic Decrement Word - LAD; Cavium OCTEON2 */
|
|
case 0x06: {
|
|
DIP("lad r%u,(r%u)\n", regRd, regRs);
|
|
IRTemp new = newTemp(Ity_I32);
|
|
assign(addr, getIReg(regRs));
|
|
assign(new, binop(Iop_Sub32,
|
|
load(Ity_I32, mkexpr(addr)),
|
|
mkU32(1)));
|
|
mips_irgen_load_and_add32(addr, new, regRd, True);
|
|
break;
|
|
}
|
|
/* Load Atomic Decrement Doubleword - LADD; Cavium OCTEON2 */
|
|
case 0x07: {
|
|
DIP("ladd r%u,(r%u)\n", regRd, regRs);
|
|
IRTemp new = newTemp(Ity_I64);
|
|
assign (addr, getIReg(regRs));
|
|
assign(new, binop(Iop_Sub64,
|
|
load(Ity_I64, mkexpr(addr)),
|
|
mkU64(1)));
|
|
mips_irgen_load_and_add64(addr, new, regRd, True);
|
|
break;
|
|
}
|
|
/* Load Atomic Set Word - LAS; Cavium OCTEON2 */
|
|
case 0x0a: {
|
|
DIP("las r%u,(r%u)\n", regRd, regRs);
|
|
IRTemp new = newTemp(Ity_I32);
|
|
assign(addr, getIReg(regRs));
|
|
assign(new, mkU32(0xffffffff));
|
|
mips_irgen_load_and_add32(addr, new, regRd, True);
|
|
break;
|
|
}
|
|
/* Load Atomic Set Doubleword - LASD; Cavium OCTEON2 */
|
|
case 0x0b: {
|
|
DIP("lasd r%u,(r%u)\n", regRd, regRs);
|
|
IRTemp new = newTemp(Ity_I64);
|
|
assign (addr, getIReg(regRs));
|
|
assign(new, mkU64(0xffffffffffffffffULL));
|
|
mips_irgen_load_and_add64(addr, new, regRd, True);
|
|
break;
|
|
}
|
|
/* Load Atomic Clear Word - LAC; Cavium OCTEON2 */
|
|
case 0x0e: {
|
|
DIP("lac r%u,(r%u)\n", regRd, regRs);
|
|
IRTemp new = newTemp(Ity_I32);
|
|
assign (addr, getIReg(regRs));
|
|
assign(new, mkU32(0));
|
|
mips_irgen_load_and_add32(addr, new, regRd, True);
|
|
break;
|
|
}
|
|
/* Load Atomic Clear Doubleword - LACD; Cavium OCTEON2 */
|
|
case 0x0f: {
|
|
DIP("lacd r%u,(r%u)\n", regRd, regRs);
|
|
IRTemp new = newTemp(Ity_I64);
|
|
assign(addr, getIReg(regRs));
|
|
assign(new, mkU64(0));
|
|
mips_irgen_load_and_add64(addr, new, regRd, True);
|
|
break;
|
|
}
|
|
/* Load Atomic Add Word - LAA; Cavium OCTEON2 */
|
|
case 0x12: {
|
|
DIP("laa r%u,(r%u),r%u\n", regRd, regRs, regRt);
|
|
IRTemp new = newTemp(Ity_I32);
|
|
assign(addr, getIReg(regRs));
|
|
assign(new, binop(Iop_Add32,
|
|
load(Ity_I32, mkexpr(addr)),
|
|
mkNarrowTo32(ty, getIReg(regRt))));
|
|
mips_irgen_load_and_add32(addr, new, regRd, True);
|
|
break;
|
|
}
|
|
/* Load Atomic Add Doubleword - LAAD; Cavium OCTEON2 */
|
|
case 0x13: {
|
|
DIP("laad r%u,(r%u),r%u\n", regRd, regRs, regRt);
|
|
IRTemp new = newTemp(Ity_I64);
|
|
assign (addr, getIReg(regRs));
|
|
assign(new, binop(Iop_Add64,
|
|
load(Ity_I64, mkexpr(addr)),
|
|
getIReg(regRt)));
|
|
mips_irgen_load_and_add64(addr, new, regRd, True);
|
|
break;
|
|
}
|
|
/* Load Atomic Swap Word - LAW; Cavium OCTEON2 */
|
|
case 0x16: {
|
|
DIP("law r%u,(r%u)\n", regRd, regRs);
|
|
IRTemp new = newTemp(Ity_I32);
|
|
assign(addr, getIReg(regRs));
|
|
assign(new, mkNarrowTo32(ty, getIReg(regRt)));
|
|
mips_irgen_load_and_add32(addr, new, regRd, True);
|
|
break;
|
|
}
|
|
/* Load Atomic Swap Doubleword - LAWD; Cavium OCTEON2 */
|
|
case 0x17: {
|
|
DIP("lawd r%u,(r%u)\n", regRd, regRs);
|
|
IRTemp new = newTemp(Ity_I64);
|
|
assign(addr, getIReg(regRs));
|
|
assign(new, getIReg(regRt));
|
|
mips_irgen_load_and_add64(addr, new, regRd, True);
|
|
break;
|
|
}
|
|
default:
|
|
vex_printf("Unknown laxx instruction, opc3=0x%x\n", opc3);
|
|
vex_printf("Instruction=0x%08x\n", theInstr);
|
|
return False;
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* Unsigned Byte Add - BADDU rd, rs, rt; Cavium OCTEON */
|
|
case 0x28: {
|
|
DIP("BADDU r%u, r%u, r%u", regRs, regRt, regRd);
|
|
IRTemp t0 = newTemp(Ity_I8);
|
|
|
|
assign(t0, binop(Iop_Add8,
|
|
mkNarrowTo8(ty, getIReg(regRs)),
|
|
mkNarrowTo8(ty, getIReg(regRt))));
|
|
|
|
if (mode64)
|
|
putIReg(regRd, binop(mkSzOp(ty, Iop_And8),
|
|
unop(Iop_8Uto64, mkexpr(t0)),
|
|
mkSzImm(ty, 0xFF)));
|
|
else
|
|
putIReg(regRd, binop(mkSzOp(ty, Iop_And8),
|
|
unop(Iop_8Uto32, mkexpr(t0)),
|
|
mkSzImm(ty, 0xFF)));
|
|
break;
|
|
}
|
|
|
|
case 0x2c: { /* Count Ones in a Word - POP; Cavium OCTEON */
|
|
int i, shift[5];
|
|
IRTemp mask[5];
|
|
IRTemp old = newTemp(ty);
|
|
IRTemp nyu = IRTemp_INVALID;
|
|
assign(old, getIReg(regRs));
|
|
DIP("pop r%u, r%u", regRd, regRs);
|
|
|
|
for (i = 0; i < 5; i++) {
|
|
mask[i] = newTemp(ty);
|
|
shift[i] = 1 << i;
|
|
}
|
|
if(mode64) {
|
|
assign(mask[0], mkU64(0x0000000055555555));
|
|
assign(mask[1], mkU64(0x0000000033333333));
|
|
assign(mask[2], mkU64(0x000000000F0F0F0F));
|
|
assign(mask[3], mkU64(0x0000000000FF00FF));
|
|
assign(mask[4], mkU64(0x000000000000FFFF));
|
|
|
|
for (i = 0; i < 5; i++) {
|
|
nyu = newTemp(ty);
|
|
assign(nyu,
|
|
binop(Iop_Add64,
|
|
binop(Iop_And64,
|
|
mkexpr(old), mkexpr(mask[i])),
|
|
binop(Iop_And64,
|
|
binop(Iop_Shr64,
|
|
mkexpr(old), mkU8(shift[i])),
|
|
mkexpr(mask[i]))));
|
|
old = nyu;
|
|
}
|
|
} else {
|
|
assign(mask[0], mkU32(0x55555555));
|
|
assign(mask[1], mkU32(0x33333333));
|
|
assign(mask[2], mkU32(0x0F0F0F0F));
|
|
assign(mask[3], mkU32(0x00FF00FF));
|
|
assign(mask[4], mkU32(0x0000FFFF));
|
|
assign(old, getIReg(regRs));
|
|
|
|
for (i = 0; i < 5; i++) {
|
|
nyu = newTemp(ty);
|
|
assign(nyu,
|
|
binop(Iop_Add32,
|
|
binop(Iop_And32,
|
|
mkexpr(old), mkexpr(mask[i])),
|
|
binop(Iop_And32,
|
|
binop(Iop_Shr32,
|
|
mkexpr(old), mkU8(shift[i])),
|
|
mkexpr(mask[i]))));
|
|
old = nyu;
|
|
}
|
|
}
|
|
putIReg(regRd, mkexpr(nyu));
|
|
break;
|
|
}
|
|
|
|
/* Count Ones in a Doubleword - DPOP; Cavium OCTEON */
|
|
case 0x2d: {
|
|
int i, shift[6];
|
|
IRTemp mask[6];
|
|
IRTemp old = newTemp(ty);
|
|
IRTemp nyu = IRTemp_INVALID;
|
|
DIP("dpop r%u, r%u", regRd, regRs);
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
mask[i] = newTemp(ty);
|
|
shift[i] = 1 << i;
|
|
}
|
|
vassert(mode64); /*Caution! Only for Mode 64*/
|
|
assign(mask[0], mkU64(0x5555555555555555ULL));
|
|
assign(mask[1], mkU64(0x3333333333333333ULL));
|
|
assign(mask[2], mkU64(0x0F0F0F0F0F0F0F0FULL));
|
|
assign(mask[3], mkU64(0x00FF00FF00FF00FFULL));
|
|
assign(mask[4], mkU64(0x0000FFFF0000FFFFULL));
|
|
assign(mask[5], mkU64(0x00000000FFFFFFFFULL));
|
|
assign(old, getIReg(regRs));
|
|
for (i = 0; i < 6; i++) {
|
|
nyu = newTemp(Ity_I64);
|
|
assign(nyu,
|
|
binop(Iop_Add64,
|
|
binop(Iop_And64,
|
|
mkexpr(old), mkexpr(mask[i])),
|
|
binop(Iop_And64,
|
|
binop(Iop_Shr64,
|
|
mkexpr(old), mkU8(shift[i])),
|
|
mkexpr(mask[i]))));
|
|
old = nyu;
|
|
}
|
|
putIReg(regRd, mkexpr(nyu));
|
|
break;
|
|
}
|
|
|
|
case 0x32: /* 5. CINS rd, rs, p, lenm1 */
|
|
DIP("cins r%u, r%u, %u, %u\n", regRt, regRs, p, lenM1);
|
|
assign ( tmp , binop(Iop_Shl64, mkexpr(tmpRs),
|
|
mkU8(64-( lenM1+1 ))));
|
|
assign ( tmpRt, binop(Iop_Shr64, mkexpr( tmp ),
|
|
mkU8(64-(p+lenM1+1))));
|
|
putIReg( regRt, mkexpr(tmpRt));
|
|
break;
|
|
|
|
case 0x33: /* 6. CINS32 rd, rs, p+32, lenm1 */
|
|
DIP("cins32 r%u, r%u, %d, %d\n", regRt, regRs, p+32, lenM1);
|
|
assign ( tmp , binop(Iop_Shl64, mkexpr(tmpRs),
|
|
mkU8(64-( lenM1+1 ))));
|
|
assign ( tmpRt, binop(Iop_Shr64, mkexpr( tmp ),
|
|
mkU8(32-(p+lenM1+1))));
|
|
putIReg( regRt, mkexpr(tmpRt));
|
|
break;
|
|
|
|
case 0x3A: /* 3. EXTS rt, rs, p len */
|
|
DIP("exts r%u, r%u, %d, %d\n", regRt, regRs, p, lenM1);
|
|
size = lenM1 + 1; /* lenm1+1 */
|
|
UChar lsAmt = 64 - (p + size); /* p+lenm1+1 */
|
|
UChar rsAmt = 64 - size; /* lenm1+1 */
|
|
tmp = newTemp(Ity_I64);
|
|
assign(tmp, binop(Iop_Shl64, mkexpr(tmpRs), mkU8(lsAmt)));
|
|
putIReg(regRt, binop(Iop_Sar64, mkexpr(tmp), mkU8(rsAmt)));
|
|
break;
|
|
|
|
case 0x3B: /* 4. EXTS32 rt, rs, p len */
|
|
DIP("exts32 r%u, r%u, %d, %d\n", regRt, regRs, p, lenM1);
|
|
assign ( tmp , binop(Iop_Shl64, mkexpr(tmpRs),
|
|
mkU8(32-(p+lenM1+1))));
|
|
assign ( tmpRt, binop(Iop_Sar64, mkexpr(tmp),
|
|
mkU8(64-(lenM1+1))) );
|
|
putIReg( regRt, mkexpr(tmpRt));
|
|
break;
|
|
|
|
case 0x2B: /* 20. SNE rd, rs, rt */
|
|
DIP("sne r%u, r%u, r%u", regRd,regRs, regRt);
|
|
if (mode64)
|
|
putIReg(regRd, unop(Iop_1Uto64, binop(Iop_CmpNE64,
|
|
getIReg(regRs),
|
|
getIReg(regRt))));
|
|
else
|
|
putIReg(regRd,unop(Iop_1Uto32, binop(Iop_CmpNE32,
|
|
getIReg(regRs),
|
|
getIReg(regRt))));
|
|
break;
|
|
|
|
case 0x2A: /* Set Equals - SEQ; Cavium OCTEON */
|
|
DIP("seq r%u, r%u, %d", regRd, regRs, regRt);
|
|
if (mode64)
|
|
putIReg(regRd, unop(Iop_1Uto64,
|
|
binop(Iop_CmpEQ64, getIReg(regRs),
|
|
getIReg(regRt))));
|
|
else
|
|
putIReg(regRd, unop(Iop_1Uto32,
|
|
binop(Iop_CmpEQ32, getIReg(regRs),
|
|
getIReg(regRt))));
|
|
break;
|
|
|
|
case 0x2E: /* Set Equals Immediate - SEQI; Cavium OCTEON */
|
|
DIP("seqi r%u, r%u, %u", regRt, regRs, imm);
|
|
if (mode64)
|
|
putIReg(regRt, unop(Iop_1Uto64,
|
|
binop(Iop_CmpEQ64, getIReg(regRs),
|
|
mkU64(extend_s_10to64(imm)))));
|
|
else
|
|
putIReg(regRt, unop(Iop_1Uto32,
|
|
binop(Iop_CmpEQ32, getIReg(regRs),
|
|
mkU32(extend_s_10to32(imm)))));
|
|
break;
|
|
|
|
case 0x2F: /* Set Not Equals Immediate - SNEI; Cavium OCTEON */
|
|
DIP("snei r%u, r%u, %u", regRt, regRs, imm);
|
|
if (mode64)
|
|
putIReg(regRt, unop(Iop_1Uto64,
|
|
binop(Iop_CmpNE64,
|
|
getIReg(regRs),
|
|
mkU64(extend_s_10to64(imm)))));
|
|
else
|
|
putIReg(regRt, unop(Iop_1Uto32,
|
|
binop(Iop_CmpNE32,
|
|
getIReg(regRs),
|
|
mkU32(extend_s_10to32(imm)))));
|
|
break;
|
|
|
|
default:
|
|
return False;
|
|
}
|
|
break;
|
|
} /* opc1 0x1C ends here*/
|
|
case 0x1F: {
|
|
switch(opc2) {
|
|
case 0x0A: { // lx - Load indexed instructions
|
|
switch (get_sa(theInstr)) {
|
|
case 0x00: { // LWX rd, index(base)
|
|
DIP("lwx r%u, r%u(r%u)", regRd, regRt, regRs);
|
|
LOADX_STORE_PATTERN;
|
|
putIReg(regRd, mkWidenFrom32(ty, load(Ity_I32, mkexpr(t1)),
|
|
True));
|
|
break;
|
|
}
|
|
case 0x04: // LHX rd, index(base)
|
|
DIP("lhx r%u, r%u(r%u)", regRd, regRt, regRs);
|
|
LOADX_STORE_PATTERN;
|
|
if (mode64)
|
|
putIReg(regRd, unop(Iop_16Sto64, load(Ity_I16,
|
|
mkexpr(t1))));
|
|
else
|
|
putIReg(regRd, unop(Iop_16Sto32, load(Ity_I16,
|
|
mkexpr(t1))));
|
|
break;
|
|
case 0x08: { // LDX rd, index(base)
|
|
DIP("ldx r%u, r%u(r%u)", regRd, regRt, regRs);
|
|
vassert(mode64); /* Currently Implemented only for n64 */
|
|
LOADX_STORE_PATTERN;
|
|
putIReg(regRd, load(Ity_I64, mkexpr(t1)));
|
|
break;
|
|
}
|
|
case 0x06: { // LBUX rd, index(base)
|
|
DIP("lbux r%u, r%u(r%u)", regRd, regRt, regRs);
|
|
LOADX_STORE_PATTERN;
|
|
if (mode64)
|
|
putIReg(regRd, unop(Iop_8Uto64, load(Ity_I8,
|
|
mkexpr(t1))));
|
|
else
|
|
putIReg(regRd, unop(Iop_8Uto32, load(Ity_I8,
|
|
mkexpr(t1))));
|
|
break;
|
|
}
|
|
case 0x10: { // LWUX rd, index(base) (Cavium OCTEON)
|
|
DIP("lwux r%u, r%u(r%u)", regRd, regRt, regRs);
|
|
LOADX_STORE_PATTERN; /* same for both 32 and 64 modes*/
|
|
putIReg(regRd, mkWidenFrom32(ty, load(Ity_I32, mkexpr(t1)),
|
|
False));
|
|
break;
|
|
}
|
|
case 0x14: { // LHUX rd, index(base) (Cavium OCTEON)
|
|
DIP("lhux r%u, r%u(r%u)", regRd, regRt, regRs);
|
|
LOADX_STORE_PATTERN;
|
|
if (mode64)
|
|
putIReg(regRd,
|
|
unop(Iop_16Uto64, load(Ity_I16, mkexpr(t1))));
|
|
else
|
|
putIReg(regRd,
|
|
unop(Iop_16Uto32, load(Ity_I16, mkexpr(t1))));
|
|
break;
|
|
}
|
|
case 0x16: { // LBX rd, index(base) (Cavium OCTEON)
|
|
DIP("lbx r%u, r%u(r%u)", regRd, regRs, regRt);
|
|
LOADX_STORE_PATTERN;
|
|
if (mode64)
|
|
putIReg(regRd,
|
|
unop(Iop_8Sto64, load(Ity_I8, mkexpr(t1))));
|
|
else
|
|
putIReg(regRd,
|
|
unop(Iop_8Sto32, load(Ity_I8, mkexpr(t1))));
|
|
break;
|
|
}
|
|
default:
|
|
vex_printf("\nUnhandled LX instruction opc3 = %x\n",
|
|
get_sa(theInstr));
|
|
return False;
|
|
}
|
|
break;
|
|
}
|
|
} /* opc1 = 0x1F & opc2 = 0xA (LX) ends here*/
|
|
break;
|
|
} /* opc1 = 0x1F ends here*/
|
|
default:
|
|
return False;
|
|
} /* main opc1 switch ends here */
|
|
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;
|
|
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%u r%u", ac_mfhilo, rd);
|
|
putIReg(rd, unop(Iop_64HIto32, getAcc(ac_mfhilo)));
|
|
break;
|
|
}
|
|
|
|
case 0x11: { /* MTHI */
|
|
DIP("mthi ac%u r%u", 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%u r%u", ac_mfhilo, rd);
|
|
putIReg(rd, unop(Iop_64to32, getAcc(ac_mfhilo)));
|
|
break;
|
|
}
|
|
|
|
case 0x13: { /* MTLO */
|
|
DIP("mtlo ac%u r%u", 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%u r%u, r%u", 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%u r%u, r%u", 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%u, r%u, r%u", 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%u r%u, r%u", 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%u r%u, r%u", 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%u r%u, r%u", 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%u, r%u", 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%u, %u", 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%u, r%u", 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%u, r%u", 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%u, r%u", 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%u, r%u", 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%u, r%u", 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%u, r%u", 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%u, %u", 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%u, r%u", 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%u, r%u", rd, rt);
|
|
vassert(!mode64);
|
|
putIReg(rd, binop(Iop_And32,
|
|
getIReg(rt),
|
|
mkU32(0xffff0000)));
|
|
break;
|
|
}
|
|
case 0xD: { /* PRECEQ.W.PHR */
|
|
DIP("preceq.w.phr r%u, r%u", 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%u, r%u", 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%u, r%u", 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%u, r%u", 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%u, r%u", 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%u, r%u", 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%u, r%u", 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%u, ac%u, %u", rt, ac, rs);
|
|
vassert(!mode64);
|
|
t0 = newTemp(Ity_I64);
|
|
t1 = newTemp(Ity_I64);
|
|
t2 = newTemp(Ity_I32);
|
|
t3 = newTemp(Ity_I1);
|
|
t4 = newTemp(Ity_I1);
|
|
t5 = newTemp(Ity_I1);
|
|
t6 = newTemp(Ity_I1);
|
|
t7 = newTemp(Ity_I32);
|
|
t8 = newTemp(Ity_I64);
|
|
t9 = newTemp(Ity_I64);
|
|
t10 = newTemp(Ity_I1);
|
|
t11 = newTemp(Ity_I1);
|
|
t12 = newTemp(Ity_I1);
|
|
t13 = newTemp(Ity_I1);
|
|
t14 = newTemp(Ity_I32);
|
|
|
|
assign(t0, getAcc(ac));
|
|
if (0 == rs) {
|
|
assign(t1, mkexpr(t0));
|
|
} else {
|
|
assign(t1, binop(Iop_Sar64, mkexpr(t0), mkU8(rs)));
|
|
}
|
|
/* Check if bits 63..31 of the result in t1 aren't 0. */
|
|
assign(t3, binop(Iop_CmpNE32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t1)),
|
|
mkU32(0)));
|
|
assign(t4, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
unop(Iop_64to32,
|
|
mkexpr(t1)),
|
|
mkU32(0x80000000)),
|
|
mkU32(0)));
|
|
/* Check if bits 63..31 of the result in t1 aren't
|
|
0x1ffffffff. */
|
|
assign(t5, binop(Iop_CmpNE32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t1)),
|
|
mkU32(0xffffffff)));
|
|
assign(t6, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
unop(Iop_64to32,
|
|
mkexpr(t1)),
|
|
mkU32(0x80000000)),
|
|
mkU32(0x80000000)));
|
|
/* If bits 63..31 aren't 0 nor 0x1ffffffff, set DSP
|
|
control register. */
|
|
assign(t7, binop(Iop_And32,
|
|
binop(Iop_Or32,
|
|
unop(Iop_1Sto32, mkexpr(t3)),
|
|
unop(Iop_1Sto32, mkexpr(t4))),
|
|
binop(Iop_Or32,
|
|
unop(Iop_1Sto32, mkexpr(t5)),
|
|
unop(Iop_1Sto32, mkexpr(t6)))));
|
|
putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
|
|
mkexpr(t7),
|
|
mkU32(0)),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
mkU32(0x00800000)),
|
|
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. */
|
|
if (0 == rs) {
|
|
assign(t8, mkU64(0x0ULL));
|
|
} else {
|
|
assign(t8, binop(Iop_And64,
|
|
binop(Iop_Shr64,
|
|
mkexpr(t0),
|
|
mkU8(rs-1)),
|
|
mkU64(0x1ULL)));
|
|
}
|
|
assign(t9, binop(Iop_Add64, mkexpr(t1), mkexpr(t8)));
|
|
|
|
/* Repeat previous steps for the rounded value. */
|
|
assign(t10, binop(Iop_CmpNE32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t9)),
|
|
mkU32(0)));
|
|
assign(t11, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
unop(Iop_64to32,
|
|
mkexpr(t9)),
|
|
mkU32(0x80000000)),
|
|
mkU32(0)));
|
|
|
|
assign(t12, binop(Iop_CmpNE32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t9)),
|
|
mkU32(0xffffffff)));
|
|
assign(t13, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
unop(Iop_64to32,
|
|
mkexpr(t9)),
|
|
mkU32(0x80000000)),
|
|
mkU32(0x80000000)));
|
|
|
|
assign(t14, binop(Iop_And32,
|
|
binop(Iop_Or32,
|
|
unop(Iop_1Sto32, mkexpr(t10)),
|
|
unop(Iop_1Sto32, mkexpr(t11))),
|
|
binop(Iop_Or32,
|
|
unop(Iop_1Sto32, mkexpr(t12)),
|
|
unop(Iop_1Sto32, mkexpr(t13)))));
|
|
putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
|
|
mkexpr(t14),
|
|
mkU32(0)),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
mkU32(0x00800000)),
|
|
getDSPControl()));
|
|
if (0 == rs) {
|
|
putIReg(rt, unop(Iop_64to32, mkexpr(t0)));
|
|
} else {
|
|
putIReg(rt, unop(Iop_64to32, mkexpr(t1)));
|
|
}
|
|
break;
|
|
}
|
|
case 0x1: { /* EXTRV.W */
|
|
DIP("extrv.w r%u, ac%u, r%u", rt, ac, rs);
|
|
vassert(!mode64);
|
|
t0 = newTemp(Ity_I64);
|
|
t1 = newTemp(Ity_I64);
|
|
t2 = newTemp(Ity_I32);
|
|
t3 = newTemp(Ity_I1);
|
|
t4 = newTemp(Ity_I1);
|
|
t5 = newTemp(Ity_I1);
|
|
t6 = newTemp(Ity_I1);
|
|
t7 = newTemp(Ity_I32);
|
|
t8 = newTemp(Ity_I64);
|
|
t9 = newTemp(Ity_I64);
|
|
t10 = newTemp(Ity_I1);
|
|
t11 = newTemp(Ity_I1);
|
|
t12 = newTemp(Ity_I1);
|
|
t13 = newTemp(Ity_I1);
|
|
t14 = newTemp(Ity_I32);
|
|
t15 = newTemp(Ity_I8);
|
|
|
|
assign(t15, unop(Iop_32to8,
|
|
binop(Iop_And32,
|
|
getIReg(rs),
|
|
mkU32(0x1f))));
|
|
assign(t0, getAcc(ac));
|
|
assign(t1, binop(Iop_Sar64, mkexpr(t0), mkexpr(t15)));
|
|
putIReg(rt, IRExpr_ITE(binop(Iop_CmpEQ32,
|
|
unop(Iop_8Uto32,
|
|
mkexpr(t15)),
|
|
mkU32(0)),
|
|
unop(Iop_64to32, mkexpr(t0)),
|
|
unop(Iop_64to32, mkexpr(t1))));
|
|
|
|
/* Check if bits 63..31 of the result in t1 aren't 0. */
|
|
assign(t3, binop(Iop_CmpNE32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t1)),
|
|
mkU32(0)));
|
|
assign(t4, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
unop(Iop_64to32,
|
|
mkexpr(t1)),
|
|
mkU32(0x80000000)),
|
|
mkU32(0)));
|
|
/* Check if bits 63..31 of the result in t1 aren't
|
|
0x1ffffffff. */
|
|
assign(t5, binop(Iop_CmpNE32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t1)),
|
|
mkU32(0xffffffff)));
|
|
assign(t6, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
unop(Iop_64to32,
|
|
mkexpr(t1)),
|
|
mkU32(0x80000000)),
|
|
mkU32(0x80000000)));
|
|
/* If bits 63..31 aren't 0 nor 0x1ffffffff, set DSP
|
|
control register. */
|
|
assign(t7, binop(Iop_And32,
|
|
binop(Iop_Or32,
|
|
unop(Iop_1Sto32, mkexpr(t3)),
|
|
unop(Iop_1Sto32, mkexpr(t4))),
|
|
binop(Iop_Or32,
|
|
unop(Iop_1Sto32, mkexpr(t5)),
|
|
unop(Iop_1Sto32, mkexpr(t6)))));
|
|
putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
|
|
mkexpr(t7),
|
|
mkU32(0)),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
mkU32(0x00800000)),
|
|
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(t8,
|
|
IRExpr_ITE(binop(Iop_CmpEQ32,
|
|
unop(Iop_8Uto32,
|
|
mkexpr(t15)),
|
|
mkU32(0)),
|
|
mkU64(0x0ULL),
|
|
binop(Iop_And64,
|
|
binop(Iop_Shr64,
|
|
mkexpr(t0),
|
|
unop(Iop_32to8,
|
|
binop(Iop_Sub32,
|
|
unop(Iop_8Uto32,
|
|
mkexpr(t15)),
|
|
mkU32(1)))),
|
|
mkU64(0x1ULL))));
|
|
|
|
assign(t9, binop(Iop_Add64, mkexpr(t1), mkexpr(t8)));
|
|
|
|
/* Repeat previous steps for the rounded value. */
|
|
assign(t10, binop(Iop_CmpNE32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t9)),
|
|
mkU32(0)));
|
|
assign(t11, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
unop(Iop_64to32,
|
|
mkexpr(t9)),
|
|
mkU32(0x80000000)),
|
|
mkU32(0)));
|
|
|
|
assign(t12, binop(Iop_CmpNE32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t9)),
|
|
mkU32(0xffffffff)));
|
|
assign(t13, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
unop(Iop_64to32,
|
|
mkexpr(t9)),
|
|
mkU32(0x80000000)),
|
|
mkU32(0x80000000)));
|
|
|
|
assign(t14, binop(Iop_And32,
|
|
binop(Iop_Or32,
|
|
unop(Iop_1Sto32, mkexpr(t10)),
|
|
unop(Iop_1Sto32, mkexpr(t11))),
|
|
binop(Iop_Or32,
|
|
unop(Iop_1Sto32, mkexpr(t12)),
|
|
unop(Iop_1Sto32, mkexpr(t13)))));
|
|
putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
|
|
mkexpr(t14),
|
|
mkU32(0)),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
mkU32(0x00800000)),
|
|
getDSPControl()));
|
|
break;
|
|
}
|
|
case 0x2: { /* EXTP */
|
|
DIP("extp r%u, ac%u, %u", 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%u, ac%u, r%u", 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%u, ac%u, %u", rt, ac, rs);
|
|
vassert(!mode64);
|
|
t0 = newTemp(Ity_I64);
|
|
t1 = newTemp(Ity_I64);
|
|
t2 = newTemp(Ity_I32);
|
|
t3 = newTemp(Ity_I1);
|
|
t4 = newTemp(Ity_I1);
|
|
t5 = newTemp(Ity_I1);
|
|
t6 = newTemp(Ity_I1);
|
|
t7 = newTemp(Ity_I32);
|
|
t8 = newTemp(Ity_I64);
|
|
t9 = newTemp(Ity_I64);
|
|
t10 = newTemp(Ity_I1);
|
|
t11 = newTemp(Ity_I1);
|
|
t12 = newTemp(Ity_I1);
|
|
t13 = newTemp(Ity_I1);
|
|
t14 = newTemp(Ity_I32);
|
|
t15 = newTemp(Ity_I64);
|
|
t16 = newTemp(Ity_I1);
|
|
|
|
assign(t0, getAcc(ac));
|
|
assign(t16, binop(Iop_CmpEQ32,
|
|
mkU32(rs),
|
|
mkU32(0)));
|
|
assign(t1, IRExpr_ITE(mkexpr(t16),
|
|
mkexpr(t0),
|
|
binop(Iop_Sar64,
|
|
mkexpr(t0),
|
|
mkU8(rs))));
|
|
/* 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 significant bit of the shifted value
|
|
from acc. */
|
|
assign(t15, binop(Iop_Shr64,
|
|
mkexpr(t0),
|
|
unop(Iop_32to8,
|
|
binop(Iop_Sub32,
|
|
binop(Iop_And32,
|
|
mkU32(rs),
|
|
mkU32(0x1f)),
|
|
mkU32(1)))));
|
|
|
|
assign(t8,
|
|
IRExpr_ITE(mkexpr(t16),
|
|
mkU64(0x0ULL),
|
|
binop(Iop_And64,
|
|
mkexpr(t15),
|
|
mkU64(0x0000000000000001ULL))));
|
|
assign(t9, binop(Iop_Add64, mkexpr(t1), mkexpr(t8)));
|
|
putIReg(rt, unop(Iop_64to32, mkexpr(t9)));
|
|
|
|
/* Check if bits 63..31 of the result in t1 aren't 0. */
|
|
assign(t3, binop(Iop_CmpNE32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t1)),
|
|
mkU32(0)));
|
|
assign(t4, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
unop(Iop_64to32,
|
|
mkexpr(t1)),
|
|
mkU32(0x80000000)),
|
|
mkU32(0)));
|
|
|
|
/* Check if bits 63..31 of the result in t1 aren't
|
|
0x1ffffffff. */
|
|
assign(t5, binop(Iop_CmpNE32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t1)),
|
|
mkU32(0xffffffff)));
|
|
assign(t6, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
unop(Iop_64to32,
|
|
mkexpr(t1)),
|
|
mkU32(0x80000000)),
|
|
mkU32(0x80000000)));
|
|
/* If bits 63..31 aren't 0 nor 0x1ffffffff, set DSP
|
|
control register. */
|
|
assign(t7, binop(Iop_And32,
|
|
binop(Iop_Or32,
|
|
unop(Iop_1Sto32, mkexpr(t3)),
|
|
unop(Iop_1Sto32, mkexpr(t4))),
|
|
binop(Iop_Or32,
|
|
unop(Iop_1Sto32, mkexpr(t5)),
|
|
unop(Iop_1Sto32, mkexpr(t6)))));
|
|
putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
|
|
mkexpr(t7),
|
|
mkU32(0)),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
mkU32(0x00800000)),
|
|
getDSPControl()));
|
|
|
|
/* Repeat previous steps for the rounded value. */
|
|
assign(t10, binop(Iop_CmpNE32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t9)),
|
|
mkU32(0)));
|
|
assign(t11, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
unop(Iop_64to32,
|
|
mkexpr(t9)),
|
|
mkU32(0x80000000)),
|
|
mkU32(0)));
|
|
|
|
assign(t12, binop(Iop_CmpNE32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t9)),
|
|
mkU32(0xffffffff)));
|
|
assign(t13, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
unop(Iop_64to32,
|
|
mkexpr(t9)),
|
|
mkU32(0x80000000)),
|
|
mkU32(0x80000000)));
|
|
|
|
assign(t14, binop(Iop_And32,
|
|
binop(Iop_Or32,
|
|
unop(Iop_1Sto32, mkexpr(t10)),
|
|
unop(Iop_1Sto32, mkexpr(t11))),
|
|
binop(Iop_Or32,
|
|
unop(Iop_1Sto32, mkexpr(t12)),
|
|
unop(Iop_1Sto32, mkexpr(t13)))));
|
|
putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
|
|
mkexpr(t14),
|
|
mkU32(0)),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
mkU32(0x00800000)),
|
|
getDSPControl()));
|
|
break;
|
|
}
|
|
case 0x5: { /* EXTRV_R.W */
|
|
DIP("extrv_r.w r%u, ac%u, r%u", rt, ac, rs);
|
|
vassert(!mode64);
|
|
t0 = newTemp(Ity_I64);
|
|
t1 = newTemp(Ity_I64);
|
|
t2 = newTemp(Ity_I32);
|
|
t3 = newTemp(Ity_I1);
|
|
t4 = newTemp(Ity_I1);
|
|
t5 = newTemp(Ity_I1);
|
|
t6 = newTemp(Ity_I1);
|
|
t7 = newTemp(Ity_I32);
|
|
t8 = newTemp(Ity_I64);
|
|
t9 = newTemp(Ity_I64);
|
|
t10 = newTemp(Ity_I1);
|
|
t11 = newTemp(Ity_I1);
|
|
t12 = newTemp(Ity_I1);
|
|
t13 = newTemp(Ity_I1);
|
|
t14 = newTemp(Ity_I32);
|
|
t15 = newTemp(Ity_I8);
|
|
|
|
assign(t15, unop(Iop_32to8,
|
|
binop(Iop_And32,
|
|
getIReg(rs),
|
|
mkU32(0x1f))));
|
|
assign(t0, getAcc(ac));
|
|
assign(t1, binop(Iop_Sar64, mkexpr(t0), mkexpr(t15)));
|
|
|
|
/* Check if bits 63..31 of the result in t1 aren't 0. */
|
|
assign(t3, binop(Iop_CmpNE32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t1)),
|
|
mkU32(0)));
|
|
assign(t4, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
unop(Iop_64to32,
|
|
mkexpr(t1)),
|
|
mkU32(0x80000000)),
|
|
mkU32(0)));
|
|
/* Check if bits 63..31 of the result in t1 aren't
|
|
0x1ffffffff. */
|
|
assign(t5, binop(Iop_CmpNE32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t1)),
|
|
mkU32(0xffffffff)));
|
|
assign(t6, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
unop(Iop_64to32,
|
|
mkexpr(t1)),
|
|
mkU32(0x80000000)),
|
|
mkU32(0x80000000)));
|
|
/* If bits 63..31 aren't 0 nor 0x1ffffffff, set DSP
|
|
control register. */
|
|
assign(t7, binop(Iop_And32,
|
|
binop(Iop_Or32,
|
|
unop(Iop_1Sto32, mkexpr(t3)),
|
|
unop(Iop_1Sto32, mkexpr(t4))),
|
|
binop(Iop_Or32,
|
|
unop(Iop_1Sto32, mkexpr(t5)),
|
|
unop(Iop_1Sto32, mkexpr(t6)))));
|
|
putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
|
|
mkexpr(t7),
|
|
mkU32(0)),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
mkU32(0x00800000)),
|
|
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(t8,
|
|
IRExpr_ITE(binop(Iop_CmpEQ32,
|
|
unop(Iop_8Uto32,
|
|
mkexpr(t15)),
|
|
mkU32(0)),
|
|
mkU64(0x0ULL),
|
|
binop(Iop_And64,
|
|
binop(Iop_Shr64,
|
|
mkexpr(t0),
|
|
unop(Iop_32to8,
|
|
binop(Iop_Sub32,
|
|
unop(Iop_8Uto32,
|
|
mkexpr(t15)),
|
|
mkU32(1)))),
|
|
mkU64(0x1ULL))));
|
|
|
|
assign(t9, binop(Iop_Add64, mkexpr(t1), mkexpr(t8)));
|
|
/* Put rounded value in destination register. */
|
|
putIReg(rt, unop(Iop_64to32, mkexpr(t9)));
|
|
|
|
/* Repeat previous steps for the rounded value. */
|
|
assign(t10, binop(Iop_CmpNE32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t9)),
|
|
mkU32(0)));
|
|
assign(t11, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
unop(Iop_64to32,
|
|
mkexpr(t9)),
|
|
mkU32(0x80000000)),
|
|
mkU32(0)));
|
|
|
|
assign(t12, binop(Iop_CmpNE32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t9)),
|
|
mkU32(0xffffffff)));
|
|
assign(t13, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
unop(Iop_64to32,
|
|
mkexpr(t9)),
|
|
mkU32(0x80000000)),
|
|
mkU32(0x80000000)));
|
|
|
|
assign(t14, binop(Iop_And32,
|
|
binop(Iop_Or32,
|
|
unop(Iop_1Sto32, mkexpr(t10)),
|
|
unop(Iop_1Sto32, mkexpr(t11))),
|
|
binop(Iop_Or32,
|
|
unop(Iop_1Sto32, mkexpr(t12)),
|
|
unop(Iop_1Sto32, mkexpr(t13)))));
|
|
putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
|
|
mkexpr(t14),
|
|
mkU32(0)),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
mkU32(0x00800000)),
|
|
getDSPControl()));
|
|
break;
|
|
}
|
|
case 0x6: { /* EXTR_RS.W */
|
|
DIP("extr_rs.w r%u, ac%u, %u", rt, ac, rs);
|
|
vassert(!mode64);
|
|
t0 = newTemp(Ity_I64);
|
|
t1 = newTemp(Ity_I64);
|
|
t2 = newTemp(Ity_I32);
|
|
t3 = newTemp(Ity_I1);
|
|
t4 = newTemp(Ity_I1);
|
|
t5 = newTemp(Ity_I1);
|
|
t6 = newTemp(Ity_I1);
|
|
t7 = newTemp(Ity_I32);
|
|
t8 = newTemp(Ity_I64);
|
|
t9 = newTemp(Ity_I64);
|
|
t10 = newTemp(Ity_I1);
|
|
t11 = newTemp(Ity_I1);
|
|
t12 = newTemp(Ity_I1);
|
|
t13 = newTemp(Ity_I1);
|
|
t14 = newTemp(Ity_I32);
|
|
t16 = newTemp(Ity_I32);
|
|
|
|
assign(t0, getAcc(ac));
|
|
if (0 == rs) {
|
|
assign(t1, mkexpr(t0));
|
|
} else {
|
|
assign(t1, binop(Iop_Sar64, mkexpr(t0), mkU8(rs)));
|
|
}
|
|
|
|
/* Check if bits 63..31 of the result in t1 aren't 0. */
|
|
assign(t3, binop(Iop_CmpNE32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t1)),
|
|
mkU32(0)));
|
|
assign(t4, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
unop(Iop_64to32,
|
|
mkexpr(t1)),
|
|
mkU32(0x80000000)),
|
|
mkU32(0)));
|
|
/* Check if bits 63..31 of the result in t1 aren't
|
|
0x1ffffffff. */
|
|
assign(t5, binop(Iop_CmpNE32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t1)),
|
|
mkU32(0xffffffff)));
|
|
assign(t6, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
unop(Iop_64to32,
|
|
mkexpr(t1)),
|
|
mkU32(0x80000000)),
|
|
mkU32(0x80000000)));
|
|
/* If bits 63..31 aren't 0 nor 0x1ffffffff, set DSP
|
|
control register. */
|
|
assign(t7, binop(Iop_And32,
|
|
binop(Iop_Or32,
|
|
unop(Iop_1Sto32, mkexpr(t3)),
|
|
unop(Iop_1Sto32, mkexpr(t4))),
|
|
binop(Iop_Or32,
|
|
unop(Iop_1Sto32, mkexpr(t5)),
|
|
unop(Iop_1Sto32, mkexpr(t6)))));
|
|
putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
|
|
mkexpr(t7),
|
|
mkU32(0)),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
mkU32(0x00800000)),
|
|
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. */
|
|
if (0 == rs) {
|
|
assign(t8, mkU64(0x0ULL));
|
|
} else {
|
|
assign(t8, binop(Iop_And64,
|
|
binop(Iop_Shr64,
|
|
mkexpr(t0),
|
|
mkU8(rs-1)),
|
|
mkU64(0x1ULL)));
|
|
}
|
|
|
|
assign(t9, binop(Iop_Add64, mkexpr(t1), mkexpr(t8)));
|
|
|
|
/* Repeat previous steps for the rounded value. */
|
|
assign(t10, binop(Iop_CmpNE32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t9)),
|
|
mkU32(0)));
|
|
assign(t11, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
unop(Iop_64to32,
|
|
mkexpr(t9)),
|
|
mkU32(0x80000000)),
|
|
mkU32(0)));
|
|
|
|
assign(t12, binop(Iop_CmpNE32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t9)),
|
|
mkU32(0xffffffff)));
|
|
assign(t13, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
unop(Iop_64to32,
|
|
mkexpr(t9)),
|
|
mkU32(0x80000000)),
|
|
mkU32(0x80000000)));
|
|
|
|
assign(t14, binop(Iop_And32,
|
|
binop(Iop_Or32,
|
|
unop(Iop_1Sto32, mkexpr(t10)),
|
|
unop(Iop_1Sto32, mkexpr(t11))),
|
|
binop(Iop_Or32,
|
|
unop(Iop_1Sto32, mkexpr(t12)),
|
|
unop(Iop_1Sto32, mkexpr(t13)))));
|
|
putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
|
|
mkexpr(t14),
|
|
mkU32(0)),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
mkU32(0x00800000)),
|
|
getDSPControl()));
|
|
|
|
assign(t16, binop(Iop_And32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t9)),
|
|
mkU32(0x80000000)));
|
|
putIReg(rt, IRExpr_ITE(binop(Iop_CmpNE32,
|
|
mkexpr(t14),
|
|
mkU32(0)),
|
|
IRExpr_ITE(binop(Iop_CmpEQ32,
|
|
mkexpr(t16),
|
|
mkU32(0)),
|
|
mkU32(0x7fffffff),
|
|
mkU32(0x80000000)),
|
|
unop(Iop_64to32, mkexpr(t9))));
|
|
break;
|
|
}
|
|
case 0x7: { /* EXTRV_RS.W */
|
|
DIP("extrv_rs.w r%u, ac%u, r%u", rt, ac, rs);
|
|
vassert(!mode64);
|
|
t0 = newTemp(Ity_I64);
|
|
t1 = newTemp(Ity_I64);
|
|
t2 = newTemp(Ity_I32);
|
|
t3 = newTemp(Ity_I1);
|
|
t4 = newTemp(Ity_I1);
|
|
t5 = newTemp(Ity_I1);
|
|
t6 = newTemp(Ity_I1);
|
|
t7 = newTemp(Ity_I32);
|
|
t8 = newTemp(Ity_I64);
|
|
t9 = newTemp(Ity_I64);
|
|
t10 = newTemp(Ity_I1);
|
|
t11 = newTemp(Ity_I1);
|
|
t12 = newTemp(Ity_I1);
|
|
t13 = newTemp(Ity_I1);
|
|
t14 = newTemp(Ity_I32);
|
|
t15 = newTemp(Ity_I32);
|
|
t16 = newTemp(Ity_I32);
|
|
t17 = newTemp(Ity_I1);
|
|
|
|
assign(t15, binop(Iop_And32,
|
|
getIReg(rs),
|
|
mkU32(0x1f)));
|
|
assign(t17, binop(Iop_CmpEQ32,
|
|
mkexpr(t15),
|
|
mkU32(0)));
|
|
assign(t0, getAcc(ac));
|
|
assign(t1, IRExpr_ITE(mkexpr(t17),
|
|
mkexpr(t0),
|
|
binop(Iop_Sar64,
|
|
mkexpr(t0),
|
|
unop(Iop_32to8,
|
|
mkexpr(t15)))));
|
|
|
|
/* Check if bits 63..31 of the result in t1 aren't 0. */
|
|
assign(t3, binop(Iop_CmpNE32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t1)),
|
|
mkU32(0)));
|
|
assign(t4, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
unop(Iop_64to32,
|
|
mkexpr(t1)),
|
|
mkU32(0x80000000)),
|
|
mkU32(0)));
|
|
/* Check if bits 63..31 of the result in t1 aren't
|
|
0x1ffffffff. */
|
|
assign(t5, binop(Iop_CmpNE32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t1)),
|
|
mkU32(0xffffffff)));
|
|
assign(t6, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
unop(Iop_64to32,
|
|
mkexpr(t1)),
|
|
mkU32(0x80000000)),
|
|
mkU32(0x80000000)));
|
|
/* If bits 63..31 aren't 0 nor 0x1ffffffff, set DSP
|
|
control register. */
|
|
assign(t7, binop(Iop_And32,
|
|
binop(Iop_Or32,
|
|
unop(Iop_1Sto32, mkexpr(t3)),
|
|
unop(Iop_1Sto32, mkexpr(t4))),
|
|
binop(Iop_Or32,
|
|
unop(Iop_1Sto32, mkexpr(t5)),
|
|
unop(Iop_1Sto32, mkexpr(t6)))));
|
|
putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
|
|
mkexpr(t7),
|
|
mkU32(0)),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
mkU32(0x00800000)),
|
|
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(t8,
|
|
IRExpr_ITE(mkexpr(t17),
|
|
mkU64(0x0ULL),
|
|
binop(Iop_And64,
|
|
binop(Iop_Shr64,
|
|
mkexpr(t0),
|
|
unop(Iop_32to8,
|
|
binop(Iop_Sub32,
|
|
mkexpr(t15),
|
|
mkU32(1)))),
|
|
mkU64(0x1ULL))));
|
|
|
|
assign(t9, binop(Iop_Add64, mkexpr(t1), mkexpr(t8)));
|
|
|
|
/* Repeat previous steps for the rounded value. */
|
|
assign(t10, binop(Iop_CmpNE32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t9)),
|
|
mkU32(0)));
|
|
assign(t11, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
unop(Iop_64to32,
|
|
mkexpr(t9)),
|
|
mkU32(0x80000000)),
|
|
mkU32(0)));
|
|
|
|
assign(t12, binop(Iop_CmpNE32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t9)),
|
|
mkU32(0xffffffff)));
|
|
assign(t13, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
unop(Iop_64to32,
|
|
mkexpr(t9)),
|
|
mkU32(0x80000000)),
|
|
mkU32(0x80000000)));
|
|
|
|
assign(t14, binop(Iop_And32,
|
|
binop(Iop_Or32,
|
|
unop(Iop_1Sto32, mkexpr(t10)),
|
|
unop(Iop_1Sto32, mkexpr(t11))),
|
|
binop(Iop_Or32,
|
|
unop(Iop_1Sto32, mkexpr(t12)),
|
|
unop(Iop_1Sto32, mkexpr(t13)))));
|
|
putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
|
|
mkexpr(t14),
|
|
mkU32(0)),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
mkU32(0x00800000)),
|
|
getDSPControl()));
|
|
|
|
assign(t16, binop(Iop_And32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t9)),
|
|
mkU32(0x80000000)));
|
|
putIReg(rt, IRExpr_ITE(binop(Iop_CmpNE32,
|
|
mkexpr(t14),
|
|
mkU32(0)),
|
|
IRExpr_ITE(binop(Iop_CmpEQ32,
|
|
mkexpr(t16),
|
|
mkU32(0)),
|
|
mkU32(0x7fffffff),
|
|
mkU32(0x80000000)),
|
|
unop(Iop_64to32, mkexpr(t9))));
|
|
break;
|
|
}
|
|
case 0xA: { /* EXTPDP */
|
|
DIP("extpdp r%u, ac%u, %u", 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%u, ac%u, r%u", 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%u, ac%u, %u", 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);
|
|
t9 = newTemp(Ity_I32);
|
|
|
|
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_And32,
|
|
unop(Iop_64to32,
|
|
mkexpr(t1)),
|
|
mkU32(0x80000000)));
|
|
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_And32,
|
|
binop(Iop_Or32,
|
|
unop(Iop_1Sto32,
|
|
binop(Iop_CmpNE32,
|
|
mkU32(0),
|
|
binop(Iop_And32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t3)),
|
|
mkU32(0x7fffffff)))),
|
|
unop(Iop_1Sto32,
|
|
binop(Iop_CmpNE32,
|
|
mkU32(0),
|
|
unop(Iop_64to32,
|
|
mkexpr(t3))))),
|
|
unop(Iop_1Sto32,
|
|
binop(Iop_CmpEQ32,
|
|
binop(Iop_And32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t3)),
|
|
mkU32(0x80000000)),
|
|
mkU32(0)))));
|
|
putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
|
|
mkU32(0),
|
|
mkexpr(t4)),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
mkU32(0x00800000)),
|
|
getDSPControl()));
|
|
/* Check if t1<0xffffffffffff8000 (0xffffffffffff8000-t1)>0
|
|
1. subtract t1 from 0xffffffffffff8000
|
|
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_And32,
|
|
binop(Iop_Or32,
|
|
unop(Iop_1Sto32,
|
|
binop(Iop_CmpNE32,
|
|
mkU32(0),
|
|
binop(Iop_And32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t6)),
|
|
mkU32(0x7fffffff)))),
|
|
unop(Iop_1Sto32,
|
|
binop(Iop_CmpNE32,
|
|
mkU32(0),
|
|
unop(Iop_64to32,
|
|
mkexpr(t6))))),
|
|
unop(Iop_1Sto32,
|
|
binop(Iop_CmpEQ32,
|
|
binop(Iop_And32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t6)),
|
|
mkU32(0x80000000)),
|
|
mkU32(0)))));
|
|
putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
|
|
mkU32(0),
|
|
mkexpr(t7)),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
mkU32(0x00800000)),
|
|
getDSPControl()));
|
|
putIReg(rt, IRExpr_ITE(binop(Iop_CmpNE32,
|
|
mkU32(0),
|
|
mkexpr(t4)),
|
|
mkU32(0x00007fff),
|
|
IRExpr_ITE(binop(Iop_CmpNE32,
|
|
mkU32(0),
|
|
mkexpr(t7)),
|
|
mkU32(0xffff8000),
|
|
unop(Iop_64to32,
|
|
mkexpr(t1)))));
|
|
break;
|
|
}
|
|
case 0xF: { /* EXTRV_S.H */
|
|
DIP("extrv_s.h r%u, ac%u, %u", 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);
|
|
t9 = 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_And32,
|
|
unop(Iop_64to32,
|
|
mkexpr(t1)),
|
|
mkU32(0x80000000)));
|
|
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_And32,
|
|
binop(Iop_Or32,
|
|
unop(Iop_1Sto32,
|
|
binop(Iop_CmpNE32,
|
|
mkU32(0),
|
|
binop(Iop_And32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t3)),
|
|
mkU32(0x7fffffff)))),
|
|
unop(Iop_1Sto32,
|
|
binop(Iop_CmpNE32,
|
|
mkU32(0),
|
|
unop(Iop_64to32,
|
|
mkexpr(t3))))),
|
|
unop(Iop_1Sto32,
|
|
binop(Iop_CmpEQ32,
|
|
binop(Iop_And32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t3)),
|
|
mkU32(0x80000000)),
|
|
mkU32(0)))));
|
|
putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
|
|
mkU32(0),
|
|
mkexpr(t4)),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
mkU32(0x00800000)),
|
|
getDSPControl()));
|
|
/* Check if t1<0xffffffffffff8000 (0xffffffffffff8000-t1)>0
|
|
1. subtract t1 from 0xffffffffffff8000
|
|
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_And32,
|
|
binop(Iop_Or32,
|
|
unop(Iop_1Sto32,
|
|
binop(Iop_CmpNE32,
|
|
mkU32(0),
|
|
binop(Iop_And32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t6)),
|
|
mkU32(0x7fffffff)))),
|
|
unop(Iop_1Sto32,
|
|
binop(Iop_CmpNE32,
|
|
mkU32(0),
|
|
unop(Iop_64to32,
|
|
mkexpr(t6))))),
|
|
unop(Iop_1Sto32,
|
|
binop(Iop_CmpEQ32,
|
|
binop(Iop_And32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t6)),
|
|
mkU32(0x80000000)),
|
|
mkU32(0)))));
|
|
putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
|
|
mkU32(0),
|
|
mkexpr(t7)),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
mkU32(0x00800000)),
|
|
getDSPControl()));
|
|
putIReg(rt, IRExpr_ITE(binop(Iop_CmpNE32,
|
|
mkU32(0),
|
|
mkexpr(t4)),
|
|
mkU32(0x00007fff),
|
|
IRExpr_ITE(binop(Iop_CmpNE32,
|
|
mkU32(0),
|
|
mkexpr(t7)),
|
|
mkU32(0xffff8000),
|
|
unop(Iop_64to32,
|
|
mkexpr(t1)))));
|
|
break;
|
|
}
|
|
case 0x12: { /* RDDSP*/
|
|
DIP("rddsp r%u, mask 0x%x", rd, rddsp_mask);
|
|
vassert(!mode64);
|
|
|
|
putIReg(rd, mkU32(0x0));
|
|
|
|
if ((rddsp_mask & 0x1) == 0x1) {
|
|
/* 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 & 0x2) == 0x2) {
|
|
/* 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 & 0x4) == 0x4) {
|
|
/* Read C field (bit 13) of DSPControl register. */
|
|
putIReg(rd, binop(Iop_Or32,
|
|
getIReg(rd),
|
|
binop(Iop_And32,
|
|
getDSPControl(),
|
|
mkU32(0x00002000))));
|
|
}
|
|
|
|
if ((rddsp_mask & 0x8) == 0x8) {
|
|
/* 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 & 0x10) == 0x10) {
|
|
/* 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 & 0x20) == 0x20) {
|
|
/* Read EFI field (bit 14) of DSPControl register. */
|
|
putIReg(rd, binop(Iop_Or32,
|
|
getIReg(rd),
|
|
binop(Iop_And32,
|
|
getDSPControl(),
|
|
mkU32(0x00004000))));
|
|
}
|
|
|
|
if ((rddsp_mask & 0x3f) == 0x3f) {
|
|
/* Read all fields of DSPControl register. */
|
|
putIReg(rd, getDSPControl());
|
|
}
|
|
break;
|
|
}
|
|
case 0x13: { /* WRDSP */
|
|
DIP("wrdsp r%u, mask 0x%x", rs, wrdsp_mask);
|
|
vassert(!mode64);
|
|
|
|
if ((wrdsp_mask & 0x3f) == 0x3f) {
|
|
/* 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 & 0x1) == 0x1) {
|
|
/* 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 & 0x2) == 0x2) {
|
|
/* 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 & 0x4) == 0x4) {
|
|
/* 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 & 0x8) == 0x8) {
|
|
/* 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 & 0x10) == 0x10) {
|
|
/* 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 & 0x20) == 0x20) {
|
|
/* 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%u, %u", ac, shift);
|
|
vassert(!mode64);
|
|
t0 = newTemp(Ity_I64);
|
|
t1 = newTemp(Ity_I64);
|
|
|
|
assign(t0, getAcc(ac));
|
|
|
|
putAcc(ac, mkexpr(t0));
|
|
|
|
if (0x20 == (shift & 0x3f)) {
|
|
putAcc(ac, binop(Iop_32HLto64,
|
|
unop(Iop_64to32, mkexpr(t0)),
|
|
mkU32(0x0)));
|
|
} else if (0x20 == (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%u, r%u", ac, rs);
|
|
vassert(!mode64);
|
|
t0 = newTemp(Ity_I64);
|
|
t1 = newTemp(Ity_I32);
|
|
t2 = newTemp(Ity_I1);
|
|
t3 = newTemp(Ity_I64);
|
|
t4 = newTemp(Ity_I64);
|
|
|
|
assign(t0, getAcc(ac));
|
|
assign(t1, binop(Iop_And32, getIReg(rs), mkU32(0x3f)));
|
|
assign(t2, binop(Iop_CmpEQ32, mkexpr(t1), mkU32(0x20)));
|
|
assign(t3, binop(Iop_Shl64,
|
|
mkexpr(t0),
|
|
unop(Iop_32to8,
|
|
binop(Iop_Add32,
|
|
unop(Iop_Not32,
|
|
mkexpr(t1)),
|
|
mkU32(0x1)))));
|
|
assign(t4, binop(Iop_Shr64,
|
|
mkexpr(t0),
|
|
unop(Iop_32to8,
|
|
mkexpr(t1))));
|
|
|
|
putAcc(ac,
|
|
IRExpr_ITE(mkexpr(t2),
|
|
binop(Iop_32HLto64,
|
|
unop(Iop_64to32, mkexpr(t0)),
|
|
mkU32(0x0)),
|
|
IRExpr_ITE(binop(Iop_CmpEQ32,
|
|
binop(Iop_And32,
|
|
mkexpr(t1),
|
|
mkU32(0x20)),
|
|
mkU32(0x20)),
|
|
mkexpr(t3),
|
|
mkexpr(t4))));
|
|
break;
|
|
}
|
|
case 0x1F: { /* MTHLIP */
|
|
DIP("mthlip r%u, ac%u", 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%u, r%u(r%u)", 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%u, r%u(r%u)", 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%u, r%u(r%u)", 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%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u r%u, r%u", 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%u r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u", 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%u, r%u", 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%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u", 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%u, r%u", 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%u, r%u", 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%u, r%u, r%u", 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%u, r%u, %u", 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%u, r%u, r%u", 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%u, r%u, %u", 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%u, r%u, %u", 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%u, r%u, %u", 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%u, r%u, %u", 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%u, r%u, %u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, %u", rd, rt, rs);
|
|
vassert(!mode64);
|
|
t0 = newTemp(Ity_I32);
|
|
t1 = newTemp(Ity_I1);
|
|
t2 = newTemp(Ity_I1);
|
|
t3 = newTemp(Ity_I32);
|
|
t4 = newTemp(Ity_I1);
|
|
t5 = newTemp(Ity_I1);
|
|
t6 = newTemp(Ity_I32);
|
|
t7 = newTemp(Ity_I1);
|
|
t8 = newTemp(Ity_I1);
|
|
t9 = newTemp(Ity_I1);
|
|
t10 = newTemp(Ity_I1);
|
|
|
|
if (0 == rs) {
|
|
putIReg(rd, getIReg(rt));
|
|
} else {
|
|
/* Shift bits 7..0 and 23..16. */
|
|
assign(t0, binop(Iop_Shl32,
|
|
binop(Iop_And32,
|
|
getIReg(rt),
|
|
mkU32(0x00ff00ff)),
|
|
mkU8(rs)));
|
|
assign(t1, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
mkexpr(t0),
|
|
mkU32(0xff000000)),
|
|
mkU32(0x00000000)));
|
|
assign(t2, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
mkexpr(t0),
|
|
mkU32(0xff000000)),
|
|
mkU32(0xff000000)));
|
|
assign(t7, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
mkexpr(t0),
|
|
mkU32(0x0000ff00)),
|
|
mkU32(0x00000000)));
|
|
assign(t8, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
mkexpr(t0),
|
|
mkU32(0x0000ff00)),
|
|
mkU32(0x000ff00)));
|
|
/* Shift bits 15..8 and 31..24. */
|
|
assign(t3, binop(Iop_Shl32,
|
|
binop(Iop_Shr32,
|
|
binop(Iop_And32,
|
|
getIReg(rt),
|
|
mkU32(0xff00ff00)),
|
|
mkU8(8)),
|
|
mkU8(rs)));
|
|
assign(t4, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
mkexpr(t3),
|
|
mkU32(0xff000000)),
|
|
mkU32(0x00000000)));
|
|
assign(t5, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
mkexpr(t3),
|
|
mkU32(0xff000000)),
|
|
mkU32(0xff000000)));
|
|
assign(t9, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
mkexpr(t3),
|
|
mkU32(0x0000ff00)),
|
|
mkU32(0x00000000)));
|
|
assign(t10, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
mkexpr(t3),
|
|
mkU32(0x0000ff00)),
|
|
mkU32(0x0000ff00)));
|
|
|
|
assign(t6, binop(Iop_Or32,
|
|
binop(Iop_Or32,
|
|
binop(Iop_And32,
|
|
unop(Iop_1Uto32,
|
|
mkexpr(t1)),
|
|
unop(Iop_1Uto32,
|
|
mkexpr(t2))),
|
|
binop(Iop_And32,
|
|
unop(Iop_1Uto32,
|
|
mkexpr(t7)),
|
|
unop(Iop_1Uto32,
|
|
mkexpr(t8)))),
|
|
binop(Iop_Or32,
|
|
binop(Iop_And32,
|
|
unop(Iop_1Uto32,
|
|
mkexpr(t4)),
|
|
unop(Iop_1Uto32,
|
|
mkexpr(t5))),
|
|
binop(Iop_And32,
|
|
unop(Iop_1Uto32,
|
|
mkexpr(t9)),
|
|
unop(Iop_1Uto32,
|
|
mkexpr(t10))))));
|
|
|
|
putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
|
|
mkexpr(t6),
|
|
mkU32(0x0)),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
mkU32(0x400000)),
|
|
getDSPControl()));
|
|
putIReg(rd, binop(Iop_Or32,
|
|
binop(Iop_Shl32,
|
|
binop(Iop_And32,
|
|
mkexpr(t3),
|
|
mkU32(0x00ff00ff)),
|
|
mkU8(8)),
|
|
binop(Iop_And32,
|
|
mkexpr(t0),
|
|
mkU32(0x00ff00ff))));
|
|
}
|
|
break;
|
|
}
|
|
case 0x3: { /* SHRL.QB */
|
|
DIP("shrl.qb r%u, r%u, %u", 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%u, r%u, r%u", rd, rt, rs);
|
|
vassert(!mode64);
|
|
t0 = newTemp(Ity_I32);
|
|
t1 = newTemp(Ity_I1);
|
|
t2 = newTemp(Ity_I1);
|
|
t3 = newTemp(Ity_I32);
|
|
t4 = newTemp(Ity_I1);
|
|
t5 = newTemp(Ity_I1);
|
|
t6 = newTemp(Ity_I32);
|
|
t7 = newTemp(Ity_I1);
|
|
t8 = newTemp(Ity_I1);
|
|
t9 = newTemp(Ity_I1);
|
|
t10 = newTemp(Ity_I1);
|
|
t11 = newTemp(Ity_I8);
|
|
|
|
assign(t11, unop(Iop_32to8,
|
|
binop(Iop_And32,
|
|
getIReg(rs),
|
|
mkU32(0x7))));
|
|
/* Shift bits 7..0 and 23..16. */
|
|
assign(t0, binop(Iop_Shl32,
|
|
binop(Iop_And32,
|
|
getIReg(rt),
|
|
mkU32(0x00ff00ff)),
|
|
mkexpr(t11)));
|
|
assign(t1, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
mkexpr(t0),
|
|
mkU32(0xff000000)),
|
|
mkU32(0x00000000)));
|
|
assign(t2, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
mkexpr(t0),
|
|
mkU32(0xff000000)),
|
|
mkU32(0xff000000)));
|
|
assign(t7, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
mkexpr(t0),
|
|
mkU32(0x0000ff00)),
|
|
mkU32(0x00000000)));
|
|
assign(t8, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
mkexpr(t0),
|
|
mkU32(0x0000ff00)),
|
|
mkU32(0x000ff00)));
|
|
/* Shift bits 15..8 and 31..24. */
|
|
assign(t3, binop(Iop_Shl32,
|
|
binop(Iop_Shr32,
|
|
binop(Iop_And32,
|
|
getIReg(rt),
|
|
mkU32(0xff00ff00)),
|
|
mkU8(8)),
|
|
mkexpr(t11)));
|
|
assign(t4, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
mkexpr(t3),
|
|
mkU32(0xff000000)),
|
|
mkU32(0x00000000)));
|
|
assign(t5, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
mkexpr(t3),
|
|
mkU32(0xff000000)),
|
|
mkU32(0xff000000)));
|
|
assign(t9, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
mkexpr(t3),
|
|
mkU32(0x0000ff00)),
|
|
mkU32(0x00000000)));
|
|
assign(t10, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
mkexpr(t3),
|
|
mkU32(0x0000ff00)),
|
|
mkU32(0x0000ff00)));
|
|
|
|
assign(t6, binop(Iop_Or32,
|
|
binop(Iop_Or32,
|
|
binop(Iop_And32,
|
|
unop(Iop_1Uto32,
|
|
mkexpr(t1)),
|
|
unop(Iop_1Uto32,
|
|
mkexpr(t2))),
|
|
binop(Iop_And32,
|
|
unop(Iop_1Uto32,
|
|
mkexpr(t7)),
|
|
unop(Iop_1Uto32,
|
|
mkexpr(t8)))),
|
|
binop(Iop_Or32,
|
|
binop(Iop_And32,
|
|
unop(Iop_1Uto32,
|
|
mkexpr(t4)),
|
|
unop(Iop_1Uto32,
|
|
mkexpr(t5))),
|
|
binop(Iop_And32,
|
|
unop(Iop_1Uto32,
|
|
mkexpr(t9)),
|
|
unop(Iop_1Uto32,
|
|
mkexpr(t10))))));
|
|
|
|
putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
|
|
mkexpr(t6),
|
|
mkU32(0x0)),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
mkU32(0x400000)),
|
|
getDSPControl()));
|
|
putIReg(rd, IRExpr_ITE(binop(Iop_CmpEQ32,
|
|
unop(Iop_8Uto32, mkexpr(t11)),
|
|
mkU32(0)),
|
|
getIReg(rt),
|
|
binop(Iop_Or32,
|
|
binop(Iop_Shl32,
|
|
binop(Iop_And32,
|
|
mkexpr(t3),
|
|
mkU32(0xff00ff)),
|
|
mkU8(8)),
|
|
binop(Iop_And32,
|
|
mkexpr(t0),
|
|
mkU32(0x00ff00ff)))));
|
|
break;
|
|
}
|
|
case 0x1: { /* SHRLV.QB */
|
|
DIP("shrlv.qb r%u, r%u, r%u", 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%u, r%u, %u", 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%u, r%u, %u", 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%u, r%u, %u", 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%u, r%u, r%u", 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%u, r%u, %u", 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);
|
|
|
|
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, unop(Iop_1Uto32,
|
|
binop(Iop_CmpNE32,
|
|
binop(Iop_Sar32,
|
|
mkexpr(t0),
|
|
mkU8(16)),
|
|
mkU32(0))));
|
|
assign(t2, unop(Iop_1Uto32,
|
|
binop(Iop_CmpNE32,
|
|
binop(Iop_Sar32,
|
|
mkexpr(t0),
|
|
mkU8(16)),
|
|
mkU32(0xffffffff))));
|
|
assign(t3, binop(Iop_And32,
|
|
mkexpr(t1),
|
|
mkexpr(t2)));
|
|
putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32,
|
|
mkexpr(t3),
|
|
mkU32(0x1)),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
mkU32(0x400000)),
|
|
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, unop(Iop_1Uto32,
|
|
binop(Iop_CmpNE32,
|
|
binop(Iop_Sar32,
|
|
mkexpr(t4),
|
|
mkU8(16)),
|
|
mkU32(0))));
|
|
assign(t6, unop(Iop_1Uto32,
|
|
binop(Iop_CmpNE32,
|
|
binop(Iop_Sar32,
|
|
mkexpr(t4),
|
|
mkU8(16)),
|
|
mkU32(0xffffffff))));
|
|
assign(t7, binop(Iop_And32,
|
|
mkexpr(t5),
|
|
mkexpr(t6)));
|
|
putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32,
|
|
mkexpr(t7),
|
|
mkU32(0x1)),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
mkU32(0x400000)),
|
|
getDSPControl()));
|
|
putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32,
|
|
mkexpr(t7),
|
|
mkU32(0x1)),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
mkU32(0x400000)),
|
|
getDSPControl()));
|
|
putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32,
|
|
binop(Iop_And32,
|
|
getIReg(rt),
|
|
mkU32(0x80000000)),
|
|
binop(Iop_Shl32,
|
|
binop(Iop_And32,
|
|
mkexpr(t4),
|
|
mkU32(0x00008000)),
|
|
mkU8(16))
|
|
),
|
|
getDSPControl(),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
mkU32(0x400000))));
|
|
putIReg(rd, binop(Iop_16HLto32,
|
|
unop(Iop_32to16, mkexpr(t4)),
|
|
unop(Iop_32to16, mkexpr(t0))));
|
|
}
|
|
break;
|
|
}
|
|
case 0x9: { /* SHRA.PH */
|
|
DIP("shra.ph r%u, r%u, %u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, %u", 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);
|
|
t12 = newTemp(Ity_I32);
|
|
t13 = newTemp(Ity_I32);
|
|
t14 = 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, unop(Iop_1Uto32,
|
|
binop(Iop_CmpNE32,
|
|
binop(Iop_Sar32,
|
|
mkexpr(t0),
|
|
mkU8(16)),
|
|
mkU32(0))));
|
|
assign(t2, unop(Iop_1Uto32,
|
|
binop(Iop_CmpNE32,
|
|
binop(Iop_Sar32,
|
|
mkexpr(t0),
|
|
mkU8(16)),
|
|
mkU32(0xffffffff))));
|
|
assign(t3, binop(Iop_And32,
|
|
mkexpr(t1),
|
|
mkexpr(t2)));
|
|
putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32,
|
|
mkexpr(t3),
|
|
mkU32(0x1)),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
mkU32(0x400000)),
|
|
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))));
|
|
assign(t8,
|
|
IRExpr_ITE(binop(Iop_CmpEQ32,
|
|
mkexpr(t3),
|
|
mkU32(0x1)),
|
|
IRExpr_ITE(binop(Iop_CmpEQ32,
|
|
binop(Iop_And32,
|
|
getIReg(rt),
|
|
mkU32(0x8000)),
|
|
mkU32(0)),
|
|
mkU32(0x00007fff),
|
|
mkU32(0x00008000)),
|
|
binop(Iop_And32,
|
|
mkexpr(t0),
|
|
mkU32(0x0000ffff))));
|
|
assign(t10,
|
|
IRExpr_ITE(binop(Iop_CmpEQ32,
|
|
binop(Iop_And32,
|
|
getIReg(rt),
|
|
mkU32(0x00008000)),
|
|
binop(Iop_And32,
|
|
mkexpr(t0),
|
|
mkU32(0x00008000))),
|
|
mkexpr(t8),
|
|
IRExpr_ITE(binop(Iop_CmpEQ32,
|
|
binop(Iop_And32,
|
|
getIReg(rt),
|
|
mkU32(0x8000)),
|
|
mkU32(0)),
|
|
mkU32(0x00007fff),
|
|
mkU32(0x00008000))));
|
|
/* Shift higher 16 bits. */
|
|
assign(t4, binop(Iop_Shl32,
|
|
unop(Iop_16Sto32,
|
|
unop(Iop_32HIto16, getIReg(rt))),
|
|
mkU8(rs)));
|
|
|
|
assign(t5, unop(Iop_1Uto32,
|
|
binop(Iop_CmpNE32,
|
|
binop(Iop_Sar32,
|
|
mkexpr(t4),
|
|
mkU8(16)),
|
|
mkU32(0))));
|
|
assign(t6, unop(Iop_1Uto32,
|
|
binop(Iop_CmpNE32,
|
|
binop(Iop_Sar32,
|
|
mkexpr(t4),
|
|
mkU8(16)),
|
|
mkU32(0xffffffff))));
|
|
assign(t7, binop(Iop_And32,
|
|
mkexpr(t5),
|
|
mkexpr(t6)));
|
|
putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32,
|
|
mkexpr(t7),
|
|
mkU32(0x1)),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
mkU32(0x400000)),
|
|
getDSPControl()));
|
|
putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32,
|
|
mkexpr(t7),
|
|
mkU32(0x1)),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
mkU32(0x400000)),
|
|
getDSPControl()));
|
|
assign(t12, binop(Iop_Shl32,
|
|
binop(Iop_And32,
|
|
mkexpr(t4),
|
|
mkU32(0x8000)),
|
|
mkU8(16)));
|
|
putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32,
|
|
binop(Iop_And32,
|
|
getIReg(rt),
|
|
mkU32(0x80000000)),
|
|
mkexpr(t12)),
|
|
getDSPControl(),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
mkU32(0x400000))));
|
|
assign(t13, IRExpr_ITE(binop(Iop_CmpEQ32,
|
|
binop(Iop_And32,
|
|
getIReg(rt),
|
|
mkU32(0x80000000)),
|
|
mkU32(0)),
|
|
mkU32(0x7fff0000),
|
|
mkU32(0x80000000)));
|
|
assign(t9,
|
|
IRExpr_ITE(binop(Iop_CmpEQ32,
|
|
mkexpr(t7),
|
|
mkU32(0x1)),
|
|
mkexpr(t13),
|
|
binop(Iop_Shl32,
|
|
binop(Iop_And32,
|
|
mkexpr(t4),
|
|
mkU32(0x0000ffff)),
|
|
mkU8(16))));
|
|
assign(t14, IRExpr_ITE(binop(Iop_CmpEQ32,
|
|
binop(Iop_And32,
|
|
getIReg(rt),
|
|
mkU32(0x80000000)),
|
|
mkU32(0)),
|
|
mkU32(0x7fff0000),
|
|
mkU32(0x80000000)));
|
|
assign(t11,
|
|
IRExpr_ITE(binop(Iop_CmpEQ32,
|
|
binop(Iop_And32,
|
|
getIReg(rt),
|
|
mkU32(0x80000000)),
|
|
binop(Iop_Shl32,
|
|
binop(Iop_And32,
|
|
mkexpr(t4),
|
|
mkU32(0x00008000)),
|
|
mkU8(16))),
|
|
mkexpr(t9),
|
|
mkexpr(t14)));
|
|
putIReg(rd, binop(Iop_Or32,
|
|
mkexpr(t10),
|
|
mkexpr(t11)));
|
|
}
|
|
break;
|
|
}
|
|
case 0xD: { /* SHRA_R.PH */
|
|
DIP("shra.ph r%u, r%u, %u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, %u", 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%u, r%u, %u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, %u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u r%u, r%u", 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%u r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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%u, r%u, r%u", 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);
|
|
|
|
assign(t0, getAcc(ac));
|
|
/* Calculate the 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(binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
unop(Iop_1Sto32,
|
|
mkexpr(t2)),
|
|
unop(Iop_1Sto32,
|
|
mkexpr(t3))),
|
|
mkU32(0)),
|
|
mkU64(0x000000007fffffffULL),
|
|
mkexpr(t1)));
|
|
|
|
putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
unop(Iop_1Sto32,
|
|
mkexpr(t2)),
|
|
unop(Iop_1Sto32,
|
|
mkexpr(t3))),
|
|
mkU32(0)),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
binop(Iop_Shl32,
|
|
mkU32(0x1),
|
|
mkU8(ac+16))),
|
|
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(binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
unop(Iop_1Sto32,
|
|
mkexpr(t6)),
|
|
unop(Iop_1Sto32,
|
|
mkexpr(t7))),
|
|
mkU32(0)),
|
|
mkU64(0x000000007fffffffULL),
|
|
mkexpr(t5)));
|
|
|
|
putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
unop(Iop_1Sto32,
|
|
mkexpr(t6)),
|
|
unop(Iop_1Sto32,
|
|
mkexpr(t7))),
|
|
mkU32(0)),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
binop(Iop_Shl32,
|
|
mkU32(0x1),
|
|
mkU8(ac+16))),
|
|
getDSPControl()));
|
|
/* Subtract intermediate products from 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_CmpEQ32,
|
|
unop(Iop_64to32,
|
|
mkexpr(t9)),
|
|
unop(Iop_64to32,
|
|
getAcc(ac))),
|
|
getDSPControl(),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
binop(Iop_Shl32,
|
|
mkU32(0x1),
|
|
mkU8(ac+16)))));
|
|
putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t9)),
|
|
unop(Iop_64HIto32,
|
|
getAcc(ac))),
|
|
mkexpr(t10),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
binop(Iop_Shl32,
|
|
mkU32(0x1),
|
|
mkU8(ac+16)))));
|
|
break;
|
|
}
|
|
case 0x1B: { /* DPSQX_SA.W.PH */
|
|
DIP("dpsqx_sa.w.ph ac%u, r%u, r%u", 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);
|
|
|
|
assign(t0, getAcc(ac));
|
|
/* Calculate the 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(binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
unop(Iop_1Sto32,
|
|
mkexpr(t2)),
|
|
unop(Iop_1Sto32,
|
|
mkexpr(t3))),
|
|
mkU32(0)),
|
|
mkU64(0x000000007fffffffULL),
|
|
mkexpr(t1)));
|
|
|
|
putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
unop(Iop_1Sto32,
|
|
mkexpr(t2)),
|
|
unop(Iop_1Sto32,
|
|
mkexpr(t3))),
|
|
mkU32(0)),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
binop(Iop_Shl32,
|
|
mkU32(0x1),
|
|
mkU8(ac+16))),
|
|
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(binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
unop(Iop_1Sto32,
|
|
mkexpr(t6)),
|
|
unop(Iop_1Sto32,
|
|
mkexpr(t7))),
|
|
mkU32(0)),
|
|
mkU64(0x000000007fffffffULL),
|
|
mkexpr(t5)));
|
|
|
|
putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
unop(Iop_1Sto32,
|
|
mkexpr(t6)),
|
|
unop(Iop_1Sto32,
|
|
mkexpr(t7))),
|
|
mkU32(0)),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
binop(Iop_Shl32,
|
|
mkU32(0x1),
|
|
mkU8(ac+16))),
|
|
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_CmpEQ32,
|
|
unop(Iop_64to32,
|
|
mkexpr(t9)),
|
|
unop(Iop_64to32,
|
|
getAcc(ac))),
|
|
getDSPControl(),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
binop(Iop_Shl32,
|
|
mkU32(0x1),
|
|
mkU8(ac+16)))));
|
|
putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32,
|
|
unop(Iop_64HIto32,
|
|
mkexpr(t9)),
|
|
unop(Iop_64HIto32,
|
|
getAcc(ac))),
|
|
mkexpr(t10),
|
|
binop(Iop_Or32,
|
|
getDSPControl(),
|
|
binop(Iop_Shl32,
|
|
mkU32(0x1),
|
|
mkU8(ac+16)))));
|
|
break;
|
|
}
|
|
default:
|
|
return -1;
|
|
}
|
|
break; /* end of DPAQ.W.PH */
|
|
}
|
|
case 0x31: { /* APPEND */
|
|
switch(sa) {
|
|
case 0x0: { /* APPEND */
|
|
DIP("append r%u, r%u, %u", 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%u, r%u, %u", 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%u, r%u, %u", 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 -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- Disassemble a single instruction ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
/* Disassemble a single instruction into IR. The instruction is
|
|
located in host memory at guest_instr, and has guest IP of
|
|
guest_PC_curr_instr, which will have been set before the call
|
|
here. */
|
|
|
|
static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *,
|
|
Addr),
|
|
Bool resteerCisOk,
|
|
void* callback_opaque,
|
|
Long delta64,
|
|
const VexArchInfo* archinfo,
|
|
const VexAbiInfo* abiinfo,
|
|
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;
|
|
|
|
static IRExpr *lastn = NULL; /* last jump addr */
|
|
static IRStmt *bstmt = NULL; /* branch (Exit) stmt */
|
|
|
|
/* The running delta */
|
|
Int delta = (Int) delta64;
|
|
|
|
/* Holds eip at the start of the insn, so that we can print
|
|
consistent error messages for unimplemented insns. */
|
|
Int delta_start = delta;
|
|
|
|
/* Are we in a delay slot ? */
|
|
Bool delay_slot_branch, likely_delay_slot, delay_slot_jump;
|
|
|
|
/* Set result defaults. */
|
|
dres.whatNext = Dis_Continue;
|
|
dres.len = 0;
|
|
dres.continueAt = 0;
|
|
dres.jk_StopHere = Ijk_INVALID;
|
|
|
|
delay_slot_branch = likely_delay_slot = delay_slot_jump = False;
|
|
|
|
const UChar *code = guest_code + delta;
|
|
cins = getUInt(code);
|
|
DIP("\t0x%llx:\t0x%08x\t", (Addr64)guest_PC_curr_instr, cins);
|
|
|
|
if (delta != 0) {
|
|
if (branch_or_jump(guest_code + delta - 4)) {
|
|
if (lastn == NULL && bstmt == NULL) {
|
|
vassert(0);
|
|
} else {
|
|
dres.whatNext = Dis_StopHere;
|
|
if (lastn != NULL) {
|
|
delay_slot_jump = True;
|
|
} else if (bstmt != NULL) {
|
|
delay_slot_branch = True;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (branch_or_link_likely(guest_code + delta - 4)) {
|
|
likely_delay_slot = True;
|
|
}
|
|
}
|
|
|
|
/* Spot "Special" instructions (see comment at top of file). */
|
|
{
|
|
/* Spot the 16-byte preamble:
|
|
****mips32****
|
|
"srl $0, $0, 13
|
|
"srl $0, $0, 29
|
|
"srl $0, $0, 3
|
|
"srl $0, $0, 19
|
|
|
|
****mips64****
|
|
dsll $0, $0, 3
|
|
dsll $0, $0, 13
|
|
dsll $0, $0, 29
|
|
dsll $0, $0, 19 */
|
|
|
|
UInt word1 = mode64 ? 0xF8 : 0x342;
|
|
UInt word2 = mode64 ? 0x378 : 0x742;
|
|
UInt word3 = mode64 ? 0x778 : 0xC2;
|
|
UInt word4 = mode64 ? 0x4F8 : 0x4C2;
|
|
if (getUInt(code + 0) == word1 && getUInt(code + 4) == word2 &&
|
|
getUInt(code + 8) == word3 && getUInt(code + 12) == word4) {
|
|
/* Got a "Special" instruction preamble. Which one is it? */
|
|
if (getUInt(code + 16) == 0x01ad6825 /* or $13, $13, $13 */ ) {
|
|
/* $11 = client_request ( $12 ) */
|
|
DIP("$11 = client_request ( $12 )");
|
|
if (mode64)
|
|
putPC(mkU64(guest_PC_curr_instr + 20));
|
|
else
|
|
putPC(mkU32(guest_PC_curr_instr + 20));
|
|
dres.jk_StopHere = Ijk_ClientReq;
|
|
dres.whatNext = Dis_StopHere;
|
|
|
|
goto decode_success;
|
|
} else if (getUInt(code + 16) == 0x01ce7025 /* or $14, $14, $14 */ ) {
|
|
/* $11 = guest_NRADDR */
|
|
DIP("$11 = guest_NRADDR");
|
|
dres.len = 20;
|
|
delta += 20;
|
|
if (mode64)
|
|
putIReg(11, IRExpr_Get(offsetof(VexGuestMIPS64State,
|
|
guest_NRADDR), Ity_I64));
|
|
else
|
|
putIReg(11, IRExpr_Get(offsetof(VexGuestMIPS32State,
|
|
guest_NRADDR), Ity_I32));
|
|
goto decode_success;
|
|
} else if (getUInt(code + 16) == 0x01ef7825 /* or $15, $15, $15 */ ) {
|
|
/* branch-and-link-to-noredir $25 */
|
|
DIP("branch-and-link-to-noredir $25");
|
|
if (mode64)
|
|
putIReg(31, mkU64(guest_PC_curr_instr + 20));
|
|
else
|
|
putIReg(31, mkU32(guest_PC_curr_instr + 20));
|
|
putPC(getIReg(25));
|
|
dres.jk_StopHere = Ijk_NoRedir;
|
|
dres.whatNext = Dis_StopHere;
|
|
goto decode_success;
|
|
} else if (getUInt(code + 16) == 0x016b5825 /* or $11,$11,$11 */ ) {
|
|
/* IR injection */
|
|
DIP("IR injection");
|
|
#if defined (_MIPSEL)
|
|
vex_inject_ir(irsb, Iend_LE);
|
|
#elif defined (_MIPSEB)
|
|
vex_inject_ir(irsb, Iend_BE);
|
|
#endif
|
|
if (mode64) {
|
|
stmt(IRStmt_Put(offsetof(VexGuestMIPS64State, guest_CMSTART),
|
|
mkU64(guest_PC_curr_instr)));
|
|
stmt(IRStmt_Put(offsetof(VexGuestMIPS64State, guest_CMLEN),
|
|
mkU64(20)));
|
|
|
|
putPC(mkU64(guest_PC_curr_instr + 20));
|
|
} else {
|
|
stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_CMSTART),
|
|
mkU32(guest_PC_curr_instr)));
|
|
stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_CMLEN),
|
|
mkU32(20)));
|
|
|
|
putPC(mkU32(guest_PC_curr_instr + 20));
|
|
}
|
|
dres.whatNext = Dis_StopHere;
|
|
dres.jk_StopHere = Ijk_InvalICache;
|
|
dres.len = 20;
|
|
delta += 20;
|
|
goto decode_success;
|
|
}
|
|
|
|
/* We don't know what it is. Set opc1/opc2 so decode_failure
|
|
can print the insn following the Special-insn preamble. */
|
|
delta += 16;
|
|
goto decode_failure;
|
|
/*NOTREACHED*/}
|
|
}
|
|
|
|
opcode = get_opcode(cins);
|
|
imm = get_imm(cins);
|
|
rs = get_rs(cins);
|
|
rt = get_rt(cins);
|
|
rd = get_rd(cins);
|
|
sa = get_sa(cins);
|
|
fs = get_fs(cins);
|
|
fd = get_fd(cins);
|
|
ft = get_ft(cins);
|
|
tf = get_tf(cins);
|
|
nd = get_nd(cins);
|
|
sel = get_sel(cins);
|
|
fmt = get_fmt(cins);
|
|
instr_index = get_instr_index(cins);
|
|
trap_code = get_code(cins);
|
|
function = get_function(cins);
|
|
IRType ty = mode64 ? Ity_I64 : Ity_I32;
|
|
IRType tyF = fp_mode64 ? Ity_F64 : Ity_F32;
|
|
|
|
ac = get_acNo(cins);
|
|
|
|
switch (opcode) {
|
|
|
|
case 0x03: /* JAL */
|
|
DIP("jal 0x%x", instr_index);
|
|
if (mode64) {
|
|
putIReg(31, mkU64(guest_PC_curr_instr + 8));
|
|
t0 = newTemp(ty);
|
|
assign(t0, mkU64((guest_PC_curr_instr & 0xFFFFFFFFF0000000ULL) |
|
|
(instr_index << 2)));
|
|
} else {
|
|
putIReg(31, mkU32(guest_PC_curr_instr + 8));
|
|
t0 = newTemp(ty);
|
|
assign(t0, mkU32((guest_PC_curr_instr & 0xF0000000) |
|
|
(instr_index << 2)));
|
|
}
|
|
lastn = mkexpr(t0);
|
|
break;
|
|
case 0x02: /* J */
|
|
DIP("j 0x%x", instr_index);
|
|
t0 = newTemp(ty);
|
|
if (mode64)
|
|
assign(t0, mkU64((guest_PC_curr_instr & 0xFFFFFFFFF0000000ULL) |
|
|
(instr_index << 2)));
|
|
else
|
|
assign(t0, mkU32((guest_PC_curr_instr & 0xF0000000) |
|
|
(instr_index << 2)));
|
|
lastn = mkexpr(t0);
|
|
break;
|
|
|
|
case 0x11: { /* COP1 */
|
|
if (fmt == 0x3 && fd == 0 && function == 0) { /* MFHC1 */
|
|
DIP("mfhc1 r%u, f%u", rt, fs);
|
|
if (fp_mode64) {
|
|
t0 = newTemp(Ity_I64);
|
|
t1 = newTemp(Ity_I32);
|
|
assign(t0, unop(Iop_ReinterpF64asI64, getDReg(fs)));
|
|
assign(t1, unop(Iop_64HIto32, mkexpr(t0)));
|
|
putIReg(rt, mkWidenFrom32(ty, mkexpr(t1), True));
|
|
} else {
|
|
ILLEGAL_INSTRUCTON;
|
|
}
|
|
break;
|
|
} else if (fmt == 0x7 && fd == 0 && function == 0) { /* MTHC1 */
|
|
DIP("mthc1 r%u, f%u", rt, fs);
|
|
if (fp_mode64) {
|
|
t0 = newTemp(Ity_I64);
|
|
assign(t0, binop(Iop_32HLto64, getIReg(rt),
|
|
unop(Iop_ReinterpF32asI32,
|
|
getLoFromF64(Ity_F64 /* 32FPR mode. */,
|
|
getDReg(fs)))));
|
|
putDReg(fs, unop(Iop_ReinterpI64asF64, mkexpr(t0)));
|
|
} else {
|
|
ILLEGAL_INSTRUCTON;
|
|
}
|
|
break;
|
|
} else if (fmt == 0x8) { /* BC */
|
|
/* FcConditionalCode(bc1_cc) */
|
|
UInt bc1_cc = get_bc1_cc(cins);
|
|
t1 = newTemp(Ity_I1);
|
|
t2 = newTemp(Ity_I32);
|
|
t3 = newTemp(Ity_I1);
|
|
|
|
assign(t1, binop(Iop_CmpEQ32, mkU32(0), mkU32(bc1_cc)));
|
|
assign(t2, IRExpr_ITE(mkexpr(t1),
|
|
binop(Iop_And32,
|
|
binop(Iop_Shr32, getFCSR(), mkU8(23)),
|
|
mkU32(0x1)),
|
|
binop(Iop_And32,
|
|
binop(Iop_Shr32, getFCSR(),
|
|
mkU8(24 + bc1_cc)),
|
|
mkU32(0x1))));
|
|
|
|
if (tf == 1 && nd == 0) {
|
|
/* branch on true */
|
|
DIP("bc1t %u, %u", bc1_cc, imm);
|
|
assign(t3, binop(Iop_CmpEQ32, mkU32(1), mkexpr(t2)));
|
|
dis_branch(False, mkexpr(t3), imm, &bstmt);
|
|
break;
|
|
} else if (tf == 0 && nd == 0) {
|
|
/* branch on false */
|
|
DIP("bc1f %u, %u", bc1_cc, imm);
|
|
assign(t3, binop(Iop_CmpEQ32, mkU32(0), mkexpr(t2)));
|
|
dis_branch(False, mkexpr(t3), imm, &bstmt);
|
|
break;
|
|
} else if (nd == 1 && tf == 0) {
|
|
DIP("bc1fl %u, %u", bc1_cc, imm);
|
|
lastn = dis_branch_likely(binop(Iop_CmpNE32, mkexpr(t2),
|
|
mkU32(0x0)), imm);
|
|
break;
|
|
} else if (nd == 1 && tf == 1) {
|
|
DIP("bc1tl %u, %u", bc1_cc, imm);
|
|
lastn = dis_branch_likely(binop(Iop_CmpEQ32, mkexpr(t2),
|
|
mkU32(0x0)), imm);
|
|
break;
|
|
} else
|
|
goto decode_failure;
|
|
} else {
|
|
switch (function) {
|
|
case 0x4: { /* SQRT.fmt */
|
|
switch (fmt) {
|
|
case 0x10: { /* S */
|
|
IRExpr *rm = get_IR_roundingmode();
|
|
putFReg(fd, mkWidenFromF32(tyF, binop(Iop_SqrtF32, rm,
|
|
getLoFromF64(tyF, getFReg(fs)))));
|
|
break;
|
|
}
|
|
case 0x11: { /* D */
|
|
IRExpr *rm = get_IR_roundingmode();
|
|
putDReg(fd, binop(Iop_SqrtF64, rm, getDReg(fs)));
|
|
break;
|
|
}
|
|
default:
|
|
goto decode_failure;
|
|
}
|
|
}
|
|
break;
|
|
case 0x5: /* abs.fmt */
|
|
switch (fmt) {
|
|
case 0x10: /* S */
|
|
DIP("abs.s f%u, f%u", fd, fs);
|
|
putFReg(fd, mkWidenFromF32(tyF, unop(Iop_AbsF32,
|
|
getLoFromF64(tyF, getFReg(fs)))));
|
|
break;
|
|
case 0x11: /* D */
|
|
DIP("abs.d f%u, f%u", fd, fs);
|
|
putDReg(fd, unop(Iop_AbsF64, getDReg(fs)));
|
|
break;
|
|
default:
|
|
goto decode_failure;
|
|
}
|
|
break; /* case 0x5 */
|
|
|
|
case 0x02: /* MUL.fmt */
|
|
switch (fmt) {
|
|
case 0x11: { /* D */
|
|
DIP("mul.d f%u, f%u, f%u", fd, fs, ft);
|
|
IRExpr *rm = get_IR_roundingmode();
|
|
putDReg(fd, triop(Iop_MulF64, rm, getDReg(fs),
|
|
getDReg(ft)));
|
|
break;
|
|
}
|
|
case 0x10: { /* S */
|
|
DIP("mul.s f%u, f%u, f%u", fd, fs, ft);
|
|
IRExpr *rm = get_IR_roundingmode();
|
|
putFReg(fd, mkWidenFromF32(tyF, triop(Iop_MulF32, rm,
|
|
getLoFromF64(tyF, getFReg(fs)),
|
|
getLoFromF64(tyF, getFReg(ft)))));
|
|
break;
|
|
}
|
|
default:
|
|
goto decode_failure;
|
|
}
|
|
break; /* MUL.fmt */
|
|
|
|
case 0x03: /* DIV.fmt */
|
|
switch (fmt) {
|
|
case 0x11: { /* D */
|
|
DIP("div.d f%u, f%u, f%u", fd, fs, ft);
|
|
IRExpr *rm = get_IR_roundingmode();
|
|
putDReg(fd, triop(Iop_DivF64, rm, getDReg(fs),
|
|
getDReg(ft)));
|
|
break;
|
|
}
|
|
case 0x10: { /* S */
|
|
DIP("div.s f%u, f%u, f%u", fd, fs, ft);
|
|
calculateFCSR(fs, ft, DIVS, False, 2);
|
|
IRExpr *rm = get_IR_roundingmode();
|
|
putFReg(fd, mkWidenFromF32(tyF, triop(Iop_DivF32, rm,
|
|
getLoFromF64(tyF, getFReg(fs)),
|
|
getLoFromF64(tyF, getFReg(ft)))));
|
|
break;
|
|
}
|
|
default:
|
|
goto decode_failure;
|
|
}
|
|
break; /* DIV.fmt */
|
|
|
|
case 0x01: /* SUB.fmt */
|
|
switch (fmt) {
|
|
case 0x11: { /* D */
|
|
DIP("sub.d f%u, f%u, f%u", fd, fs, ft);
|
|
calculateFCSR(fs, ft, SUBD, False, 2);
|
|
IRExpr *rm = get_IR_roundingmode();
|
|
putDReg(fd, triop(Iop_SubF64, rm, getDReg(fs),
|
|
getDReg(ft)));
|
|
break;
|
|
}
|
|
case 0x10: { /* S */
|
|
DIP("sub.s f%u, f%u, f%u", fd, fs, ft);
|
|
calculateFCSR(fs, ft, SUBS, True, 2);
|
|
IRExpr *rm = get_IR_roundingmode();
|
|
putFReg(fd, mkWidenFromF32(tyF, triop(Iop_SubF32, rm,
|
|
getLoFromF64(tyF, getFReg(fs)),
|
|
getLoFromF64(tyF, getFReg(ft)))));
|
|
break;
|
|
}
|
|
default:
|
|
goto decode_failure;
|
|
}
|
|
break; /* SUB.fmt */
|
|
|
|
case 0x06: /* MOV.fmt */
|
|
switch (fmt) {
|
|
case 0x11: /* D */
|
|
DIP("mov.d f%u, f%u", fd, fs);
|
|
if (fp_mode64) {
|
|
putDReg(fd, getDReg(fs));
|
|
} else {
|
|
putFReg(fd, getFReg(fs));
|
|
putFReg(fd + 1, getFReg(fs + 1));
|
|
}
|
|
break;
|
|
case 0x10: /* S */
|
|
DIP("mov.s f%u, f%u", fd, fs);
|
|
putFReg(fd, getFReg(fs));
|
|
break;
|
|
default:
|
|
goto decode_failure;
|
|
}
|
|
break; /* MOV.fmt */
|
|
|
|
case 0x7: /* neg.fmt */
|
|
switch (fmt) {
|
|
case 0x10: /* S */
|
|
DIP("neg.s f%u, f%u", fd, fs);
|
|
putFReg(fd, mkWidenFromF32(tyF, unop(Iop_NegF32,
|
|
getLoFromF64(tyF, getFReg(fs)))));
|
|
break;
|
|
case 0x11: /* D */
|
|
DIP("neg.d f%u, f%u", fd, fs);
|
|
putDReg(fd, unop(Iop_NegF64, getDReg(fs)));
|
|
break;
|
|
default:
|
|
goto decode_failure;
|
|
}
|
|
break; /* case 0x7 */
|
|
|
|
case 0x08: /* ROUND.L.fmt */
|
|
switch (fmt) {
|
|
case 0x10: /* S */
|
|
DIP("round.l.s f%u, f%u", fd, fs);
|
|
if (fp_mode64) {
|
|
calculateFCSR(fs, 0, ROUNDLS, True, 1);
|
|
t0 = newTemp(Ity_I64);
|
|
|
|
assign(t0, binop(Iop_F32toI64S, mkU32(0x0),
|
|
getLoFromF64(Ity_F64, getFReg(fs))));
|
|
|
|
putDReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t0)));
|
|
} else {
|
|
ILLEGAL_INSTRUCTON;
|
|
}
|
|
break;
|
|
case 0x11: /* D */
|
|
DIP("round.l.d f%u, f%u", fd, fs);
|
|
if (fp_mode64) {
|
|
calculateFCSR(fs, 0, ROUNDLD, False, 1);
|
|
putDReg(fd, binop(Iop_RoundF64toInt, mkU32(0x0),
|
|
getDReg(fs)));
|
|
} else {
|
|
ILLEGAL_INSTRUCTON;
|
|
}
|
|
break;
|
|
default:
|
|
goto decode_failure;
|
|
|
|
}
|
|
break; /* ROUND.L.fmt */
|
|
|
|
case 0x09: /* TRUNC.L.fmt */
|
|
switch (fmt) {
|
|
case 0x10: /* S */
|
|
DIP("trunc.l.s f%u, f%u", fd, fs);
|
|
if (fp_mode64) {
|
|
calculateFCSR(fs, 0, TRUNCLS, True, 1);
|
|
t0 = newTemp(Ity_I64);
|
|
assign(t0, binop(Iop_F32toI64S, mkU32(0x3),
|
|
getLoFromF64(Ity_F64, getFReg(fs))));
|
|
|
|
putDReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t0)));
|
|
} else {
|
|
ILLEGAL_INSTRUCTON;
|
|
}
|
|
break;
|
|
case 0x11: /* D */
|
|
DIP("trunc.l.d f%u, f%u", fd, fs);
|
|
if (fp_mode64) {
|
|
calculateFCSR(fs, 0, TRUNCLD, False, 1);
|
|
putDReg(fd, binop(Iop_RoundF64toInt, mkU32(0x3),
|
|
getDReg(fs)));
|
|
} else {
|
|
ILLEGAL_INSTRUCTON;
|
|
}
|
|
break;
|
|
default:
|
|
goto decode_failure;
|
|
}
|
|
break; /* TRUNC.L.fmt */
|
|
|
|
case 0x15: /* RECIP.fmt */
|
|
switch (fmt) {
|
|
case 0x10: { /* S */
|
|
DIP("recip.s f%u, f%u", fd, fs);
|
|
IRExpr *rm = get_IR_roundingmode();
|
|
putFReg(fd, mkWidenFromF32(tyF, triop(Iop_DivF32,
|
|
rm, unop(Iop_ReinterpI32asF32,
|
|
mkU32(ONE_SINGLE)), getLoFromF64(tyF,
|
|
getFReg(fs)))));
|
|
break;
|
|
}
|
|
case 0x11: { /* D */
|
|
DIP("recip.d f%u, f%u", fd, fs);
|
|
IRExpr *rm = get_IR_roundingmode();
|
|
/* putDReg(fd, 1.0/getDreg(fs)); */
|
|
putDReg(fd, triop(Iop_DivF64, rm,
|
|
unop(Iop_ReinterpI64asF64,
|
|
mkU64(ONE_DOUBLE)), getDReg(fs)));
|
|
break;
|
|
}
|
|
default:
|
|
goto decode_failure;
|
|
|
|
}
|
|
break; /* case 0x15 */
|
|
|
|
case 0x13: /* MOVN.fmt */
|
|
switch (fmt) {
|
|
case 0x10: /* S */
|
|
DIP("movn.s f%u, f%u, r%u", fd, fs, rt);
|
|
t1 = newTemp(Ity_F64);
|
|
t2 = newTemp(Ity_F64);
|
|
t3 = newTemp(Ity_I1);
|
|
t4 = newTemp(Ity_F64);
|
|
if (mode64) {
|
|
assign(t1, getFReg(fs));
|
|
assign(t2, getFReg(fd));
|
|
assign(t3, binop(Iop_CmpNE64, mkU64(0), getIReg(rt)));
|
|
} else {
|
|
if (fp_mode64) {
|
|
assign(t1, getFReg(fs));
|
|
assign(t2, getFReg(fd));
|
|
assign(t3, binop(Iop_CmpNE32, mkU32(0), getIReg(rt)));
|
|
} else {
|
|
assign(t1, unop(Iop_F32toF64, getFReg(fs)));
|
|
assign(t2, unop(Iop_F32toF64, getFReg(fd)));
|
|
assign(t3, binop(Iop_CmpNE32, mkU32(0), getIReg(rt)));
|
|
}
|
|
}
|
|
|
|
assign(t4, IRExpr_ITE(mkexpr(t3), mkexpr(t1), mkexpr(t2)));
|
|
if (fp_mode64) {
|
|
IRTemp f = newTemp(Ity_F64);
|
|
IRTemp fd_hi = newTemp(Ity_I32);
|
|
t5 = newTemp(Ity_I64);
|
|
assign(f, getFReg(fd));
|
|
assign(fd_hi, unop(Iop_64HIto32, unop(Iop_ReinterpF64asI64,
|
|
mkexpr(f))));
|
|
|
|
assign(t5, mkWidenFrom32(Ity_I64, unop(Iop_64to32,
|
|
unop(Iop_ReinterpF64asI64, mkexpr(t4))), True));
|
|
|
|
putFReg(fd, unop (Iop_ReinterpI64asF64, mkexpr(t5)));
|
|
} else
|
|
putFReg(fd, binop(Iop_F64toF32, get_IR_roundingmode(),
|
|
mkexpr(t4)));
|
|
break;
|
|
case 0x11: /* D */
|
|
DIP("movn.d f%u, f%u, r%u", fd, fs, rt);
|
|
|
|
t3 = newTemp(Ity_I1);
|
|
t4 = newTemp(Ity_F64);
|
|
|
|
if (mode64)
|
|
assign(t3, binop(Iop_CmpNE64, mkU64(0), getIReg(rt)));
|
|
else
|
|
assign(t3, binop(Iop_CmpNE32, mkU32(0), getIReg(rt)));
|
|
|
|
putDReg(fd, IRExpr_ITE(mkexpr(t3), getDReg(fs), getDReg(fd)));
|
|
break;
|
|
default:
|
|
goto decode_failure;
|
|
}
|
|
break; /* MOVN.fmt */
|
|
|
|
case 0x12: /* MOVZ.fmt */
|
|
switch (fmt) {
|
|
case 0x10: /* S */
|
|
DIP("movz.s f%u, f%u, r%u", fd, fs, rt);
|
|
|
|
t1 = newTemp(Ity_F64);
|
|
t2 = newTemp(Ity_F64);
|
|
t3 = newTemp(Ity_I1);
|
|
t4 = newTemp(Ity_F64);
|
|
if (fp_mode64) {
|
|
assign(t1, getFReg(fs));
|
|
assign(t2, getFReg(fd));
|
|
if (mode64)
|
|
assign(t3, binop(Iop_CmpEQ64, mkU64(0), getIReg(rt)));
|
|
else
|
|
assign(t3, binop(Iop_CmpEQ32, mkU32(0), getIReg(rt)));
|
|
} else {
|
|
assign(t1, unop(Iop_F32toF64, getFReg(fs)));
|
|
assign(t2, unop(Iop_F32toF64, getFReg(fd)));
|
|
assign(t3, binop(Iop_CmpEQ32, mkU32(0), getIReg(rt)));
|
|
}
|
|
assign(t4, IRExpr_ITE(mkexpr(t3), mkexpr(t1), mkexpr(t2)));
|
|
|
|
if (fp_mode64) {
|
|
IRTemp f = newTemp(Ity_F64);
|
|
IRTemp fd_hi = newTemp(Ity_I32);
|
|
t7 = newTemp(Ity_I64);
|
|
assign(f, getFReg(fd));
|
|
assign(fd_hi, unop(Iop_64HIto32,
|
|
unop(Iop_ReinterpF64asI64, mkexpr(f))));
|
|
assign(t7, mkWidenFrom32(Ity_I64, unop(Iop_64to32,
|
|
unop(Iop_ReinterpF64asI64, mkexpr(t4))), True));
|
|
|
|
putFReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t7)));
|
|
} else
|
|
putFReg(fd, binop(Iop_F64toF32, get_IR_roundingmode(),
|
|
mkexpr(t4)));
|
|
|
|
break;
|
|
case 0x11: /* D */
|
|
DIP("movz.d f%u, f%u, r%u", fd, fs, rt);
|
|
t3 = newTemp(Ity_I1);
|
|
t4 = newTemp(Ity_F64);
|
|
if (mode64)
|
|
assign(t3, binop(Iop_CmpEQ64, mkU64(0), getIReg(rt)));
|
|
else
|
|
assign(t3, binop(Iop_CmpEQ32, mkU32(0), getIReg(rt)));
|
|
|
|
putDReg(fd, IRExpr_ITE(mkexpr(t3), getDReg(fs), getDReg(fd)));
|
|
break;
|
|
default:
|
|
goto decode_failure;
|
|
}
|
|
break; /* MOVZ.fmt */
|
|
|
|
case 0x11: /* MOVT.fmt */
|
|
if (tf == 1) {
|
|
UInt mov_cc = get_mov_cc(cins);
|
|
switch (fmt) { /* MOVCF = 010001 */
|
|
case 0x11: /* D */
|
|
DIP("movt.d f%u, f%u, %u", fd, fs, mov_cc);
|
|
t1 = newTemp(Ity_I1);
|
|
t2 = newTemp(Ity_I32);
|
|
t3 = newTemp(Ity_I1);
|
|
t4 = newTemp(Ity_F64);
|
|
|
|
assign(t1, binop(Iop_CmpEQ32, mkU32(0), mkU32(mov_cc)));
|
|
assign(t2, IRExpr_ITE(mkexpr(t1),
|
|
binop(Iop_And32,
|
|
binop(Iop_Shr32, getFCSR(),
|
|
mkU8(23)),
|
|
mkU32(0x1)),
|
|
binop(Iop_And32,
|
|
binop(Iop_Shr32, getFCSR(),
|
|
mkU8(24 + mov_cc)),
|
|
mkU32(0x1))
|
|
));
|
|
|
|
assign(t3, binop(Iop_CmpEQ32, mkU32(1), mkexpr(t2)));
|
|
assign(t4, IRExpr_ITE(mkexpr(t3),
|
|
getDReg(fs), getDReg(fd)));
|
|
putDReg(fd, mkexpr(t4));
|
|
break;
|
|
case 0x10: /* S */
|
|
DIP("movt.s f%u, f%u, %u", fd, fs, mov_cc);
|
|
t1 = newTemp(Ity_I1);
|
|
t2 = newTemp(Ity_I32);
|
|
t3 = newTemp(Ity_I1);
|
|
t4 = newTemp(Ity_F64);
|
|
t5 = newTemp(Ity_F64);
|
|
t6 = newTemp(Ity_F64);
|
|
t7 = newTemp(Ity_I64);
|
|
|
|
if (fp_mode64) {
|
|
assign(t5, getFReg(fs));
|
|
assign(t6, getFReg(fd));
|
|
} else {
|
|
assign(t5, unop(Iop_F32toF64, getFReg(fs)));
|
|
assign(t6, unop(Iop_F32toF64, getFReg(fd)));
|
|
}
|
|
|
|
assign(t1, binop(Iop_CmpEQ32, mkU32(0), mkU32(mov_cc)));
|
|
assign(t2, IRExpr_ITE(mkexpr(t1),
|
|
binop(Iop_And32,
|
|
binop(Iop_Shr32, getFCSR(),
|
|
mkU8(23)),
|
|
mkU32(0x1)),
|
|
binop(Iop_And32,
|
|
binop(Iop_Shr32, getFCSR(),
|
|
mkU8(24 + mov_cc)),
|
|
mkU32(0x1))
|
|
));
|
|
|
|
assign(t3, binop(Iop_CmpEQ32, mkU32(1), mkexpr(t2)));
|
|
assign(t4, IRExpr_ITE(mkexpr(t3),
|
|
mkexpr(t5), mkexpr(t6)));
|
|
|
|
if (fp_mode64) {
|
|
IRTemp f = newTemp(Ity_F64);
|
|
IRTemp fd_hi = newTemp(Ity_I32);
|
|
assign(f, getFReg(fd));
|
|
assign(fd_hi, unop(Iop_64HIto32,
|
|
unop(Iop_ReinterpF64asI64, mkexpr(f))));
|
|
assign(t7, mkWidenFrom32(Ity_I64, unop(Iop_64to32,
|
|
unop(Iop_ReinterpF64asI64, mkexpr(t4))),
|
|
True));
|
|
|
|
putFReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t7)));
|
|
} else
|
|
putFReg(fd, binop(Iop_F64toF32, get_IR_roundingmode(),
|
|
mkexpr(t4)));
|
|
break;
|
|
default:
|
|
goto decode_failure;
|
|
}
|
|
} else if (tf == 0) /* movf.fmt */
|
|
{
|
|
UInt mov_cc = get_mov_cc(cins);
|
|
switch (fmt) /* MOVCF = 010001 */
|
|
{
|
|
case 0x11: /* D */
|
|
DIP("movf.d f%u, f%u, %u", fd, fs, mov_cc);
|
|
t1 = newTemp(Ity_I1);
|
|
t2 = newTemp(Ity_I32);
|
|
t3 = newTemp(Ity_I1);
|
|
t4 = newTemp(Ity_F64);
|
|
|
|
assign(t1, binop(Iop_CmpEQ32, mkU32(0), mkU32(mov_cc)));
|
|
assign(t2, IRExpr_ITE(mkexpr(t1),
|
|
binop(Iop_And32,
|
|
binop(Iop_Shr32, getFCSR(),
|
|
mkU8(23)),
|
|
mkU32(0x1)),
|
|
binop(Iop_And32,
|
|
binop(Iop_Shr32, getFCSR(),
|
|
mkU8(24 + mov_cc)),
|
|
mkU32(0x1))
|
|
));
|
|
|
|
assign(t3, binop(Iop_CmpEQ32, mkU32(0), mkexpr(t2)));
|
|
assign(t4, IRExpr_ITE(mkexpr(t3),
|
|
getDReg(fs), getDReg(fd)));
|
|
putDReg(fd, mkexpr(t4));
|
|
break;
|
|
case 0x10: /* S */
|
|
DIP("movf.s f%u, f%u, %u", fd, fs, mov_cc);
|
|
t1 = newTemp(Ity_I1);
|
|
t2 = newTemp(Ity_I32);
|
|
t3 = newTemp(Ity_I1);
|
|
t4 = newTemp(Ity_F64);
|
|
t5 = newTemp(Ity_F64);
|
|
t6 = newTemp(Ity_F64);
|
|
|
|
if (fp_mode64) {
|
|
assign(t5, getFReg(fs));
|
|
assign(t6, getFReg(fd));
|
|
} else {
|
|
assign(t5, unop(Iop_F32toF64, getFReg(fs)));
|
|
assign(t6, unop(Iop_F32toF64, getFReg(fd)));
|
|
}
|
|
|
|
assign(t1, binop(Iop_CmpEQ32, mkU32(0), mkU32(mov_cc)));
|
|
assign(t2, IRExpr_ITE(mkexpr(t1),
|
|
binop(Iop_And32,
|
|
binop(Iop_Shr32, getFCSR(),
|
|
mkU8(23)),
|
|
mkU32(0x1)),
|
|
binop(Iop_And32,
|
|
binop(Iop_Shr32, getFCSR(),
|
|
mkU8(24 + mov_cc)),
|
|
mkU32(0x1))
|
|
));
|
|
|
|
assign(t3, binop(Iop_CmpEQ32, mkU32(0), mkexpr(t2)));
|
|
assign(t4, IRExpr_ITE(mkexpr(t3),
|
|
mkexpr(t5), mkexpr(t6)));
|
|
|
|
if (fp_mode64) {
|
|
IRTemp f = newTemp(Ity_F64);
|
|
IRTemp fd_hi = newTemp(Ity_I32);
|
|
t7 = newTemp(Ity_I64);
|
|
assign(f, getFReg(fd));
|
|
assign(fd_hi, unop(Iop_64HIto32,
|
|
unop(Iop_ReinterpF64asI64, mkexpr(f))));
|
|
assign(t7, mkWidenFrom32(Ity_I64, unop(Iop_64to32,
|
|
unop(Iop_ReinterpF64asI64, mkexpr(t4))),
|
|
True));
|
|
|
|
putFReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t7)));
|
|
} else
|
|
putFReg(fd, binop(Iop_F64toF32, get_IR_roundingmode(),
|
|
mkexpr(t4)));
|
|
break;
|
|
default:
|
|
goto decode_failure;
|
|
}
|
|
}
|
|
|
|
break; /* MOVT.fmt */
|
|
|
|
case 0x0: /* add.fmt */
|
|
switch (fmt) {
|
|
case 0x10: { /* S */
|
|
DIP("add.s f%u, f%u, f%u", fd, fs, ft);
|
|
calculateFCSR(fs, ft, ADDS, True, 2);
|
|
IRExpr *rm = get_IR_roundingmode();
|
|
putFReg(fd, mkWidenFromF32(tyF, triop(Iop_AddF32, rm,
|
|
getLoFromF64(tyF, getFReg(fs)),
|
|
getLoFromF64(tyF, getFReg(ft)))));
|
|
break;
|
|
}
|
|
case 0x11: { /* D */
|
|
DIP("add.d f%u, f%u, f%u", fd, fs, ft);
|
|
calculateFCSR(fs, ft, ADDD, False, 2);
|
|
IRExpr *rm = get_IR_roundingmode();
|
|
putDReg(fd, triop(Iop_AddF64, rm, getDReg(fs), getDReg(ft)));
|
|
break;
|
|
}
|
|
|
|
case 0x4: /* MTC1 (Move Word to Floating Point) */
|
|
DIP("mtc1 r%u, f%u", rt, fs);
|
|
if (fp_mode64) {
|
|
t0 = newTemp(Ity_I32);
|
|
t1 = newTemp(Ity_F32);
|
|
assign(t0, mkNarrowTo32(ty, getIReg(rt)));
|
|
assign(t1, unop(Iop_ReinterpI32asF32, mkexpr(t0)));
|
|
|
|
putFReg(fs, mkWidenFromF32(tyF, mkexpr(t1)));
|
|
} else
|
|
putFReg(fs, unop(Iop_ReinterpI32asF32, getIReg(rt)));
|
|
break;
|
|
|
|
case 0x5: /* Doubleword Move to Floating Point DMTC1; MIPS64 */
|
|
DIP("dmtc1 r%u, f%u", rt, fs);
|
|
vassert(mode64);
|
|
putFReg(fs, unop(Iop_ReinterpI64asF64, getIReg(rt)));
|
|
break;
|
|
|
|
case 0x0: /* MFC1 */
|
|
DIP("mfc1 r%u, f%u", rt, fs);
|
|
if (fp_mode64) {
|
|
t0 = newTemp(Ity_I64);
|
|
t1 = newTemp(Ity_I32);
|
|
assign(t0, unop(Iop_ReinterpF64asI64, getFReg(fs)));
|
|
assign(t1, unop(Iop_64to32, mkexpr(t0)));
|
|
putIReg(rt, mkWidenFrom32(ty, mkexpr(t1), True));
|
|
} else
|
|
putIReg(rt, unop(Iop_ReinterpF32asI32, getFReg(fs)));
|
|
break;
|
|
|
|
case 0x1: /* Doubleword Move from Floating Point DMFC1;
|
|
MIPS64 */
|
|
DIP("dmfc1 r%u, f%u", rt, fs);
|
|
putIReg(rt, unop(Iop_ReinterpF64asI64, getFReg(fs)));
|
|
break;
|
|
|
|
case 0x6: /* CTC1 */
|
|
DIP("ctc1 r%u, f%u", rt, fs);
|
|
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);
|
|
assign(t0, mkNarrowTo32(ty, getIReg(rt)));
|
|
if (fs == 25) { /* FCCR */
|
|
assign(t1, binop(Iop_Shl32, binop(Iop_And32, mkexpr(t0),
|
|
mkU32(0x000000FE)), mkU8(24)));
|
|
assign(t2, binop(Iop_And32, mkexpr(t0),
|
|
mkU32(0x01000000)));
|
|
assign(t3, binop(Iop_Shl32, binop(Iop_And32, mkexpr(t0),
|
|
mkU32(0x00000001)), mkU8(23)));
|
|
assign(t4, binop(Iop_And32, mkexpr(t0),
|
|
mkU32(0x007FFFFF)));
|
|
putFCSR(binop(Iop_Or32, binop(Iop_Or32, mkexpr(t1),
|
|
mkexpr(t2)), binop(Iop_Or32, mkexpr(t3),
|
|
mkexpr(t4))));
|
|
} else if (fs == 26) { /* FEXR */
|
|
assign(t1, binop(Iop_And32, getFCSR(), mkU32(0xFFFC0000)));
|
|
assign(t2, binop(Iop_And32, mkexpr(t0),
|
|
mkU32(0x0003F000)));
|
|
assign(t3, binop(Iop_And32, getFCSR(), mkU32(0x00000F80)));
|
|
assign(t4, binop(Iop_And32, mkexpr(t0),
|
|
mkU32(0x0000007C)));
|
|
assign(t5, binop(Iop_And32, getFCSR(), mkU32(0x00000003)));
|
|
putFCSR(binop(Iop_Or32, binop(Iop_Or32, binop(Iop_Or32,
|
|
mkexpr(t1), mkexpr(t2)), binop(Iop_Or32,
|
|
mkexpr(t3), mkexpr(t4))), mkexpr(t5)));
|
|
} else if (fs == 28) {
|
|
assign(t1, binop(Iop_And32, getFCSR(), mkU32(0xFE000000)));
|
|
assign(t2, binop(Iop_Shl32, binop(Iop_And32, mkexpr(t0),
|
|
mkU32(0x00000002)), mkU8(22)));
|
|
assign(t3, binop(Iop_And32, getFCSR(), mkU32(0x00FFF000)));
|
|
assign(t4, binop(Iop_And32, mkexpr(t0),
|
|
mkU32(0x00000F80)));
|
|
assign(t5, binop(Iop_And32, getFCSR(), mkU32(0x0000007C)));
|
|
assign(t6, binop(Iop_And32, mkexpr(t0),
|
|
mkU32(0x00000003)));
|
|
putFCSR(binop(Iop_Or32, binop(Iop_Or32, binop(Iop_Or32,
|
|
mkexpr(t1), mkexpr(t2)), binop(Iop_Or32,
|
|
mkexpr(t3), mkexpr(t4))), binop(Iop_Or32,
|
|
mkexpr(t5), mkexpr(t6))));
|
|
} else if (fs == 31) {
|
|
putFCSR(mkexpr(t0));
|
|
}
|
|
break;
|
|
case 0x2: /* CFC1 */
|
|
DIP("cfc1 r%u, f%u", rt, fs);
|
|
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);
|
|
assign(t0, getFCSR());
|
|
if (fs == 0) {
|
|
putIReg(rt, mkWidenFrom32(ty,
|
|
IRExpr_Get(offsetof(VexGuestMIPS32State,
|
|
guest_FIR),
|
|
Ity_I32),
|
|
False));
|
|
} else if (fs == 25) {
|
|
assign(t1, mkU32(0x000000FF));
|
|
assign(t2, binop(Iop_Shr32, binop(Iop_And32, mkexpr(t0),
|
|
mkU32(0xFE000000)), mkU8(25)));
|
|
assign(t3, binop(Iop_Shr32, binop(Iop_And32, mkexpr(t0),
|
|
mkU32(0x00800000)), mkU8(23)));
|
|
putIReg(rt, mkWidenFrom32(ty, binop(Iop_Or32,
|
|
binop(Iop_Or32, mkexpr(t1), mkexpr(t2)),
|
|
mkexpr(t3)), False));
|
|
} else if (fs == 26) {
|
|
assign(t1, mkU32(0xFFFFF07C));
|
|
assign(t2, binop(Iop_And32, mkexpr(t0),
|
|
mkU32(0x0003F000)));
|
|
assign(t3, binop(Iop_And32, mkexpr(t0),
|
|
mkU32(0x0000007C)));
|
|
putIReg(rt, mkWidenFrom32(ty, binop(Iop_Or32,
|
|
binop(Iop_Or32, mkexpr(t1), mkexpr(t2)),
|
|
mkexpr(t3)), False));
|
|
} else if (fs == 28) {
|
|
assign(t1, mkU32(0x00000F87));
|
|
assign(t2, binop(Iop_And32, mkexpr(t0),
|
|
mkU32(0x00000F83)));
|
|
assign(t3, binop(Iop_Shr32, binop(Iop_And32, mkexpr(t0),
|
|
mkU32(0x01000000)), mkU8(22)));
|
|
putIReg(rt, mkWidenFrom32(ty, binop(Iop_Or32,
|
|
binop(Iop_Or32, mkexpr(t1), mkexpr(t2)),
|
|
mkexpr(t3)), False));
|
|
} else if (fs == 31) {
|
|
putIReg(rt, mkWidenFrom32(ty, getFCSR(), False));
|
|
}
|
|
break;
|
|
default:
|
|
goto decode_failure;
|
|
}
|
|
break;
|
|
|
|
case 0x21: /* CVT.D */
|
|
switch (fmt) {
|
|
case 0x10: /* S */
|
|
DIP("cvt.d.s f%u, f%u", fd, fs);
|
|
calculateFCSR(fs, 0, CVTDS, True, 1);
|
|
if (fp_mode64) {
|
|
t0 = newTemp(Ity_I64);
|
|
t1 = newTemp(Ity_I32);
|
|
t3 = newTemp(Ity_F32);
|
|
t4 = newTemp(Ity_F32);
|
|
/* get lo half of FPR */
|
|
assign(t0, unop(Iop_ReinterpF64asI64, getFReg(fs)));
|
|
|
|
assign(t1, unop(Iop_64to32, mkexpr(t0)));
|
|
|
|
assign(t3, unop(Iop_ReinterpI32asF32, mkexpr(t1)));
|
|
|
|
putFReg(fd, unop(Iop_F32toF64, mkexpr(t3)));
|
|
} else
|
|
putDReg(fd, unop(Iop_F32toF64, getFReg(fs)));
|
|
break;
|
|
|
|
case 0x14:
|
|
DIP("cvt.d.w %u, %u", fd, fs);
|
|
calculateFCSR(fs, 0, CVTDW, True, 1);
|
|
if (fp_mode64) {
|
|
t0 = newTemp(Ity_I64);
|
|
t1 = newTemp(Ity_I32);
|
|
t3 = newTemp(Ity_F32);
|
|
t4 = newTemp(Ity_F32);
|
|
/* get lo half of FPR */
|
|
assign(t0, unop(Iop_ReinterpF64asI64, getFReg(fs)));
|
|
|
|
assign(t1, unop(Iop_64to32, mkexpr(t0)));
|
|
putDReg(fd,unop(Iop_I32StoF64, mkexpr(t1)));
|
|
break;
|
|
} else {
|
|
t0 = newTemp(Ity_I32);
|
|
assign(t0, unop(Iop_ReinterpF32asI32, getFReg(fs)));
|
|
putDReg(fd, unop(Iop_I32StoF64, mkexpr(t0)));
|
|
break;
|
|
}
|
|
|
|
case 0x15: { /* L */
|
|
if (fp_mode64) {
|
|
DIP("cvt.d.l %u, %u", fd, fs);
|
|
calculateFCSR(fs, 0, CVTDL, False, 1);
|
|
t0 = newTemp(Ity_I64);
|
|
assign(t0, unop(Iop_ReinterpF64asI64, getFReg(fs)));
|
|
|
|
putFReg(fd, binop(Iop_I64StoF64,
|
|
get_IR_roundingmode(), mkexpr(t0)));
|
|
break;
|
|
} else
|
|
goto decode_failure;
|
|
}
|
|
default:
|
|
goto decode_failure;
|
|
}
|
|
break; /* CVT.D */
|
|
|
|
case 0x20: /* cvt.s */
|
|
switch (fmt) {
|
|
case 0x14: /* W */
|
|
DIP("cvt.s.w %u, %u", fd, fs);
|
|
calculateFCSR(fs, 0, CVTSW, True, 1);
|
|
if (fp_mode64) {
|
|
t0 = newTemp(Ity_I64);
|
|
t1 = newTemp(Ity_I32);
|
|
t3 = newTemp(Ity_F32);
|
|
t4 = newTemp(Ity_F32);
|
|
/* get lo half of FPR */
|
|
assign(t0, unop(Iop_ReinterpF64asI64, getFReg(fs)));
|
|
|
|
assign(t1, unop(Iop_64to32, mkexpr(t0)));
|
|
putFReg(fd, mkWidenFromF32(tyF, binop(Iop_I32StoF32,
|
|
get_IR_roundingmode(), mkexpr(t1))));
|
|
} else {
|
|
t0 = newTemp(Ity_I32);
|
|
assign(t0, unop(Iop_ReinterpF32asI32, getFReg(fs)));
|
|
putFReg(fd, binop(Iop_I32StoF32, get_IR_roundingmode(),
|
|
mkexpr(t0)));
|
|
}
|
|
break;
|
|
|
|
case 0x11: /* D */
|
|
DIP("cvt.s.d %u, %u", fd, fs);
|
|
calculateFCSR(fs, 0, CVTSD, False, 1);
|
|
t0 = newTemp(Ity_F32);
|
|
assign(t0, binop(Iop_F64toF32, get_IR_roundingmode(),
|
|
getDReg(fs)));
|
|
putFReg(fd, mkWidenFromF32(tyF, mkexpr(t0)));
|
|
break;
|
|
|
|
case 0x15: /* L */
|
|
DIP("cvt.s.l %u, %u", fd, fs);
|
|
calculateFCSR(fs, 0, CVTSL, False, 1);
|
|
t0 = newTemp(Ity_I64);
|
|
assign(t0, unop(Iop_ReinterpF64asI64, getFReg(fs)));
|
|
|
|
putFReg(fd, mkWidenFromF32(tyF, binop(Iop_I64StoF32,
|
|
get_IR_roundingmode(), mkexpr(t0))));
|
|
break;
|
|
|
|
default:
|
|
goto decode_failure;
|
|
}
|
|
break; /* cvt.s */
|
|
|
|
case 0x24: /* cvt.w */
|
|
switch (fmt) {
|
|
case 0x10: /* S */
|
|
DIP("cvt.w.s %u, %u", fd, fs);
|
|
calculateFCSR(fs, 0, CVTWS, True, 1);
|
|
putFReg(fd,
|
|
mkWidenFromF32(tyF,
|
|
binop(Iop_RoundF32toInt,
|
|
get_IR_roundingmode(),
|
|
getLoFromF64(tyF, getFReg(fs))))
|
|
);
|
|
break;
|
|
|
|
case 0x11:
|
|
DIP("cvt.w.d %u, %u", fd, fs);
|
|
calculateFCSR(fs, 0, CVTWD, False, 1);
|
|
t0 = newTemp(Ity_I32);
|
|
t1 = newTemp(Ity_F32);
|
|
assign(t0, binop(Iop_F64toI32S, get_IR_roundingmode(),
|
|
getDReg(fs)));
|
|
assign(t1, unop(Iop_ReinterpI32asF32, mkexpr(t0)));
|
|
putFReg(fd, mkWidenFromF32(tyF, mkexpr(t1)));
|
|
break;
|
|
|
|
default:
|
|
goto decode_failure;
|
|
|
|
}
|
|
break;
|
|
|
|
case 0x25: /* cvt.l */
|
|
switch (fmt) {
|
|
case 0x10: /* S */
|
|
DIP("cvt.l.s %u, %u", fd, fs);
|
|
if (fp_mode64) {
|
|
calculateFCSR(fs, 0, CVTLS, True, 1);
|
|
t0 = newTemp(Ity_I64);
|
|
|
|
assign(t0, binop(Iop_F32toI64S, get_IR_roundingmode(),
|
|
getLoFromF64(tyF, getFReg(fs))));
|
|
|
|
putDReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t0)));
|
|
} else {
|
|
ILLEGAL_INSTRUCTON;
|
|
}
|
|
break;
|
|
|
|
case 0x11: { /* D */
|
|
DIP("cvt.l.d %u, %u", fd, fs);
|
|
if (fp_mode64) {
|
|
calculateFCSR(fs, 0, CVTLD, False, 1);
|
|
putDReg(fd, binop(Iop_RoundF64toInt,
|
|
get_IR_roundingmode(), getDReg(fs)));
|
|
} else {
|
|
ILLEGAL_INSTRUCTON;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
goto decode_failure;
|
|
}
|
|
break;
|
|
|
|
case 0x0B: /* FLOOR.L.fmt */
|
|
switch (fmt) {
|
|
case 0x10: /* S */
|
|
DIP("floor.l.s %u, %u", fd, fs);
|
|
if (fp_mode64) {
|
|
calculateFCSR(fs, 0, FLOORLS, True, 1);
|
|
t0 = newTemp(Ity_I64);
|
|
|
|
assign(t0, binop(Iop_F32toI64S, mkU32(0x1),
|
|
getLoFromF64(tyF, getFReg(fs))));
|
|
|
|
putDReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t0)));
|
|
} else {
|
|
ILLEGAL_INSTRUCTON;
|
|
}
|
|
break;
|
|
|
|
case 0x11: /* D */
|
|
DIP("floor.l.d %u, %u", fd, fs);
|
|
if (fp_mode64) {
|
|
calculateFCSR(fs, 0, FLOORLD, False, 1);
|
|
putDReg(fd, binop(Iop_RoundF64toInt, mkU32(0x1),
|
|
getDReg(fs)));
|
|
} else {
|
|
ILLEGAL_INSTRUCTON;
|
|
}
|
|
break;
|
|
default:
|
|
goto decode_failure;
|
|
}
|
|
break;
|
|
|
|
case 0x0C: /* ROUND.W.fmt */
|
|
switch (fmt) {
|
|
case 0x10: /* S */
|
|
DIP("round.w.s f%u, f%u", fd, fs);
|
|
calculateFCSR(fs, 0, ROUNDWS, True, 1);
|
|
if (fp_mode64) {
|
|
t0 = newTemp(Ity_I64);
|
|
t1 = newTemp(Ity_I32);
|
|
t3 = newTemp(Ity_F32);
|
|
t4 = newTemp(Ity_F32);
|
|
/* get lo half of FPR */
|
|
assign(t0, unop(Iop_ReinterpF64asI64, getFReg(fs)));
|
|
|
|
assign(t1, unop(Iop_64to32, mkexpr(t0)));
|
|
|
|
assign(t3, unop(Iop_ReinterpI32asF32, mkexpr(t1)));
|
|
|
|
assign(t4, binop(Iop_RoundF32toInt, mkU32(0x0),
|
|
mkexpr(t3)));
|
|
|
|
putFReg(fd, mkWidenFromF32(tyF, mkexpr(t4)));
|
|
} else
|
|
putFReg(fd, binop(Iop_RoundF32toInt, mkU32(0x0),
|
|
getFReg(fs)));
|
|
break;
|
|
|
|
case 0x11: /* D */
|
|
DIP("round.w.d f%u, f%u", fd, fs);
|
|
calculateFCSR(fs, 0, ROUNDWD, False, 1);
|
|
if (fp_mode64) {
|
|
t0 = newTemp(Ity_I32);
|
|
assign(t0, binop(Iop_F64toI32S, mkU32(0x0),
|
|
getDReg(fs)));
|
|
putFReg(fd, mkWidenFromF32(tyF,
|
|
unop(Iop_ReinterpI32asF32, mkexpr(t0))));
|
|
} else {
|
|
t0 = newTemp(Ity_I32);
|
|
|
|
assign(t0, binop(Iop_F64toI32S, mkU32(0x0),
|
|
getDReg(fs)));
|
|
|
|
putFReg(fd, unop(Iop_ReinterpI32asF32, mkexpr(t0)));
|
|
}
|
|
break;
|
|
default:
|
|
goto decode_failure;
|
|
|
|
}
|
|
break; /* ROUND.W.fmt */
|
|
|
|
case 0x0F: /* FLOOR.W.fmt */
|
|
switch (fmt) {
|
|
case 0x10: /* S */
|
|
DIP("floor.w.s f%u, f%u", fd, fs);
|
|
calculateFCSR(fs, 0, FLOORWS, True, 1);
|
|
if (fp_mode64) {
|
|
t0 = newTemp(Ity_I64);
|
|
t1 = newTemp(Ity_I32);
|
|
t3 = newTemp(Ity_F32);
|
|
t4 = newTemp(Ity_F32);
|
|
/* get lo half of FPR */
|
|
assign(t0, unop(Iop_ReinterpF64asI64, getFReg(fs)));
|
|
|
|
assign(t1, unop(Iop_64to32, mkexpr(t0)));
|
|
|
|
assign(t3, unop(Iop_ReinterpI32asF32, mkexpr(t1)));
|
|
|
|
assign(t4, binop(Iop_RoundF32toInt, mkU32(0x1),
|
|
mkexpr(t3)));
|
|
|
|
putFReg(fd, mkWidenFromF32(tyF, mkexpr(t4)));
|
|
} else
|
|
putFReg(fd, binop(Iop_RoundF32toInt, mkU32(0x1),
|
|
getFReg(fs)));
|
|
break;
|
|
|
|
case 0x11: /* D */
|
|
DIP("floor.w.d f%u, f%u", fd, fs);
|
|
calculateFCSR(fs, 0, FLOORWD, False, 1);
|
|
if (fp_mode64) {
|
|
t0 = newTemp(Ity_I32);
|
|
assign(t0, binop(Iop_F64toI32S, mkU32(0x1),
|
|
getDReg(fs)));
|
|
putFReg(fd, mkWidenFromF32(tyF,
|
|
unop(Iop_ReinterpI32asF32, mkexpr(t0))));
|
|
break;
|
|
} else {
|
|
t0 = newTemp(Ity_I32);
|
|
|
|
assign(t0, binop(Iop_F64toI32S, mkU32(0x1),
|
|
getDReg(fs)));
|
|
|
|
putFReg(fd, unop(Iop_ReinterpI32asF32, mkexpr(t0)));
|
|
break;
|
|
}
|
|
default:
|
|
goto decode_failure;
|
|
|
|
}
|
|
break; /* FLOOR.W.fmt */
|
|
|
|
case 0x0D: /* TRUNC.W */
|
|
switch (fmt) {
|
|
case 0x10: /* S */
|
|
DIP("trunc.w.s %u, %u", fd, fs);
|
|
calculateFCSR(fs, 0, TRUNCWS, True, 1);
|
|
if (fp_mode64) {
|
|
t0 = newTemp(Ity_I64);
|
|
t1 = newTemp(Ity_I32);
|
|
t3 = newTemp(Ity_F32);
|
|
t4 = newTemp(Ity_F32);
|
|
/* get lo half of FPR */
|
|
assign(t0, unop(Iop_ReinterpF64asI64, getFReg(fs)));
|
|
|
|
assign(t1, unop(Iop_64to32, mkexpr(t0)));
|
|
|
|
assign(t3, unop(Iop_ReinterpI32asF32, mkexpr(t1)));
|
|
|
|
assign(t4, binop(Iop_RoundF32toInt, mkU32(0x3),
|
|
mkexpr(t3)));
|
|
|
|
putFReg(fd, mkWidenFromF32(tyF, mkexpr(t4)));
|
|
} else
|
|
putFReg(fd, binop(Iop_RoundF32toInt, mkU32(0x3),
|
|
getFReg(fs)));
|
|
break;
|
|
case 0x11: /* D */
|
|
DIP("trunc.w.d %u, %u", fd, fs);
|
|
calculateFCSR(fs, 0, TRUNCWD, False, 1);
|
|
if (fp_mode64) {
|
|
t0 = newTemp(Ity_I32);
|
|
|
|
assign(t0, binop(Iop_F64toI32S, mkU32(0x3),
|
|
getFReg(fs)));
|
|
|
|
putFReg(fd, mkWidenFromF32(tyF,
|
|
unop(Iop_ReinterpI32asF32, mkexpr(t0))));
|
|
} else {
|
|
t0 = newTemp(Ity_I32);
|
|
|
|
assign(t0, binop(Iop_F64toI32S, mkU32(0x3),
|
|
getDReg(fs)));
|
|
|
|
putFReg(fd, unop(Iop_ReinterpI32asF32, mkexpr(t0)));
|
|
}
|
|
break;
|
|
default:
|
|
goto decode_failure;
|
|
|
|
}
|
|
break;
|
|
|
|
case 0x0E: /* CEIL.W.fmt */
|
|
switch (fmt) {
|
|
case 0x10: /* S */
|
|
DIP("ceil.w.s %u, %u", fd, fs);
|
|
calculateFCSR(fs, 0, CEILWS, True, 1);
|
|
if (fp_mode64) {
|
|
t0 = newTemp(Ity_I64);
|
|
t1 = newTemp(Ity_I32);
|
|
t3 = newTemp(Ity_F32);
|
|
t4 = newTemp(Ity_F32);
|
|
/* get lo half of FPR */
|
|
assign(t0, unop(Iop_ReinterpF64asI64, getFReg(fs)));
|
|
|
|
assign(t1, unop(Iop_64to32, mkexpr(t0)));
|
|
|
|
assign(t3, unop(Iop_ReinterpI32asF32, mkexpr(t1)));
|
|
|
|
assign(t4, binop(Iop_RoundF32toInt, mkU32(0x2),
|
|
mkexpr(t3)));
|
|
|
|
putFReg(fd, mkWidenFromF32(tyF, mkexpr(t4)));
|
|
} else
|
|
putFReg(fd, binop(Iop_RoundF32toInt, mkU32(0x2),
|
|
getFReg(fs)));
|
|
break;
|
|
|
|
case 0x11: /* D */
|
|
DIP("ceil.w.d %u, %u", fd, fs);
|
|
calculateFCSR(fs, 0, CEILWD, False, 1);
|
|
if (!fp_mode64) {
|
|
t0 = newTemp(Ity_I32);
|
|
assign(t0, binop(Iop_F64toI32S, mkU32(0x2),
|
|
getDReg(fs)));
|
|
putFReg(fd, unop(Iop_ReinterpI32asF32, mkexpr(t0)));
|
|
} else {
|
|
t0 = newTemp(Ity_I32);
|
|
assign(t0, binop(Iop_F64toI32S, mkU32(0x2),
|
|
getDReg(fs)));
|
|
putFReg(fd, mkWidenFromF32(tyF,
|
|
unop(Iop_ReinterpI32asF32, mkexpr(t0))));
|
|
}
|
|
break;
|
|
default:
|
|
goto decode_failure;
|
|
|
|
}
|
|
break;
|
|
|
|
case 0x0A: /* CEIL.L.fmt */
|
|
switch (fmt) {
|
|
case 0x10: /* S */
|
|
DIP("ceil.l.s %u, %u", fd, fs);
|
|
if (fp_mode64) {
|
|
calculateFCSR(fs, 0, CEILLS, True, 1);
|
|
t0 = newTemp(Ity_I64);
|
|
|
|
assign(t0, binop(Iop_F32toI64S, mkU32(0x2),
|
|
getLoFromF64(tyF, getFReg(fs))));
|
|
|
|
putFReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t0)));
|
|
} else {
|
|
ILLEGAL_INSTRUCTON;
|
|
}
|
|
break;
|
|
|
|
case 0x11: /* D */
|
|
DIP("ceil.l.d %u, %u", fd, fs);
|
|
if (fp_mode64) {
|
|
calculateFCSR(fs, 0, CEILLD, False, 1);
|
|
putDReg(fd, binop(Iop_RoundF64toInt, mkU32(0x2),
|
|
getDReg(fs)));
|
|
} else {
|
|
ILLEGAL_INSTRUCTON;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
goto decode_failure;
|
|
|
|
}
|
|
break;
|
|
|
|
case 0x16: /* RSQRT.fmt */
|
|
switch (fmt) {
|
|
case 0x10: { /* S */
|
|
DIP("rsqrt.s %u, %u", fd, fs);
|
|
IRExpr *rm = get_IR_roundingmode();
|
|
putFReg(fd, mkWidenFromF32(tyF, triop(Iop_DivF32, rm,
|
|
unop(Iop_ReinterpI32asF32, mkU32(ONE_SINGLE)),
|
|
binop(Iop_SqrtF32, rm, getLoFromF64(tyF,
|
|
getFReg(fs))))));
|
|
break;
|
|
}
|
|
case 0x11: { /* D */
|
|
DIP("rsqrt.d %u, %u", fd, fs);
|
|
IRExpr *rm = get_IR_roundingmode();
|
|
putDReg(fd, triop(Iop_DivF64, rm,
|
|
unop(Iop_ReinterpI64asF64,
|
|
mkU64(ONE_DOUBLE)),
|
|
binop(Iop_SqrtF64, rm, getDReg(fs))));
|
|
break;
|
|
}
|
|
default:
|
|
goto decode_failure;
|
|
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if (dis_instr_CCondFmt(cins))
|
|
break;
|
|
goto decode_failure;
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
break; /* COP1 */
|
|
case 0x10: /* COP0 */
|
|
if (rs == 0) { /* MFC0 */
|
|
DIP("mfc0 r%u, r%u, %u", rt, rd, sel);
|
|
IRTemp val = newTemp(Ity_I32);
|
|
IRExpr** args = mkIRExprVec_3 (IRExpr_BBPTR(), mkU32(rd), mkU32(sel));
|
|
IRDirty *d = unsafeIRDirty_1_N(val,
|
|
0,
|
|
"mips32_dirtyhelper_mfc0",
|
|
&mips32_dirtyhelper_mfc0,
|
|
args);
|
|
stmt(IRStmt_Dirty(d));
|
|
putIReg(rt, mkexpr(val));
|
|
} else if (rs == 1) {
|
|
/* Doubleword Move from Coprocessor 0 - DMFC0; MIPS64 */
|
|
DIP("dmfc0 r%u, r%u, %u", rt, rd, sel);
|
|
IRTemp val = newTemp(Ity_I64);
|
|
IRExpr** args = mkIRExprVec_3 (IRExpr_BBPTR(), mkU64(rd), mkU64(sel));
|
|
IRDirty *d = unsafeIRDirty_1_N(val,
|
|
0,
|
|
"mips64_dirtyhelper_dmfc0",
|
|
&mips64_dirtyhelper_dmfc0,
|
|
args);
|
|
stmt(IRStmt_Dirty(d));
|
|
putDReg(rt, mkexpr(val));
|
|
} else
|
|
goto decode_failure;
|
|
break;
|
|
|
|
case 0x31: /* LWC1 */
|
|
/* Load Word to Floating Point - LWC1 (MIPS32) */
|
|
DIP("lwc1 f%u, %u(r%u)", ft, imm, rs);
|
|
if (fp_mode64) {
|
|
t1 = newTemp(Ity_F32);
|
|
t2 = newTemp(Ity_I64);
|
|
if (mode64) {
|
|
t0 = newTemp(Ity_I64);
|
|
/* new LO */
|
|
assign(t0, binop(Iop_Add64, getIReg(rs),
|
|
mkU64(extend_s_16to64(imm))));
|
|
} else {
|
|
t0 = newTemp(Ity_I32);
|
|
/* new LO */
|
|
assign(t0, binop(Iop_Add32, getIReg(rs),
|
|
mkU32(extend_s_16to32(imm))));
|
|
}
|
|
assign(t1, load(Ity_F32, mkexpr(t0)));
|
|
assign(t2, mkWidenFrom32(Ity_I64, unop(Iop_ReinterpF32asI32,
|
|
mkexpr(t1)), True));
|
|
putDReg(ft, unop(Iop_ReinterpI64asF64, mkexpr(t2)));
|
|
} else {
|
|
t0 = newTemp(Ity_I32);
|
|
assign(t0, binop(Iop_Add32, getIReg(rs),
|
|
mkU32(extend_s_16to32(imm))));
|
|
putFReg(ft, load(Ity_F32, mkexpr(t0)));
|
|
}
|
|
break;
|
|
|
|
case 0x39: /* SWC1 */
|
|
DIP("swc1 f%u, %u(r%u)", ft, imm, rs);
|
|
if (fp_mode64) {
|
|
t0 = newTemp(Ity_I64);
|
|
t2 = newTemp(Ity_I32);
|
|
LOAD_STORE_PATTERN;
|
|
assign(t0, unop(Iop_ReinterpF64asI64, getFReg(ft)));
|
|
assign(t2, unop(Iop_64to32, mkexpr(t0)));
|
|
store(mkexpr(t1), unop(Iop_ReinterpI32asF32, mkexpr(t2)));
|
|
} else {
|
|
LOAD_STORE_PATTERN;
|
|
store(mkexpr(t1), getFReg(ft));
|
|
}
|
|
break;
|
|
|
|
case 0x33: /* PREF */
|
|
DIP("pref");
|
|
break;
|
|
|
|
case 0x35:
|
|
/* Load Doubleword to Floating Point - LDC1 (MIPS32) */
|
|
DIP("ldc1 f%u, %u(%u)", rt, imm, rs);
|
|
LOAD_STORE_PATTERN;
|
|
putDReg(ft, load(Ity_F64, mkexpr(t1)));
|
|
break;
|
|
|
|
case 0x3D:
|
|
/* Store Doubleword from Floating Point - SDC1 */
|
|
DIP("sdc1 f%u, %u(%u)", ft, imm, rs);
|
|
LOAD_STORE_PATTERN;
|
|
store(mkexpr(t1), getDReg(ft));
|
|
break;
|
|
|
|
case 0x23: /* LW */
|
|
DIP("lw r%u, %u(r%u)", rt, imm, rs);
|
|
LOAD_STORE_PATTERN;
|
|
putIReg(rt, mkWidenFrom32(ty, load(Ity_I32, mkexpr(t1)), True));
|
|
break;
|
|
|
|
case 0x20: /* LB */
|
|
DIP("lb r%u, %u(r%u)", rt, imm, rs);
|
|
LOAD_STORE_PATTERN;
|
|
if (mode64)
|
|
putIReg(rt, unop(Iop_8Sto64, load(Ity_I8, mkexpr(t1))));
|
|
else
|
|
putIReg(rt, unop(Iop_8Sto32, load(Ity_I8, mkexpr(t1))));
|
|
break;
|
|
|
|
case 0x24: /* LBU */
|
|
DIP("lbu r%u, %u(r%u)", rt, imm, rs);
|
|
LOAD_STORE_PATTERN;
|
|
if (mode64)
|
|
putIReg(rt, unop(Iop_8Uto64, load(Ity_I8, mkexpr(t1))));
|
|
else
|
|
putIReg(rt, unop(Iop_8Uto32, load(Ity_I8, mkexpr(t1))));
|
|
break;
|
|
|
|
case 0x21: /* LH */
|
|
DIP("lh r%u, %u(r%u)", rt, imm, rs);
|
|
LOAD_STORE_PATTERN;
|
|
if (mode64)
|
|
putIReg(rt, unop(Iop_16Sto64, load(Ity_I16, mkexpr(t1))));
|
|
else
|
|
putIReg(rt, unop(Iop_16Sto32, load(Ity_I16, mkexpr(t1))));
|
|
break;
|
|
|
|
case 0x25: /* LHU */
|
|
DIP("lhu r%u, %u(r%u)", rt, imm, rs);
|
|
LOAD_STORE_PATTERN;
|
|
if (mode64)
|
|
putIReg(rt, unop(Iop_16Uto64, load(Ity_I16, mkexpr(t1))));
|
|
else
|
|
putIReg(rt, unop(Iop_16Uto32, load(Ity_I16, mkexpr(t1))));
|
|
break;
|
|
|
|
case 0x0F: /* LUI */
|
|
p = (imm << 16);
|
|
DIP("lui r%u, imm: 0x%x", rt, imm);
|
|
if (mode64)
|
|
putIReg(rt, mkU64(extend_s_32to64(p)));
|
|
else
|
|
putIReg(rt, mkU32(p));
|
|
break;
|
|
|
|
case 0x13: /* COP1X */
|
|
switch (function) {
|
|
case 0x0: { /* LWXC1 */
|
|
/* Load Word Indexed to Floating Point - LWXC1 (MIPS32r2) */
|
|
DIP("lwxc1 f%u, r%u(r%u)", fd, rt, rs);
|
|
if (fp_mode64) {
|
|
t0 = newTemp(Ity_I64);
|
|
t1 = newTemp(Ity_I32);
|
|
t3 = newTemp(Ity_F32);
|
|
t4 = newTemp(Ity_I64);
|
|
|
|
t2 = newTemp(ty);
|
|
/* new LO */
|
|
assign(t2, binop(mode64 ? Iop_Add64 : Iop_Add32, getIReg(rs),
|
|
getIReg(rt)));
|
|
assign(t3, load(Ity_F32, mkexpr(t2)));
|
|
|
|
assign(t4, mkWidenFrom32(Ity_I64, unop(Iop_ReinterpF32asI32,
|
|
mkexpr(t3)), True));
|
|
|
|
putFReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t4)));
|
|
} else {
|
|
t0 = newTemp(Ity_I32);
|
|
assign(t0, binop(Iop_Add32, getIReg(rs), getIReg(rt)));
|
|
putFReg(fd, load(Ity_F32, mkexpr(t0)));
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 0x1: { /* LDXC1 */
|
|
/* Load Doubleword Indexed to Floating Point
|
|
LDXC1 (MIPS32r2 and MIPS64) */
|
|
if (fp_mode64) {
|
|
DIP("ldxc1 f%u, r%u(r%u)", fd, rt, rs);
|
|
t0 = newTemp(ty);
|
|
assign(t0, binop(mode64 ? Iop_Add64 : Iop_Add32, getIReg(rs),
|
|
getIReg(rt)));
|
|
putFReg(fd, load(Ity_F64, mkexpr(t0)));
|
|
break;
|
|
} else {
|
|
t0 = newTemp(Ity_I32);
|
|
assign(t0, binop(Iop_Add32, getIReg(rs), getIReg(rt)));
|
|
|
|
t1 = newTemp(Ity_I32);
|
|
assign(t1, binop(Iop_Add32, mkexpr(t0), mkU32(4)));
|
|
|
|
#if defined (_MIPSEL)
|
|
putFReg(fd, load(Ity_F32, mkexpr(t0)));
|
|
putFReg(fd + 1, load(Ity_F32, mkexpr(t1)));
|
|
#elif defined (_MIPSEB)
|
|
putFReg(fd + 1, load(Ity_F32, mkexpr(t0)));
|
|
putFReg(fd, load(Ity_F32, mkexpr(t1)));
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
|
|
case 0x5: /* Load Doubleword Indexed Unaligned to Floating Point - LUXC1;
|
|
MIPS32r2 */
|
|
DIP("luxc1 f%u, r%u(r%u)", fd, rt, rs);
|
|
t0 = newTemp(Ity_I64);
|
|
t1 = newTemp(Ity_I64);
|
|
assign(t0, binop(Iop_Add64, getIReg(rs), getIReg(rt)));
|
|
assign(t1, binop(Iop_And64, mkexpr(t0),
|
|
mkU64(0xfffffffffffffff8ULL)));
|
|
putFReg(fd, load(Ity_F64, mkexpr(t1)));
|
|
break;
|
|
|
|
case 0x8: { /* Store Word Indexed from Floating Point - SWXC1 */
|
|
DIP("swxc1 f%u, r%u(r%u)", ft, rt, rs);
|
|
if (fp_mode64) {
|
|
t0 = newTemp(ty);
|
|
assign(t0, binop(mode64 ? Iop_Add64 : Iop_Add32, getIReg(rs),
|
|
getIReg(rt)));
|
|
store(mkexpr(t0), getLoFromF64(tyF, getFReg(fs)));
|
|
|
|
} else {
|
|
t0 = newTemp(Ity_I32);
|
|
assign(t0, binop(Iop_Add32, getIReg(rs), getIReg(rt)));
|
|
|
|
store(mkexpr(t0), getFReg(fs));
|
|
}
|
|
break;
|
|
}
|
|
case 0x9: { /* Store Doubleword Indexed from Floating Point - SDXC1 */
|
|
DIP("sdc1 f%u, %u(%u)", ft, imm, rs);
|
|
if (fp_mode64) {
|
|
t0 = newTemp(ty);
|
|
assign(t0, binop(mode64 ? Iop_Add64 : Iop_Add32, getIReg(rs),
|
|
getIReg(rt)));
|
|
store(mkexpr(t0), getFReg(fs));
|
|
} else {
|
|
t0 = newTemp(Ity_I32);
|
|
assign(t0, binop(Iop_Add32, getIReg(rs), getIReg(rt)));
|
|
|
|
t1 = newTemp(Ity_I32);
|
|
assign(t1, binop(Iop_Add32, mkexpr(t0), mkU32(4)));
|
|
|
|
#if defined (_MIPSEL)
|
|
store(mkexpr(t0), getFReg(fs));
|
|
store(mkexpr(t1), getFReg(fs + 1));
|
|
#elif defined (_MIPSEB)
|
|
store(mkexpr(t0), getFReg(fs + 1));
|
|
store(mkexpr(t1), getFReg(fs));
|
|
#endif
|
|
}
|
|
break;
|
|
}
|
|
case 0xD: /* Store Doubleword Indexed Unaligned from Floating Point -
|
|
SUXC1; MIPS64 MIPS32r2 */
|
|
DIP("suxc1 f%u, r%u(r%u)", fd, rt, rs);
|
|
t0 = newTemp(Ity_I64);
|
|
t1 = newTemp(Ity_I64);
|
|
assign(t0, binop(Iop_Add64, getIReg(rs), getIReg(rt)));
|
|
assign(t1, binop(Iop_And64, mkexpr(t0), mkU64(0xfffffffffffffff8ULL)));
|
|
store(mkexpr(t1), getFReg(fs));
|
|
break;
|
|
|
|
case 0x0F: {
|
|
DIP("prefx");
|
|
break;
|
|
}
|
|
case 0x20: { /* MADD.S */
|
|
DIP("madd.s f%u, f%u, f%u, f%u", fd, fmt, fs, ft);
|
|
IRExpr *rm = get_IR_roundingmode();
|
|
t1 = newTemp(Ity_F32);
|
|
assign(t1, qop(Iop_MAddF32, rm,
|
|
getLoFromF64(tyF, getFReg(fmt)),
|
|
getLoFromF64(tyF, getFReg(fs)),
|
|
getLoFromF64(tyF, getFReg(ft))));
|
|
putFReg(fd, mkWidenFromF32(tyF, mkexpr(t1)));
|
|
break; /* MADD.S */
|
|
}
|
|
case 0x21: { /* MADD.D */
|
|
DIP("madd.d f%u, f%u, f%u, f%u", fd, fmt, fs, ft);
|
|
IRExpr *rm = get_IR_roundingmode();
|
|
putDReg(fd, qop(Iop_MAddF64, rm, getDReg(fmt), getDReg(fs),
|
|
getDReg(ft)));
|
|
break; /* MADD.D */
|
|
}
|
|
case 0x28: { /* MSUB.S */
|
|
DIP("msub.s f%u, f%u, f%u, f%u", fd, fmt, fs, ft);
|
|
IRExpr *rm = get_IR_roundingmode();
|
|
t1 = newTemp(Ity_F32);
|
|
assign(t1, qop(Iop_MSubF32, rm,
|
|
getLoFromF64(tyF, getFReg(fmt)),
|
|
getLoFromF64(tyF, getFReg(fs)),
|
|
getLoFromF64(tyF, getFReg(ft))));
|
|
putFReg(fd, mkWidenFromF32(tyF, mkexpr(t1)));
|
|
break; /* MSUB.S */
|
|
}
|
|
case 0x29: { /* MSUB.D */
|
|
DIP("msub.d f%u, f%u, f%u, f%u", fd, fmt, fs, ft);
|
|
IRExpr *rm = get_IR_roundingmode();
|
|
putDReg(fd, qop(Iop_MSubF64, rm, getDReg(fmt), getDReg(fs),
|
|
getDReg(ft)));
|
|
break; /* MSUB.D */
|
|
}
|
|
case 0x30: { /* NMADD.S */
|
|
DIP("nmadd.s f%u, f%u, f%u, f%u", fd, fmt, fs, ft);
|
|
IRExpr *rm = get_IR_roundingmode();
|
|
t1 = newTemp(Ity_F32);
|
|
assign(t1, qop(Iop_MAddF32, rm,
|
|
getLoFromF64(tyF, getFReg(fmt)),
|
|
getLoFromF64(tyF, getFReg(fs)),
|
|
getLoFromF64(tyF, getFReg(ft))));
|
|
|
|
putFReg(fd, mkWidenFromF32(tyF, unop(Iop_NegF32, mkexpr(t1))));
|
|
break; /* NMADD.S */
|
|
}
|
|
case 0x31: { /* NMADD.D */
|
|
DIP("nmadd.d f%u, f%u, f%u, f%u", fd, fmt, fs, ft);
|
|
IRExpr *rm = get_IR_roundingmode();
|
|
t1 = newTemp(Ity_F64);
|
|
assign(t1, qop(Iop_MAddF64, rm, getDReg(fmt), getDReg(fs),
|
|
getDReg(ft)));
|
|
putDReg(fd, unop(Iop_NegF64, mkexpr(t1)));
|
|
break; /* NMADD.D */
|
|
}
|
|
case 0x38: { /* NMSUBB.S */
|
|
DIP("nmsub.s f%u, f%u, f%u, f%u", fd, fmt, fs, ft);
|
|
IRExpr *rm = get_IR_roundingmode();
|
|
t1 = newTemp(Ity_F32);
|
|
assign(t1, qop(Iop_MSubF32, rm,
|
|
getLoFromF64(tyF, getFReg(fmt)),
|
|
getLoFromF64(tyF, getFReg(fs)),
|
|
getLoFromF64(tyF, getFReg(ft))));
|
|
|
|
putFReg(fd, mkWidenFromF32(tyF, unop(Iop_NegF32, mkexpr(t1))));
|
|
break; /* NMSUBB.S */
|
|
}
|
|
case 0x39: { /* NMSUBB.D */
|
|
DIP("nmsub.d f%u, f%u, f%u, f%u", fd, fmt, fs, ft);
|
|
IRExpr *rm = get_IR_roundingmode();
|
|
t1 = newTemp(Ity_F64);
|
|
assign(t1, qop(Iop_MSubF64, rm, getDReg(fmt), getDReg(fs),
|
|
getDReg(ft)));
|
|
putDReg(fd, unop(Iop_NegF64, mkexpr(t1)));
|
|
break; /* NMSUBB.D */
|
|
}
|
|
|
|
default:
|
|
goto decode_failure;
|
|
}
|
|
break;
|
|
|
|
case 0x22: /* LWL */
|
|
DIP("lwl r%u, %u(r%u)", rt, imm, rs);
|
|
if (mode64) {
|
|
/* t1 = addr */
|
|
t1 = newTemp(Ity_I64);
|
|
#if defined (_MIPSEL)
|
|
assign(t1, binop(Iop_Add64, getIReg(rs), mkU64(extend_s_16to64(imm))));
|
|
#elif defined (_MIPSEB)
|
|
assign(t1, binop(Iop_Xor64,
|
|
mkU64(0x03),
|
|
binop(Iop_Add64,
|
|
getIReg(rs),
|
|
mkU64(extend_s_16to64(imm)))));
|
|
#endif
|
|
/* t2 = word addr */
|
|
/* t4 = addr mod 4 */
|
|
LWX_SWX_PATTERN64;
|
|
|
|
/* t3 = word content - shifted */
|
|
t3 = newTemp(Ity_I32);
|
|
assign(t3, binop(Iop_Shl32,
|
|
load(Ity_I32, mkexpr(t2)),
|
|
narrowTo(Ity_I8,
|
|
binop(Iop_Shl32,
|
|
binop(Iop_Sub32,
|
|
mkU32(0x03),
|
|
mkexpr(t4)),
|
|
mkU8(3)))));
|
|
|
|
/* rt content - adjusted */
|
|
t5 = newTemp(Ity_I32);
|
|
assign(t5, binop(Iop_And32,
|
|
mkNarrowTo32(ty, getIReg(rt)),
|
|
binop(Iop_Shr32,
|
|
mkU32(0x00FFFFFF),
|
|
narrowTo(Ity_I8, binop(Iop_Mul32,
|
|
mkU32(0x08),
|
|
mkexpr(t4))))));
|
|
|
|
putIReg(rt, mkWidenFrom32(ty, binop(Iop_Or32, mkexpr(t5),
|
|
mkexpr(t3)), True));
|
|
} else {
|
|
/* t1 = addr */
|
|
t1 = newTemp(Ity_I32);
|
|
#if defined (_MIPSEL)
|
|
assign(t1, binop(Iop_Add32, getIReg(rs), mkU32(extend_s_16to32(imm))));
|
|
#elif defined (_MIPSEB)
|
|
assign(t1, binop(Iop_Xor32, mkU32(0x3), binop(Iop_Add32, getIReg(rs),
|
|
mkU32(extend_s_16to32(imm)))));
|
|
#endif
|
|
|
|
/* t2 = word addr */
|
|
/* t4 = addr mod 4 */
|
|
LWX_SWX_PATTERN;
|
|
|
|
/* t3 = word content - shifted */
|
|
t3 = newTemp(Ity_I32);
|
|
assign(t3, binop(Iop_Shl32, load(Ity_I32, mkexpr(t2)), narrowTo(Ity_I8,
|
|
binop(Iop_Shl32, binop(Iop_Sub32, mkU32(0x03), mkexpr(t4)),
|
|
mkU8(3)))));
|
|
|
|
/* rt content - adjusted */
|
|
t5 = newTemp(Ity_I32);
|
|
assign(t5, binop(Iop_And32,
|
|
getIReg(rt),
|
|
binop(Iop_Shr32,
|
|
mkU32(0x00FFFFFF),
|
|
narrowTo(Ity_I8, binop(Iop_Mul32,
|
|
mkU32(0x08),
|
|
mkexpr(t4))))));
|
|
|
|
putIReg(rt, binop(Iop_Or32, mkexpr(t5), mkexpr(t3)));
|
|
}
|
|
break;
|
|
|
|
case 0x26: /* LWR */
|
|
DIP("lwr r%u, %u(r%u)", rt, imm, rs);
|
|
if (mode64) {
|
|
/* t1 = addr */
|
|
t1 = newTemp(Ity_I64);
|
|
#if defined (_MIPSEL)
|
|
assign(t1, binop(Iop_Add64, getIReg(rs), mkU64(extend_s_16to64(imm))));
|
|
#elif defined (_MIPSEB)
|
|
assign(t1, binop(Iop_Xor64,
|
|
mkU64(0x3),
|
|
binop(Iop_Add64,
|
|
getIReg(rs),
|
|
mkU64(extend_s_16to64(imm)))));
|
|
#endif
|
|
/* t2 = word addr */
|
|
/* t4 = addr mod 4 */
|
|
LWX_SWX_PATTERN64;
|
|
|
|
/* t3 = word content - shifted */
|
|
t3 = newTemp(Ity_I32);
|
|
assign(t3, binop(Iop_Shr32,
|
|
load(Ity_I32, mkexpr(t2)),
|
|
narrowTo(Ity_I8,
|
|
binop(Iop_Shl32, mkexpr(t4), mkU8(0x03)))));
|
|
|
|
/* rt content - adjusted */
|
|
t5 = newTemp(Ity_I32);
|
|
assign(t5, binop(Iop_And32, mkNarrowTo32(ty, getIReg(rt)),
|
|
unop(Iop_Not32, binop(Iop_Shr32, mkU32(0xFFFFFFFF),
|
|
narrowTo(Ity_I8, binop(Iop_Shl32, mkexpr(t4), mkU8(0x3)))))));
|
|
|
|
putIReg(rt, mkWidenFrom32(ty, binop(Iop_Or32, mkexpr(t5),
|
|
mkexpr(t3)), True));
|
|
|
|
} else {
|
|
/* t1 = addr */
|
|
t1 = newTemp(Ity_I32);
|
|
#if defined (_MIPSEL)
|
|
assign(t1, binop(Iop_Add32, getIReg(rs), mkU32(extend_s_16to32(imm))));
|
|
#elif defined (_MIPSEB)
|
|
assign(t1, binop(Iop_Xor32, mkU32(0x3), binop(Iop_Add32, getIReg(rs),
|
|
mkU32(extend_s_16to32(imm)))));
|
|
#endif
|
|
|
|
/* t2 = word addr */
|
|
/* t4 = addr mod 4 */
|
|
LWX_SWX_PATTERN;
|
|
|
|
/* t3 = word content - shifted */
|
|
t3 = newTemp(Ity_I32);
|
|
assign(t3, binop(Iop_Shr32, load(Ity_I32, mkexpr(t2)),
|
|
narrowTo(Ity_I8, binop(Iop_Shl32, mkexpr(t4),
|
|
mkU8(3)))));
|
|
|
|
/* rt content - adjusted */
|
|
t5 = newTemp(Ity_I32);
|
|
assign(t5, binop(Iop_And32, getIReg(rt), unop(Iop_Not32,
|
|
binop(Iop_Shr32, mkU32(0xFFFFFFFF), narrowTo(Ity_I8,
|
|
binop(Iop_Shl32, mkexpr(t4), mkU8(0x3)))))));
|
|
|
|
putIReg(rt, binop(Iop_Or32, mkexpr(t5), mkexpr(t3)));
|
|
}
|
|
break;
|
|
|
|
case 0x2B: /* SW */
|
|
DIP("sw r%u, %u(r%u)", rt, imm, rs);
|
|
LOAD_STORE_PATTERN;
|
|
store(mkexpr(t1), mkNarrowTo32(ty, getIReg(rt)));
|
|
break;
|
|
|
|
case 0x2C: { /* SDL rt, offset(base) MIPS64 */
|
|
DIP("sdl r%u, %u(r%u)", rt, imm, rs);
|
|
vassert(mode64);
|
|
IRTemp A_byte = newTemp(Ity_I8);
|
|
IRTemp B_byte = newTemp(Ity_I8);
|
|
IRTemp C_byte = newTemp(Ity_I8);
|
|
IRTemp D_byte = newTemp(Ity_I8);
|
|
IRTemp E_byte = newTemp(Ity_I8);
|
|
IRTemp F_byte = newTemp(Ity_I8);
|
|
IRTemp G_byte = newTemp(Ity_I8);
|
|
IRTemp H_byte = newTemp(Ity_I8);
|
|
IRTemp B_pos = newTemp(Ity_I64);
|
|
IRTemp C_pos = newTemp(Ity_I64);
|
|
IRTemp D_pos = newTemp(Ity_I64);
|
|
IRTemp E_pos = newTemp(Ity_I64);
|
|
IRTemp F_pos = newTemp(Ity_I64);
|
|
IRTemp G_pos = newTemp(Ity_I64);
|
|
|
|
/* H byte */
|
|
assign(H_byte, getByteFromReg(rt, 0));
|
|
/* G byte */
|
|
assign(G_byte, getByteFromReg(rt, 1));
|
|
/* F byte */
|
|
assign(F_byte, getByteFromReg(rt, 2));
|
|
/* E byte */
|
|
assign(E_byte, getByteFromReg(rt, 3));
|
|
/* D byte */
|
|
assign(D_byte, getByteFromReg(rt, 4));
|
|
/* C byte */
|
|
assign(C_byte, getByteFromReg(rt, 5));
|
|
/* B byte */
|
|
assign(B_byte, getByteFromReg(rt, 6));
|
|
/* A byte */
|
|
assign(A_byte, getByteFromReg(rt, 7));
|
|
|
|
/* t1 = addr */
|
|
t1 = newTemp(Ity_I64);
|
|
assign(t1, binop(Iop_Add64, getIReg(rs), mkU64(extend_s_16to64(imm))));
|
|
|
|
/* t2 = word addr */
|
|
t2 = newTemp(Ity_I64);
|
|
assign(t2, binop(Iop_And64, mkexpr(t1), mkU64(0xFFFFFFFFFFFFFFF8ULL)));
|
|
|
|
/* t3 = addr mod 7 */
|
|
t3 = newTemp(Ity_I64);
|
|
assign(t3, binop(Iop_And64, mkexpr(t1), mkU64(0x7)));
|
|
|
|
#if defined (_MIPSEL)
|
|
/* Calculate X_byte position. */
|
|
assign(B_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkexpr(t3), mkU64(0x1)),
|
|
mkU64(0x0),
|
|
mkU64(0x1)));
|
|
|
|
assign(C_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkexpr(t3), mkU64(0x2)),
|
|
mkU64(0x0),
|
|
mkU64(0x2)));
|
|
|
|
assign(D_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkexpr(t3), mkU64(0x3)),
|
|
mkU64(0x0),
|
|
mkU64(0x3)));
|
|
|
|
assign(E_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkexpr(t3), mkU64(0x4)),
|
|
mkU64(0x0),
|
|
mkU64(0x4)));
|
|
|
|
assign(F_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkexpr(t3), mkU64(0x5)),
|
|
mkU64(0x0),
|
|
mkU64(0x5)));
|
|
|
|
assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x7)),
|
|
mkU64(0x1),
|
|
mkU64(0x0)));
|
|
|
|
/* Store X_byte on the right place. */
|
|
store(mkexpr(t2), mkexpr(H_byte));
|
|
store(binop(Iop_Add64, mkexpr(t2), mkexpr(G_pos)), mkexpr(G_byte));
|
|
store(binop(Iop_Sub64, mkexpr(t1), mkexpr(F_pos)), mkexpr(F_byte));
|
|
store(binop(Iop_Sub64, mkexpr(t1), mkexpr(E_pos)), mkexpr(E_byte));
|
|
store(binop(Iop_Sub64, mkexpr(t1), mkexpr(D_pos)), mkexpr(D_byte));
|
|
store(binop(Iop_Sub64, mkexpr(t1), mkexpr(C_pos)), mkexpr(C_byte));
|
|
store(binop(Iop_Sub64, mkexpr(t1), mkexpr(B_pos)), mkexpr(B_byte));
|
|
store(mkexpr(t1), mkexpr(A_byte));
|
|
|
|
#else /* _MIPSEB */
|
|
/* Calculate X_byte position. */
|
|
assign(B_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x7)),
|
|
mkU64(0x0),
|
|
mkU64(0x1)));
|
|
|
|
assign(C_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkexpr(t3), mkU64(0x6)),
|
|
mkU64(0x2),
|
|
mkU64(0x0)));
|
|
|
|
assign(D_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkexpr(t3), mkU64(0x5)),
|
|
mkU64(0x3),
|
|
mkU64(0x0)));
|
|
|
|
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)));
|
|
|
|
assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x0)),
|
|
mkU64(0x6),
|
|
mkU64(0x7)));
|
|
|
|
/* Store X_byte on the right place. */
|
|
store(binop(Iop_Add64, mkexpr(t2), mkU64(0x7)), mkexpr(H_byte));
|
|
store(binop(Iop_Add64, mkexpr(t2), mkexpr(G_pos)), mkexpr(G_byte));
|
|
store(binop(Iop_Add64, mkexpr(t1), mkexpr(F_pos)), mkexpr(F_byte));
|
|
store(binop(Iop_Add64, mkexpr(t1), mkexpr(E_pos)), mkexpr(E_byte));
|
|
store(binop(Iop_Add64, mkexpr(t1), mkexpr(D_pos)), mkexpr(D_byte));
|
|
store(binop(Iop_Add64, mkexpr(t1), mkexpr(C_pos)), mkexpr(C_byte));
|
|
store(binop(Iop_Add64, mkexpr(t1), mkexpr(B_pos)), mkexpr(B_byte));
|
|
store(mkexpr(t1), mkexpr(A_byte));
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
|
|
case 0x2D: {
|
|
/* SDR rt, offset(base) - MIPS64 */
|
|
vassert(mode64);
|
|
DIP("sdr r%u, %u(r%u)", rt, imm, rs);
|
|
IRTemp A_byte = newTemp(Ity_I8);
|
|
IRTemp B_byte = newTemp(Ity_I8);
|
|
IRTemp C_byte = newTemp(Ity_I8);
|
|
IRTemp D_byte = newTemp(Ity_I8);
|
|
IRTemp E_byte = newTemp(Ity_I8);
|
|
IRTemp F_byte = newTemp(Ity_I8);
|
|
IRTemp G_byte = newTemp(Ity_I8);
|
|
IRTemp H_byte = newTemp(Ity_I8);
|
|
IRTemp B_pos = newTemp(Ity_I64);
|
|
IRTemp C_pos = newTemp(Ity_I64);
|
|
IRTemp D_pos = newTemp(Ity_I64);
|
|
IRTemp E_pos = newTemp(Ity_I64);
|
|
IRTemp F_pos = newTemp(Ity_I64);
|
|
IRTemp G_pos = newTemp(Ity_I64);
|
|
|
|
/* H byte */
|
|
assign(H_byte, getByteFromReg(rt, 0));
|
|
/* G byte */
|
|
assign(G_byte, getByteFromReg(rt, 1));
|
|
/* F byte */
|
|
assign(F_byte, getByteFromReg(rt, 2));
|
|
/* E byte */
|
|
assign(E_byte, getByteFromReg(rt, 3));
|
|
/* D byte */
|
|
assign(D_byte, getByteFromReg(rt, 4));
|
|
/* C byte */
|
|
assign(C_byte, getByteFromReg(rt, 5));
|
|
/* B byte */
|
|
assign(B_byte, getByteFromReg(rt, 6));
|
|
/* A byte */
|
|
assign(A_byte, getByteFromReg(rt, 7));
|
|
|
|
/* t1 = addr */
|
|
t1 = newTemp(Ity_I64);
|
|
assign(t1, binop(Iop_Add64, getIReg(rs), mkU64(extend_s_16to64(imm))));
|
|
|
|
/* t2 = word addr */
|
|
t2 = newTemp(Ity_I64);
|
|
assign(t2, binop(Iop_And64, mkexpr(t1), mkU64(0xFFFFFFFFFFFFFFF8ULL)));
|
|
|
|
/* t3 = addr mod 7 */
|
|
t3 = newTemp(Ity_I64);
|
|
assign(t3, binop(Iop_And64, mkexpr(t1), mkU64(0x7)));
|
|
|
|
#if defined (_MIPSEL)
|
|
/* Calculate X_byte position. */
|
|
assign(B_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkU64(0x1), mkexpr(t3)),
|
|
mkU64(0x0),
|
|
mkU64(0x6)));
|
|
|
|
assign(C_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkU64(0x2), mkexpr(t3)),
|
|
mkU64(0x0),
|
|
mkU64(0x5)));
|
|
|
|
assign(D_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkU64(0x3), mkexpr(t3)),
|
|
mkU64(0x0),
|
|
mkU64(0x4)));
|
|
|
|
assign(E_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkU64(0x4), mkexpr(t3)),
|
|
mkU64(0x0),
|
|
mkU64(0x3)));
|
|
|
|
assign(F_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkU64(0x5), mkexpr(t3)),
|
|
mkU64(0x0),
|
|
mkU64(0x2)));
|
|
|
|
assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x7)),
|
|
mkU64(0x0),
|
|
mkU64(0x1)));
|
|
|
|
/* Store X_byte on the right place. */
|
|
store(binop(Iop_Add64, mkexpr(t2), mkU64(0x7)), mkexpr(A_byte));
|
|
store(binop(Iop_Add64, mkexpr(t1), mkexpr(B_pos)), mkexpr(B_byte));
|
|
store(binop(Iop_Add64, mkexpr(t1), mkexpr(C_pos)), mkexpr(C_byte));
|
|
store(binop(Iop_Add64, mkexpr(t1), mkexpr(D_pos)), mkexpr(D_byte));
|
|
store(binop(Iop_Add64, mkexpr(t1), mkexpr(E_pos)), mkexpr(E_byte));
|
|
store(binop(Iop_Add64, mkexpr(t1), mkexpr(F_pos)), mkexpr(F_byte));
|
|
store(binop(Iop_Add64, mkexpr(t1), mkexpr(G_pos)), mkexpr(G_byte));
|
|
store(mkexpr(t1), mkexpr(H_byte));
|
|
|
|
#else /* _MIPSEB */
|
|
/* Calculate X_byte position. */
|
|
assign(B_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkU64(0x5), mkexpr(t3)),
|
|
mkU64(0x6),
|
|
mkU64(0x0)));
|
|
|
|
assign(C_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkU64(0x4), mkexpr(t3)),
|
|
mkU64(0x5),
|
|
mkU64(0x0)));
|
|
|
|
assign(D_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkU64(0x3), mkexpr(t3)),
|
|
mkU64(0x4),
|
|
mkU64(0x0)));
|
|
|
|
assign(E_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkU64(0x2), mkexpr(t3)),
|
|
mkU64(0x3),
|
|
mkU64(0x0)));
|
|
|
|
assign(F_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkU64(0x1), mkexpr(t3)),
|
|
mkU64(0x2),
|
|
mkU64(0x0)));
|
|
|
|
assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x0)),
|
|
mkU64(0x0),
|
|
mkU64(0x1)));
|
|
|
|
/* Store X_byte on the right place. */
|
|
store(mkexpr(t2), mkexpr(A_byte));
|
|
store(binop(Iop_Sub64, mkexpr(t1), mkexpr(B_pos)), mkexpr(B_byte));
|
|
store(binop(Iop_Sub64, mkexpr(t1), mkexpr(C_pos)), mkexpr(C_byte));
|
|
store(binop(Iop_Sub64, mkexpr(t1), mkexpr(D_pos)), mkexpr(D_byte));
|
|
store(binop(Iop_Sub64, mkexpr(t1), mkexpr(E_pos)), mkexpr(E_byte));
|
|
store(binop(Iop_Sub64, mkexpr(t1), mkexpr(F_pos)), mkexpr(F_byte));
|
|
store(binop(Iop_Sub64, mkexpr(t1), mkexpr(G_pos)), mkexpr(G_byte));
|
|
store(mkexpr(t1), mkexpr(H_byte));
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
case 0x28: /* SB */
|
|
DIP("sb r%u, %u(r%u)", rt, imm, rs);
|
|
LOAD_STORE_PATTERN;
|
|
store(mkexpr(t1), narrowTo(Ity_I8, getIReg(rt)));
|
|
break;
|
|
|
|
case 0x29: /* SH */
|
|
DIP("sh r%u, %u(r%u)", rt, imm, rs);
|
|
LOAD_STORE_PATTERN;
|
|
store(mkexpr(t1), narrowTo(Ity_I16, getIReg(rt)));
|
|
break;
|
|
|
|
case 0x2A: /* SWL */
|
|
DIP("swl r%u, %u(r%u)", rt, imm, rs);
|
|
if (mode64) {
|
|
IRTemp E_byte = newTemp(Ity_I8);
|
|
IRTemp F_byte = newTemp(Ity_I8);
|
|
IRTemp G_byte = newTemp(Ity_I8);
|
|
IRTemp H_byte = newTemp(Ity_I8);
|
|
IRTemp F_pos = newTemp(Ity_I64);
|
|
IRTemp G_pos = newTemp(Ity_I64);
|
|
|
|
/* H byte */
|
|
assign(H_byte, getByteFromReg(rt, 0));
|
|
/* G byte */
|
|
assign(G_byte, getByteFromReg(rt, 1));
|
|
/* F byte */
|
|
assign(F_byte, getByteFromReg(rt, 2));
|
|
/* E byte */
|
|
assign(E_byte, getByteFromReg(rt, 3));
|
|
|
|
/* t1 = addr */
|
|
t1 = newTemp(Ity_I64);
|
|
assign(t1, binop(Iop_Add64, getIReg(rs), mkU64(extend_s_16to64(imm))));
|
|
|
|
/* t2 = word addr */
|
|
t2 = newTemp(Ity_I64);
|
|
assign(t2, binop(Iop_And64, mkexpr(t1), mkU64(0xFFFFFFFFFFFFFFFCULL)));
|
|
|
|
/* t3 = addr mod 4 */
|
|
t3 = newTemp(Ity_I64);
|
|
assign(t3, binop(Iop_And64, mkexpr(t1), mkU64(0x3)));
|
|
|
|
#if defined (_MIPSEL)
|
|
/* Calculate X_byte position. */
|
|
assign(F_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x0)),
|
|
mkU64(0x0),
|
|
mkU64(0x1)));
|
|
|
|
assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x3)),
|
|
mkU64(0x1),
|
|
mkU64(0x0)));
|
|
|
|
/* Store X_byte on the right place. */
|
|
store(mkexpr(t2), mkexpr(H_byte));
|
|
store(binop(Iop_Add64, mkexpr(t2), mkexpr(G_pos)), mkexpr(G_byte));
|
|
store(binop(Iop_Sub64, mkexpr(t1), mkexpr(F_pos)), mkexpr(F_byte));
|
|
store(mkexpr(t1), mkexpr(E_byte));
|
|
|
|
#else /* _MIPSEB */
|
|
/* Calculate X_byte position. */
|
|
assign(F_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x3)),
|
|
mkU64(0x0),
|
|
mkU64(0x1)));
|
|
|
|
assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x0)),
|
|
mkU64(0x2),
|
|
mkU64(0x3)));
|
|
|
|
store(binop(Iop_Add64, mkexpr(t2), mkU64(3)), mkexpr(H_byte));
|
|
store(binop(Iop_Add64, mkexpr(t2), mkexpr(G_pos)), mkexpr(G_byte));
|
|
store(binop(Iop_Add64, mkexpr(t1), mkexpr(F_pos)), mkexpr(F_byte));
|
|
store(mkexpr(t1), mkexpr(E_byte));
|
|
|
|
#endif
|
|
} else {
|
|
IRTemp E_byte = newTemp(Ity_I8);
|
|
IRTemp F_byte = newTemp(Ity_I8);
|
|
IRTemp G_byte = newTemp(Ity_I8);
|
|
IRTemp H_byte = newTemp(Ity_I8);
|
|
IRTemp F_pos = newTemp(Ity_I32);
|
|
IRTemp G_pos = newTemp(Ity_I32);
|
|
|
|
/* H byte */
|
|
assign(H_byte, getByteFromReg(rt, 0));
|
|
/* G byte */
|
|
assign(G_byte, getByteFromReg(rt, 1));
|
|
/* F byte */
|
|
assign(F_byte, getByteFromReg(rt, 2));
|
|
/* E byte */
|
|
assign(E_byte, getByteFromReg(rt, 3));
|
|
|
|
/* t1 = addr */
|
|
t1 = newTemp(Ity_I32);
|
|
assign(t1, binop(Iop_Add32, getIReg(rs), mkU32(extend_s_16to32(imm))));
|
|
|
|
/* t2 = word addr */
|
|
t2 = newTemp(Ity_I32);
|
|
assign(t2, binop(Iop_And32, mkexpr(t1), mkU32(0xFFFFFFFCULL)));
|
|
|
|
/* t3 = addr mod 4 */
|
|
t3 = newTemp(Ity_I32);
|
|
assign(t3, binop(Iop_And32, mkexpr(t1), mkU32(0x3)));
|
|
|
|
#if defined (_MIPSEL)
|
|
/* Calculate X_byte position. */
|
|
assign(F_pos, IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t3), mkU32(0x0)),
|
|
mkU32(0x0),
|
|
mkU32(0x1)));
|
|
|
|
assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t3), mkU32(0x3)),
|
|
mkU32(0x1),
|
|
mkU32(0x0)));
|
|
|
|
/* Store X_byte on the right place. */
|
|
store(mkexpr(t2), mkexpr(H_byte));
|
|
store(binop(Iop_Add32, mkexpr(t2), mkexpr(G_pos)), mkexpr(G_byte));
|
|
store(binop(Iop_Sub32, mkexpr(t1), mkexpr(F_pos)), mkexpr(F_byte));
|
|
store(mkexpr(t1), mkexpr(E_byte));
|
|
|
|
#else /* _MIPSEB */
|
|
/* Calculate X_byte position. */
|
|
assign(F_pos, IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t3), mkU32(0x3)),
|
|
mkU32(0x0),
|
|
mkU32(0x1)));
|
|
|
|
assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t3), mkU32(0x0)),
|
|
mkU32(0x2),
|
|
mkU32(0x3)));
|
|
|
|
store(binop(Iop_Add32, mkexpr(t2), mkU32(3)), mkexpr(H_byte));
|
|
store(binop(Iop_Add32, mkexpr(t2), mkexpr(G_pos)), mkexpr(G_byte));
|
|
store(binop(Iop_Add32, mkexpr(t1), mkexpr(F_pos)), mkexpr(F_byte));
|
|
store(mkexpr(t1), mkexpr(E_byte));
|
|
|
|
#endif
|
|
}
|
|
break;
|
|
|
|
case 0x2E: /* SWR */
|
|
DIP("swr r%u, %u(r%u)", rt, imm, rs);
|
|
if (mode64) {
|
|
IRTemp E_byte = newTemp(Ity_I8);
|
|
IRTemp F_byte = newTemp(Ity_I8);
|
|
IRTemp G_byte = newTemp(Ity_I8);
|
|
IRTemp H_byte = newTemp(Ity_I8);
|
|
IRTemp F_pos = newTemp(Ity_I64);
|
|
IRTemp G_pos = newTemp(Ity_I64);
|
|
|
|
/* H byte */
|
|
assign(H_byte, getByteFromReg(rt, 0));
|
|
/* G byte */
|
|
assign(G_byte, getByteFromReg(rt, 1));
|
|
/* F byte */
|
|
assign(F_byte, getByteFromReg(rt, 2));
|
|
/* E byte */
|
|
assign(E_byte, getByteFromReg(rt, 3));
|
|
|
|
/* t1 = addr */
|
|
t1 = newTemp(Ity_I64);
|
|
assign(t1, binop(Iop_Add64, getIReg(rs), mkU64(extend_s_16to64(imm))));
|
|
|
|
/* t2 = word addr */
|
|
t2 = newTemp(Ity_I64);
|
|
assign(t2, binop(Iop_And64, mkexpr(t1), mkU64(0xFFFFFFFFFFFFFFFCULL)));
|
|
|
|
/* t3 = addr mod 4 */
|
|
t3 = newTemp(Ity_I64);
|
|
assign(t3, binop(Iop_And64, mkexpr(t1), mkU64(0x3)));
|
|
|
|
#if defined (_MIPSEL)
|
|
/* Calculate X_byte position. */
|
|
assign(F_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x0)),
|
|
mkU64(0x2),
|
|
mkU64(0x3)));
|
|
|
|
assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x3)),
|
|
mkU64(0x0),
|
|
mkU64(0x1)));
|
|
|
|
/* Store X_byte on the right place. */
|
|
store(binop(Iop_Add64, mkexpr(t2), mkU64(0x3)), mkexpr(E_byte));
|
|
store(binop(Iop_Add64, mkexpr(t2), mkexpr(F_pos)), mkexpr(F_byte));
|
|
store(binop(Iop_Add64, mkexpr(t1), mkexpr(G_pos)), mkexpr(G_byte));
|
|
store(mkexpr(t1), mkexpr(H_byte));
|
|
|
|
#else /* _MIPSEB */
|
|
/* Calculate X_byte position. */
|
|
assign(F_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x3)),
|
|
mkU64(0x1),
|
|
mkU64(0x0)));
|
|
|
|
assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x0)),
|
|
mkU64(0x0),
|
|
mkU64(0x1)));
|
|
|
|
/* Store X_byte on the right place. */
|
|
store(mkexpr(t2), mkexpr(E_byte));
|
|
store(binop(Iop_Add64, mkexpr(t2), mkexpr(F_pos)), mkexpr(F_byte));
|
|
store(binop(Iop_Sub64, mkexpr(t1), mkexpr(G_pos)), mkexpr(G_byte));
|
|
store(mkexpr(t1), mkexpr(H_byte));
|
|
#endif
|
|
} else {
|
|
IRTemp E_byte = newTemp(Ity_I8);
|
|
IRTemp F_byte = newTemp(Ity_I8);
|
|
IRTemp G_byte = newTemp(Ity_I8);
|
|
IRTemp H_byte = newTemp(Ity_I8);
|
|
IRTemp F_pos = newTemp(Ity_I32);
|
|
IRTemp G_pos = newTemp(Ity_I32);
|
|
|
|
/* H byte */
|
|
assign(H_byte, getByteFromReg(rt, 0));
|
|
/* G byte */
|
|
assign(G_byte, getByteFromReg(rt, 1));
|
|
/* F byte */
|
|
assign(F_byte, getByteFromReg(rt, 2));
|
|
/* E byte */
|
|
assign(E_byte, getByteFromReg(rt, 3));
|
|
|
|
/* t1 = addr */
|
|
t1 = newTemp(Ity_I32);
|
|
assign(t1, binop(Iop_Add32, getIReg(rs), mkU32(extend_s_16to32(imm))));
|
|
|
|
/* t2 = word addr */
|
|
t2 = newTemp(Ity_I32);
|
|
assign(t2, binop(Iop_And32, mkexpr(t1), mkU32(0xFFFFFFFCULL)));
|
|
|
|
/* t3 = addr mod 4 */
|
|
t3 = newTemp(Ity_I32);
|
|
assign(t3, binop(Iop_And32, mkexpr(t1), mkU32(0x3)));
|
|
|
|
#if defined (_MIPSEL)
|
|
/* Calculate X_byte position. */
|
|
assign(F_pos, IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t3), mkU32(0x0)),
|
|
mkU32(0x2),
|
|
mkU32(0x3)));
|
|
|
|
assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t3), mkU32(0x3)),
|
|
mkU32(0x0),
|
|
mkU32(0x1)));
|
|
|
|
/* Store X_byte on the right place. */
|
|
store(binop(Iop_Add32, mkexpr(t2), mkU32(0x3)), mkexpr(E_byte));
|
|
store(binop(Iop_Add32, mkexpr(t2), mkexpr(F_pos)), mkexpr(F_byte));
|
|
store(binop(Iop_Add32, mkexpr(t1), mkexpr(G_pos)), mkexpr(G_byte));
|
|
store(mkexpr(t1), mkexpr(H_byte));
|
|
|
|
#else /* _MIPSEB */
|
|
/* Calculate X_byte position. */
|
|
assign(F_pos, IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t3), mkU32(0x3)),
|
|
mkU32(0x1),
|
|
mkU32(0x0)));
|
|
|
|
assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t3), mkU32(0x0)),
|
|
mkU32(0x0),
|
|
mkU32(0x1)));
|
|
|
|
/* Store X_byte on the right place. */
|
|
store(mkexpr(t2), mkexpr(E_byte));
|
|
store(binop(Iop_Add32, mkexpr(t2), mkexpr(F_pos)), mkexpr(F_byte));
|
|
store(binop(Iop_Sub32, mkexpr(t1), mkexpr(G_pos)), mkexpr(G_byte));
|
|
store(mkexpr(t1), mkexpr(H_byte));
|
|
#endif
|
|
}
|
|
break;
|
|
|
|
case 0x1C: /* Special2 */
|
|
switch (function) {
|
|
/* Cavium Specific instructions */
|
|
case 0x03: case 0x32: case 0x33: /* DMUL, CINS , CINS32 */
|
|
case 0x3A: case 0x3B: case 0x2B: /* EXT, EXT32, SNE */
|
|
/* CVM Compare Instructions */
|
|
case 0x2A: case 0x2E: case 0x2F: /* SEQ, SEQI, SNEI */
|
|
/* CPU Load, Store, Memory, and Control Instructions */
|
|
case 0x18: case 0x19: /* SAA, SAAD */
|
|
case 0x1F: /* LAA, LAAD, LAI, LAID */
|
|
case 0x28: case 0x2C: case 0x2D: /* BADDU, POP, DPOP */
|
|
if (VEX_MIPS_COMP_ID(archinfo->hwcaps) == VEX_PRID_COMP_CAVIUM) {
|
|
if (dis_instr_CVM(cins))
|
|
break;
|
|
goto decode_failure;
|
|
} else {
|
|
goto decode_failure;
|
|
}
|
|
break;
|
|
|
|
case 0x02: { /* MUL */
|
|
DIP("mul r%u, r%u, r%u", rd, rs, rt);
|
|
if (mode64) {
|
|
IRTemp tmpRs32 = newTemp(Ity_I32);
|
|
IRTemp tmpRt32 = newTemp(Ity_I32);
|
|
IRTemp tmpRes = newTemp(Ity_I32);
|
|
|
|
assign(tmpRs32, mkNarrowTo32(ty, getIReg(rs)));
|
|
assign(tmpRt32, mkNarrowTo32(ty, getIReg(rt)));
|
|
assign(tmpRes, binop(Iop_Mul32,
|
|
mkexpr(tmpRs32), mkexpr(tmpRt32)));
|
|
putIReg(rd, mkWidenFrom32(ty, mkexpr(tmpRes), True));
|
|
} else
|
|
putIReg(rd, binop(Iop_Mul32, getIReg(rs), getIReg(rt)));
|
|
break;
|
|
}
|
|
|
|
case 0x00: { /* MADD */
|
|
if (mode64) {
|
|
DIP("madd r%u, r%u", 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(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)));
|
|
|
|
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 (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) {
|
|
/* 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%u, r%u", 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(t3, binop(Iop_MullS32, 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)));
|
|
|
|
putHI(binop(Iop_Add32, mkexpr(t6), unop(Iop_64HIto32,
|
|
mkexpr(t3))));
|
|
putLO(mkexpr(t4));
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 0x01: { /* MADDU */
|
|
if (mode64) {
|
|
DIP("maddu r%u, r%u", 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(t3, binop(Iop_MullU32, 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)));
|
|
|
|
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 (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) {
|
|
/* 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%u, r%u", 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(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)));
|
|
|
|
putHI(binop(Iop_Add32, mkexpr(t6), unop(Iop_64HIto32,
|
|
mkexpr(t3))));
|
|
putLO(mkexpr(t4));
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 0x04: { /* MSUB */
|
|
if (mode64) {
|
|
DIP("msub r%u, r%u", 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(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_Sub64, mkexpr(t4), mkexpr(t3)));
|
|
|
|
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 (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) {
|
|
/* 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%u, r%u", 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(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)));
|
|
|
|
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)));
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 0x05: { /* MSUBU */
|
|
if (mode64) {
|
|
DIP("msubu r%u, r%u", 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(t3, binop(Iop_MullU32, mkNarrowTo32(ty, getIReg(rs)),
|
|
mkNarrowTo32(ty, getIReg(rt))));
|
|
|
|
assign(t4, binop(Iop_32HLto64, mkexpr(t1), mkexpr(t2)));
|
|
assign(t5, binop(Iop_Sub64, mkexpr(t4), mkexpr(t3)));
|
|
|
|
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 (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) {
|
|
/* 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%u, r%u", 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(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)));
|
|
|
|
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)));
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 0x6: /* dmul MIPS64 - Netlogic */
|
|
DIP("dmul r%u, r%u, r%u", rd, rs, rt);
|
|
t0 = newTemp(Ity_I128);
|
|
|
|
assign(t0, binop(Iop_MullU64, getIReg(rs), getIReg(rt)));
|
|
|
|
putIReg(rd, unop(Iop_128to64, mkexpr(t0)));
|
|
break;
|
|
|
|
case 0x10: /* LDADDW - Swap Word - Netlogic */
|
|
DIP("ldaddw r%u, r%u", rt, rs);
|
|
t0 = newTemp(Ity_I32);
|
|
t1 = newTemp(Ity_I32);
|
|
t2 = newTemp(Ity_I32);
|
|
t3 = newTemp(Ity_I64);
|
|
t4 = newTemp(Ity_I32);
|
|
t5 = newTemp(Ity_I32);
|
|
t6 = newTemp(Ity_I32);
|
|
|
|
/* v = GPR[rt] */
|
|
assign(t0, mkNarrowTo32(ty, getIReg(rt)));
|
|
|
|
/* GPR[rt] = memory[base]; */
|
|
assign(t1, load(Ity_I32, getIReg(rs)));
|
|
putIReg(rt, mkWidenFrom32(ty, mkexpr(t1), True));
|
|
|
|
/* memory[base] = memory[base] + v; */
|
|
store(getIReg(rs), binop(Iop_Add32, mkexpr(t0), mkexpr(t1)));
|
|
break;
|
|
|
|
case 0x12: /* LDADDD - Swap Word - Netlogic */
|
|
DIP("ldaddw r%u, r%u", rt, rs);
|
|
t0 = newTemp(Ity_I64);
|
|
t1 = newTemp(Ity_I64);
|
|
|
|
/* v = GPR[rt] */
|
|
assign(t0, getIReg(rt));
|
|
|
|
/* GPR[rt] = memory[base]; */
|
|
assign(t1, load(Ity_I64, getIReg(rs)));
|
|
putIReg(rt, mkexpr(t1));
|
|
|
|
/* memory[base] = memory[base] + v; */
|
|
store(getIReg(rs), binop(Iop_Add64, mkexpr(t0), mkexpr(t1)));
|
|
break;
|
|
|
|
case 0x14: /* SWAPW - Swap Word - Netlogic */
|
|
DIP("swapw r%u, r%u", rt, rs);
|
|
t0 = newTemp(Ity_I32);
|
|
t1 = newTemp(Ity_I32);
|
|
assign(t0, mkNarrowTo32(ty, getIReg(rt)));
|
|
assign(t1, load(Ity_I32, getIReg(rs)));
|
|
putIReg(rt, mkWidenFrom32(ty, mkexpr(t1), True));
|
|
store(getIReg(rs), mkexpr(t0));
|
|
break;
|
|
|
|
case 0x16: /* SWAPD - Swap Double - Netlogic */
|
|
DIP("swapw r%u, r%u", rt, rs);
|
|
t0 = newTemp(Ity_I64);
|
|
t1 = newTemp(Ity_I64);
|
|
assign(t0, getIReg(rt));
|
|
assign(t1, load(Ity_I64, getIReg(rs)));
|
|
putIReg(rt, mkexpr(t1));
|
|
store(getIReg(rs), mkexpr(t0));
|
|
break;
|
|
|
|
case 0x20: { /* CLZ */
|
|
DIP("clz r%u, r%u", rd, rs);
|
|
if (mode64) {
|
|
IRTemp tmpClz32 = newTemp(Ity_I32);
|
|
IRTemp tmpRs32 = newTemp(Ity_I32);
|
|
|
|
assign(tmpRs32, mkNarrowTo32(ty, getIReg(rs)));
|
|
assign(tmpClz32, unop(Iop_Clz32, mkexpr(tmpRs32)));
|
|
putIReg(rd, mkWidenFrom32(ty, mkexpr(tmpClz32), True));
|
|
} else {
|
|
t1 = newTemp(Ity_I1);
|
|
assign(t1, binop(Iop_CmpEQ32, getIReg(rs), mkU32(0)));
|
|
putIReg(rd, IRExpr_ITE(mkexpr(t1),
|
|
mkU32(0x00000020),
|
|
unop(Iop_Clz32, getIReg(rs))));
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 0x21: { /* CLO */
|
|
DIP("clo r%u, r%u", rd, rs);
|
|
if (mode64) {
|
|
IRTemp tmpClo32 = newTemp(Ity_I32);
|
|
IRTemp tmpRs32 = newTemp(Ity_I32);
|
|
assign(tmpRs32, mkNarrowTo32(ty, getIReg(rs)));
|
|
|
|
t1 = newTemp(Ity_I1);
|
|
assign(t1, binop(Iop_CmpEQ32, mkexpr(tmpRs32), mkU32(0xffffffff)));
|
|
assign(tmpClo32, IRExpr_ITE(mkexpr(t1),
|
|
mkU32(0x00000020),
|
|
unop(Iop_Clz32, unop(Iop_Not32, mkexpr(tmpRs32)))));
|
|
|
|
putIReg(rd, mkWidenFrom32(ty, mkexpr(tmpClo32), True));
|
|
break;
|
|
} else {
|
|
t1 = newTemp(Ity_I1);
|
|
assign(t1, binop(Iop_CmpEQ32, getIReg(rs), mkU32(0xffffffff)));
|
|
putIReg(rd, IRExpr_ITE(mkexpr(t1),
|
|
mkU32(0x00000020),
|
|
unop(Iop_Clz32,
|
|
unop(Iop_Not32, getIReg(rs)))));
|
|
break;
|
|
}
|
|
}
|
|
|
|
case 0x24: /* Count Leading Zeros in Doubleword - DCLZ; MIPS64 */
|
|
DIP("dclz r%u, r%u", rd, rs);
|
|
t1 = newTemp(Ity_I1);
|
|
assign(t1, binop(Iop_CmpEQ64, getIReg(rs), mkU64(0)));
|
|
putIReg(rd, IRExpr_ITE(mkexpr(t1),
|
|
mkU64(0x00000040),
|
|
unop(Iop_Clz64, getIReg(rs))));
|
|
break;
|
|
|
|
case 0x25: /* Count Leading Ones in Doubleword - DCLO; MIPS64 */
|
|
DIP("dclo r%u, r%u", rd, rs);
|
|
t1 = newTemp(Ity_I1);
|
|
assign(t1, binop(Iop_CmpEQ64, getIReg(rs),
|
|
mkU64(0xffffffffffffffffULL)));
|
|
putIReg(rd, IRExpr_ITE(mkexpr(t1),
|
|
mkU64(0x40),
|
|
unop(Iop_Clz64, unop(Iop_Not64,
|
|
getIReg(rs)))));
|
|
break;
|
|
|
|
default:
|
|
goto decode_failure;
|
|
}
|
|
break;
|
|
|
|
case 0x1F: /* Special3 */
|
|
switch (function) {
|
|
case 0x01: {
|
|
/* Doubleword Extract Bit Field - DEXTM; MIPS64r2 */
|
|
msb = get_msb(cins);
|
|
lsb = get_lsb(cins);
|
|
size = msb + 1;
|
|
UInt srcPos = lsb;
|
|
UInt dstSz = msb + 33;
|
|
t1 = newTemp(Ity_I64);
|
|
DIP("dextm r%u, r%u, %u, %u", rt, rs, lsb, msb + 1);
|
|
|
|
UChar lsAmt = 64 - (srcPos + dstSz); /* left shift amount; */
|
|
UChar rsAmt = 64 - dstSz; /* right shift amount; */
|
|
|
|
assign(t1, binop(Iop_Shl64, getIReg(rs), mkU8(lsAmt)));
|
|
putIReg(rt, binop(Iop_Shr64, mkexpr(t1), mkU8(rsAmt)));
|
|
|
|
break;
|
|
}
|
|
case 0x02: {
|
|
/* Doubleword Extract Bit Field Upper - DEXTU; MIPS64r2 */
|
|
msb = get_msb(cins);
|
|
lsb = get_lsb(cins);
|
|
size = msb + 1;
|
|
UInt srcPos = lsb + 32;
|
|
UInt dstSz = msb + 1;
|
|
DIP("dextu r%u, r%u, %u, %u", rt, rs, srcPos, dstSz);
|
|
t1 = newTemp(Ity_I64);
|
|
|
|
vassert(srcPos >= 32 && srcPos < 64);
|
|
vassert(dstSz > 0 && dstSz <= 32);
|
|
vassert((srcPos + dstSz) > 32 && (srcPos + dstSz) <= 64);
|
|
|
|
UChar lsAmt = 64 - (srcPos + dstSz); /* left shift amount; */
|
|
UChar rsAmt = 64 - dstSz; /* right shift amount; */
|
|
|
|
assign(t1, binop(Iop_Shl64, getIReg(rs), mkU8(lsAmt)));
|
|
putIReg(rt, binop(Iop_Shr64, mkexpr(t1), mkU8(rsAmt)));
|
|
break;
|
|
}
|
|
case 0x05: {
|
|
/* Doubleword Insert Bit Field Middle - DINSM; MIPS64r2 */
|
|
msb = get_msb(cins);
|
|
lsb = get_lsb(cins);
|
|
size = msb + 1;
|
|
UInt dstPos = lsb;
|
|
UInt srcSz = msb - lsb + 33;
|
|
t1 = newTemp(ty);
|
|
t2 = newTemp(ty);
|
|
t3 = newTemp(ty);
|
|
t4 = newTemp(ty);
|
|
IRTemp tmpT1 = newTemp(ty);
|
|
IRTemp tmpT2 = newTemp(ty);
|
|
IRTemp tmpT3 = newTemp(ty);
|
|
IRTemp tmpT4 = newTemp(ty);
|
|
IRTemp tmpT5 = newTemp(ty);
|
|
IRTemp tmpT6 = newTemp(ty);
|
|
IRTemp tmpT7 = newTemp(ty);
|
|
IRTemp tmpRs = newTemp(ty);
|
|
IRTemp tmpRt = newTemp(ty);
|
|
IRTemp tmpRd = newTemp(ty);
|
|
|
|
assign(tmpRs, getIReg(rs));
|
|
assign(tmpRt, getIReg(rt));
|
|
DIP("dinsm r%u, r%u, %u, %u", rt, rs, lsb, msb);
|
|
|
|
UChar lsAmt = dstPos + srcSz - 1; /* left shift amount; */
|
|
UChar rsAmt = dstPos + srcSz - 1; /* right shift amount; */
|
|
|
|
assign(t1, binop(Iop_Shr64, mkexpr(tmpRt), mkU8(rsAmt)));
|
|
assign(tmpT1, binop(Iop_Shr64, mkexpr(t1), mkU8(1)));
|
|
assign(t2, binop(Iop_Shl64, mkexpr(tmpT1), mkU8(lsAmt)));
|
|
assign(tmpT2, binop(Iop_Shl64, mkexpr(t2), mkU8(1)));
|
|
|
|
lsAmt = 63 - dstPos; /* left shift amount; */
|
|
rsAmt = 63 - dstPos; /* right shift amount; */
|
|
|
|
assign(t3, binop(Iop_Shl64, mkexpr(tmpRt), mkU8(lsAmt)));
|
|
assign(tmpT3, binop(Iop_Shl64, mkexpr(t3), mkU8(1)));
|
|
assign(t4, binop(Iop_Shr64, mkexpr(tmpT3), mkU8(rsAmt)));
|
|
assign(tmpT4, binop(Iop_Shr64, mkexpr(t4), mkU8(1)));
|
|
|
|
/* extract size from src register */
|
|
lsAmt = 64 - srcSz; /* left shift amount; */
|
|
rsAmt = 64 - (lsb + srcSz); /* right shift amount; */
|
|
|
|
assign(tmpT5, binop(Iop_Shl64, mkexpr(tmpRs), mkU8(lsAmt)));
|
|
assign(tmpT6, binop(Iop_Shr64, mkexpr(tmpT5), mkU8(rsAmt)));
|
|
|
|
assign(tmpT7, binop(Iop_Or64, mkexpr(tmpT2), mkexpr(tmpT4)));
|
|
assign(tmpRd, binop(Iop_Or64, mkexpr(tmpT6), mkexpr(tmpT7)));
|
|
putIReg(rt, mkexpr(tmpRd));
|
|
break;
|
|
}
|
|
case 0x06: {
|
|
/* Doubleword Insert Bit Field Upper - DINSU; MIPS64r2 */
|
|
msb = get_msb(cins);
|
|
lsb = get_lsb(cins);
|
|
size = msb + 1;
|
|
UInt dstPos = lsb + 32;
|
|
UInt srcSz = msb - lsb + 1;
|
|
IRTemp tmpT1 = newTemp(ty);
|
|
IRTemp tmpT2 = newTemp(ty);
|
|
IRTemp tmpT3 = newTemp(ty);
|
|
IRTemp tmpT4 = newTemp(ty);
|
|
IRTemp tmpT5 = newTemp(ty);
|
|
IRTemp tmpT6 = newTemp(ty);
|
|
IRTemp tmpT7 = newTemp(ty);
|
|
IRTemp tmpT8 = newTemp(ty);
|
|
IRTemp tmpT9 = newTemp(ty);
|
|
IRTemp tmpRs = newTemp(ty);
|
|
IRTemp tmpRt = newTemp(ty);
|
|
IRTemp tmpRd = newTemp(ty);
|
|
|
|
assign(tmpRs, getIReg(rs));
|
|
assign(tmpRt, getIReg(rt));
|
|
DIP("dinsu r%u, r%u, %u, %u", rt, rs, lsb, msb);
|
|
|
|
UChar lsAmt = 64 - srcSz; /* left shift amount; */
|
|
UChar rsAmt = 64 - (dstPos + srcSz); /* right shift amount; */
|
|
assign(tmpT1, binop(Iop_Shl64, mkexpr(tmpRs), mkU8(lsAmt)));
|
|
assign(tmpT2, binop(Iop_Shr64, mkexpr(tmpT1), mkU8(rsAmt)));
|
|
|
|
lsAmt = 64 - dstPos; /* left shift amount; */
|
|
rsAmt = 64 - dstPos; /* right shift amount; */
|
|
assign(tmpT3, binop(Iop_Shl64, mkexpr(tmpRt), mkU8(lsAmt)));
|
|
assign(tmpT4, binop(Iop_Shr64, mkexpr(tmpT3), mkU8(rsAmt)));
|
|
|
|
lsAmt = dstPos; /* left shift amount; */
|
|
rsAmt = srcSz; /* right shift amount; */
|
|
assign(tmpT5, binop(Iop_Shr64, mkexpr(tmpRt), mkU8(rsAmt)));
|
|
assign(tmpT6, binop(Iop_Shr64, mkexpr(tmpT5), mkU8(lsAmt)));
|
|
|
|
assign(tmpT7, binop(Iop_Shl64, mkexpr(tmpT6), mkU8(rsAmt)));
|
|
assign(tmpT8, binop(Iop_Shl64, mkexpr(tmpT7), mkU8(lsAmt)));
|
|
|
|
assign(tmpT9, binop(Iop_Or64, mkexpr(tmpT8), mkexpr(tmpT4)));
|
|
assign(tmpRd, binop(Iop_Or64, mkexpr(tmpT2), mkexpr(tmpT9)));
|
|
putIReg(rt, mkexpr(tmpRd));
|
|
break;
|
|
}
|
|
case 0x07: {
|
|
/* Doubleword Insert Bit Field - DINS; MIPS64r2 */
|
|
IRTemp tmp1 = newTemp(ty);
|
|
IRTemp tmpT1 = newTemp(ty);
|
|
IRTemp tmpT2 = newTemp(ty);
|
|
IRTemp tmpT3 = newTemp(ty);
|
|
IRTemp tmpT4 = newTemp(ty);
|
|
IRTemp tmpT5 = newTemp(ty);
|
|
IRTemp tmpT6 = newTemp(ty);
|
|
IRTemp tmpT7 = newTemp(ty);
|
|
IRTemp tmpT8 = newTemp(ty);
|
|
IRTemp tmpT9 = newTemp(ty);
|
|
IRTemp tmp = newTemp(ty);
|
|
IRTemp tmpRs = newTemp(ty);
|
|
IRTemp tmpRt = newTemp(ty);
|
|
IRTemp tmpRd = newTemp(ty);
|
|
|
|
assign(tmpRs, getIReg(rs));
|
|
assign(tmpRt, getIReg(rt));
|
|
|
|
msb = get_msb(cins);
|
|
lsb = get_lsb(cins);
|
|
size = msb + 1;
|
|
DIP("dins r%u, r%u, %u, %u", rt, rs, lsb,
|
|
msb - lsb + 1);
|
|
UChar lsAmt = 63 - lsb; /* left shift amount; */
|
|
UChar rsAmt = 63 - lsb; /* right shift amount; */
|
|
assign(tmp, binop(Iop_Shl64, mkexpr(tmpRt), mkU8(lsAmt)));
|
|
assign(tmpT1, binop(Iop_Shl64, mkexpr(tmp), mkU8(1)));
|
|
assign(tmp1, binop(Iop_Shr64, mkexpr(tmpT1), mkU8(rsAmt)));
|
|
assign(tmpT2, binop(Iop_Shr64, mkexpr(tmp1), mkU8(1)));
|
|
|
|
lsAmt = msb; /* left shift amount; */
|
|
rsAmt = 1; /*right shift amount; */
|
|
assign(tmpT3, binop(Iop_Shr64, mkexpr(tmpRt), mkU8(rsAmt)));
|
|
assign(tmpT4, binop(Iop_Shr64, mkexpr(tmpT3), mkU8(lsAmt)));
|
|
assign(tmpT5, binop(Iop_Shl64, mkexpr(tmpT4), mkU8(rsAmt)));
|
|
assign(tmpT6, binop(Iop_Shl64, mkexpr(tmpT5), mkU8(lsAmt)));
|
|
|
|
lsAmt = 64 - (msb - lsb + 1); /* left shift amount; */
|
|
rsAmt = 64 - (msb + 1); /* right shift amount; */
|
|
assign(tmpT7, binop(Iop_Shl64, mkexpr(tmpRs), mkU8(lsAmt)));
|
|
assign(tmpT8, binop(Iop_Shr64, mkexpr(tmpT7), mkU8(rsAmt)));
|
|
|
|
assign(tmpT9, binop(Iop_Or64, mkexpr(tmpT2), mkexpr(tmpT8)));
|
|
assign(tmpRd, binop(Iop_Or64, mkexpr(tmpT6), mkexpr(tmpT9)));
|
|
putIReg(rt, mkexpr(tmpRd));
|
|
break;
|
|
}
|
|
case 0x24: /* DBSHFL */
|
|
lsb = get_lsb(cins);
|
|
IRTemp tmpRs = newTemp(ty);
|
|
IRTemp tmpRt = newTemp(ty);
|
|
IRTemp tmpRd = newTemp(ty);
|
|
assign(tmpRs, getIReg(rs));
|
|
assign(tmpRt, getIReg(rt));
|
|
switch (lsb) {
|
|
case 0x02: { /* DSBH */
|
|
DIP("dsbh r%u, r%u", rd, rt);
|
|
IRTemp tmpT1 = newTemp(ty);
|
|
IRTemp tmpT2 = newTemp(ty);
|
|
IRTemp tmpT3 = newTemp(ty);
|
|
IRTemp tmpT4 = newTemp(ty);
|
|
IRTemp tmpT5 = newTemp(Ity_I64);
|
|
IRTemp tmpT6 = newTemp(ty);
|
|
assign(tmpT5, mkU64(0xFF00FF00FF00FF00ULL));
|
|
assign(tmpT6, mkU64(0x00FF00FF00FF00FFULL));
|
|
assign(tmpT1, binop(Iop_And64, mkexpr(tmpRt), mkexpr(tmpT5)));
|
|
assign(tmpT2, binop(Iop_Shr64, mkexpr(tmpT1), mkU8(8)));
|
|
assign(tmpT3, binop(Iop_And64, mkexpr(tmpRt), mkexpr(tmpT6)));
|
|
assign(tmpT4, binop(Iop_Shl64, mkexpr(tmpT3), mkU8(8)));
|
|
assign(tmpRd, binop(Iop_Or64, mkexpr(tmpT4), mkexpr(tmpT2)));
|
|
putIReg(rd, mkexpr(tmpRd));
|
|
break;
|
|
}
|
|
case 0x05: { /* DSHD */
|
|
DIP("dshd r%u, r%u\n", rd, rt);
|
|
IRTemp tmpT1 = newTemp(ty);
|
|
IRTemp tmpT2 = newTemp(ty);
|
|
IRTemp tmpT3 = newTemp(ty);
|
|
IRTemp tmpT4 = newTemp(ty);
|
|
IRTemp tmpT5 = newTemp(Ity_I64);
|
|
IRTemp tmpT6 = newTemp(ty);
|
|
IRTemp tmpT7 = newTemp(ty);
|
|
IRTemp tmpT8 = newTemp(ty);
|
|
IRTemp tmpT9 = newTemp(ty);
|
|
assign(tmpT5, mkU64(0xFFFF0000FFFF0000ULL));
|
|
assign(tmpT6, mkU64(0x0000FFFF0000FFFFULL));
|
|
assign(tmpT1, binop(Iop_And64, mkexpr(tmpRt), mkexpr(tmpT5)));
|
|
assign(tmpT2, binop(Iop_Shr64, mkexpr(tmpT1), mkU8(16)));
|
|
assign(tmpT3, binop(Iop_And64, mkexpr(tmpRt), mkexpr(tmpT6)));
|
|
assign(tmpT4, binop(Iop_Shl64, mkexpr(tmpT3), mkU8(16)));
|
|
assign(tmpT7, binop(Iop_Or64, mkexpr(tmpT4), mkexpr(tmpT2)));
|
|
assign(tmpT8, binop(Iop_Shl64, mkexpr(tmpT7), mkU8(32)));
|
|
assign(tmpT9, binop(Iop_Shr64, mkexpr(tmpT7), mkU8(32)));
|
|
assign(tmpRd, binop(Iop_Or64, mkexpr(tmpT8), mkexpr(tmpT9)));
|
|
putIReg(rd, mkexpr(tmpRd));
|
|
break;
|
|
}
|
|
default:
|
|
vex_printf("\nop6o10 = %u", lsb);
|
|
goto decode_failure;;
|
|
}
|
|
break;
|
|
case 0x3B: { /* RDHWR */
|
|
DIP("rdhwr r%u, r%u", rt, rd);
|
|
if (rd == 29) {
|
|
putIReg(rt, getULR());
|
|
#if defined(__mips__) && ((defined(__mips_isa_rev) && __mips_isa_rev >= 2))
|
|
} else if (rd == 1
|
|
|| (rd == 31
|
|
&& VEX_MIPS_COMP_ID(archinfo->hwcaps)
|
|
== VEX_PRID_COMP_CAVIUM)) {
|
|
if (mode64) {
|
|
IRTemp val = newTemp(Ity_I64);
|
|
IRExpr** args = mkIRExprVec_2 (mkU64(rt), mkU64(rd));
|
|
IRDirty *d = unsafeIRDirty_1_N(val,
|
|
0,
|
|
"mips64_dirtyhelper_rdhwr",
|
|
&mips64_dirtyhelper_rdhwr,
|
|
args);
|
|
stmt(IRStmt_Dirty(d));
|
|
putIReg(rt, mkexpr(val));
|
|
} else {
|
|
IRTemp val = newTemp(Ity_I32);
|
|
IRExpr** args = mkIRExprVec_2 (mkU32(rt), mkU32(rd));
|
|
IRDirty *d = unsafeIRDirty_1_N(val,
|
|
0,
|
|
"mips32_dirtyhelper_rdhwr",
|
|
&mips32_dirtyhelper_rdhwr,
|
|
args);
|
|
stmt(IRStmt_Dirty(d));
|
|
putIReg(rt, mkexpr(val));
|
|
}
|
|
#endif
|
|
} else
|
|
goto decode_failure;
|
|
break;
|
|
}
|
|
case 0x04: /* INS */
|
|
msb = get_msb(cins);
|
|
lsb = get_lsb(cins);
|
|
size = msb - lsb + 1;
|
|
DIP("ins size:%u msb:%u lsb:%u", size, msb, lsb);
|
|
|
|
vassert(lsb + size <= 32);
|
|
vassert(lsb + size > 0);
|
|
|
|
/* put size bits from rs at the pos in temporary */
|
|
t0 = newTemp(Ity_I32);
|
|
t3 = newTemp(Ity_I32);
|
|
/* shift left for 32 - size to clear leading bits and get zeros
|
|
at the end */
|
|
assign(t0, binop(Iop_Shl32, mkNarrowTo32(ty, getIReg(rs)),
|
|
mkU8(32 - size)));
|
|
/* now set it at pos */
|
|
t1 = newTemp(Ity_I32);
|
|
assign(t1, binop(Iop_Shr32, mkexpr(t0), mkU8(32 - size - lsb)));
|
|
|
|
if (lsb > 0) {
|
|
t2 = newTemp(Ity_I32);
|
|
/* clear everything but lower pos bits from rt */
|
|
assign(t2, binop(Iop_Shl32, mkNarrowTo32(ty, getIReg(rt)),
|
|
mkU8(32 - lsb)));
|
|
assign(t3, binop(Iop_Shr32, mkexpr(t2), mkU8(32 - lsb)));
|
|
} else
|
|
assign(t3, mkU32(0));
|
|
|
|
if (msb < 31) {
|
|
t4 = newTemp(Ity_I32);
|
|
/* clear everything but upper msb + 1 bits from rt */
|
|
assign(t4, binop(Iop_Shr32, mkNarrowTo32(ty, getIReg(rt)),
|
|
mkU8(msb + 1)));
|
|
t5 = newTemp(Ity_I32);
|
|
assign(t5, binop(Iop_Shl32, mkexpr(t4), mkU8(msb + 1)));
|
|
|
|
/* now combine these registers */
|
|
if (lsb > 0) {
|
|
t6 = newTemp(Ity_I32);
|
|
assign(t6, binop(Iop_Or32, mkexpr(t5), mkexpr(t1)));
|
|
putIReg(rt, mkWidenFrom32(ty, binop(Iop_Or32, mkexpr(t6),
|
|
mkexpr(t3)), True));
|
|
} else {
|
|
putIReg(rt, mkWidenFrom32(ty, binop(Iop_Or32, mkexpr(t1),
|
|
mkexpr(t5)), True));
|
|
}
|
|
} else {
|
|
putIReg(rt, mkWidenFrom32(ty, binop(Iop_Or32, mkexpr(t1),
|
|
mkexpr(t3)), True));
|
|
}
|
|
break;
|
|
|
|
case 0x00: /* EXT */
|
|
msb = get_msb(cins);
|
|
lsb = get_lsb(cins);
|
|
size = msb + 1;
|
|
DIP("ext size:%u msb:%u lsb:%u", size, msb, lsb);
|
|
vassert(lsb + size <= 32);
|
|
vassert(lsb + size > 0);
|
|
/* put size bits from rs at the top of in temporary */
|
|
if (lsb + size < 32) {
|
|
t0 = newTemp(Ity_I32);
|
|
assign(t0, binop(Iop_Shl32, mkNarrowTo32(ty, getIReg(rs)),
|
|
mkU8(32 - lsb - size)));
|
|
|
|
putIReg(rt, mkWidenFrom32(ty, binop(Iop_Shr32, mkexpr(t0),
|
|
mkU8(32 - size)), True));
|
|
} else {
|
|
putIReg(rt, mkWidenFrom32(ty, binop(Iop_Shr32,
|
|
mkNarrowTo32(ty, getIReg(rs)),
|
|
mkU8(32 - size)), True));
|
|
}
|
|
break;
|
|
|
|
case 0x03: /* Doubleword Extract Bit Field - DEXT; MIPS64r2 */
|
|
msb = get_msb(cins);
|
|
lsb = get_lsb(cins);
|
|
size = msb + 1;
|
|
DIP("dext r%u, r%u, %u, %u", rt, rs, lsb, msb + 1);
|
|
t1 = newTemp(Ity_I64);
|
|
vassert(lsb >= 0 && lsb < 32);
|
|
vassert(size > 0 && size <= 32);
|
|
vassert((lsb + size) > 0 && (lsb + size) <= 63);
|
|
|
|
UChar lsAmt = 63 - (lsb + msb); /* left shift amount; */
|
|
UChar rsAmt = 63 - msb; /* right shift amount; */
|
|
|
|
assign(t1, binop(Iop_Shl64, getIReg(rs), mkU8(lsAmt)));
|
|
putIReg(rt, binop(Iop_Shr64, mkexpr(t1), mkU8(rsAmt)));
|
|
|
|
break;
|
|
|
|
case 0x20: /* BSHFL */
|
|
switch (sa) {
|
|
case 0x02: /* WSBH */
|
|
DIP("wsbh r%u, r%u", rd, rt);
|
|
t0 = newTemp(Ity_I32);
|
|
t1 = newTemp(Ity_I32);
|
|
t2 = newTemp(Ity_I32);
|
|
t3 = newTemp(Ity_I32);
|
|
assign(t0, binop(Iop_Shl32, binop(Iop_And32, mkNarrowTo32(ty,
|
|
getIReg(rt)), mkU32(0x00FF0000)),
|
|
mkU8(0x8)));
|
|
assign(t1, binop(Iop_Shr32, binop(Iop_And32, mkNarrowTo32(ty,
|
|
getIReg(rt)), mkU32(0xFF000000)), mkU8(0x8)));
|
|
assign(t2, binop(Iop_Shl32, binop(Iop_And32, mkNarrowTo32(ty,
|
|
getIReg(rt)), mkU32(0x000000FF)), mkU8(0x8)));
|
|
assign(t3, binop(Iop_Shr32, binop(Iop_And32, mkNarrowTo32(ty,
|
|
getIReg(rt)), mkU32(0x0000FF00)), mkU8(0x8)));
|
|
putIReg(rd, mkWidenFrom32(ty, binop(Iop_Or32, binop(Iop_Or32,
|
|
mkexpr(t0), mkexpr(t1)),
|
|
binop(Iop_Or32, mkexpr(t2),
|
|
mkexpr(t3))), True));
|
|
break;
|
|
|
|
case 0x10: /* SEB */
|
|
DIP("seb r%u, r%u", rd, rt);
|
|
if (mode64)
|
|
putIReg(rd, unop(Iop_8Sto64, unop(Iop_64to8, getIReg(rt))));
|
|
else
|
|
putIReg(rd, unop(Iop_8Sto32, unop(Iop_32to8, getIReg(rt))));
|
|
break;
|
|
|
|
case 0x18: /* SEH */
|
|
DIP("seh r%u, r%u", rd, rt);
|
|
if (mode64)
|
|
putIReg(rd, unop(Iop_16Sto64, unop(Iop_64to16, getIReg(rt))));
|
|
else
|
|
putIReg(rd, unop(Iop_16Sto32, unop(Iop_32to16, getIReg(rt))));
|
|
break;
|
|
|
|
default:
|
|
goto decode_failure;
|
|
|
|
}
|
|
break; /* BSHFL */
|
|
|
|
/* --- MIPS32(r2) DSP ASE(r2) / Cavium Specfic (LX) instructions --- */
|
|
case 0xA: /* LX */
|
|
if (VEX_MIPS_COMP_ID(archinfo->hwcaps) == VEX_PRID_COMP_CAVIUM) {
|
|
if (dis_instr_CVM(cins))
|
|
break;
|
|
goto decode_failure;
|
|
}
|
|
case 0xC: /* INSV */
|
|
case 0x38: { /* EXTR.W */
|
|
if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) {
|
|
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 (VEX_MIPS_PROC_DSP2(archinfo->hwcaps)) {
|
|
UInt retVal = disDSPInstr_MIPS_WRK ( cins );
|
|
if (0 != retVal ) {
|
|
goto decode_failure_dsp;
|
|
}
|
|
break;
|
|
} else {
|
|
goto decode_failure_dsp;
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) {
|
|
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 (VEX_MIPS_PROC_DSP2(archinfo->hwcaps)) {
|
|
UInt retVal = disDSPInstr_MIPS_WRK ( cins );
|
|
if (0 != retVal ) {
|
|
goto decode_failure_dsp;
|
|
}
|
|
break;
|
|
} else {
|
|
goto decode_failure_dsp;
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) {
|
|
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 (VEX_MIPS_PROC_DSP2(archinfo->hwcaps)) {
|
|
UInt retVal = disDSPInstr_MIPS_WRK ( cins );
|
|
if (0 != retVal ) {
|
|
goto decode_failure_dsp;
|
|
}
|
|
break;
|
|
} else {
|
|
goto decode_failure_dsp;
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) {
|
|
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 (VEX_MIPS_PROC_DSP2(archinfo->hwcaps)) {
|
|
UInt retVal = disDSPInstr_MIPS_WRK ( cins );
|
|
if (0 != retVal ) {
|
|
goto decode_failure_dsp;
|
|
}
|
|
break;
|
|
} else {
|
|
goto decode_failure_dsp;
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) {
|
|
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 (VEX_MIPS_PROC_DSP2(archinfo->hwcaps)) {
|
|
UInt retVal = disDSPInstr_MIPS_WRK ( cins );
|
|
if (0 != retVal ) {
|
|
goto decode_failure_dsp;
|
|
}
|
|
break;
|
|
} else {
|
|
goto decode_failure_dsp;
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) {
|
|
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 (VEX_MIPS_PROC_DSP2(archinfo->hwcaps)) {
|
|
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:
|
|
if (0x3B == function &&
|
|
(VEX_MIPS_COMP_ID(archinfo->hwcaps) == VEX_PRID_COMP_BROADCOM)) {
|
|
/*RDHWR*/
|
|
DIP("rdhwr r%u, r%u", rt, rd);
|
|
if (rd == 29) {
|
|
putIReg(rt, getULR());
|
|
} else
|
|
goto decode_failure;
|
|
break;
|
|
} else {
|
|
goto decode_failure;
|
|
}
|
|
|
|
case 0x00: /* Special */
|
|
|
|
switch (function) {
|
|
case 0x1: {
|
|
UInt mov_cc = get_mov_cc(cins);
|
|
if (tf == 0) { /* MOVF */
|
|
DIP("movf r%u, r%u, %u", rd, rs, mov_cc);
|
|
t1 = newTemp(Ity_I1);
|
|
t2 = newTemp(Ity_I32);
|
|
t3 = newTemp(Ity_I1);
|
|
|
|
assign(t1, binop(Iop_CmpEQ32, mkU32(0), mkU32(mov_cc)));
|
|
assign(t2, IRExpr_ITE(mkexpr(t1),
|
|
binop(Iop_And32,
|
|
binop(Iop_Shr32, getFCSR(),
|
|
mkU8(23)),
|
|
mkU32(0x1)),
|
|
binop(Iop_And32,
|
|
binop(Iop_Shr32, getFCSR(),
|
|
mkU8(24 + mov_cc)),
|
|
mkU32(0x1))
|
|
));
|
|
assign(t3, binop(Iop_CmpEQ32, mkU32(0), mkexpr(t2)));
|
|
putIReg(rd, IRExpr_ITE(mkexpr(t3), getIReg(rs), getIReg(rd)));
|
|
} else if (tf == 1) { /* MOVT */
|
|
DIP("movt r%u, r%u, %u", rd, rs, mov_cc);
|
|
t1 = newTemp(Ity_I1);
|
|
t2 = newTemp(Ity_I32);
|
|
t3 = newTemp(Ity_I1);
|
|
|
|
assign(t1, binop(Iop_CmpEQ32, mkU32(0), mkU32(mov_cc)));
|
|
assign(t2, IRExpr_ITE(mkexpr(t1),
|
|
binop(Iop_And32,
|
|
binop(Iop_Shr32, getFCSR(),
|
|
mkU8(23)),
|
|
mkU32(0x1)),
|
|
binop(Iop_And32,
|
|
binop(Iop_Shr32, getFCSR(),
|
|
mkU8(24 + mov_cc)),
|
|
mkU32(0x1))
|
|
));
|
|
assign(t3, binop(Iop_CmpEQ32, mkU32(1), mkexpr(t2)));
|
|
putIReg(rd, IRExpr_ITE(mkexpr(t3), getIReg(rs), getIReg(rd)));
|
|
}
|
|
break;
|
|
}
|
|
case 0x0A: { /* MOVZ */
|
|
DIP("movz r%u, r%u, r%u", rd, rs, rt);
|
|
t1 = newTemp(ty);
|
|
t2 = newTemp(ty);
|
|
if (mode64) {
|
|
assign(t1, unop(Iop_32Sto64, unop(Iop_1Sto32, binop(Iop_CmpEQ64,
|
|
getIReg(rt), mkU64(0x0)))));
|
|
assign(t2, unop(Iop_32Sto64, unop(Iop_1Sto32, binop(Iop_CmpNE64,
|
|
getIReg(rt), mkU64(0x0)))));
|
|
putIReg(rd, binop(Iop_Add64, binop(Iop_And64, getIReg(rs),
|
|
mkexpr(t1)), binop(Iop_And64, getIReg(rd),mkexpr(t2))));
|
|
} else {
|
|
assign(t1, unop(Iop_1Sto32, binop(Iop_CmpEQ32, getIReg(rt),
|
|
mkU32(0x0))));
|
|
assign(t2, unop(Iop_1Sto32, binop(Iop_CmpNE32, getIReg(rt),
|
|
mkU32(0x0))));
|
|
putIReg(rd, binop(Iop_Add32, binop(Iop_And32, getIReg(rs),
|
|
mkexpr(t1)), binop(Iop_And32, getIReg(rd),
|
|
mkexpr(t2))));
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 0x0B: { /* MOVN */
|
|
DIP("movn r%u, r%u, r%u", rd, rs, rt);
|
|
t1 = newTemp(ty);
|
|
t2 = newTemp(ty);
|
|
if (mode64) {
|
|
assign(t1, unop(Iop_32Sto64, unop(Iop_1Sto32, binop(Iop_CmpEQ64,
|
|
getIReg(rt), mkU64(0x0)))));
|
|
assign(t2, unop(Iop_32Sto64, unop(Iop_1Sto32, binop(Iop_CmpNE64,
|
|
getIReg(rt), mkU64(0x0)))));
|
|
putIReg(rd, binop(Iop_Add64, binop(Iop_And64, getIReg(rs),
|
|
mkexpr(t2)), binop(Iop_And64, getIReg(rd),
|
|
mkexpr(t1))));
|
|
} else {
|
|
assign(t1, unop(Iop_1Sto32, binop(Iop_CmpEQ32, getIReg(rt),
|
|
mkU32(0x0))));
|
|
assign(t2, unop(Iop_1Sto32, binop(Iop_CmpNE32, getIReg(rt),
|
|
mkU32(0x0))));
|
|
putIReg(rd, binop(Iop_Add32, binop(Iop_And32, getIReg(rs),
|
|
mkexpr(t2)), binop(Iop_And32, getIReg(rd),
|
|
mkexpr(t1))));
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 0x18: { /* MULT */
|
|
if ( (1 <= ac) && ( 3 >= ac) ) {
|
|
if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) {
|
|
/* 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%u, r%u", 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 0x19: { /* MULTU */
|
|
if ( (1 <= ac) && ( 3 >= ac) ) {
|
|
if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) {
|
|
/* 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%u, r%u", rs, rt);
|
|
t2 = newTemp(Ity_I64);
|
|
|
|
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%u, r%u, r%u", rd, rs, rt);
|
|
IRTemp tmpRs32 = newTemp(Ity_I32);
|
|
IRTemp tmpRt32 = newTemp(Ity_I32);
|
|
|
|
assign(tmpRs32, mkNarrowTo32(ty, getIReg(rs)));
|
|
assign(tmpRt32, mkNarrowTo32(ty, getIReg(rt)));
|
|
|
|
t0 = newTemp(Ity_I32);
|
|
t1 = newTemp(Ity_I32);
|
|
t2 = newTemp(Ity_I32);
|
|
t3 = newTemp(Ity_I32);
|
|
t4 = newTemp(Ity_I32);
|
|
/* dst = src0 + src1
|
|
if (sign(src0 ) != sign(src1 ))
|
|
goto no overflow;
|
|
if (sign(dst) == sign(src0 ))
|
|
goto no overflow;
|
|
we have overflow! */
|
|
|
|
assign(t0, binop(Iop_Add32, mkexpr(tmpRs32), mkexpr(tmpRt32)));
|
|
assign(t1, binop(Iop_Xor32, mkexpr(tmpRs32), mkexpr(tmpRt32)));
|
|
assign(t2, unop(Iop_1Uto32,
|
|
binop(Iop_CmpEQ32,
|
|
binop(Iop_And32, mkexpr(t1), mkU32(0x80000000)),
|
|
mkU32(0x80000000))));
|
|
|
|
assign(t3, binop(Iop_Xor32, mkexpr(t0), mkexpr(tmpRs32)));
|
|
assign(t4, unop(Iop_1Uto32,
|
|
binop(Iop_CmpNE32,
|
|
binop(Iop_And32, mkexpr(t3), mkU32(0x80000000)),
|
|
mkU32(0x80000000))));
|
|
|
|
stmt(IRStmt_Exit(binop(Iop_CmpEQ32,
|
|
binop(Iop_Or32, mkexpr(t2), mkexpr(t4)),
|
|
mkU32(0)),
|
|
Ijk_SigFPE_IntOvf,
|
|
mode64 ? IRConst_U64(guest_PC_curr_instr + 4) :
|
|
IRConst_U32(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
|
|
putIReg(rd, mkWidenFrom32(ty, mkexpr(t0), True));
|
|
break;
|
|
}
|
|
case 0x1A: /* DIV */
|
|
DIP("div r%u, r%u", rs, rt);
|
|
if (mode64) {
|
|
t2 = newTemp(Ity_I64);
|
|
|
|
assign(t2, binop(Iop_DivModS64to32,
|
|
getIReg(rs), mkNarrowTo32(ty, getIReg(rt))));
|
|
|
|
putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t2)), True));
|
|
putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t2)), True));
|
|
} else {
|
|
t1 = newTemp(Ity_I64);
|
|
t2 = newTemp(Ity_I64);
|
|
|
|
assign(t1, unop(Iop_32Sto64, getIReg(rs)));
|
|
assign(t2, binop(Iop_DivModS64to32, mkexpr(t1), getIReg(rt)));
|
|
|
|
putHI(unop(Iop_64HIto32, mkexpr(t2)));
|
|
putLO(unop(Iop_64to32, mkexpr(t2)));
|
|
}
|
|
break;
|
|
|
|
case 0x1B: /* DIVU */
|
|
DIP("divu r%u, r%u", rs, rt);
|
|
if (mode64) {
|
|
t2 = newTemp(Ity_I64);
|
|
|
|
assign(t2, binop(Iop_DivModU64to32,
|
|
getIReg(rs), mkNarrowTo32(ty, getIReg(rt))));
|
|
|
|
putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t2)), True));
|
|
putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t2)), True));
|
|
} else {
|
|
t1 = newTemp(Ity_I64);
|
|
t2 = newTemp(Ity_I64);
|
|
assign(t1, unop(Iop_32Uto64, getIReg(rs)));
|
|
assign(t2, binop(Iop_DivModU64to32, mkexpr(t1), getIReg(rt)));
|
|
putHI(unop(Iop_64HIto32, mkexpr(t2)));
|
|
putLO(unop(Iop_64to32, mkexpr(t2)));
|
|
}
|
|
break;
|
|
|
|
case 0x1C: /* Doubleword Multiply - DMULT; MIPS64 */
|
|
DIP("dmult r%u, r%u", rs, rt);
|
|
t0 = newTemp(Ity_I128);
|
|
|
|
assign(t0, binop(Iop_MullS64, getIReg(rs), getIReg(rt)));
|
|
|
|
putHI(unop(Iop_128HIto64, mkexpr(t0)));
|
|
putLO(unop(Iop_128to64, mkexpr(t0)));
|
|
break;
|
|
|
|
case 0x1D: /* Doubleword Multiply Unsigned - DMULTU; MIPS64 */
|
|
DIP("dmultu r%u, r%u", rs, rt);
|
|
t0 = newTemp(Ity_I128);
|
|
|
|
assign(t0, binop(Iop_MullU64, getIReg(rs), getIReg(rt)));
|
|
|
|
putHI(unop(Iop_128HIto64, mkexpr(t0)));
|
|
putLO(unop(Iop_128to64, mkexpr(t0)));
|
|
break;
|
|
|
|
case 0x1E: /* Doubleword Divide DDIV; MIPS64 */
|
|
DIP("ddiv r%u, r%u", rs, rt);
|
|
t1 = newTemp(Ity_I128);
|
|
|
|
assign(t1, binop(Iop_DivModS64to64, getIReg(rs), getIReg(rt)));
|
|
|
|
putHI(unop(Iop_128HIto64, mkexpr(t1)));
|
|
putLO(unop(Iop_128to64, mkexpr(t1)));
|
|
break;
|
|
|
|
case 0x1F: /* Doubleword Divide Unsigned DDIVU; MIPS64 check this */
|
|
DIP("ddivu r%u, r%u", rs, rt);
|
|
t1 = newTemp(Ity_I128);
|
|
t2 = newTemp(Ity_I128);
|
|
|
|
assign(t1, binop(Iop_64HLto128, mkU64(0), getIReg(rs)));
|
|
|
|
assign(t2, binop(Iop_DivModU128to64, mkexpr(t1), getIReg(rt)));
|
|
|
|
putHI(unop(Iop_128HIto64, mkexpr(t2)));
|
|
putLO(unop(Iop_128to64, mkexpr(t2)));
|
|
break;
|
|
|
|
case 0x10: { /* MFHI */
|
|
if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) {
|
|
/* If DSP is present -> DSP ASE MFHI */
|
|
UInt retVal = disDSPInstr_MIPS_WRK ( cins );
|
|
if (0 != retVal ) {
|
|
goto decode_failure;
|
|
}
|
|
break;
|
|
} else {
|
|
DIP("mfhi r%u", rd);
|
|
putIReg(rd, getHI());
|
|
break;
|
|
}
|
|
}
|
|
|
|
case 0x11: { /* MTHI */
|
|
if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) {
|
|
/* If DSP is present -> DSP ASE MTHI */
|
|
UInt retVal = disDSPInstr_MIPS_WRK ( cins );
|
|
if (0 != retVal ) {
|
|
goto decode_failure;
|
|
}
|
|
break;
|
|
} else {
|
|
DIP("mthi r%u", rs);
|
|
putHI(getIReg(rs));
|
|
break;
|
|
}
|
|
}
|
|
|
|
case 0x12: { /* MFLO */
|
|
if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) {
|
|
/* If DSP is present -> DSP ASE MFLO */
|
|
UInt retVal = disDSPInstr_MIPS_WRK ( cins );
|
|
if (0 != retVal ) {
|
|
goto decode_failure;
|
|
}
|
|
break;
|
|
} else {
|
|
DIP("mflo r%u", rd);
|
|
putIReg(rd, getLO());
|
|
break;
|
|
}
|
|
}
|
|
|
|
case 0x13: { /* MTLO */
|
|
if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) {
|
|
/* If DSP is present -> DSP ASE MTLO */
|
|
UInt retVal = disDSPInstr_MIPS_WRK ( cins );
|
|
if (0 != retVal ) {
|
|
goto decode_failure;
|
|
}
|
|
break;
|
|
} else {
|
|
DIP("mtlo r%u", rs);
|
|
putLO(getIReg(rs));
|
|
break;
|
|
}
|
|
}
|
|
|
|
case 0x21: /* ADDU */
|
|
DIP("addu r%u, r%u, r%u", rd, rs, rt);
|
|
if (mode64) {
|
|
ALU_PATTERN64(Iop_Add32);
|
|
} else {
|
|
ALU_PATTERN(Iop_Add32);
|
|
}
|
|
break;
|
|
|
|
case 0x22: { /* SUB */
|
|
DIP("sub r%u, r%u, r%u", rd, rs, rt);
|
|
IRTemp tmpRs32 = newTemp(Ity_I32);
|
|
IRTemp tmpRt32 = newTemp(Ity_I32);
|
|
|
|
assign(tmpRs32, mkNarrowTo32(ty, getIReg(rs)));
|
|
assign(tmpRt32, mkNarrowTo32(ty, getIReg(rt)));
|
|
t0 = newTemp(Ity_I32);
|
|
t1 = newTemp(Ity_I32);
|
|
t2 = newTemp(Ity_I32);
|
|
t3 = newTemp(Ity_I32);
|
|
t4 = newTemp(Ity_I32);
|
|
t5 = newTemp(Ity_I32);
|
|
/* dst = src0 + (-1 * src1)
|
|
if(sign(src0 ) != sign((-1 * src1) ))
|
|
goto no overflow;
|
|
if(sign(dst) == sign(src0 ))
|
|
goto no overflow;
|
|
we have overflow! */
|
|
|
|
assign(t5, binop(Iop_Mul32, mkexpr(tmpRt32), mkU32(-1)));
|
|
assign(t0, binop(Iop_Add32, mkexpr(tmpRs32), mkexpr(t5)));
|
|
assign(t1, binop(Iop_Xor32, mkexpr(tmpRs32), mkexpr(t5)));
|
|
assign(t2, unop(Iop_1Sto32, binop(Iop_CmpEQ32, binop(Iop_And32,
|
|
mkexpr(t1), mkU32(0x80000000)), mkU32(0x80000000))));
|
|
|
|
assign(t3, binop(Iop_Xor32, mkexpr(t0), mkexpr(tmpRs32)));
|
|
assign(t4, unop(Iop_1Sto32, binop(Iop_CmpNE32, binop(Iop_And32,
|
|
mkexpr(t3), mkU32(0x80000000)), mkU32(0x80000000))));
|
|
|
|
stmt(IRStmt_Exit(binop(Iop_CmpEQ32, binop(Iop_Or32, mkexpr(t2),
|
|
mkexpr(t4)), mkU32(0)), Ijk_SigFPE_IntOvf,
|
|
mode64 ? IRConst_U64(guest_PC_curr_instr + 4) :
|
|
IRConst_U32(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
|
|
putIReg(rd, mkWidenFrom32(ty, mkexpr(t0), True));
|
|
break;
|
|
}
|
|
case 0x23: /* SUBU */
|
|
DIP("subu r%u, r%u, r%u", rd, rs, rt);
|
|
if (mode64) {
|
|
ALU_PATTERN64(Iop_Sub32);
|
|
} else {
|
|
ALU_PATTERN(Iop_Sub32);
|
|
}
|
|
break;
|
|
|
|
case 0x24: /* AND */
|
|
DIP("and r%u, r%u, r%u", rd, rs, rt);
|
|
if (mode64) {
|
|
ALU_PATTERN(Iop_And64);
|
|
} else {
|
|
ALU_PATTERN(Iop_And32);
|
|
}
|
|
break;
|
|
|
|
case 0x25: /* OR */
|
|
DIP("or r%u, r%u, r%u", rd, rs, rt);
|
|
if (mode64) {
|
|
ALU_PATTERN(Iop_Or64);
|
|
} else {
|
|
ALU_PATTERN(Iop_Or32);
|
|
}
|
|
break;
|
|
|
|
case 0x26: /* XOR */
|
|
DIP("xor r%u, r%u, r%u", rd, rs, rt);
|
|
if (mode64) {
|
|
ALU_PATTERN(Iop_Xor64);
|
|
} else {
|
|
ALU_PATTERN(Iop_Xor32);
|
|
}
|
|
break;
|
|
|
|
case 0x27: /* NOR */
|
|
DIP("nor r%u, r%u, r%u", rd, rs, rt);
|
|
if (mode64)
|
|
putIReg(rd, unop(Iop_Not64, binop(Iop_Or64, getIReg(rs),
|
|
getIReg(rt))));
|
|
else
|
|
putIReg(rd, unop(Iop_Not32, binop(Iop_Or32, getIReg(rs),
|
|
getIReg(rt))));
|
|
break;
|
|
|
|
case 0x08: /* JR */
|
|
DIP("jr r%u", rs);
|
|
t0 = newTemp(ty);
|
|
assign(t0, getIReg(rs));
|
|
lastn = mkexpr(t0);
|
|
break;
|
|
|
|
case 0x09: /* JALR */
|
|
DIP("jalr r%u r%u", rd, rs);
|
|
if (mode64) {
|
|
putIReg(rd, mkU64(guest_PC_curr_instr + 8));
|
|
t0 = newTemp(Ity_I64);
|
|
assign(t0, getIReg(rs));
|
|
lastn = mkexpr(t0);
|
|
} else {
|
|
putIReg(rd, mkU32(guest_PC_curr_instr + 8));
|
|
t0 = newTemp(Ity_I32);
|
|
assign(t0, getIReg(rs));
|
|
lastn = mkexpr(t0);
|
|
}
|
|
break;
|
|
|
|
case 0x0C: /* SYSCALL */
|
|
DIP("syscall");
|
|
if (mode64)
|
|
putPC(mkU64(guest_PC_curr_instr + 4));
|
|
else
|
|
putPC(mkU32(guest_PC_curr_instr + 4));
|
|
dres.jk_StopHere = Ijk_Sys_syscall;
|
|
dres.whatNext = Dis_StopHere;
|
|
break;
|
|
|
|
case 0x2A: /* SLT */
|
|
DIP("slt r%u, r%u, r%u", rd, rs, rt);
|
|
if (mode64)
|
|
putIReg(rd, unop(Iop_1Uto64, binop(Iop_CmpLT64S, getIReg(rs),
|
|
getIReg(rt))));
|
|
else
|
|
putIReg(rd, unop(Iop_1Uto32, binop(Iop_CmpLT32S, getIReg(rs),
|
|
getIReg(rt))));
|
|
break;
|
|
|
|
case 0x2B: /* SLTU */
|
|
DIP("sltu r%u, r%u, r%u", rd, rs, rt);
|
|
if (mode64)
|
|
putIReg(rd, unop(Iop_1Uto64, binop(Iop_CmpLT64U, getIReg(rs),
|
|
getIReg(rt))));
|
|
else
|
|
putIReg(rd, unop(Iop_1Uto32, binop(Iop_CmpLT32U, getIReg(rs),
|
|
getIReg(rt))));
|
|
break;
|
|
|
|
case 0x00: { /* SLL */
|
|
DIP("sll r%u, r%u, %u", rd, rt, sa);
|
|
IRTemp tmpRt32 = newTemp(Ity_I32);
|
|
IRTemp tmpSh32 = newTemp(Ity_I32);
|
|
IRTemp tmpRd = newTemp(Ity_I64);
|
|
if (mode64) {
|
|
assign(tmpRt32, mkNarrowTo32(ty, getIReg(rt)));
|
|
assign(tmpSh32, binop(Iop_Shl32, mkexpr(tmpRt32), mkU8(sa)));
|
|
assign(tmpRd, mkWidenFrom32(ty, mkexpr(tmpSh32), True));
|
|
putIReg(rd, mkexpr(tmpRd));
|
|
} else
|
|
SXX_PATTERN(Iop_Shl32);
|
|
break;
|
|
}
|
|
|
|
case 0x04: { /* SLLV */
|
|
DIP("sllv r%u, r%u, r%u", rd, rt, rs);
|
|
if (mode64) {
|
|
IRTemp tmpRs8 = newTemp(Ity_I8);
|
|
IRTemp tmpRt32 = newTemp(Ity_I32);
|
|
IRTemp tmpSh32 = newTemp(Ity_I32);
|
|
IRTemp tmp = newTemp(ty);
|
|
assign(tmp, binop(mkSzOp(ty, Iop_And8), getIReg(rs),
|
|
mkSzImm(ty, 31)));
|
|
assign(tmpRs8, mkNarrowTo8(ty, mkexpr(tmp)));
|
|
assign(tmpRt32, mkNarrowTo32(ty, getIReg(rt)));
|
|
assign(tmpSh32, binop(Iop_Shl32, mkexpr(tmpRt32), mkexpr(tmpRs8)));
|
|
putIReg(rd, mkWidenFrom32(ty, mkexpr(tmpSh32), True));
|
|
} else {
|
|
SXXV_PATTERN(Iop_Shl32);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 0x03: /* SRA */
|
|
DIP("sra r%u, r%u, %u", rd, rt, sa);
|
|
if (mode64) {
|
|
IRTemp tmpRt32 = newTemp(Ity_I32);
|
|
IRTemp tmpSh32 = newTemp(Ity_I32);
|
|
|
|
t1 = newTemp(Ity_I64);
|
|
t2 = newTemp(Ity_I64);
|
|
t3 = newTemp(Ity_I64);
|
|
|
|
assign(t1, binop(Iop_And64, getIReg(rt), /* hi */
|
|
mkU64(0xFFFFFFFF00000000ULL)));
|
|
|
|
assign(t2, binop(Iop_Sar64, mkexpr(t1), mkU8(sa)));
|
|
|
|
assign(tmpRt32, mkNarrowTo32(ty, getIReg(rt)));
|
|
assign(tmpSh32, binop(Iop_Sar32, mkexpr(tmpRt32), mkU8(sa)));
|
|
|
|
putIReg(rd, mkWidenFrom32(ty, mkexpr(tmpSh32), True));
|
|
} else {
|
|
SXX_PATTERN(Iop_Sar32);
|
|
}
|
|
break;
|
|
|
|
case 0x07: /* SRAV */
|
|
DIP("srav r%u, r%u, r%u", rd, rt, rs);
|
|
if (mode64) {
|
|
IRTemp tmpRt32 = newTemp(Ity_I32);
|
|
IRTemp tmpSh32 = newTemp(Ity_I32);
|
|
|
|
t1 = newTemp(Ity_I64);
|
|
t2 = newTemp(Ity_I64);
|
|
t3 = newTemp(Ity_I64);
|
|
t4 = newTemp(Ity_I8);
|
|
|
|
assign(t4, unop(Iop_32to8, binop(Iop_And32,
|
|
mkNarrowTo32(ty, getIReg(rs)), mkU32(0x0000001F))));
|
|
|
|
assign(t1, binop(Iop_And64, getIReg(rt), /* hi */
|
|
mkU64(0xFFFFFFFF00000000ULL)));
|
|
|
|
assign(t2, binop(Iop_Sar64, mkexpr(t1), mkexpr(t4)));
|
|
|
|
assign(tmpRt32, mkNarrowTo32(ty, getIReg(rt)));
|
|
assign(tmpSh32, binop(Iop_Sar32, mkexpr(tmpRt32), mkexpr(t4)));
|
|
|
|
putIReg(rd, mkWidenFrom32(ty, mkexpr(tmpSh32), True));
|
|
} else {
|
|
SXXV_PATTERN(Iop_Sar32);
|
|
}
|
|
break;
|
|
|
|
case 0x02: { /* SRL */
|
|
rot = get_rot(cins);
|
|
if (rot) {
|
|
DIP("rotr r%u, r%u, %u", rd, rt, sa);
|
|
putIReg(rd, mkWidenFrom32(ty, genROR32(mkNarrowTo32(ty,
|
|
getIReg(rt)), sa), True));
|
|
} else {
|
|
DIP("srl r%u, r%u, %u", rd, rt, sa);
|
|
if (mode64) {
|
|
IRTemp tmpSh32 = newTemp(Ity_I32);
|
|
IRTemp tmpRt32 = newTemp(Ity_I32);
|
|
|
|
assign(tmpRt32, mkNarrowTo32(ty, getIReg(rt)));
|
|
assign(tmpSh32, binop(Iop_Shr32, mkexpr(tmpRt32), mkU8(sa)));
|
|
putIReg(rd, mkWidenFrom32(ty, mkexpr(tmpSh32), True));
|
|
} else {
|
|
SXX_PATTERN(Iop_Shr32);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 0x06: {
|
|
rot = get_rotv(cins);
|
|
if (rot) {
|
|
DIP("rotrv r%u, r%u, r%u", rd, rt, rs);
|
|
putIReg(rd, mkWidenFrom32(ty, genRORV32(mkNarrowTo32(ty,
|
|
getIReg(rt)), mkNarrowTo32(ty, getIReg(rs))), True));
|
|
break;
|
|
} else { /* SRLV */
|
|
DIP("srlv r%u, r%u, r%u", rd, rt, rs);
|
|
if (mode64) {
|
|
SXXV_PATTERN64(Iop_Shr32);
|
|
} else {
|
|
SXXV_PATTERN(Iop_Shr32);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
case 0x0D: /* BREAK */
|
|
DIP("break 0x%x", trap_code);
|
|
if (mode64)
|
|
jmp_lit64(&dres, Ijk_SigTRAP, (guest_PC_curr_instr + 4));
|
|
else
|
|
jmp_lit32(&dres, Ijk_SigTRAP, (guest_PC_curr_instr + 4));
|
|
vassert(dres.whatNext == Dis_StopHere);
|
|
break;
|
|
|
|
case 0x30: { /* TGE */
|
|
DIP("tge r%u, r%u %u", rs, rt, trap_code);
|
|
if (mode64) {
|
|
if (trap_code == 7)
|
|
stmt (IRStmt_Exit (unop (Iop_Not1,
|
|
binop (Iop_CmpLT64S,
|
|
getIReg (rs),
|
|
getIReg (rt))),
|
|
Ijk_SigFPE_IntDiv,
|
|
IRConst_U64(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
else if (trap_code == 6)
|
|
stmt (IRStmt_Exit (unop (Iop_Not1,
|
|
binop (Iop_CmpLT64S,
|
|
getIReg (rs),
|
|
getIReg (rt))),
|
|
Ijk_SigFPE_IntOvf,
|
|
IRConst_U64(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
else
|
|
stmt (IRStmt_Exit (unop (Iop_Not1,
|
|
binop (Iop_CmpLT64S,
|
|
getIReg (rs),
|
|
getIReg (rt))),
|
|
Ijk_SigTRAP,
|
|
IRConst_U64(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
} else {
|
|
if (trap_code == 7)
|
|
stmt (IRStmt_Exit (unop (Iop_Not1,
|
|
binop (Iop_CmpLT32S,
|
|
getIReg (rs),
|
|
getIReg (rt))),
|
|
Ijk_SigFPE_IntDiv,
|
|
IRConst_U32(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
else if (trap_code == 6)
|
|
stmt (IRStmt_Exit (unop (Iop_Not1,
|
|
binop (Iop_CmpLT32S,
|
|
getIReg (rs),
|
|
getIReg (rt))),
|
|
Ijk_SigFPE_IntOvf,
|
|
IRConst_U32(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
else
|
|
stmt (IRStmt_Exit (unop (Iop_Not1,
|
|
binop (Iop_CmpLT32S,
|
|
getIReg (rs),
|
|
getIReg (rt))),
|
|
Ijk_SigTRAP,
|
|
IRConst_U32(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
}
|
|
break;
|
|
}
|
|
case 0x31: { /* TGEU */
|
|
DIP("tgeu r%u, r%u %u", rs, rt, trap_code);
|
|
if (mode64) {
|
|
if (trap_code == 7)
|
|
stmt (IRStmt_Exit (unop (Iop_Not1,
|
|
binop (Iop_CmpLT64U,
|
|
getIReg (rs),
|
|
getIReg (rt))),
|
|
Ijk_SigFPE_IntDiv,
|
|
IRConst_U64(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
else if (trap_code == 6)
|
|
stmt (IRStmt_Exit (unop (Iop_Not1,
|
|
binop (Iop_CmpLT64U,
|
|
getIReg (rs),
|
|
getIReg (rt))),
|
|
Ijk_SigFPE_IntOvf,
|
|
IRConst_U64(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
else
|
|
stmt (IRStmt_Exit (unop (Iop_Not1,
|
|
binop (Iop_CmpLT64U,
|
|
getIReg (rs),
|
|
getIReg (rt))),
|
|
Ijk_SigTRAP,
|
|
IRConst_U64(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
} else {
|
|
if (trap_code == 7)
|
|
stmt (IRStmt_Exit (unop (Iop_Not1,
|
|
binop (Iop_CmpLT32U,
|
|
getIReg (rs),
|
|
getIReg (rt))),
|
|
Ijk_SigFPE_IntDiv,
|
|
IRConst_U32(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
else if (trap_code == 6)
|
|
stmt (IRStmt_Exit (unop (Iop_Not1,
|
|
binop (Iop_CmpLT32U,
|
|
getIReg (rs),
|
|
getIReg (rt))),
|
|
Ijk_SigFPE_IntOvf,
|
|
IRConst_U32(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
else
|
|
stmt (IRStmt_Exit (unop (Iop_Not1,
|
|
binop (Iop_CmpLT32U,
|
|
getIReg (rs),
|
|
getIReg (rt))),
|
|
Ijk_SigTRAP,
|
|
IRConst_U32(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
}
|
|
break;
|
|
}
|
|
case 0x32: { /* TLT */
|
|
DIP("tlt r%u, r%u %u", rs, rt, trap_code);
|
|
if (mode64) {
|
|
if (trap_code == 7)
|
|
stmt(IRStmt_Exit(binop(Iop_CmpLT64S, getIReg(rs),
|
|
getIReg(rt)), Ijk_SigFPE_IntDiv,
|
|
IRConst_U64(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
else if (trap_code == 6)
|
|
stmt(IRStmt_Exit(binop(Iop_CmpLT64S, getIReg(rs),
|
|
getIReg(rt)), Ijk_SigFPE_IntOvf,
|
|
IRConst_U64(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
else
|
|
stmt(IRStmt_Exit(binop(Iop_CmpLT64S, getIReg(rs),
|
|
getIReg(rt)), Ijk_SigTRAP,
|
|
IRConst_U64(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
} else {
|
|
if (trap_code == 7)
|
|
stmt(IRStmt_Exit(binop(Iop_CmpLT32S, getIReg(rs),
|
|
getIReg(rt)), Ijk_SigFPE_IntDiv,
|
|
IRConst_U32(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
else if (trap_code == 6)
|
|
stmt(IRStmt_Exit(binop(Iop_CmpLT32S, getIReg(rs),
|
|
getIReg(rt)), Ijk_SigFPE_IntOvf,
|
|
IRConst_U32(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
else
|
|
stmt(IRStmt_Exit(binop(Iop_CmpLT32S, getIReg(rs),
|
|
getIReg(rt)), Ijk_SigTRAP,
|
|
IRConst_U32(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
}
|
|
break;
|
|
}
|
|
case 0x33: { /* TLTU */
|
|
DIP("tltu r%u, r%u %u", rs, rt, trap_code);
|
|
if (mode64) {
|
|
if (trap_code == 7)
|
|
stmt(IRStmt_Exit(binop(Iop_CmpLT64U, getIReg(rs),
|
|
getIReg(rt)), Ijk_SigFPE_IntDiv,
|
|
IRConst_U64(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
else if (trap_code == 6)
|
|
stmt(IRStmt_Exit(binop(Iop_CmpLT64U, getIReg(rs),
|
|
getIReg(rt)), Ijk_SigFPE_IntOvf,
|
|
IRConst_U64(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
else
|
|
stmt(IRStmt_Exit(binop(Iop_CmpLT64U, getIReg(rs),
|
|
getIReg(rt)), Ijk_SigTRAP,
|
|
IRConst_U64(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
} else {
|
|
if (trap_code == 7)
|
|
stmt(IRStmt_Exit(binop(Iop_CmpLT32U, getIReg(rs),
|
|
getIReg(rt)), Ijk_SigFPE_IntDiv,
|
|
IRConst_U32(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
else if (trap_code == 6)
|
|
stmt(IRStmt_Exit(binop(Iop_CmpLT32U, getIReg(rs),
|
|
getIReg(rt)), Ijk_SigFPE_IntOvf,
|
|
IRConst_U32(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
else
|
|
stmt(IRStmt_Exit(binop(Iop_CmpLT32U, getIReg(rs),
|
|
getIReg (rt)), Ijk_SigTRAP,
|
|
IRConst_U32(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
}
|
|
break;
|
|
}
|
|
case 0x34: { /* TEQ */
|
|
DIP("teq r%u, r%u, %u", rs, rt, trap_code);
|
|
if (mode64) {
|
|
if (trap_code == 7)
|
|
stmt(IRStmt_Exit(binop(Iop_CmpEQ64, getIReg(rs),
|
|
getIReg(rt)), Ijk_SigFPE_IntDiv,
|
|
IRConst_U64(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
else if (trap_code == 6)
|
|
stmt(IRStmt_Exit(binop(Iop_CmpEQ64, getIReg(rs),
|
|
getIReg(rt)), Ijk_SigFPE_IntOvf,
|
|
IRConst_U64(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
else
|
|
stmt(IRStmt_Exit(binop(Iop_CmpEQ64, getIReg(rs),
|
|
getIReg(rt)), Ijk_SigTRAP,
|
|
IRConst_U64(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
} else {
|
|
if (trap_code == 7)
|
|
stmt(IRStmt_Exit(binop(Iop_CmpEQ32, getIReg(rs),
|
|
getIReg(rt)), Ijk_SigFPE_IntDiv,
|
|
IRConst_U32(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
else if (trap_code == 6)
|
|
stmt(IRStmt_Exit(binop(Iop_CmpEQ32, getIReg(rs),
|
|
getIReg(rt)), Ijk_SigFPE_IntOvf,
|
|
IRConst_U32(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
else
|
|
stmt(IRStmt_Exit(binop(Iop_CmpEQ32, getIReg(rs),
|
|
getIReg(rt)), Ijk_SigTRAP,
|
|
IRConst_U32(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
}
|
|
break;
|
|
}
|
|
case 0x36: { /* TNE */
|
|
DIP("tne r%u, r%u %u", rs, rt, trap_code);
|
|
if (mode64) {
|
|
if (trap_code == 7)
|
|
stmt(IRStmt_Exit(binop(Iop_CmpNE64, getIReg(rs),
|
|
getIReg(rt)), Ijk_SigFPE_IntDiv,
|
|
IRConst_U64(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
else if (trap_code == 6)
|
|
stmt(IRStmt_Exit(binop(Iop_CmpNE64, getIReg(rs),
|
|
getIReg(rt)), Ijk_SigFPE_IntOvf,
|
|
IRConst_U64(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
else
|
|
stmt(IRStmt_Exit(binop(Iop_CmpNE64, getIReg(rs),
|
|
getIReg(rt)), Ijk_SigTRAP,
|
|
IRConst_U64(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
} else {
|
|
if (trap_code == 7)
|
|
stmt(IRStmt_Exit(binop(Iop_CmpNE32, getIReg(rs),
|
|
getIReg(rt)), Ijk_SigFPE_IntDiv,
|
|
IRConst_U32(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
else if (trap_code == 6)
|
|
stmt(IRStmt_Exit(binop(Iop_CmpNE32, getIReg(rs),
|
|
getIReg(rt)), Ijk_SigFPE_IntOvf,
|
|
IRConst_U32(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
else
|
|
stmt(IRStmt_Exit(binop(Iop_CmpNE32, getIReg(rs),
|
|
getIReg(rt)), Ijk_SigTRAP,
|
|
IRConst_U32(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
}
|
|
break;
|
|
}
|
|
case 0x14:
|
|
case 0x16:
|
|
case 0x17: /* DSLLV, DROTRV:DSRLV, DSRAV */
|
|
case 0x38:
|
|
case 0x3A:
|
|
case 0x3B: /* DSLL, DROTL:DSRL, DSRA */
|
|
case 0x3C:
|
|
case 0x3E:
|
|
case 0x3F: /* DSLL32, DROTR32:DSRL32, DSRA32 */
|
|
if (dis_instr_shrt(cins))
|
|
break;
|
|
goto decode_failure;
|
|
|
|
case 0x0F: /* SYNC */
|
|
DIP("sync 0x%x", sel);
|
|
/* Just ignore it. */
|
|
break;
|
|
|
|
case 0x2C: { /* Doubleword Add - DADD; MIPS64 */
|
|
DIP("dadd r%u, r%u, r%u", rd, rs, rt);
|
|
IRTemp tmpRs64 = newTemp(Ity_I64);
|
|
IRTemp tmpRt64 = newTemp(Ity_I64);
|
|
|
|
assign(tmpRs64, getIReg(rs));
|
|
assign(tmpRt64, getIReg(rt));
|
|
|
|
t0 = newTemp(Ity_I64);
|
|
t1 = newTemp(Ity_I64);
|
|
t2 = newTemp(Ity_I64);
|
|
t3 = newTemp(Ity_I64);
|
|
t4 = newTemp(Ity_I64);
|
|
/* dst = src0 + src1
|
|
if(sign(src0 ) != sign(src1 ))
|
|
goto no overflow;
|
|
if(sign(dst) == sign(src0 ))
|
|
goto no overflow;
|
|
we have overflow! */
|
|
|
|
assign(t0, binop(Iop_Add64, mkexpr(tmpRs64), mkexpr(tmpRt64)));
|
|
assign(t1, binop(Iop_Xor64, mkexpr(tmpRs64), mkexpr(tmpRt64)));
|
|
assign(t2, unop(Iop_1Uto64,
|
|
binop(Iop_CmpEQ64,
|
|
binop(Iop_And64, mkexpr(t1),
|
|
mkU64(0x8000000000000000ULL)),
|
|
mkU64(0x8000000000000000ULL))));
|
|
|
|
assign(t3, binop(Iop_Xor64, mkexpr(t0), mkexpr(tmpRs64)));
|
|
assign(t4, unop(Iop_1Uto64,
|
|
binop(Iop_CmpNE64,
|
|
binop(Iop_And64, mkexpr(t3),
|
|
mkU64(0x8000000000000000ULL)),
|
|
mkU64(0x8000000000000000ULL))));
|
|
|
|
stmt(IRStmt_Exit(binop(Iop_CmpEQ64,
|
|
binop(Iop_Or64, mkexpr(t2), mkexpr(t4)),
|
|
mkU64(0)),
|
|
Ijk_SigFPE_IntOvf,
|
|
IRConst_U64(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
|
|
putIReg(rd, mkexpr(t0));
|
|
break;
|
|
}
|
|
|
|
case 0x2D: /* Doubleword Add Unsigned - DADDU; MIPS64 */
|
|
DIP("daddu r%u, r%u, r%u", rd, rs, rt);
|
|
ALU_PATTERN(Iop_Add64);
|
|
break;
|
|
|
|
case 0x2E: { /* Doubleword Subtract - DSUB; MIPS64 */
|
|
DIP("dsub r%u, r%u, r%u", rd, rs, rt);
|
|
IRTemp tmpRs64 = newTemp(Ity_I64);
|
|
IRTemp tmpRt64 = newTemp(Ity_I64);
|
|
|
|
assign(tmpRs64, getIReg(rs));
|
|
assign(tmpRt64, getIReg(rt));
|
|
t0 = newTemp(Ity_I64);
|
|
t1 = newTemp(Ity_I64);
|
|
t2 = newTemp(Ity_I64);
|
|
t3 = newTemp(Ity_I64);
|
|
t4 = newTemp(Ity_I64);
|
|
t5 = newTemp(Ity_I64);
|
|
/* dst = src0 + (-1 * src1)
|
|
if(sign(src0 ) != sign((-1 * src1) ))
|
|
goto no overflow;
|
|
if(sign(dst) == sign(src0 ))
|
|
goto no overflow;
|
|
we have overflow! */
|
|
|
|
assign(t5, binop(Iop_Mul64,
|
|
mkexpr(tmpRt64),
|
|
mkU64(0xffffffffffffffffULL)));
|
|
assign(t0, binop(Iop_Add64, mkexpr(tmpRs64), mkexpr(t5)));
|
|
assign(t1, binop(Iop_Xor64, mkexpr(tmpRs64), mkexpr(t5)));
|
|
assign(t2, unop(Iop_1Sto64,
|
|
binop(Iop_CmpEQ64,
|
|
binop(Iop_And64,
|
|
mkexpr(t1),
|
|
mkU64(0x8000000000000000ULL)),
|
|
mkU64(0x8000000000000000ULL))));
|
|
|
|
assign(t3, binop(Iop_Xor64, mkexpr(t0), mkexpr(tmpRs64)));
|
|
assign(t4, unop(Iop_1Sto64,
|
|
binop(Iop_CmpNE64,
|
|
binop(Iop_And64,
|
|
mkexpr(t3),
|
|
mkU64(0x8000000000000000ULL)),
|
|
mkU64(0x8000000000000000ULL))));
|
|
|
|
stmt(IRStmt_Exit(binop(Iop_CmpEQ64, binop(Iop_Or64, mkexpr(t2),
|
|
mkexpr(t4)), mkU64(0)), Ijk_SigFPE_IntOvf,
|
|
IRConst_U64(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
|
|
putIReg(rd, binop(Iop_Sub64, getIReg(rs), getIReg(rt)));
|
|
break;
|
|
}
|
|
|
|
case 0x2F: /* Doubleword Subtract Unsigned - DSUBU; MIPS64 */
|
|
DIP("dsub r%u, r%u,r%u", rd, rt, rt);
|
|
ALU_PATTERN(Iop_Sub64);
|
|
break;
|
|
|
|
default:
|
|
goto decode_failure;
|
|
}
|
|
break;
|
|
|
|
case 0x01: /* Regimm */
|
|
|
|
switch (rt) {
|
|
case 0x00: /* BLTZ */
|
|
DIP("bltz r%u, %u", rs, imm);
|
|
if (mode64) {
|
|
if (!dis_instr_branch(cins, &dres, resteerOkFn,
|
|
callback_opaque, &bstmt))
|
|
goto decode_failure;
|
|
} else
|
|
dis_branch(False, binop(Iop_CmpEQ32, binop(Iop_And32, getIReg(rs),
|
|
mkU32(0x80000000)), mkU32(0x80000000)), imm, &bstmt);
|
|
break;
|
|
|
|
case 0x01: /* BGEZ */
|
|
DIP("bgez r%u, %u", rs, imm);
|
|
if (mode64) {
|
|
if (!dis_instr_branch(cins, &dres, resteerOkFn,
|
|
callback_opaque, &bstmt))
|
|
goto decode_failure;
|
|
} else
|
|
dis_branch(False, binop(Iop_CmpEQ32, binop(Iop_And32, getIReg(rs),
|
|
mkU32(0x80000000)), mkU32(0x0)), imm, &bstmt);
|
|
break;
|
|
|
|
case 0x02: /* BLTZL */
|
|
DIP("bltzl r%u, %u", rs, imm);
|
|
lastn = dis_branch_likely(binop(mode64 ? Iop_CmpNE64 : Iop_CmpNE32,
|
|
binop(mode64 ? Iop_And64 : Iop_And32, getIReg(rs),
|
|
mode64 ? mkU64(0x8000000000000000ULL) : mkU32(0x80000000)),
|
|
mode64 ? mkU64(0x8000000000000000ULL) : mkU32(0x80000000)),
|
|
imm);
|
|
break;
|
|
|
|
case 0x03: /* BGEZL */
|
|
DIP("bgezl r%u, %u", rs, imm);
|
|
lastn = dis_branch_likely(binop(mode64 ? Iop_CmpNE64 : Iop_CmpNE32,
|
|
binop(mode64 ? Iop_And64 : Iop_And32, getIReg(rs),
|
|
mode64 ? mkU64(0x8000000000000000ULL) : mkU32(0x80000000)),
|
|
mode64 ? mkU64(0x0) : mkU32(0x0)), imm);
|
|
break;
|
|
|
|
case 0x10: /* BLTZAL */
|
|
DIP("bltzal r%u, %u", rs, imm);
|
|
if (mode64) {
|
|
if (!dis_instr_branch(cins, &dres, resteerOkFn,
|
|
callback_opaque, &bstmt))
|
|
goto decode_failure;
|
|
} else
|
|
dis_branch(True, binop(Iop_CmpEQ32, binop(Iop_And32, getIReg(rs),
|
|
mkU32(0x80000000)), mkU32(0x80000000)), imm, &bstmt);
|
|
break;
|
|
|
|
case 0x12: /* BLTZALL */
|
|
DIP("bltzall r%u, %u", rs, imm);
|
|
putIReg(31, mode64 ? mkU64(guest_PC_curr_instr + 8) :
|
|
mkU32(guest_PC_curr_instr + 8));
|
|
lastn = dis_branch_likely(binop(mode64 ? Iop_CmpNE64 : Iop_CmpNE32,
|
|
binop(mode64 ? Iop_And64 : Iop_And32, getIReg(rs),
|
|
mode64 ? mkU64(0x8000000000000000ULL) : mkU32(0x80000000)),
|
|
mode64 ? mkU64(0x8000000000000000ULL) : mkU32(0x80000000)),
|
|
imm);
|
|
break;
|
|
|
|
case 0x11: /* BGEZAL */
|
|
DIP("bgezal r%u, %u", rs, imm);
|
|
if (mode64) {
|
|
if (!dis_instr_branch(cins, &dres, resteerOkFn,
|
|
callback_opaque, &bstmt))
|
|
goto decode_failure;
|
|
} else
|
|
dis_branch(True, binop(Iop_CmpEQ32, binop(Iop_And32, getIReg(rs),
|
|
mkU32(0x80000000)), mkU32(0x0)), imm, &bstmt);
|
|
break;
|
|
|
|
case 0x13: /* BGEZALL */
|
|
DIP("bgezall r%u, %u", rs, imm);
|
|
if (mode64) {
|
|
putIReg(31, mkU64(guest_PC_curr_instr + 8));
|
|
lastn = dis_branch_likely(binop(Iop_CmpNE64,
|
|
binop(Iop_And64,
|
|
getIReg(rs),
|
|
mkU64(0x8000000000000000ULL)),
|
|
mkU64(0x0)),
|
|
imm);
|
|
} else {
|
|
putIReg(31, mkU32(guest_PC_curr_instr + 8));
|
|
lastn = dis_branch_likely(binop(Iop_CmpNE32, binop(Iop_And32,
|
|
getIReg(rs), mkU32(0x80000000)),
|
|
mkU32(0x0)), imm);
|
|
}
|
|
break;
|
|
|
|
case 0x08: /* TGEI */
|
|
DIP("tgei r%u, %u %u", rs, imm, trap_code);
|
|
if (mode64) {
|
|
stmt (IRStmt_Exit (unop (Iop_Not1,
|
|
binop (Iop_CmpLT64S,
|
|
getIReg (rs),
|
|
mkU64 (extend_s_16to64 (imm)))),
|
|
Ijk_SigTRAP,
|
|
IRConst_U64(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
} else {
|
|
stmt (IRStmt_Exit (unop (Iop_Not1,
|
|
binop (Iop_CmpLT32S,
|
|
getIReg (rs),
|
|
mkU32 (extend_s_16to32 (imm)))),
|
|
Ijk_SigTRAP,
|
|
IRConst_U32(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
}
|
|
break;
|
|
|
|
case 0x09: { /* TGEIU */
|
|
DIP("tgeiu r%u, %u %u", rs, imm, trap_code);
|
|
if (mode64) {
|
|
stmt (IRStmt_Exit (unop (Iop_Not1,
|
|
binop (Iop_CmpLT64U,
|
|
getIReg (rs),
|
|
mkU64 (extend_s_16to64 (imm)))),
|
|
Ijk_SigTRAP,
|
|
IRConst_U64(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
} else {
|
|
stmt (IRStmt_Exit (unop (Iop_Not1,
|
|
binop (Iop_CmpLT32U,
|
|
getIReg (rs),
|
|
mkU32 (extend_s_16to32 (imm)))),
|
|
Ijk_SigTRAP,
|
|
IRConst_U32(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
}
|
|
break;
|
|
}
|
|
case 0x0A: { /* TLTI */
|
|
DIP("tlti r%u, %u %u", rs, imm, trap_code);
|
|
if (mode64) {
|
|
stmt (IRStmt_Exit (binop (Iop_CmpLT64S, getIReg (rs),
|
|
mkU64 (extend_s_16to64 (imm))),
|
|
Ijk_SigTRAP,
|
|
IRConst_U64(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
} else {
|
|
stmt (IRStmt_Exit (binop (Iop_CmpLT32S, getIReg (rs),
|
|
mkU32 (extend_s_16to32 (imm))),
|
|
Ijk_SigTRAP,
|
|
IRConst_U32(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
}
|
|
break;
|
|
}
|
|
case 0x0B: { /* TLTIU */
|
|
DIP("tltiu r%u, %u %u", rs, imm, trap_code);
|
|
if (mode64) {
|
|
stmt (IRStmt_Exit (binop (Iop_CmpLT64U, getIReg (rs),
|
|
mkU64 (extend_s_16to64 (imm))),
|
|
Ijk_SigTRAP,
|
|
IRConst_U64(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
} else {
|
|
stmt (IRStmt_Exit (binop (Iop_CmpLT32U, getIReg (rs),
|
|
mkU32 (extend_s_16to32 (imm))),
|
|
Ijk_SigTRAP,
|
|
IRConst_U32(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
}
|
|
break;
|
|
}
|
|
case 0x0C: { /* TEQI */
|
|
DIP("teqi r%u, %u %u", rs, imm, trap_code);
|
|
if (mode64) {
|
|
stmt (IRStmt_Exit (binop (Iop_CmpEQ64, getIReg (rs),
|
|
mkU64 (extend_s_16to64 (imm))),
|
|
Ijk_SigTRAP,
|
|
IRConst_U64(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
} else {
|
|
stmt (IRStmt_Exit (binop (Iop_CmpEQ32, getIReg (rs),
|
|
mkU32 (extend_s_16to32 (imm))),
|
|
Ijk_SigTRAP,
|
|
IRConst_U32(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
}
|
|
break;
|
|
}
|
|
case 0x0E: { /* TNEI */
|
|
DIP("tnei r%u, %u %u", rs, imm, trap_code);
|
|
if (mode64) {
|
|
stmt (IRStmt_Exit (binop (Iop_CmpNE64, getIReg (rs),
|
|
mkU64 (extend_s_16to64 (imm))),
|
|
Ijk_SigTRAP,
|
|
IRConst_U64(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
} else {
|
|
stmt (IRStmt_Exit (binop (Iop_CmpNE32, getIReg (rs),
|
|
mkU32 (extend_s_16to32 (imm))),
|
|
Ijk_SigTRAP,
|
|
IRConst_U32(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
}
|
|
break;
|
|
}
|
|
case 0x1C: { /* BPOSGE32 */
|
|
DIP("bposge32 %u", 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 */
|
|
break;
|
|
|
|
default:
|
|
goto decode_failure;
|
|
}
|
|
break;
|
|
|
|
case 0x04:
|
|
DIP("beq r%u, r%u, %u", rs, rt, imm);
|
|
if (mode64)
|
|
dis_branch(False, binop(Iop_CmpEQ64, getIReg(rs), getIReg(rt)),
|
|
imm, &bstmt);
|
|
else
|
|
dis_branch(False, binop(Iop_CmpEQ32, getIReg(rs), getIReg(rt)),
|
|
imm, &bstmt);
|
|
break;
|
|
|
|
case 0x14:
|
|
DIP("beql r%u, r%u, %u", rs, rt, imm);
|
|
lastn = dis_branch_likely(binop(mode64 ? Iop_CmpNE64 : Iop_CmpNE32,
|
|
getIReg(rs), getIReg(rt)), imm);
|
|
break;
|
|
|
|
case 0x05:
|
|
DIP("bne r%u, r%u, %u", rs, rt, imm);
|
|
if (mode64)
|
|
dis_branch(False, binop(Iop_CmpNE64, getIReg(rs), getIReg(rt)),
|
|
imm, &bstmt);
|
|
else
|
|
dis_branch(False, binop(Iop_CmpNE32, getIReg(rs), getIReg(rt)),
|
|
imm, &bstmt);
|
|
break;
|
|
|
|
case 0x15:
|
|
DIP("bnel r%u, r%u, %u", rs, rt, imm);
|
|
lastn = dis_branch_likely(binop(mode64 ? Iop_CmpEQ64 : Iop_CmpEQ32,
|
|
getIReg(rs), getIReg(rt)), imm);
|
|
break;
|
|
|
|
case 0x07: /* BGTZ */
|
|
DIP("bgtz r%u, %u", rs, imm);
|
|
if (mode64)
|
|
dis_branch(False, unop(Iop_Not1, binop(Iop_CmpLE64S, getIReg(rs),
|
|
mkU64(0x00))), imm, &bstmt);
|
|
else
|
|
dis_branch(False, unop(Iop_Not1, binop(Iop_CmpLE32S, getIReg(rs),
|
|
mkU32(0x00))), imm, &bstmt);
|
|
break;
|
|
|
|
case 0x17: /* BGTZL */
|
|
DIP("bgtzl r%u, %u", rs, imm);
|
|
if (mode64)
|
|
lastn = dis_branch_likely(binop(Iop_CmpLE64S, getIReg(rs),
|
|
mkU64(0x00)), imm);
|
|
else
|
|
lastn = dis_branch_likely(binop(Iop_CmpLE32S, getIReg(rs),
|
|
mkU32(0x00)), imm);
|
|
break;
|
|
|
|
case 0x06: /* BLEZ */
|
|
DIP("blez r%u, %u", rs, imm);
|
|
if (mode64)
|
|
dis_branch(False, binop(Iop_CmpLE64S, getIReg(rs), mkU64(0x0)),
|
|
imm, &bstmt);
|
|
else
|
|
dis_branch(False,binop(Iop_CmpLE32S, getIReg(rs), mkU32(0x0)), imm,
|
|
&bstmt);
|
|
break;
|
|
|
|
case 0x16: /* BLEZL */
|
|
DIP("blezl r%u, %u", rs, imm);
|
|
lastn = dis_branch_likely(unop(Iop_Not1, (binop(mode64 ? Iop_CmpLE64S :
|
|
Iop_CmpLE32S, getIReg(rs), mode64 ?
|
|
mkU64(0x0) : mkU32(0x0)))), imm);
|
|
break;
|
|
|
|
case 0x08: { /* ADDI */
|
|
DIP("addi r%u, r%u, %u", rt, rs, imm);
|
|
IRTemp tmpRs32 = newTemp(Ity_I32);
|
|
assign(tmpRs32, mkNarrowTo32(ty, getIReg(rs)));
|
|
|
|
t0 = newTemp(Ity_I32);
|
|
t1 = newTemp(Ity_I32);
|
|
t2 = newTemp(Ity_I32);
|
|
t3 = newTemp(Ity_I32);
|
|
t4 = newTemp(Ity_I32);
|
|
/* dst = src0 + sign(imm)
|
|
if(sign(src0 ) != sign(imm ))
|
|
goto no overflow;
|
|
if(sign(dst) == sign(src0 ))
|
|
goto no overflow;
|
|
we have overflow! */
|
|
|
|
assign(t0, binop(Iop_Add32, mkexpr(tmpRs32),
|
|
mkU32(extend_s_16to32(imm))));
|
|
assign(t1, binop(Iop_Xor32, mkexpr(tmpRs32),
|
|
mkU32(extend_s_16to32(imm))));
|
|
assign(t2, unop(Iop_1Sto32, binop(Iop_CmpEQ32, binop(Iop_And32,
|
|
mkexpr(t1), mkU32(0x80000000)), mkU32(0x80000000))));
|
|
|
|
assign(t3, binop(Iop_Xor32, mkexpr(t0), mkexpr(tmpRs32)));
|
|
assign(t4, unop(Iop_1Sto32, binop(Iop_CmpNE32, binop(Iop_And32,
|
|
mkexpr(t3), mkU32(0x80000000)), mkU32(0x80000000))));
|
|
|
|
stmt(IRStmt_Exit(binop(Iop_CmpEQ32, binop(Iop_Or32, mkexpr(t2),
|
|
mkexpr(t4)), mkU32(0)), Ijk_SigFPE_IntOvf,
|
|
mode64 ? IRConst_U64(guest_PC_curr_instr + 4) :
|
|
IRConst_U32(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
|
|
putIReg(rt, mkWidenFrom32(ty, mkexpr(t0), True));
|
|
break;
|
|
}
|
|
case 0x09: /* ADDIU */
|
|
DIP("addiu r%u, r%u, %u", rt, rs, imm);
|
|
if (mode64) {
|
|
putIReg(rt, mkWidenFrom32(ty, binop(Iop_Add32,
|
|
mkNarrowTo32(ty, getIReg(rs)),mkU32(extend_s_16to32(imm))),
|
|
True));
|
|
} else
|
|
putIReg(rt, binop(Iop_Add32, getIReg(rs),mkU32(extend_s_16to32(imm))));
|
|
break;
|
|
|
|
case 0x0C: /* ANDI */
|
|
DIP("andi r%u, r%u, %u", rt, rs, imm);
|
|
if (mode64) {
|
|
ALUI_PATTERN64(Iop_And64);
|
|
} else {
|
|
ALUI_PATTERN(Iop_And32);
|
|
}
|
|
break;
|
|
|
|
case 0x0E: /* XORI */
|
|
DIP("xori r%u, r%u, %u", rt, rs, imm);
|
|
if (mode64) {
|
|
ALUI_PATTERN64(Iop_Xor64);
|
|
} else {
|
|
ALUI_PATTERN(Iop_Xor32);
|
|
}
|
|
break;
|
|
|
|
case 0x0D: /* ORI */
|
|
DIP("ori r%u, r%u, %u", rt, rs, imm);
|
|
if (mode64) {
|
|
ALUI_PATTERN64(Iop_Or64);
|
|
} else {
|
|
ALUI_PATTERN(Iop_Or32);
|
|
}
|
|
break;
|
|
|
|
case 0x0A: /* SLTI */
|
|
DIP("slti r%u, r%u, %u", rt, rs, imm);
|
|
if (mode64)
|
|
putIReg(rt, unop(Iop_1Uto64, binop(Iop_CmpLT64S, getIReg(rs),
|
|
mkU64(extend_s_16to64(imm)))));
|
|
else
|
|
putIReg(rt, unop(Iop_1Uto32, binop(Iop_CmpLT32S, getIReg(rs),
|
|
mkU32(extend_s_16to32(imm)))));
|
|
break;
|
|
|
|
case 0x0B: /* SLTIU */
|
|
DIP("sltiu r%u, r%u, %u", rt, rs, imm);
|
|
if (mode64)
|
|
putIReg(rt, unop(Iop_1Uto64, binop(Iop_CmpLT64U, getIReg(rs),
|
|
mkU64(extend_s_16to64(imm)))));
|
|
else
|
|
putIReg(rt, unop(Iop_1Uto32, binop(Iop_CmpLT32U, getIReg(rs),
|
|
mkU32(extend_s_16to32(imm)))));
|
|
break;
|
|
|
|
case 0x18: { /* Doubleword Add Immidiate - DADD; MIPS64 */
|
|
DIP("daddi r%u, r%u, %u", rt, rs, imm);
|
|
IRTemp tmpRs64 = newTemp(Ity_I64);
|
|
assign(tmpRs64, getIReg(rs));
|
|
|
|
t0 = newTemp(Ity_I64);
|
|
t1 = newTemp(Ity_I64);
|
|
t2 = newTemp(Ity_I64);
|
|
t3 = newTemp(Ity_I64);
|
|
t4 = newTemp(Ity_I64);
|
|
/* dst = src0 + sign(imm)
|
|
if(sign(src0 ) != sign(imm ))
|
|
goto no overflow;
|
|
if(sign(dst) == sign(src0 ))
|
|
goto no overflow;
|
|
we have overflow! */
|
|
|
|
assign(t0, binop(Iop_Add64, mkexpr(tmpRs64),
|
|
mkU64(extend_s_16to64(imm))));
|
|
assign(t1, binop(Iop_Xor64, mkexpr(tmpRs64),
|
|
mkU64(extend_s_16to64(imm))));
|
|
assign(t2, unop(Iop_1Sto64, binop(Iop_CmpEQ64, binop(Iop_And64,
|
|
mkexpr(t1), mkU64(0x8000000000000000ULL)),
|
|
mkU64(0x8000000000000000ULL))));
|
|
|
|
assign(t3, binop(Iop_Xor64, mkexpr(t0), mkexpr(tmpRs64)));
|
|
assign(t4, unop(Iop_1Sto64, binop(Iop_CmpNE64, binop(Iop_And64,
|
|
mkexpr(t3), mkU64(0x8000000000000000ULL)),
|
|
mkU64(0x8000000000000000ULL))));
|
|
|
|
stmt(IRStmt_Exit(binop(Iop_CmpEQ64, binop(Iop_Or64, mkexpr(t2),
|
|
mkexpr(t4)), mkU64(0)), Ijk_SigFPE_IntOvf,
|
|
IRConst_U64(guest_PC_curr_instr + 4),
|
|
OFFB_PC));
|
|
|
|
putIReg(rt, mkexpr(t0));
|
|
break;
|
|
}
|
|
|
|
case 0x19: /* Doubleword Add Immidiate Unsigned - DADDIU; MIPS64 */
|
|
DIP("daddiu r%u, r%u, %u", rt, rs, imm);
|
|
putIReg(rt, binop(Iop_Add64, getIReg(rs), mkU64(extend_s_16to64(imm))));
|
|
break;
|
|
|
|
case 0x1A: {
|
|
/* Load Doubleword Left - LDL; MIPS64 */
|
|
vassert(mode64);
|
|
DIP("ldl r%u, %u(r%u)", rt, imm, rs);
|
|
/* t1 = addr */
|
|
#if defined (_MIPSEL)
|
|
t1 = newTemp(Ity_I64);
|
|
assign(t1, binop(Iop_Add64, getIReg(rs), mkU64(extend_s_16to64(imm))));
|
|
#elif defined (_MIPSEB)
|
|
t1 = newTemp(Ity_I64);
|
|
assign(t1, binop(Iop_Xor64, mkU64(0x7), binop(Iop_Add64, getIReg(rs),
|
|
mkU64(extend_s_16to64(imm)))));
|
|
#endif
|
|
/* t2 = word addr */
|
|
/* t4 = addr mod 8 */
|
|
LWX_SWX_PATTERN64_1;
|
|
|
|
/* t3 = word content - shifted */
|
|
t3 = newTemp(Ity_I64);
|
|
assign(t3, binop(Iop_Shl64, load(Ity_I64, mkexpr(t2)),
|
|
narrowTo(Ity_I8, binop(Iop_Shl64, binop(Iop_Sub64, mkU64(0x07),
|
|
mkexpr(t4)), mkU8(3)))));
|
|
|
|
/* rt content - adjusted */
|
|
t5 = newTemp(Ity_I64);
|
|
t6 = newTemp(Ity_I64);
|
|
t7 = newTemp(Ity_I64);
|
|
|
|
assign(t5, binop(Iop_Mul64, mkexpr(t4), mkU64(0x8)));
|
|
|
|
assign(t6, binop(Iop_Shr64, mkU64(0x00FFFFFFFFFFFFFFULL),
|
|
narrowTo(Ity_I8, mkexpr(t5))));
|
|
|
|
assign(t7, binop(Iop_And64, getIReg(rt), mkexpr(t6)));
|
|
|
|
putIReg(rt, binop(Iop_Or64, mkexpr(t7), mkexpr(t3)));
|
|
break;
|
|
}
|
|
|
|
case 0x1B: {
|
|
/* Load Doubleword Right - LDR; MIPS64 */
|
|
vassert(mode64);
|
|
DIP("ldr r%u,%u(r%u)", rt, imm, rs);
|
|
/* t1 = addr */
|
|
#if defined (_MIPSEL)
|
|
t1 = newTemp(Ity_I64);
|
|
assign(t1, binop(Iop_Add64, getIReg(rs), mkU64(extend_s_16to64(imm))));
|
|
#elif defined (_MIPSEB)
|
|
t1 = newTemp(Ity_I64);
|
|
assign(t1, binop(Iop_Xor64, mkU64(0x7), binop(Iop_Add64, getIReg(rs),
|
|
mkU64(extend_s_16to64(imm)))));
|
|
#endif
|
|
/* t2 = word addr */
|
|
/* t4 = addr mod 8 */
|
|
LWX_SWX_PATTERN64_1;
|
|
|
|
/* t3 = word content - shifted */
|
|
t3 = newTemp(Ity_I64);
|
|
assign(t3, binop(Iop_Shr64, load(Ity_I64, mkexpr(t2)),
|
|
narrowTo(Ity_I8, binop(Iop_Shl64, mkexpr(t4), mkU8(3)))));
|
|
|
|
/* rt content - adjusted */
|
|
t5 = newTemp(Ity_I64);
|
|
assign(t5, binop(Iop_And64, getIReg(rt), unop(Iop_Not64,
|
|
binop(Iop_Shr64, mkU64(0xFFFFFFFFFFFFFFFFULL),
|
|
narrowTo(Ity_I8, binop(Iop_Shl64, mkexpr(t4), mkU8(0x3)))))));
|
|
|
|
putIReg(rt, binop(Iop_Or64, mkexpr(t5), mkexpr(t3)));
|
|
break;
|
|
}
|
|
|
|
case 0x27: /* Load Word unsigned - LWU; MIPS64 */
|
|
DIP("lwu r%u,%u(r%u)", rt, imm, rs);
|
|
LOAD_STORE_PATTERN;
|
|
|
|
putIReg(rt, mkWidenFrom32(ty, load(Ity_I32, mkexpr(t1)), False));
|
|
break;
|
|
|
|
case 0x30: /* LL / LWC0 */
|
|
DIP("ll r%u, %u(r%u)", rt, imm, rs);
|
|
LOAD_STORE_PATTERN;
|
|
|
|
t2 = newTemp(Ity_I32);
|
|
#if defined (_MIPSEL)
|
|
stmt(IRStmt_LLSC(Iend_LE, t2, mkexpr(t1), NULL /* this is a load */ ));
|
|
#elif defined (_MIPSEB)
|
|
stmt(IRStmt_LLSC(Iend_BE, t2, mkexpr(t1), NULL /* this is a load */ ));
|
|
#endif
|
|
if (mode64)
|
|
putIReg(rt, unop(Iop_32Sto64, mkexpr(t2)));
|
|
else
|
|
putIReg(rt, mkexpr(t2));
|
|
break;
|
|
|
|
case 0x34: /* Load Linked Doubleword - LLD; MIPS64 */
|
|
DIP("lld r%u, %u(r%u)", rt, imm, rs);
|
|
LOAD_STORE_PATTERN;
|
|
|
|
t2 = newTemp(Ity_I64);
|
|
#if defined (_MIPSEL)
|
|
stmt(IRStmt_LLSC
|
|
(Iend_LE, t2, mkexpr(t1), NULL /* this is a load */ ));
|
|
#elif defined (_MIPSEB)
|
|
stmt(IRStmt_LLSC
|
|
(Iend_BE, t2, mkexpr(t1), NULL /* this is a load */ ));
|
|
#endif
|
|
|
|
putIReg(rt, mkexpr(t2));
|
|
break;
|
|
|
|
case 0x38: /* SC / SWC0 */
|
|
DIP("sc r%u, %u(r%u)", rt, imm, rs);
|
|
LOAD_STORE_PATTERN;
|
|
|
|
t2 = newTemp(Ity_I1);
|
|
#if defined (_MIPSEL)
|
|
stmt(IRStmt_LLSC(Iend_LE, t2, mkexpr(t1), mkNarrowTo32(ty, getIReg(rt))));
|
|
#elif defined (_MIPSEB)
|
|
stmt(IRStmt_LLSC(Iend_BE, t2, mkexpr(t1), mkNarrowTo32(ty, getIReg(rt))));
|
|
#endif
|
|
|
|
putIReg(rt, unop(mode64 ? Iop_1Uto64 : Iop_1Uto32, mkexpr(t2)));
|
|
break;
|
|
|
|
case 0x3C: /* Store Conditional Doubleword - SCD; MIPS64 */
|
|
DIP("sdc r%u, %u(r%u)", rt, imm, rs);
|
|
LOAD_STORE_PATTERN;
|
|
|
|
t2 = newTemp(Ity_I1);
|
|
#if defined (_MIPSEL)
|
|
stmt(IRStmt_LLSC(Iend_LE, t2, mkexpr(t1), getIReg(rt)));
|
|
#elif defined (_MIPSEB)
|
|
stmt(IRStmt_LLSC(Iend_BE, t2, mkexpr(t1), getIReg(rt)));
|
|
#endif
|
|
|
|
putIReg(rt, unop(Iop_1Uto64, mkexpr(t2)));
|
|
break;
|
|
|
|
case 0x37: /* Load Doubleword - LD; MIPS64 */
|
|
DIP("ld r%u, %u(r%u)", rt, imm, rs);
|
|
LOAD_STORE_PATTERN;
|
|
putIReg(rt, load(Ity_I64, mkexpr(t1)));
|
|
break;
|
|
|
|
case 0x3F: /* Store Doubleword - SD; MIPS64 */
|
|
DIP("sd r%u, %u(r%u)", rt, imm, rs);
|
|
LOAD_STORE_PATTERN;
|
|
store(mkexpr(t1), getIReg(rt));
|
|
break;
|
|
|
|
case 0x32: /* Branch on Bit Clear - BBIT0; Cavium OCTEON */
|
|
/* Cavium Specific instructions. */
|
|
if (VEX_MIPS_COMP_ID(archinfo->hwcaps) == VEX_PRID_COMP_CAVIUM) {
|
|
DIP("bbit0 r%u, 0x%x, %x", rs, rt, imm);
|
|
t0 = newTemp(Ity_I32);
|
|
t1 = newTemp(Ity_I32);
|
|
assign(t0, mkU32(0x1));
|
|
assign(t1, binop(Iop_Shl32, mkexpr(t0), mkU8(rt)));
|
|
dis_branch(False, binop(Iop_CmpEQ32,
|
|
binop(Iop_And32,
|
|
mkexpr(t1),
|
|
mkNarrowTo32(ty, getIReg(rs))),
|
|
mkU32(0x0)),
|
|
imm, &bstmt);
|
|
break;
|
|
} else {
|
|
goto decode_failure;
|
|
}
|
|
|
|
case 0x36: /* Branch on Bit Clear Plus 32 - BBIT032; Cavium OCTEON */
|
|
/* Cavium Specific instructions. */
|
|
if (VEX_MIPS_COMP_ID(archinfo->hwcaps) == VEX_PRID_COMP_CAVIUM) {
|
|
DIP("bbit032 r%u, 0x%x, %x", rs, rt, imm);
|
|
t0 = newTemp(Ity_I64);
|
|
t1 = newTemp(Ity_I8); /* Shift. */
|
|
t2 = newTemp(Ity_I64);
|
|
assign(t0, mkU64(0x1));
|
|
assign(t1, binop(Iop_Add8, mkU8(rt), mkU8(32)));
|
|
assign(t2, binop(Iop_Shl64, mkexpr(t0), mkexpr(t1)));
|
|
dis_branch(False, binop(Iop_CmpEQ64,
|
|
binop(Iop_And64,
|
|
mkexpr(t2),
|
|
getIReg(rs)),
|
|
mkU64(0x0)),
|
|
imm, &bstmt);
|
|
break;
|
|
} else {
|
|
goto decode_failure;
|
|
}
|
|
|
|
case 0x3A: /* Branch on Bit Set - BBIT1; Cavium OCTEON */
|
|
/* Cavium Specific instructions. */
|
|
if (VEX_MIPS_COMP_ID(archinfo->hwcaps) == VEX_PRID_COMP_CAVIUM) {
|
|
DIP("bbit1 r%u, 0x%x, %x", rs, rt, imm);
|
|
t0 = newTemp(Ity_I32);
|
|
t1 = newTemp(Ity_I32);
|
|
assign(t0, mkU32(0x1));
|
|
assign(t1, binop(Iop_Shl32, mkexpr(t0), mkU8(rt)));
|
|
dis_branch(False, binop(Iop_CmpNE32,
|
|
binop(Iop_And32,
|
|
mkexpr(t1),
|
|
mkNarrowTo32(ty, getIReg(rs))),
|
|
mkU32(0x0)),
|
|
imm, &bstmt);
|
|
break;
|
|
} else {
|
|
goto decode_failure;
|
|
}
|
|
|
|
case 0x3E: /* Branch on Bit Set Plus 32 - BBIT132; Cavium OCTEON */
|
|
/* Cavium Specific instructions. */
|
|
if (VEX_MIPS_COMP_ID(archinfo->hwcaps) == VEX_PRID_COMP_CAVIUM) {
|
|
DIP("bbit132 r%u, 0x%x, %x", rs, rt, imm);
|
|
t0 = newTemp(Ity_I64);
|
|
t1 = newTemp(Ity_I8); /* Shift. */
|
|
t2 = newTemp(Ity_I64);
|
|
assign(t0, mkU64(0x1));
|
|
assign(t1, binop(Iop_Add8, mkU8(rt), mkU8(32)));
|
|
assign(t2, binop(Iop_Shl64, mkexpr(t0), mkexpr(t1)));
|
|
dis_branch(False, binop(Iop_CmpNE64,
|
|
binop(Iop_And64,
|
|
mkexpr(t2),
|
|
getIReg(rs)),
|
|
mkU64(0x0)),
|
|
imm, &bstmt);
|
|
break;
|
|
} else {
|
|
goto decode_failure;
|
|
}
|
|
|
|
default:
|
|
goto decode_failure;
|
|
|
|
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)
|
|
vex_printf("vex mips->IR: unhandled instruction bytes: "
|
|
"0x%x 0x%x 0x%x 0x%x\n",
|
|
(UInt) getIByte(delta_start + 0),
|
|
(UInt) getIByte(delta_start + 1),
|
|
(UInt) getIByte(delta_start + 2),
|
|
(UInt) getIByte(delta_start + 3));
|
|
|
|
/* Tell the dispatcher that this insn cannot be decoded, and so has
|
|
not been executed, and (is currently) the next to be executed.
|
|
EIP should be up-to-date since it made so at the start bnezof each
|
|
insn, but nevertheless be paranoid and update it again right
|
|
now. */
|
|
if (mode64) {
|
|
stmt(IRStmt_Put(offsetof(VexGuestMIPS64State, guest_PC),
|
|
mkU64(guest_PC_curr_instr)));
|
|
jmp_lit64(&dres, Ijk_NoDecode, guest_PC_curr_instr);
|
|
} else {
|
|
stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_PC),
|
|
mkU32(guest_PC_curr_instr)));
|
|
jmp_lit32(&dres, Ijk_NoDecode, guest_PC_curr_instr);
|
|
}
|
|
dres.whatNext = Dis_StopHere;
|
|
dres.len = 0;
|
|
return dres;
|
|
} /* switch (opc) for the main (primary) opcode switch. */
|
|
|
|
/* All MIPS insn have 4 bytes */
|
|
|
|
if (delay_slot_branch) {
|
|
delay_slot_branch = False;
|
|
stmt(bstmt);
|
|
bstmt = NULL;
|
|
if (mode64)
|
|
putPC(mkU64(guest_PC_curr_instr + 4));
|
|
else
|
|
putPC(mkU32(guest_PC_curr_instr + 4));
|
|
dres.jk_StopHere = is_Branch_or_Jump_and_Link(guest_code + delta - 4) ?
|
|
Ijk_Call : Ijk_Boring;
|
|
}
|
|
|
|
if (likely_delay_slot) {
|
|
dres.jk_StopHere = Ijk_Boring;
|
|
dres.whatNext = Dis_StopHere;
|
|
putPC(lastn);
|
|
lastn = NULL;
|
|
}
|
|
if (delay_slot_jump) {
|
|
putPC(lastn);
|
|
lastn = NULL;
|
|
dres.jk_StopHere = is_Branch_or_Jump_and_Link(guest_code + delta - 4) ?
|
|
Ijk_Call : Ijk_Boring;
|
|
}
|
|
|
|
decode_success:
|
|
/* All decode successes end up here. */
|
|
switch (dres.whatNext) {
|
|
case Dis_Continue:
|
|
if (mode64)
|
|
putPC(mkU64(guest_PC_curr_instr + 4));
|
|
else
|
|
putPC(mkU32(guest_PC_curr_instr + 4));
|
|
break;
|
|
case Dis_ResteerU:
|
|
case Dis_ResteerC:
|
|
putPC(mkU32(dres.continueAt));
|
|
break;
|
|
case Dis_StopHere:
|
|
break;
|
|
default:
|
|
vassert(0);
|
|
break;
|
|
}
|
|
|
|
/* 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)) {
|
|
dres.whatNext = Dis_StopHere;
|
|
dres.jk_StopHere = Ijk_Boring;
|
|
if (mode64)
|
|
putPC(mkU64(guest_PC_curr_instr + 4));
|
|
else
|
|
putPC(mkU32(guest_PC_curr_instr + 4));
|
|
}
|
|
dres.len = 4;
|
|
|
|
DIP("\n");
|
|
|
|
return dres;
|
|
|
|
}
|
|
|
|
/*------------------------------------------------------------*/
|
|
/*--- Top-level fn ---*/
|
|
/*------------------------------------------------------------*/
|
|
|
|
/* Disassemble a single instruction into IR. The instruction
|
|
is located in host memory at &guest_code[delta]. */
|
|
DisResult disInstr_MIPS( IRSB* irsb_IN,
|
|
Bool (*resteerOkFn) ( void *, Addr ),
|
|
Bool resteerCisOk,
|
|
void* callback_opaque,
|
|
const UChar* guest_code_IN,
|
|
Long delta,
|
|
Addr guest_IP,
|
|
VexArch guest_arch,
|
|
const VexArchInfo* archinfo,
|
|
const VexAbiInfo* abiinfo,
|
|
VexEndness host_endness_IN,
|
|
Bool sigill_diag_IN )
|
|
{
|
|
DisResult dres;
|
|
/* Set globals (see top of this file) */
|
|
vassert(guest_arch == VexArchMIPS32 || guest_arch == VexArchMIPS64);
|
|
|
|
mode64 = guest_arch != VexArchMIPS32;
|
|
#if (__mips_fpr==64)
|
|
fp_mode64 = ((VEX_MIPS_REV(archinfo->hwcaps) == VEX_PRID_CPU_32FPR)
|
|
|| guest_arch == VexArchMIPS64);
|
|
#endif
|
|
|
|
guest_code = guest_code_IN;
|
|
irsb = irsb_IN;
|
|
host_endness = host_endness_IN;
|
|
#if defined(VGP_mips32_linux)
|
|
guest_PC_curr_instr = (Addr32)guest_IP;
|
|
#elif defined(VGP_mips64_linux)
|
|
guest_PC_curr_instr = (Addr64)guest_IP;
|
|
#endif
|
|
|
|
dres = disInstr_MIPS_WRK(resteerOkFn, resteerCisOk, callback_opaque,
|
|
delta, archinfo, abiinfo, sigill_diag_IN);
|
|
|
|
return dres;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------*/
|
|
/*--- end guest_mips_toIR.c ---*/
|
|
/*--------------------------------------------------------------------*/
|