From: Cerion Armour-Brown Date: Tue, 28 Jun 2005 17:23:09 +0000 (+0000) Subject: AltiVec insn parsing for guest end. X-Git-Tag: svn/VALGRIND_3_0_1^2~110 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=733de36e8e925ec8fd5fd0780f7e384793e3951a;p=thirdparty%2Fvalgrind.git AltiVec insn parsing for guest end. git-svn-id: svn://svn.valgrind.org/vex/trunk@1224 --- diff --git a/VEX/priv/guest-ppc32/toIR.c b/VEX/priv/guest-ppc32/toIR.c index 30827bb075..a291ebee02 100644 --- a/VEX/priv/guest-ppc32/toIR.c +++ b/VEX/priv/guest-ppc32/toIR.c @@ -36,12 +36,19 @@ /* Translates PPC32 code to IR. */ /* References - All page references, unless otherwise indicated, refer to IBM's + +#define PPC32 "PowerPC Microprocessor Family: The Programming Environments for 32-Bit Microprocessors" 02/21/2000 http://www-3.ibm.com/chips/techlib/techlib.nsf/techdocs/852569B20050FF778525699600719DF2 +#define AV + "PowerPC Microprocessor Family: + AltiVec(TM) Technology Programming Environments Manual" + 07/10/2003 + http://www-3.ibm.com/chips/techlib/techlib.nsf/techdocs/FBFA164F824370F987256D6A006F424D + Other refs: "PowerPC Microprocessor Family: Programming Environments Manual for 64 and 32-Bit Microprocessors @@ -109,39 +116,6 @@ static IRBB* irbb; /*--- Offsets of various parts of the ppc32 guest state. ---*/ /*------------------------------------------------------------*/ -#define OFFB_GPR0 offsetof(VexGuestPPC32State,guest_GPR0) -#define OFFB_GPR1 offsetof(VexGuestPPC32State,guest_GPR1) -#define OFFB_GPR2 offsetof(VexGuestPPC32State,guest_GPR2) -#define OFFB_GPR3 offsetof(VexGuestPPC32State,guest_GPR3) -#define OFFB_GPR4 offsetof(VexGuestPPC32State,guest_GPR4) -#define OFFB_GPR5 offsetof(VexGuestPPC32State,guest_GPR5) -#define OFFB_GPR6 offsetof(VexGuestPPC32State,guest_GPR6) -#define OFFB_GPR7 offsetof(VexGuestPPC32State,guest_GPR7) -#define OFFB_GPR8 offsetof(VexGuestPPC32State,guest_GPR8) -#define OFFB_GPR9 offsetof(VexGuestPPC32State,guest_GPR9) -#define OFFB_GPR10 offsetof(VexGuestPPC32State,guest_GPR10) -#define OFFB_GPR11 offsetof(VexGuestPPC32State,guest_GPR11) -#define OFFB_GPR12 offsetof(VexGuestPPC32State,guest_GPR12) -#define OFFB_GPR13 offsetof(VexGuestPPC32State,guest_GPR13) -#define OFFB_GPR14 offsetof(VexGuestPPC32State,guest_GPR14) -#define OFFB_GPR15 offsetof(VexGuestPPC32State,guest_GPR15) -#define OFFB_GPR16 offsetof(VexGuestPPC32State,guest_GPR16) -#define OFFB_GPR17 offsetof(VexGuestPPC32State,guest_GPR17) -#define OFFB_GPR18 offsetof(VexGuestPPC32State,guest_GPR18) -#define OFFB_GPR19 offsetof(VexGuestPPC32State,guest_GPR19) -#define OFFB_GPR20 offsetof(VexGuestPPC32State,guest_GPR20) -#define OFFB_GPR21 offsetof(VexGuestPPC32State,guest_GPR21) -#define OFFB_GPR22 offsetof(VexGuestPPC32State,guest_GPR22) -#define OFFB_GPR23 offsetof(VexGuestPPC32State,guest_GPR23) -#define OFFB_GPR24 offsetof(VexGuestPPC32State,guest_GPR24) -#define OFFB_GPR25 offsetof(VexGuestPPC32State,guest_GPR25) -#define OFFB_GPR26 offsetof(VexGuestPPC32State,guest_GPR26) -#define OFFB_GPR27 offsetof(VexGuestPPC32State,guest_GPR27) -#define OFFB_GPR28 offsetof(VexGuestPPC32State,guest_GPR28) -#define OFFB_GPR29 offsetof(VexGuestPPC32State,guest_GPR29) -#define OFFB_GPR30 offsetof(VexGuestPPC32State,guest_GPR30) -#define OFFB_GPR31 offsetof(VexGuestPPC32State,guest_GPR31) - #define OFFB_CIA offsetof(VexGuestPPC32State,guest_CIA) #define OFFB_LR offsetof(VexGuestPPC32State,guest_LR) #define OFFB_CTR offsetof(VexGuestPPC32State,guest_CTR) @@ -156,6 +130,9 @@ static IRBB* irbb; #define OFFB_XER offsetof(VexGuestPPC32State,guest_XER) +#define OFFB_VRSAVE offsetof(VexGuestPPC32State,guest_VRSAVE) +#define OFFB_VSCR offsetof(VexGuestPPC32State,guest_VSCR) + #define OFFB_EMWARN offsetof(VexGuestPPC32State,guest_EMWARN) #define OFFB_TISTART offsetof(VexGuestPPC32State,guest_TISTART) @@ -170,7 +147,7 @@ static IRBB* irbb; #define SHIFT_XER_SO 31 #define SHIFT_XER_OV 30 #define SHIFT_XER_CA 29 -#define SHIFT_XER_BC 0 +#define SHIFT_XER_BC 0 #define SHIFT_CR_LT 8 #define SHIFT_CR_GT 4 @@ -180,6 +157,9 @@ static IRBB* irbb; #define SHIFT_FPSCR_RN 0 #define MASK_FPSCR_RN (3 << SHIFT_FPSCR_RN) +#define SHIFT_VSCR_NJ 16 +#define SHIFT_VSCR_SAT 0 + // Special purpose (i.e. non-gpr/fpr) registers typedef enum { @@ -189,6 +169,8 @@ typedef enum { PPC32_SPR_XER, // Summary Overflow PPC32_SPR_CR, // Condition Register PPC32_SPR_FPSCR, // Floating Point Status/Control Register + PPC32_SPR_VRSAVE, // Vector Save/Restore Register + PPC32_SPR_VSCR, // Vector Status and Control Register PPC32_SPR_MAX } PPC32SPR; @@ -465,6 +447,11 @@ static void unimplemented ( Char* str ) /* Various simple conversions */ +static UChar extend_s_5to8 ( UChar x ) +{ + return (UChar)((((Int)x) << 27) >> 27); +} + #if 0 static UInt extend_s_8to32( UInt x ) { @@ -617,6 +604,63 @@ static void putFReg ( UInt archreg, IRExpr* e ) } +static Int vectorGuestRegOffset ( UInt archreg ) +{ + vassert(archreg < 32); + + switch (archreg) { + case 0: return offsetof(VexGuestPPC32State, guest_VR0); + case 1: return offsetof(VexGuestPPC32State, guest_VR1); + case 2: return offsetof(VexGuestPPC32State, guest_VR2); + case 3: return offsetof(VexGuestPPC32State, guest_VR3); + case 4: return offsetof(VexGuestPPC32State, guest_VR4); + case 5: return offsetof(VexGuestPPC32State, guest_VR5); + case 6: return offsetof(VexGuestPPC32State, guest_VR6); + case 7: return offsetof(VexGuestPPC32State, guest_VR7); + case 8: return offsetof(VexGuestPPC32State, guest_VR8); + case 9: return offsetof(VexGuestPPC32State, guest_VR9); + case 10: return offsetof(VexGuestPPC32State, guest_VR10); + case 11: return offsetof(VexGuestPPC32State, guest_VR11); + case 12: return offsetof(VexGuestPPC32State, guest_VR12); + case 13: return offsetof(VexGuestPPC32State, guest_VR13); + case 14: return offsetof(VexGuestPPC32State, guest_VR14); + case 15: return offsetof(VexGuestPPC32State, guest_VR15); + case 16: return offsetof(VexGuestPPC32State, guest_VR16); + case 17: return offsetof(VexGuestPPC32State, guest_VR17); + case 18: return offsetof(VexGuestPPC32State, guest_VR18); + case 19: return offsetof(VexGuestPPC32State, guest_VR19); + case 20: return offsetof(VexGuestPPC32State, guest_VR20); + case 21: return offsetof(VexGuestPPC32State, guest_VR21); + case 22: return offsetof(VexGuestPPC32State, guest_VR22); + case 23: return offsetof(VexGuestPPC32State, guest_VR23); + case 24: return offsetof(VexGuestPPC32State, guest_VR24); + case 25: return offsetof(VexGuestPPC32State, guest_VR25); + case 26: return offsetof(VexGuestPPC32State, guest_VR26); + case 27: return offsetof(VexGuestPPC32State, guest_VR27); + case 28: return offsetof(VexGuestPPC32State, guest_VR28); + case 29: return offsetof(VexGuestPPC32State, guest_VR29); + case 30: return offsetof(VexGuestPPC32State, guest_VR30); + case 31: return offsetof(VexGuestPPC32State, guest_VR31); + } + + vpanic("vextorGuestRegOffset(ppc32)"); /*notreached*/ +} + +static IRExpr* getVReg ( UInt archreg ) +{ + vassert(archreg < 32); + return IRExpr_Get( vectorGuestRegOffset(archreg), Ity_V128 ); +} + +/* Ditto, but write to a reg instead. */ +static void putVReg ( UInt archreg, IRExpr* e ) +{ + vassert(archreg < 32); + vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_V128); + stmt( IRStmt_Put(vectorGuestRegOffset(archreg), e) ); +} + + static void assign ( IRTemp dst, IRExpr* e ) { stmt( IRStmt_Tmp(dst, e) ); @@ -896,6 +940,17 @@ static IRExpr* getReg_masked ( PPC32SPR reg, UInt mask ) break; } + case PPC32_SPR_VRSAVE: + assign( val, IRExpr_Get(OFFB_VRSAVE, Ity_I32) ); + break; + + case PPC32_SPR_VSCR: + // All other bits are 'Reserved'. Returning zero for these bits. + mask = mask & 0x00010001; + assign( val, IRExpr_Get(OFFB_VSCR, Ity_I32) ); + break; + break; + default: vpanic("getReg(ppc32)"); } @@ -1040,6 +1095,20 @@ static void putReg_masked ( PPC32SPR reg, IRExpr* src, UInt mask ) ); } + case PPC32_SPR_VRSAVE: + stmt( IRStmt_Put( OFFB_VRSAVE, src ) ); + break; + + case PPC32_SPR_VSCR: +//CAB: There are only 2 valid bits in VSCR - maybe split into two vars... + + // All other bits are 'Reserved'. Ignoring writes to these bits. + assign( src_mskd, binop(Iop_And32, src, mkU32(mask & 0x00010001)) ); + assign( reg_old, getReg_masked( PPC32_SPR_XER, (~mask & 0x00010001) ) ); + stmt( IRStmt_Put( OFFB_VSCR, + binop(Iop_Or32, mkexpr(src_mskd), mkexpr(reg_old)) )); + break; + /* Ignore all other writes */ @@ -3136,10 +3205,11 @@ static Bool dis_proc_ctl ( UInt theInstr ) DIP("mfspr r%d,0x%x\n", Rd_addr, SPR_flipped); switch (SPR_flipped) { // Choose a register... - case 0x1: putIReg( Rd_addr, getReg( PPC32_SPR_XER ) ); break; - case 0x8: putIReg( Rd_addr, getReg( PPC32_SPR_LR ) ); break; - case 0x9: putIReg( Rd_addr, getReg( PPC32_SPR_CTR ) ); break; - + case 0x1: putIReg( Rd_addr, getReg( PPC32_SPR_XER ) ); break; + case 0x8: putIReg( Rd_addr, getReg( PPC32_SPR_LR ) ); break; + case 0x9: putIReg( Rd_addr, getReg( PPC32_SPR_CTR ) ); break; + case 0x100: putIReg( Rd_addr, getReg( PPC32_SPR_VRSAVE ) ); break; + case 0x012: case 0x013: case 0x016: case 0x019: case 0x01A: case 0x01B: case 0x110: case 0x111: case 0x112: case 0x113: @@ -3185,9 +3255,10 @@ vassert(0); DIP("mtspr 0x%x,r%d\n", SPR_flipped, Rs_addr); switch (SPR_flipped) { // Choose a register... - case 0x1: putReg( PPC32_SPR_XER, mkexpr(Rs) ); break; - case 0x8: putReg( PPC32_SPR_LR, mkexpr(Rs) ); break; - case 0x9: putReg( PPC32_SPR_CTR, mkexpr(Rs) ); break; + case 0x1: putReg( PPC32_SPR_XER, mkexpr(Rs) ); break; + case 0x8: putReg( PPC32_SPR_LR, mkexpr(Rs) ); break; + case 0x9: putReg( PPC32_SPR_CTR, mkexpr(Rs) ); break; + case 0x100: putReg( PPC32_SPR_VRSAVE, mkexpr(Rs) ); break; case 0x012: case 0x013: case 0x016: case 0x019: case 0x01A: case 0x01B: @@ -4280,185 +4351,1462 @@ static Bool dis_fp_scr ( UInt theInstr ) - - - - - - - /*------------------------------------------------------------*/ -/*--- Disassemble a single instruction ---*/ +/*--- AltiVec Instruction Translation ---*/ /*------------------------------------------------------------*/ -/* Disassemble a single instruction into IR. The instruction - is located in host memory at &guest_code[delta]. - Set *size to be the size of the instruction. - If the returned value is Dis_Resteer, - the next guest address is assigned to *whereNext. If resteerOK - is False, disInstr may not return Dis_Resteer. */ - -static DisResult disInstr ( /*IN*/ Bool resteerOK, - /*IN*/ Bool (*resteerOkFn) ( Addr64 ), - /*IN*/ UInt delta, - /*OUT*/ Int* size, - /*OUT*/ Addr64* whereNext ) +/* + Altivec Cache Control Instructions (Data Streams) +*/ +static Bool dis_av_datastream ( UInt theInstr ) { - UChar opc1; - UInt opc2; - DisResult whatNext = Dis_Continue; - UInt theInstr; + UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */ + UChar flag_T = toUChar((theInstr >> 25) & 0x1); /* theInstr[25] */ + UChar flag_A = toUChar((theInstr >> 25) & 0x1); /* theInstr[25] */ + UChar b23to24 = toUChar((theInstr >> 23) & 0x3); /* theInstr[23:24] */ + UChar STRM = toUChar((theInstr >> 21) & 0x3); /* theInstr[21:22] */ + UChar rA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */ + UChar rB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */ + UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */ + UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */ + if (opc1 != 0x1F || b23to24 != 0 || b0 != 0) { + vex_printf("dis_av_datastream(PPC32)(instr)\n"); + return False; + } - /* At least this is simple on PPC32: insns are all 4 bytes long, and - 4-aligned. So just fish the whole thing out of memory right now - and have done. */ + switch (opc2) { + case 0x156: // dst (Data Stream Touch, AV p115) + DIP("dst%s r%d,r%d,%d\n", flag_T ? "t" : "", rA_addr, rB_addr, STRM); + DIP(" => not implemented\n"); + return False; - /* We will set *size to 4 if the insn is successfully decoded. - Setting it to 0 by default makes bbToIR_PPC32 abort if we fail the - decode. */ - *size = 0; + case 0x176: // dstst (Data Stream Touch for Store, AV p117) + DIP("dstst%s r%d,r%d,%d\n", flag_T ? "t" : "", rA_addr, rB_addr, STRM); + DIP(" => not implemented\n"); + return False; - theInstr = getUIntBigendianly( (UChar*)(&guest_code[delta]) ); + case 0x336: // dss (Data Stream Stop, AV p114) + if (rA_addr != 0 || rB_addr != 0) { + vex_printf("dis_av_datastream(PPC32)(opc2,dst)\n"); + return False; + } + if (flag_A == 0) { + DIP("dss %d\n", STRM); + DIP(" => not implemented\n"); + } else { + DIP("dssall\n"); + DIP(" => not implemented\n"); + } + return False; - DIP("\t0x%x: ", guest_pc_bbstart+delta); + default: + vex_printf("dis_av_datastream(PPC32)(opc2)\n"); + return False; + } + return True; +} +/* + AltiVec Processor Control Instructions +*/ +static Bool dis_av_procctl ( UInt theInstr ) +{ + UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */ + UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */ + UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */ + UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */ + UInt opc2 = (theInstr >> 0) & 0x7FF; /* theInstr[0:10] */ - /* Spot the client-request magic sequence. */ - // Essentially a v. unlikely sequence of noops that we can catch - { - UInt* code = (UInt*)(guest_code + delta); + if (opc1 != 0x4) { + vex_printf("dis_av_procctl(PPC32)(instr)\n"); + return False; + } - /* Spot this: - 0x7C03D808 tw 0,3,27 => trap word if(0) => nothing - 0x5400E800 rlwinm 0,0,29,0,0 => r0 = rotl(r0,29) - 0x54001800 rlwinm 0,0,3,0,0 => r0 = rotl(r0,3) - 0x54006800 rlwinm 0,0,13,0,0 => r0 = rotl(r0,13) - 0x54009800 rlwinm 0,0,19,0,0 => r0 = rotl(r0,19) - 0x60000000 nop - */ - if (code[0] == 0x7C03D808 && - code[1] == 0x5400E800 && - code[2] == 0x54001800 && - code[3] == 0x54006800 && - code[4] == 0x54009800 && - code[5] == 0x60000000) { - DIP("%%r3 = client_request ( %%r31 )\n"); - *size = 24; - delta += 24; + switch (opc2) { + case 0x604: // mfvscr (Move from VSCR, AV p129) + if (vA_addr != 0 || vB_addr != 0) { + vex_printf("dis_av_procctl(PPC32)(opc2,dst)\n"); + return False; + } + DIP("mfvscr v%d\n", vD_addr); + DIP(" => not implemented\n"); + return False; - irbb->next = mkU32(guest_pc_bbstart+delta); - irbb->jumpkind = Ijk_ClientReq; - whatNext = Dis_StopHere; - goto decode_success; + case 0x644: // mtvscr (Move to VSCR, AV p130) + if (vD_addr != 0 || vA_addr != 0) { + vex_printf("dis_av_procctl(PPC32)(opc2,dst)\n"); + return False; } + DIP("mtvscr v%d\n", vB_addr); + DIP(" => not implemented\n"); + return False; + + default: + vex_printf("dis_av_procctl(PPC32)(opc2)\n"); + return False; } + return True; +} +/* + AltiVec Load Instructions +*/ +static Bool dis_av_load ( UInt theInstr ) +{ + UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */ + UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */ + UChar rA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */ + UChar rB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */ + UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */ + UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */ - opc1 = toUChar((theInstr >> 26) & 0x3F ); /* theInstr[26:31] */ - opc2 = ((theInstr >> 1 ) & 0x3FF); /* theInstr[1:10] */ + if (opc1 != 0x1F || b0 != 0) { + vex_printf("dis_av_load(PPC32)(instr)\n"); + return False; + } -#if PPC32_TOIR_DEBUG - vex_printf("\ndisInstr(ppc32): instr: 0x%x\n", theInstr); - vex_printf("disInstr(ppc32): instr: "); - vex_printf_binary( theInstr, 32, True ); - vex_printf("\n"); -#endif + switch (opc2) { + case 0x006: // lvsl (Load Vector for Shift Left, AV p123) + DIP("lvsl v%d,r%d,r%d\n", vD_addr, rA_addr, rB_addr); + DIP(" => not implemented\n"); + return False; - // Note: all 'reserved' bits must be cleared, else invalid - switch (opc1) { + case 0x026: // lvsr (Load Vector for Shift Right, AV p125) + DIP("lvsr v%d,r%d,r%d\n", vD_addr, rA_addr, rB_addr); + DIP(" => not implemented\n"); + return False; - /* Integer Arithmetic Instructions */ - case 0x0C: case 0x0D: case 0x0E: // addic, addic., addi - case 0x0F: case 0x07: case 0x08: // addis, mulli, subfic - if (dis_int_arith( theInstr )) goto decode_success; - goto decode_failure; + case 0x007: // lvebx (Load Vector Element Byte Indexed, AV p119) + DIP("lvebx v%d,r%d,r%d\n", vD_addr, rA_addr, rB_addr); + DIP(" => not implemented\n"); + return False; - /* Integer Compare Instructions */ - case 0x0B: case 0x0A: // cmpi, cmpli - if (dis_int_cmp( theInstr )) goto decode_success; - goto decode_failure; + case 0x027: // lvehx (Load Vector Element Half Word Indexed, AV p121) + DIP("lvehx v%d,r%d,r%d\n", vD_addr, rA_addr, rB_addr); + DIP(" => not implemented\n"); + return False; - /* Integer Logical Instructions */ - case 0x1C: case 0x1D: case 0x18: // andi., andis., ori - case 0x19: case 0x1A: case 0x1B: // oris, xori, xoris - if (dis_int_logic( theInstr )) goto decode_success; - goto decode_failure; + case 0x047: // lvewx (Load Vector Element Word Indexed, AV p122) + DIP("lvewx v%d,r%d,r%d\n", vD_addr, rA_addr, rB_addr); + DIP(" => not implemented\n"); + return False; - /* Integer Rotate Instructions */ - case 0x14: case 0x15: case 0x17: // rlwimi, rlwinm, rlwnm - if (dis_int_rot( theInstr )) goto decode_success; - goto decode_failure; + case 0x067: // lvx (Load Vector Indexed, AV p127) + DIP("lvx v%d,r%d,r%d\n", vD_addr, rA_addr, rB_addr); + DIP(" => not implemented\n"); + return False; - /* Integer Load Instructions */ - case 0x22: case 0x23: case 0x2A: // lbz, lbzu, lha - case 0x2B: case 0x28: case 0x29: // lhau, lhz, lhzu - case 0x20: case 0x21: // lwz, lwzu - if (dis_int_load( theInstr )) goto decode_success; - goto decode_failure; + case 0x167: // lvxl (Load Vector Indexed LRU, AV p128) + // XXX: lvxl gives explicit control over cache block replacement + DIP("lvxl v%d,r%d,r%d\n", vD_addr, rA_addr, rB_addr); + DIP(" => not implemented\n"); + return False; - /* Integer Store Instructions */ - case 0x26: case 0x27: case 0x2C: // stb, stbu, sth - case 0x2D: case 0x24: case 0x25: // sthu, stw, stwu - if (dis_int_store( theInstr )) goto decode_success; - goto decode_failure; + default: + vex_printf("dis_av_load(PPC32)(opc2)\n"); + return False; + } + return True; +} - /* Integer Load and Store Multiple Instructions */ - case 0x2E: case 0x2F: // lmw, stmw - if (dis_int_ldst_mult( theInstr )) goto decode_success; - goto decode_failure; +/* + AltiVec Store Instructions +*/ +static Bool dis_av_store ( UInt theInstr ) +{ + UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */ + UChar vS_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */ + UChar rA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */ + UChar rB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */ + UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */ + UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */ - /* Branch Instructions */ - case 0x12: case 0x10: // b, bc - if (dis_branch(theInstr, &whatNext)) goto decode_success; - goto decode_failure; + IRTemp rA = newTemp(Ity_I32); + IRTemp rB = newTemp(Ity_I32); + IRTemp vS = newTemp(Ity_V128); + IRTemp EA = newTemp(Ity_I32); + IRTemp EA_aligned = newTemp(Ity_I32); - /* System Linkage Instructions */ - case 0x11: // sc - if (dis_syslink(theInstr, &whatNext)) goto decode_success; - goto decode_failure; + assign( rA, getIReg(rA_addr)); + assign( rB, getIReg(rB_addr)); + assign( vS, getVReg(vS_addr)); - /* Trap Instructions */ - case 0x03: // twi - DIP("trap op (twi) => not implemented\n"); - goto decode_failure; + if (rA_addr == 0) { + assign( EA, mkexpr(rB) ); + } else { + assign( EA, binop(Iop_Add32, mkexpr(rA), mkexpr(rB)) ); + } - /* Floating Point Load Instructions */ - case 0x30: case 0x31: case 0x32: // lfs, lfsu, lfd - case 0x33: // lfdu - if (dis_fp_load( theInstr )) goto decode_success; - goto decode_failure; + if (opc1 != 0x1F || b0 != 0) { + vex_printf("dis_av_store(PPC32)(instr)\n"); + return False; + } - /* Floating Point Store Instructions */ - case 0x34: case 0x35: case 0x36: // stfsx, stfsux, stfdx - case 0x37: // stfdux - if (dis_fp_store( theInstr )) goto decode_success; - goto decode_failure; + switch (opc2) { + case 0x087: // stvebx (Store Vector Byte Indexed, AV p131) + DIP("stvebx v%d,r%d,r%d\n", vS_addr, rA_addr, rB_addr); + DIP(" => not implemented\n"); + return False; - case 0x3B: - opc2 = (theInstr >> 1) & 0x1F; /* theInstr[1:5] */ - switch (opc2) { - /* Floating Point Arith Instructions */ - case 0x12: case 0x14: case 0x15: // fdivs, fsubs, fadds - case 0x16: case 0x18: case 0x19: // fsqrts, fres, fmuls - if (dis_fp_arith(theInstr)) goto decode_success; - goto decode_failure; +// eb = EA & 0xF; +// STORE(vS[eb*8:eb*8+7], 1, EA); +// storeBE( mkexpr(EA), mkexpr(vS) ); - /* Floating Point Mult-Add Instructions */ - case 0x1C: case 0x1D: case 0x1E: // fmsubs, fmadds, fnmsubs - case 0x1F: // fnmadds - if (dis_fp_multadd(theInstr)) goto decode_success; - goto decode_failure; + case 0x0A7: // stvehx (Store Vector Half Word Indexed, AV p132) + DIP("stvehx v%d,r%d,r%d\n", vS_addr, rA_addr, rB_addr); + DIP(" => not implemented\n"); + return False; - default: - goto decode_failure; - } - break; +// EA_aligned = EA & 0xFFFF_FFFE +// eb = EA_aligned & 0xF; +// STORE(vS[eb*8:eb*8+15], 2, EA_aligned); - case 0x3F: - /* Instrs using opc[1:5] never overlap with instrs using opc[1:10], - so we can simply fall through the first switch statement */ + case 0x0C7: // stvewx (Store Vector Word Indexed, AV p133) + DIP("stvewx v%d,r%d,r%d\n", vS_addr, rA_addr, rB_addr); + DIP(" => not implemented\n"); + return False; + +// EA_aligned = EA & 0xFFFF_FFFC +// eb = EA_aligned & 0xF; +// STORE(vS[eb*8:eb*8+31], 4, EA_aligned); + + case 0x0E7: // stvx (Store Vector Indexed, AV p134) + DIP("stvx v%d,r%d,r%d\n", vS_addr, rA_addr, rB_addr); + assign( EA_aligned, binop( Iop_And32, mkexpr(EA), mkU32(0xFFFFFFF0) )); + storeBE( mkexpr(EA_aligned), mkexpr(vS) ); + break; + + case 0x1E7: // stvxl (Store Vector Indexed LRU, AV p135) + // XXX: stvxl can give explicit control over cache block replacement + DIP("stvxl v%d,r%d,r%d\n", vS_addr, rA_addr, rB_addr); + DIP(" => not implemented\n"); + return False; + +// EA_aligned = EA & 0xFFFF_FFF0; +// STORE(vS, 16, EA); + + default: + vex_printf("dis_av_store(PPC32)(opc2)\n"); + return False; + } + return True; +} + +/* + AltiVec Arithmetic Instructions +*/ +static Bool dis_av_arith ( UInt theInstr ) +{ + UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */ + UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */ + UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */ + UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */ + UInt opc2 = (theInstr >> 0) & 0x7FF; /* theInstr[0:10] */ + + if (opc1 != 0x4) { + vex_printf("dis_av_arith(PPC32)(opc1 != 0x4)\n"); + return False; + } + + switch (opc2) { + /* Add */ + case 0x180: // vaddcuw (Add Carryout Unsigned Word, AV p136) + DIP("vaddcuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x000: // vaddubm (Add Unsigned Byte Modulo, AV p141) + DIP("vaddubm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x040: // vadduhm (Add Unsigned Half Word Modulo, AV p143) + DIP("vadduhm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x080: // vadduwm (Add Unsigned Word Modulo, AV p145) + DIP("vadduwm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x200: // vaddubs (Add Unsigned Byte Saturate, AV p142) + DIP("vaddubs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x240: // vadduhs (Add Unsigned Half Word Saturate, AV p144) + DIP("vadduhs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x280: // vadduws (Add Unsigned Word Saturate, AV p146) + DIP("vadduws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x300: // vaddsbs (Add Signed Byte Saturate, AV p138) + DIP("vaddsbs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x340: // vaddshs (Add Signed Half Word Saturate, AV p139) + DIP("vaddshs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x380: // vaddsws (Add Signed Word Saturate, AV p140) + DIP("vaddsws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + /* Subtract */ + case 0x580: // vsubcuw (Subtract Carryout Unsigned Word, AV p260) + DIP("vsubcuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x400: // vsububm (Subtract Unsigned Byte Modulo, AV p265) + DIP("vsububm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x440: // vsubuhm (Subtract Unsigned Half Word Modulo, AV p267) + DIP("vsubuhm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x480: // vsubuwm (Subtract Unsigned Word Modulo, AV p269) + DIP("vsubuwm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x600: // vsububs (Subtract Unsigned Byte Saturate, AV p266) + DIP("vsububs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x640: // vsubuhs (Subtract Unsigned Half Word Saturate, AV p268) + DIP("vsubuhs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x680: // vsubuws (Subtract Unsigned Word Saturate, AV p270) + DIP("vsubuws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x700: // vsubsbs (Subtract Signed Byte Saturate, AV p262) + DIP("vsubsbs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x740: // vsubshs (Subtract Signed Half Word Saturate, AV p263) + DIP("vsubshs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x780: // vsubsws (Subtract Signed Word Saturate, AV p264) + DIP("vsubsws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + + /* Maximum */ + case 0x002: // vmaxub (Maximum Unsigned Byte, AV p182) + DIP("vmaxub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x042: // vmaxuh (Maximum Unsigned Half Word, AV p183) + DIP("vmaxuh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x082: // vmaxuw (Maximum Unsigned Word, AV p184) + DIP("vmaxuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x102: // vmaxsb (Maximum Signed Byte, AV p179) + DIP("vmaxsb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x142: // vmaxsh (Maximum Signed Half Word, AV p180) + DIP("vmaxsh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x182: // vmaxsw (Maximum Signed Word, AV p181) + DIP("vmaxsw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + + /* Minimum */ + case 0x202: // vminub (Minimum Unsigned Byte, AV p191) + DIP("vminub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x242: // vminuh (Minimum Unsigned Half Word, AV p192) + DIP("vminuh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x282: // vminuw (Minimum Unsigned Word, AV p193) + DIP("vminuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x302: // vminsb (Minimum Signed Byte, AV p188) + DIP("vminsb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x342: // vminsh (Minimum Signed Half Word, AV p189) + DIP("vminsh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x382: // vminsw (Minimum Signed Word, AV p190) + DIP("vminsw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + + /* Average */ + case 0x402: // vavgub (Average Unsigned Byte, AV p152) + DIP("vavgub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x442: // vavguh (Average Unsigned Half Word, AV p153) + DIP("vavguh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x482: // vavguw (Average Unsigned Word, AV p154) + DIP("vavguw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x502: // vavgsb (Average Signed Byte, AV p149) + DIP("vavgsb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x542: // vavgsh (Average Signed Half Word, AV p150) + DIP("vavgsh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x582: // vavgsw (Average Signed Word, AV p151) + DIP("vavgsw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + + /* Multiply */ + case 0x008: // vmuloub (Multiply Odd Unsigned Byte, AV p213) + DIP("vmuloub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x048: // vmulouh (Multiply Odd Unsigned Half Word, AV p214) + DIP("vmulouh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x108: // vmulosb (Multiply Odd Signed Byte, AV p211) + DIP("vmulosb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x148: // vmulosh (Multiply Odd Signed Half Word, AV p212) + DIP("vmulosh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x208: // vmuleub (Multiply Even Unsigned Byte, AV p209) + DIP("vmuleub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x248: // vmuleuh (Multiply Even Unsigned Half Word, AV p210) + DIP("vmuleuh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x308: // vmulesb (Multiply Even Signed Byte, AV p207) + DIP("vmulesb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x348: // vmulesh (Multiply Even Signed Half Word, AV p208) + DIP("vmulesh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + + /* Sum Across Partial */ + case 0x608: // vsum4ubs (Sum Partial (1/4) UB Saturate, AV p275) + DIP("vsum4ubs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x708: // vsum4sbs (Sum Partial (1/4) SB Saturate, AV p273) + DIP("vsum4sbs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x648: // vsum4shs (Sum Partial (1/4) SHW Saturate, AV p274) + DIP("vsum4shs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x688: // vsum2sws (Sum Partial (1/2) SW Saturate, AV p272) + DIP("vsum2sws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x788: // vsumsws (Sum SW Saturate, AV p271) + DIP("vsumsws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + default: + vex_printf("dis_av_arith(PPC32)(opc2=0x%x)\n", opc2); + return False; + } + return True; +} + +/* + AltiVec Logic Instructions +*/ +static Bool dis_av_logic ( UInt theInstr ) +{ + UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */ + UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */ + UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */ + UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */ + UInt opc2 = (theInstr >> 0) & 0x7FF; /* theInstr[0:10] */ + + if (opc1 != 0x4) { + vex_printf("dis_av_logic(PPC32)(opc1 != 0x4)\n"); + return False; + } + + switch (opc2) { + case 0x404: // vand (And, AV p147) + DIP("vand v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x444: // vandc (And, AV p148) + DIP("vandc v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x484: // vor (Or, AV p217) + DIP("vor v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x4C4: // vxor (Xor, AV p282) + DIP("vxor v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x504: // vnor (Nor, AV p216) + DIP("vnor v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + default: + vex_printf("dis_av_logic(PPC32)(opc2=0x%x)\n", opc2); + return False; + } + return True; +} + +/* + AltiVec Compare Instructions +*/ +static Bool dis_av_cmp ( UInt theInstr ) +{ + UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */ + UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */ + UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */ + UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */ + UChar flag_Rc = toUChar((theInstr >> 10) & 0x1); /* theInstr[10] */ + UInt opc2 = (theInstr >> 0) & 0x3FF; /* theInstr[0:9] */ + + if (opc1 != 0x4) { + vex_printf("dis_av_cmp(PPC32)(instr)\n"); + return False; + } + + switch (opc2) { + case 0x006: // vcmpequb (Compare Equal-to Unsigned B, AV p160) + DIP("vcmpequb%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x046: // vcmpequh (Compare Equal-to Unsigned HW, AV p161) + DIP("vcmpequh%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x086: // vcmpequw (Compare Equal-to Unsigned W, AV p162) + DIP("vcmpequw%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x206: // vcmpgtub (Compare Greater-than Unsigned B, AV p168) + DIP("vcmpgtub%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x246: // vcmpgtuh (Compare Greater-than Unsigned HW, AV p169) + DIP("vcmpgtuh%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x286: // vcmpgtuw (Compare Greater-than Unsigned W, AV p170) + DIP("vcmpgtuw%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x306: // vcmpgtsb (Compare Greater-than Signed B, AV p165) + DIP("vcmpgtsb%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x346: // vcmpgtsh (Compare Greater-than Signed HW, AV p166) + DIP("vcmpgtsh%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x386: // vcmpgtsw (Compare Greater-than Signed W, AV p167) + DIP("vcmpgtsw%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + default: + vex_printf("dis_av_cmp(PPC32)(opc2)\n"); + return False; + } + return True; +} + +/* + AltiVec Multiply-Sum Instructions +*/ +static Bool dis_av_multarith ( UInt theInstr ) +{ + UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */ + UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */ + UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */ + UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */ + UChar vC_addr = toUChar((theInstr >> 6) & 0x1F); /* theInstr[6:10] */ + UChar opc2 = toUChar((theInstr >> 0) & 0x3F); /* theInstr[0:5] */ + + if (opc1 != 0x4) { + vex_printf("dis_av_multarith(PPC32)(instr)\n"); + return False; + } + + switch (opc2) { + + /* Multiply-Add */ + case 0x20: // vmhaddshs (Multiply High, Add Signed HW Saturate, AV p185) + DIP("vmhaddshs v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr); + DIP(" => not implemented\n"); + return False; + + case 0x21: // vmhraddshs (Multiply High Round, Add Signed HW Saturate, AV p186) + DIP("vmhraddshs v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr); + DIP(" => not implemented\n"); + return False; + + case 0x22: // vmladduhm (Multiply Low, Add Unsigned HW Modulo, AV p194) + DIP("vmladduhm v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr); + DIP(" => not implemented\n"); + return False; + + + /* Multiply-Sum */ + case 0x24: // vmsumubm (Multiply Sum Unsigned B Modulo, AV p204) + DIP("vmsumubm v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr); + DIP(" => not implemented\n"); + return False; + + case 0x25: // vmsummbm (Multiply Sum Mixed-Sign B Modulo, AV p201) + DIP("vmsummbm v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr); + DIP(" => not implemented\n"); + return False; + + case 0x26: // vmsumuhm (Multiply Sum Unsigned HW Modulo, AV p205) + DIP("vmsumuhm v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr); + DIP(" => not implemented\n"); + return False; + + case 0x27: // vmsumuhs (Multiply Sum Unsigned HW Saturate, AV p206) + DIP("vmsumuhs v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr); + DIP(" => not implemented\n"); + return False; + + case 0x28: // vmsumshm (Multiply Sum Signed HW Modulo, AV p202) + DIP("vmsumshm v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr); + DIP(" => not implemented\n"); + return False; + + case 0x29: // vmsumshs (Multiply Sum Signed HW Saturate, AV p203) + DIP("vmsumshs v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr); + DIP(" => not implemented\n"); + return False; + + default: + vex_printf("dis_av_multarith(PPC32)(opc2)\n"); + return False; + } + return True; +} + +/* + AltiVec Shift/Rotate Instructions +*/ +static Bool dis_av_shift ( UInt theInstr ) +{ + UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */ + UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */ + UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */ + UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */ + UInt opc2 = (theInstr >> 0) & 0x7FF; /* theInstr[0:10] */ + + if (opc1 != 0x4){ + vex_printf("dis_av_shift(PPC32)(instr)\n"); + return False; + } + + switch (opc2) { + /* Rotate */ + case 0x004: // vrlb (Rotate Left Integer B, AV p234) + DIP("vrlb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x044: // vrlh (Rotate Left Integer HW, AV p235) + DIP("vrlh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x084: // vrlw (Rotate Left Integer W, AV p236) + DIP("vrlw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + + /* Shift Left */ + case 0x104: // vslb (Shift Left Integer B, AV p240) + DIP("vslb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x144: // vslh (Shift Left Integer HW, AV p242) + DIP("vslh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x184: // vslw (Shift Left Integer W, AV p244) + DIP("vslw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x1C4: // vsl (Shift Left, AV p239) + DIP("vsl v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x40C: // vslo (Shift Left by Octet, AV p243) + DIP("vslo v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + /* Shift Right */ + case 0x204: // vsrb (Shift Right B, AV p256) + DIP("vsrb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x244: // vsrh (Shift Right HW, AV p257) + DIP("vsrh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x284: // vsrw (Shift Right W, AV p259) + DIP("vsrw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x2C4: // vsr (Shift Right, AV p252) + DIP("vsr v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x304: // vsrab (Shift Right Algebraic B, AV p253) + DIP("vsrab v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x344: // vsrah (Shift Right Algebraic HW, AV p254) + DIP("vsrah v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x384: // vsraw (Shift Right Algebraic W, AV p255) + DIP("vsraw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x44C: // vsro (Shift Right by Octet, AV p258) + DIP("vsro v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + default: + vex_printf("dis_av_shift(PPC32)(opc2)\n"); + return False; + } + return True; +} + +/* + AltiVec Permute Instructions +*/ +static Bool dis_av_permute ( UInt theInstr ) +{ + UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */ + UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */ + UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */ + UChar UIMM_5 = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */ + UChar SIMM_5 = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */ + UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */ + UChar vC_addr = toUChar((theInstr >> 6) & 0x1F); /* theInstr[6:10] */ + UChar b10 = toUChar((theInstr >> 10) & 0x1); /* theInstr[10] */ + UChar SHB_uimm4 = toUChar((theInstr >> 6) & 0xF); /* theInstr[6:9] */ + UInt opc2 = (theInstr >> 0) & 0x3F; /* theInstr[0:5] */ + + UChar SIMM_8 = extend_s_5to8(SIMM_5); + + if (opc1 != 0x4) { + vex_printf("dis_av_permute(PPC32)(instr)\n"); + return False; + } + + switch (opc2) { + case 0x2A: // vsel (Conditional Select, AV p238) + DIP("vsel v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr); + DIP(" => not implemented\n"); + return False; + + case 0x2B: // vperm (Permute, AV p218) + DIP("vperm v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr); + DIP(" => not implemented\n"); + return False; + + case 0x2C: // vsldoi (Shift Left Double by Octet Imm, AV p241) + if (b10 != 0) { + vex_printf("dis_av_permute(PPC32)(vsldoi)\n"); + return False; + } + DIP("vsldoi v%d,v%d,v%d,%u\n", vD_addr, vA_addr, vB_addr, SHB_uimm4); + DIP(" => not implemented\n"); + return False; + + default: + break; // Fall through... + } + + opc2 = (theInstr) & 0x7FF; /* theInstr[0:10] */ + switch (opc2) { + + /* Merge */ + case 0x00C: // vmrghb (Merge High B, AV p195) + DIP("vmrghb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x04C: // vmrghh (Merge High HW, AV p196) + DIP("vmrghh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x08C: // vmrghw (Merge High W, AV p197) + DIP("vmrghw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x10C: // vmrglb (Merge Low B, AV p198) + DIP("vmrglb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x14C: // vmrglh (Merge Low HW, AV p199) + DIP("vmrglh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x18C: // vmrglw (Merge Low W, AV p200) + DIP("vmrglw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + /* Splat */ + case 0x20C: // vspltb (Splat Byte, AV p245) + DIP("vspltb v%d,v%d,%u\n", vD_addr, vB_addr, UIMM_5); + DIP(" => not implemented\n"); + return False; + + case 0x24C: // vsplth (Splat Half Word, AV p246) + DIP("vsplth v%d,v%d,%u\n", vD_addr, vB_addr, UIMM_5); + DIP(" => not implemented\n"); + return False; + + case 0x28C: // vspltw (Splat Word, AV p250) + DIP("vspltw v%d,v%d,%u\n", vD_addr, vB_addr, UIMM_5); + DIP(" => not implemented\n"); + return False; + + case 0x30C: // vspltisb (Splat Immediate Signed B, AV p247) + DIP("vspltisb v%d,%d\n", vD_addr, (Char)SIMM_8); + DIP(" => not implemented\n"); + return False; + + case 0x34C: // vspltish (Splat Immediate Signed HW, AV p248) + DIP("vspltish v%d,%d\n", vD_addr, (Char)SIMM_8); + DIP(" => not implemented\n"); + return False; + + case 0x38C: // vspltisw (Splat Immediate Signed W, AV p249) + DIP("vspltisw v%d,%d\n", vD_addr, (Char)SIMM_8); + DIP(" => not implemented\n"); + return False; + + default: + vex_printf("dis_av_permute(PPC32)(opc2)\n"); + return False; + } + return True; +} + +/* + AltiVec Pack/Unpack Instructions +*/ +static Bool dis_av_pack ( UInt theInstr ) +{ + UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */ + UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */ + UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */ + UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */ + UInt opc2 = (theInstr >> 0) & 0x7FF; /* theInstr[0:10] */ + + if (opc1 != 0x4) { + vex_printf("dis_av_pack(PPC32)(instr)\n"); + return False; + } + + switch (opc2) { + /* Packing */ + case 0x00E: // vpkuhum (Pack Unsigned HW Unsigned Modulo, AV p224) + DIP("vpkuhum v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x04E: // vpkuwum (Pack Unsigned W Unsigned Modulo, AV p226) + DIP("vpkuwum v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x08E: // vpkuhus (Pack Unsigned HW Unsigned Saturate, AV p225) + DIP("vpkuhus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x0CE: // vpkuwus (Pack Unsigned W Unsigned Saturate, AV p227) + DIP("vpkuwus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x10E: // vpkshus (Pack Signed HW Unsigned Saturate, AV p221) + DIP("vpkshus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x14E: // vpkswus (Pack Signed W Unsigned Saturate, AV p223) + DIP("vpkswus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x18E: // vpkshss (Pack Signed HW Signed Saturate, AV p220) + DIP("vpkshss v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x1CE: // vpkswss (Pack Signed W Signed Saturate, AV p222) + DIP("vpkswss v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x30E: // vpkpx (Pack Pixel, AV p219) + DIP("vpkpx v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + default: + break; // Fall through... + } + + + if (vA_addr != 0) { + vex_printf("dis_av_pack(PPC32)(vA_addr)\n"); + return False; + } + + switch (opc2) { + /* Unpacking */ + case 0x20E: // vupkhsb (Unpack High Signed B, AV p277) + DIP("vupkhsb v%d,v%d\n", vD_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x24E: // vupkhsh (Unpack High Signed HW, AV p278) + DIP("vupkhsh v%d,v%d\n", vD_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x28E: // vupklsb (Unpack Low Signed B, AV p280) + DIP("vupklsb v%d,v%d\n", vD_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x2CE: // vupklsh (Unpack Low Signed HW, AV p281) + DIP("vupklsh v%d,v%d\n", vD_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x34E: // vupkhpx (Unpack High Pixel16, AV p276) + DIP("vupkhpx v%d,v%d\n", vD_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x3CE: // vupklpx (Unpack Low Pixel16, AV p279) + DIP("vupklpx v%d,v%d\n", vD_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + default: + vex_printf("dis_av_pack(PPC32)(opc2)\n"); + return False; + } + return True; +} + + +/* + AltiVec Floating Point Arithmetic Instructions +*/ +static Bool dis_av_fp_arith ( UInt theInstr ) +{ + UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */ + UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */ + UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */ + UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */ + UChar vC_addr = toUChar((theInstr >> 6) & 0x1F); /* theInstr[6:10] */ + UInt opc2=0; + + if (opc1 != 0x4) { + vex_printf("dis_av_fp_arith(PPC32)(instr)\n"); + return False; + } + + opc2 = (theInstr) & 0x3F; /* theInstr[0:5] */ + switch (opc2) { + case 0x2E: // vmaddfp (Multiply Add FP, AV p177) + DIP("vmaddfp v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vC_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x2F: // vnmsubfp (Negative Multiply-Subtract FP, AV p215) + DIP("vnmsubfp v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vC_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + default: + break; // Fall through... + } + + opc2 = (theInstr) & 0x7FF; /* theInstr[0:10] */ + switch (opc2) { + case 0x00A: // vaddfp (Add FP, AV p137) + DIP("vaddfp v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x04A: // vsubfp (Subtract FP, AV p261) + DIP("vsubfp v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x40A: // vmaxfp (Maximum FP, AV p178) + DIP("vmaxfp v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x44A: // vminfp (Minimum FP, AV p187) + DIP("vminfp v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + default: + break; // Fall through... + } + + + if (vA_addr != 0) { + vex_printf("dis_av_fp_arith(PPC32)(vA_addr)\n"); + return False; + } + + switch (opc2) { + case 0x10A: // vrefp (Reciprocal Esimate FP, AV p228) + DIP("vrefp v%d,v%d\n", vD_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x14A: // vrsqrtefp (Reciprocal Square Root Estimate FP, AV p237) + DIP("vrsqrtefp v%d,v%d\n", vD_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x18A: // vexptefp (2 Raised to the Exp Est FP, AV p173) + DIP("vexptefp v%d,v%d\n", vD_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x1CA: // vlogefp (Log2 Estimate FP, AV p175) + DIP("vlogefp v%d,v%d\n", vD_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + default: + vex_printf("dis_av_fp_arith(PPC32)(opc2=0x%x)\n",opc2); + return False; + } + return True; +} + +/* + AltiVec Floating Point Compare Instructions +*/ +static Bool dis_av_fp_cmp ( UInt theInstr ) +{ + UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */ + UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */ + UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */ + UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */ + UChar flag_Rc = toUChar((theInstr >> 10) & 0x1); /* theInstr[10] */ + UInt opc2 = (theInstr >> 0) & 0x3FF; /* theInstr[0:9] */ + + if (opc1 != 0x4) { + vex_printf("dis_av_fp_cmp(PPC32)(instr)\n"); + return False; + } + + switch (opc2) { + case 0x0C6: // vcmpeqfp (Compare Equal-to FP, AV p159) + DIP("vcmpeqfp%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x1C6: // vcmpgefp (Compare Greater-than-or-Equal-to FP, AV p163) + DIP("vcmpgefp%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x2C6: // vcmpgtfp (Compare Greater-than FP, AV p164) + DIP("vcmpgtfp%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x3C6: // vcmpbfp (Compare Bounds FP, AV p157) + DIP("vcmpbfp%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + default: + vex_printf("dis_av_fp_cmp(PPC32)(opc2)\n"); + return False; + } + return True; +} + +/* + AltiVec Floating Point Convert/Round Instructions +*/ +static Bool dis_av_fp_convert ( UInt theInstr ) +{ + UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */ + UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */ + UChar UIMM_5 = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */ + UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */ + UInt opc2 = (theInstr >> 0) & 0x7FF; /* theInstr[0:10] */ + + if (opc1 != 0x4) { + vex_printf("dis_av_fp_convert(PPC32)(instr)\n"); + return False; + } + + switch (opc2) { + case 0x30A: // vcfux (Convert from Unsigned Fixed-Point W, AV p156) + DIP("vcfux v%d,v%d,%u\n", vD_addr, vB_addr, UIMM_5); + DIP(" => not implemented\n"); + return False; + + case 0x34A: // vcfsx (Convert from Signed Fixed-Point W, AV p155) + DIP("vcfsx v%d,v%d,%u\n", vD_addr, vB_addr, UIMM_5); + DIP(" => not implemented\n"); + return False; + + case 0x38A: // vctuxs (Convert to Unsigned Fixed-Point W Saturate, AV p172) + DIP("vctuxs v%d,v%d,%u\n", vD_addr, vB_addr, UIMM_5); + DIP(" => not implemented\n"); + return False; + + case 0x3CA: // vctsxs (Convert to Signed Fixed-Point W Saturate, AV p171) + DIP("vctsxs v%d,v%d,%u\n", vD_addr, vB_addr, UIMM_5); + DIP(" => not implemented\n"); + return False; + + default: + break; // Fall through... + } + + if (UIMM_5 != 0) { + vex_printf("dis_av_fp_convert(PPC32)(UIMM_5)\n"); + return False; + } + + switch (opc2) { + case 0x20A: // vrfin (Round to FP Integer Nearest, AV p231) + DIP("vrfin v%d,v%d\n", vD_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x24A: // vrfiz (Round to FP Integer toward zero, AV p233) + DIP("vrfiz v%d,v%d\n", vD_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x28A: // vrfip (Round to FP Integer toward +inf, AV p232) + DIP("vrfip v%d,v%d\n", vD_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + case 0x2CA: // vrfim (Round to FP Integer toward -inf, AV p230) + DIP("vrfim v%d,v%d\n", vD_addr, vB_addr); + DIP(" => not implemented\n"); + return False; + + default: + vex_printf("dis_av_fp_convert(PPC32)(opc2)\n"); + return False; + } + return True; +} + + + + + + +/*------------------------------------------------------------*/ +/*--- Disassemble a single instruction ---*/ +/*------------------------------------------------------------*/ + +/* Disassemble a single instruction into IR. The instruction + is located in host memory at &guest_code[delta]. + Set *size to be the size of the instruction. + If the returned value is Dis_Resteer, + the next guest address is assigned to *whereNext. If resteerOK + is False, disInstr may not return Dis_Resteer. */ + +static DisResult disInstr ( /*IN*/ Bool resteerOK, + /*IN*/ Bool (*resteerOkFn) ( Addr64 ), + /*IN*/ UInt delta, + /*OUT*/ Int* size, + /*OUT*/ Addr64* whereNext ) +{ + UChar opc1; + UInt opc2; + DisResult whatNext = Dis_Continue; + UInt theInstr; + + + /* At least this is simple on PPC32: insns are all 4 bytes long, and + 4-aligned. So just fish the whole thing out of memory right now + and have done. */ + + /* We will set *size to 4 if the insn is successfully decoded. + Setting it to 0 by default makes bbToIR_PPC32 abort if we fail the + decode. */ + *size = 0; + + theInstr = getUIntBigendianly( (UChar*)(&guest_code[delta]) ); + + DIP("\t0x%x: ", guest_pc_bbstart+delta); + + + /* Spot the client-request magic sequence. */ + // Essentially a v. unlikely sequence of noops that we can catch + { + UInt* code = (UInt*)(guest_code + delta); + + /* Spot this: + 0x7C03D808 tw 0,3,27 => trap word if(0) => nothing + 0x5400E800 rlwinm 0,0,29,0,0 => r0 = rotl(r0,29) + 0x54001800 rlwinm 0,0,3,0,0 => r0 = rotl(r0,3) + 0x54006800 rlwinm 0,0,13,0,0 => r0 = rotl(r0,13) + 0x54009800 rlwinm 0,0,19,0,0 => r0 = rotl(r0,19) + 0x60000000 nop + */ + if (code[0] == 0x7C03D808 && + code[1] == 0x5400E800 && + code[2] == 0x54001800 && + code[3] == 0x54006800 && + code[4] == 0x54009800 && + code[5] == 0x60000000) { + DIP("%%r3 = client_request ( %%r31 )\n"); + *size = 24; + delta += 24; + + irbb->next = mkU32(guest_pc_bbstart+delta); + irbb->jumpkind = Ijk_ClientReq; + whatNext = Dis_StopHere; + goto decode_success; + } + } + + + opc1 = toUChar((theInstr >> 26) & 0x3F ); /* theInstr[26:31] */ + opc2 = ((theInstr >> 1 ) & 0x3FF); /* theInstr[1:10] */ + +#if PPC32_TOIR_DEBUG + vex_printf("\ndisInstr(ppc32): instr: 0x%x\n", theInstr); + vex_printf("disInstr(ppc32): instr: "); + vex_printf_binary( theInstr, 32, True ); + vex_printf("\n"); +#endif + + + // Note: all 'reserved' bits must be cleared, else invalid + switch (opc1) { + + /* Integer Arithmetic Instructions */ + case 0x0C: case 0x0D: case 0x0E: // addic, addic., addi + case 0x0F: case 0x07: case 0x08: // addis, mulli, subfic + if (dis_int_arith( theInstr )) goto decode_success; + goto decode_failure; + + /* Integer Compare Instructions */ + case 0x0B: case 0x0A: // cmpi, cmpli + if (dis_int_cmp( theInstr )) goto decode_success; + goto decode_failure; + + /* Integer Logical Instructions */ + case 0x1C: case 0x1D: case 0x18: // andi., andis., ori + case 0x19: case 0x1A: case 0x1B: // oris, xori, xoris + if (dis_int_logic( theInstr )) goto decode_success; + goto decode_failure; + + /* Integer Rotate Instructions */ + case 0x14: case 0x15: case 0x17: // rlwimi, rlwinm, rlwnm + if (dis_int_rot( theInstr )) goto decode_success; + goto decode_failure; + + /* Integer Load Instructions */ + case 0x22: case 0x23: case 0x2A: // lbz, lbzu, lha + case 0x2B: case 0x28: case 0x29: // lhau, lhz, lhzu + case 0x20: case 0x21: // lwz, lwzu + if (dis_int_load( theInstr )) goto decode_success; + goto decode_failure; + + /* Integer Store Instructions */ + case 0x26: case 0x27: case 0x2C: // stb, stbu, sth + case 0x2D: case 0x24: case 0x25: // sthu, stw, stwu + if (dis_int_store( theInstr )) goto decode_success; + goto decode_failure; + + /* Integer Load and Store Multiple Instructions */ + case 0x2E: case 0x2F: // lmw, stmw + if (dis_int_ldst_mult( theInstr )) goto decode_success; + goto decode_failure; + + /* Branch Instructions */ + case 0x12: case 0x10: // b, bc + if (dis_branch(theInstr, &whatNext)) goto decode_success; + goto decode_failure; + + /* System Linkage Instructions */ + case 0x11: // sc + if (dis_syslink(theInstr, &whatNext)) goto decode_success; + goto decode_failure; + + /* Trap Instructions */ + case 0x03: // twi + DIP("trap op (twi) => not implemented\n"); + goto decode_failure; + + /* Floating Point Load Instructions */ + case 0x30: case 0x31: case 0x32: // lfs, lfsu, lfd + case 0x33: // lfdu + if (dis_fp_load( theInstr )) goto decode_success; + goto decode_failure; + + /* Floating Point Store Instructions */ + case 0x34: case 0x35: case 0x36: // stfsx, stfsux, stfdx + case 0x37: // stfdux + if (dis_fp_store( theInstr )) goto decode_success; + goto decode_failure; + + case 0x3B: + opc2 = (theInstr >> 1) & 0x1F; /* theInstr[1:5] */ + switch (opc2) { + /* Floating Point Arith Instructions */ + case 0x12: case 0x14: case 0x15: // fdivs, fsubs, fadds + case 0x16: case 0x18: case 0x19: // fsqrts, fres, fmuls + if (dis_fp_arith(theInstr)) goto decode_success; + goto decode_failure; + + /* Floating Point Mult-Add Instructions */ + case 0x1C: case 0x1D: case 0x1E: // fmsubs, fmadds, fnmsubs + case 0x1F: // fnmadds + if (dis_fp_multadd(theInstr)) goto decode_success; + goto decode_failure; + + default: + goto decode_failure; + } + break; + + case 0x3F: + /* Instrs using opc[1:5] never overlap with instrs using opc[1:10], + so we can simply fall through the first switch statement */ opc2 = (theInstr >> 1) & 0x1F; /* theInstr[1:5] */ switch (opc2) { @@ -4558,6 +5906,7 @@ static DisResult disInstr ( /*IN*/ Bool resteerOK, case 0x0C8: // subfze if (dis_int_arith( theInstr )) goto decode_success; goto decode_failure; + default: break; // Fall through... } @@ -4636,7 +5985,7 @@ static DisResult disInstr ( /*IN*/ Bool resteerOK, goto decode_failure; /* Trap Instructions */ - case 0x004: // tw + case 0x004: // tw DIP("trap op (tw) => not implemented\n"); goto decode_failure; @@ -4652,9 +6001,165 @@ static DisResult disInstr ( /*IN*/ Bool resteerOK, if (dis_fp_store( theInstr )) goto decode_success; goto decode_failure; + + /* AltiVec instructions */ + + /* AV Cache Control - Data streams */ + case 0x156: case 0x176: case 0x336: // dst, dstst, dss + if (dis_av_datastream( theInstr )) goto decode_success; + goto decode_failure; + + /* AV Load */ + case 0x006: case 0x026: // lvsl, lvsr + case 0x007: case 0x027: case 0x047: // lvebx, lvehx, lvewx + case 0x067: case 0x167: // lvx, lvxl + if (dis_av_load( theInstr )) goto decode_success; + goto decode_failure; + + /* AV Store */ + case 0x087: case 0x0A7: case 0x0C7: // stvebx, stvehx, stvewx + case 0x0E7: case 0x1E7: // stvx, stvxl + if (dis_av_store( theInstr )) goto decode_success; + goto decode_failure; + + default: + goto decode_failure; + } + break; + + + case 0x04: /* AltiVec instructions */ - case 0x0E7: // stvx - DIP("Altivec op (stvx) => not implemented\n"); + + opc2 = (theInstr) & 0x3F; /* theInstr[0:5] */ + switch (opc2) { + /* AV Mult-Add, Mult-Sum */ + case 0x20: case 0x21: case 0x22: // vmhaddshs, vmhraddshs, vmladduhm + case 0x24: case 0x25: case 0x26: // vmsumubm, vmsummbm, vmsumuhm + case 0x27: case 0x28: case 0x29: // vmsumuhs, vmsumshm, vmsumshs + if (dis_av_multarith( theInstr )) goto decode_success; + goto decode_failure; + + /* AV Permutations */ + case 0x2A: // vsel + case 0x2B: // vperm + if (dis_av_permute( theInstr )) goto decode_success; + goto decode_failure; + + /* AV Shift */ + case 0x2C: // vsldoi + if (dis_av_shift( theInstr )) goto decode_success; + goto decode_failure; + + /* AV Floating Point Mult-Add/Sub */ + case 0x2E: case 0x2F: // vmaddfp, vnmsubfp + if (dis_av_fp_arith( theInstr )) goto decode_success; + goto decode_failure; + + default: + break; // Fall through... + } + + opc2 = (theInstr) & 0x7FF; /* theInstr[0:10] */ + switch (opc2) { + /* AV Arithmetic */ + case 0x180: // vaddcuw + case 0x000: case 0x040: case 0x080: // vaddubm, vadduhm, vadduwm + case 0x200: case 0x240: case 0x280: // vaddubs, vadduhs, vadduws + case 0x300: case 0x340: case 0x380: // vaddsbs, vaddshs, vaddsws + case 0x580: // vsubcuw + case 0x400: case 0x440: case 0x480: // vsububm, vsubuhm, vsubuwm + case 0x600: case 0x640: case 0x680: // vsububs, vsubuhs, vsubuws + case 0x700: case 0x740: case 0x780: // vsubsbs, vsubshs, vsubsws + case 0x402: case 0x442: case 0x482: // vavgub, vavguh, vavguw + case 0x502: case 0x542: case 0x582: // vavgsb, vavgsh, vavgsw + case 0x002: case 0x042: case 0x082: // vmaxub, vmaxuh, vmaxuw + case 0x102: case 0x142: case 0x182: // vmaxsb, vmaxsh, vmaxsw + case 0x202: case 0x242: case 0x282: // vminub, vminuh, vminuw + case 0x302: case 0x342: case 0x382: // vminsb, vminsh, vminsw + case 0x008: case 0x048: // vmuloub, vmulouh + case 0x108: case 0x148: // vmulosb, vmulosh + case 0x208: case 0x248: // vmuleub, vmuleuh + case 0x308: case 0x348: // vmulesb, vmulesh + case 0x608: case 0x708: case 0x648: // vsum4ubs, vsum4sbs, vsum4shs + case 0x688: case 0x788: // vsum2sws, vsumsws + if (dis_av_arith( theInstr )) goto decode_success; + goto decode_failure; + + /* AV Rotate, Shift */ + case 0x004: case 0x044: case 0x084: // vrlb, vrlh, vrlw + case 0x104: case 0x144: case 0x184: // vslb, vslh, vslw + case 0x204: case 0x244: case 0x284: // vsrb, vsrh, vsrw + case 0x304: case 0x344: case 0x384: // vsrab, vsrah, vsraw + case 0x1C4: case 0x2C4: // vsl, vsr + case 0x40C: case 0x44C: // vslo, vsro + if (dis_av_shift( theInstr )) goto decode_success; + goto decode_failure; + + /* AV Logic */ + case 0x404: case 0x444: case 0x484: // vand, vandc, vor + case 0x4C4: case 0x504: // vxor, vnor + if (dis_av_logic( theInstr )) goto decode_success; + goto decode_failure; + + /* AV Processor Control */ + case 0x604: case 0x644: // mfvscr, mtvscr + if (dis_av_procctl( theInstr )) goto decode_success; + goto decode_failure; + + /* AV Floating Point Arithmetic */ + case 0x00A: case 0x04A: // vaddfp, vsubfp + case 0x10A: case 0x14A: case 0x18A: // vrefp, vrsqrtefp, vexptefp + case 0x1CA: // vlogefp + case 0x40A: case 0x44A: // vmaxfp, vminfp + if (dis_av_fp_arith( theInstr )) goto decode_success; + goto decode_failure; + + /* AV Floating Point Round/Convert */ + case 0x20A: case 0x24A: case 0x28A: // vrfin, vrfiz, vrfip + case 0x2CA: // vrfim + case 0x30A: case 0x34A: case 0x38A: // vcfux, vcfsx, vctuxs + case 0x3CA: // vctsxs + if (dis_av_fp_convert( theInstr )) goto decode_success; + goto decode_failure; + + /* AV Merge, Splat */ + case 0x00C: case 0x04C: case 0x08C: // vmrghb, vmrghh, vmrghw + case 0x10C: case 0x14C: case 0x18C: // vmrglb, vmrglh, vmrglw + case 0x20C: case 0x24C: case 0x28C: // vspltb, vsplth, vspltw + case 0x30C: case 0x34C: case 0x38C: // vspltisb, vspltish, vspltisw + if (dis_av_permute( theInstr )) goto decode_success; + goto decode_failure; + + /* AV Pack, Unpack */ + case 0x00E: case 0x04E: case 0x08E: // vpkuhum, vpkuwum, vpkuhus + case 0x0CE: // vpkuwus + case 0x10E: case 0x14E: case 0x18E: // vpkshus, vpkswus, vpkshss + case 0x1CE: // vpkswss + case 0x20E: case 0x24E: case 0x28E: // vupkhsb, vupkhsh, vupklsb + case 0x2CE: // vupklsh + case 0x30E: case 0x34E: case 0x3CE: // vpkpx, vupkhpx, vupklpx + if (dis_av_pack( theInstr )) goto decode_success; + goto decode_failure; + + default: + break; // Fall through... + } + + opc2 = (theInstr) & 0x3FF; /* theInstr[0:9] (Bit 10 = Rc)*/ + switch (opc2) { + + /* AV Compare */ + case 0x006: case 0x046: case 0x086: // vcmpequb, vcmpequh, vcmpequw + case 0x206: case 0x246: case 0x286: // vcmpgtub, vcmpgtuh, vcmpgtuw + case 0x306: case 0x346: case 0x386: // vcmpgtsb, vcmpgtsh, vcmpgtsw + if (dis_av_cmp( theInstr )) goto decode_success; + goto decode_failure; + + /* AV Floating Point Compare */ + case 0x0C6: case 0x1C6: case 0x2C6: // vcmpeqfp, vcmpgefp, vcmpgtfp + case 0x3C6: // vcmpbfp + if (dis_av_fp_cmp( theInstr )) goto decode_success; goto decode_failure; default: