]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
POWER Processor decimal FP support, part 5 (VEX side). Bug #299694.
authorJulian Seward <jseward@acm.org>
Sat, 2 Jun 2012 23:47:02 +0000 (23:47 +0000)
committerJulian Seward <jseward@acm.org>
Sat, 2 Jun 2012 23:47:02 +0000 (23:47 +0000)
(Carl Love, carll@us.ibm.com and Maynard Johnson, maynardj@us.ibm.com)

This patch adds support for Power Decimal Floating Point (DFP) . This
is the fifth patch set in the series of five to add the DFP
instruction support to Valgrind.  Adds support for the ddedpd,
ddedpdq, denbcd, denbcdq, dtstsf, and dtstsfq instructions.

git-svn-id: svn://svn.valgrind.org/vex/trunk@2367

VEX/priv/guest_ppc_toIR.c
VEX/priv/host_generic_simd64.c
VEX/priv/host_generic_simd64.h
VEX/priv/host_ppc_isel.c
VEX/priv/ir_defs.c
VEX/pub/libvex_ir.h

index 54a2c4d39df3553518eb9d772183d7fa3905d6d1..e4caa579a526f86c2949279ec32a2156771fc052 100644 (file)
@@ -8513,7 +8513,9 @@ static Bool dis_fp_scr ( UInt theInstr, Bool GX_level )
 /*------------------------------------------------------------*/
 #define DFP_LONG  1
 #define DFP_EXTND 2
+#define DFP_LONG_BIAS   398
 #define DFP_LONG_ENCODED_FIELD_MASK  0x1F00
+#define DFP_EXTND_BIAS  6176
 #define DFP_EXTND_ENCODED_FIELD_MASK 0x1F000
 #define DFP_LONG_EXP_MSK   0XFF
 #define DFP_EXTND_EXP_MSK  0XFFF
@@ -8522,28 +8524,111 @@ static Bool dis_fp_scr ( UInt theInstr, Bool GX_level )
 #define DFP_LONG_GFIELD_RT_SHIFT  (63 - 13 - 32) // adj for upper 32-bits 
 #define DFP_G_FIELD_EXTND_MASK    0x7FFFC000  // upper 32-bits only
 #define DFP_EXTND_GFIELD_RT_SHIFT (63 - 17 - 32) //adj for upper 32 bits
-
 #define DFP_T_FIELD_LONG_MASK     0x3FFFF  // mask for upper 32-bits
 #define DFP_T_FIELD_EXTND_MASK    0x03FFFF // mask for upper 32-bits
-
 #define DFP_LONG_EXP_MAX          369      // biased max
 #define DFP_LONG_EXP_MIN          0        // biased min
 #define DFP_EXTND_EXP_MAX         6111     // biased max
 #define DFP_EXTND_EXP_MIN         0        // biased min
+#define DFP_LONG_MAX_SIG_DIGITS   16
+#define DFP_EXTND_MAX_SIG_DIGITS  34
+#define MAX_DIGITS_IN_STRING      8
+
 
 #define  AND(x, y) binop( Iop_And32, x, y )
-#define   OR(x, y) binop( Iop_Or32,  x, y )
 #define AND4(w, x, y, z) AND( AND( w, x ), AND( y, z ) )
+#define   OR(x, y) binop( Iop_Or32,  x, y )
 #define  OR3(x, y, z)    OR( x, OR( y, z ) )
 #define  OR4(w, x, y, z) OR( OR( w, x ), OR( y, z ) )
+#define  NOT(x) unop( Iop_1Uto32, unop( Iop_Not1, unop( Iop_32to1,  mkexpr( x ) ) ) )
+
 #define  SHL(value, by) binop( Iop_Shl32, value, mkU8( by ) )
+#define  SHR(value, by) binop( Iop_Shr32, value, mkU8( by ) )
+
 #define BITS5(_b4,_b3,_b2,_b1,_b0) \
    (((_b4) << 4) | ((_b3) << 3) | ((_b2) << 2) | \
     ((_b1) << 1) | ((_b0) << 0))
 
-static void Get_lmd(IRTemp * lmd, IRExpr * gfield_0_4 )
+static IRExpr * Gfield_encoding( IRExpr * lmexp, IRExpr * lmd32 )
 {
+   IRTemp lmd_07_mask   = newTemp( Ity_I32 );
+   IRTemp lmd_8_mask    = newTemp( Ity_I32 );
+   IRTemp lmd_9_mask    = newTemp( Ity_I32 );
+   IRTemp lmexp_00_mask = newTemp( Ity_I32 );
+   IRTemp lmexp_01_mask = newTemp( Ity_I32 );
+   IRTemp lmexp_10_mask = newTemp( Ity_I32 );
+   IRTemp lmd_07_val    = newTemp( Ity_I32 );
+   IRTemp lmd_8_val     = newTemp( Ity_I32 );
+   IRTemp lmd_9_val     = newTemp( Ity_I32 );
+
+   /* The encodig is as follows:
+    * lmd - left most digit
+    * lme - left most 2-bits of the exponent
+    *
+    *    lmd
+    *   0 - 7    (lmexp << 3) | lmd
+    *     8      0b11000 (24 decimal) if lme=0b00;
+    *            0b11010 (26 decimal) if lme=0b01;
+    *            0b11100 (28 decimal) if lme=0b10;
+    *     9      0b11001 (25 decimal) if lme=0b00;
+    *            0b11011 (27 decimal) if lme=0b01;
+    *            0b11101 (29 decimal) if lme=0b10;
+    */
+
+   /* Generate the masks for each condition */
+   assign( lmd_07_mask,
+           unop( Iop_1Sto32, binop( Iop_CmpLE32U, lmd32, mkU32( 7 ) ) ) );
+   assign( lmd_8_mask,
+           unop( Iop_1Sto32, binop( Iop_CmpEQ32, lmd32, mkU32( 8 ) ) ) );
+   assign( lmd_9_mask,
+           unop( Iop_1Sto32, binop( Iop_CmpEQ32, lmd32, mkU32( 9 ) ) ) );
+   assign( lmexp_00_mask,
+           unop( Iop_1Sto32, binop( Iop_CmpEQ32, lmexp, mkU32( 0 ) ) ) );
+   assign( lmexp_01_mask,
+           unop( Iop_1Sto32, binop( Iop_CmpEQ32, lmexp, mkU32( 1 ) ) ) );
+   assign( lmexp_10_mask,
+           unop( Iop_1Sto32, binop( Iop_CmpEQ32, lmexp, mkU32( 2 ) ) ) );
 
+   /* Generate the values for each LMD condition, assuming the condition
+    * is TRUE.
+    */
+   assign( lmd_07_val,
+           binop( Iop_Or32, binop( Iop_Shl32, lmexp, mkU8( 3 ) ), lmd32 ) );
+   assign( lmd_8_val,
+           binop( Iop_Or32,
+                  binop( Iop_Or32,
+                         binop( Iop_And32,
+                                mkexpr( lmexp_00_mask ),
+                                mkU32( 24 ) ),
+                         binop( Iop_And32,
+                                mkexpr( lmexp_01_mask ),
+                                mkU32( 26 ) ) ),
+                  binop( Iop_And32, mkexpr( lmexp_10_mask ), mkU32( 28 ) ) ) );
+   assign( lmd_9_val,
+           binop( Iop_Or32,
+                  binop( Iop_Or32,
+                         binop( Iop_And32,
+                                mkexpr( lmexp_00_mask ),
+                                mkU32( 25 ) ),
+                         binop( Iop_And32,
+                                mkexpr( lmexp_01_mask ),
+                                mkU32( 27 ) ) ),
+                  binop( Iop_And32, mkexpr( lmexp_10_mask ), mkU32( 29 ) ) ) );
+
+   /* generate the result from the possible LMD values */
+   return binop( Iop_Or32,
+                 binop( Iop_Or32,
+                        binop( Iop_And32,
+                               mkexpr( lmd_07_mask ),
+                               mkexpr( lmd_07_val ) ),
+                        binop( Iop_And32,
+                               mkexpr( lmd_8_mask ),
+                               mkexpr( lmd_8_val ) ) ),
+                 binop( Iop_And32, mkexpr( lmd_9_mask ), mkexpr( lmd_9_val ) ) );
+}
+
+static void Get_lmd( IRTemp * lmd, IRExpr * gfield_0_4 )
+{
    /* Extract the exponent and the left most digit of the mantissa
     * from the G field bits [0:4].
     */
@@ -8618,11 +8703,450 @@ static void Get_lmd(IRTemp * lmd, IRExpr * gfield_0_4 )
                      ) ) );
 }
 
+#define DIGIT1_SHR 4    // shift digit 1 to bottom 4 bits
+#define DIGIT2_SHR 8    // shift digit 2 to bottom 4 bits
+#define DIGIT3_SHR 12
+#define DIGIT4_SHR 16
+#define DIGIT5_SHR 20
+#define DIGIT6_SHR 24
+#define DIGIT7_SHR 28
+
+static IRExpr * bcd_digit_inval( IRExpr * bcd_u, IRExpr * bcd_l )
+{
+   /* 60-bit BCD string stored in two 32-bit values.  Check that each,
+    * digit is a valid BCD number, i.e. less then 9.
+    */
+   IRTemp valid = newTemp( Ity_I32 );
+
+   assign( valid,
+           AND4( AND4 ( unop( Iop_1Sto32,
+                              binop( Iop_CmpLE32U,
+                                     binop( Iop_And32,
+                                            bcd_l,
+                                            mkU32 ( 0xF ) ),
+                                      mkU32( 0x9 ) ) ),
+                        unop( Iop_1Sto32,
+                              binop( Iop_CmpLE32U,
+                                     binop( Iop_And32,
+                                            binop( Iop_Shr32,
+                                                   bcd_l,
+                                                   mkU8 ( DIGIT1_SHR ) ),
+                                             mkU32 ( 0xF ) ),
+                                      mkU32( 0x9 ) ) ),
+                        unop( Iop_1Sto32,
+                              binop( Iop_CmpLE32U,
+                                     binop( Iop_And32,
+                                            binop( Iop_Shr32,
+                                                   bcd_l,
+                                                   mkU8 ( DIGIT2_SHR ) ),
+                                            mkU32 ( 0xF ) ),
+                                      mkU32( 0x9 ) ) ),
+                        unop( Iop_1Sto32,
+                              binop( Iop_CmpLE32U,
+                                     binop( Iop_And32,
+                                            binop( Iop_Shr32,
+                                                   bcd_l,
+                                                   mkU8 ( DIGIT3_SHR ) ),
+                                             mkU32 ( 0xF ) ),
+                                      mkU32( 0x9 ) ) ) ),
+                 AND4 ( unop( Iop_1Sto32,
+                              binop( Iop_CmpLE32U,
+                                     binop( Iop_And32,
+                                            binop( Iop_Shr32,
+                                                   bcd_l,
+                                                   mkU8 ( DIGIT4_SHR ) ),
+                                            mkU32 ( 0xF ) ),
+                                     mkU32( 0x9 ) ) ),
+                        unop( Iop_1Sto32,
+                              binop( Iop_CmpLE32U,
+                                     binop( Iop_And32,
+                                            binop( Iop_Shr32,
+                                                   bcd_l,
+                                                   mkU8 ( DIGIT5_SHR ) ),
+                                            mkU32 ( 0xF ) ),
+                                     mkU32( 0x9 ) ) ),
+                        unop( Iop_1Sto32,
+                              binop( Iop_CmpLE32U,
+                                     binop( Iop_And32,
+                                            binop( Iop_Shr32,
+                                                   bcd_l,
+                                                   mkU8 ( DIGIT6_SHR ) ),
+                                            mkU32 ( 0xF ) ),
+                                     mkU32( 0x9 ) ) ),
+                        unop( Iop_1Sto32,
+                              binop( Iop_CmpLE32U,
+                                     binop( Iop_And32,
+                                            binop( Iop_Shr32,
+                                                   bcd_l,
+                                                   mkU8 ( DIGIT7_SHR ) ),
+                                            mkU32 ( 0xF ) ),
+                                     mkU32( 0x9 ) ) ) ),
+                 AND4( unop( Iop_1Sto32,
+                             binop( Iop_CmpLE32U,
+                                    binop( Iop_And32,
+                                           bcd_u,
+                                           mkU32 ( 0xF ) ),
+                                    mkU32( 0x9 ) ) ),
+                       unop( Iop_1Sto32,
+                             binop( Iop_CmpLE32U,
+                                    binop( Iop_And32,
+                                           binop( Iop_Shr32,
+                                                  bcd_u,
+                                                  mkU8 ( DIGIT1_SHR ) ),
+                                           mkU32 ( 0xF ) ),
+                                    mkU32( 0x9 ) ) ),
+                       unop( Iop_1Sto32,
+                             binop( Iop_CmpLE32U,
+                                    binop( Iop_And32,
+                                           binop( Iop_Shr32,
+                                                  bcd_u,
+                                                  mkU8 ( DIGIT2_SHR ) ),
+                                           mkU32 ( 0xF ) ),
+                                    mkU32( 0x9 ) ) ),
+                       unop( Iop_1Sto32,
+                             binop( Iop_CmpLE32U,
+                                    binop( Iop_And32,
+                                           binop( Iop_Shr32,
+                                                  bcd_u,
+                                                  mkU8 ( DIGIT3_SHR ) ),
+                                           mkU32 ( 0xF ) ),
+                                    mkU32( 0x9 ) ) ) ),
+                 AND4( unop( Iop_1Sto32,
+                             binop( Iop_CmpLE32U,
+                                    binop( Iop_And32,
+                                           binop( Iop_Shr32,
+                                                  bcd_u,
+                                                  mkU8 ( DIGIT4_SHR ) ),
+                                           mkU32 ( 0xF ) ),
+                                    mkU32( 0x9 ) ) ),
+                       unop( Iop_1Sto32,
+                             binop( Iop_CmpLE32U,
+                                    binop( Iop_And32,
+                                           binop( Iop_Shr32,
+                                                  bcd_u,
+                                                  mkU8 ( DIGIT5_SHR ) ),
+                                           mkU32 ( 0xF ) ),
+                                    mkU32( 0x9 ) ) ),
+                       unop( Iop_1Sto32,
+                             binop( Iop_CmpLE32U,
+                                    binop( Iop_And32,
+                                           binop( Iop_Shr32,
+                                                  bcd_u,
+                                                  mkU8 ( DIGIT6_SHR ) ),
+                                           mkU32 ( 0xF ) ),
+                                    mkU32( 0x9 ) ) ),
+                       unop( Iop_1Sto32,
+                             binop( Iop_CmpLE32U,
+                                    binop( Iop_And32,
+                                           binop( Iop_Shr32,
+                                                  bcd_u,
+                                                  mkU8 ( DIGIT7_SHR ) ),
+                                           mkU32 ( 0xF ) ),
+                                    mkU32( 0x9 ) ) ) ) ) );
+           
+   return unop( Iop_Not32, mkexpr( valid ) );
+}
+#undef DIGIT1_SHR
+#undef DIGIT2_SHR
+#undef DIGIT3_SHR
+#undef DIGIT4_SHR
+#undef DIGIT5_SHR
+#undef DIGIT6_SHR
+#undef DIGIT7_SHR
+
+static IRExpr * Generate_neg_sign_mask( IRExpr * sign )
+{
+   return binop( Iop_Or32,
+                 unop( Iop_1Sto32, binop( Iop_CmpEQ32, sign, mkU32( 0xB ) ) ),
+                 unop( Iop_1Sto32, binop( Iop_CmpEQ32, sign, mkU32( 0xD ) ) )
+               );
+}
+
+static IRExpr * Generate_pos_sign_mask( IRExpr * sign )
+{
+   return binop( Iop_Or32,
+                 binop( Iop_Or32,
+                        unop( Iop_1Sto32,
+                              binop( Iop_CmpEQ32, sign, mkU32( 0xA ) ) ),
+                        unop( Iop_1Sto32,
+                              binop( Iop_CmpEQ32, sign, mkU32( 0xC ) ) ) ),
+                 binop( Iop_Or32,
+                        unop( Iop_1Sto32,
+                              binop( Iop_CmpEQ32, sign, mkU32( 0xE ) ) ),
+                        unop( Iop_1Sto32,
+                              binop( Iop_CmpEQ32, sign, mkU32( 0xF ) ) ) ) );
+}
+
+static IRExpr * Generate_sign_bit( IRExpr * pos_sign_mask,
+                                   IRExpr * neg_sign_mask )
+{
+   return binop( Iop_Or32,
+                 binop( Iop_And32, neg_sign_mask, mkU32( 0x80000000 ) ),
+                 binop( Iop_And32, pos_sign_mask, mkU32( 0x00000000 ) ) );
+}
+
+static IRExpr * Generate_inv_mask( IRExpr * invalid_bcd_mask,
+                                   IRExpr * pos_sign_mask,
+                                   IRExpr * neg_sign_mask )
+/* first argument is all 1's if the BCD string had an invalid digit in it. */
+{
+   return binop( Iop_Or32,
+                 invalid_bcd_mask,
+                 unop( Iop_1Sto32,
+                       binop( Iop_CmpEQ32,
+                              binop( Iop_Or32, pos_sign_mask, neg_sign_mask ),
+                              mkU32( 0x0 ) ) ) );
+}
+
+static void Generate_132_bit_bcd_string( IRExpr * frBI64_hi, IRExpr * frBI64_lo,
+                                         IRTemp * top_12_l, IRTemp * mid_60_u,
+                                         IRTemp * mid_60_l, IRTemp * low_60_u,
+                                         IRTemp * low_60_l)
+{
+   IRTemp tmplow60 = newTemp( Ity_I64 );
+   IRTemp tmpmid60 = newTemp( Ity_I64 );
+   IRTemp tmptop12 = newTemp( Ity_I64 );
+   IRTemp low_50   = newTemp( Ity_I64 );
+   IRTemp mid_50   = newTemp( Ity_I64 );
+   IRTemp top_10   = newTemp( Ity_I64 );
+   IRTemp top_12_u = newTemp( Ity_I32 ); // only needed for a dummy arg
+
+   /* Convert the 110-bit densely packed BCD string to a 128-bit BCD string */
+
+   /* low_50[49:0] = ((frBI64_lo[49:32]  << 14) | frBI64_lo[31:0]) */
+   assign( low_50,
+           binop( Iop_32HLto64,
+                  binop( Iop_And32,
+                         unop( Iop_64HIto32, frBI64_lo ),
+                         mkU32( 0x3FFFF ) ),
+                         unop( Iop_64to32, frBI64_lo ) ) );
+
+   /* Convert the 50 bit densely packed BCD string to a 60 bit
+    * BCD string.
+    */
+   assign( tmplow60, unop( Iop_DPBtoBCD, mkexpr( low_50 ) ) );
+   assign( *low_60_u, unop( Iop_64HIto32, mkexpr( tmplow60 ) ) );
+   assign( *low_60_l, unop( Iop_64to32, mkexpr( tmplow60 ) ) );
+
+   /* mid_50[49:0] =  ((frBI64_hi[35:32] << 14) | frBI64_hi[31:18]) |
+    *                 ((frBI64_hi[17:0]  << 14) | frBI64_lo[63:50])
+    */
+   assign( mid_50,
+           binop( Iop_32HLto64,
+                  binop( Iop_Or32,
+                         binop( Iop_Shl32,
+                                binop( Iop_And32,
+                                       unop( Iop_64HIto32, frBI64_hi ),
+                                       mkU32( 0xF ) ),
+                                mkU8( 14 ) ),
+                         binop( Iop_Shr32,
+                                unop( Iop_64to32, frBI64_hi ),
+                                mkU8( 18 ) ) ),
+                  binop( Iop_Or32,
+                         binop( Iop_Shl32,
+                                unop( Iop_64to32, frBI64_hi ),
+                                mkU8( 14 ) ),
+                         binop( Iop_Shr32,
+                                unop( Iop_64HIto32, frBI64_lo ),
+                                mkU8( 18 ) ) ) ) );
+
+   /* Convert the 50 bit densely packed BCD string to a 60 bit
+    * BCD string.
+    */
+   assign( tmpmid60, unop( Iop_DPBtoBCD, mkexpr( mid_50 ) ) );
+   assign( *mid_60_u, unop( Iop_64HIto32, mkexpr( tmpmid60 ) ) );
+   assign( *mid_60_l, unop( Iop_64to32, mkexpr( tmpmid60 ) ) );
+
+   /* top_10[49:0] = frBI64_hi[45:36]) |  */
+   assign( top_10,
+           binop( Iop_32HLto64,
+                  mkU32( 0 ),
+                  binop( Iop_And32,
+                         binop( Iop_Shr32,
+                                unop( Iop_64HIto32, frBI64_hi ),
+                                mkU8( 4 ) ),
+                         mkU32( 0x3FF ) ) ) );
+
+   /* Convert the 10 bit densely packed BCD string to a 12 bit
+    * BCD string.
+    */
+   assign( tmptop12, unop( Iop_DPBtoBCD, mkexpr( top_10 ) ) );
+   assign( top_12_u, unop( Iop_64HIto32, mkexpr( tmptop12 ) ) );
+   assign( *top_12_l, unop( Iop_64to32, mkexpr( tmptop12 ) ) );
+}
+
+static void Count_zeros( int start, IRExpr * init_cnt, IRExpr * init_flag,
+                         IRTemp * final_cnt, IRTemp * final_flag,
+                         IRExpr * string )
+{
+   IRTemp cnt[MAX_DIGITS_IN_STRING + 1];IRTemp flag[MAX_DIGITS_IN_STRING+1];
+   int digits = MAX_DIGITS_IN_STRING;
+   int i;
+
+   cnt[start-1] = newTemp( Ity_I8 );
+   flag[start-1] = newTemp( Ity_I8 );
+   assign( cnt[start-1], init_cnt);
+   assign( flag[start-1], init_flag);
+
+   for ( i = start; i <= digits; i++) {
+      cnt[i] = newTemp( Ity_I8 );
+      flag[i] = newTemp( Ity_I8 );
+      assign( cnt[i],
+              binop( Iop_Add8,
+                     mkexpr( cnt[i-1] ),
+                     binop(Iop_And8,
+                           unop( Iop_1Uto8,
+                                 binop(Iop_CmpEQ32,
+                                       binop(Iop_And32,
+                                             string,
+                                             mkU32( 0xF <<
+                                                    ( ( digits - i ) * 4) ) ),
+                                       mkU32( 0 ) ) ),
+                           binop( Iop_Xor8, /* complement flag */
+                                  mkexpr( flag[i - 1] ),
+                                  mkU8( 0xFF ) ) ) ) );
+
+      /* set flag to 1 if digit was not a zero */
+      assign( flag[i],
+              binop(Iop_Or8,
+                    unop( Iop_1Sto8,
+                          binop(Iop_CmpNE32,
+                                binop(Iop_And32,
+                                      string,
+                                      mkU32( 0xF <<
+                                             ( (digits - i) * 4) ) ),
+                                mkU32( 0 ) ) ),
+                    mkexpr( flag[i - 1] ) ) );
+   }
+
+   *final_cnt = cnt[digits];
+   *final_flag = flag[digits];
+}
+
+static IRExpr * Count_leading_zeros_60( IRExpr * lmd, IRExpr * upper_28,
+                                        IRExpr * low_32 )
+{
+   IRTemp num_lmd    = newTemp( Ity_I8 );
+   IRTemp num_upper  = newTemp( Ity_I8 );
+   IRTemp num_low    = newTemp( Ity_I8 );
+   IRTemp lmd_flag   = newTemp( Ity_I8 );
+   IRTemp upper_flag = newTemp( Ity_I8 );
+   IRTemp low_flag   = newTemp( Ity_I8 );
+
+   assign( num_lmd, unop( Iop_1Uto8, binop( Iop_CmpEQ32, lmd, mkU32( 0 ) ) ) );
+   assign( lmd_flag, unop( Iop_Not8, mkexpr( num_lmd ) ) );
+
+   Count_zeros( 2,
+                mkexpr( num_lmd ),
+                mkexpr( lmd_flag ),
+                &num_upper,
+                &upper_flag,
+                upper_28 );
+
+   Count_zeros( 1,
+                mkexpr( num_upper ),
+                mkexpr( upper_flag ),
+                &num_low,
+                &low_flag,
+                low_32 );
+
+   return mkexpr( num_low );
+}
+
+static IRExpr * Count_leading_zeros_128( IRExpr * lmd, IRExpr * top_12_l,
+                                         IRExpr * mid_60_u, IRExpr * mid_60_l,
+                                         IRExpr * low_60_u, IRExpr * low_60_l)
+{
+   IRTemp num_lmd   = newTemp( Ity_I8 );
+   IRTemp num_top   = newTemp( Ity_I8 );
+   IRTemp num_mid_u = newTemp( Ity_I8 );
+   IRTemp num_mid_l = newTemp( Ity_I8 );
+   IRTemp num_low_u = newTemp( Ity_I8 );
+   IRTemp num_low_l = newTemp( Ity_I8 );
+
+   IRTemp lmd_flag   = newTemp( Ity_I8 );
+   IRTemp top_flag   = newTemp( Ity_I8 );
+   IRTemp mid_u_flag = newTemp( Ity_I8 );
+   IRTemp mid_l_flag = newTemp( Ity_I8 );
+   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. */
+   assign( num_lmd, unop( Iop_1Uto8, binop( Iop_CmpEQ32, lmd, mkU32( 0 ) ) ) );
+
+   assign( lmd_flag, unop( Iop_Not8, mkexpr( num_lmd ) ) );
+
+   Count_zeros( 6,
+                mkexpr( num_lmd ),
+                mkexpr( lmd_flag ),
+                &num_top,
+                &top_flag,
+                top_12_l );
+
+   Count_zeros( 1,
+                mkexpr( num_top ),
+                mkexpr( top_flag ),
+                &num_mid_u,
+                &mid_u_flag,
+                binop( Iop_Or32,
+                       binop( Iop_Shl32, mid_60_u, mkU8( 2 ) ),
+                       binop( Iop_Shr32, mid_60_l, mkU8( 30 ) ) ) );
+
+   Count_zeros( 2,
+                mkexpr( num_mid_u ),
+                mkexpr( mid_u_flag ),
+                &num_mid_l,
+                &mid_l_flag,
+                mid_60_l );
+
+   Count_zeros( 1,
+                mkexpr( num_mid_l ),
+                mkexpr( mid_l_flag ),
+                &num_low_u,
+                &low_u_flag,
+                binop( Iop_Or32,
+                       binop( Iop_Shl32, low_60_u, mkU8( 2 ) ),
+                       binop( Iop_Shr32, low_60_l, mkU8( 30 ) ) ) );
+
+   Count_zeros( 2,
+                mkexpr( num_low_u ),
+                mkexpr( low_u_flag ),
+                &num_low_l,
+                &low_l_flag,
+                low_60_l );
+
+   return mkexpr( num_low_l );
+}
+
+static IRExpr * Check_unordered(IRExpr * val)
+{
+   IRTemp gfield0to5 = newTemp( Ity_I32 );
+
+   /* Extract G[0:4] */
+   assign( gfield0to5,
+           binop( Iop_And32,
+                  binop( Iop_Shr32, unop( Iop_64HIto32, val ), mkU8( 26 ) ),
+                  mkU32( 0x1F ) ) );
+
+   /* Check for unordered, return all 1'x if true */
+   return binop( Iop_Or32, /* QNaN check */
+                 unop( Iop_1Sto32,
+                       binop( Iop_CmpEQ32,
+                              mkexpr( gfield0to5 ),
+                              mkU32( 0x1E ) ) ),
+                              unop( Iop_1Sto32, /* SNaN check */
+                                    binop( Iop_CmpEQ32,
+                                           mkexpr( gfield0to5 ),
+                                           mkU32( 0x1F ) ) ) );
+}
+
 #undef AND
-#undef OR
 #undef AND4
+#undef OR
 #undef OR3
 #undef OR4
+#undef NOT
+#undef SHR
 #undef SHL
 #undef BITS5
 
@@ -9925,7 +10449,7 @@ static Bool dis_dfp_class_test ( UInt theInstr )
                                           unop( Iop_1Sto32,
                                                 binop( Iop_CmpNE32,
                                                        mkexpr( lmd ),
-                                                      mkU32( 0 ) ) ) ),
+                                                       mkU32( 0 ) ) ) ),
                                   mkU32( 0x1 ) ),
                            mkU8( 1 ) ) );
 
@@ -9991,6 +10515,867 @@ static Bool dis_dfp_class_test ( UInt theInstr )
    return True;
 }
 
+static Bool dis_dfp_bcd(UInt theInstr) {
+   UInt opc2        = ifieldOPClo10( theInstr );
+   ULong sp         = IFIELD(theInstr, 19, 2);
+   ULong s          = IFIELD(theInstr, 20, 1);
+   UChar frT_addr   = ifieldRegDS( theInstr );
+   UChar frB_addr   = ifieldRegB( theInstr );
+   IRTemp frB       = newTemp( Ity_D64 );
+   IRTemp frBI64    = newTemp( Ity_I64 );
+   IRTemp result    = newTemp( Ity_I64 );
+   IRTemp resultD64 = newTemp( Ity_D64 );
+   IRTemp bcd64     = newTemp( Ity_I64 );
+   IRTemp bcd_u     = newTemp( Ity_I32 );
+   IRTemp bcd_l     = newTemp( Ity_I32 );
+   IRTemp dbcd_u    = newTemp( Ity_I32 );
+   IRTemp dbcd_l    = newTemp( Ity_I32 );
+   IRTemp lmd       = newTemp( Ity_I32 );
+
+   assign( frB, getDReg( frB_addr ) );
+   assign( frBI64, unop( Iop_ReinterpD64asI64, mkexpr( frB ) ) );
+
+   switch ( opc2 ) {
+   case 0x142: // ddedpd   DFP Decode DPD to BCD
+      DIP( "ddedpd %llu,r%u,r%u\n", sp, frT_addr, frB_addr );
+
+         assign( bcd64, unop( Iop_DPBtoBCD, mkexpr( frBI64 ) ) );
+         assign( bcd_u, unop( Iop_64HIto32, mkexpr( bcd64 ) ) );
+         assign( bcd_l, unop( Iop_64to32, mkexpr( bcd64 ) ) );
+
+      if ( ( sp == 0 ) || ( sp == 1 ) ) {
+         /* Unsigned BCD string */
+         Get_lmd( &lmd,
+                  binop( Iop_Shr32,
+                         unop( Iop_64HIto32, mkexpr( frBI64 ) ),
+                         mkU8( 31 - 5 ) ) ); // G-field[0:4]
+
+         assign( result,
+                 binop( Iop_32HLto64,
+                        binop( Iop_Or32,
+                               binop( Iop_Shl32, mkexpr( lmd ), mkU8( 28 ) ),
+                               mkexpr( bcd_u ) ),
+                        mkexpr( bcd_l ) ) );
+
+      } else {
+         /* Signed BCD string, the cases for sp 2 and 3 only differ in how
+          * the positive and negative values are encoded in the least
+          * significant bits.
+          */
+         IRTemp sign = newTemp( Ity_I32 );
+
+         if (sp == 2) {
+            /* Positive sign = 0xC, negative sign = 0xD */
+
+            assign( sign,
+                    binop( Iop_Or32,
+                           binop( Iop_Shr32,
+                                  unop( Iop_64HIto32, mkexpr( frBI64 ) ),
+                                  mkU8( 31 ) ),
+                           mkU32( 0xC ) ) );
+
+         } else if ( sp == 3 ) {
+            /* Positive sign = 0xF, negative sign = 0xD */
+            IRTemp tmp32 = newTemp( Ity_I32 );
+
+            /* Complement sign bit then OR into bit position 1 */
+            assign( tmp32,
+                    binop( Iop_Xor32,
+                           binop( Iop_Shr32,
+                                  unop( Iop_64HIto32, mkexpr( frBI64 ) ),
+                                  mkU8( 30 ) ),
+                           mkU32( 0x2 ) ) );
+
+            assign( sign, binop( Iop_Or32, mkexpr( tmp32 ), mkU32( 0xD ) ) );
+
+         } else {
+            vpanic( "The impossible happened: dis_dfp_bcd(ppc), undefined SP field" );
+         }
+
+         /* Put sign in bottom 4 bits, move most significant 4-bits from
+          * bcd_l to bcd_u.
+          */
+         assign( result,
+                 binop( Iop_32HLto64,
+                        binop( Iop_Or32,
+                               binop( Iop_Shr32,
+                                      mkexpr( bcd_l ),
+                                      mkU8( 28 ) ),
+                               binop( Iop_Shl32,
+                                      mkexpr( bcd_u ),
+                                      mkU8( 4 ) ) ),
+                        binop( Iop_Or32,
+                                      mkexpr( sign ),
+                               binop( Iop_Shl32,
+                                      mkexpr( bcd_l ),
+                                      mkU8( 4 ) ) ) ) );
+      }
+
+      putDReg( frT_addr, unop( Iop_ReinterpI64asD64, mkexpr( result ) ) );
+      break;
+
+   case 0x342: // denbcd   DFP Encode BCD to DPD
+   {
+      IRTemp valid_mask   = newTemp( Ity_I32 );
+      IRTemp invalid_mask = newTemp( Ity_I32 );
+      IRTemp without_lmd  = newTemp( Ity_I64 );
+      IRTemp tmp64        = newTemp( Ity_I64 );
+      IRTemp dbcd64       = newTemp( Ity_I64 );
+      IRTemp left_exp     = newTemp( Ity_I32 );
+      IRTemp g0_4         = newTemp( Ity_I32 );
+
+      DIP( "denbcd %llu,r%u,r%u\n", s, frT_addr, frB_addr );
+
+      if ( s == 0 ) {
+         /* Unsigned BCD string */
+         assign( dbcd64, unop( Iop_BCDtoDPB, mkexpr(frBI64 ) ) );
+         assign( dbcd_u, unop( Iop_64HIto32, mkexpr( dbcd64 ) ) );
+         assign( dbcd_l, unop( Iop_64to32, mkexpr( dbcd64 ) ) );
+
+         assign( lmd,
+                 binop( Iop_Shr32,
+                        binop( Iop_And32,
+                               unop( Iop_64HIto32, mkexpr( frBI64 ) ),
+                               mkU32( 0xF0000000 ) ),
+                        mkU8( 28 ) ) );
+
+         assign( invalid_mask,
+                 bcd_digit_inval( unop( Iop_64HIto32, mkexpr( frBI64 ) ),
+                                  unop( Iop_64to32, mkexpr( frBI64 ) ) ) );
+         assign( valid_mask, unop( Iop_Not32, mkexpr( invalid_mask ) ) );
+
+         assign( without_lmd,
+                 unop( Iop_ReinterpD64asI64,
+                       binop( Iop_InsertExpD64,
+                              unop( Iop_ReinterpI64asD64,
+                                    mkU64( DFP_LONG_BIAS ) ),
+                              unop( Iop_ReinterpI64asD64,
+                                    binop( Iop_32HLto64,
+                                           mkexpr( dbcd_u ),
+                                           mkexpr( dbcd_l ) ) ) ) ) );
+         assign( left_exp,
+                 binop( Iop_Shr32,
+                        binop( Iop_And32,
+                               unop( Iop_64HIto32, mkexpr( without_lmd ) ),
+                               mkU32( 0x60000000 ) ),
+                        mkU8( 29 ) ) );
+
+         assign( g0_4,
+                 binop( Iop_Shl32,
+                        Gfield_encoding( mkexpr( left_exp ), mkexpr( lmd ) ),
+                        mkU8( 26 ) ) );
+
+         assign( tmp64,
+                 binop( Iop_32HLto64,
+                        binop( Iop_Or32,
+                               binop( Iop_And32,
+                                      unop( Iop_64HIto32,
+                                            mkexpr( without_lmd ) ),
+                                      mkU32( 0x83FFFFFF ) ),
+                               mkexpr( g0_4 ) ),
+                        unop( Iop_64to32, mkexpr( without_lmd ) ) ) );
+
+      } else if ( s == 1 ) {
+         IRTemp sign = newTemp( Ity_I32 );
+         IRTemp sign_bit = newTemp( Ity_I32 );
+         IRTemp pos_sign_mask = newTemp( Ity_I32 );
+         IRTemp neg_sign_mask = newTemp( Ity_I32 );
+         IRTemp tmp = newTemp( Ity_I64 );
+
+         /* Signed BCD string, least significant 4 bits are sign bits
+          * positive sign = 0xC, negative sign = 0xD
+          */
+         assign( tmp, unop( Iop_BCDtoDPB,
+                            binop( Iop_32HLto64,
+                                   binop( Iop_Shr32,
+                                          unop( Iop_64HIto32,
+                                                mkexpr( frBI64 ) ),
+                                                mkU8( 4 ) ),
+                                   binop( Iop_Or32,
+                                          binop( Iop_Shr32,
+                                                 unop( Iop_64to32,
+                                                       mkexpr( frBI64 ) ),
+                                                  mkU8( 4 ) ),
+                                          binop( Iop_Shl32,
+                                                 unop( Iop_64HIto32,
+                                                       mkexpr( frBI64 ) ),
+                                                       mkU8( 28 ) ) ) ) ) );
+
+         assign( dbcd_u, unop( Iop_64HIto32, mkexpr( tmp ) ) );
+         assign( dbcd_l, unop( Iop_64to32, mkexpr( tmp ) ) );
+
+         /* Get the sign of the BCD string. */
+         assign( sign,
+                 binop( Iop_And32,
+                        unop( Iop_64to32, mkexpr( frBI64 ) ),
+                        mkU32( 0xF ) ) );
+
+         assign( neg_sign_mask, Generate_neg_sign_mask( mkexpr( sign ) ) );
+         assign( pos_sign_mask, Generate_pos_sign_mask( mkexpr( sign ) ) );
+         assign( sign_bit,
+                 Generate_sign_bit( mkexpr( pos_sign_mask ),
+                                    mkexpr( neg_sign_mask ) ) );
+
+         /* Check for invalid sign and BCD digit.  Don't check the bottom
+          * four bits of bcd_l as that is the sign value.
+          */
+         assign( invalid_mask,
+                 Generate_inv_mask(
+                                   bcd_digit_inval( unop( Iop_64HIto32,
+                                                          mkexpr( frBI64 ) ),
+                                                    binop( Iop_Shr32,
+                                                           unop( Iop_64to32,
+                                                                 mkexpr( frBI64 ) ),
+                                                           mkU8( 4 ) ) ),
+                                   mkexpr( pos_sign_mask ),
+                                   mkexpr( neg_sign_mask ) ) );
+
+         assign( valid_mask, unop( Iop_Not32, mkexpr( invalid_mask ) ) );
+
+         /* Generate the result assuming the sign value was valid. */
+         assign( tmp64,
+                 unop( Iop_ReinterpD64asI64,
+                       binop( Iop_InsertExpD64,
+                              unop( Iop_ReinterpI64asD64,
+                                    mkU64( DFP_LONG_BIAS ) ),
+                              unop( Iop_ReinterpI64asD64,
+                                    binop( Iop_32HLto64,
+                                           binop( Iop_Or32,
+                                                  mkexpr( dbcd_u ),
+                                                  mkexpr( sign_bit ) ),
+                                           mkexpr( dbcd_l ) ) ) ) ) );
+      }
+
+      /* Generate the value to store depending on the validity of the
+       * sign value and the validity of the BCD digits.
+       */
+      assign( resultD64,
+              unop( Iop_ReinterpI64asD64,
+                    binop( Iop_32HLto64,
+                           binop( Iop_Or32,
+                                  binop( Iop_And32,
+                                         mkexpr( valid_mask ),
+                                         unop( Iop_64HIto32,
+                                               mkexpr( tmp64 ) ) ),
+                                  binop( Iop_And32,
+                                         mkU32( 0x7C000000 ),
+                                         mkexpr( invalid_mask ) ) ),
+                           binop( Iop_Or32,
+                                  binop( Iop_And32,
+                                         mkexpr( valid_mask ),
+                                         unop( Iop_64to32, mkexpr( tmp64 ) ) ),
+                                  binop( Iop_And32,
+                                         mkU32( 0x0 ),
+                                         mkexpr( invalid_mask ) ) ) ) ) );
+      putDReg( frT_addr, mkexpr( resultD64 ) );
+   }
+   break;
+   default:
+      vpanic( "ERROR: dis_dfp_bcd(ppc), undefined opc2 case " );
+      return False;
+   }
+   return True;
+}
+
+static Bool dis_dfp_bcdq( UInt theInstr )
+{
+   UInt opc2        = ifieldOPClo10( theInstr );
+   ULong sp         = IFIELD(theInstr, 19, 2);
+   ULong s          = IFIELD(theInstr, 20, 1);
+   IRTemp frB_hi    = newTemp( Ity_D64 );
+   IRTemp frB_lo    = newTemp( Ity_D64 );
+   IRTemp frBI64_hi = newTemp( Ity_I64 );
+   IRTemp frBI64_lo = newTemp( Ity_I64 );
+   UChar frT_addr   = ifieldRegDS( theInstr );
+   UChar frB_addr   = ifieldRegB( theInstr );
+
+   IRTemp lmd       = newTemp( Ity_I32 );
+   IRTemp result_hi = newTemp( Ity_I64 );
+   IRTemp result_lo = newTemp( Ity_I64 );
+
+   assign( frB_hi, getDReg( frB_addr ) );
+   assign( frB_lo, getDReg( frB_addr + 1 ) );
+   assign( frBI64_hi, unop( Iop_ReinterpD64asI64, mkexpr( frB_hi ) ) );
+   assign( frBI64_lo, unop( Iop_ReinterpD64asI64, mkexpr( frB_lo ) ) );
+
+   switch ( opc2 ) {
+   case 0x142: // ddedpdq   DFP Decode DPD to BCD
+   {
+      IRTemp low_60_u = newTemp( Ity_I32 );
+      IRTemp low_60_l = newTemp( Ity_I32 );
+      IRTemp mid_60_u = newTemp( Ity_I32 );
+      IRTemp mid_60_l = newTemp( Ity_I32 );
+      IRTemp top_12_l = newTemp( Ity_I32 );
+
+      DIP( "ddedpdq %llu,r%u,r%u\n", sp, frT_addr, frB_addr );
+
+      /* Note, instruction only stores the lower 32 BCD digits in
+       * the result
+       */
+      Generate_132_bit_bcd_string( mkexpr( frBI64_hi ),
+                                   mkexpr( frBI64_lo ),
+                                   &top_12_l,
+                                   &mid_60_u,
+                                   &mid_60_l,
+                                   &low_60_u,
+                                   &low_60_l );
+
+      if ( ( sp == 0 ) || ( sp == 1 ) ) {
+         /* Unsigned BCD string */
+         assign( result_hi,
+                 binop( Iop_32HLto64,
+                        binop( Iop_Or32,
+                               binop( Iop_Shl32,
+                                      mkexpr( top_12_l ),
+                                      mkU8( 24 ) ),
+                               binop( Iop_Shr32,
+                                      mkexpr( mid_60_u ),
+                                      mkU8( 4 ) ) ),
+                        binop( Iop_Or32,
+                               binop( Iop_Shl32,
+                                      mkexpr( mid_60_u ),
+                                      mkU8( 28 ) ),
+                               binop( Iop_Shr32,
+                                      mkexpr( mid_60_l ),
+                                      mkU8( 4 ) ) ) ) );
+
+         assign( result_lo,
+                 binop( Iop_32HLto64,
+                        binop( Iop_Or32,
+                               binop( Iop_Shl32,
+                                      mkexpr( mid_60_l ),
+                                      mkU8( 28 ) ),
+                               mkexpr( low_60_u ) ),
+                        mkexpr( low_60_l ) ) );
+
+      } else {
+         /* Signed BCD string, the cases for sp 2 and 3 only differ in how
+          * the positive and negative values are encoded in the least
+          * significant bits.
+          */
+         IRTemp sign = newTemp( Ity_I32 );
+
+         if ( sp == 2 ) {
+            /* Positive sign = 0xC, negative sign = 0xD */
+            assign( sign,
+                    binop( Iop_Or32,
+                           binop( Iop_Shr32,
+                                  unop( Iop_64HIto32, mkexpr( frBI64_hi ) ),
+                                  mkU8( 31 ) ),
+                           mkU32( 0xC ) ) );
+
+         } else if ( sp == 3 ) {
+            IRTemp tmp32 = newTemp( Ity_I32 );
+
+            /* Positive sign = 0xF, negative sign = 0xD.
+             * Need to complement sign bit then OR into bit position 1.
+             */
+            assign( tmp32,
+                    binop( Iop_Xor32,
+                           binop( Iop_Shr32,
+                                  unop( Iop_64HIto32, mkexpr( frBI64_hi ) ),
+                                  mkU8( 30 ) ),
+                           mkU32( 0x2 ) ) );
+
+            assign( sign, binop( Iop_Or32, mkexpr( tmp32 ), mkU32( 0xD ) ) );
+
+         } else {
+            vpanic( "The impossible happened: dis_dfp_bcd(ppc), undefined SP field" );
+         }
+
+         assign( result_hi,
+                 binop( Iop_32HLto64,
+                        binop( Iop_Or32,
+                               binop( Iop_Shl32,
+                                      mkexpr( top_12_l ),
+                                      mkU8( 28 ) ),
+                               mkexpr( mid_60_u ) ),
+                        mkexpr( mid_60_l ) ) );
+
+         assign( result_lo,
+                 binop( Iop_32HLto64,
+                        binop( Iop_Or32,
+                               binop( Iop_Shl32,
+                                      mkexpr( low_60_u ),
+                                      mkU8( 4 ) ),
+                               binop( Iop_Shr32,
+                                      mkexpr( low_60_l ),
+                                      mkU8( 28 ) ) ),
+                        binop( Iop_Or32,
+                               binop( Iop_Shl32,
+                                      mkexpr( low_60_l ),
+                                      mkU8( 4 ) ),
+                               mkexpr( sign ) ) ) );
+      }
+
+      putDReg( frT_addr, unop( Iop_ReinterpI64asD64, mkexpr( result_hi ) ) );
+      putDReg( frT_addr + 1,
+               unop( Iop_ReinterpI64asD64, mkexpr( result_lo ) ) );
+   }
+   break;
+   case 0x342: // denbcdq   DFP Encode BCD to DPD
+   {
+      IRTemp valid_mask      = newTemp( Ity_I32 );
+      IRTemp invalid_mask    = newTemp( Ity_I32 );
+      IRTemp result128       = newTemp( Ity_D128 );
+      IRTemp dfp_significand = newTemp( Ity_D128 );
+      IRTemp tmp_hi          = newTemp( Ity_I64 );
+      IRTemp tmp_lo          = newTemp( Ity_I64 );
+      IRTemp dbcd_top_l      = newTemp( Ity_I32 );
+      IRTemp dbcd_mid_u      = newTemp( Ity_I32 );
+      IRTemp dbcd_mid_l      = newTemp( Ity_I32 );
+      IRTemp dbcd_low_u      = newTemp( Ity_I32 );
+      IRTemp dbcd_low_l      = newTemp( Ity_I32 );
+      IRTemp bcd_top_8       = newTemp( Ity_I64 );
+      IRTemp bcd_mid_60      = newTemp( Ity_I64 );
+      IRTemp bcd_low_60      = newTemp( Ity_I64 );
+      IRTemp sign_bit        = newTemp( Ity_I32 );
+      IRTemp tmptop10        = newTemp( Ity_I64 );
+      IRTemp tmpmid50        = newTemp( Ity_I64 );
+      IRTemp tmplow50        = newTemp( Ity_I64 );
+      IRTemp inval_bcd_digit_mask = newTemp( Ity_I32 );
+
+      DIP( "denbcd %llu,r%u,r%u\n", s, frT_addr, frB_addr );
+
+      if ( s == 0 ) {
+         /* Unsigned BCD string */
+         assign( sign_bit, mkU32( 0 ) ); // set to zero for unsigned string
+
+         assign( bcd_top_8,
+                 binop( Iop_32HLto64,
+                        mkU32( 0 ),
+                        binop( Iop_And32,
+                               binop( Iop_Shr32,
+                                      unop( Iop_64HIto32,
+                                            mkexpr( frBI64_hi ) ),
+                                      mkU8( 24 ) ),
+                               mkU32( 0xFF ) ) ) );
+         assign( bcd_mid_60,
+                 binop( Iop_32HLto64,
+                        binop( Iop_Or32,
+                               binop( Iop_Shr32,
+                                      unop( Iop_64to32,
+                                            mkexpr( frBI64_hi ) ),
+                                      mkU8( 28 ) ),
+                               binop( Iop_Shl32,
+                                      unop( Iop_64HIto32,
+                                            mkexpr( frBI64_hi ) ),
+                                      mkU8( 4 ) ) ),
+                        binop( Iop_Or32,
+                               binop( Iop_Shl32,
+                                      unop( Iop_64to32,
+                                            mkexpr( frBI64_hi ) ),
+                                      mkU8( 4 ) ),
+                               binop( Iop_Shr32,
+                                      unop( Iop_64HIto32,
+                                            mkexpr( frBI64_lo ) ),
+                                      mkU8( 28 ) ) ) ) );
+
+         /* Note, the various helper functions ignores top 4-bits */
+         assign( bcd_low_60, mkexpr( frBI64_lo ) );
+
+         assign( tmptop10, unop( Iop_BCDtoDPB, mkexpr( bcd_top_8 ) ) );
+         assign( dbcd_top_l, unop( Iop_64to32, mkexpr( tmptop10 ) ) );
+
+         assign( tmpmid50, unop( Iop_BCDtoDPB, mkexpr( bcd_mid_60 ) ) );
+         assign( dbcd_mid_u, unop( Iop_64HIto32, mkexpr( tmpmid50 ) ) );
+         assign( dbcd_mid_l, unop( Iop_64to32, mkexpr( tmpmid50 ) ) );
+
+         assign( tmplow50, unop( Iop_BCDtoDPB, mkexpr( bcd_low_60 ) ) );
+         assign( dbcd_low_u, unop( Iop_64HIto32, mkexpr( tmplow50 ) ) );
+         assign( dbcd_low_l, unop( Iop_64to32, mkexpr( tmplow50 ) ) );
+
+         /* The entire BCD string fits in lower 110-bits.  The LMD = 0,
+          * value is not part of the final result. Only the right most
+          * BCD digits are stored.
+          */
+         assign( lmd, mkU32( 0 ) );
+
+         assign( invalid_mask,
+                 binop( Iop_Or32,
+                        bcd_digit_inval( mkU32( 0 ),
+                                         unop( Iop_64to32,
+                                               mkexpr( bcd_top_8 ) ) ),
+                        binop( Iop_Or32,
+                               bcd_digit_inval( unop( Iop_64HIto32,
+                                                      mkexpr( bcd_mid_60 ) ),
+                                                unop( Iop_64to32,
+                                                      mkexpr( bcd_mid_60 ) ) ),
+                               bcd_digit_inval( unop( Iop_64HIto32,
+                                                      mkexpr( bcd_low_60 ) ),
+                                                unop( Iop_64to32,
+                                                      mkexpr( bcd_low_60 ) )
+                                                ) ) ) );
+
+      } else if ( s == 1 ) {
+         IRTemp sign          = newTemp( Ity_I32 );
+         IRTemp zero          = newTemp( Ity_I32 );
+         IRTemp pos_sign_mask = newTemp( Ity_I32 );
+         IRTemp neg_sign_mask = newTemp( Ity_I32 );
+
+         /* The sign of the BCD string is stored in lower 4 bits */
+         assign( sign,
+                 binop( Iop_And32,
+                        unop( Iop_64to32, mkexpr( frBI64_lo ) ),
+                        mkU32( 0xF ) ) );
+         assign( neg_sign_mask, Generate_neg_sign_mask( mkexpr( sign ) ) );
+         assign( pos_sign_mask, Generate_pos_sign_mask( mkexpr( sign ) ) );
+         assign( sign_bit,
+                 Generate_sign_bit( mkexpr( pos_sign_mask ),
+                                    mkexpr( neg_sign_mask ) ) );
+
+         /* Generate the value assuminig the sign and BCD digits are vaild */
+         assign( bcd_top_8,
+                 binop( Iop_32HLto64,
+                        mkU32( 0x0 ),
+                        binop( Iop_Shr32,
+                               unop( Iop_64HIto32, mkexpr( frBI64_hi ) ),
+                               mkU8( 28 ) ) ) );
+
+         /* The various helper routines ignore the upper 4-bits */
+         assign( bcd_mid_60, mkexpr( frBI64_hi ) );
+
+         /* Remove bottom four sign bits */
+         assign( bcd_low_60,
+                 binop( Iop_32HLto64,
+                        binop( Iop_Shr32,
+                               unop( Iop_64HIto32,
+                                     mkexpr( frBI64_lo ) ),
+                               mkU8( 4 ) ),
+                               binop( Iop_Or32,
+                                      binop( Iop_Shl32,
+                                             unop( Iop_64HIto32,
+                                                   mkexpr( frBI64_lo ) ),
+                                             mkU8( 28 ) ),
+                                      binop( Iop_Shr32,
+                                             unop( Iop_64to32,
+                                                   mkexpr( frBI64_lo ) ),
+                                             mkU8( 4 ) ) ) ) );
+         assign( tmptop10, unop( Iop_BCDtoDPB, mkexpr(bcd_top_8 ) ) );
+         assign( dbcd_top_l, unop( Iop_64to32, mkexpr( tmptop10 ) ) );
+
+         assign( tmpmid50, unop( Iop_BCDtoDPB, mkexpr(bcd_mid_60 ) ) );
+         assign( dbcd_mid_u, unop( Iop_64HIto32, mkexpr( tmpmid50 ) ) );
+         assign( dbcd_mid_l, unop( Iop_64to32, mkexpr( tmpmid50 ) ) );
+
+         assign( tmplow50, unop( Iop_BCDtoDPB, mkexpr( bcd_low_60 ) ) );
+         assign( dbcd_low_u, unop( Iop_64HIto32, mkexpr( tmplow50 ) ) );
+         assign( dbcd_low_l, unop( Iop_64to32, mkexpr( tmplow50 ) ) );
+
+         /* The entire BCD string fits in lower 110-bits.  The LMD value
+          * is not stored in the final result for the DFP Long instruction.
+          */
+         assign( lmd, mkU32( 0 ) );
+
+         /* Check for invalid sign and invalid BCD digit.  Don't check the
+          *  bottom four bits of frBI64_lo as that is the sign value.
+          */
+         assign( zero, mkU32( 0 ) );
+         assign( inval_bcd_digit_mask,
+                 binop( Iop_Or32,
+                        bcd_digit_inval( mkexpr( zero ),
+                                         unop( Iop_64to32,
+                                               mkexpr( bcd_top_8 ) ) ),
+                        binop( Iop_Or32,
+                               bcd_digit_inval( unop( Iop_64HIto32,
+                                                     mkexpr( bcd_mid_60 ) ),
+                                               unop( Iop_64to32,
+                                                     mkexpr( bcd_mid_60 ) ) ),
+                               bcd_digit_inval( unop( Iop_64HIto32,
+                                                     mkexpr( frBI64_lo ) ),
+                                               binop( Iop_Shr32,
+                                                      unop( Iop_64to32,
+                                                            mkexpr( frBI64_lo ) ),
+                                                        mkU8( 4 ) ) ) ) ) );
+         assign( invalid_mask,
+                 Generate_inv_mask( mkexpr( inval_bcd_digit_mask ),
+                                    mkexpr( pos_sign_mask ),
+                                    mkexpr( neg_sign_mask ) ) );
+
+      }
+
+      assign( valid_mask, unop( Iop_Not32, mkexpr( invalid_mask ) ) );
+
+      /* Calculate the value of the result assuming sign and BCD digits
+       * are all valid.
+       */
+      assign( dfp_significand,
+              binop( Iop_D64HLtoD128,
+                     unop( Iop_ReinterpI64asD64,
+                           binop( Iop_32HLto64,
+                                  binop( Iop_Or32,
+                                         mkexpr( sign_bit ),
+                                         mkexpr( dbcd_top_l ) ),
+                                  binop( Iop_Or32,
+                                         binop( Iop_Shl32,
+                                                mkexpr( dbcd_mid_u ),
+                                                mkU8( 18 ) ),
+                                         binop( Iop_Shr32,
+                                                mkexpr( dbcd_mid_l ),
+                                                mkU8( 14 ) ) ) ) ),
+                     unop( Iop_ReinterpI64asD64,
+                           binop( Iop_32HLto64,
+                                  binop( Iop_Or32,
+                                         mkexpr( dbcd_low_u ),
+                                         binop( Iop_Shl32,
+                                                mkexpr( dbcd_mid_l ),
+                                                mkU8( 18 ) ) ),
+                                  mkexpr( dbcd_low_l ) ) ) ) );
+
+      /* Break the result back down to 32-bit chunks and replace chunks.
+       * If there was an invalid BCD digit or invalid sign value, replace
+       * the calculated result with the invalid bit string.
+       */
+      assign( result128,
+              binop( Iop_InsertExpD128,
+                     unop( Iop_ReinterpI64asD64, mkU64( DFP_EXTND_BIAS ) ),
+                     mkexpr( dfp_significand ) ) );
+
+      assign( tmp_hi,
+              unop( Iop_ReinterpD64asI64,
+                    unop( Iop_D128HItoD64, mkexpr( result128 ) ) ) );
+
+      assign( tmp_lo,
+              unop( Iop_ReinterpD64asI64,
+                    unop( Iop_D128LOtoD64, mkexpr( result128 ) ) ) );
+
+      assign( result_hi,
+              binop( Iop_32HLto64,
+                     binop( Iop_Or32,
+                            binop( Iop_And32,
+                                   mkexpr( valid_mask ),
+                                   unop( Iop_64HIto32, mkexpr( tmp_hi ) ) ),
+                            binop( Iop_And32,
+                                   mkU32( 0x7C000000 ),
+                                   mkexpr( invalid_mask ) ) ),
+                     binop( Iop_Or32,
+                            binop( Iop_And32,
+                                   mkexpr( valid_mask ),
+                                   unop( Iop_64to32, mkexpr( tmp_hi ) ) ),
+                            binop( Iop_And32,
+                                   mkU32( 0x0 ),
+                                   mkexpr( invalid_mask ) ) ) ) );
+
+      assign( result_lo,
+              binop( Iop_32HLto64,
+                     binop( Iop_Or32,
+                            binop( Iop_And32,
+                                   mkexpr( valid_mask ),
+                                   unop( Iop_64HIto32, mkexpr( tmp_lo ) ) ),
+                            binop( Iop_And32,
+                                   mkU32( 0x0 ),
+                                   mkexpr( invalid_mask ) ) ),
+                     binop( Iop_Or32,
+                            binop( Iop_And32,
+                                   mkexpr( valid_mask ),
+                                   unop( Iop_64to32, mkexpr( tmp_lo ) ) ),
+                            binop( Iop_And32,
+                                   mkU32( 0x0 ),
+                                   mkexpr( invalid_mask ) ) ) ) );
+
+      putDReg( frT_addr, unop( Iop_ReinterpI64asD64, mkexpr( result_hi ) ) );
+      putDReg( frT_addr + 1,
+               unop( Iop_ReinterpI64asD64, mkexpr( result_lo ) ) );
+
+   }
+   break;
+   default:
+      vpanic( "ERROR: dis_dfp_bcdq(ppc), undefined opc2 case " );
+      break;
+   }
+   return True;
+}
+
+static Bool dis_dfp_significant_digits( UInt 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 );
+   IRTemp field   = newTemp( Ity_I32 );
+   UChar crfD     = toUChar( IFIELD( theInstr, 23, 3 ) ); // AKA BF
+   IRTemp Unordered_true     = newTemp( Ity_I32 );
+   IRTemp Eq_true_mask       = newTemp( Ity_I32 );
+   IRTemp Lt_true_mask       = newTemp( Ity_I32 );
+   IRTemp Gt_true_mask       = newTemp( Ity_I32 );
+   IRTemp KisZero_true_mask  = newTemp( Ity_I32 );
+   IRTemp KisZero_false_mask = newTemp( Ity_I32 );
+
+   /* 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 ) ) ) );
+
+   switch ( opc1 ) {
+   case 0x3b: // dtstsf   DFP Test Significance
+   {
+      IRTemp frB     = newTemp( Ity_D64 );
+      IRTemp frBI64  = newTemp( Ity_I64 );
+      IRTemp B_bcd_u = newTemp( Ity_I32 );
+      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 );
+
+      assign( frB, getDReg( frB_addr ) );
+      assign( frBI64, unop( Iop_ReinterpD64asI64, mkexpr( frB ) ) );
+
+      /* Get the BCD string for the value stored in a series of I32 values.
+       * Count the number of leading zeros.  Subtract the number of leading
+       * zeros from 16 (maximum number of significant digits in DFP
+       * Long).
+       */
+      Get_lmd( &lmd_B,
+               binop( Iop_Shr32,
+                      unop( Iop_64HIto32, mkexpr( frBI64 ) ),
+                      mkU8( 31 - 5 ) ) ); // G-field[0:4]
+
+      assign( tmp64, unop( Iop_DPBtoBCD, mkexpr( frBI64 ) ) );
+      assign( B_bcd_u, unop( Iop_64HIto32, mkexpr( tmp64 ) ) );
+      assign( B_bcd_l, unop( Iop_64to32, mkexpr( tmp64 ) ) );
+
+      assign( B_sig,
+              binop( Iop_Sub8,
+                     mkU8( DFP_LONG_MAX_SIG_DIGITS ),
+                     Count_leading_zeros_60( mkexpr( lmd_B ),
+                                             mkexpr( B_bcd_u ),
+                                             mkexpr( B_bcd_l ) ) ) );
+      assign( Unordered_true, Check_unordered( mkexpr( frBI64 ) ) );
+   }
+   break;
+   case 0x3F: // dtstsfq     DFP Test Significance
+   {
+      IRTemp frB_hi     = newTemp( Ity_D64 );
+      IRTemp frB_lo     = newTemp( Ity_D64 );
+      IRTemp frBI64_hi  = newTemp( Ity_I64 );
+      IRTemp frBI64_lo  = newTemp( Ity_I64 );
+      IRTemp B_low_60_u = newTemp( Ity_I32 );
+      IRTemp B_low_60_l = newTemp( Ity_I32 );
+      IRTemp B_mid_60_u = newTemp( Ity_I32 );
+      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 );
+
+      assign( frB_hi, getDReg( frB_addr ) );
+      assign( frB_lo, getDReg( frB_addr + 1 ) );
+
+      assign( frBI64_hi, unop( Iop_ReinterpD64asI64, mkexpr( frB_hi ) ) );
+      assign( frBI64_lo, unop( Iop_ReinterpD64asI64, mkexpr( frB_lo ) ) );
+
+      /* Get the BCD string for the value stored in a series of I32 values.
+       * Count the number of leading zeros.  Subtract the number of leading
+       * zeros from 32 (maximum number of significant digits in DFP
+       * extended).
+       */
+      Get_lmd( &lmd_B,
+               binop( Iop_Shr32,
+                      unop( Iop_64HIto32, mkexpr( frBI64_hi ) ),
+                      mkU8( 31 - 5 ) ) ); // G-field[0:4]
+
+      Generate_132_bit_bcd_string( mkexpr( frBI64_hi ),
+                                   mkexpr( frBI64_lo ),
+                                   &B_top_12_l,
+                                   &B_mid_60_u,
+                                   &B_mid_60_l,
+                                   &B_low_60_u,
+                                   &B_low_60_l );
+
+      assign( B_sig,
+              binop( Iop_Sub8,
+                     mkU8( DFP_EXTND_MAX_SIG_DIGITS ),
+                     Count_leading_zeros_128( mkexpr( lmd_B ),
+                                              mkexpr( B_top_12_l ),
+                                              mkexpr( B_mid_60_u ),
+                                              mkexpr( B_mid_60_l ),
+                                              mkexpr( B_low_60_u ),
+                                              mkexpr( B_low_60_l ) ) ) );
+
+      assign( Unordered_true, Check_unordered( mkexpr( frBI64_hi ) ) );
+   }
+   break;
+   }
+
+   /* Compare (16 - cnt[0]) against K and set the condition code field
+    * accordingly.
+    *
+    * The field layout is as follows:
+    *
+    * bit[3:0]    Description
+    *    3     K != 0 and K < Number of significant digits if FRB
+    *    2     K != 0 and K > Number of significant digits if FRB OR K = 0
+    *    1     K != 0 and K = Number of significant digits if FRB
+    *    0     K ? Number of significant digits if FRB
+    */
+   assign( Eq_true_mask,
+           unop( Iop_1Sto32,
+                 binop( Iop_CmpEQ32,
+                        unop( Iop_8Uto32, mkexpr( K ) ),
+                        unop( Iop_8Uto32, mkexpr( B_sig ) ) ) ) );
+   assign( Lt_true_mask,
+           unop( Iop_1Sto32,
+                 binop( Iop_CmpLT32U,
+                        unop( Iop_8Uto32, mkexpr( K ) ),
+                        unop( Iop_8Uto32, mkexpr( B_sig ) ) ) ) );
+   assign( Gt_true_mask,
+           unop( Iop_1Sto32,
+                 binop( Iop_CmpLT32U,
+                        unop( Iop_8Uto32, mkexpr( B_sig ) ),
+                        unop( Iop_8Uto32, mkexpr( K ) ) ) ) );
+
+   assign( KisZero_true_mask,
+           unop( Iop_1Sto32,
+                 binop( Iop_CmpEQ32,
+                        unop( Iop_8Uto32, mkexpr( K ) ),
+                        mkU32( 0 ) ) ) );
+   assign( KisZero_false_mask,
+           unop( Iop_1Sto32,
+                 binop( Iop_CmpNE32,
+                        unop( Iop_8Uto32, mkexpr( K ) ),
+                        mkU32( 0 ) ) ) );
+
+   assign( field,
+           binop( Iop_Or32,
+                  binop( Iop_And32,
+                         mkexpr( KisZero_false_mask ),
+                         binop( Iop_Or32,
+                                binop( Iop_And32,
+                                       mkexpr( Lt_true_mask ),
+                                       mkU32( 0x8 ) ),
+                                binop( Iop_Or32,
+                                       binop( Iop_And32,
+                                              mkexpr( Gt_true_mask ),
+                                              mkU32( 0x4 ) ),
+                                       binop( Iop_And32,
+                                              mkexpr( Eq_true_mask ),
+                                              mkU32( 0x2 ) ) ) ) ),
+                  binop( Iop_And32,
+                         mkexpr( KisZero_true_mask ),
+                         mkU32( 0x4 ) ) ) );
+
+   putGST_field( PPC_GST_CR,
+                 binop( Iop_Or32,
+                        binop( Iop_And32,
+                               mkexpr( Unordered_true ),
+                               mkU32( 0x1 ) ),
+                        binop( Iop_And32,
+                               unop( Iop_Not32, mkexpr( Unordered_true ) ),
+                               mkexpr( field ) ) ),
+                 crfD );
+
+   return True;
+}
 
 /*------------------------------------------------------------*/
 /*--- AltiVec Instruction Translation                      ---*/
@@ -15203,6 +16588,19 @@ DisResult disInstr_PPC_WRK (
             if (dis_dfp_fmt_conv( theInstr ))
                goto decode_success;
             goto decode_failure;
+         case 0x2A2: // dtstsf - DFP number of significant digits
+            if (!allow_DFP)
+               goto decode_failure;
+            if (dis_dfp_significant_digits(theInstr))
+               goto decode_success;
+            goto decode_failure;
+         case 0x142: // ddedpd   DFP Decode DPD to BCD
+         case 0x342: // denbcd   DFP Encode BCD to DPD
+            if (!allow_DFP)
+               goto decode_failure;
+            if (dis_dfp_bcd(theInstr))
+               goto decode_success;
+            goto decode_failure;
          case 0x162:  // dxex - Extract exponent 
          case 0x362:  // diex - Insert exponent
             if (!allow_DFP)
@@ -15507,6 +16905,21 @@ DisResult disInstr_PPC_WRK (
             goto decode_success;
          goto decode_failure;
 
+      case 0x2A2: // dtstsfq - DFP number of significant digits
+         if (!allow_DFP)
+            goto decode_failure;
+         if (dis_dfp_significant_digits(theInstr))
+            goto decode_success;
+         goto decode_failure;
+
+      case 0x142: // ddedpdq   DFP Decode DPD to BCD
+      case 0x342: // denbcdq   DFP Encode BCD to DPD
+         if (!allow_DFP)
+            goto decode_failure;
+         if (dis_dfp_bcdq(theInstr))
+            goto decode_success;
+         goto decode_failure;
+
       /* Floating Point Compare Instructions */         
       case 0x000: // fcmpu
       case 0x020: // fcmpo
index 52af103d453bf00d172bfdfe0411b4337cb1b901..3bebe9068547a1d983cb570c73e992fffd9bcc75 100644 (file)
@@ -1379,7 +1379,132 @@ UInt h_generic_calc_Sad8Ux4 ( UInt xx, UInt yy )
           + absdiff8U( sel8x4_0(xx), sel8x4_0(yy) );
 }
 
+/*------------------------------------------------------------------*/
+/* Decimal Floating Point (DFP) externally visible helper functions */
+/* that implement Iop_BCDtoDPB and Iop_DPBtoBCD                     */
+/*------------------------------------------------------------------*/
+
+#define NOT( x )    ( ( ( x ) == 0) ? 1 : 0)
+#define GET( x, y ) ( ( ( x ) & ( 0x1UL << ( y ) ) ) >> ( y ) )
+#define PUT( x, y ) ( ( x )<< ( y ) )
+
+ULong dpb_to_bcd( ULong chunk )
+{
+   Short a, b, c, d, e, f, g, h, i, j, k, m;
+   Short p, q, r, s, t, u, v, w, x, y;
+   ULong value;
+
+   /* convert 10 bit densely packed BCD to BCD */
+   p = GET( chunk, 9 );
+   q = GET( chunk, 8 );
+   r = GET( chunk, 7 );
+   s = GET( chunk, 6 );
+   t = GET( chunk, 5 );
+   u = GET( chunk, 4 );
+   v = GET( chunk, 3 );
+   w = GET( chunk, 2 );
+   x = GET( chunk, 1 );
+   y = GET( chunk, 0 );
+
+   /* The BCD bit values are given by the following boolean equations.*/
+   a = ( NOT(s) & v & w ) | ( t & v & w & s ) | ( v & w & NOT(x) );
+   b = ( p & s & x & NOT(t) ) | ( p & NOT(w) ) | ( p & NOT(v) );
+   c = ( q & s & x & NOT(t) ) | ( q & NOT(w) ) | ( q & NOT(v) );
+   d = r;
+   e = ( v & NOT(w) & x ) | ( s & v & w & x ) | ( NOT(t) & v & x & w );
+   f = ( p & t & v & w & x & NOT(s) ) | ( s & NOT(x) & v ) | ( s & NOT(v) );
+   g = ( q & t & w & v & x & NOT(s) ) | ( t & NOT(x) & v ) | ( t & NOT(v) );
+   h = u;
+   i = ( t & v & w & x ) | ( s & v & w & x ) | ( v & NOT(w) & NOT(x) );
+   j = ( p & NOT(s) & NOT(t) & w & v ) | ( s & v & NOT(w) & x )
+            | ( p & w & NOT(x) & v ) | ( w & NOT(v) );
+   k = ( q & NOT(s) & NOT(t) & v & w ) | ( t & v & NOT(w) & x )
+            | ( q & v & w & NOT(x) ) | ( x & NOT(v) );
+   m = y;
+
+   value = PUT(a, 11) | PUT(b, 10) | PUT(c, 9) | PUT(d, 8) | PUT(e, 7)
+            | PUT(f, 6) | PUT(g, 5) | PUT(h, 4) | PUT(i, 3) | PUT(j, 2)
+            | PUT(k, 1) | PUT(m, 0);
+   return value;
+}
+
+ULong bcd_to_dpb( ULong chunk )
+{
+   Short a, b, c, d, e, f, g, h, i, j, k, m;
+   Short p, q, r, s, t, u, v, w, x, y;
+   ULong value;
+   /* Convert a 3 digit BCD value to a 10 bit Densely Packed Binary (DPD) value
+    The boolean equations to calculate the value of each of the DPD bit
+    is given in Appendix B  of Book 1: Power ISA User Instruction set.  The
+    bits for the DPD number are [abcdefghijkm].  The bits for the BCD value
+    are [pqrstuvwxy].  The boolean logic equations in psuedo C code are:
+    */
+   a = GET( chunk, 11 );
+   b = GET( chunk, 10 );
+   c = GET( chunk, 9 );
+   d = GET( chunk, 8 );
+   e = GET( chunk, 7 );
+   f = GET( chunk, 6 );
+   g = GET( chunk, 5 );
+   h = GET( chunk, 4 );
+   i = GET( chunk, 3 );
+   j = GET( chunk, 2 );
+   k = GET( chunk, 1 );
+   m = GET( chunk, 0 );
+
+   p = ( f & a & i & NOT(e) ) | ( j & a & NOT(i) ) | ( b & NOT(a) );
+   q = ( g & a & i & NOT(e) ) | ( k & a & NOT(i) ) | ( c & NOT(a) );
+   r = d;
+   s = ( j & NOT(a) & e & NOT(i) ) | ( f & NOT(i) & NOT(e) )
+            | ( f & NOT(a) & NOT(e) ) | ( e & i );
+   t = ( k & NOT(a) & e & NOT(i) ) | ( g & NOT(i) & NOT(e) )
+            | ( g & NOT(a) & NOT(e) ) | ( a & i );
+   u = h;
+   v = a | e | i;
+   w = ( NOT(e) & j & NOT(i) ) | ( e & i ) | a;
+   x = ( NOT(a) & k & NOT(i) ) | ( a & i ) | e;
+   y = m;
+
+   value = PUT(p, 9) | PUT(q, 8) | PUT(r, 7) | PUT(s, 6) | PUT(t, 5) 
+            | PUT(u, 4) | PUT(v, 3) | PUT(w, 2) | PUT(x, 1) | y;
+
+   return value;
+}
+
+ULong h_DPBtoBCD( ULong dpb )
+{
+   ULong result, chunk;
+   Int i;
+
+   result = 0;
+
+   for (i = 0; i < 5; i++) {
+      chunk = dpb >> ( 4 - i ) * 10;
+      result = result << 12;
+      result |= dpb_to_bcd( chunk & 0x3FF );
+   }
+   return result;
+}
+
+ULong h_BCDtoDPB( ULong bcd )
+{
+   ULong result, chunk;
+   Int i;
+
+   result = 0;
+
+   for (i = 0; i < 5; i++) {
+      chunk = bcd >> ( 4 - i ) * 12;
+      result = result << 10;
+      result |= bcd_to_dpb( chunk & 0xFFF );
+   }
+   return result;
+}
+#undef NOT
+#undef GET
+#undef PUT
 
 /*---------------------------------------------------------------*/
 /*--- end                               host_generic_simd64.c ---*/
 /*---------------------------------------------------------------*/
+
index 5b6640cdc872975d24bf189e4845839ac0d3ea11..1492ad00369418cc46bca21cc006b5c957eb499d 100644 (file)
@@ -156,6 +156,12 @@ extern UInt h_generic_calc_Sad8Ux4  ( UInt, UInt );
 extern UInt h_generic_calc_CmpNEZ16x2 ( UInt );
 extern UInt h_generic_calc_CmpNEZ8x4  ( UInt );
 
+extern ULong h_DPBtoBCD( ULong dpb );
+extern ULong h_BCDtoDPB( ULong bcd );
+
+ULong dpb_to_bcd(ULong chunk);  // helper for h_DPBtoBCD
+ULong bcd_to_dpb(ULong chunk);  // helper for h_BCDtoDPB
+
 #endif /* ndef __VEX_HOST_GENERIC_SIMD64_H */
 
 /*---------------------------------------------------------------*/
index 9cd0e52c10035da6b6965d35d8ce73bf8a87f482..3c273ddb4b21e97c3745dd1509359c652c9058e8 100644 (file)
@@ -42,6 +42,7 @@
 #include "main_util.h"
 #include "main_globals.h"
 #include "host_generic_regs.h"
+#include "host_generic_simd64.h"
 #include "host_ppc_defs.h"
 
 /* GPR register class for ppc32/64 */
@@ -2002,9 +2003,58 @@ static HReg iselWordExpr_R_wrk ( ISelEnv* env, IRExpr* e )
             add_to_sp( env, 16 );       // Reset SP
             return r_dst;
          } 
-
          break;
 
+      case Iop_BCDtoDPB: {
+         PPCCondCode cc;
+         UInt        argiregs;
+         HReg        argregs[1];
+         HReg        r_dst  = newVRegI(env);
+         Int         argreg;
+         HWord*      fdescr;
+
+         argiregs = 0;
+         argreg = 0;
+         argregs[0] = hregPPC_GPR3(mode64);
+
+         argiregs |= (1 << (argreg+3));
+         addInstr(env, mk_iMOVds_RR( argregs[argreg++],
+                                     iselWordExpr_R(env, e->Iex.Unop.arg) ) );
+
+         cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
+
+         fdescr = (HWord*)h_BCDtoDPB;
+         addInstr(env, PPCInstr_Call( cc, (Addr64)(fdescr[0]), argiregs ) );
+
+         addInstr(env, mk_iMOVds_RR(r_dst, argregs[0]));
+         return r_dst;
+      }
+
+      case Iop_DPBtoBCD: {
+         PPCCondCode cc;
+         UInt        argiregs;
+         HReg        argregs[1];
+         HReg        r_dst  = newVRegI(env);
+         Int         argreg;
+         HWord*      fdescr;
+
+         argiregs = 0;
+         argreg = 0;
+         argregs[0] = hregPPC_GPR3(mode64);
+
+         argiregs |= (1 << (argreg+3));
+         addInstr(env, mk_iMOVds_RR( argregs[argreg++],
+                                     iselWordExpr_R(env, e->Iex.Unop.arg) ) );
+
+         cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
+
+         fdescr = (HWord*)h_DPBtoBCD;
+         addInstr(env, PPCInstr_Call( cc, (Addr64)(fdescr[0]), argiregs ) );
+
+         addInstr(env, mk_iMOVds_RR(r_dst, argregs[0]));
+         return r_dst;
+      }
+
       default: 
          break;
       }
@@ -3154,10 +3204,10 @@ static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo,
       }
 
       case Iop_ReinterpD64asI64: {
-         HReg fr_src  = iselDfp64Expr(env, e->Iex.Unop.arg);
-         PPCAMode *am_addr0, *am_addr1;
-         HReg r_dstLo = newVRegI(env);
-         HReg r_dstHi = newVRegI(env);
+         HReg fr_src  = iselDfp64Expr(env, e->Iex.Unop.arg);
+         PPCAMode *am_addr0, *am_addr1;
+         HReg r_dstLo = newVRegI(env);
+         HReg r_dstHi = newVRegI(env);
 
 
          sub_from_sp( env, 16 );     // Move SP down 16 bytes
@@ -3167,7 +3217,7 @@ static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo,
          // store as D64
          addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
                                         fr_src, am_addr0 ));
-         
+
          // load hi,lo as Ity_I32's
          addInstr(env, PPCInstr_Load( 4, r_dstHi,
                                       am_addr0, False/*mode32*/ ));
@@ -3175,12 +3225,89 @@ static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo,
                                       am_addr1, False/*mode32*/ ));
          *rHi = r_dstHi;
          *rLo = r_dstLo;
-         
+
          add_to_sp( env, 16 );       // Reset SP
 
          return;
       }
 
+      case Iop_BCDtoDPB: {
+         PPCCondCode cc;
+         UInt        argiregs;
+         HReg        argregs[2];
+         Int         argreg;
+         HReg        tLo = newVRegI(env);
+         HReg        tHi = newVRegI(env);
+         HReg        tmpHi;
+         HReg        tmpLo;
+         ULong       target;
+         Bool        mode64 = env->mode64;
+
+         argregs[0] = hregPPC_GPR3(mode64);
+         argregs[1] = hregPPC_GPR4(mode64);
+
+         argiregs = 0;
+         argreg = 0;
+
+         iselInt64Expr( &tmpHi, &tmpLo, env, e->Iex.Unop.arg );
+
+         argiregs |= ( 1 << (argreg+3 ) );
+         addInstr( env, mk_iMOVds_RR( argregs[argreg++], tmpHi ) );
+
+         argiregs |= ( 1 << (argreg+3 ) );
+         addInstr( env, mk_iMOVds_RR( argregs[argreg], tmpLo ) );
+
+         cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
+         target = toUInt( Ptr_to_ULong(h_BCDtoDPB ) );
+
+         addInstr( env, PPCInstr_Call( cc, (Addr64)target, argiregs ) );
+         addInstr( env, mk_iMOVds_RR( tHi, argregs[argreg-1] ) );
+         addInstr( env, mk_iMOVds_RR( tLo, argregs[argreg] ) );
+
+         *rHi = tHi;
+         *rLo = tLo;
+         return;
+      }
+
+      case Iop_DPBtoBCD: {
+         PPCCondCode cc;
+         UInt        argiregs;
+         HReg        argregs[2];
+         Int         argreg;
+         HReg        tLo = newVRegI(env);
+         HReg        tHi = newVRegI(env);
+         HReg        tmpHi;
+         HReg        tmpLo;
+         ULong       target;
+         Bool        mode64 = env->mode64;
+
+         argregs[0] = hregPPC_GPR3(mode64);
+         argregs[1] = hregPPC_GPR4(mode64);
+
+         argiregs = 0;
+         argreg = 0;
+
+         iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Unop.arg);
+
+         argiregs |= (1 << (argreg+3));
+         addInstr(env, mk_iMOVds_RR( argregs[argreg++], tmpHi ));
+
+         argiregs |= (1 << (argreg+3));
+         addInstr(env, mk_iMOVds_RR( argregs[argreg], tmpLo));
+
+         cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
+
+         target = toUInt( Ptr_to_ULong( h_DPBtoBCD ) );
+
+         addInstr(env, PPCInstr_Call( cc, (Addr64)target, argiregs ) );
+         addInstr(env, mk_iMOVds_RR(tHi, argregs[argreg-1]));
+         addInstr(env, mk_iMOVds_RR(tLo, argregs[argreg]));
+
+         *rHi = tHi;
+         *rLo = tLo;
+         return;
+      }
+
       default:
          break;
       }
@@ -4089,7 +4216,7 @@ static void iselDfp128Expr_wrk(HReg* rHi, HReg *rLo, ISelEnv* env, IRExpr* e)
          HReg r_dstLo = newVRegF(env);
          HReg r_srcHi = newVRegF(env);
          HReg r_srcLo = newVRegF(env);
-         PPCRI* rmc = iselWordExpr_RI(env, e->Iex.Binop.arg1);
+         PPCRI* rmc = iselWordExpr_RI(env, triop->arg1);
 
          /* dst will be used to pass in the left operand and get the result */
          iselDfp128Expr(&r_dstHi, &r_dstLo, env, triop->arg2);
index ea7fe5d4e1f81f2eb030078c1ba3bf51c687919d..050dfe9faeff631c4f26b1cbfbc5c7f29d47c688 100644 (file)
@@ -982,6 +982,8 @@ void ppIROp ( IROp op )
       case Iop_V256to64_2: vex_printf("V256to64_2"); return;
       case Iop_V256to64_3: vex_printf("V256to64_3"); return;
       case Iop_64x4toV256: vex_printf("64x4toV256"); return;
+      case Iop_DPBtoBCD: vex_printf("Iop_DPBtoBCD"); return;
+      case Iop_BCDtoDPB: vex_printf("Iop_BCDtoDPB"); return;
       default: vpanic("ppIROp(1)");
    }
 
@@ -2716,6 +2718,10 @@ void typeOfPrimop ( IROp op,
       case Iop_I64StoD128:    /* I64 bit pattern stored in Float register */
          UNARY(Ity_D64, Ity_D128);
 
+      case Iop_DPBtoBCD:
+      case Iop_BCDtoDPB:
+         UNARY(Ity_I64, Ity_I64);
+
       case Iop_D128HItoD64:
       case Iop_D128LOtoD64:
          UNARY(Ity_D128, Ity_D64);
index 74a21ec0fc79fc46ea8e7686f5129dc0b86a789e..0f82703ac7f4e381a9120c7bba3f5e3886c2d927 100644 (file)
@@ -1105,6 +1105,16 @@ typedef
       /* Support for 128-bit DFP type */
       Iop_D64HLtoD128, Iop_D128HItoD64, Iop_D128LOtoD64,
 
+      /*  I64 -> I64  
+       *     Convert 50-bit densely packed BCD string to 60 bit BCD string
+       */
+      Iop_DPBtoBCD,
+
+      /* I64 -> I64
+       *     Convert 60 bit BCD string to 50-bit densely packed BCD string
+       */
+      Iop_BCDtoDPB,
+
       /* Conversion I64 -> D64 */
       Iop_ReinterpI64asD64,