Cleaned up and filled out:
Added some clean helper functions to calculate CR0 and XER flags
Made a start on add and branch ops (mostly to get a feel, will prob have
to redo)
git-svn-id: svn://svn.valgrind.org/vex/trunk@755 8f6e269a-dfd6-0310-a8e1-e2731360e62c
diff --git a/priv/guest-ppc32/gdefs.h b/priv/guest-ppc32/gdefs.h
index 83c9872..0c32489 100644
--- a/priv/guest-ppc32/gdefs.h
+++ b/priv/guest-ppc32/gdefs.h
@@ -74,8 +74,18 @@
/* --- CLEAN HELPERS --- */
-// Calculate CR0[0,1,2] (neg,pos,zero) from result
-extern UInt ppc32g_calculate_flags_cr0 ( UInt result );
+// Calculate CR0 flags
+extern UInt ppc32g_calculate_cr0_all ( UChar op, UInt word1, UInt word2 );
+extern UInt ppc32g_calculate_cr0_bit0 ( UChar op, UInt word1, UInt word2 );
+extern UInt ppc32g_calculate_cr0_bit1 ( UChar op, UInt word1, UInt word2 );
+extern UInt ppc32g_calculate_cr0_bit2 ( UChar op, UInt word1, UInt word2 );
+extern UInt ppc32g_calculate_cr0_bit3 ( UChar op, UInt word1, UInt word2 );
+
+// Calculate XER flags
+extern UInt ppc32g_calculate_xer_ov ( UInt theInstr, UInt Ra, UInt Rb, UInt Rd, UChar ov );
+extern UInt ppc32g_calculate_xer_ca ( UInt theInstr, UInt Ra, UInt Rb, UInt Rd, UChar ca );
+
+
diff --git a/priv/guest-ppc32/ghelpers.c b/priv/guest-ppc32/ghelpers.c
index 7cf7d75..f50f728 100644
--- a/priv/guest-ppc32/ghelpers.c
+++ b/priv/guest-ppc32/ghelpers.c
@@ -59,12 +59,109 @@
/* CALLED FROM GENERATED CODE: CLEAN HELPER */
-/* Calculate all the 4 flags from the supplied thunk parameters. */
-UInt ppc32g_calculate_flags_cr0 ( UInt result )
+/* Calculates CR0[LT,GT,EQ,SO] flags from the supplied
+ thunk parameters. */
+UInt ppc32g_calculate_cr0_all ( UChar op, UInt word1, UInt word2 )
{
+ Int sword1 = (Int)word1;
+ if (op) {
+ return (word1 & 0xF0000000);
+ } else {
+ return
+ ((word2 & 1) << 3)
+ | (((sword1 == 0) ? 1:0) << 2)
+ | (((sword1 > 0) ? 1:0) << 1)
+ | (((sword1 < 0) ? 1:0) << 0);
+ }
+}
+
+UInt ppc32g_calculate_cr0_bit0 ( UChar op, UInt word1, UInt word2 )
+{
+ return (ppc32g_calculate_cr0_all(op,word1,word2) >> 0) & 1;
+}
+
+UInt ppc32g_calculate_cr0_bit1 ( UChar op, UInt word1, UInt word2 )
+{
+ return (ppc32g_calculate_cr0_all(op,word1,word2) >> 1) & 1;
+}
+
+UInt ppc32g_calculate_cr0_bit2 ( UChar op, UInt word1, UInt word2 )
+{
+ return (ppc32g_calculate_cr0_all(op,word1,word2) >> 2) & 1;
+}
+
+UInt ppc32g_calculate_cr0_bit3 ( UChar op, UInt word1, UInt word2 )
+{
+ return (ppc32g_calculate_cr0_all(op,word1,word2) >> 3) & 1;
+}
+
+
+
+
+
+
+// Calculate XER_OV
+UInt ppc32g_calculate_xer_ov ( UInt theInstr, UInt Ra, UInt Rb, UInt Rd, UChar ov )
+{
+ UChar opc1 = (theInstr >> 26) & 0x3F; /* opcode1: theInstr[0:5] */
+ UInt opc2 = (theInstr >> 1) & 0x1FF; /* opcode2: theInstr[22:30] */
+
+ switch (opc1) {
+ case 0x1F:
+ switch (opc2) {
+ case 0x10A: // addo
+ // i.e. ((both_same_sign) & (sign_changed) & (sign_mask))
+ return ((Ra^Rb^-1) & (Ra^Rd) & (1<<31)) ? 1:0;
+
+ case 0x00A: // addc
+ return ((Ra^Rb^-1) & (Ra^Rd) & (1<<31)) ? 1:0;
+
+ case 0x08A: // addeo
+ return ((Ra^Rb^-1) & (Ra^Rd) & (1<<31)) ? 1:0;
+
+ default:
+ break;
+ }
+
+ default:
+ break;
+ }
+
return 0;
}
+// Calculate XER_CA
+UInt ppc32g_calculate_xer_ca ( UInt theInstr, UInt Ra, UInt Rb, UInt Rd, UChar ca )
+{
+ UChar opc1 = (theInstr >> 26) & 0x3F; /* opcode1: theInstr[0:5] */
+ UInt opc2 = (theInstr >> 1) & 0x1FF; /* opcode2: theInstr[22:30] */
+
+ switch (opc1) {
+ case 0x0D: // addic
+ case 0x0E: // addic.
+ return (Rd < Ra) ? 1:0;
+
+ case 0x1F:
+ switch (opc2) {
+ case 0x00A: // addc
+ return (Rd < Ra) ? 1:0;
+
+ case 0x08A: // adde
+ return (Rd < Ra || (ca==1 && Rd==Ra)) ? 1:0;
+
+ default:
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+
+
@@ -104,10 +201,11 @@
/* VISIBLE TO LIBVEX CLIENT */
UInt LibVEX_GuestPPC32_get_flags ( /*IN*/VexGuestPPC32State* vex_state )
{
- UInt flags;
- vassert(0); // FIXME
-
- flags = ppc32g_calculate_flags_cr0( vex_state->guest_Result );
+ UInt flags = ppc32g_calculate_cr0_all(
+ vex_state->guest_CC_OP,
+ vex_state->guest_CC_DEP1,
+ vex_state->guest_CC_DEP2
+ );
return flags;
}
@@ -148,17 +246,14 @@
vex_state->guest_GPR31 = 0;
vex_state->guest_CIA = 0;
- vex_state->guest_LR = 0;
- vex_state->guest_CTR = 0;
+ vex_state->guest_LR = 0;
+ vex_state->guest_CTR = 0;
- vex_state->guest_Result = 0;
+ vex_state->guest_CC_OP = 0;
+ vex_state->guest_CC_DEP1 = 0;
+ vex_state->guest_CC_DEP2 = 0;
- vex_state->guest_CR2 = 0;
- vex_state->guest_CR3 = 0;
- vex_state->guest_CR4 = 0;
- vex_state->guest_CR5 = 0;
- vex_state->guest_CR6 = 0;
- vex_state->guest_CR7 = 0;
+ vex_state->guest_CR2_7 = 0;
vex_state->guest_XER_SO = 0;
vex_state->guest_XER_OV = 0;
@@ -209,7 +304,7 @@
/* flags thunk: only using last_result, which is always defd. */
.alwaysDefd
- = { /* 0 */ ALWAYSDEFD(guest_Result)
+ = { /* 0 */ ALWAYSDEFD(guest_CC_OP)
}
};
diff --git a/priv/guest-ppc32/toIR.c b/priv/guest-ppc32/toIR.c
index cb15068..cb9d7cc 100644
--- a/priv/guest-ppc32/toIR.c
+++ b/priv/guest-ppc32/toIR.c
@@ -122,7 +122,21 @@
#define OFFB_GPR30 offsetof(VexGuestPPC32State,guest_GPR30)
#define OFFB_GPR31 offsetof(VexGuestPPC32State,guest_GPR31)
-#define OFFB_RESULT offsetof(VexGuestPPC32State,guest_Result)
+#define OFFB_CIA offsetof(VexGuestPPC32State,guest_CIA)
+#define OFFB_LR offsetof(VexGuestPPC32State,guest_LR)
+#define OFFB_CTR offsetof(VexGuestPPC32State,guest_CTR)
+
+#define OFFB_CC_OP offsetof(VexGuestPPC32State,guest_CC_OP)
+#define OFFB_CC_DEP1 offsetof(VexGuestPPC32State,guest_CC_DEP1)
+#define OFFB_CC_DEP2 offsetof(VexGuestPPC32State,guest_CC_DEP2)
+
+#define OFFB_CR2_7 offsetof(VexGuestPPC32State,guest_CR2_7)
+
+#define OFFB_XER_SO offsetof(VexGuestPPC32State,guest_XER_SO)
+#define OFFB_XER_OV offsetof(VexGuestPPC32State,guest_XER_OV)
+#define OFFB_XER_CA offsetof(VexGuestPPC32State,guest_XER_CA)
+
+
/*------------------------------------------------------------*/
@@ -298,14 +312,12 @@
addStmtToIRBB( irbb, st );
}
-#if 0
/* Generate a new temporary of the given type. */
static IRTemp newTemp ( IRType ty )
{
vassert(isPlausibleType(ty));
return newIRTemp( irbb->tyenv, ty );
}
-#endif
#if 0
/* Bomb out if we can't handle something. */
@@ -324,102 +336,24 @@
{
return (UInt)((((Int)x) << 24) >> 24);
}
+#endif
+
+#if 0
+static UInt extend_s_14to32 ( UInt x )
+{
+ return (UInt)((((Int)x) << 14) >> 14);
+}
+#endif
static UInt extend_s_16to32 ( UInt x )
{
return (UInt)((((Int)x) << 16) >> 16);
}
-#endif
-#if 0
static UInt extend_s_24to32 ( UInt x )
{
return (UInt)((((Int)x) << 8) >> 8);
}
-#endif
-
-#if 0
-/* Fetch a byte from the guest insn stream. */
-static UChar getIByte ( UInt delta )
-{
- return guest_code[delta];
-}
-#endif
-
-/* Get a 8/16/32-bit unsigned value out of the insn stream. */
-
-#if 0
-static UInt getUChar ( UInt delta )
-{
- UInt v = guest_code[delta+0];
- return v & 0xFF;
-}
-#endif
-
-#if 0
-static UInt getUDisp16 ( UInt delta )
-{
- UInt v = guest_code[delta+1]; v <<= 8;
- v |= guest_code[delta+0];
- return v & 0xFFFF;
-}
-#endif
-
-#if 0
-static UInt getUDisp32 ( UInt delta )
-{
- UInt v = guest_code[delta+3]; v <<= 8;
- v |= guest_code[delta+2]; v <<= 8;
- v |= guest_code[delta+1]; v <<= 8;
- v |= guest_code[delta+0];
- return v;
-}
-#endif
-
-#if 0
-static UInt getUDisp ( Int size, UInt delta )
-{
- switch (size) {
- case 4: return getUDisp32(delta);
- case 2: return getUDisp16(delta);
- case 1: return getUChar(delta);
- default: vpanic("getUDisp(PPC32)");
- }
- return 0; /*notreached*/
-}
-#endif
-
-#if 0
-/* Get a byte value out of the insn stream and sign-extend to 32
- bits. */
-static UInt getSDisp8 ( UInt delta )
-{
- return extend_s_8to32( (UInt) (guest_code[delta]) );
-}
-#endif
-
-#if 0
-static UInt getSDisp16 ( UInt delta0 )
-{
- UChar* eip = (UChar*)(&guest_code[delta0]);
- UInt d = *eip++;
- d |= ((*eip++) << 8);
- return extend_s_16to32(d);
-}
-#endif
-
-#if 0
-static UInt getSDisp ( Int size, UInt delta )
-{
- switch (size) {
- case 4: return getUDisp32(delta);
- case 2: return getSDisp16(delta);
- case 1: return getSDisp8(delta);
- default: vpanic("getSDisp(PPC32)");
- }
- return 0; /*notreached*/
-}
-#endif
/*------------------------------------------------------------*/
@@ -443,7 +377,7 @@
}
#endif
-#if 0
+
static Int integerGuestRegOffset ( UInt archreg )
{
vassert(archreg < 32);
@@ -488,9 +422,7 @@
vpanic("integerGuestRegOffset(ppc32,le)"); /*notreached*/
}
-#endif
-#if 0
static IRExpr* getIReg ( UInt archreg )
{
vassert(archreg < 32);
@@ -509,6 +441,7 @@
stmt( IRStmt_Tmp(dst, e) );
}
+#if 0
static void storeLE ( IRExpr* addr, IRExpr* data )
{
stmt( IRStmt_STle(addr,data) );
@@ -518,6 +451,7 @@
{
return IRExpr_Unop(op, a);
}
+#endif
static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
{
@@ -534,7 +468,6 @@
vassert(i < 256);
return IRExpr_Const(IRConst_U8(i));
}
-#endif
#if 0
static IRExpr* mkU16 ( UInt i )
@@ -619,34 +552,145 @@
/* -------------- Evaluating the flags-thunk. -------------- */
-#if 0
-static IRExpr* mk_ppc32g_calculate_flags_cr0 ( void )
+static IRExpr** get_ppc32g_cr0_args ( void )
{
- IRExpr** args
- = mkIRExprVec_1( IRExpr_Get(OFFB_RESULT, Ity_I32) );
+ return mkIRExprVec_3( IRExpr_Get(OFFB_CC_OP, Ity_I8),
+ IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
+ IRExpr_Get(OFFB_CC_DEP2, Ity_I32) );
+}
+static IRExpr* mk_ppc32g_calculate_cr0_all ( void )
+{
IRExpr* call
= mkIRExprCCall(
Ity_I32,
- 0/*regpppc32*/,
- "ppc32g_calculate_flags_all", &ppc32g_calculate_flags_all,
- args
+ 0/*regparm*/,
+ "ppc32g_calculate_cr0_all", &ppc32g_calculate_cr0_all,
+ get_ppc32g_cr0_args()
);
/* Exclude OP from definedness checking. We're only
interested in DEP1 and DEP2. */
- call->Iex.CCall.cee->mcx_mask = 1;
+// call->Iex.CCall.cee->mcx_mask = 1;
+
+// CAB: Haven't looked at the whole 'definedness' stuff...
+
+ return call;
+}
+
+#if 0
+static IRExpr* mk_ppc32g_calculate_cr0_bit0 ( void )
+{
+ IRExpr* call
+ = mkIRExprCCall(
+ Ity_I32,
+ 0/*regparm*/,
+ "ppc32g_calculate_cr0_bit0", &ppc32g_calculate_cr0_bit0,
+ get_ppc32g_cr0_args()
+ );
+ return call;
+}
+
+static IRExpr* mk_ppc32g_calculate_cr0_bit1 ( void )
+{
+ IRExpr* call
+ = mkIRExprCCall(
+ Ity_I32,
+ 0/*regparm*/,
+ "ppc32g_calculate_cr0_bit1", &ppc32g_calculate_cr0_bit1,
+ get_ppc32g_cr0_args()
+ );
+ return call;
+}
+
+static IRExpr* mk_ppc32g_calculate_cr0_bit2 ( void )
+{
+ IRExpr* call
+ = mkIRExprCCall(
+ Ity_I32,
+ 0/*regparm*/,
+ "ppc32g_calculate_cr0_bit2", &ppc32g_calculate_cr0_bit2,
+ get_ppc32g_cr0_args()
+ );
+ return call;
+}
+
+static IRExpr* mk_ppc32g_calculate_cr0_bit3 ( void )
+{
+ IRExpr* call
+ = mkIRExprCCall(
+ Ity_I32,
+ 0/*regparm*/,
+ "ppc32g_calculate_cr0_bit3", &ppc32g_calculate_cr0_bit3,
+ get_ppc32g_cr0_args()
+ );
return call;
}
#endif
+// Calculate XER_OV flag
+static IRExpr* mk_ppc32g_calculate_xer_ov ( UInt theInstr, IRTemp Ra,
+ IRTemp Rb, IRTemp Rd )
+{
+ IRExpr** args =
+ mkIRExprVec_5(
+ mkU32(theInstr), mkexpr(Ra), mkexpr(Rb), mkexpr(Rd),
+ IRExpr_Get(OFFB_XER_OV, Ity_I8) );
+
+ IRExpr* call
+ = mkIRExprCCall(
+ Ity_I32,
+ 0/*regparm*/,
+ "ppc32g_calculate_xer_ov", &ppc32g_calculate_xer_ov,
+ args
+ );
+ return call;
+}
+
+// Calculate XER_CA flag
+static IRExpr* mk_ppc32g_calculate_xer_ca ( UInt theInstr, IRTemp Ra,
+ IRTemp Rb, IRTemp Rd )
+{
+ IRExpr** args =
+ mkIRExprVec_5(
+ mkU32(theInstr), mkexpr(Ra), mkexpr(Rb), mkexpr(Rd),
+ IRExpr_Get(OFFB_XER_CA, Ity_I8) );
+
+ IRExpr* call
+ = mkIRExprCCall(
+ Ity_I32,
+ 0/*regparm*/,
+ "ppc32g_calculate_xer_ca", &ppc32g_calculate_xer_ca,
+ args
+ );
+ return call;
+}
+
+
+
+// Helper to set XER_OV,SO flags
+static void mk_ppc32g_set_xer_ov_so( UInt theInstr, IRTemp Ra, IRTemp Rb, IRTemp Rd )
+{
+ IRTemp ir_tmp = newTemp(Ity_I32);
+ assign( ir_tmp, mk_ppc32g_calculate_xer_ov( theInstr, Ra, Rb, Rd ) );
+ stmt( IRStmt_Put( OFFB_XER_OV, mkexpr(ir_tmp) ));
+ stmt( IRStmt_Put( OFFB_XER_SO, mkexpr(ir_tmp) ));
+}
+
+// Helper to set XER_CA flag
+static void mk_ppc32g_set_xer_ca( UInt theInstr, IRTemp Ra, IRTemp Rb, IRTemp Rd )
+{
+ stmt( IRStmt_Put( OFFB_XER_CA,
+ mk_ppc32g_calculate_xer_ca( theInstr, Ra, Rb, Rd ) ) );
+}
-#if 0
+
+
/* -------------- Building the flags-thunk. -------------- */
@@ -654,6 +698,8 @@
flag-setting operation. Hence the various setFlags_* functions.
*/
+#if 0
+
/* U-widen 8/16/32 bit int expr to 32. */
static IRExpr* widenUto32 ( IRExpr* e )
{
@@ -685,34 +731,26 @@
vpanic("narrowTo(PPC32)");
}
+#endif
-/* Set the flags thunk OP, DEP1 and DEP2 fields. The supplied op is
- auto-sized up to the real op. */
+/* Set the flags thunk OP, DEP1, DEP2 fields. */
static
-void setFlags_DEP1_DEP2 ( IRTemp result )
+void setFlags_CR0_Result ( IRTemp result )
{
- stmt( IRStmt_Put( OFFB_RESULT, mkU32(result)) );
+ stmt( IRStmt_Put( OFFB_CC_OP, mkU8(0)) );
+ stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(result)) );
+ stmt( IRStmt_Put( OFFB_CC_DEP2, IRExpr_Get(OFFB_XER_SO, Ity_I32) ) );
}
-#endif
-
-
-
-
-
-
-
-
-/* -------------- Condition codes. -------------- */
-
-#if 0
-/* Condition codes, using the PPC32 encoding. */
-static HChar* name_PPC32Condcode ( PPC32Condcode cond )
+#if 0 // Used by 'stwcx.' only, methinks...
+/* Set the flags thunk OP, DEP1 fields, write 0 to DEP2. */
+static
+void setFlags_CR0_Flags ( IRTemp flags_cr0 )
{
- switch (cond) {
- default: vpanic("name_PPC32Condcode");
- }
+ stmt( IRStmt_Put( OFFB_CC_OP, mkU8(1)) );
+ stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(flags_cr0)) );
+ stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0)) );
}
#endif
@@ -728,6 +766,283 @@
+/*
+ Integer Arithmetic Instructions
+*/
+static Bool dis_int_arith ( UInt theInstr, UChar form )
+{
+ UChar opc1 = (theInstr) & 0x3F; /* opcode1: theInstr[0:5] */
+ UChar Rd_addr = (theInstr >> 6 ) & 0x1F; /* reg D: theInstr[6:10] */
+ UChar Ra_addr = (theInstr >> 11) & 0x1F; /* reg A: theInstr[11:15] */
+ UInt SIMM_16 = (theInstr >> 16) & 0xFFFF; /* SIMM: theInstr[16:31] */
+
+ UChar Rb_addr = (theInstr >> 16) & 0x1F; /* reg B: theInstr[16:20] */
+ UChar flag_OE = (theInstr >> 21) & 1; /* OE: theInstr[21] */
+ UInt opc2 = (theInstr >> 22) & 0x1FF; /* opcode2: theInstr[22:30] */
+ UChar flag_Rc = (theInstr >> 31) & 1; /* Rc: theInstr[31] */
+
+ UInt EXTS_SIMM = 0;
+
+ IRTemp Ra = newTemp(Ity_I32);
+ IRTemp Rb = newTemp(Ity_I32);
+ IRTemp Rd = newTemp(Ity_I32);
+ IRTemp tmp = newTemp(Ity_I32);
+
+ assign( Ra, getIReg(Ra_addr) );
+
+ if (form == 0) { // D-Form: rA, rD, EXTS(SIMM)
+ EXTS_SIMM = extend_s_16to32(SIMM_16);
+ } else { // XO-Form: rA, rB, rD
+ assign( Rb, getIReg(Rb_addr) );
+ }
+
+ switch (opc1) {
+
+ /* D-Form */
+ case 0x0C: // addi (Add Immediate)
+ if ( Ra_addr == 0 ) {
+ assign( Rd, mkU32(EXTS_SIMM) );
+ } else {
+ assign( Rd, binop( Iop_Add32, mkexpr(Ra), mkU32(EXTS_SIMM) ) );
+ }
+ break;
+
+ case 0x0D: // addic (Add Immediate Carrying)
+ assign( Rd, binop( Iop_Add32, mkexpr(Ra), mkU32(EXTS_SIMM) ) );
+ mk_ppc32g_set_xer_ca( theInstr, Ra, Rb, Rd );
+ break;
+
+ case 0x0E: // addic. (Add Immediate Carrying and Record)
+ assign( Rd, binop( Iop_Add32, mkexpr(Ra), mkU32(EXTS_SIMM) ) );
+ mk_ppc32g_set_xer_ca( theInstr, Ra, Rb, Rd );
+ setFlags_CR0_Result( Rd );
+ break;
+
+ case 0x0F: // addis (Add Immediate Shifted)
+ if ( Ra_addr == 0 ) {
+ assign( Rd, mkU32(EXTS_SIMM << 16) );
+ } else {
+ assign( Rd, binop( Iop_Add32, mkexpr(Ra), mkU32(EXTS_SIMM << 16) ) );
+ }
+ break;
+
+
+ /* XO-Form */
+ case 0x1F:
+ switch (opc2) {
+ case 0x10A: // add (Add)
+ assign( Rd, binop(Iop_Add32, mkexpr(Ra), mkexpr(Rb)) );
+ if (flag_Rc) { setFlags_CR0_Result( Rd ); }
+ if (flag_OE) { mk_ppc32g_set_xer_ov_so( theInstr, Ra, Rb, Rd ); }
+ break;
+
+ case 0x00A: // addc (Add Carrying)
+ assign( Rd, binop(Iop_Add32, mkexpr(Ra), mkexpr(Rb)) );
+ if (flag_Rc) { setFlags_CR0_Result( Rd ); }
+ mk_ppc32g_set_xer_ca( theInstr, Ra, Rb, Rd );
+ if (flag_OE) { mk_ppc32g_set_xer_ov_so( theInstr, Ra, Rb, Rd ); }
+ break;
+
+ case 0x08A: // adde (Add Extended)
+ // rD = rA + rB + XER[CA]
+ assign( tmp, IRExpr_Get(OFFB_XER_CA, Ity_I32) );
+ assign( Rd, binop(Iop_Add32,
+ binop(Iop_Add32, mkexpr(Ra), mkexpr(Rb)),
+ mkexpr(tmp)) );
+
+ if (flag_Rc) { setFlags_CR0_Result( Rd ); }
+ mk_ppc32g_set_xer_ca( theInstr, Ra, Rb, Rd );
+ if (flag_OE) { mk_ppc32g_set_xer_ov_so( theInstr, Ra, Rb, Rd ); }
+ break;
+
+ case 0x0EA: // addme (Add to Minus One Extended)
+ // B=0
+ // rD = rA + XER[CA] - 1 (-1 == 0xFFFF_FFFF_FFFF_FFFF)
+ // if (Rc=1) { set guest_result }
+ // set XER[CA]
+ // if (OE=1) { XER[SO,OV] }
+ return False;
+
+ case 0x0CA: // addze (Add to Zero Extended)
+ // B=0
+ // rD = rA + XER[CA]
+ // if (Rc=1) { set guest_result }
+ // set XER[CA]
+ // if (OE=1) { XER[SO,OV] }
+ return False;
+
+ default:
+ return False;
+ }
+ break;
+ default:
+ return False;
+ }
+
+ putIReg( Rd_addr, mkexpr(Rd) );
+
+ return False; // True...
+}
+
+
+
+static Bool dis_branch ( theInstr )
+{
+ UChar opc1 = (theInstr) & 0x3F; /* opcode1: theInstr[0:5] */
+ UChar BO = (theInstr >> 6 ) & 0x1F; /* BO: theInstr[6:10] */
+ UChar BI = (theInstr >> 11) & 0x1F; /* BI: theInstr[11:15] */
+ UInt BD = (theInstr >> 16) & 0x3FFF; /* BD: theInstr[16:29] */
+ UChar ins16_20 = (theInstr >> 16) & 0x1F; /* zeros: theInstr[16:20] */
+ UChar opc2 = (theInstr >> 21) & 0x3F; /* opcode2: theInstr[21:30] */
+ UInt LI = (theInstr >> 6 ) & 0xFFFFFF; /* LI: theInstr[6:29] */
+ UChar flag_AA = (theInstr >> 30) & 1; /* AA: theInstr[30] */
+ UChar flag_LK = (theInstr >> 31) & 1; /* LK: theInstr[31] */
+
+ IRTemp ctr = newTemp(Ity_I32);
+ IRTemp cia = newTemp(Ity_I32);
+ IRTemp lr = newTemp(Ity_I32);
+ IRTemp nia = newTemp(Ity_I32);
+ IRTemp ctr_ok = newTemp(Ity_I32);
+ IRTemp cond_ok = newTemp(Ity_I32);
+ IRTemp cr_bi = newTemp(Ity_I32);
+ IRTemp tmp = newTemp(Ity_I32);
+// IRTemp tmp2 = newTemp(Ity_I32);
+
+ assign( ctr, IRExpr_Get(OFFB_CTR, Ity_I32) );
+ assign( cia, IRExpr_Get(OFFB_CIA, Ity_I32) );
+
+ assign( lr, binop(Iop_Add32, mkexpr(cia), mkU32(4)) );
+
+
+ switch (opc1) {
+ case 0x12: // b (Branch)
+ assign( tmp, mkU32(extend_s_24to32(LI << 2)) );
+ if (flag_AA) {
+ assign( nia, mkexpr(tmp) );
+ } else {
+ assign( nia, binop( Iop_Add32, mkexpr(cia), mkexpr(tmp) ));
+ }
+ if (flag_LK) {
+ stmt( IRStmt_Put( OFFB_LR, mkexpr(lr) ));
+ }
+
+ irbb->jumpkind = flag_LK ? Ijk_Call : Ijk_Boring;
+ irbb->next = mkexpr(nia);
+
+ DIP("b%s%s 0x%x\n", flag_LK ? "l" : "", flag_AA ? "a" : "", LI);
+ break;
+
+ case 0x10: // bc (Branch Conditional)
+
+ // Need to assert any of the bits of B0 ?
+
+ if (!((BO>>2)&1)) {
+ assign( ctr, binop( Iop_Sub32, mkexpr(ctr), mkU32(1) ) );
+ stmt( IRStmt_Put( OFFB_CTR, mkexpr(ctr)) );
+ }
+
+ // ctr_ok = BO[2] | ((CTR[31] != 0) ^ BO[3])
+ assign( ctr_ok,
+ binop( Iop_Or32, mkexpr((BO>>2)&1),
+ binop( Iop_Xor32, mkU32((BO>>3)&1),
+ binop( Iop_CmpNE32, mkU32(0),
+ binop( Iop_And32,
+ mkexpr(ctr),
+ mkU32(1<<31) )))));
+
+ // cond_ok = BO[0] | (CR[BI] == BO[1])
+ if (BI < 4) { // Get CR[BI] from guest_state
+ assign( cr_bi, binop(Iop_And32, mkU32(1),
+ binop(Iop_Shr32,
+ mk_ppc32g_calculate_cr0_all(),
+ mkU32(BI))) );
+ } else {
+ assign( cr_bi, binop(Iop_And32, mkU32(1),
+ binop(Iop_Shr32,
+ IRExpr_Get(OFFB_CR2_7, Ity_I32),
+ mkU32(BI))) );
+ }
+ assign( cond_ok, binop( Iop_Or32, mkexpr(BO & 1),
+ binop( Iop_CmpEQ8, mkexpr(cr_bi),
+ mkU32((BO>>1)&1) )));
+
+ // CAB: umm... querying guest state to set irbb->... how to do this?
+
+/*
+ assign( tmp, binop(Iop_And32, mkexpr(ctr_ok), mkexpr(cond_ok)) );
+ if (tmp) {
+ assign( tmp2, mkU32(extend_s_24to32(BD << 2)) );
+ if (flag_AA) {
+ assign( nia, mkexpr(tmp2) );
+ } else {
+ assign( nia, binop(Iop_Add32, mkexpr(cia), mkexpr(tmp2)) );
+ }
+ if (flag_LK) {
+ stmt( IRStmt_Put( OFFB_LR, mkexpr(lr) ));
+ }
+
+ irbb->jumpkind = flag_LK ? Ijk_Call : Ijk_Boring;
+ irbb->next = mkexpr(nia);
+ }
+*/
+
+ DIP("bc%s%s 0x%x, 0x%x, 0x%x\n",
+ flag_LK ? "l" : "", flag_AA ? "a" : "", BO, BI, BD);
+ return False;
+
+ case 0x13:
+ switch (opc2) {
+ case 0x210: // bcctr (Branch Conditional to Count Register)
+ vassert(ins16_20==0);
+/*
+ cond_ok = BO[0] | (CR[BI] == BO[1])
+ if (cond_ok) {
+ NIA = CTR[0-61] || 0b00
+ if (flag_LK) {
+ LR = CIA + 4
+ }
+ }
+*/
+ DIP("bcctr%s 0x%x, 0x%x,\n", flag_LK ? "l" : "", BO, BI);
+ return False;
+
+ case 0x010: // bclr (Branch Conditional to Link Register)
+ vassert(ins16_20==0);
+/*
+ if (!BO[2]) {
+ CTR -= 1
+ }
+ ctr_ok = BO[2] | ((CTR[31] == 0) ^ BO[3])
+ cond_ok = BO[0] | (CR[BI] a BO[1])
+ if (ctr_ok & cond_ok) {
+ NIA = LR[0-61] || 0b00
+ if (flag_LK) {
+ LR = CIA + 4
+ }
+*/
+ DIP("bclr%s 0x%x, 0x%x,\n", flag_LK ? "l" : "", BO, BI);
+ return False;
+
+ default:
+ return False;
+ }
+ break;
+ default:
+ return False;
+ }
+
+ return True;
+}
+
+
+
+
+
+
+
+
+
+
/*------------------------------------------------------------*/
/*--- Disassemble a single instruction ---*/
/*------------------------------------------------------------*/
@@ -745,14 +1060,14 @@
/*OUT*/ UInt* size,
/*OUT*/ Addr64* whereNext )
{
- // IRType ty;
- // IRTemp addr, t1, t2;
- // Int alen;
- UChar opc;
+// IRType ty;
+// IRTemp addr, t1, t2;
+// Int alen;
+ UChar opc1, opc2;
// PPC32Condcode cond;
- // UInt d32;
- // UChar dis_buf[50];
- // Int am_sz, d_sz;
+// UInt d32;
+// UChar dis_buf[50];
+// Int am_sz, d_sz;
DisResult whatNext = Dis_Continue;
UInt theInstr;
@@ -779,7 +1094,7 @@
/* Spot the client-request magic sequence. */
// Essentially a v. unlikely sequence of noops that we can catch
{
- UInt* code = (UInt*)(guest_code + delta);
+// UInt* code = (UInt*)(guest_code + delta);
// CAB: easy way to rotate left?
@@ -793,14 +1108,16 @@
*/
/* I suspect these will have to be turned the other way round to
work on little-endian ppc32. */
- if (code[0] == 0xE1A00EE0 &&
+ if (0){
+/*
+ code[0] == 0xE1A00EE0 &&
code[1] == 0xE1A001E0 &&
code[2] == 0xE1A00DE0 &&
code[3] == 0xE1A002E0 &&
code[4] == 0xE1A006E0 &&
code[5] == 0xE1A009E0) {
-
- // uh ... I'll figure this out later. possibly r0 = client_request(r0) */
+*/
+ // uh ... I'll figure this out later. possibly r0 = client_request(r0)
DIP("?CAB? = client_request ( ?CAB? )\n");
*size = 24;
@@ -817,15 +1134,60 @@
- opc = 0;//(theInstr >> 20) & 0xFF; /* opcode1: bits 27:20 */
-// vex_printf("disInstr(ppc32): opcode: 0x%2x, %,09b\n", opc, opc );
+ opc1 = (theInstr) & 0x3F; /* opcode1: [0:5] */
+ opc2 = (theInstr >> 21) & 0x3FF; /* opcode2: [21:30] */
+// vex_printf("disInstr(ppc): opcode1: 0x%2x, %,09b\n", opc1, opc1 );
+// vex_printf("disInstr(ppc): opcode2: 0x%2x, %,09b\n", opc2, opc2 );
+ // Note: all 'reserved' bits must be cleared, else invalid
+ switch (opc1) {
- switch (opc) {
- case 0:
+ /*
+ Branch Instructions
+ */
+ case 0x12: // b
+ case 0x10: // bc
+ if (dis_branch(theInstr)) break;
goto decode_failure;
+
+ case 0x13:
+ switch (opc2) {
+
+ /*
+ Branch Instructions
+ */
+ case 0x210: // bcctr
+ case 0x010: // bclr
+ if (dis_branch(theInstr)) break;
+ goto decode_failure;
+
+ default:
+ goto decode_failure;
+ }
+
+
+
+ case 0x1F:
+ switch (opc2) {
+
+ /*
+ Integer Arithmetic Instructions
+ */
+ case 0x10A: case 0x30A: // add
+ case 0x00A: case 0x20A: // addc
+ case 0x08A: case 0x28A: // adde
+ case 0x0EA: case 0x2EA: // addme
+ case 0x0CA: case 0x2CA: // addze
+ if (dis_int_arith(theInstr, 1)) break;
+ goto decode_failure;
+
+ default:
+ goto decode_failure;
+ }
+
+
default:
decode_failure:
/* All decode failures end up here. */