|
From: <sv...@va...> - 2016-06-29 18:06:28
|
Author: carll
Date: Wed Jun 29 19:06:15 2016
New Revision: 3222
Log:
Power PC Add support for ISA 3.0, part 4
Added support to emulate the setb, cmprb, cmpeqb, dtstsfi,
dtstsfiq, dtstsfq, dtstsfiq, xscmpexpdp, xsxexpd, xsxsigdp,
xststdcsp, xststdcdp, xvtstdcsp, xvxsigdp, xsiexpdp, xvxexpdp,
xvxsigdp, xvxexpsp, xvxsigsp, xvtstdcdp, xvxsigdp, wait, addpcis
instructions.
bugzilla 363858
Modified:
trunk/priv/guest_ppc_defs.h
trunk/priv/guest_ppc_helpers.c
trunk/priv/guest_ppc_toIR.c
trunk/pub/libvex_guest_ppc32.h
trunk/pub/libvex_guest_ppc64.h
Modified: trunk/priv/guest_ppc_defs.h
==============================================================================
--- trunk/priv/guest_ppc_defs.h (original)
+++ trunk/priv/guest_ppc_defs.h Wed Jun 29 19:06:15 2016
@@ -147,7 +147,16 @@
/* --- CLEAN HELPERS --- */
-/* none, right now */
+extern ULong is_BCDstring128_helper( ULong Signed, ULong hi64, ULong low64 );
+extern ULong increment_BCDstring32_helper( ULong Signed,
+ ULong bcd_string, ULong carry_in );
+extern ULong convert_to_zoned_helper( ULong src_hi, ULong src_low,
+ ULong upper_byte,
+ ULong return_upper );
+extern ULong convert_to_national_helper( ULong src, ULong return_upper );
+extern ULong convert_from_zoned_helper( ULong src_hi, ULong src_low );
+extern ULong convert_from_national_helper( ULong src_hi, ULong src_low );
+
/* --- DIRTY HELPERS --- */
Modified: trunk/priv/guest_ppc_helpers.c
==============================================================================
--- trunk/priv/guest_ppc_helpers.c (original)
+++ trunk/priv/guest_ppc_helpers.c Wed Jun 29 19:06:15 2016
@@ -216,6 +216,216 @@
}
+/*---------------------------------------------------------------*/
+/*--- Misc BCD clean helpers. ---*/
+/*---------------------------------------------------------------*/
+
+/* This C-helper takes a 128-bit BCD value as two 64-bit pieces.
+ * It checks the string to see if it is a valid 128-bit BCD value.
+ * A valid BCD value has a sign value in bits [3:0] between 0xA
+ * and 0xF inclusive. each of the BCD digits represented as a 4-bit
+ * hex number in bits BCD value[128:4] mut be between 0 and 9
+ * inclusive. Returns an unsigned 64-bit value if valid.
+ */
+ULong is_BCDstring128_helper( ULong Signed, ULong bcd_string_hi,
+ ULong bcd_string_low ) {
+ Int i;
+ ULong valid_bcd, sign_valid = False;
+ ULong digit;
+ UInt sign;
+
+ if ( Signed == True ) {
+ sign = bcd_string_low & 0xF;
+ if( ( sign >= 0xA ) && ( sign <= 0xF ) )
+ sign_valid = True;
+
+ /* Change the sign digit to a zero
+ * so the for loop below works the same
+ * for signed and unsigned BCD stings
+ */
+ bcd_string_low &= 0xFFFFFFFFFFFFFFF0ULL;
+
+ } else {
+ sign_valid = True; /* set sign to True so result is only
+ based on the validity of the digits */
+ }
+
+ valid_bcd = True; // Assume true to start
+ for( i = 0; i < 32; i++ ) {
+ /* check high and low 64-bit strings in parallel */
+ digit = bcd_string_low & 0xF;
+ if ( digit > 0x9 )
+ valid_bcd = False;
+ bcd_string_low = bcd_string_low >> 4;
+
+ digit = bcd_string_hi & 0xF;
+ if ( digit > 0x9 )
+ valid_bcd = False;
+ bcd_string_hi = bcd_string_hi >> 4;
+ }
+
+ return valid_bcd & sign_valid;
+}
+
+/* This clean helper takes a signed 32-bit BCD value and a carry in
+ * and adds 1 to the value of the BCD value. The BCD value is passed
+ * in as a single 64-bit value. The incremented value is returned in
+ * the lower 32 bits of the result. If the input was signed the sign of
+ * the result is the same as the input. The carry out is returned in
+ * bits [35:32] of the result.
+ */
+ULong increment_BCDstring32_helper( ULong Signed,
+ ULong bcd_string, ULong carry_in ) {
+ UInt i, num_digits = 8;
+ ULong bcd_value, result = 0;
+ ULong carry, digit, new_digit;
+
+ carry = carry_in;
+
+ if ( Signed == True ) {
+ bcd_value = bcd_string >> 4; /* remove sign */
+ num_digits = num_digits - 1;
+ } else {
+ bcd_value = bcd_string;
+ }
+
+ for( i = 0; i < num_digits; i++ ) {
+ digit = bcd_value & 0xF;
+ bcd_value = bcd_value >> 4;
+ new_digit = digit + carry;
+
+ if ( new_digit > 10 ) {
+ carry = 1;
+ new_digit = new_digit - 10;
+
+ } else {
+ carry = 0;
+ }
+ result = result | (new_digit << (i*4) );
+ }
+
+ if ( Signed == True ) {
+ result = ( carry << 32) | ( result << 4 ) | ( bcd_string & 0xF );
+ } else {
+ result = ( carry << 32) | result;
+ }
+
+ return result;
+}
+
+/*---------------------------------------------------------------*/
+/*--- Misc packed decimal clean helpers. ---*/
+/*---------------------------------------------------------------*/
+
+/* This C-helper takes a 64-bit packed decimal value stored in a
+ * 64-bit value. It converts the zoned decimal format. The lower
+ * byte may contain a sign value, set it to zero. If return_upper
+ * is zero, return lower 64 bits of result, otherwise return upper
+ * 64 bits of the result.
+ */
+ULong convert_to_zoned_helper( ULong src_hi, ULong src_low,
+ ULong upper_byte, ULong return_upper ) {
+ UInt i, sh;
+ ULong tmp = 0, new_value;
+
+ /* Remove the sign from the source. Put in the upper byte of result.
+ * Sign inserted later.
+ */
+ if ( return_upper == 0 ) { /* return lower 64-bit result */
+ for(i = 0; i < 7; i++) {
+ sh = ( 8 - i ) * 4;
+ new_value = ( ( src_low >> sh ) & 0xf ) | upper_byte;
+ tmp = tmp | ( new_value << ( ( 7 - i ) * 8 ) );
+ }
+
+ } else {
+ /* Byte for i=0 is in upper 64-bit of the source, do it separately */
+ new_value = ( src_hi & 0xf ) | upper_byte;
+ tmp = tmp | new_value << 56;
+
+ for( i = 1; i < 8; i++ ) {
+ sh = ( 16 - i ) * 4;
+ new_value = ( ( src_low >> sh ) & 0xf ) | upper_byte;
+ tmp = tmp | ( new_value << ( ( 7 - i ) * 8 ) );
+ }
+ }
+ return tmp;
+}
+
+/* This C-helper takes the lower 64-bits of the 128-bit packed decimal
+ * src value. It converts the src value to a 128-bit national format.
+ * If return_upper is zero, the helper returns lower 64 bits of result,
+ * otherwise it returns the upper 64-bits of the result.
+ */
+ULong convert_to_national_helper( ULong src, ULong return_upper ) {
+
+ UInt i;
+ UInt sh = 3, max = 4, min = 0; /* initialize max, min for return upper */
+ ULong tmp = 0, new_value;
+
+ if ( return_upper == 0 ) { /* return lower 64-bit result */
+ min = 4;
+ max = 7;
+ sh = 7;
+ }
+
+ for( i = min; i < max; i++ ) {
+ new_value = ( ( src >> ( ( 7 - i ) * 4 ) ) & 0xf ) | 0x0030;
+ tmp = tmp | ( new_value << ( ( sh - i ) * 16 ) );
+ }
+ return tmp;
+}
+
+/* This C-helper takes a 128-bit zoned value stored in a 128-bit
+ * value. It converts it to the packed 64-bit decimal format without a
+ * a sign value. The sign is supposed to be in bits [3:0] and the packed
+ * value in bits [67:4]. This helper leaves it to the caller to put the
+ * result into a V128 and shift the returned value over and put the sign
+ * in.
+ */
+ULong convert_from_zoned_helper( ULong src_hi, ULong src_low ) {
+ UInt i;
+ ULong tmp = 0, nibble;
+
+ /* Unroll the i = 0 iteration so the sizes of the loop for the upper
+ * and lower extraction match. Skip sign in lease significant byte.
+ */
+ nibble = ( src_hi >> 56 ) & 0xF;
+ tmp = tmp | ( nibble << 60 );
+
+ for( i = 1; i < 8; i++ ) {
+ /* get the high nibbles, put into result */
+ nibble = ( src_hi >> ( ( 7 - i ) * 8 ) ) & 0xF;
+ tmp = tmp | ( nibble << ( ( 15 - i ) * 4 ) );
+
+ /* get the low nibbles, put into result */
+ nibble = ( src_low >> ( ( 8 - i ) * 8 ) ) & 0xF;
+ tmp = tmp | ( nibble << ( ( 8 - i ) * 4 ) );
+ }
+ return tmp;
+}
+
+/* This C-helper takes a 128-bit national value stored in a 128-bit
+ * value. It converts it to a signless packed 64-bit decimal format.
+ */
+ULong convert_from_national_helper( ULong src_hi, ULong src_low ) {
+ UInt i;
+ ULong tmp = 0, hword;
+
+ src_low = src_low & 0xFFFFFFFFFFFFFFF0ULL; /* remove the sign */
+
+ for( i = 0; i < 4; i++ ) {
+ /* get the high half-word, put into result */
+ hword = ( src_hi >> ( ( 3 - i ) * 16 ) ) & 0xF;
+ tmp = tmp | ( hword << ( ( 7 - i ) * 4 ) );
+
+ /* get the low half-word, put into result */
+ hword = ( src_low >> ( ( 3 - i ) * 16 ) ) & 0xF;
+ tmp = tmp | ( hword << ( ( 3 - i ) * 4 ) );
+ }
+ return tmp;
+}
+
/*----------------------------------------------*/
/*--- The exported fns .. ---*/
/*----------------------------------------------*/
@@ -500,7 +710,7 @@
vex_state->guest_FPROUND = PPCrm_NEAREST;
vex_state->guest_DFPROUND = PPCrm_NEAREST;
- vex_state->guest_FPCC = 0;
+ vex_state->guest_C_FPCC = 0;
vex_state->pad2 = 0;
vex_state->guest_VRSAVE = 0;
@@ -667,7 +877,7 @@
vex_state->guest_FPROUND = PPCrm_NEAREST;
vex_state->guest_DFPROUND = PPCrm_NEAREST;
- vex_state->guest_FPCC = 0;
+ vex_state->guest_C_FPCC = 0;
vex_state->pad2 = 0;
vex_state->guest_VRSAVE = 0;
@@ -834,7 +1044,7 @@
/* 8 */ ALWAYSDEFD32(guest_REDIR_SP),
/* 9 */ ALWAYSDEFD32(guest_REDIR_STACK),
/* 10 */ ALWAYSDEFD32(guest_IP_AT_SYSCALL),
- /* 11 */ ALWAYSDEFD32(guest_FPCC)
+ /* 11 */ ALWAYSDEFD32(guest_C_FPCC)
}
};
@@ -876,7 +1086,7 @@
/* 8 */ ALWAYSDEFD64(guest_REDIR_SP),
/* 9 */ ALWAYSDEFD64(guest_REDIR_STACK),
/* 10 */ ALWAYSDEFD64(guest_IP_AT_SYSCALL),
- /* 11 */ ALWAYSDEFD64(guest_FPCC)
+ /* 11 */ ALWAYSDEFD64(guest_C_FPCC)
}
};
Modified: trunk/priv/guest_ppc_toIR.c
==============================================================================
--- trunk/priv/guest_ppc_toIR.c (original)
+++ trunk/priv/guest_ppc_toIR.c Wed Jun 29 19:06:15 2016
@@ -277,7 +277,7 @@
#define OFFB_XER_BC offsetofPPCGuestState(guest_XER_BC)
#define OFFB_FPROUND offsetofPPCGuestState(guest_FPROUND)
#define OFFB_DFPROUND offsetofPPCGuestState(guest_DFPROUND)
-#define OFFB_FPCC offsetofPPCGuestState(guest_FPCC)
+#define OFFB_C_FPCC offsetofPPCGuestState(guest_C_FPCC)
#define OFFB_VRSAVE offsetofPPCGuestState(guest_VRSAVE)
#define OFFB_VSCR offsetofPPCGuestState(guest_VSCR)
#define OFFB_EMNOTE offsetofPPCGuestState(guest_EMNOTE)
@@ -457,8 +457,10 @@
PPC_GST_MAX
} PPC_GST;
-#define MASK_FPSCR_RN 0x3ULL // Binary floating point rounding mode
-#define MASK_FPSCR_DRN 0x700000000ULL // Decimal floating point rounding mode
+#define MASK_FPSCR_RN 0x3ULL // Binary floating point rounding mode
+#define MASK_FPSCR_DRN 0x700000000ULL // Decimal floating point rounding mode
+#define MASK_FPSCR_C_FPCC 0x1F000ULL // Floating-Point Condition code FPCC
+
#define MASK_VSCR_VALID 0x00010001
@@ -634,6 +636,8 @@
return IRExpr_RdTmp(tmp);
}
+#define mkU1(_n) IRExpr_Const(IRConst_U1(_n))
+
static IRExpr* mkU8 ( UChar i )
{
return IRExpr_Const(IRConst_U8(i));
@@ -3205,6 +3209,31 @@
)
);
}
+
+ if (mask & MASK_FPSCR_C_FPCC) {
+ stmt(
+ IRStmt_Put(
+ OFFB_C_FPCC,
+ unop(
+ Iop_32to8,
+ binop(
+ Iop_Or32,
+ binop(
+ Iop_And32,
+ unop(Iop_64to32, src),
+ mkU32(MASK_FPSCR_C_FPCC & mask)
+ ),
+ binop(
+ Iop_And32,
+ unop(Iop_8Uto32, IRExpr_Get(OFFB_C_FPCC,Ity_I8)),
+ mkU32(MASK_FPSCR_C_FPCC & ~mask)
+ )
+ )
+ )
+ )
+ );
+ }
+
/* Similarly, update FPSCR.DRN if any bits of |mask|
corresponding to FPSCR.DRN are set. */
if (mask & MASK_FPSCR_DRN) {
@@ -3303,29 +3332,53 @@
/* The assumption is that the value of the FPCC are passed in the lower
* four bits of a 32 bit value.
*
- * Note, the FPCC bits are a field of the FPSCR
+ * Note, the C and FPCC bits which are a field of the FPSCR
* register are stored in their own "register" in
- * memory. We don't need to shift it to the bits to
- * their location in the FPSCR register. Note, not all
- * of the FPSCR register bits are supported. We are
- * writing all of the bits in the FPCC field.
+ * memory. The FPCC bits are in the lower 4 bits. We don't need to
+ * shift it to the bits to their location in the FPSCR register. Note,
+ * not all of the FPSCR register bits are supported. We are writing all
+ * of the bits in the FPCC field but not the C field.
+ */
+ IRExpr* tmp;
+
+ vassert( typeOfIRExpr( irsb->tyenv, e ) == Ity_I32 );
+ /* Get the C bit field */
+ tmp = binop( Iop_And32,
+ mkU32( 0x10 ),
+ unop( Iop_8Uto32, IRExpr_Get( OFFB_C_FPCC, Ity_I8 ) ) );
+
+ stmt( IRStmt_Put( OFFB_C_FPCC,
+ unop( Iop_32to8,
+ binop( Iop_Or32, tmp,
+ binop( Iop_And32, mkU32( 0xF ), e ) ) ) ) );
+
+}
+
+static IRExpr* /* ::Ity_I32 */ getC ( void )
+{
+ /* Note, the Floating-Point Result Class Descriptor (C) bit is a field of
+ * the FPSCR registered are stored in its own "register" in guest state
+ * with the FPCC bit field. C | FPCC
*/
+ IRTemp val = newTemp(Ity_I32);
- vassert( typeOfIRExpr(irsb->tyenv, e) == Ity_I32 );
- stmt( IRStmt_Put(OFFB_FPCC,
- unop( Iop_32to8,
- binop( Iop_And32, mkU32( 0xF ), e ) ) ) );
+ assign( val, binop( Iop_Shr32,
+ unop( Iop_8Uto32, IRExpr_Get( OFFB_C_FPCC, Ity_I8 ) ),
+ mkU8( 4 ) ) );
+ return mkexpr(val);
}
static IRExpr* /* ::Ity_I32 */ getFPCC ( void )
{
/* Note, the FPCC bits are a field of the FPSCR
* register are stored in their own "register" in
- * guest state.
+ * guest state with the C bit field. C | FPCC
*/
IRTemp val = newTemp( Ity_I32 );
- assign( val, unop( Iop_8Uto32, IRExpr_Get( OFFB_FPCC, Ity_I8 ) ) );
+ assign( val, binop( Iop_And32, unop( Iop_8Uto32,
+ IRExpr_Get( OFFB_C_FPCC, Ity_I8 ) ),
+ mkU32( 0xF ) ));
return mkexpr(val);
}
@@ -3834,6 +3887,432 @@
mkAND1( both_neg, neg_cmp ) ) ) ) );
}
+/*-----------------------------------------------------------
+ * Helpers for VX instructions that work on National decimal values,
+ * Zoned decimal values and BCD values.
+ *
+ *------------------------------------------------------------*/
+static IRExpr * is_National_decimal (IRTemp src)
+{
+ /* The src is a 128-bit value containing a sign code in half word 7
+ * and seven digits in halfwords 0 to 6 (IBM numbering). A valid
+ * national decimal value has the following:
+ * - the sign code must be 0x002B (positive) or 0x002D (negative)
+ * - the digits must be in the range 0x0030 to 0x0039
+ */
+ Int i;
+ IRExpr * valid_pos_sign;
+ IRExpr * valid_neg_sign;
+ IRTemp valid_num[8];
+ IRTemp digit[7];
+
+ valid_pos_sign = binop( Iop_CmpEQ64,
+ binop( Iop_And64,
+ mkU64( 0xFFFF ),
+ unop( Iop_V128to64, mkexpr( src ) ) ),
+ mkU64( 0x002B ) );
+
+ valid_neg_sign = binop( Iop_CmpEQ64,
+ binop( Iop_And64,
+ mkU64( 0xFFFF ),
+ unop( Iop_V128to64, mkexpr( src ) ) ),
+ mkU64( 0x002D ) );
+
+ valid_num[0] = newTemp( Ity_I1 );
+ digit[0] = newTemp( Ity_I64 );
+ assign( valid_num[0], mkU1( 1 ) ); // Assume true to start
+
+ for(i = 0; i < 7; i++) {
+ valid_num[i+1] = newTemp( Ity_I1 );
+ digit[i] = newTemp( Ity_I64 );
+ assign( digit[i], binop( Iop_And64,
+ unop( Iop_V128to64,
+ binop( Iop_ShrV128,
+ mkexpr( src ),
+ mkU8( (7-i)*16 ) ) ),
+ mkU64( 0xFFFF ) ) );
+
+ assign( valid_num[i+1],
+ mkAND1( mkexpr( valid_num[i] ),
+ mkAND1( binop( Iop_CmpLE64U,
+ mkexpr( digit[i] ),
+ mkU64( 0x39 ) ),
+ binop( Iop_CmpLE64U,
+ mkU64( 0x30 ),
+ mkexpr( digit[i] ) ) ) ) );
+ }
+
+ return mkAND1( mkOR1( valid_pos_sign, valid_neg_sign),
+ mkexpr( valid_num[7] ) );
+}
+
+static IRExpr * is_Zoned_decimal (IRTemp src, UChar ps)
+{
+ /* The src is a 128-bit value containing a sign code the least significant
+ * two bytes. The upper pairs of bytes contain digits. A valid Zoned
+ * decimal value has the following:
+ * - the sign code must be between 0x0X to 0xFX inclusive (X - don't care)
+ * - bits [0:3] of each digit must be equal to 0x3
+ * - bits [4:7] of each digit must be between 0x0 and 0x9
+ *
+ * If ps = 0
+ * Positive sign codes are: 0x0, 0x1, 0x2, 0x3, 0x8, 0x9, 0xA, 0xB
+ * (note 0bX0XX XXXX is positive)
+ *
+ * Negative sign codes are 0x4, 0x5, 0x6, 0x7, 0xC, 0xD, 0xE, 0xF
+ * (note 0bX1XX XXXX is negative)
+ *
+ * If ps = 1, then the sign code must be in the range 0xA to 0xF
+ * Positive sign codes are: 0xA, 0xC, 0xE, 0xF
+ *
+ * Negative sign codes are 0xB, 0xD
+ */
+ Int i, mask_hi, mask_lo;
+ IRExpr *valid_range;
+ IRTemp valid_num[16];
+ IRTemp digit[15];
+
+ /* check the range of the sign value based on the value of ps */
+ valid_range = mkOR1(
+ mkAND1( binop( Iop_CmpEQ64,
+ mkU64( 1 ),
+ mkU64( ps ) ),
+ mkAND1( binop( Iop_CmpLE64U,
+ binop( Iop_And64,
+ mkU64( 0xF0 ),
+ unop( Iop_V128to64,
+ mkexpr( src ) ) ),
+
+ mkU64( 0xF0 ) ),
+ binop( Iop_CmpLE64U,
+ mkU64( 0xA0 ),
+ binop( Iop_And64,
+ mkU64( 0xF0 ),
+ unop( Iop_V128to64,
+ mkexpr( src ) ))))),
+ binop( Iop_CmpEQ64,
+ mkU64( 0 ),
+ mkU64( ps ) ) );
+
+ valid_num[0] = newTemp( Ity_I1 );
+ assign( valid_num[0], mkU1( 1) ); // Assume true to start
+
+ if (ps == 0) {
+ mask_hi = 0x39;
+ mask_lo = 0x30;
+ } else {
+ mask_hi = 0xF9;
+ mask_lo = 0xF0;
+ }
+
+ for(i = 0; i < 15; i++) {
+ valid_num[i+1] = newTemp( Ity_I1 );
+ digit[i] = newTemp( Ity_I64 );
+ assign( digit[i], binop( Iop_And64,
+ unop( Iop_V128to64,
+ binop( Iop_ShrV128,
+ mkexpr( src ),
+ mkU8( (15-i)*8 ) ) ),
+ mkU64( 0xFF ) ) );
+
+ assign( valid_num[i+1],
+ mkAND1( mkexpr( valid_num[i] ),
+ mkAND1( binop( Iop_CmpLE64U,
+ mkexpr( digit[i] ),
+ mkU64( mask_hi ) ),
+ binop( Iop_CmpLE64U,
+ mkU64( mask_lo ),
+ mkexpr( digit[i] ) ) ) ) );
+ }
+
+ return mkAND1( valid_range, mkexpr( valid_num[15] ) );
+}
+
+static IRExpr * CmpGT128U ( IRExpr *src1, IRExpr *src2 )
+{
+ /* Unsigend compare of two 128-bit values */
+ IRExpr *pos_upper_gt, *pos_upper_eq, *pos_lower_gt;
+
+ pos_upper_gt = binop( Iop_CmpLT64U,
+ unop( Iop_V128HIto64, src2 ),
+ unop( Iop_V128HIto64, src1 ) );
+ pos_upper_eq = binop( Iop_CmpEQ64,
+ unop( Iop_V128HIto64, src1 ),
+ unop( Iop_V128HIto64, src2 ) );
+ pos_lower_gt = binop( Iop_CmpLT64U,
+ unop( Iop_V128to64, src2),
+ unop( Iop_V128to64, src1) );
+ return mkOR1( pos_upper_gt,
+ mkAND1( pos_upper_eq,
+ pos_lower_gt ) );
+}
+
+
+static IRExpr * is_BCDstring128 (UInt Signed, IRExpr *src)
+{
+
+ IRTemp valid = newTemp( Ity_I64 );
+
+ /* The src is a 128-bit value containing a MAX_DIGITS BCD digits and
+ * a sign. The upper bytes are BCD values between 0x0 and 0x9. The sign
+ * byte is the least significant byte. This function returns 64-bit 1
+ * value if sign and digits are valid, 0 otherwise.
+ *
+ * This function was originally written using IR code. It has been
+ * replaced with a clean helper due to the large amount of IR code
+ * needed by this function.
+ */
+ assign( valid,
+ mkIRExprCCall( Ity_I64, 0 /*regparms*/,
+ "is_BCDstring128_helper",
+ &is_BCDstring128_helper,
+ mkIRExprVec_3( mkU64( Signed ),
+ unop( Iop_V128HIto64, src ),
+ unop( Iop_V128to64, src ) ) ) );
+ return mkexpr( valid );
+}
+
+static IRExpr * BCDstring_zero (IRExpr *src)
+{
+ /* The src is a 128-bit value containing a BCD string and a sign in the
+ * least significant byte. The function returns a 1 if the BCD string
+ * values are all zero, 0 otherwise.
+ */
+ IRTemp tsrc = newTemp( Ity_V128 );
+ assign( tsrc, src);
+
+ return mkAND1( binop( Iop_CmpEQ64,
+ mkU64( 0 ),
+ unop( Iop_V128HIto64,
+ mkexpr( tsrc ) ) ),
+ binop( Iop_CmpEQ64,
+ mkU64( 0 ),
+ unop( Iop_V128to64,
+ mkexpr( tsrc ) ) ) );
+}
+
+static IRExpr * check_BCD_round (IRExpr *src, IRTemp shift)
+{
+ /* The src is a 128-bit value containing 31 BCD digits with the sign in
+ * the least significant byte. The bytes are BCD values between 0x0 and 0x9.
+ * This routine checks the BCD digit in position shift (counting from
+ * the least significant digit). If the digit is greater then five,
+ * a 1 is returned indicating the string needs to be rounded up,
+ * otherwise, 0 is returned. The value of shift (I64) is the index of
+ * the BCD digit times four bits.
+ */
+ return binop( Iop_CmpLE64U,
+ mkU64( 6 ),
+ binop( Iop_And64,
+ unop( Iop_V128to64,
+ binop( Iop_ShrV128,
+ src,
+ unop( Iop_64to8, mkexpr( shift ) ) ) ),
+ mkU64( 0xF ) ) );
+}
+
+static IRTemp increment_BCDstring (IRExpr *src, IRExpr *carry_in)
+{
+ /* The src is a 128-bit value containing 31 BCD digits with the sign in
+ * the least significant byte. The bytes are BCD values between 0x0 and 0x9.
+ * This function returns the BCD string incremented by 1.
+ *
+ * Call a clean helper to do the computation as it requires a lot of
+ * IR code to do this.
+ *
+ * The helper function takes a 32-bit BCD string, in a 64-bit value, and
+ * increments the string by the 32-bi carry in value.
+ *
+ * The incremented value is returned in the lower 32-bits of the result.
+ * The carry out is returned in bits [35:32] of the result. The
+ * helper function will be called for each of the four 32-bit strings
+ * that make up the src string passing the returned carry out to the
+ * next call.
+ */
+ IRTemp bcd_result = newTemp( Ity_V128 );
+ IRTemp bcd_result0 = newTemp( Ity_I64 );
+ IRTemp bcd_result1 = newTemp( Ity_I64 );
+ IRTemp bcd_result2 = newTemp( Ity_I64 );
+ IRTemp bcd_result3 = newTemp( Ity_I64 );
+ IRExpr *bcd_string0, *bcd_string1, *bcd_string2, *bcd_string3;
+
+ bcd_string0 = binop( Iop_And64,
+ mkU64( 0xFFFFFFFF ), unop( Iop_V128to64, src ) );
+ bcd_string1 = binop( Iop_Shr64, unop( Iop_V128to64, src ), mkU8( 32 ) );
+ bcd_string2 = binop( Iop_And64,
+ mkU64( 0xFFFFFFFF ), unop( Iop_V128HIto64, src ) );
+ bcd_string3 = binop( Iop_Shr64, unop( Iop_V128HIto64, src ), mkU8( 32 ) );
+
+ assign( bcd_result0,
+ mkIRExprCCall( Ity_I64, 0 /*regparms*/,
+ "increment_BCDstring32_helper",
+ &increment_BCDstring32_helper,
+ mkIRExprVec_3( mkU64( True /*Signed*/ ),
+ bcd_string0,
+ binop( Iop_32HLto64, mkU32( 0 ),
+ carry_in ) ) ) );
+
+ assign( bcd_result1,
+ mkIRExprCCall( Ity_I64, 0 /*regparms*/,
+ "increment_BCDstring32_helper",
+ &increment_BCDstring32_helper,
+ mkIRExprVec_3( mkU64( False /*Unsigned*/ ),
+ bcd_string1,
+ binop( Iop_Shr64,
+ mkexpr( bcd_result0 ),
+ mkU8( 32 ) ) ) ) );
+ assign( bcd_result2,
+ mkIRExprCCall( Ity_I64, 0 /*regparms*/,
+ "increment_BCDstring32_helper",
+ &increment_BCDstring32_helper,
+ mkIRExprVec_3( mkU64( False /*Unsigned*/ ),
+ bcd_string2,
+ binop( Iop_Shr64,
+ mkexpr( bcd_result1 ),
+ mkU8( 32 ) ) ) ) );
+ assign( bcd_result3,
+ mkIRExprCCall( Ity_I64, 0 /*regparms*/,
+ "increment_BCDstring32_helper",
+ &increment_BCDstring32_helper,
+ mkIRExprVec_3( mkU64( False /*Unsigned*/ ),
+ bcd_string3,
+ binop( Iop_Shr64,
+ mkexpr( bcd_result2 ),
+ mkU8( 32 ) ) ) ) );
+
+ /* Put the 128-bit result together from the intermediate results. Remember
+ * to mask out the carry out from the upper 32 bits of the results.
+ */
+ assign( bcd_result,
+ binop( Iop_64HLtoV128,
+ binop( Iop_Or64,
+ binop( Iop_And64,
+ mkU64( 0xFFFFFFFF ), mkexpr (bcd_result2 ) ),
+ binop( Iop_Shl64,
+ mkexpr (bcd_result3 ), mkU8( 32 ) ) ),
+ binop( Iop_Or64,
+ binop( Iop_And64,
+ mkU64( 0xFFFFFFFF ), mkexpr (bcd_result0 ) ),
+ binop( Iop_Shl64,
+ mkexpr (bcd_result1 ), mkU8( 32 ) ) ) ) );
+ return bcd_result;
+}
+
+static IRExpr * convert_to_zoned ( IRExpr *src, IRExpr *upper_byte )
+{
+ /* The function takes a V128 packed decimal value and returns
+ * the value in zoned format. Note, the sign of the value is ignored.
+ */
+ IRTemp result_low = newTemp( Ity_I64 );
+ IRTemp result_hi = newTemp( Ity_I64 );
+ IRTemp result = newTemp( Ity_V128 );
+
+ /* Since we can only return 64-bits from a clean helper, we will
+ * have to get the lower and upper 64-bits separately.
+ */
+
+ assign( result_low,
+ mkIRExprCCall( Ity_I64, 0 /*regparms*/,
+ "convert_to_zoned_helper",
+ &convert_to_zoned_helper,
+ mkIRExprVec_4( unop( Iop_V128HIto64, src ),
+ unop( Iop_V128to64, src ),
+ upper_byte,
+ mkU64( 0 ) ) ) );
+
+ assign( result_hi,
+ mkIRExprCCall( Ity_I64, 0 /*regparms*/,
+ "convert_to_zoned_helper",
+ &convert_to_zoned_helper,
+ mkIRExprVec_4( unop( Iop_V128HIto64, src ),
+ unop( Iop_V128to64, src ),
+ upper_byte,
+ mkU64( 1 ) ) ) );
+
+
+ assign( result,
+ binop( Iop_64HLtoV128, mkexpr( result_hi ), mkexpr( result_low ) ) );
+
+ return mkexpr( result );
+}
+
+static IRExpr * convert_to_national ( IRExpr *src ) {
+ /* The function takes 128-bit value which has a 64-bit packed decimal
+ * value in the lower 64-bits of the source. The packed decimal is
+ * converted to the national format via a clean helper. The clean
+ * helper is used to to the large amount of IR code needed to do the
+ * conversion. The helper returns the upper 64-bits of the 128-bit
+ * result if return_upper != 0. Otherwise, the lower 64-bits of the
+ * result is returned.
+ */
+ IRTemp result_low = newTemp( Ity_I64 );
+ IRTemp result_hi = newTemp( Ity_I64 );
+ IRTemp result = newTemp( Ity_V128 );
+
+ /* Since we can only return 64-bits from a clean helper, we will
+ * have to get the lower and upper 64-bits separately.
+ */
+
+ assign( result_low,
+ mkIRExprCCall( Ity_I64, 0 /*regparms*/,
+ "convert_to_national_helper",
+ &convert_to_national_helper,
+ mkIRExprVec_2( unop( Iop_V128to64, src ),
+ mkU64( 0 ) ) ) );
+
+ assign( result_hi,
+ mkIRExprCCall( Ity_I64, 0 /*regparms*/,
+ "convert_to_national_helper",
+ &convert_to_national_helper,
+ mkIRExprVec_2( unop( Iop_V128to64, src ),
+ mkU64( 1 ) ) ) );
+
+ assign( result,
+ binop( Iop_64HLtoV128, mkexpr( result_hi ), mkexpr( result_low ) ) );
+
+ return mkexpr( result );
+}
+
+static IRExpr * convert_from_zoned ( IRExpr *src ) {
+ /* The function takes 128-bit zoned value and returns a signless 64-bit
+ * packed decimal value in the lower 64-bits of the 128-bit result.
+ */
+ IRTemp result = newTemp( Ity_V128 );
+
+ assign( result,
+ binop( Iop_ShlV128,
+ binop( Iop_64HLtoV128,
+ mkU64( 0 ),
+ mkIRExprCCall( Ity_I64, 0 /*regparms*/,
+ "convert_from_zoned_helper",
+ &convert_from_zoned_helper,
+ mkIRExprVec_2( unop( Iop_V128HIto64,
+ src ),
+ unop( Iop_V128to64,
+ src ) ) ) ),
+ mkU8( 4 ) ) );
+
+ return mkexpr( result );
+}
+
+static IRExpr * convert_from_national ( IRExpr *src ) {
+ /* The function takes 128-bit national value and returns a 64-bit
+ * packed decimal value.
+ */
+ IRTemp result = newTemp( Ity_I64);
+
+ assign( result,
+ mkIRExprCCall( Ity_I64, 0 /*regparms*/,
+ "convert_from_national_helper",
+ &convert_from_national_helper,
+ mkIRExprVec_2( unop( Iop_V128HIto64,
+ src ),
+ unop( Iop_V128to64,
+ src ) ) ) );
+
+ return mkexpr( result );
+}
+
/*------------------------------------------------------------*/
/* Transactional memory helpers
*
@@ -4926,7 +5405,7 @@
break;
default:
- vex_printf("dis_int_cmp(ppc)(opc1)\n");
+ vex_printf("dis_modulo_int(ppc)(opc1)\n");
return False;
}
@@ -4937,6 +5416,164 @@
/*
+ Byte Compare Instructions
+*/
+static Bool dis_byte_cmp ( UInt theInstr )
+{
+ /* X-Form */
+ UChar opc1 = ifieldOPC(theInstr);
+ UInt opc2 = ifieldOPClo10(theInstr);
+ UChar rA_addr = ifieldRegA(theInstr);
+ UChar rB_addr = ifieldRegB(theInstr);
+ IRTemp rA = newTemp(Ity_I64);
+ IRTemp rB = newTemp(Ity_I64);
+ UChar L = toUChar( IFIELD( theInstr, 21, 1 ) );
+ UChar BF = toUChar( IFIELD( theInstr, 23, 3 ) );
+
+ assign( rA, getIReg(rA_addr) );
+ assign( rB, getIReg(rB_addr) );
+
+ if (opc1 != 0x1F) {
+ vex_printf("dis_byte_cmp(ppc)(opc1)\n");
+ return False;
+ }
+
+ switch (opc2) {
+ case 0xc0: // cmprb (Compare Ranged Byte)
+ {
+ IRExpr *value;
+ IRExpr *hi_1, *lo_1, *hi_2, *lo_2;
+ IRExpr *inrange_1, *inrange_2;
+
+ DIP("cmprb %u,%u,r%u,r%u\n", BF, L, rA_addr, rB_addr);
+
+ hi_1 = binop( Iop_Shr64,
+ binop( Iop_And64,
+ mkexpr( rB ),
+ mkU64( 0xFF000000 ) ),
+ mkU8( 24 ) );
+ lo_1 = binop( Iop_Shr64,
+ binop( Iop_And64,
+ mkexpr( rB ),
+ mkU64( 0xFF0000 ) ) ,
+ mkU8( 16 ) );
+ hi_2 = binop( Iop_Shr64,
+ binop( Iop_And64,
+ mkexpr( rB ),
+ mkU64( 0xFF00 ) ),
+ mkU8( 8 ) );
+ lo_2 = binop( Iop_And64,
+ mkexpr( rB ),
+ mkU64( 0xFF ) );
+ value = binop( Iop_And64,
+ mkexpr( rA ),
+ mkU64( 0xFF ) );
+
+ inrange_1 = mkAND1( binop( Iop_CmpLE64U, value, hi_1 ),
+ mkNOT1( binop( Iop_CmpLT64U, value, lo_1 ) ) );
+ inrange_2 = mkAND1( binop( Iop_CmpLE64U, value, hi_2 ),
+ mkNOT1( binop( Iop_CmpLT64U, value, lo_2 ) ) );
+
+ putGST_field( PPC_GST_CR,
+ binop( Iop_Shl32,
+ binop( Iop_Or32,
+ unop( Iop_1Uto32, inrange_2 ),
+ binop( Iop_And32,
+ mkU32 ( L ),
+ unop( Iop_1Uto32, inrange_1 ) ) ),
+ mkU8( 2 ) ),
+ BF );
+ }
+ break;
+
+ case 0xE0: // cmpeqb (Compare Equal Byte)
+ {
+ Int i;
+ IRTemp tmp[9];
+ IRExpr *value;
+
+ DIP("cmpeqb %u,r%u,r%u\n", BF, rA_addr, rB_addr);
+
+ value = binop( Iop_And64,
+ mkexpr( rA ),
+ mkU64( 0xFF ) );
+
+ tmp[0] = newTemp(Ity_I32);
+ assign( tmp[0], mkU32( 0 ) );
+
+ for(i = 0; i < 8; i++) {
+ tmp[i+1] = newTemp(Ity_I32);
+ assign( tmp[i+1], binop( Iop_Or32,
+ unop( Iop_1Uto32,
+ binop( Iop_CmpEQ64,
+ value,
+ binop( Iop_And64,
+ binop( Iop_Shr64,
+ mkexpr( rB ),
+ mkU8( i*8 ) ),
+ mkU64( 0xFF ) ) ) ),
+ mkexpr( tmp[i] ) ) );
+ }
+
+ putGST_field( PPC_GST_CR,
+ binop( Iop_Shl32,
+ unop( Iop_1Uto32,
+ mkNOT1( binop( Iop_CmpEQ32,
+ mkexpr( tmp[8] ),
+ mkU32( 0 ) ) ) ),
+ mkU8( 2 ) ),
+ BF );
+ }
+ break;
+
+ default:
+ vex_printf("dis_byte_cmp(ppc)(opc2)\n");
+ return False;
+ }
+ return True;
+}
+
+/*
+ * Integer Miscellaneous instructions
+ */
+static Bool dis_int_misc ( UInt theInstr )
+{
+ Int wc = IFIELD(theInstr, 21, 2);
+ UChar opc1 = ifieldOPC(theInstr);
+ UInt opc2 = ifieldOPClo10(theInstr);
+
+ if ( opc1 != 0x1F ) {
+ vex_printf("dis_modulo_int(ppc)(opc1)\n");
+ return False;
+ }
+
+ switch (opc2) {
+ case 0x01E: // wait, (X-from)
+ DIP("wait %u\n", wc);
+
+ /* The wait instruction causes instruction fetching and execution
+ * to be suspended. Instruction fetching and execution are resumed
+ * when the events specified by the WC field occur.
+ *
+ * 0b00 Resume instruction fetching and execution when an
+ * exception or an event-based branch exception occurs,
+ * or a resume signal from the platform is recieved.
+ *
+ * 0b01 Reserved.
+ *
+ * For our purposes, we will just assume the contition is always
+ * immediately satisfied.
+ */
+ break;
+ default:
+ vex_printf("dis_int_misc(ppc)(opc2)\n");
+ return False;
+}
+
+ return True;
+}
+
+/*
Integer Compare Instructions
*/
static Bool dis_int_cmp ( UInt theInstr )
@@ -4961,7 +5598,7 @@
return False;
}
- if (b22 != 0) {
+ if (( b22 != 0 ) && ( opc2 != 0x080 ) ) { // setb case exception
vex_printf("dis_int_cmp(ppc)(b22)\n");
return False;
}
@@ -5041,6 +5678,50 @@
putCR0( crfD, getXER_SO() );
break;
+ case 0x080: // setb (Set Boolean)
+ {
+ UChar rT_addr = ifieldRegDS(theInstr);
+ Int bfa = IFIELD(theInstr, 18, 3);
+ IRTemp cr = newTemp(Ity_I32);
+ IRTemp cr0 = newTemp(Ity_I32);
+ IRTemp cr1 = newTemp(Ity_I32);
+ IRTemp result = newTemp(Ity_I64);
+
+ DIP("setb r%u,%d\n", rT_addr, bfa);
+
+ /* Fetch the entire condition code value */
+ assign( cr, getGST( PPC_GST_CR ) );
+
+ /* Get bit zero (IBM numbering) of the CR field specified
+ * by bfa.
+ */
+ assign( cr0, binop( Iop_And32,
+ binop( Iop_Shr32,
+ mkexpr( cr ),
+ mkU8( (7-bfa)*4 ) ),
+ mkU32( 0x8 ) ) );
+ assign( cr1, binop( Iop_And32,
+ binop( Iop_Shr32,
+ mkexpr( cr ),
+ mkU8( (7-bfa)*4 ) ),
+ mkU32( 0x4 ) ) );
+ assign( result, binop( Iop_Or64,
+ unop( Iop_1Sto64,
+ binop( Iop_CmpEQ32,
+ mkexpr( cr0 ),
+ mkU32( 0x8 ) ) ),
+ binop( Iop_32HLto64,
+ mkU32( 0 ),
+ unop( Iop_1Uto32,
+ binop( Iop_CmpEQ32,
+ mkexpr( cr1 ),
+ mkU32( 0x4 ) ) ) ) ) );
+ if ( ty == Ity_I64 )
+ putIReg( rT_addr, mkexpr( result ) );
+ else
+ putIReg( rT_addr, unop( Iop_64to32, mkexpr(result ) ) );
+ }
+ break;
default:
vex_printf("dis_int_cmp(ppc)(opc2)\n");
return False;
@@ -6888,11 +7569,62 @@
return True;
}
+/*
+ * PC relative instruction
+ */
+static Bool dis_pc_relative ( UInt theInstr )
+{
+ /* DX-Form */
+ UChar opc1 = ifieldOPC(theInstr);
+ unsigned long long D;
+ UInt d0 = IFIELD(theInstr, 6, 10);
+ UInt d1 = IFIELD(theInstr, 16, 5);
+ UInt d2 = IFIELD(theInstr, 0, 1);
+ UChar rT_addr = ifieldRegDS(theInstr);
+ UInt opc2 = ifieldOPClo5(theInstr);
+ IRType ty = mode64 ? Ity_I64 : Ity_I32;
+
+ if ( opc1 != 0x13) {
+ vex_printf("dis_pc_relative(ppc)(opc1)\n");
+ return False;
+ }
+
+ switch (opc2) {
+ case 0x002: // addpcis (Add PC immediate Shifted DX-form)
+ {
+ IRExpr* nia = mkSzImm(ty, nextInsnAddr());
+ IRExpr* result;
+
+ D = (d0 << 6) | (d1 << 1) | d2;
+ DIP("addpcis %u,%llu\n", rT_addr, D);
+
+ if ( (D & 0x8000) == 0x8000 )
+ D = 0xFFFFFFFFFFFF0000UL | D; // sign extend
+
+ if ( ty == Ity_I32 ) {
+ result = binop( Iop_Add32, nia, mkU32( D << 16 ) );
+
+ } else if ( ty == Ity_I64 ) {
+ result = binop( Iop_Add64, nia, mkU64( D << 16 ) );
+
+ } else {
+ vex_printf("dis_pc_relative(unsupported type)\n");
+ }
+ putIReg( rT_addr, result);
+ }
+ break;
+
+ default:
+ vex_printf("dis_pc_relative(ppc)(opc2)\n");
+ return False;
+ }
+ return True;
+}
/*
Condition Register Logical Instructions
-*/
+ */
static Bool dis_cond_logic ( UInt theInstr )
{
/* XL-Form */
@@ -10555,9 +11287,13 @@
IRExpr* fpscr_lower
= binop( Iop_Or32,
getGST_masked( PPC_GST_FPSCR, MASK_FPSCR_RN),
- binop( Iop_Shl32,
- getFPCC(),
- mkU8( 63-51 ) ) );
+ binop( Iop_Or32,
+ binop( Iop_Shl32,
+ getC(),
+ mkU8(63-47) ) ,
+ binop( Iop_Shl32,
+ getFPCC(),
+ mkU8(63-51) ) ) );
IRExpr* fpscr_upper = getGST_masked_upper( PPC_GST_FPSCR,
MASK_FPSCR_DRN );
@@ -10622,6 +11358,12 @@
else
mask |= BFP_MASK_SEED >> ( 4 * ( i + 8 * ( 1 - Wbit ) ) );
}
+ if ((FM & (1<<(7-i))) == 0x2) { //set the FPCC bits
+ mask |= 0xF000;
+ }
+ if ((FM & (1<<(7-i))) == 0x4) { //set the Floating-Point Class Descriptor (C) bit
+ mask |= 0x10000;
+ }
}
}
assign( frB, getFReg(frB_addr));
@@ -11200,7 +11942,7 @@
IRTemp low_u_flag = newTemp( Ity_I8 );
IRTemp low_l_flag = newTemp( Ity_I8 );
- /* Check the LMD, digit 16, to see if it is zero. */
+ /* Check the LMD, digit 34, to see if it is zero. */
assign( num_lmd, unop( Iop_1Uto8, binop( Iop_CmpEQ32, lmd, mkU32( 0 ) ) ) );
assign( lmd_flag, unop( Iop_Not8, mkexpr( num_lmd ) ) );
@@ -11212,7 +11954,7 @@
&top_flag,
top_12_l );
- Count_zeros( 1,
+ Count_zeros( 2,
mkexpr( num_top ),
mkexpr( top_flag ),
&num_mid_u,
@@ -11221,14 +11963,14 @@
binop( Iop_Shl32, mid_60_u, mkU8( 2 ) ),
binop( Iop_Shr32, mid_60_l, mkU8( 30 ) ) ) );
- Count_zeros( 2,
+ Count_zeros( 1,
mkexpr( num_mid_u ),
mkexpr( mid_u_flag ),
&num_mid_l,
&mid_l_flag,
mid_60_l );
- Count_zeros( 1,
+ Count_zeros( 2,
mkexpr( num_mid_l ),
mkexpr( mid_l_flag ),
&num_low_u,
@@ -11237,7 +11979,7 @@
binop( Iop_Shl32, low_60_u, mkU8( 2 ) ),
binop( Iop_Shr32, low_60_l, mkU8( 30 ) ) ) );
- Count_zeros( 2,
+ Count_zeros( 1,
mkexpr( num_low_u ),
mkexpr( low_u_flag ),
&num_low_l,
@@ -11263,10 +12005,10 @@
binop( Iop_CmpEQ32,
mkexpr( gfield0to5 ),
mkU32( 0x1E ) ) ),
- unop( Iop_1Sto32, /* SNaN check */
- binop( Iop_CmpEQ32,
- mkexpr( gfield0to5 ),
- mkU32( 0x1F ) ) ) );
+ unop( Iop_1Sto32, /* SNaN check */
+ binop( Iop_CmpEQ32,
+ mkexpr( gfield0to5 ),
+ mkU32( 0x1F ) ) ) );
}
#undef AND
@@ -13359,10 +14101,11 @@
static Bool dis_dfp_significant_digits( UInt theInstr )
{
+ UInt opc1 = ifieldOPC( theInstr );
+ UInt opc2 = ifieldOPClo10(theInstr);
UChar frA_addr = ifieldRegA( theInstr );
UChar frB_addr = ifieldRegB( theInstr );
IRTemp frA = newTemp( Ity_D64 );
- UInt opc1 = ifieldOPC( theInstr );
IRTemp B_sig = newTemp( Ity_I8 );
IRTemp K = newTemp( Ity_I8 );
IRTemp lmd_B = newTemp( Ity_I32 );
@@ -13375,22 +14118,37 @@
IRTemp KisZero_true_mask = newTemp( Ity_I32 );
IRTemp KisZero_false_mask = newTemp( Ity_I32 );
IRTemp cc = newTemp( Ity_I32 );
+ UChar UIM = toUChar( IFIELD( theInstr, 16, 6 ) );
+ IRTemp BCD_valid = newTemp( Ity_I32 );
- /* Get the reference singificance stored in frA */
- assign( frA, getDReg( frA_addr ) );
+ if (opc2 == 0x2A2) { // dtstsf DFP Test Significance
+ // dtstsfq DFP Test Significance Quad
+ /* Get the reference singificance stored in frA */
+ assign( frA, getDReg( frA_addr ) );
- /* Convert from 64 bit to 8 bits in two steps. The Iop_64to8 is not
- * supported in 32-bit mode.
- */
- assign( K, unop( Iop_32to8,
- binop( Iop_And32,
- unop( Iop_64to32,
- unop( Iop_ReinterpD64asI64,
- mkexpr( frA ) ) ),
- mkU32( 0x3F ) ) ) );
+ /* Convert from 64 bit to 8 bits in two steps. The Iop_64to8 is not
+ * supported in 32-bit mode.
+ */
+ assign( K, unop( Iop_32to8,
+ binop( Iop_And32,
+ unop( Iop_64to32,
+ unop( Iop_ReinterpD64asI64,
+ mkexpr( frA ) ) ),
+ mkU32( 0x3F ) ) ) );
+
+ } else if (opc2 == 0x2A3) { // dtstsfi DFP Test Significance Immediate
+ // dtstsfiq DFP Test Significance Quad Immediate
+ /* get the significane from the immediate field */
+ assign( K, mkU8( UIM) );
+
+ } else {
+ vex_printf("dis_dfp_significant_digits(ppc)(opc2) wrong\n");
+ return False;
+ }
switch ( opc1 ) {
case 0x3b: // dtstsf DFP Test Significance
+ // dtstsfi DFP Test Significance Immediate
{
IRTemp frB = newTemp( Ity_D64 );
IRTemp frBI64 = newTemp( Ity_I64 );
@@ -13398,7 +14156,11 @@
IRTemp B_bcd_l = newTemp( Ity_I32 );
IRTemp tmp64 = newTemp( Ity_I64 );
- DIP( "dtstsf %u,r%u,r%u\n", crfD, frA_addr, frB_addr );
+ if (opc2 == 0x2A2) {
+ DIP( "dtstsf %u,r%u,r%u\n", crfD, frA_addr, frB_addr );
+ } else {
+ DIP( "dtstsfi %u,%u,r%u\n", crfD, UIM, frB_addr );
+ }
assign( frB, getDReg( frB_addr ) );
assign( frBI64, unop( Iop_ReinterpD64asI64, mkexpr( frB ) ) );
@@ -13423,10 +14185,23 @@
Count_leading_zeros_60( mkexpr( lmd_B ),
mkexpr( B_bcd_u ),
mkexpr( B_bcd_l ) ) ) );
- assign( Unordered_true, Check_unordered( mkexpr( frBI64 ) ) );
+
+ assign( BCD_valid,
+ binop( Iop_Or32,
+ bcd_digit_inval( mkexpr( B_bcd_u), mkexpr( B_bcd_l) ),
+ bcd_digit_inval( mkexpr( lmd_B), mkU32( 0 ) ) ) );
+
+ /* Set unordered to True if the number is NaN, Inf or an invalid
+ * digit.
+ */
+ assign( Unordered_true,
+ binop( Iop_Or32,
+ Check_unordered( mkexpr( frBI64 ) ),
+ mkexpr( BCD_valid) ) );
}
break;
case 0x3F: // dtstsfq DFP Test Significance
+ // dtstsfqi DFP Test Significance Immediate
{
IRTemp frB_hi = newTemp( Ity_D64 );
IRTemp frB_lo = newTemp( Ity_D64 );
@@ -13438,7 +14213,11 @@
IRTemp B_mid_60_l = newTemp( Ity_I32 );
IRTemp B_top_12_l = newTemp( Ity_I32 );
- DIP( "dtstsfq %u,r%u,r%u\n", crfD, frA_addr, frB_addr );
+ if (opc2 == 0x2A2) {
+ DIP( "dtstsfq %u,r%u,r%u\n", crfD, frA_addr, frB_addr );
+ } else {
+ DIP( "dtstsfiq %u,%u,r%u\n", crfD, UIM, frB_addr );
+ }
assign( frB_hi, getDReg( frB_addr ) );
assign( frB_lo, getDReg( frB_addr + 1 ) );
@@ -13464,6 +14243,16 @@
&B_low_60_u,
&B_low_60_l );
+ assign( BCD_valid,
+ binop( Iop_Or32,
+ binop( Iop_Or32,
+ bcd_digit_inval( mkexpr( lmd_B ),
+ mkexpr( B_top_12_l ) ),
+ bcd_digit_inval( mkexpr( B_mid_60_u ),
+ mkexpr( B_mid_60_l ) ) ),
+ bcd_digit_inval( mkexpr( B_low_60_u ),
+ mkexpr( B_low_60_l ) ) ) );
+
assign( B_sig,
binop( Iop_Sub8,
mkU8( DFP_EXTND_MAX_SIG_DIGITS ),
@@ -13474,7 +14263,13 @@
mkexpr( B_low_60_u ),
mkexpr( B_low_60_l ) ) ) );
- assign( Unordered_true, Check_unordered( mkexpr( frBI64_hi ) ) );
+ /* Set unordered to True if the number is NaN, Inf or an invalid
+ * digit.
+ */
+ assign( Unordered_true,
+ binop( Iop_Or32,
+ Check_unordered( mkexpr( frBI64_hi ) ),
+ mkexpr( BCD_valid) ) );
}
break;
}
@@ -13549,7 +14344,6 @@
return True;
}
-
/*------------------------------------------------------------*/
/*--- AltiVec Instruction Translation ---*/
/*------------------------------------------------------------*/
@@ -18334,8 +19128,8 @@
assign( ld_result, binop( Iop_ShrV128,
binop( Iop_ShlV128,
binop( Iop_64HLtoV128,
- mkexpr( tmp_hi[8] ),
- mkexpr( tmp_low[8] ) ),
+ mkexpr( tmp_low[8] ),
+ mkexpr( tmp_hi[8] ) ),
mkexpr( shift ) ),
mkexpr( shift ) ) );
@@ -18350,11 +19144,112 @@
break;
}
- case 0x16C: // lxvwsx
+ case 0x12D: // lxvll (Load VSX Vector Left-Justified with Length XX1 form)
{
- IRTemp data = newTemp( Ity_I64 );
-
- DIP("lxvwsx %d,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
+ IRTemp byte[16];
+ IRTemp tmp_low[9];
+ IRTemp tmp_hi[9];
+ IRTemp mask = newTemp(Ity_V128);
+ IRTemp rB = newTemp( Ity_I64 );
+ IRTemp nb = newTemp( Ity_I64 );
+ IRTemp nb_zero = newTemp(Ity_V128);
+ IRTemp mask_shift = newTemp(Ity_I64);
+ Int i;
+ UInt ea_off = 0;
+ IRExpr* irx_addr;
+ IRTemp base_addr = newTemp( ty );
+ IRTemp nb_compare_zero = newTemp( Ity_I64 );
+
+ DIP("lxvll %d,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
+
+ tmp_low[0] = newTemp(Ity_I64);
+ tmp_hi[0] = newTemp(Ity_I64);
+
+ assign( rB, getIReg(rB_addr));
+ assign( base_addr, ea_rAor0( rA_addr ) );
+ assign( tmp_low[0], mkU64( 0 ) );
+ assign( tmp_hi[0], mkU64( 0 ) );
+
+ /* mask_shift is number of 16 bytes minus (nb times 8-bits per byte) */
+ assign( nb, binop( Iop_Shr64, mkexpr( rB ), mkU8( 56 ) ) );
+
+ assign( nb_compare_zero, unop( Iop_1Sto64,
+ binop( Iop_CmpEQ64,
+ mkexpr( nb ),
+ mkU64( 0 ) ) ) );
+
+ /* nb_zero is 0xFF..FF if the nb_field = 0 */
+ assign( nb_zero, binop( Iop_64HLtoV128,
+ mkexpr( nb_compare_zero ),
+ mkexpr( nb_compare_zero ) ) );
+
+ assign( mask_shift, binop( Iop_Sub64,
+ mkU64( 16*8 ),
+ binop( Iop_Mul64,
+ mkexpr( nb ),
+ mkU64( 8 ) ) ) );
+
+ /* fetch all 16 bytes, we will remove what we don't want later */
+ for (i = 0; i < 8; i++) {
+ byte[i] = newTemp(Ity_I64);
+ tmp_hi[i+1] = newTemp(Ity_I64);
+
+ irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
+ ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
+ ea_off += 1;
+
+ /* Instruction always loads in Big Endian format */
+ assign( byte[i], binop( Iop_Shl64,
+ unop( Iop_8Uto64,
+ load( Ity_I8, irx_addr ) ),
+ mkU8( 8 * (7 - i) ) ) );
+ assign( tmp_hi[i+1],
+ binop( Iop_Or64,
+ mkexpr( byte[i] ), mkexpr( tmp_hi[i] ) ) );
+ }
+
+ for (i = 0; i < 8; i++) {
+ byte[i + 8] = newTemp(Ity_I64);
+ tmp_low[i+1] = newTemp(Ity_I64);
+
+ irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
+ ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
+ ea_off += 1;
+
+ /* Instruction always loads in Big Endian format */
+ assign( byte[i+8], binop( Iop_Shl64,
+ unop( Iop_8Uto64,
+ load( Ity_I8, irx_addr ) ),
+ mkU8( 8 * (7 - i) ) ) );
+ assign( tmp_low[i+1], binop( Iop_Or64,
+ mkexpr( byte[i+8] ),
+ mkexpr( tmp_low[i] ) ) );
+ }
+
+ /* Create mask to clear the right most 16 - nb bytes, set to zero
+ * if nb= 0.
+ */
+ assign( mask, binop( Iop_AndV128,
+ binop( Iop_ShlV128,
+ binop( Iop_ShrV128,
+ mkV128( 0xFFFF ),
+ unop( Iop_64to8, mkexpr( mask_shift ) ) ),
+ unop( Iop_64to8, mkexpr( mask_shift ) ) ),
+ unop( Iop_NotV128, mkexpr( nb_zero ) ) ) );
+
+ putVSReg( XT, binop( Iop_AndV128,
+ mkexpr( mask ),
+ binop( Iop_64HLtoV128,
+ mkexpr( tmp_hi[8] ),
+ mkexpr( tmp_low[8] ) ) ) );
+ break;
+ }
+
+ case 0x16C: // lxvwsx
+ {
+ IRTemp data = newTemp( Ity_I64 );
+
+ DIP("lxvwsx %d,r%u,r%u\n", (UInt)XT, rA_addr, rB_addr);
/* The load is a 64-bit fetch that is Endian aware, just want
* the lower 32 bits. */
@@ -18886,9 +19781,8 @@
unop( Iop_NotV128, mkexpr( nb_zero ) ) ),
binop( Iop_AndV128,
mkexpr( nb_zero ),
- binop( Iop_64HLtoV128,
- mkU64( 0x0 ),
- mkU64( 0x0 ) ) ) ) );
+ mkV128( 0 ) ) ) );
+
assign( store_val,
binop( Iop_OrV128,
binop( Iop_AndV128,
@@ -18912,9 +19806,7 @@
unop( Iop_NotV128, mkexpr( nb_zero ) ) ),
binop( Iop_AndV128,
mkexpr( nb_zero ),
- binop( Iop_64HLtoV128,
- mkU64( 0x0 ),
- mkU64( 0x0 ) ) ) ) );
+ mkV128( 0 ) ) ) );
assign( store_val,
binop( Iop_OrV128,
@@ -18964,6 +19856,7 @@
ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
store( irx_addr, unop( Iop_64to32, mkexpr( word1 ) ) );
+
ea_off += 4;
irx_addr = binop( mkSzOp( ty, Iop_Add8 ), mkexpr( base_addr ),
ty == Ity_I64 ? mkU64( ea_off ) : mkU32( ea_off ) );
@@ -18972,11 +19865,274 @@
break;
}
+ case 0x1AD: // stxvll (Store VSX Vector Left-justified with length XX1-form)
+ {
+ UInt ea_off = 0;
+ IRExpr* irx_addr;
+ IRTemp word0[5];
+ IRTemp word1[5];
+ IRTemp word2[5];
+ IRTemp word3[5];
+ IRTemp shift = newTemp(Ity_I8);
+ IRTemp nb_gt16 = newTemp(Ity_I8);
+ IRTemp nb_zero = newTemp(Ity_V128);
+ IRTemp nb = newTemp(Ity_I8);
+ IRTemp nb_field = newTemp(Ity_I64);
+ IRTemp n_bytes = newTemp(Ity_I8);
+ IRTemp base_addr = newTemp( ty );
+ IRTemp current_mem = newTemp(Ity_V128);
+ IRTemp store_val = newTemp(Ity_V128);
+ IRTemp nb_mask = newTemp(Ity_V128);
+ IRTemp mask = newTemp( Ity_I64 );
+ IRTemp byte[16];
+ IRTemp tmp_low[9];
+ IRTemp tmp_hi[9];
+ IRTemp nb_field_compare_zero = newTemp( Ity_I64 );
+ Int i;
+
+ DIP("stxvll %d,r%u,r%u\n", (UInt)XS, rA_addr, rB_addr);
+
+ assign( nb_field, binop( Iop_Shr64,
+ getIReg(rB_addr),
+ mkU8( 56 ) ) );
+ assign( nb, unop( Iop_64to8, mkexpr( nb_field ) ) );
+ assign( mask, mkU64( 0xFFFFFFFFFFFFFFFFULL ) );
+
+ /* nb_gt16 will be all zeros if nb > 16 */
+ assign( nb_gt16, unop( Iop_1Sto8,
+ binop( Iop_CmpLT64U,
+ binop( Iop_Shr64,
+ mkexpr( nb_field ),
+ mkU8( 4 ) ),
+ mkU64( 1 ) ) ) );
+
+ assign( nb_field_compare_zero, unop( Iop_1Sto64,
+ binop( Iop_CmpEQ64,
+ mkexpr( nb_field ),
+ mkU64( 0 ) ) ) );
+
+ /* nb_zero is 0xFF..FF if the nb_field = 0 */
+ assign( nb_zero, binop( Iop_64HLtoV128,
+ mkexpr( nb_field_compare_zero ),
+ mkexpr( nb_field_compare_zero ) ) );...
[truncated message content] |