blob: 14656e12db4aef7d2fbbb1cfea1170e51b531cb2 [file] [log] [blame]
cerion896a1372005-01-25 12:24:25 +00001
2/*--------------------------------------------------------------------*/
3/*--- ---*/
cerion1515db92005-01-25 17:21:23 +00004/*--- This file (guest-ppc32/toIR.c) is ---*/
sewardjdbcfae72005-08-02 11:14:04 +00005/*--- Copyright (C) OpenWorks LLP. All rights reserved. ---*/
cerion896a1372005-01-25 12:24:25 +00006/*--- ---*/
7/*--------------------------------------------------------------------*/
8
9/*
10 This file is part of LibVEX, a library for dynamic binary
11 instrumentation and translation.
12
sewardj7bd6ffe2005-08-03 16:07:36 +000013 Copyright (C) 2004-2005 OpenWorks LLP. All rights reserved.
cerion896a1372005-01-25 12:24:25 +000014
sewardj7bd6ffe2005-08-03 16:07:36 +000015 This library is made available under a dual licensing scheme.
cerion896a1372005-01-25 12:24:25 +000016
sewardj7bd6ffe2005-08-03 16:07:36 +000017 If you link LibVEX against other code all of which is itself
18 licensed under the GNU General Public License, version 2 dated June
19 1991 ("GPL v2"), then you may use LibVEX under the terms of the GPL
20 v2, as appearing in the file LICENSE.GPL. If the file LICENSE.GPL
21 is missing, you can obtain a copy of the GPL v2 from the Free
22 Software Foundation Inc., 51 Franklin St, Fifth Floor, Boston, MA
23 02110-1301, USA.
24
25 For any other uses of LibVEX, you must first obtain a commercial
26 license from OpenWorks LLP. Please contact info@open-works.co.uk
27 for information about commercial licensing.
28
29 This software is provided by OpenWorks LLP "as is" and any express
30 or implied warranties, including, but not limited to, the implied
31 warranties of merchantability and fitness for a particular purpose
32 are disclaimed. In no event shall OpenWorks LLP be liable for any
33 direct, indirect, incidental, special, exemplary, or consequential
34 damages (including, but not limited to, procurement of substitute
35 goods or services; loss of use, data, or profits; or business
36 interruption) however caused and on any theory of liability,
37 whether in contract, strict liability, or tort (including
38 negligence or otherwise) arising in any way out of the use of this
39 software, even if advised of the possibility of such damage.
cerion896a1372005-01-25 12:24:25 +000040
41 Neither the names of the U.S. Department of Energy nor the
42 University of California nor the names of its contributors may be
43 used to endorse or promote products derived from this software
44 without prior written permission.
cerion896a1372005-01-25 12:24:25 +000045*/
46
sewardjb51f0f42005-07-18 11:38:02 +000047/* TODO 2005 07 15:
48
sewardje14bb9f2005-07-22 09:39:02 +000049 Spot rlwini cases which are simply left/right shifts and
50 emit Shl32/Shr32 accordingly.
51
52 Move mtxer/mfxer code into its own function.
sewardj87e651f2005-09-09 08:31:18 +000053
54 LIMITATIONS:
55
56 Various, including:
57
58 - Some invalid forms of lswi and lswx are accepted when they should
59 not be.
60
sewardjb51f0f42005-07-18 11:38:02 +000061*/
62
63
cerion1515db92005-01-25 17:21:23 +000064/* Translates PPC32 code to IR. */
cerion896a1372005-01-25 12:24:25 +000065
cerion645c9302005-01-31 10:09:59 +000066/* References
ceriona982c052005-06-28 17:23:09 +000067
68#define PPC32
cerion645c9302005-01-31 10:09:59 +000069 "PowerPC Microprocessor Family:
cerione9d361a2005-03-04 17:35:29 +000070 The Programming Environments for 32-Bit Microprocessors"
71 02/21/2000
72 http://www-3.ibm.com/chips/techlib/techlib.nsf/techdocs/852569B20050FF778525699600719DF2
73
ceriona982c052005-06-28 17:23:09 +000074#define AV
75 "PowerPC Microprocessor Family:
76 AltiVec(TM) Technology Programming Environments Manual"
77 07/10/2003
78 http://www-3.ibm.com/chips/techlib/techlib.nsf/techdocs/FBFA164F824370F987256D6A006F424D
79
cerione9d361a2005-03-04 17:35:29 +000080 Other refs:
81 "PowerPC Microprocessor Family:
cerion645c9302005-01-31 10:09:59 +000082 Programming Environments Manual for 64 and 32-Bit Microprocessors
83 Version 2.0"
cerion26d07b22005-02-02 17:13:28 +000084 06/10/2003
cerion645c9302005-01-31 10:09:59 +000085 http://www-3.ibm.com/chips/techlib/techlib.nsf/techdocs/F6153E213FDD912E87256D49006C6541
86*/
87
cerion896a1372005-01-25 12:24:25 +000088#include "libvex_basictypes.h"
89#include "libvex_ir.h"
90#include "libvex.h"
cerion1515db92005-01-25 17:21:23 +000091#include "libvex_guest_ppc32.h"
cerion896a1372005-01-25 12:24:25 +000092
93#include "main/vex_util.h"
94#include "main/vex_globals.h"
sewardj9e6491a2005-07-02 19:24:10 +000095#include "guest-generic/bb_to_IR.h"
cerion1515db92005-01-25 17:21:23 +000096#include "guest-ppc32/gdefs.h"
cerion896a1372005-01-25 12:24:25 +000097
98
99/*------------------------------------------------------------*/
100/*--- Globals ---*/
101/*------------------------------------------------------------*/
102
sewardj9e6491a2005-07-02 19:24:10 +0000103/* These are set at the start of the translation of an insn, right
104 down in disInstr_PPC32, so that we don't have to pass them around
105 endlessly. They are all constant during the translation of any
106 given insn. */
cerion896a1372005-01-25 12:24:25 +0000107
cerioned623db2005-06-20 12:42:04 +0000108/* We need to know this to do sub-register accesses correctly. */
cerioned623db2005-06-20 12:42:04 +0000109static Bool host_is_bigendian;
110
cerion896a1372005-01-25 12:24:25 +0000111/* Pointer to the guest code area. */
cerion896a1372005-01-25 12:24:25 +0000112static UChar* guest_code;
113
114/* The guest address corresponding to guest_code[0]. */
sewardj9e6491a2005-07-02 19:24:10 +0000115static Addr32 guest_CIA_bbstart;
cerion896a1372005-01-25 12:24:25 +0000116
sewardj01a9e802005-02-01 20:46:00 +0000117/* The guest address for the instruction currently being
118 translated. */
sewardj9e6491a2005-07-02 19:24:10 +0000119static Addr32 guest_CIA_curr_instr;
sewardj01a9e802005-02-01 20:46:00 +0000120
cerion896a1372005-01-25 12:24:25 +0000121/* The IRBB* into which we're generating code. */
122static IRBB* irbb;
123
124
125/*------------------------------------------------------------*/
126/*--- Debugging output ---*/
127/*------------------------------------------------------------*/
128
cerione9d361a2005-03-04 17:35:29 +0000129#define PPC32_TOIR_DEBUG 0
130
cerion896a1372005-01-25 12:24:25 +0000131#define DIP(format, args...) \
132 if (vex_traceflags & VEX_TRACE_FE) \
133 vex_printf(format, ## args)
134
135#define DIS(buf, format, args...) \
136 if (vex_traceflags & VEX_TRACE_FE) \
137 vex_sprintf(buf, format, ## args)
138
139
cerion896a1372005-01-25 12:24:25 +0000140/*------------------------------------------------------------*/
cerion38674602005-02-08 02:19:25 +0000141/*--- Offsets of various parts of the ppc32 guest state. ---*/
cerion896a1372005-01-25 12:24:25 +0000142/*------------------------------------------------------------*/
143
cerion91ad5362005-01-27 23:02:41 +0000144#define OFFB_CIA offsetof(VexGuestPPC32State,guest_CIA)
145#define OFFB_LR offsetof(VexGuestPPC32State,guest_LR)
146#define OFFB_CTR offsetof(VexGuestPPC32State,guest_CTR)
147
sewardjb51f0f42005-07-18 11:38:02 +0000148#define OFFB_XER_SO offsetof(VexGuestPPC32State,guest_XER_SO)
sewardj20ef5472005-07-21 14:48:31 +0000149#define OFFB_XER_OV offsetof(VexGuestPPC32State,guest_XER_OV)
sewardjb51f0f42005-07-18 11:38:02 +0000150#define OFFB_XER_CA offsetof(VexGuestPPC32State,guest_XER_CA)
sewardj20ef5472005-07-21 14:48:31 +0000151#define OFFB_XER_BC offsetof(VexGuestPPC32State,guest_XER_BC)
cerion91ad5362005-01-27 23:02:41 +0000152
cerion094d1392005-06-20 13:45:57 +0000153#define OFFB_FPROUND offsetof(VexGuestPPC32State,guest_FPROUND)
154
ceriona982c052005-06-28 17:23:09 +0000155#define OFFB_VRSAVE offsetof(VexGuestPPC32State,guest_VRSAVE)
156#define OFFB_VSCR offsetof(VexGuestPPC32State,guest_VSCR)
157
cerion094d1392005-06-20 13:45:57 +0000158#define OFFB_EMWARN offsetof(VexGuestPPC32State,guest_EMWARN)
159
sewardj7ce9d152005-03-15 16:54:13 +0000160#define OFFB_TISTART offsetof(VexGuestPPC32State,guest_TISTART)
161#define OFFB_TILEN offsetof(VexGuestPPC32State,guest_TILEN)
cerion91ad5362005-01-27 23:02:41 +0000162
sewardj7787af42005-08-04 18:32:19 +0000163#define OFFB_RESVN offsetof(VexGuestPPC32State,guest_RESVN)
164
cerion91ad5362005-01-27 23:02:41 +0000165
cerion38674602005-02-08 02:19:25 +0000166/*------------------------------------------------------------*/
sewardjb51f0f42005-07-18 11:38:02 +0000167/*--- Extract instruction fields --- */
cerion38674602005-02-08 02:19:25 +0000168/*------------------------------------------------------------*/
cerione9d361a2005-03-04 17:35:29 +0000169
sewardjb51f0f42005-07-18 11:38:02 +0000170/* Extract primary opcode, instr[31:26] */
171static UInt ifieldOPC ( UInt instr ) {
172 return (instr >> 26) & 0x3F;
173}
cerione9d361a2005-03-04 17:35:29 +0000174
sewardjb51f0f42005-07-18 11:38:02 +0000175/* Extract 10-bit secondary opcode, instr[11:1] */
176static UInt ifieldOPClo10 ( UInt instr) {
177 return (instr >> 1 ) & 0x3FF;
178}
cerione9d361a2005-03-04 17:35:29 +0000179
sewardjb51f0f42005-07-18 11:38:02 +0000180/* Extract RD (destination register) field, instr[25:21] */
181static UInt ifieldRD ( UInt instr ) {
182 return (instr >> 21) & 0x1F;
183}
cerion094d1392005-06-20 13:45:57 +0000184
sewardjb51f0f42005-07-18 11:38:02 +0000185/* Extract RA (first source register) field, instr[20:16] */
186static UInt ifieldRA ( UInt instr ) {
187 return (instr >> 16) & 0x1F;
188}
189
190/* Extract RB (first source register) field, instr[15:11] */
191static UInt ifieldRB ( UInt instr ) {
192 return (instr >> 11) & 0x1F;
193}
194
195/* Extract bottom bit (Rc?) from instr */
196static UInt ifieldBIT0 ( UInt instr ) {
197 return instr & 1;
198}
199
200/* Extract lower half of instruction and sign extent to 32 bits */
201static Int ifieldSIMM16 ( UInt instr ) {
202 Int i = instr & 0xFFFF;
203 return (i << 16) >> 16;
204}
205
206
207//zz /*------------------------------------------------------------*/
208//zz /*--- Abstract register interface (non-gpr|fpr) --- */
209//zz /*------------------------------------------------------------*/
210//zz
211//zz /* Offsets of bitfields within various ppc32 registers */
212//zz #define SHIFT_XER_SO 31
213//zz #define SHIFT_XER_OV 30
214//zz #define SHIFT_XER_CA 29
215//zz #define SHIFT_XER_BC 0
216//zz
217//zz #define SHIFT_CR_LT 8
218//zz #define SHIFT_CR_GT 4
219//zz #define SHIFT_CR_EQ 2
220//zz #define SHIFT_CR_SO 1
sewardje14bb9f2005-07-22 09:39:02 +0000221
222#define SHIFT_FPSCR_RN 0
223#define MASK_FPSCR_RN (3 << SHIFT_FPSCR_RN)
224
sewardjb51f0f42005-07-18 11:38:02 +0000225//zz #define SHIFT_VSCR_NJ 16
226//zz #define SHIFT_VSCR_SAT 0
ceriona982c052005-06-28 17:23:09 +0000227
cerion094d1392005-06-20 13:45:57 +0000228
cerione9d361a2005-03-04 17:35:29 +0000229// Special purpose (i.e. non-gpr/fpr) registers
230typedef enum {
231 PPC32_SPR_CIA, // Current Instruction Address
232 PPC32_SPR_LR, // Link Register
233 PPC32_SPR_CTR, // Count Register
sewardjb51f0f42005-07-18 11:38:02 +0000234//zz PPC32_SPR_XER, // Summary Overflow
235//zz PPC32_SPR_CR, // Condition Register
sewardje14bb9f2005-07-22 09:39:02 +0000236 PPC32_SPR_FPSCR, // Floating Point Status/Control Register
ceriona982c052005-06-28 17:23:09 +0000237 PPC32_SPR_VRSAVE, // Vector Save/Restore Register
cerion225a0342005-09-12 20:49:09 +0000238 PPC32_SPR_VSCR, // Vector Status and Control Register
sewardje14bb9f2005-07-22 09:39:02 +0000239 PPC32_SPR_MAX
cerione9d361a2005-03-04 17:35:29 +0000240} PPC32SPR;
241
sewardjb51f0f42005-07-18 11:38:02 +0000242//zz /*
243//zz Note on FPSCR: Floating Point Status and Control Register
244//zz
245//zz We're only keeping hold of fp rounding-mode bits, via guest_FPROUND
246//zz The rest of the FPSCR is set to 0x0, which corresponds to
247//zz 'all exceptions masked'
248//zz
249//zz FPSCR[29:31] => Exception Summaries
250//zz FPSCR[17:28] => Exceptions
251//zz FPSCR[16] => FPRF::Class Descriptor
252//zz FPSCR[12:15] => FPRF::Condition Code
253//zz FPSCR[11] => Unused (0)
254//zz FPSCR[8:10] => Exceptions
255//zz FPSCR[3:7] => Exception Control
256//zz FPSCR[2] => Non-IEEE mode
257//zz FPSCR[0:1] => Rounding Mode
258//zz
259//zz CAB: Perhaps necessary to record writes to FPRF ?
260//zz Set by dis_fp_cmp() instrs, also some fp arith/round/conv instrs.
261//zz Tested using dis_fp_scr(): e.g fpscr->cr, branch conditional...
262//zz */
263//zz
264//zz
265//zz /* Gets from SPR (non-GPR|FPR) registers */
266//zz static IRExpr* getReg_masked ( PPC32SPR reg, UInt mask );
267static IRExpr* getSPR ( PPC32SPR reg );
268//zz static IRExpr* getReg_field ( PPC32SPR reg, UInt field_idx );
269//zz static IRExpr* getReg_bit ( PPC32SPR reg, UInt bit_idx );
270//zz
271//zz /* Puts to SPR (non-GPR|FPR) registers */
272//zz static void putReg_masked ( PPC32SPR reg, IRExpr* src, UInt mask );
273static void putSPR ( PPC32SPR reg, IRExpr* src );
274//zz static void putReg_field ( PPC32SPR reg, IRExpr* src, UInt field_idx );
275//zz static void putReg_bit ( PPC32SPR reg, IRExpr* src, UInt bit_idx );
sewardje14bb9f2005-07-22 09:39:02 +0000276
277/* FP Helpers */
278static void put_emwarn ( IRExpr* e /* :: Ity_I32 */ );
cerion094d1392005-06-20 13:45:57 +0000279
cerion38674602005-02-08 02:19:25 +0000280
281
282
283/*------------------------------------------------------------*/
284/*--- Misc Helpers ---*/
285/*------------------------------------------------------------*/
286
287static UInt MASK( UInt begin, UInt end )
288{
cerionb85e8bb2005-02-16 08:54:33 +0000289 UInt m1 = ((UInt)(-1)) << begin;
290 UInt m2 = ((UInt)(-1)) << (end + 1);
291 UInt mask = m1 ^ m2;
292 if (begin > end) mask = ~mask; // wrap mask
293 return mask;
cerion38674602005-02-08 02:19:25 +0000294}
295
cerion32aad402005-09-10 12:02:24 +0000296#if PPC32_TOIR_DEBUG
297static void vex_printf_binary( UInt x, UInt len, Bool spaces )
298{
299 UInt i;
300 vassert(len > 0 && len <= 32);
301
302 for (i=len; i>0; i--) {
303 vex_printf("%d", ((x & (1<<(len-1))) != 0) );
304 x = x << 1;
305 if (((i-1)%4)==0 && (i > 1) && spaces) {
306 vex_printf(" ");
307 }
308 }
309}
310#endif
cerion38674602005-02-08 02:19:25 +0000311
cerion896a1372005-01-25 12:24:25 +0000312
cerion896a1372005-01-25 12:24:25 +0000313/*------------------------------------------------------------*/
314/*--- Helper bits and pieces for deconstructing the ---*/
sewardj684aa952005-01-30 12:52:14 +0000315/*--- ppc32 insn stream. ---*/
cerion896a1372005-01-25 12:24:25 +0000316/*------------------------------------------------------------*/
317
318/* Add a statement to the list held by "irbb". */
319static void stmt ( IRStmt* st )
320{
321 addStmtToIRBB( irbb, st );
322}
323
cerion896a1372005-01-25 12:24:25 +0000324/* Generate a new temporary of the given type. */
325static IRTemp newTemp ( IRType ty )
326{
sewardj496a58d2005-03-20 18:44:44 +0000327 vassert(isPlausibleIRType(ty));
cerion896a1372005-01-25 12:24:25 +0000328 return newIRTemp( irbb->tyenv, ty );
329}
cerion896a1372005-01-25 12:24:25 +0000330
cerion32aad402005-09-10 12:02:24 +0000331/* Various simple conversions */
332
333static UChar extend_s_5to8 ( UChar x )
334{
335 return toUChar((((Int)x) << 27) >> 27);
336}
337
sewardjb51f0f42005-07-18 11:38:02 +0000338//zz #if 0
339//zz static UInt extend_s_8to32( UInt x )
340//zz {
341//zz return (UInt)((((Int)x) << 24) >> 24);
342//zz }
343//zz #endif
cerion91ad5362005-01-27 23:02:41 +0000344
cerion896a1372005-01-25 12:24:25 +0000345static UInt extend_s_16to32 ( UInt x )
346{
347 return (UInt)((((Int)x) << 16) >> 16);
348}
cerion896a1372005-01-25 12:24:25 +0000349
cerion6b30d852005-06-24 11:25:46 +0000350static UInt extend_s_26to32 ( UInt x )
cerion896a1372005-01-25 12:24:25 +0000351{
cerion6b30d852005-06-24 11:25:46 +0000352 return (UInt)((((Int)x) << 6) >> 6);
cerion896a1372005-01-25 12:24:25 +0000353}
cerion896a1372005-01-25 12:24:25 +0000354
sewardj684aa952005-01-30 12:52:14 +0000355/* Do a big-endian load of a 32-bit word, regardless of the endianness
356 of the underlying host. */
cerioncf004462005-01-31 15:24:55 +0000357static UInt getUIntBigendianly ( UChar* p )
sewardj684aa952005-01-30 12:52:14 +0000358{
cerioncf004462005-01-31 15:24:55 +0000359 UInt w = 0;
sewardj684aa952005-01-30 12:52:14 +0000360 w = (w << 8) | p[0];
361 w = (w << 8) | p[1];
362 w = (w << 8) | p[2];
363 w = (w << 8) | p[3];
364 return w;
365}
366
cerion896a1372005-01-25 12:24:25 +0000367
368/*------------------------------------------------------------*/
369/*--- Helpers for constructing IR. ---*/
370/*------------------------------------------------------------*/
371
cerion896a1372005-01-25 12:24:25 +0000372static void assign ( IRTemp dst, IRExpr* e )
373{
374 stmt( IRStmt_Tmp(dst, e) );
375}
376
cerionae694622005-01-28 17:52:47 +0000377static void storeBE ( IRExpr* addr, IRExpr* data )
cerion896a1372005-01-25 12:24:25 +0000378{
sewardj7787af42005-08-04 18:32:19 +0000379 vassert(typeOfIRExpr(irbb->tyenv, addr) == Ity_I32);
sewardjaf1ceca2005-06-30 23:31:27 +0000380 stmt( IRStmt_Store(Iend_BE,addr,data) );
cerion896a1372005-01-25 12:24:25 +0000381}
382
383static IRExpr* unop ( IROp op, IRExpr* a )
384{
385 return IRExpr_Unop(op, a);
386}
387
388static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
389{
390 return IRExpr_Binop(op, a1, a2);
391}
392
393static IRExpr* mkexpr ( IRTemp tmp )
394{
395 return IRExpr_Tmp(tmp);
396}
397
sewardj7f080782005-07-27 00:22:15 +0000398//uu static IRExpr* mkU1 ( UInt i )
399//uu {
400//uu vassert(i < 2);
401//uu return IRExpr_Const(IRConst_U1( toBool(i) ));
402//uu }
cerion45552a92005-02-03 18:20:22 +0000403
sewardj684c0372005-02-07 02:33:58 +0000404static IRExpr* mkU8 ( UChar i )
cerion896a1372005-01-25 12:24:25 +0000405{
cerion896a1372005-01-25 12:24:25 +0000406 return IRExpr_Const(IRConst_U8(i));
407}
cerion896a1372005-01-25 12:24:25 +0000408
cerion896a1372005-01-25 12:24:25 +0000409static IRExpr* mkU32 ( UInt i )
410{
411 return IRExpr_Const(IRConst_U32(i));
412}
413
cerionae694622005-01-28 17:52:47 +0000414static IRExpr* loadBE ( IRType ty, IRExpr* data )
cerion896a1372005-01-25 12:24:25 +0000415{
sewardjaf1ceca2005-06-30 23:31:27 +0000416 return IRExpr_Load(Iend_BE,ty,data);
cerion896a1372005-01-25 12:24:25 +0000417}
cerion896a1372005-01-25 12:24:25 +0000418
sewardj20ef5472005-07-21 14:48:31 +0000419static IRExpr* mkOR1 ( IRExpr* arg1, IRExpr* arg2 )
420{
421 vassert(typeOfIRExpr(irbb->tyenv, arg1) == Ity_I1);
422 vassert(typeOfIRExpr(irbb->tyenv, arg2) == Ity_I1);
423 return
424 unop(Iop_32to1, binop(Iop_Or32, unop(Iop_1Uto32, arg1),
425 unop(Iop_1Uto32, arg2)));
426}
427
428static IRExpr* mkAND1 ( IRExpr* arg1, IRExpr* arg2 )
429{
430 vassert(typeOfIRExpr(irbb->tyenv, arg1) == Ity_I1);
431 vassert(typeOfIRExpr(irbb->tyenv, arg2) == Ity_I1);
432 return
433 unop(Iop_32to1, binop(Iop_And32, unop(Iop_1Uto32, arg1),
434 unop(Iop_1Uto32, arg2)));
435}
sewardjb51f0f42005-07-18 11:38:02 +0000436
437static Int integerGuestRegOffset ( UInt archreg )
cerion45b70ff2005-01-31 17:03:25 +0000438{
sewardjb51f0f42005-07-18 11:38:02 +0000439 vassert(archreg < 32);
440
441 // jrs: probably not necessary; only matters if we reference sub-parts
442 // of the ppc32 registers, but that isn't the case
443 // later: this might affect Altivec though?
444 vassert(host_is_bigendian);
445
446 switch (archreg) {
447 case 0: return offsetof(VexGuestPPC32State, guest_GPR0);
448 case 1: return offsetof(VexGuestPPC32State, guest_GPR1);
449 case 2: return offsetof(VexGuestPPC32State, guest_GPR2);
450 case 3: return offsetof(VexGuestPPC32State, guest_GPR3);
451 case 4: return offsetof(VexGuestPPC32State, guest_GPR4);
452 case 5: return offsetof(VexGuestPPC32State, guest_GPR5);
453 case 6: return offsetof(VexGuestPPC32State, guest_GPR6);
454 case 7: return offsetof(VexGuestPPC32State, guest_GPR7);
455 case 8: return offsetof(VexGuestPPC32State, guest_GPR8);
456 case 9: return offsetof(VexGuestPPC32State, guest_GPR9);
457 case 10: return offsetof(VexGuestPPC32State, guest_GPR10);
458 case 11: return offsetof(VexGuestPPC32State, guest_GPR11);
459 case 12: return offsetof(VexGuestPPC32State, guest_GPR12);
460 case 13: return offsetof(VexGuestPPC32State, guest_GPR13);
461 case 14: return offsetof(VexGuestPPC32State, guest_GPR14);
462 case 15: return offsetof(VexGuestPPC32State, guest_GPR15);
463 case 16: return offsetof(VexGuestPPC32State, guest_GPR16);
464 case 17: return offsetof(VexGuestPPC32State, guest_GPR17);
465 case 18: return offsetof(VexGuestPPC32State, guest_GPR18);
466 case 19: return offsetof(VexGuestPPC32State, guest_GPR19);
467 case 20: return offsetof(VexGuestPPC32State, guest_GPR20);
468 case 21: return offsetof(VexGuestPPC32State, guest_GPR21);
469 case 22: return offsetof(VexGuestPPC32State, guest_GPR22);
470 case 23: return offsetof(VexGuestPPC32State, guest_GPR23);
471 case 24: return offsetof(VexGuestPPC32State, guest_GPR24);
472 case 25: return offsetof(VexGuestPPC32State, guest_GPR25);
473 case 26: return offsetof(VexGuestPPC32State, guest_GPR26);
474 case 27: return offsetof(VexGuestPPC32State, guest_GPR27);
475 case 28: return offsetof(VexGuestPPC32State, guest_GPR28);
476 case 29: return offsetof(VexGuestPPC32State, guest_GPR29);
477 case 30: return offsetof(VexGuestPPC32State, guest_GPR30);
478 case 31: return offsetof(VexGuestPPC32State, guest_GPR31);
479 default: break;
480 }
481 vpanic("integerGuestRegOffset(ppc32,be)"); /*notreached*/
482}
483
484static IRExpr* getIReg ( UInt archreg )
485{
486 vassert(archreg < 32);
487 return IRExpr_Get( integerGuestRegOffset(archreg), Ity_I32 );
488}
489
490/* Ditto, but write to a reg instead. */
491static void putIReg ( UInt archreg, IRExpr* e )
492{
493 vassert(archreg < 32);
494 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I32);
495 stmt( IRStmt_Put(integerGuestRegOffset(archreg), e) );
496}
497
498
499static Int floatGuestRegOffset ( UInt archreg )
500{
501 vassert(archreg < 32);
502
503 switch (archreg) {
504 case 0: return offsetof(VexGuestPPC32State, guest_FPR0);
505 case 1: return offsetof(VexGuestPPC32State, guest_FPR1);
506 case 2: return offsetof(VexGuestPPC32State, guest_FPR2);
507 case 3: return offsetof(VexGuestPPC32State, guest_FPR3);
508 case 4: return offsetof(VexGuestPPC32State, guest_FPR4);
509 case 5: return offsetof(VexGuestPPC32State, guest_FPR5);
510 case 6: return offsetof(VexGuestPPC32State, guest_FPR6);
511 case 7: return offsetof(VexGuestPPC32State, guest_FPR7);
512 case 8: return offsetof(VexGuestPPC32State, guest_FPR8);
513 case 9: return offsetof(VexGuestPPC32State, guest_FPR9);
514 case 10: return offsetof(VexGuestPPC32State, guest_FPR10);
515 case 11: return offsetof(VexGuestPPC32State, guest_FPR11);
516 case 12: return offsetof(VexGuestPPC32State, guest_FPR12);
517 case 13: return offsetof(VexGuestPPC32State, guest_FPR13);
518 case 14: return offsetof(VexGuestPPC32State, guest_FPR14);
519 case 15: return offsetof(VexGuestPPC32State, guest_FPR15);
520 case 16: return offsetof(VexGuestPPC32State, guest_FPR16);
521 case 17: return offsetof(VexGuestPPC32State, guest_FPR17);
522 case 18: return offsetof(VexGuestPPC32State, guest_FPR18);
523 case 19: return offsetof(VexGuestPPC32State, guest_FPR19);
524 case 20: return offsetof(VexGuestPPC32State, guest_FPR20);
525 case 21: return offsetof(VexGuestPPC32State, guest_FPR21);
526 case 22: return offsetof(VexGuestPPC32State, guest_FPR22);
527 case 23: return offsetof(VexGuestPPC32State, guest_FPR23);
528 case 24: return offsetof(VexGuestPPC32State, guest_FPR24);
529 case 25: return offsetof(VexGuestPPC32State, guest_FPR25);
530 case 26: return offsetof(VexGuestPPC32State, guest_FPR26);
531 case 27: return offsetof(VexGuestPPC32State, guest_FPR27);
532 case 28: return offsetof(VexGuestPPC32State, guest_FPR28);
533 case 29: return offsetof(VexGuestPPC32State, guest_FPR29);
534 case 30: return offsetof(VexGuestPPC32State, guest_FPR30);
535 case 31: return offsetof(VexGuestPPC32State, guest_FPR31);
536 default: break;
537 }
538 vpanic("floatGuestRegOffset(ppc32)"); /*notreached*/
539}
540
541static IRExpr* getFReg ( UInt archreg )
542{
543 vassert(archreg < 32);
544 return IRExpr_Get( floatGuestRegOffset(archreg), Ity_F64 );
545}
546
547/* Ditto, but write to a reg instead. */
548static void putFReg ( UInt archreg, IRExpr* e )
549{
550 vassert(archreg < 32);
551 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_F64);
552 stmt( IRStmt_Put(floatGuestRegOffset(archreg), e) );
553}
554
555
556static Int vectorGuestRegOffset ( UInt archreg )
557{
558 vassert(archreg < 32);
559
560 switch (archreg) {
561 case 0: return offsetof(VexGuestPPC32State, guest_VR0);
562 case 1: return offsetof(VexGuestPPC32State, guest_VR1);
563 case 2: return offsetof(VexGuestPPC32State, guest_VR2);
564 case 3: return offsetof(VexGuestPPC32State, guest_VR3);
565 case 4: return offsetof(VexGuestPPC32State, guest_VR4);
566 case 5: return offsetof(VexGuestPPC32State, guest_VR5);
567 case 6: return offsetof(VexGuestPPC32State, guest_VR6);
568 case 7: return offsetof(VexGuestPPC32State, guest_VR7);
569 case 8: return offsetof(VexGuestPPC32State, guest_VR8);
570 case 9: return offsetof(VexGuestPPC32State, guest_VR9);
571 case 10: return offsetof(VexGuestPPC32State, guest_VR10);
572 case 11: return offsetof(VexGuestPPC32State, guest_VR11);
573 case 12: return offsetof(VexGuestPPC32State, guest_VR12);
574 case 13: return offsetof(VexGuestPPC32State, guest_VR13);
575 case 14: return offsetof(VexGuestPPC32State, guest_VR14);
576 case 15: return offsetof(VexGuestPPC32State, guest_VR15);
577 case 16: return offsetof(VexGuestPPC32State, guest_VR16);
578 case 17: return offsetof(VexGuestPPC32State, guest_VR17);
579 case 18: return offsetof(VexGuestPPC32State, guest_VR18);
580 case 19: return offsetof(VexGuestPPC32State, guest_VR19);
581 case 20: return offsetof(VexGuestPPC32State, guest_VR20);
582 case 21: return offsetof(VexGuestPPC32State, guest_VR21);
583 case 22: return offsetof(VexGuestPPC32State, guest_VR22);
584 case 23: return offsetof(VexGuestPPC32State, guest_VR23);
585 case 24: return offsetof(VexGuestPPC32State, guest_VR24);
586 case 25: return offsetof(VexGuestPPC32State, guest_VR25);
587 case 26: return offsetof(VexGuestPPC32State, guest_VR26);
588 case 27: return offsetof(VexGuestPPC32State, guest_VR27);
589 case 28: return offsetof(VexGuestPPC32State, guest_VR28);
590 case 29: return offsetof(VexGuestPPC32State, guest_VR29);
591 case 30: return offsetof(VexGuestPPC32State, guest_VR30);
592 case 31: return offsetof(VexGuestPPC32State, guest_VR31);
593 default: break;
594 }
595 vpanic("vextorGuestRegOffset(ppc32)"); /*notreached*/
596}
597
598static IRExpr* getVReg ( UInt archreg )
599{
600 vassert(archreg < 32);
601 return IRExpr_Get( vectorGuestRegOffset(archreg), Ity_V128 );
602}
603
604/* Ditto, but write to a reg instead. */
605static void putVReg ( UInt archreg, IRExpr* e )
606{
607 vassert(archreg < 32);
608 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_V128);
609 stmt( IRStmt_Put(vectorGuestRegOffset(archreg), e) );
610}
611
612static Int guestCR321offset ( UInt cr )
613{
614 switch (cr) {
615 case 0: return offsetof(VexGuestPPC32State, guest_CR0_321 );
616 case 1: return offsetof(VexGuestPPC32State, guest_CR1_321 );
617 case 2: return offsetof(VexGuestPPC32State, guest_CR2_321 );
618 case 3: return offsetof(VexGuestPPC32State, guest_CR3_321 );
619 case 4: return offsetof(VexGuestPPC32State, guest_CR4_321 );
620 case 5: return offsetof(VexGuestPPC32State, guest_CR5_321 );
621 case 6: return offsetof(VexGuestPPC32State, guest_CR6_321 );
622 case 7: return offsetof(VexGuestPPC32State, guest_CR7_321 );
623 default: vpanic("guestCR321offset(ppc32)");
624 }
625}
626
627static Int guestCR0offset ( UInt cr )
628{
629 switch (cr) {
630 case 0: return offsetof(VexGuestPPC32State, guest_CR0_0 );
631 case 1: return offsetof(VexGuestPPC32State, guest_CR1_0 );
632 case 2: return offsetof(VexGuestPPC32State, guest_CR2_0 );
633 case 3: return offsetof(VexGuestPPC32State, guest_CR3_0 );
634 case 4: return offsetof(VexGuestPPC32State, guest_CR4_0 );
635 case 5: return offsetof(VexGuestPPC32State, guest_CR5_0 );
636 case 6: return offsetof(VexGuestPPC32State, guest_CR6_0 );
637 case 7: return offsetof(VexGuestPPC32State, guest_CR7_0 );
638 default: vpanic("guestCR3offset(ppc32)");
639 }
640}
641
642static void putCR321 ( UInt cr, IRExpr* e )
643{
644 vassert(cr < 8);
645 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I8);
646 stmt( IRStmt_Put(guestCR321offset(cr), e) );
647}
648
649static void putCR0 ( UInt cr, IRExpr* e )
650{
651 vassert(cr < 8);
652 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I8);
653 stmt( IRStmt_Put(guestCR0offset(cr), e) );
654}
655
656static IRExpr* /* :: Ity_I8 */ getCR0 ( UInt cr )
657{
658 vassert(cr < 8);
659 return IRExpr_Get(guestCR0offset(cr), Ity_I8);
660}
661
662static IRExpr* /* :: Ity_I8 */ getCR321 ( UInt cr )
663{
664 vassert(cr < 8);
665 return IRExpr_Get(guestCR321offset(cr), Ity_I8);
666}
667
668static IRExpr* /* :: Ity_I8 */ getXER_SO ( void )
669{
670 return IRExpr_Get( OFFB_XER_SO, Ity_I8 );
671}
672
673// ROTL(src32, rot_amt5)
sewardjc9659532005-07-21 21:33:57 +0000674static IRExpr* ROTL32 ( IRExpr* src, IRExpr* rot_amt )
sewardjb51f0f42005-07-18 11:38:02 +0000675{
sewardjc9659532005-07-21 21:33:57 +0000676 IRExpr* masked;
cerionb85e8bb2005-02-16 08:54:33 +0000677 vassert(typeOfIRExpr(irbb->tyenv,src) == Ity_I32);
sewardjc9659532005-07-21 21:33:57 +0000678 vassert(typeOfIRExpr(irbb->tyenv,rot_amt) == Ity_I32);
sewardjb51f0f42005-07-18 11:38:02 +0000679
sewardjc9659532005-07-21 21:33:57 +0000680 masked
681 = unop(Iop_32to8, binop(Iop_And32, rot_amt, mkU32(31)));
sewardjb51f0f42005-07-18 11:38:02 +0000682
cerionb85e8bb2005-02-16 08:54:33 +0000683 // (src << rot_amt) | (src >> (32-rot_amt))
sewardjc9659532005-07-21 21:33:57 +0000684 /* Note: the MuxOX is not merely an optimisation; it's needed
685 because otherwise the Shr32 is a shift by the word size when
686 masked denotes zero. For rotates by immediates, a lot of
687 this junk gets folded out. */
688 return
689 IRExpr_Mux0X(
690 masked,
691 /* zero rotate. */
692 src,
693 /* non-zero rotate */
694 binop( Iop_Or32,
695 binop(Iop_Shl32, src, masked),
696 binop(Iop_Shr32, src, binop(Iop_Sub8, mkU8(32), masked))
697 )
698 );
cerion45b70ff2005-01-31 17:03:25 +0000699}
cerion896a1372005-01-25 12:24:25 +0000700
sewardj87e651f2005-09-09 08:31:18 +0000701/* Do the standard effective address calculation: (rA|0) + rB. */
702static IRExpr* /* :: Ity_I32 */ ea_standard ( Int rA, Int rB )
703{
704 vassert(rA >= 0 && rA < 32);
705 vassert(rB >= 0 && rB < 32);
706 if (rA == 0) {
707 return getIReg(rB);
708 } else {
709 return binop(Iop_Add32, getIReg(rA), getIReg(rB));
710 }
711}
712
713/* Do the effective address calculation: (rA|0). */
714static IRExpr* /* :: Ity_I32 */ ea_rA_or_zero ( Int rA )
715{
716 vassert(rA >= 0 && rA < 32);
717 if (rA == 0) {
718 return mkU32(0);
719 } else {
720 return getIReg(rA);
721 }
722}
723
cerion896a1372005-01-25 12:24:25 +0000724
cerion896a1372005-01-25 12:24:25 +0000725/*------------------------------------------------------------*/
sewardjb51f0f42005-07-18 11:38:02 +0000726/*--- Helpers for condition codes. ---*/
cerion896a1372005-01-25 12:24:25 +0000727/*------------------------------------------------------------*/
728
sewardjb51f0f42005-07-18 11:38:02 +0000729/* Condition register layout.
cerion896a1372005-01-25 12:24:25 +0000730
sewardjb51f0f42005-07-18 11:38:02 +0000731 In the hardware, CR is laid out like this. The leftmost end is the
732 most significant bit in the register; however the IBM documentation
733 numbers the bits backwards for some reason.
734
735 CR0 CR1 .......... CR6 CR7
736 0 .. 3 ....................... 28 .. 31 (IBM bit numbering)
737 31 28 3 0 (normal bit numbering)
738
739 Each CR field is 4 bits:
740
741 < > == SO
742
743 Hence in IBM's notation, BI=0 indicates CR7.SO, BI=1 is CR7.==,
744 etc.
745
746 Indexing from BI to guest state:
747
748 let n = BI / 4
749 off = BI % 4
750 this references CR n:
751
752 off==3 -> guest_CRn_SO
753 off==2 -> guest_CRn_123 >> 1
754 off==1 -> guest_CRn_123 >> 2
755 off==0 -> guest_CRn_123 >> 3
756
757 Bear in mind the only significant bit in guest_CRn_SO is bit 0
758 (normal notation) and in guest_CRn_123 the significant bits are
759 3, 2 and 1 (normal notation).
760*/
761/* Fetch the specified CR bit (as per IBM/hardware notation) and
762 return it at the bottom of an I32; the top 31 bits are guaranteed
763 to be zero. */
764static IRExpr* /* :: Ity_I32 */ getCRbit ( UInt bi )
cerion896a1372005-01-25 12:24:25 +0000765{
sewardjb51f0f42005-07-18 11:38:02 +0000766 UInt n = bi / 4;
767 UInt off = bi % 4;
768 vassert(bi < 32);
769 if (off == 3) {
770 /* Fetch the SO bit for this CR field */
771 /* Note: And32 is redundant paranoia iff guest state only has 0
772 or 1 in that slot. */
773 return binop(Iop_And32, unop(Iop_8Uto32, getCR0(n)), mkU32(1));
774 } else {
775 /* Fetch the <, > or == bit for this CR field */
776 return binop( Iop_And32,
777 binop( Iop_Shr32,
778 unop(Iop_8Uto32, getCR321(n)),
sewardjc7cd2142005-09-09 22:31:49 +0000779 mkU8(toUChar(3-off)) ),
sewardjb51f0f42005-07-18 11:38:02 +0000780 mkU32(1) );
781 }
cerion91ad5362005-01-27 23:02:41 +0000782}
783
sewardjb51f0f42005-07-18 11:38:02 +0000784/* Dually, write the least significant bit of BIT to the specified CR
785 bit. Indexing as per getCRbit. */
786static void putCRbit ( UInt bi, IRExpr* bit )
787{
788 IRExpr* safe;
789 vassert(typeOfIRExpr(irbb->tyenv,bit) == Ity_I32);
790 safe = binop(Iop_And32, bit, mkU32(1));
791 UInt n = bi / 4;
792 UInt off = bi % 4;
793 vassert(bi < 32);
794 if (off == 3) {
795 /* This is the SO bit for this CR field */
796 putCR0(n, unop(Iop_32to8, safe));
797 } else {
798 off = 3 - off;
799 vassert(off == 1 || off == 2 || off == 3);
800 putCR321(
801 n,
802 unop( Iop_32to8,
803 binop( Iop_Or32,
804 /* old value with field masked out */
805 binop(Iop_And32, unop(Iop_8Uto32, getCR321(n)),
806 mkU32(~(1 << off))),
807 /* new value in the right place */
sewardjc7cd2142005-09-09 22:31:49 +0000808 binop(Iop_Shl32, safe, mkU8(toUChar(off)))
sewardjb51f0f42005-07-18 11:38:02 +0000809 )
810 )
811 );
812 }
813}
814
815
816/* Fetch the specified CR bit (as per IBM/hardware notation) and
817 return it somewhere in an I32; it does not matter where, but
818 whichever bit it is, all other bits are guaranteed to be zero. In
819 other words, the I32-typed expression will be zero if the bit is
820 zero and nonzero if the bit is 1. Write into *where the index
821 of where the bit will be. */
822
823static IRExpr* /* :: Ity_I32 */ getCRbit_anywhere ( UInt bi, Int* where )
824{
825 UInt n = bi / 4;
826 UInt off = bi % 4;
827 vassert(bi < 32);
828 if (off == 3) {
829 /* Fetch the SO bit for this CR field */
830 /* Note: And32 is redundant paranoia iff guest state only has 0
831 or 1 in that slot. */
832 *where = 0;
833 return binop(Iop_And32, unop(Iop_8Uto32, getCR0(n)), mkU32(1));
834 } else {
835 /* Fetch the <, > or == bit for this CR field */
836 *where = 3-off;
837 return binop( Iop_And32,
838 unop(Iop_8Uto32, getCR321(n)),
839 mkU32(1 << (3-off)) );
840 }
841}
842
843
844/* Synthesise the entire CR into a single word. Expensive. */
845
846static IRExpr* /* :: Ity_I32 */ getEntireCR ( void )
847{
848# define FIELD(_n) \
849 binop(Iop_Shl32, \
850 unop(Iop_8Uto32, \
851 binop(Iop_Or8, \
852 binop(Iop_And8, getCR321(_n), mkU8(7<<1)), \
853 binop(Iop_And8, getCR0(_n), mkU8(1)) \
854 ) \
855 ), \
856 mkU8(4 * (7-(_n))) \
857 )
858
859 return binop(Iop_Or32,
860 binop(Iop_Or32,
861 binop(Iop_Or32, FIELD(0), FIELD(1)),
862 binop(Iop_Or32, FIELD(2), FIELD(3))
863 ),
864 binop(Iop_Or32,
865 binop(Iop_Or32, FIELD(4), FIELD(5)),
866 binop(Iop_Or32, FIELD(6), FIELD(7))
867 )
868 );
869# undef FIELD
870}
871
872static void putCRfields ( IRExpr* w32, UInt mask )
873{
874 IRTemp t;
875 Int cr;
876 vassert(typeOfIRExpr(irbb->tyenv,w32) == Ity_I32);
877 vassert(mask < 256);
878 for (cr = 0; cr < 8; cr++) {
879 if ((mask & (1 << (7-cr))) == 0)
880 continue;
881 t = newTemp(Ity_I32);
sewardjc7cd2142005-09-09 22:31:49 +0000882 assign( t, binop(Iop_Shr32, w32, mkU8(toUChar(4*(7-cr)))) );
sewardjb51f0f42005-07-18 11:38:02 +0000883 putCR0( cr, unop(Iop_32to8,
884 binop(Iop_And32, mkexpr(t), mkU32(1))) );
885 putCR321( cr, unop(Iop_32to8,
886 binop(Iop_And32, mkexpr(t), mkU32(7<<1))) );
887 }
888}
889
890
sewardjb51f0f42005-07-18 11:38:02 +0000891/* Set the CR0 flags following an arithmetic operation.
892 (Condition Register CR0 Field Definition, PPC32 p60)
cerion896a1372005-01-25 12:24:25 +0000893*/
sewardj20ef5472005-07-21 14:48:31 +0000894static void set_CR0 ( IRExpr* result )
cerion896a1372005-01-25 12:24:25 +0000895{
cerion62bec572005-02-01 21:29:39 +0000896 vassert(typeOfIRExpr(irbb->tyenv,result) == Ity_I32);
sewardjb51f0f42005-07-18 11:38:02 +0000897 putCR321( 0, unop(Iop_32to8,
898 binop(Iop_CmpORD32S, result, mkU32(0))) );
899 putCR0( 0, getXER_SO() );
cerion896a1372005-01-25 12:24:25 +0000900}
cerion896a1372005-01-25 12:24:25 +0000901
sewardj20ef5472005-07-21 14:48:31 +0000902
903/* RES is the result of doing OP on ARGL and ARGR. Set %XER.OV and
904 %XER.SO accordingly. */
905
906static void set_XER_OV( UInt op, IRExpr* res,
907 IRExpr* argL, IRExpr* argR )
908{
909 IRTemp t64;
910 IRExpr* xer_ov;
911 vassert(op < PPC32G_FLAG_OP_NUMBER);
912 vassert(typeOfIRExpr(irbb->tyenv,res) == Ity_I32);
913 vassert(typeOfIRExpr(irbb->tyenv,argL) == Ity_I32);
914 vassert(typeOfIRExpr(irbb->tyenv,argR) == Ity_I32);
915
916# define INT32_MIN 0x80000000
917
918# define XOR2(_aa,_bb) \
919 binop(Iop_Xor32,(_aa),(_bb))
920
921# define XOR3(_cc,_dd,_ee) \
922 binop(Iop_Xor32,binop(Iop_Xor32,(_cc),(_dd)),(_ee))
923
924# define AND3(_ff,_gg,_hh) \
925 binop(Iop_And32,binop(Iop_And32,(_ff),(_gg)),(_hh))
926
927#define NOT(_jj) \
928 unop(Iop_Not32, (_jj))
929
930 switch (op) {
931
932 case /* 0 */ PPC32G_FLAG_OP_ADD:
933 case /* 1 */ PPC32G_FLAG_OP_ADDE:
934 /* (argL^argR^-1) & (argL^res) & (1<<31) ?1:0 */
935 // i.e. ((both_same_sign) & (sign_changed) & (sign_mask))
936 xer_ov
937 = AND3( XOR3(argL,argR,mkU32(-1)),
938 XOR2(argL,res),
939 mkU32(INT32_MIN) );
940 /* xer_ov can only be 0 or 1<<31 */
941 xer_ov
942 = binop(Iop_Shr32, xer_ov, mkU8(31) );
943 break;
944
945 case /* 2 */ PPC32G_FLAG_OP_DIVW:
946 /* (argL == INT32_MIN && argR == -1) || argR == 0 */
947 xer_ov
948 = mkOR1(
949 mkAND1(
950 binop(Iop_CmpEQ32, argL, mkU32(INT32_MIN)),
951 binop(Iop_CmpEQ32, argR, mkU32(-1))
952 ),
953 binop(Iop_CmpEQ32, argR, mkU32(0) )
954 );
955 xer_ov
956 = unop(Iop_1Uto32, xer_ov);
957 break;
958
959 case /* 3 */ PPC32G_FLAG_OP_DIVWU:
960 /* argR == 0 */
961 xer_ov
962 = unop(Iop_1Uto32, binop(Iop_CmpEQ32, argR, mkU32(0)));
963 break;
964
965 case /* 4 */ PPC32G_FLAG_OP_MULLW:
966 /* OV true if result can't be represented in 32 bits
967 i.e sHi != sign extension of sLo */
968 t64 = newTemp(Ity_I64);
sewardj6fa6bf12005-07-21 17:07:18 +0000969 assign( t64, binop(Iop_MullS32, argL, argR) );
sewardj20ef5472005-07-21 14:48:31 +0000970 xer_ov
971 = binop( Iop_CmpNE32,
972 unop(Iop_64HIto32, mkexpr(t64)),
973 binop( Iop_Sar32,
974 unop(Iop_64to32, mkexpr(t64)),
975 mkU8(31))
976 );
977 xer_ov
978 = unop(Iop_1Uto32, xer_ov);
979 break;
980
981 case /* 5 */ PPC32G_FLAG_OP_NEG:
982 /* argL == INT32_MIN */
983 xer_ov
984 = unop( Iop_1Uto32,
985 binop(Iop_CmpEQ32, argL, mkU32(INT32_MIN)) );
986 break;
987
988 case /* 6 */ PPC32G_FLAG_OP_SUBF:
989 case /* 7 */ PPC32G_FLAG_OP_SUBFC:
990 case /* 8 */ PPC32G_FLAG_OP_SUBFE:
991 /* ((~argL)^argR^-1) & ((~argL)^res) & (1<<31) ?1:0; */
992 xer_ov
993 = AND3( XOR3(NOT(argL),argR,mkU32(-1)),
994 XOR2(NOT(argL),res),
995 mkU32(INT32_MIN) );
996 /* xer_ov can only be 0 or 1<<31 */
997 xer_ov
998 = binop(Iop_Shr32, xer_ov, mkU8(31) );
999 break;
1000
1001 default:
sewardjc7cd2142005-09-09 22:31:49 +00001002 vex_printf("set_XER_OV: op = %u\n", op);
sewardj20ef5472005-07-21 14:48:31 +00001003 vpanic("set_XER_OV(ppc32)");
1004 }
1005
1006 /* xer_ov MUST denote either 0 or 1, no other value allowed */
1007 stmt( IRStmt_Put( OFFB_XER_OV, unop(Iop_32to8, xer_ov) ) );
1008
1009 /* Update the summary overflow */
1010 stmt( IRStmt_Put(
1011 OFFB_XER_SO,
1012 binop(Iop_Or8, IRExpr_Get( OFFB_XER_SO, Ity_I8 ),
1013 IRExpr_Get( OFFB_XER_OV, Ity_I8 ) )
1014 ));
1015
1016# undef INT32_MIN
1017# undef AND3
1018# undef XOR3
1019# undef XOR2
1020# undef NOT
1021}
1022
cerion38674602005-02-08 02:19:25 +00001023
sewardjb51f0f42005-07-18 11:38:02 +00001024/* RES is the result of doing OP on ARGL and ARGR with the old %XER.CA
1025 value being OLDCA. Set %XER.CA accordingly. */
cerione9d361a2005-03-04 17:35:29 +00001026
sewardjb51f0f42005-07-18 11:38:02 +00001027static void set_XER_CA( UInt op,
1028 IRExpr* res,
1029 IRExpr* argL,
1030 IRExpr* argR,
1031 IRExpr* oldca )
cerion38674602005-02-08 02:19:25 +00001032{
sewardj9a036bf2005-03-14 18:19:08 +00001033 IRExpr* xer_ca;
cerionb85e8bb2005-02-16 08:54:33 +00001034 vassert(op < PPC32G_FLAG_OP_NUMBER);
sewardjb51f0f42005-07-18 11:38:02 +00001035 vassert(typeOfIRExpr(irbb->tyenv,res) == Ity_I32);
1036 vassert(typeOfIRExpr(irbb->tyenv,argL) == Ity_I32);
1037 vassert(typeOfIRExpr(irbb->tyenv,argR) == Ity_I32);
1038 vassert(typeOfIRExpr(irbb->tyenv,oldca) == Ity_I32);
cerion70e24122005-03-16 00:27:37 +00001039
sewardj20ef5472005-07-21 14:48:31 +00001040 /* Incoming oldca is assumed to hold the values 0 or 1 only. This
1041 seems reasonable given that it's always generated by
1042 get_XER_CA(), which masks it accordingly. In any case it being
1043 0 or 1 is an invariant of the ppc32 guest state representation;
1044 if it has any other value, that invariant has been violated. */
cerione9d361a2005-03-04 17:35:29 +00001045
sewardj20ef5472005-07-21 14:48:31 +00001046 switch (op) {
1047
1048 case /* 0 */ PPC32G_FLAG_OP_ADD:
1049 /* res <u argL */
1050 xer_ca
1051 = unop(Iop_1Uto32, binop(Iop_CmpLT32U, res, argL));
1052 break;
1053
1054 case /* 1 */ PPC32G_FLAG_OP_ADDE:
1055 /* res <u argL || (old_ca==1 && res==argL) */
1056 xer_ca
1057 = mkOR1(
1058 binop(Iop_CmpLT32U, res, argL),
1059 mkAND1(
1060 binop(Iop_CmpEQ32, oldca, mkU32(1)),
1061 binop(Iop_CmpEQ32, res, argL)
1062 )
1063 );
1064 xer_ca
1065 = unop(Iop_1Uto32, xer_ca);
1066 break;
1067
1068 case /* 8 */ PPC32G_FLAG_OP_SUBFE:
1069 /* res <u argR || (old_ca==1 && res==argR) */
1070 xer_ca
1071 = mkOR1(
1072 binop(Iop_CmpLT32U, res, argR),
1073 mkAND1(
1074 binop(Iop_CmpEQ32, oldca, mkU32(1)),
1075 binop(Iop_CmpEQ32, res, argR)
1076 )
1077 );
1078 xer_ca
1079 = unop(Iop_1Uto32, xer_ca);
1080 break;
1081
1082 case /* 7 */ PPC32G_FLAG_OP_SUBFC:
1083 case /* 9 */ PPC32G_FLAG_OP_SUBFI:
1084 /* res <=u argR */
1085 xer_ca
1086 = unop(Iop_1Uto32, binop(Iop_CmpLE32U, res, argR));
1087 break;
1088
1089 case /* 10 */ PPC32G_FLAG_OP_SRAW:
1090 /* The shift amount is guaranteed to be in 0 .. 63 inclusive.
1091 If it is <= 31, behave like SRAWI; else XER.CA is the sign
1092 bit of argL. */
1093 /* This term valid for shift amount < 32 only */
1094 xer_ca
1095 = binop(
1096 Iop_And32,
1097 binop(Iop_Sar32, argL, mkU8(31)),
1098 binop( Iop_And32,
1099 argL,
1100 binop( Iop_Sub32,
1101 binop(Iop_Shl32, mkU32(1), unop(Iop_32to8,argR)),
1102 mkU32(1) )
1103 )
1104 );
1105 xer_ca
1106 = IRExpr_Mux0X(
1107 /* shift amt > 31 ? */
1108 unop(Iop_1Uto8, binop(Iop_CmpLT32U, mkU32(31), argR)),
1109 /* no -- be like srawi */
1110 unop(Iop_1Uto32, binop(Iop_CmpNE32, xer_ca, mkU32(0))),
1111 /* yes -- get sign bit of argL */
1112 binop(Iop_Shr32, argL, mkU8(31))
1113 );
1114 break;
1115
1116 case /* 11 */ PPC32G_FLAG_OP_SRAWI:
1117 /* xer_ca is 1 iff src was negative and bits_shifted_out !=
1118 0. Since the shift amount is known to be in the range
1119 0 .. 31 inclusive the following seems viable:
1120 xer.ca == 1 iff the following is nonzero:
1121 (argL >>s 31) -- either all 0s or all 1s
1122 & (argL & (1<<argR)-1) -- the stuff shifted out */
1123 xer_ca
1124 = binop(
1125 Iop_And32,
1126 binop(Iop_Sar32, argL, mkU8(31)),
1127 binop( Iop_And32,
1128 argL,
1129 binop( Iop_Sub32,
1130 binop(Iop_Shl32, mkU32(1), unop(Iop_32to8,argR)),
1131 mkU32(1) )
1132 )
1133 );
1134 xer_ca
1135 = unop(Iop_1Uto32, binop(Iop_CmpNE32, xer_ca, mkU32(0)));
1136 break;
1137
1138 default:
sewardjc7cd2142005-09-09 22:31:49 +00001139 vex_printf("set_XER_CA: op = %u\n", op);
sewardj20ef5472005-07-21 14:48:31 +00001140 vpanic("set_XER_CA(ppc32)");
1141 }
1142
1143 /* xer_ca MUST denote either 0 or 1, no other value allowed */
1144 stmt( IRStmt_Put( OFFB_XER_CA, unop(Iop_32to8, xer_ca) ) );
sewardjb51f0f42005-07-18 11:38:02 +00001145}
1146
1147static IRExpr* /* :: Ity_I32 */ get_XER_CA ( void )
1148{
1149 return binop( Iop_And32,
1150 unop( Iop_8Uto32,
1151 IRExpr_Get(OFFB_XER_CA, Ity_I8) ),
1152 mkU32(1) );
cerion38674602005-02-08 02:19:25 +00001153}
1154
cerion896a1372005-01-25 12:24:25 +00001155
1156
cerion0c439222005-09-15 14:22:58 +00001157/* Set the CR6 flags following an AltiVec compare operation. */
1158static void set_AV_CR6 ( IRExpr* result )
1159{
1160 vassert(typeOfIRExpr(irbb->tyenv,result) == Ity_V128);
1161
1162 /* CR6[0:3] = {all_ones, 0, all_zeros, 0}
1163 all_ones = (v[0] && v[1] && v[2] && v[3])
1164 all_zeros = ~(v[0] || v[1] || v[2] || v[3])
1165 */
1166 IRTemp v0 = newTemp(Ity_V128);
1167 IRTemp v1 = newTemp(Ity_V128);
1168 IRTemp v2 = newTemp(Ity_V128);
1169 IRTemp v3 = newTemp(Ity_V128);
1170 IRTemp rOnes = newTemp(Ity_I8);
1171 IRTemp rZeros = newTemp(Ity_I8);
1172 assign( v0, result );
1173 assign( v1, binop(Iop_ShrV128, result, mkU8(32)) );
1174 assign( v2, binop(Iop_ShrV128, result, mkU8(64)) );
1175 assign( v3, binop(Iop_ShrV128, result, mkU8(96)) );
1176
1177 assign( rOnes, unop(Iop_1Uto8,
1178 binop(Iop_CmpEQ32, mkU32(0xFFFFFFFF),
1179 unop(Iop_V128to32,
1180 binop(Iop_AndV128,
1181 binop(Iop_AndV128, mkexpr(v0), mkexpr(v1)),
1182 binop(Iop_AndV128, mkexpr(v2), mkexpr(v3)))))) );
1183
1184 assign( rZeros, unop(Iop_1Uto8,
1185 binop(Iop_CmpEQ32, mkU32(0xFFFFFFFF),
1186 unop(Iop_Not32,
1187 unop(Iop_V128to32,
1188 binop(Iop_OrV128,
1189 binop(Iop_OrV128, mkexpr(v0), mkexpr(v1)),
1190 binop(Iop_OrV128, mkexpr(v2), mkexpr(v3))))
1191 ))) );
1192
1193 putCR321( 6, binop(Iop_Or8,
1194 binop(Iop_Shl8, mkexpr(rOnes), mkU8(3)),
1195 binop(Iop_Shl8, mkexpr(rZeros), mkU8(1))) );
1196 putCR0( 6, mkU8(0) );
1197}
1198
1199
1200
sewardje14bb9f2005-07-22 09:39:02 +00001201/*------------------------------------------------------------*/
1202/*--- Abstract register interface --- */
1203/*------------------------------------------------------------*/
1204
1205/* Get a masked word from the given reg */
1206static IRExpr* getReg_masked ( PPC32SPR reg, UInt mask )
1207{
1208 IRTemp val = newTemp(Ity_I32);
1209 vassert( reg < PPC32_SPR_MAX );
1210
1211 switch (reg) {
1212
1213 case PPC32_SPR_FPSCR: {
1214 vassert((mask & 0x3) == 0x3 || (mask & 0x3) == 0x0);
1215 vassert((mask & 0xF000) == 0xF000 || (mask & 0xF000) == 0x0);
1216 /* all masks now refer to valid fields */
1217
1218 /* Vex-generated code expects to run with the FPSCR set as follows:
1219 all exceptions masked, round-to-nearest.
1220 This corresponds to a FPSCR value of 0x0. */
1221
1222 /* We're only keeping track of the rounding mode,
1223 so if the mask isn't asking for this, just return 0x0 */
1224 if (mask & 0x3) {
1225 assign( val, IRExpr_Get(OFFB_FPROUND, Ity_I32) );
1226 } else {
1227 assign( val, mkU32(0x0) );
1228 }
1229 break;
1230 }
1231
sewardjb51f0f42005-07-18 11:38:02 +00001232//zz case PPC32_SPR_VRSAVE:
1233//zz assign( val, IRExpr_Get(OFFB_VRSAVE, Ity_I32) );
1234//zz break;
cerion225a0342005-09-12 20:49:09 +00001235
1236 case PPC32_SPR_VSCR:
1237 // All other bits are zero.
1238 mask = mask & 0x00010001;
1239 assign( val, IRExpr_Get(OFFB_VSCR, Ity_I32) );
1240 break;
sewardje14bb9f2005-07-22 09:39:02 +00001241
1242 default:
1243 vpanic("getReg(ppc32)");
1244 }
1245
1246 if (mask != 0xFFFFFFFF) {
1247 return binop(Iop_And32, mkexpr(val), mkU32(mask));
1248 } else {
1249 return mkexpr(val);
1250 }
1251}
1252
sewardjb51f0f42005-07-18 11:38:02 +00001253//zz /* Get word from the given reg */
1254//zz static IRExpr* getReg ( PPC32SPR reg )
1255//zz {
1256//zz vassert( reg < PPC32_SPR_MAX );
1257//zz return getReg_masked( reg, 0xFFFFFFFF );
1258//zz }
1259//zz
1260//zz /* Get a right-shifted nibble from given reg[field_idx]
1261//zz returns zero padded word */
1262//zz static IRExpr* getReg_field ( PPC32SPR reg, UInt field_idx )
1263//zz {
1264//zz IRExpr* fld;
1265//zz vassert( field_idx < 8 );
1266//zz vassert( reg < PPC32_SPR_MAX );
1267//zz
1268//zz fld = getReg_masked( reg, (0xF << (field_idx*4)) );
1269//zz
1270//zz if (field_idx != 0) {
1271//zz fld = binop(Iop_Shr32, fld, mkU8(toUChar(field_idx * 4)));
1272//zz }
1273//zz return fld;
1274//zz }
1275//zz
1276//zz /* Get a right-shifted bit from given reg[bit_idx]
1277//zz returns zero padded word */
1278//zz static IRExpr* getReg_bit ( PPC32SPR reg, UInt bit_idx )
1279//zz {
1280//zz IRExpr* val;
1281//zz vassert( bit_idx < 32 );
1282//zz vassert( reg < PPC32_SPR_MAX );
1283//zz
1284//zz val = getReg_masked( reg, 1<<bit_idx );
1285//zz
1286//zz if (bit_idx != 0) {
1287//zz val = binop(Iop_Shr32, val, mkU8(toUChar(bit_idx)));
1288//zz }
1289//zz return val;
1290//zz }
sewardje14bb9f2005-07-22 09:39:02 +00001291
1292
1293
1294/* Write masked src to the given reg */
1295static void putReg_masked ( PPC32SPR reg, IRExpr* src, UInt mask )
1296{
1297 vassert( reg < PPC32_SPR_MAX );
1298 vassert( typeOfIRExpr(irbb->tyenv,src ) == Ity_I32 );
1299
1300 switch (reg) {
sewardjb51f0f42005-07-18 11:38:02 +00001301//zz case PPC32_SPR_CIA:
1302//zz vassert(mask == 0xFFFFFFFF); // Only ever need whole reg
1303//zz stmt( IRStmt_Put( OFFB_CIA, src ) );
1304//zz break;
sewardje14bb9f2005-07-22 09:39:02 +00001305
1306 case PPC32_SPR_FPSCR:
1307 vassert((mask & 0x3) == 0x3 || (mask & 0x3) == 0x0);
1308 vassert((mask & 0xF000) == 0xF000 || (mask & 0xF000) == 0x0);
1309 /* all masks now refer to valid fields */
1310
1311 /* Allow writes to Rounding Mode */
1312 if (mask & 0x3) {
1313 stmt( IRStmt_Put( OFFB_FPROUND,
1314 binop(Iop_And32, src, mkU32(0x3)) ));
1315 }
1316
1317 /*
1318 Give EmWarn for attempted writes to:
1319 - Exception Controls
1320 - Non-IEEE Mode
1321 */
1322 if (mask & 0xFC) { // Exception Control, Non-IEE mode
1323 VexEmWarn ew = EmWarn_PPC32exns;
1324
1325 /* If any of the src::exception_control bits are actually set,
1326 side-exit to the next insn, reporting the warning,
1327 so that Valgrind's dispatcher sees the warning. */
1328 put_emwarn( mkU32(ew) );
1329 stmt(
1330 IRStmt_Exit(
1331 binop(Iop_CmpNE32, mkU32(ew), mkU32(EmWarn_NONE)),
1332 Ijk_EmWarn,
1333 IRConst_U32(guest_CIA_curr_instr + 4)
1334 )
1335 );
1336 }
1337
1338 /*
1339 Ignore all other writes
1340 */
1341 break;
1342
sewardjb51f0f42005-07-18 11:38:02 +00001343//zz case PPC32_SPR_VRSAVE:
1344//zz vassert(mask == 0xFFFFFFFF); // Only ever need whole reg
1345//zz stmt( IRStmt_Put( OFFB_VRSAVE, src ) );
1346//zz break;
cerion225a0342005-09-12 20:49:09 +00001347
1348 case PPC32_SPR_VSCR:
1349 // CAB: There are only 2 valid bits in VSCR - maybe split into two vars...
1350 // ... or perhaps only 1 bit... is non-java mode bit ever set to zero?
1351
1352 // All other bits are 'Reserved'. Ignoring writes to these bits.
1353 stmt( IRStmt_Put( OFFB_VSCR,
1354 binop(Iop_Or32,
1355 binop(Iop_And32, src, mkU32(mask & 0x00010001)),
1356 getReg_masked( PPC32_SPR_VSCR, (~mask & 0x00010001) ))));
1357 break;
sewardje14bb9f2005-07-22 09:39:02 +00001358
1359 default:
1360 vpanic("putReg(ppc32)");
1361 }
1362}
1363
sewardjb51f0f42005-07-18 11:38:02 +00001364//zz /* Write src to the given reg */
1365//zz static void putReg ( PPC32SPR reg, IRExpr* src )
1366//zz {
1367//zz vassert( typeOfIRExpr(irbb->tyenv,src ) == Ity_I32 );
1368//zz vassert( reg < PPC32_SPR_MAX );
1369//zz putReg_masked( reg, src, 0xFFFFFFFF );
1370//zz }
cerion62bec572005-02-01 21:29:39 +00001371
sewardjb51f0f42005-07-18 11:38:02 +00001372static void putSPR ( PPC32SPR reg, IRExpr* src )
cerion76222262005-02-05 13:45:57 +00001373{
sewardjb51f0f42005-07-18 11:38:02 +00001374 vassert( typeOfIRExpr(irbb->tyenv,src ) == Ity_I32 );
cerionb85e8bb2005-02-16 08:54:33 +00001375 switch (reg) {
sewardjb51f0f42005-07-18 11:38:02 +00001376 case PPC32_SPR_CIA:
1377 stmt( IRStmt_Put( OFFB_CIA, src ) );
1378 break;
1379 case PPC32_SPR_LR:
1380 stmt( IRStmt_Put( OFFB_LR, src ) );
1381 break;
1382 case PPC32_SPR_CTR:
1383 stmt( IRStmt_Put( OFFB_CTR, src ) );
1384 break;
1385 case PPC32_SPR_VRSAVE:
1386 stmt( IRStmt_Put( OFFB_VRSAVE, src ) );
1387 break;
cerion225a0342005-09-12 20:49:09 +00001388 case PPC32_SPR_VSCR:
1389 putReg_masked( reg, src, 0xFFFFFFFF );
1390 break;
sewardjb51f0f42005-07-18 11:38:02 +00001391 default:
1392 vpanic("putSPR(ppc32)");
cerion3007c7f2005-02-23 23:13:29 +00001393 }
cerion76222262005-02-05 13:45:57 +00001394}
cerion38674602005-02-08 02:19:25 +00001395
sewardjb51f0f42005-07-18 11:38:02 +00001396static IRExpr* /* :: Ity_I32 */ getSPR ( PPC32SPR reg )
cerion38674602005-02-08 02:19:25 +00001397{
cerionb85e8bb2005-02-16 08:54:33 +00001398 switch (reg) {
sewardjb51f0f42005-07-18 11:38:02 +00001399 case PPC32_SPR_LR:
1400 return IRExpr_Get( OFFB_LR, Ity_I32 );
1401 case PPC32_SPR_CTR:
1402 return IRExpr_Get( OFFB_CTR, Ity_I32 );
1403 case PPC32_SPR_VRSAVE:
1404 return IRExpr_Get( OFFB_VRSAVE, Ity_I32 );
cerion225a0342005-09-12 20:49:09 +00001405 case PPC32_SPR_VSCR:
1406 return getReg_masked( reg, 0xFFFFFFFF );
sewardjb51f0f42005-07-18 11:38:02 +00001407 default:
1408 vpanic("getSPR(ppc32)");
cerione9d361a2005-03-04 17:35:29 +00001409 }
cerion76222262005-02-05 13:45:57 +00001410}
1411
sewardj0e2cc672005-07-29 21:58:51 +00001412
1413/* Write least-significant nibble of src to reg[field_idx] */
1414static void putReg_field ( PPC32SPR reg, IRExpr* src, UInt field_idx )
1415{
1416 vassert( typeOfIRExpr(irbb->tyenv,src ) == Ity_I32 );
1417 vassert( field_idx < 8 );
1418 vassert( reg < PPC32_SPR_MAX );
1419
1420 if (field_idx != 0) {
1421 src = binop(Iop_Shl32, src, mkU8(toUChar(field_idx * 4)));
1422 }
1423 putReg_masked( reg, src, (0xF << (field_idx*4)) );
1424}
1425
1426/* Write least-significant bit of src to reg[bit_idx] */
1427static void putReg_bit ( PPC32SPR reg, IRExpr* src, UInt bit_idx )
1428{
1429 vassert( typeOfIRExpr(irbb->tyenv,src ) == Ity_I32 );
1430 vassert( bit_idx < 32 );
1431 vassert( reg < PPC32_SPR_MAX );
1432
1433 if (bit_idx != 0) {
1434 src = binop(Iop_Shl32, src, mkU8(toUChar(bit_idx)));
1435 }
1436 putReg_masked( reg, src, (1<<bit_idx) );
1437}
cerion76222262005-02-05 13:45:57 +00001438
1439
cerione9d361a2005-03-04 17:35:29 +00001440/*------------------------------------------------------------*/
cerion3d870a32005-03-18 12:23:33 +00001441/*--- Integer Instruction Translation --- */
cerione9d361a2005-03-04 17:35:29 +00001442/*------------------------------------------------------------*/
cerion896a1372005-01-25 12:24:25 +00001443
cerion91ad5362005-01-27 23:02:41 +00001444/*
1445 Integer Arithmetic Instructions
1446*/
cerion645c9302005-01-31 10:09:59 +00001447static Bool dis_int_arith ( UInt theInstr )
cerion91ad5362005-01-27 23:02:41 +00001448{
cerionb85e8bb2005-02-16 08:54:33 +00001449 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
1450 UChar Rd_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
1451 UChar Ra_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
1452
1453 /* D-Form */
1454 UInt SIMM_16 = (theInstr >> 0) & 0xFFFF; /* theInstr[0:15] */
1455
1456 /* XO-Form */
1457 UChar Rb_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
1458 UChar flag_OE = toUChar((theInstr >> 10) & 1); /* theInstr[10] */
1459 UInt opc2 = (theInstr >> 1) & 0x1FF; /* theInstr[1:9] */
1460 UChar flag_Rc = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
1461
1462 UInt EXTS_SIMM = 0;
1463
1464 IRTemp Ra = newTemp(Ity_I32);
1465 IRTemp Rb = newTemp(Ity_I32);
1466 IRTemp Rd = newTemp(Ity_I32);
1467 IRTemp res64 = newTemp(Ity_I64); // multiplies need this.
cerion70e24122005-03-16 00:27:37 +00001468
sewardjb51f0f42005-07-18 11:38:02 +00001469//zz UInt flag_op = PPC32G_FLAG_OP_NUMBER;
cerionb85e8bb2005-02-16 08:54:33 +00001470 Bool do_rc = False;
cerion91ad5362005-01-27 23:02:41 +00001471
cerionb85e8bb2005-02-16 08:54:33 +00001472 assign( Ra, getIReg(Ra_addr) );
1473 assign( Rb, getIReg(Rb_addr) ); // XO-Form: Rd, Ra, Rb
1474 EXTS_SIMM = extend_s_16to32(SIMM_16); // D-Form: Rd, Ra, EXTS(SIMM)
cerion932ad942005-01-30 10:18:50 +00001475
sewardjb51f0f42005-07-18 11:38:02 +00001476//zz assign( xer_ca, getReg_bit( PPC32_SPR_XER, SHIFT_XER_CA ) );
1477
cerionb85e8bb2005-02-16 08:54:33 +00001478 switch (opc1) {
cerionb85e8bb2005-02-16 08:54:33 +00001479 /* D-Form */
cerione9d361a2005-03-04 17:35:29 +00001480 case 0x0C: // addic (Add Immediate Carrying, PPC32 p351
cerion3007c7f2005-02-23 23:13:29 +00001481 DIP("addic r%d,r%d,0x%x\n", Rd_addr, Ra_addr, EXTS_SIMM);
cerion4561acb2005-02-21 14:07:48 +00001482 assign( Rd, binop( Iop_Add32, mkexpr(Ra), mkU32(EXTS_SIMM) ) );
sewardjb51f0f42005-07-18 11:38:02 +00001483 set_XER_CA( PPC32G_FLAG_OP_ADD,
1484 mkexpr(Rd), mkexpr(Ra), mkU32(EXTS_SIMM),
1485 mkU32(0)/*old xer.ca, which is ignored*/ );
cerion4561acb2005-02-21 14:07:48 +00001486 break;
sewardjb51f0f42005-07-18 11:38:02 +00001487
cerione9d361a2005-03-04 17:35:29 +00001488 case 0x0D: // addic. (Add Immediate Carrying and Record, PPC32 p352)
cerion3007c7f2005-02-23 23:13:29 +00001489 DIP("addic. r%d,r%d,0x%x\n", Rd_addr, Ra_addr, EXTS_SIMM);
cerion4561acb2005-02-21 14:07:48 +00001490 assign( Rd, binop( Iop_Add32, mkexpr(Ra), mkU32(EXTS_SIMM) ) );
sewardjb51f0f42005-07-18 11:38:02 +00001491 set_XER_CA( PPC32G_FLAG_OP_ADD,
1492 mkexpr(Rd), mkexpr(Ra), mkU32(EXTS_SIMM),
1493 mkU32(0)/*old xer.ca, which is ignored*/ );
cerion70e24122005-03-16 00:27:37 +00001494 do_rc = True; // Always record to CR
cerion4561acb2005-02-21 14:07:48 +00001495 flag_Rc = 1;
1496 break;
1497
cerione9d361a2005-03-04 17:35:29 +00001498 case 0x0E: // addi (Add Immediate, PPC32 p350)
cerionb85e8bb2005-02-16 08:54:33 +00001499 // li rD,val == addi rD,0,val
1500 // la disp(rA) == addi rD,rA,disp
cerionb85e8bb2005-02-16 08:54:33 +00001501 if ( Ra_addr == 0 ) {
sewardjc7cd2142005-09-09 22:31:49 +00001502 DIP("li r%d,%d\n", Rd_addr, (Int)EXTS_SIMM);
cerionb85e8bb2005-02-16 08:54:33 +00001503 assign( Rd, mkU32(EXTS_SIMM) );
1504 } else {
sewardjc7cd2142005-09-09 22:31:49 +00001505 DIP("addi r%d,r%d,0x%x\n", Rd_addr, Ra_addr, (Int)SIMM_16);
cerionb85e8bb2005-02-16 08:54:33 +00001506 assign( Rd, binop( Iop_Add32, mkexpr(Ra), mkU32(EXTS_SIMM) ) );
1507 }
1508 break;
cerion91ad5362005-01-27 23:02:41 +00001509
cerione9d361a2005-03-04 17:35:29 +00001510 case 0x0F: // addis (Add Immediate Shifted, PPC32 p353)
cerionb85e8bb2005-02-16 08:54:33 +00001511 // lis rD,val == addis rD,0,val
cerionb85e8bb2005-02-16 08:54:33 +00001512 if ( Ra_addr == 0 ) {
sewardjc7cd2142005-09-09 22:31:49 +00001513 DIP("lis r%d,%d\n", Rd_addr, (Int)SIMM_16);
cerion7c1dd1b2005-02-22 18:39:18 +00001514 assign( Rd, mkU32(SIMM_16 << 16) );
cerionb85e8bb2005-02-16 08:54:33 +00001515 } else {
sewardjb51f0f42005-07-18 11:38:02 +00001516 DIP("addis r%d,r%d,0x%x\n", Rd_addr, Ra_addr, SIMM_16);
cerion7c1dd1b2005-02-22 18:39:18 +00001517 assign( Rd, binop(Iop_Add32, mkexpr(Ra), mkU32(SIMM_16 << 16)) );
cerionb85e8bb2005-02-16 08:54:33 +00001518 }
1519 break;
cerion91ad5362005-01-27 23:02:41 +00001520
cerione9d361a2005-03-04 17:35:29 +00001521 case 0x07: // mulli (Multiply Low Immediate, PPC32 p490)
cerionb85e8bb2005-02-16 08:54:33 +00001522 DIP("mulli r%d,r%d,0x%x\n", Rd_addr, Ra_addr, SIMM_16);
1523 assign( res64, binop(Iop_MullS32, mkexpr(Ra), mkU32(EXTS_SIMM)) );
1524 assign( Rd, unop(Iop_64to32, mkexpr(res64)) );
1525 break;
cerion38674602005-02-08 02:19:25 +00001526
cerione9d361a2005-03-04 17:35:29 +00001527 case 0x08: // subfic (Subtract from Immediate Carrying, PPC32 p540)
cerionb85e8bb2005-02-16 08:54:33 +00001528 DIP("subfic r%d,r%d,0x%x\n", Rd_addr, Ra_addr, SIMM_16);
cerion01908472005-02-25 16:43:08 +00001529 // rD = exts_simm - rA
cerion9d88da62005-02-25 10:23:46 +00001530 assign( Rd, binop(Iop_Sub32, mkU32(EXTS_SIMM), mkexpr(Ra)) );
sewardjb51f0f42005-07-18 11:38:02 +00001531 set_XER_CA( PPC32G_FLAG_OP_SUBFI,
1532 mkexpr(Rd), mkexpr(Ra), mkU32(EXTS_SIMM),
1533 mkU32(0)/*old xer.ca, which is ignored*/ );
cerionb85e8bb2005-02-16 08:54:33 +00001534 break;
cerion38674602005-02-08 02:19:25 +00001535
cerionb85e8bb2005-02-16 08:54:33 +00001536 /* XO-Form */
1537 case 0x1F:
cerionb85e8bb2005-02-16 08:54:33 +00001538 do_rc = True; // All below record to CR
1539
1540 switch (opc2) {
cerione9d361a2005-03-04 17:35:29 +00001541 case 0x10A: // add (Add, PPC32 p347)
cerionb85e8bb2005-02-16 08:54:33 +00001542 DIP("add%s%s r%d,r%d,r%d\n",
1543 flag_OE ? "o" : "", flag_Rc ? "." : "",
1544 Rd_addr, Ra_addr, Rb_addr);
1545 assign( Rd, binop(Iop_Add32, mkexpr(Ra), mkexpr(Rb)) );
cerion70e24122005-03-16 00:27:37 +00001546 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001547 set_XER_OV( PPC32G_FLAG_OP_ADD,
1548 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb) );
cerion70e24122005-03-16 00:27:37 +00001549 }
cerionb85e8bb2005-02-16 08:54:33 +00001550 break;
cerion91ad5362005-01-27 23:02:41 +00001551
cerione9d361a2005-03-04 17:35:29 +00001552 case 0x00A: // addc (Add Carrying, PPC32 p348)
cerionb85e8bb2005-02-16 08:54:33 +00001553 DIP("addc%s%s r%d,r%d,r%d\n",
1554 flag_OE ? "o" : "", flag_Rc ? "." : "",
1555 Rd_addr, Ra_addr, Rb_addr);
1556 assign( Rd, binop(Iop_Add32, mkexpr(Ra), mkexpr(Rb)) );
sewardjb51f0f42005-07-18 11:38:02 +00001557 set_XER_CA( PPC32G_FLAG_OP_ADD,
1558 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb),
1559 mkU32(0)/*old xer.ca, which is ignored*/ );
cerion70e24122005-03-16 00:27:37 +00001560 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001561 set_XER_OV( PPC32G_FLAG_OP_ADD,
1562 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb) );
cerion70e24122005-03-16 00:27:37 +00001563 }
cerionb85e8bb2005-02-16 08:54:33 +00001564 break;
1565
sewardjb51f0f42005-07-18 11:38:02 +00001566 case 0x08A: { // adde (Add Extended, PPC32 p349)
1567 IRTemp old_xer_ca = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00001568 DIP("adde%s%s r%d,r%d,r%d\n",
1569 flag_OE ? "o" : "", flag_Rc ? "." : "",
1570 Rd_addr, Ra_addr, Rb_addr);
1571 // rD = rA + rB + XER[CA]
sewardjb51f0f42005-07-18 11:38:02 +00001572 assign( old_xer_ca, get_XER_CA() );
cerionb85e8bb2005-02-16 08:54:33 +00001573 assign( Rd, binop(Iop_Add32, mkexpr(Ra),
sewardjb51f0f42005-07-18 11:38:02 +00001574 binop(Iop_Add32, mkexpr(Rb), mkexpr(old_xer_ca))) );
1575 set_XER_CA( PPC32G_FLAG_OP_ADDE,
1576 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb),
1577 mkexpr(old_xer_ca) );
cerion70e24122005-03-16 00:27:37 +00001578 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001579 set_XER_OV( PPC32G_FLAG_OP_ADDE,
1580 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb) );
cerion70e24122005-03-16 00:27:37 +00001581 }
cerionb85e8bb2005-02-16 08:54:33 +00001582 break;
sewardjb51f0f42005-07-18 11:38:02 +00001583 }
1584
1585 case 0x0EA: { // addme (Add to Minus One Extended, PPC32 p354)
1586 IRTemp old_xer_ca = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00001587 if (Rb_addr != 0) {
1588 vex_printf("dis_int_arith(PPC32)(addme,Rb_addr)\n");
1589 return False;
1590 }
1591 DIP("addme%s%s r%d,r%d,r%d\n",
1592 flag_OE ? "o" : "", flag_Rc ? "." : "",
1593 Rd_addr, Ra_addr, Rb_addr);
cerion70e24122005-03-16 00:27:37 +00001594 // rD = rA + (-1) + XER[CA]
1595 // => Just another form of adde
sewardjb51f0f42005-07-18 11:38:02 +00001596 assign( old_xer_ca, get_XER_CA() );
cerionb85e8bb2005-02-16 08:54:33 +00001597 assign( Rd, binop(Iop_Add32, mkexpr(Ra),
sewardjb51f0f42005-07-18 11:38:02 +00001598 binop(Iop_Add32, mkU32(-1), mkexpr(old_xer_ca)) ));
1599 set_XER_CA( PPC32G_FLAG_OP_ADDE,
1600 mkexpr(Rd), mkexpr(Ra), mkU32(-1),
1601 mkexpr(old_xer_ca) );
cerion70e24122005-03-16 00:27:37 +00001602 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001603 set_XER_OV( PPC32G_FLAG_OP_ADDE,
1604 mkexpr(Rd), mkexpr(Ra), mkU32(-1) );
cerion70e24122005-03-16 00:27:37 +00001605 }
cerionb85e8bb2005-02-16 08:54:33 +00001606 break;
sewardjb51f0f42005-07-18 11:38:02 +00001607 }
1608
1609 case 0x0CA: { // addze (Add to Zero Extended, PPC32 p355)
1610 IRTemp old_xer_ca = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00001611 if (Rb_addr != 0) {
1612 vex_printf("dis_int_arith(PPC32)(addze,Rb_addr)\n");
1613 return False;
1614 }
1615 DIP("addze%s%s r%d,r%d,r%d\n",
1616 flag_OE ? "o" : "", flag_Rc ? "." : "",
1617 Rd_addr, Ra_addr, Rb_addr);
cerion70e24122005-03-16 00:27:37 +00001618 // rD = rA + (0) + XER[CA]
1619 // => Just another form of adde
sewardjb51f0f42005-07-18 11:38:02 +00001620 assign( old_xer_ca, get_XER_CA() );
1621 assign( Rd, binop(Iop_Add32, mkexpr(Ra), mkexpr(old_xer_ca)) );
1622 set_XER_CA( PPC32G_FLAG_OP_ADDE,
1623 mkexpr(Rd), mkexpr(Ra), mkU32(0),
1624 mkexpr(old_xer_ca) );
cerion70e24122005-03-16 00:27:37 +00001625 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001626 set_XER_OV( PPC32G_FLAG_OP_ADDE,
1627 mkexpr(Rd), mkexpr(Ra), mkU32(0) );
cerion70e24122005-03-16 00:27:37 +00001628 }
cerionb85e8bb2005-02-16 08:54:33 +00001629 break;
sewardjb51f0f42005-07-18 11:38:02 +00001630 }
cerion91ad5362005-01-27 23:02:41 +00001631
cerione9d361a2005-03-04 17:35:29 +00001632 case 0x1EB: // divw (Divide Word, PPC32 p388)
cerionb85e8bb2005-02-16 08:54:33 +00001633 DIP("divw%s%s r%d,r%d,r%d\n",
1634 flag_OE ? "o" : "", flag_Rc ? "." : "",
1635 Rd_addr, Ra_addr, Rb_addr);
1636 assign( Rd, binop(Iop_DivS32, mkexpr(Ra), mkexpr(Rb)) );
cerion70e24122005-03-16 00:27:37 +00001637 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001638 set_XER_OV( PPC32G_FLAG_OP_DIVW,
1639 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb) );
cerion70e24122005-03-16 00:27:37 +00001640 }
cerionb85e8bb2005-02-16 08:54:33 +00001641 /* Note:
1642 if (0x8000_0000 / -1) or (x / 0)
1643 => Rd=undef, if(flag_Rc) CR7=undef, if(flag_OE) XER_OV=1
1644 => But _no_ exception raised. */
1645 break;
cerion91ad5362005-01-27 23:02:41 +00001646
cerione9d361a2005-03-04 17:35:29 +00001647 case 0x1CB: // divwu (Divide Word Unsigned, PPC32 p389)
cerionb85e8bb2005-02-16 08:54:33 +00001648 DIP("divwu%s%s r%d,r%d,r%d\n",
1649 flag_OE ? "o" : "", flag_Rc ? "." : "",
1650 Rd_addr, Ra_addr, Rb_addr);
1651 assign( Rd, binop(Iop_DivU32, mkexpr(Ra), mkexpr(Rb)) );
cerion70e24122005-03-16 00:27:37 +00001652 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001653 set_XER_OV( PPC32G_FLAG_OP_DIVWU,
1654 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb) );
cerion70e24122005-03-16 00:27:37 +00001655 }
cerionb85e8bb2005-02-16 08:54:33 +00001656 /* Note: ditto comment divw, for (x / 0) */
1657 break;
cerion91ad5362005-01-27 23:02:41 +00001658
cerione9d361a2005-03-04 17:35:29 +00001659 case 0x04B: // mulhw (Multiply High Word, PPC32 p488)
cerionb85e8bb2005-02-16 08:54:33 +00001660 if (flag_OE != 0) {
1661 vex_printf("dis_int_arith(PPC32)(mulhw,flag_OE)\n");
1662 return False;
1663 }
1664 DIP("mulhw%s r%d,r%d,r%d\n", flag_Rc ? "." : "",
1665 Rd_addr, Ra_addr, Rb_addr);
1666 assign( res64, binop(Iop_MullS32, mkexpr(Ra), mkexpr(Rb)) );
1667 assign( Rd, unop(Iop_64HIto32, mkexpr(res64)) );
1668 break;
cerionc19d5e12005-02-01 15:56:25 +00001669
cerione9d361a2005-03-04 17:35:29 +00001670 case 0x00B: // mulhwu (Multiply High Word Unsigned, PPC32 p489)
cerionb85e8bb2005-02-16 08:54:33 +00001671 if (flag_OE != 0) {
1672 vex_printf("dis_int_arith(PPC32)(mulhwu,flag_OE)\n");
1673 return False;
1674 }
1675 DIP("mulhwu%s r%d,r%d,r%d\n", flag_Rc ? "." : "",
1676 Rd_addr, Ra_addr, Rb_addr);
1677 assign( res64, binop(Iop_MullU32, mkexpr(Ra), mkexpr(Rb)) );
1678 assign( Rd, unop(Iop_64HIto32, mkexpr(res64)) );
1679 break;
1680
cerione9d361a2005-03-04 17:35:29 +00001681 case 0x0EB: // mullw (Multiply Low Word, PPC32 p491)
cerionb85e8bb2005-02-16 08:54:33 +00001682 DIP("mullw%s%s r%d,r%d,r%d\n",
1683 flag_OE ? "o" : "", flag_Rc ? "." : "",
1684 Rd_addr, Ra_addr, Rb_addr);
1685 assign( res64, binop(Iop_MullU32, mkexpr(Ra), mkexpr(Rb)) );
1686 assign( Rd, unop(Iop_64to32, mkexpr(res64)) );
cerion70e24122005-03-16 00:27:37 +00001687 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001688 set_XER_OV( PPC32G_FLAG_OP_MULLW,
1689 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb) );
cerion70e24122005-03-16 00:27:37 +00001690 }
cerionb85e8bb2005-02-16 08:54:33 +00001691 break;
cerionc19d5e12005-02-01 15:56:25 +00001692
cerione9d361a2005-03-04 17:35:29 +00001693 case 0x068: // neg (Negate, PPC32 p493)
cerionb85e8bb2005-02-16 08:54:33 +00001694 if (Rb_addr != 0) {
1695 vex_printf("dis_int_arith(PPC32)(neg,Rb_addr)\n");
1696 return False;
1697 }
1698 DIP("neg%s%s r%d,r%d\n",
1699 flag_OE ? "o" : "", flag_Rc ? "." : "",
1700 Rd_addr, Ra_addr);
1701 // rD = (log not)rA + 1
1702 assign( Rd, binop(Iop_Add32,
1703 unop(Iop_Not32, mkexpr(Ra)), mkU32(1)) );
cerion70e24122005-03-16 00:27:37 +00001704 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001705 set_XER_OV( PPC32G_FLAG_OP_NEG,
1706 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb) );
cerion70e24122005-03-16 00:27:37 +00001707 }
cerionb85e8bb2005-02-16 08:54:33 +00001708 break;
cerion91ad5362005-01-27 23:02:41 +00001709
cerione9d361a2005-03-04 17:35:29 +00001710 case 0x028: // subf (Subtract From, PPC32 p537)
cerionb85e8bb2005-02-16 08:54:33 +00001711 DIP("subf%s%s r%d,r%d,r%d\n",
1712 flag_OE ? "o" : "", flag_Rc ? "." : "",
1713 Rd_addr, Ra_addr, Rb_addr);
cerion01908472005-02-25 16:43:08 +00001714 // rD = rB - rA
1715 assign( Rd, binop(Iop_Sub32, mkexpr(Rb), mkexpr(Ra)) );
cerion70e24122005-03-16 00:27:37 +00001716 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001717 set_XER_OV( PPC32G_FLAG_OP_SUBF,
1718 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb) );
cerion70e24122005-03-16 00:27:37 +00001719 }
cerionb85e8bb2005-02-16 08:54:33 +00001720 break;
cerion38674602005-02-08 02:19:25 +00001721
cerione9d361a2005-03-04 17:35:29 +00001722 case 0x008: // subfc (Subtract from Carrying, PPC32 p538)
cerionb85e8bb2005-02-16 08:54:33 +00001723 DIP("subfc%s%s r%d,r%d,r%d\n",
1724 flag_OE ? "o" : "", flag_Rc ? "." : "",
1725 Rd_addr, Ra_addr, Rb_addr);
cerion01908472005-02-25 16:43:08 +00001726 // rD = rB - rA
1727 assign( Rd, binop(Iop_Sub32, mkexpr(Rb), mkexpr(Ra)) );
sewardjb51f0f42005-07-18 11:38:02 +00001728 set_XER_CA( PPC32G_FLAG_OP_SUBFC,
1729 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb),
1730 mkU32(0)/*old xer.ca, which is ignored*/ );
cerion70e24122005-03-16 00:27:37 +00001731 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001732 set_XER_OV( PPC32G_FLAG_OP_SUBFC,
1733 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb) );
cerion70e24122005-03-16 00:27:37 +00001734 }
cerionb85e8bb2005-02-16 08:54:33 +00001735 break;
1736
sewardjb51f0f42005-07-18 11:38:02 +00001737 case 0x088: {// subfe (Subtract from Extended, PPC32 p539)
1738 IRTemp old_xer_ca = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00001739 DIP("subfe%s%s r%d,r%d,r%d\n",
1740 flag_OE ? "o" : "", flag_Rc ? "." : "",
1741 Rd_addr, Ra_addr, Rb_addr);
1742 // rD = (log not)rA + rB + XER[CA]
sewardjb51f0f42005-07-18 11:38:02 +00001743 assign( old_xer_ca, get_XER_CA() );
cerionb85e8bb2005-02-16 08:54:33 +00001744 assign( Rd, binop(Iop_Add32, unop(Iop_Not32, mkexpr(Ra)),
sewardjb51f0f42005-07-18 11:38:02 +00001745 binop(Iop_Add32, mkexpr(Rb), mkexpr(old_xer_ca))) );
1746 set_XER_CA( PPC32G_FLAG_OP_SUBFE,
1747 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb),
1748 mkexpr(old_xer_ca) );
cerion70e24122005-03-16 00:27:37 +00001749 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001750 set_XER_OV( PPC32G_FLAG_OP_SUBFE,
1751 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb) );
cerion70e24122005-03-16 00:27:37 +00001752 }
cerionb85e8bb2005-02-16 08:54:33 +00001753 break;
sewardjb51f0f42005-07-18 11:38:02 +00001754 }
1755
sewardj20ef5472005-07-21 14:48:31 +00001756 case 0x0E8: { // subfme (Subtract from Minus One Extended, PPC32 p541)
1757 IRTemp old_xer_ca = newTemp(Ity_I32);
1758 if (Rb_addr != 0) {
1759 vex_printf("dis_int_arith(PPC32)(subfme,Rb_addr)\n");
1760 return False;
1761 }
1762 DIP("subfme%s%s r%d,r%d\n",
1763 flag_OE ? "o" : "", flag_Rc ? "." : "",
1764 Rd_addr, Ra_addr);
1765 // rD = (log not)rA + (-1) + XER[CA]
1766 // => Just another form of subfe
1767 assign( old_xer_ca, get_XER_CA() );
1768 assign( Rd, binop(Iop_Add32, unop(Iop_Not32, mkexpr(Ra)),
1769 binop(Iop_Add32, mkU32(-1), mkexpr(old_xer_ca))) );
1770 set_XER_CA( PPC32G_FLAG_OP_SUBFE,
1771 mkexpr(Rd), mkexpr(Ra), mkU32(-1),
1772 mkexpr(old_xer_ca) );
1773 if (flag_OE) {
1774 set_XER_OV( PPC32G_FLAG_OP_SUBFE,
1775 mkexpr(Rd), mkexpr(Ra), mkU32(-1) );
1776 }
1777 break;
1778 }
1779
sewardjb51f0f42005-07-18 11:38:02 +00001780 case 0x0C8: { // subfze (Subtract from Zero Extended, PPC32 p542)
1781 IRTemp old_xer_ca = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00001782 if (Rb_addr != 0) {
1783 vex_printf("dis_int_arith(PPC32)(subfze,Rb_addr)\n");
1784 return False;
1785 }
1786 DIP("subfze%s%s r%d,r%d\n",
1787 flag_OE ? "o" : "", flag_Rc ? "." : "",
1788 Rd_addr, Ra_addr);
cerion70e24122005-03-16 00:27:37 +00001789 // rD = (log not)rA + (0) + XER[CA]
1790 // => Just another form of subfe
sewardjb51f0f42005-07-18 11:38:02 +00001791 assign( old_xer_ca, get_XER_CA() );
1792 assign( Rd, binop(Iop_Add32,
1793 unop(Iop_Not32, mkexpr(Ra)), mkexpr(old_xer_ca)) );
1794 set_XER_CA( PPC32G_FLAG_OP_SUBFE,
1795 mkexpr(Rd), mkexpr(Ra), mkU32(0),
1796 mkexpr(old_xer_ca) );
cerion70e24122005-03-16 00:27:37 +00001797 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001798 set_XER_OV( PPC32G_FLAG_OP_SUBFE,
1799 mkexpr(Rd), mkexpr(Ra), mkU32(0) );
cerion70e24122005-03-16 00:27:37 +00001800 }
cerionb85e8bb2005-02-16 08:54:33 +00001801 break;
sewardjb51f0f42005-07-18 11:38:02 +00001802 }
cerionae694622005-01-28 17:52:47 +00001803
cerionb85e8bb2005-02-16 08:54:33 +00001804 default:
1805 vex_printf("dis_int_arith(PPC32)(opc2)\n");
1806 return False;
1807 }
1808 break;
1809 default:
1810 vex_printf("dis_int_arith(PPC32)(opc1)\n");
1811 return False;
1812 }
cerion91ad5362005-01-27 23:02:41 +00001813
cerionb85e8bb2005-02-16 08:54:33 +00001814 putIReg( Rd_addr, mkexpr(Rd) );
cerionb85e8bb2005-02-16 08:54:33 +00001815 if (do_rc && flag_Rc) {
sewardj20ef5472005-07-21 14:48:31 +00001816 set_CR0( mkexpr(Rd) );
cerionb85e8bb2005-02-16 08:54:33 +00001817 }
1818 return True;
cerion91ad5362005-01-27 23:02:41 +00001819}
1820
1821
1822
cerion3d870a32005-03-18 12:23:33 +00001823/*
1824 Integer Compare Instructions
1825*/
cerion7aa4bbc2005-01-29 09:32:07 +00001826static Bool dis_int_cmp ( UInt theInstr )
1827{
cerionb85e8bb2005-02-16 08:54:33 +00001828 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
1829 UChar crfD = toUChar((theInstr >> 23) & 0x7); /* theInstr[23:25] */
1830 UChar b9 = toUChar((theInstr >> 22) & 0x1); /* theInstr[22] */
1831 UChar flag_L = toUChar((theInstr >> 21) & 0x1); /* theInstr[21] */
1832 UChar Ra_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
1833
1834 /* D-Form */
cerionb85e8bb2005-02-16 08:54:33 +00001835 UInt UIMM_16 = (theInstr >> 0) & 0xFFFF; /* theInstr[0:15] */
1836
1837 /* X-Form */
1838 UChar Rb_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
1839 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
1840 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
1841
1842 UInt EXTS_SIMM = 0;
cerione9d361a2005-03-04 17:35:29 +00001843 IRTemp Ra = newTemp(Ity_I32);
1844 IRTemp Rb = newTemp(Ity_I32);
sewardj7f080782005-07-27 00:22:15 +00001845//uu IRTemp xer_so = newTemp(Ity_I32);
1846//uu IRTemp cr7 = newTemp(Ity_I32);
1847//uu IRTemp mux1 = newTemp(Ity_I32);
1848//uu IRTemp mux2 = newTemp(Ity_I32);
1849//uu IRExpr* irx_cmp_lt;
1850//uu IRExpr* irx_cmp_eq;
cerion7aa4bbc2005-01-29 09:32:07 +00001851
cerionb85e8bb2005-02-16 08:54:33 +00001852 assign( Ra, getIReg(Ra_addr) );
1853
1854 if (flag_L==1) { // L==1 invalid for 32 bit.
1855 vex_printf("dis_int_cmp(PPC32)(flag_L)\n");
1856 return False;
1857 }
1858
1859 if (b9 != 0) {
1860 vex_printf("dis_int_cmp(PPC32)(b9)\n");
1861 return False;
1862 }
1863
1864 switch (opc1) {
sewardjb51f0f42005-07-18 11:38:02 +00001865 case 0x0B: // cmpi (Compare Immediate, PPC32 p368)
1866 EXTS_SIMM = extend_s_16to32(UIMM_16);
sewardjc7cd2142005-09-09 22:31:49 +00001867 DIP("cmp cr%d,r%d,%d\n", crfD, Ra_addr, (Int)EXTS_SIMM);
sewardjb51f0f42005-07-18 11:38:02 +00001868 putCR321( crfD, unop(Iop_32to8,
1869 binop(Iop_CmpORD32S, mkexpr(Ra),
1870 mkU32(EXTS_SIMM))) );
1871 putCR0( crfD, getXER_SO() );
1872 break;
1873
1874 case 0x0A: // cmpli (Compare Logical Immediate, PPC32 p370)
1875 DIP("cmpli cr%d,r%d,0x%x\n", crfD, Ra_addr, UIMM_16);
1876 putCR321( crfD, unop(Iop_32to8,
1877 binop(Iop_CmpORD32U, mkexpr(Ra),
1878 mkU32(UIMM_16))) );
1879 putCR0( crfD, getXER_SO() );
1880 break;
cerionb85e8bb2005-02-16 08:54:33 +00001881
1882 /* X Form */
1883 case 0x1F:
1884 if (b0 != 0) {
1885 vex_printf("dis_int_cmp(PPC32)(0x1F,b0)\n");
1886 return False;
1887 }
cerione9d361a2005-03-04 17:35:29 +00001888 assign( Rb, getIReg(Rb_addr) );
sewardjb51f0f42005-07-18 11:38:02 +00001889//zz irx_cmp_eq = binop(Iop_CmpEQ32, mkexpr(Ra), mkexpr(Rb));
cerion7aa4bbc2005-01-29 09:32:07 +00001890
cerionb85e8bb2005-02-16 08:54:33 +00001891 switch (opc2) {
sewardjb51f0f42005-07-18 11:38:02 +00001892 case 0x000: // cmp (Compare, PPC32 p367)
1893 DIP("cmp cr%d,r%d,r%d\n", crfD, Ra_addr, Rb_addr);
1894 putCR321( crfD, unop(Iop_32to8,
1895 binop(Iop_CmpORD32S, mkexpr(Ra), mkexpr(Rb))) );
1896 putCR0( crfD, getXER_SO() );
1897 break;
cerionb85e8bb2005-02-16 08:54:33 +00001898
sewardjb51f0f42005-07-18 11:38:02 +00001899 case 0x020: // cmpl (Compare Logical, PPC32 p369)
1900 DIP("cmpl cr%d,r%d,r%d\n", crfD, Ra_addr, Rb_addr);
1901 putCR321( crfD, unop(Iop_32to8,
1902 binop(Iop_CmpORD32U, mkexpr(Ra), mkexpr(Rb))) );
1903 putCR0( crfD, getXER_SO() );
1904 break;
cerion7aa4bbc2005-01-29 09:32:07 +00001905
sewardjb51f0f42005-07-18 11:38:02 +00001906 default:
1907 vex_printf("dis_int_cmp(PPC32)(opc2)\n");
1908 return False;
cerionb85e8bb2005-02-16 08:54:33 +00001909 }
1910 break;
cerion7aa4bbc2005-01-29 09:32:07 +00001911
cerionb85e8bb2005-02-16 08:54:33 +00001912 default:
1913 vex_printf("dis_int_cmp(PPC32)(opc1)\n");
1914 return False;
1915 }
1916
sewardjb51f0f42005-07-18 11:38:02 +00001917//zz irx_cmp_lt = unop(Iop_1Uto8, irx_cmp_lt);
1918//zz irx_cmp_eq = unop(Iop_1Uto8, irx_cmp_eq);
1919//zz
1920//zz // mux_shift_bit = (argL < argR) ? LT : GT (or EQ...)
1921//zz assign( mux1, IRExpr_Mux0X( irx_cmp_lt, mkU32(SHIFT_CR_GT), mkU32(SHIFT_CR_LT) ));
1922//zz
1923//zz // mux_shift_bit = (argL == argR) ? EQ : GT|LT
1924//zz assign( mux2, IRExpr_Mux0X( irx_cmp_eq, mkexpr(mux1), mkU32(SHIFT_CR_EQ) ));
1925//zz
1926//zz assign( xer_so, getReg_bit( PPC32_SPR_XER, SHIFT_XER_SO ) );
1927//zz assign( cr7, binop(Iop_Or32, mkexpr(mux2), mkexpr(xer_so)) );
1928//zz putReg_field( PPC32_SPR_CR, mkexpr(cr7), 7-crfD );
1929//zz return True;
cerionb85e8bb2005-02-16 08:54:33 +00001930 return True;
cerion7aa4bbc2005-01-29 09:32:07 +00001931}
1932
1933
cerion3d870a32005-03-18 12:23:33 +00001934/*
1935 Integer Logical Instructions
1936*/
cerion7aa4bbc2005-01-29 09:32:07 +00001937static Bool dis_int_logic ( UInt theInstr )
1938{
cerionb85e8bb2005-02-16 08:54:33 +00001939 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
1940 UChar Rs_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
1941 UChar Ra_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
1942
1943 /* D-Form */
1944 UInt UIMM_16 = (theInstr >> 0) & 0xFFFF; /* theInstr[0:15] */
1945
1946 /* X-Form */
1947 UChar Rb_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
1948 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
1949 UChar flag_Rc = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
1950
1951 Bool do_rc = False;
1952
1953 IRTemp Rs = newTemp(Ity_I32);
1954 IRTemp Ra = newTemp(Ity_I32);
1955 IRTemp Rb = newTemp(Ity_I32);
sewardj7f080782005-07-27 00:22:15 +00001956//uu IRTemp Sign = newTemp(Ity_I32);
cerione9d361a2005-03-04 17:35:29 +00001957 IRExpr* irx;
cerionb85e8bb2005-02-16 08:54:33 +00001958
ceriona31e8b52005-02-21 16:30:45 +00001959 assign( Rs, getIReg(Rs_addr) );
1960 assign( Rb, getIReg(Rb_addr) );
cerionb85e8bb2005-02-16 08:54:33 +00001961
1962 switch (opc1) {
cerione9d361a2005-03-04 17:35:29 +00001963 case 0x1C: // andi. (AND Immediate, PPC32 p358)
cerion4561acb2005-02-21 14:07:48 +00001964 DIP("andi. r%d,r%d,0x%x\n", Ra_addr, Rs_addr, UIMM_16);
cerionb85e8bb2005-02-16 08:54:33 +00001965 assign( Ra, binop(Iop_And32, mkexpr(Rs), mkU32(UIMM_16)) );
cerion70e24122005-03-16 00:27:37 +00001966 do_rc = True; // Always record to CR
cerionb85e8bb2005-02-16 08:54:33 +00001967 flag_Rc = 1;
1968 break;
1969
cerione9d361a2005-03-04 17:35:29 +00001970 case 0x1D: // andis. (AND Immediate Shifted, PPC32 p359)
cerionb85e8bb2005-02-16 08:54:33 +00001971 DIP("andis r%d,r%d,0x%x\n", Ra_addr, Rs_addr, UIMM_16);
1972 assign( Ra, binop(Iop_And32, mkexpr(Rs), mkU32(UIMM_16 << 16)) );
cerion70e24122005-03-16 00:27:37 +00001973 do_rc = True; // Always record to CR
cerionb85e8bb2005-02-16 08:54:33 +00001974 flag_Rc = 1;
1975 break;
cerion7aa4bbc2005-01-29 09:32:07 +00001976
cerione9d361a2005-03-04 17:35:29 +00001977 case 0x18: // ori (OR Immediate, PPC32 p497)
cerionb85e8bb2005-02-16 08:54:33 +00001978 DIP("ori r%d,r%d,0x%x\n", Ra_addr, Rs_addr, UIMM_16);
cerion70e24122005-03-16 00:27:37 +00001979 assign( Ra, binop(Iop_Or32, mkexpr(Rs), mkU32(UIMM_16)) );
cerionb85e8bb2005-02-16 08:54:33 +00001980 break;
cerion7aa4bbc2005-01-29 09:32:07 +00001981
cerione9d361a2005-03-04 17:35:29 +00001982 case 0x19: // oris (OR Immediate Shifted, PPC32 p498)
cerionb85e8bb2005-02-16 08:54:33 +00001983 DIP("oris r%d,r%d,0x%x\n", Ra_addr, Rs_addr, UIMM_16);
cerion70e24122005-03-16 00:27:37 +00001984 assign( Ra, binop(Iop_Or32, mkexpr(Rs), mkU32(UIMM_16 << 16)) );
cerionb85e8bb2005-02-16 08:54:33 +00001985 break;
cerionaabdfbf2005-01-29 12:56:15 +00001986
cerione9d361a2005-03-04 17:35:29 +00001987 case 0x1A: // xori (XOR Immediate, PPC32 p550)
cerionb85e8bb2005-02-16 08:54:33 +00001988 DIP("xori r%d,r%d,0x%x\n", Ra_addr, Rs_addr, UIMM_16);
cerion70e24122005-03-16 00:27:37 +00001989 assign( Ra, binop(Iop_Xor32, mkexpr(Rs), mkU32(UIMM_16)) );
cerionb85e8bb2005-02-16 08:54:33 +00001990 break;
cerion38674602005-02-08 02:19:25 +00001991
cerione9d361a2005-03-04 17:35:29 +00001992 case 0x1B: // xoris (XOR Immediate Shifted, PPC32 p551)
cerionb85e8bb2005-02-16 08:54:33 +00001993 DIP("xoris r%d,r%d,0x%x\n", Ra_addr, Rs_addr, UIMM_16);
cerion70e24122005-03-16 00:27:37 +00001994 assign( Ra, binop(Iop_Xor32, mkexpr(Rs), mkU32(UIMM_16 << 16)) );
cerionb85e8bb2005-02-16 08:54:33 +00001995 break;
cerionaabdfbf2005-01-29 12:56:15 +00001996
cerionb85e8bb2005-02-16 08:54:33 +00001997 /* X Form */
1998 case 0x1F:
cerion70e24122005-03-16 00:27:37 +00001999 do_rc = True; // All below record to CR
2000
cerionb85e8bb2005-02-16 08:54:33 +00002001 switch (opc2) {
sewardjb51f0f42005-07-18 11:38:02 +00002002 case 0x01C: // and (AND, PPC32 p356)
2003 DIP("and%s r%d,r%d,r%d\n",
2004 flag_Rc ? "." : "", Ra_addr, Rs_addr, Rb_addr);
2005 assign(Ra, binop(Iop_And32, mkexpr(Rs), mkexpr(Rb)));
2006 break;
cerionb85e8bb2005-02-16 08:54:33 +00002007
sewardjb51f0f42005-07-18 11:38:02 +00002008 case 0x03C: // andc (AND with Complement, PPC32 p357)
2009 DIP("andc%s r%d,r%d,r%d\n",
2010 flag_Rc ? "." : "", Ra_addr, Rs_addr, Rb_addr);
2011 assign(Ra, binop(Iop_And32, mkexpr(Rs),
2012 unop(Iop_Not32, mkexpr(Rb))));
2013 break;
2014
2015 case 0x01A: // cntlzw (Count Leading Zeros Word, PPC32 p371)
2016 if (Rb_addr!=0) {
2017 vex_printf("dis_int_logic(PPC32)(cntlzw,Rb_addr)\n");
2018 return False;
2019 }
2020 DIP("cntlzw%s r%d,r%d\n",
2021 flag_Rc ? "." : "", Ra_addr, Rs_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002022
sewardjb51f0f42005-07-18 11:38:02 +00002023 // Iop_Clz32 undefined for arg==0, so deal with that case:
2024 irx = binop(Iop_CmpNE32, mkexpr(Rs), mkU32(0));
2025 assign(Ra, IRExpr_Mux0X( unop(Iop_1Uto8, irx),
2026 mkU32(32),
2027 unop(Iop_Clz32, mkexpr(Rs)) ));
sewardjc808ef72005-08-18 11:50:43 +00002028 // alternatively: assign(Ra, verbose_Clz32(Rs));
sewardjb51f0f42005-07-18 11:38:02 +00002029 break;
cerion7aa4bbc2005-01-29 09:32:07 +00002030
sewardj20ef5472005-07-21 14:48:31 +00002031 case 0x11C: // eqv (Equivalent, PPC32 p396)
2032 DIP("eqv%s r%d,r%d,r%d\n",
2033 flag_Rc ? "." : "", Ra_addr, Rs_addr, Rb_addr);
2034 assign( Ra, unop(Iop_Not32, binop(Iop_Xor32,
2035 mkexpr(Rs), mkexpr(Rb))) );
2036 break;
cerion7aa4bbc2005-01-29 09:32:07 +00002037
cerione9d361a2005-03-04 17:35:29 +00002038 case 0x3BA: // extsb (Extend Sign Byte, PPC32 p397
cerionb85e8bb2005-02-16 08:54:33 +00002039 if (Rb_addr!=0) {
2040 vex_printf("dis_int_logic(PPC32)(extsb,Rb_addr)\n");
2041 return False;
2042 }
2043 DIP("extsb%s r%d,r%d\n",
2044 flag_Rc ? "." : "", Ra_addr, Rs_addr);
sewardjb51f0f42005-07-18 11:38:02 +00002045 assign( Ra, unop(Iop_8Sto32, unop(Iop_32to8, mkexpr(Rs))) );
cerionb85e8bb2005-02-16 08:54:33 +00002046 break;
cerion7aa4bbc2005-01-29 09:32:07 +00002047
cerione9d361a2005-03-04 17:35:29 +00002048 case 0x39A: // extsh (Extend Sign Half Word, PPC32 p398)
cerionb85e8bb2005-02-16 08:54:33 +00002049 if (Rb_addr!=0) {
2050 vex_printf("dis_int_logic(PPC32)(extsh,Rb_addr)\n");
2051 return False;
2052 }
2053 DIP("extsh%s r%d,r%d\n",
2054 flag_Rc ? "." : "", Ra_addr, Rs_addr);
sewardjb51f0f42005-07-18 11:38:02 +00002055 assign( Ra, unop(Iop_16Sto32, unop(Iop_32to16, mkexpr(Rs))) );
cerionb85e8bb2005-02-16 08:54:33 +00002056 break;
cerion7aa4bbc2005-01-29 09:32:07 +00002057
cerione9d361a2005-03-04 17:35:29 +00002058 case 0x1DC: // nand (NAND, PPC32 p492)
cerionb85e8bb2005-02-16 08:54:33 +00002059 DIP("nand%s r%d,r%d,r%d\n",
2060 flag_Rc ? "." : "", Ra_addr, Rs_addr, Rb_addr);
2061 assign( Ra, unop(Iop_Not32,
2062 binop(Iop_And32, mkexpr(Rs), mkexpr(Rb))) );
2063 break;
2064
cerione9d361a2005-03-04 17:35:29 +00002065 case 0x07C: // nor (NOR, PPC32 p494)
cerionb85e8bb2005-02-16 08:54:33 +00002066 DIP("nor%s r%d,r%d,r%d\n",
2067 flag_Rc ? "." : "", Ra_addr, Rs_addr, Rb_addr);
2068 assign( Ra, unop(Iop_Not32,
2069 binop(Iop_Or32, mkexpr(Rs), mkexpr(Rb))) );
2070 break;
cerion7aa4bbc2005-01-29 09:32:07 +00002071
cerione9d361a2005-03-04 17:35:29 +00002072 case 0x1BC: // or (OR, PPC32 p495)
sewardjb51f0f42005-07-18 11:38:02 +00002073 if ((!flag_Rc) && Rs_addr == Rb_addr) {
2074 DIP("mr r%d,r%d\n", Ra_addr, Rs_addr);
2075 assign( Ra, mkexpr(Rs) );
2076 } else {
2077 DIP("or%s r%d,r%d,r%d\n",
2078 flag_Rc ? "." : "", Ra_addr, Rs_addr, Rb_addr);
2079 assign( Ra, binop(Iop_Or32, mkexpr(Rs), mkexpr(Rb)) );
2080 }
cerionb85e8bb2005-02-16 08:54:33 +00002081 break;
cerion7aa4bbc2005-01-29 09:32:07 +00002082
cerione9d361a2005-03-04 17:35:29 +00002083 case 0x19C: // orc (OR with Complement, PPC32 p496)
cerionb85e8bb2005-02-16 08:54:33 +00002084 DIP("orc%s r%d,r%d,r%d\n",
2085 flag_Rc ? "." : "", Ra_addr, Rs_addr, Rb_addr);
2086 assign( Ra, binop(Iop_Or32, mkexpr(Rs),
2087 unop(Iop_Not32, mkexpr(Rb))) );
2088 break;
2089
cerione9d361a2005-03-04 17:35:29 +00002090 case 0x13C: // xor (XOR, PPC32 p549)
cerionb85e8bb2005-02-16 08:54:33 +00002091 DIP("xor%s r%d,r%d,r%d\n",
2092 flag_Rc ? "." : "", Ra_addr, Rs_addr, Rb_addr);
2093 assign( Ra, binop(Iop_Xor32, mkexpr(Rs), mkexpr(Rb)) );
2094 break;
cerion7aa4bbc2005-01-29 09:32:07 +00002095
cerionb85e8bb2005-02-16 08:54:33 +00002096 default:
2097 vex_printf("dis_int_logic(PPC32)(opc2)\n");
2098 return False;
2099 }
cerionb85e8bb2005-02-16 08:54:33 +00002100 break;
2101
2102 default:
2103 vex_printf("dis_int_logic(PPC32)(opc1)\n");
2104 return False;
2105 }
cerion70e24122005-03-16 00:27:37 +00002106
2107 putIReg( Ra_addr, mkexpr(Ra) );
cerionb85e8bb2005-02-16 08:54:33 +00002108 if (do_rc && flag_Rc) {
sewardj20ef5472005-07-21 14:48:31 +00002109 set_CR0( mkexpr(Ra) );
cerionb85e8bb2005-02-16 08:54:33 +00002110 }
2111 return True;
cerion645c9302005-01-31 10:09:59 +00002112}
2113
2114
2115
cerion3d870a32005-03-18 12:23:33 +00002116/*
2117 Integer Rotate Instructions
2118*/
cerion645c9302005-01-31 10:09:59 +00002119static Bool dis_int_rot ( UInt theInstr )
2120{
cerionb85e8bb2005-02-16 08:54:33 +00002121 /* M-Form */
2122 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
2123 UChar Rs_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
2124 UChar Ra_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
2125 UChar Rb_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
2126 UChar sh_imm = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
2127 UChar MaskBegin = toUChar((theInstr >> 6) & 0x1F); /* theInstr[6:10] */
2128 UChar MaskEnd = toUChar((theInstr >> 1) & 0x1F); /* theInstr[1:5] */
2129 UChar flag_Rc = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
2130
cerion239e2e42005-02-24 16:59:17 +00002131 UInt mask = MASK(31-MaskEnd, 31-MaskBegin);
cerionb85e8bb2005-02-16 08:54:33 +00002132 IRTemp Rs = newTemp(Ity_I32);
2133 IRTemp Ra = newTemp(Ity_I32);
2134 IRTemp Rb = newTemp(Ity_I32);
2135
2136 assign( Rs, getIReg(Rs_addr) );
2137 assign( Rb, getIReg(Rb_addr) );
cerione9d361a2005-03-04 17:35:29 +00002138
cerionb85e8bb2005-02-16 08:54:33 +00002139 switch (opc1) {
sewardjc9659532005-07-21 21:33:57 +00002140 case 0x14:
2141 // rlwimi (Rotate Left Word Immediate then Mask Insert, PPC32 p500)
sewardjdb36c0f2005-07-03 00:05:31 +00002142 DIP("rlwimi%s r%d,r%d,%d,%d,%d\n", flag_Rc ? "." : "",
cerionb85e8bb2005-02-16 08:54:33 +00002143 Ra_addr, Rs_addr, sh_imm, MaskBegin, MaskEnd);
2144 // Ra = (ROTL(Rs, Imm) & mask) | (Ra & ~mask);
2145 assign( Ra, binop(Iop_Or32,
2146 binop(Iop_And32, mkU32(mask),
sewardjc9659532005-07-21 21:33:57 +00002147 ROTL32(mkexpr(Rs), mkU32(sh_imm))),
cerionb85e8bb2005-02-16 08:54:33 +00002148 binop(Iop_And32, getIReg(Ra_addr), mkU32(~mask))) );
2149 break;
cerion645c9302005-01-31 10:09:59 +00002150
sewardjc9659532005-07-21 21:33:57 +00002151 case 0x15:
2152 // rlwinm (Rotate Left Word Immediate then AND with Mask, PPC32 p501)
sewardjdb36c0f2005-07-03 00:05:31 +00002153 DIP("rlwinm%s r%d,r%d,%d,%d,%d\n", flag_Rc ? "." : "",
cerionb85e8bb2005-02-16 08:54:33 +00002154 Ra_addr, Rs_addr, sh_imm, MaskBegin, MaskEnd);
2155 // Ra = ROTL(Rs, Imm) & mask
sewardjc9659532005-07-21 21:33:57 +00002156 assign( Ra, binop(Iop_And32, ROTL32(mkexpr(Rs), mkU32(sh_imm)),
sewardjb51f0f42005-07-18 11:38:02 +00002157 mkU32(mask)) );
cerionb85e8bb2005-02-16 08:54:33 +00002158 break;
cerion45b70ff2005-01-31 17:03:25 +00002159
sewardjc9659532005-07-21 21:33:57 +00002160 case 0x17:
2161 // rlwnm (Rotate Left Word then AND with Mask, PPC32 p503
2162 DIP("rlwnm%s r%d,r%d,r%d,%d,%d\n", flag_Rc ? "." : "",
2163 Ra_addr, Rs_addr, Rb_addr, MaskBegin, MaskEnd);
2164 // Ra = ROTL(Rs, Rb[0-4]) & mask
2165 // note, ROTL32 does the masking, so we don't do it here
2166 assign( Ra, binop(Iop_And32, ROTL32(mkexpr(Rs), mkexpr(Rb)),
2167 mkU32(mask)) );
2168 break;
cerion45b70ff2005-01-31 17:03:25 +00002169
cerionb85e8bb2005-02-16 08:54:33 +00002170 default:
2171 vex_printf("dis_int_rot(PPC32)(opc1)\n");
2172 return False;
2173 }
cerion645c9302005-01-31 10:09:59 +00002174
cerionb85e8bb2005-02-16 08:54:33 +00002175 putIReg( Ra_addr, mkexpr(Ra) );
2176 if (flag_Rc) {
sewardj20ef5472005-07-21 14:48:31 +00002177 set_CR0( mkexpr(Ra) );
cerionb85e8bb2005-02-16 08:54:33 +00002178 }
2179 return True;
cerion645c9302005-01-31 10:09:59 +00002180}
2181
2182
2183
cerion3d870a32005-03-18 12:23:33 +00002184/*
2185 Integer Load Instructions
2186*/
cerion645c9302005-01-31 10:09:59 +00002187static Bool dis_int_load ( UInt theInstr )
2188{
cerionb85e8bb2005-02-16 08:54:33 +00002189 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
2190 UChar Rd_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
2191 UChar Ra_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
2192
2193 /* D-Form */
2194 UInt d_imm = (theInstr >> 0) & 0xFFFF; /* theInstr[0:15] */
2195
2196 /* X-Form */
2197 UChar Rb_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
2198 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
2199 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
2200
2201 UInt exts_d_imm = extend_s_16to32(d_imm);
2202
2203 IRTemp Ra_or_0 = newTemp(Ity_I32);
2204 IRTemp EA_imm = newTemp(Ity_I32);
2205 IRTemp EA_reg = newTemp(Ity_I32);
2206 IRTemp Ra = newTemp(Ity_I32);
2207 IRTemp Rb = newTemp(Ity_I32);
2208
2209 assign( Ra, getIReg(Ra_addr) );
2210 assign( Rb, getIReg(Rb_addr) );
2211
sewardjafe85832005-09-09 10:25:39 +00002212 assign( Ra_or_0, ea_rA_or_zero(Ra_addr));
cerione9d361a2005-03-04 17:35:29 +00002213
ceriond05ee442005-02-16 18:05:16 +00002214 assign( EA_imm, binop(Iop_Add32, mkexpr(Ra_or_0), mkU32(exts_d_imm)) );
cerionb85e8bb2005-02-16 08:54:33 +00002215
2216 switch (opc1) {
cerione9d361a2005-03-04 17:35:29 +00002217 case 0x22: // lbz (Load B & Zero, PPC32 p433)
sewardjc7cd2142005-09-09 22:31:49 +00002218 DIP("lbz r%d,%d(r%d)\n", Rd_addr, (Int)exts_d_imm, Ra_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002219 putIReg( Rd_addr, unop(Iop_8Uto32,
2220 loadBE(Ity_I8, mkexpr(EA_imm))) );
2221 break;
2222
cerione9d361a2005-03-04 17:35:29 +00002223 case 0x23: // lbzu (Load B & Zero with Update, PPC32 p434)
cerionb85e8bb2005-02-16 08:54:33 +00002224 if (Ra_addr == 0 || Ra_addr == Rd_addr) {
2225 vex_printf("dis_int_load(PPC32)(lbzu,Ra_addr|Rd_addr)\n");
2226 return False;
2227 }
sewardjc7cd2142005-09-09 22:31:49 +00002228 DIP("lbzu r%d,%d(r%d)\n", Rd_addr, (Int)exts_d_imm, Ra_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002229 putIReg( Rd_addr, unop(Iop_8Uto32,
2230 loadBE(Ity_I8, mkexpr(EA_imm))) );
2231 putIReg( Ra_addr, mkexpr(EA_imm) );
2232 break;
2233
cerione9d361a2005-03-04 17:35:29 +00002234 case 0x2A: // lha (Load HW Algebraic, PPC32 p445)
sewardjc7cd2142005-09-09 22:31:49 +00002235 DIP("lha r%d,%d(r%d)\n", Rd_addr, (Int)exts_d_imm, Ra_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002236 putIReg( Rd_addr, unop(Iop_16Sto32,
2237 loadBE(Ity_I16, mkexpr(EA_imm))) );
2238 break;
cerion645c9302005-01-31 10:09:59 +00002239
cerioncb14e732005-09-09 16:38:19 +00002240 case 0x2B: // lhau (Load HW Algebraic with Update, PPC32 p446)
2241 if (Ra_addr == 0 || Ra_addr == Rd_addr) {
2242 vex_printf("dis_int_load(PPC32)(lhau,Ra_addr|Rd_addr)\n");
2243 return False;
2244 }
sewardjc7cd2142005-09-09 22:31:49 +00002245 DIP("lhau r%d,%d(r%d)\n", Rd_addr, (Int)exts_d_imm, Ra_addr);
cerioncb14e732005-09-09 16:38:19 +00002246 putIReg( Rd_addr, unop(Iop_16Sto32,
2247 loadBE(Ity_I16, mkexpr(EA_imm))) );
2248 putIReg( Ra_addr, mkexpr(EA_imm) );
2249 break;
cerionb85e8bb2005-02-16 08:54:33 +00002250
cerione9d361a2005-03-04 17:35:29 +00002251 case 0x28: // lhz (Load HW & Zero, PPC32 p450)
sewardjc7cd2142005-09-09 22:31:49 +00002252 DIP("lhz r%d,%d(r%d)\n", Rd_addr, (Int)exts_d_imm, Ra_addr);
cerione67534c2005-02-25 20:47:36 +00002253 putIReg( Rd_addr, unop(Iop_16Uto32,
cerionb85e8bb2005-02-16 08:54:33 +00002254 loadBE(Ity_I16, mkexpr(EA_imm))) );
2255 break;
2256
sewardj0e2cc672005-07-29 21:58:51 +00002257 case 0x29: // lhzu (Load HW & and Zero with Update, PPC32 p451)
2258 if (Ra_addr == 0 || Ra_addr == Rd_addr) {
2259 vex_printf("dis_int_load(PPC32)(lhzu,Ra_addr|Rd_addr)\n");
2260 return False;
2261 }
sewardjc7cd2142005-09-09 22:31:49 +00002262 DIP("lhzu r%d,%d(r%d)\n", Rd_addr, (Int)exts_d_imm, Ra_addr);
sewardj0e2cc672005-07-29 21:58:51 +00002263 putIReg( Rd_addr, unop(Iop_16Uto32,
2264 loadBE(Ity_I16, mkexpr(EA_imm))) );
2265 putIReg( Ra_addr, mkexpr(EA_imm) );
2266 break;
cerion645c9302005-01-31 10:09:59 +00002267
cerione9d361a2005-03-04 17:35:29 +00002268 case 0x20: // lwz (Load W & Zero, PPC32 p460)
sewardjc7cd2142005-09-09 22:31:49 +00002269 DIP("lwz r%d,%d(r%d)\n", Rd_addr, (Int)exts_d_imm, Ra_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002270 putIReg( Rd_addr, loadBE(Ity_I32, mkexpr(EA_imm)) );
2271 break;
2272
cerione9d361a2005-03-04 17:35:29 +00002273 case 0x21: // lwzu (Load W & Zero with Update, PPC32 p461))
cerionb85e8bb2005-02-16 08:54:33 +00002274 if (Ra_addr == 0 || Ra_addr == Rd_addr) {
2275 vex_printf("dis_int_load(PPC32)(lwzu,Ra_addr|Rd_addr)\n");
2276 return False;
2277 }
sewardjc7cd2142005-09-09 22:31:49 +00002278 DIP("lwzu r%d,%d(r%d)\n", Rd_addr, (Int)exts_d_imm, Ra_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002279 putIReg( Rd_addr, loadBE(Ity_I32, mkexpr(EA_imm)) );
2280 putIReg( Ra_addr, mkexpr(EA_imm) );
2281 break;
2282
2283 /* X Form */
2284 case 0x1F:
2285 if (b0 != 0) {
2286 vex_printf("dis_int_load(PPC32)(Ox1F,b0)\n");
2287 return False;
2288 }
cerion7c1dd1b2005-02-22 18:39:18 +00002289 assign( EA_reg, binop(Iop_Add32, mkexpr(Ra_or_0), mkexpr(Rb)) );
cerion645c9302005-01-31 10:09:59 +00002290
cerionb85e8bb2005-02-16 08:54:33 +00002291 switch (opc2) {
cerione9d361a2005-03-04 17:35:29 +00002292 case 0x077: // lbzux (Load B & Zero with Update Indexed, PPC32 p435)
cerionb85e8bb2005-02-16 08:54:33 +00002293 DIP("lbzux r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
2294 if (Ra_addr == 0 || Ra_addr == Rd_addr) {
2295 vex_printf("dis_int_load(PPC32)(lwzux,Ra_addr|Rd_addr)\n");
2296 return False;
2297 }
2298 putIReg( Rd_addr, unop(Iop_8Uto32,
2299 loadBE(Ity_I8, mkexpr(EA_reg))) );
2300 putIReg( Ra_addr, mkexpr(EA_reg) );
2301 break;
2302
cerione9d361a2005-03-04 17:35:29 +00002303 case 0x057: // lbzx (Load B & Zero Indexed, PPC32 p436)
cerionb85e8bb2005-02-16 08:54:33 +00002304 DIP("lbzx r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
2305 putIReg( Rd_addr, unop(Iop_8Uto32,
2306 loadBE(Ity_I8, mkexpr(EA_reg))) );
2307 break;
2308
cerioncb14e732005-09-09 16:38:19 +00002309 case 0x177: // lhaux (Load HW Algebraic with Update Indexed, PPC32 p447)
2310 if (Ra_addr == 0 || Ra_addr == Rd_addr) {
2311 vex_printf("dis_int_load(PPC32)(lhaux,Ra_addr|Rd_addr)\n");
2312 return False;
2313 }
2314 DIP("lhaux r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
2315 putIReg( Rd_addr, unop(Iop_16Sto32,
2316 loadBE(Ity_I16, mkexpr(EA_reg))) );
2317 putIReg( Ra_addr, mkexpr(EA_reg) );
2318 break;
cerionb85e8bb2005-02-16 08:54:33 +00002319
cerione9d361a2005-03-04 17:35:29 +00002320 case 0x157: // lhax (Load HW Algebraic Indexed, PPC32 p448)
cerionb85e8bb2005-02-16 08:54:33 +00002321 DIP("lhax r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
2322 putIReg( Rd_addr, unop(Iop_16Sto32,
2323 loadBE(Ity_I16, mkexpr(EA_reg))) );
2324 break;
2325
cerione9d361a2005-03-04 17:35:29 +00002326 case 0x137: // lhzux (Load HW & Zero with Update Indexed, PPC32 p452)
cerionb85e8bb2005-02-16 08:54:33 +00002327 if (Ra_addr == 0 || Ra_addr == Rd_addr) {
2328 vex_printf("dis_int_load(PPC32)(lhzux,Ra_addr|Rd_addr)\n");
2329 return False;
2330 }
2331 DIP("lhzux r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
cerione67534c2005-02-25 20:47:36 +00002332 putIReg( Rd_addr, unop(Iop_16Uto32,
cerionb85e8bb2005-02-16 08:54:33 +00002333 loadBE(Ity_I16, mkexpr(EA_reg))) );
2334 putIReg( Ra_addr, mkexpr(EA_reg) );
2335 break;
2336
cerione9d361a2005-03-04 17:35:29 +00002337 case 0x117: // lhzx (Load HW & Zero Indexed, PPC32 p453)
cerionb85e8bb2005-02-16 08:54:33 +00002338 DIP("lhzx r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
cerione67534c2005-02-25 20:47:36 +00002339 putIReg( Rd_addr, unop(Iop_16Uto32,
cerionb85e8bb2005-02-16 08:54:33 +00002340 loadBE(Ity_I16, mkexpr(EA_reg))) );
2341 break;
cerion44997f22005-01-31 18:45:59 +00002342
sewardj7787af42005-08-04 18:32:19 +00002343 case 0x037: // lwzux (Load W & Zero with Update Indexed, PPC32 p462)
2344 if (Ra_addr == 0 || Ra_addr == Rd_addr) {
2345 vex_printf("dis_int_load(PPC32)(lwzux,Ra_addr|Rd_addr)\n");
2346 return False;
2347 }
2348 DIP("lwzux r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
2349 putIReg( Rd_addr, loadBE(Ity_I32, mkexpr(EA_reg)) );
2350 putIReg( Ra_addr, mkexpr(EA_reg) );
2351 break;
cerionb85e8bb2005-02-16 08:54:33 +00002352
cerione9d361a2005-03-04 17:35:29 +00002353 case 0x017: // lwzx (Load W & Zero Indexed, PPC32 p463)
cerionb85e8bb2005-02-16 08:54:33 +00002354 DIP("lwzx r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
2355 putIReg( Rd_addr, loadBE(Ity_I32, mkexpr(EA_reg)) );
2356 break;
cerion44997f22005-01-31 18:45:59 +00002357
cerionb85e8bb2005-02-16 08:54:33 +00002358 default:
2359 vex_printf("dis_int_load(PPC32)(opc2)\n");
2360 return False;
2361 }
2362 break;
2363 default:
2364 vex_printf("dis_int_load(PPC32)(opc1)\n");
2365 return False;
2366 }
2367 return True;
cerion7aa4bbc2005-01-29 09:32:07 +00002368}
2369
2370
2371
cerion3d870a32005-03-18 12:23:33 +00002372/*
2373 Integer Store Instructions
2374*/
ceriond23be4e2005-01-31 07:23:07 +00002375static Bool dis_int_store ( UInt theInstr )
2376{
sewardjb51f0f42005-07-18 11:38:02 +00002377 UInt opc1 = ifieldOPC(theInstr); /* theInstr[26:31] */
2378 UInt Rs_addr = ifieldRD(theInstr); /* theInstr[21:25] */
2379 UInt Ra_addr = ifieldRA(theInstr); /* theInstr[16:20] */
cerionb85e8bb2005-02-16 08:54:33 +00002380
2381 /* D-Form */
sewardjb51f0f42005-07-18 11:38:02 +00002382 Int simm16 = ifieldSIMM16(theInstr); /* theInstr[0:15] */
cerionb85e8bb2005-02-16 08:54:33 +00002383
2384 /* X-Form */
sewardjb51f0f42005-07-18 11:38:02 +00002385 UInt Rb_addr = ifieldRB(theInstr); /* theInstr[11:15] */
2386 UInt opc2 = ifieldOPClo10(theInstr); /* theInstr[1:10] */
2387 UInt b0 = ifieldBIT0(theInstr); /* theInstr[0] */
2388
cerionb85e8bb2005-02-16 08:54:33 +00002389 IRTemp Ra_or_0 = newTemp(Ity_I32);
2390 IRTemp Rb = newTemp(Ity_I32);
2391 IRTemp Rs = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00002392 IRTemp EA_imm = newTemp(Ity_I32);
2393 IRTemp EA_reg = newTemp(Ity_I32);
2394
cerionb85e8bb2005-02-16 08:54:33 +00002395 assign( Rb, getIReg(Rb_addr) );
2396 assign( Rs, getIReg(Rs_addr) );
cerionb85e8bb2005-02-16 08:54:33 +00002397
sewardjafe85832005-09-09 10:25:39 +00002398 assign( Ra_or_0, ea_rA_or_zero(Ra_addr) );
sewardjb51f0f42005-07-18 11:38:02 +00002399 assign( EA_imm, binop(Iop_Add32, mkexpr(Ra_or_0), mkU32(simm16)) );
cerionb85e8bb2005-02-16 08:54:33 +00002400
2401 switch (opc1) {
sewardjafe85832005-09-09 10:25:39 +00002402 case 0x26: // stb (Store B, PPC32 p509)
sewardjc7cd2142005-09-09 22:31:49 +00002403 DIP("stb r%u,%d(r%u)\n", Rs_addr, simm16, Ra_addr);
sewardjafe85832005-09-09 10:25:39 +00002404 storeBE( mkexpr(EA_imm), unop(Iop_32to8, mkexpr(Rs)) );
2405 break;
sewardjb51f0f42005-07-18 11:38:02 +00002406
cerione9d361a2005-03-04 17:35:29 +00002407 case 0x27: // stbu (Store B with Update, PPC32 p510)
cerionb85e8bb2005-02-16 08:54:33 +00002408 if (Ra_addr == 0 ) {
2409 vex_printf("dis_int_store(PPC32)(stbu,Ra_addr)\n");
2410 return False;
2411 }
sewardjc7cd2142005-09-09 22:31:49 +00002412 DIP("stbu r%u,%d(r%u)\n", Rs_addr, simm16, Ra_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002413 putIReg( Ra_addr, mkexpr(EA_imm) );
sewardjb51f0f42005-07-18 11:38:02 +00002414 storeBE( mkexpr(EA_imm), unop(Iop_32to8, mkexpr(Rs)) );
cerionb85e8bb2005-02-16 08:54:33 +00002415 break;
ceriond23be4e2005-01-31 07:23:07 +00002416
cerione9d361a2005-03-04 17:35:29 +00002417 case 0x2C: // sth (Store HW, PPC32 p522)
sewardjc7cd2142005-09-09 22:31:49 +00002418 DIP("sth r%u,%d(r%u)\n", Rs_addr, simm16, Ra_addr);
sewardjb51f0f42005-07-18 11:38:02 +00002419 storeBE( mkexpr(EA_imm), unop(Iop_32to16, mkexpr(Rs)) );
cerionb85e8bb2005-02-16 08:54:33 +00002420 break;
2421
cerione9d361a2005-03-04 17:35:29 +00002422 case 0x2D: // sthu (Store HW with Update, PPC32 p524)
cerionb85e8bb2005-02-16 08:54:33 +00002423 if (Ra_addr == 0) {
2424 vex_printf("dis_int_store(PPC32)(sthu,Ra_addr)\n");
2425 return False;
2426 }
sewardjc7cd2142005-09-09 22:31:49 +00002427 DIP("sthu r%u,%d(r%u)\n", Rs_addr, simm16, Ra_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002428 putIReg( Ra_addr, mkexpr(EA_imm) );
sewardjb51f0f42005-07-18 11:38:02 +00002429 storeBE( mkexpr(EA_imm), unop(Iop_32to16, mkexpr(Rs)) );
cerionb85e8bb2005-02-16 08:54:33 +00002430 break;
ceriond23be4e2005-01-31 07:23:07 +00002431
cerione9d361a2005-03-04 17:35:29 +00002432 case 0x24: // stw (Store W, PPC32 p530)
sewardjc7cd2142005-09-09 22:31:49 +00002433 DIP("stw r%u,%d(r%u)\n", Rs_addr, simm16, Ra_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002434 storeBE( mkexpr(EA_imm), mkexpr(Rs) );
2435 break;
ceriond23be4e2005-01-31 07:23:07 +00002436
cerione9d361a2005-03-04 17:35:29 +00002437 case 0x25: // stwu (Store W with Update, PPC32 p534)
cerionb85e8bb2005-02-16 08:54:33 +00002438 if (Ra_addr == 0) {
2439 vex_printf("dis_int_store(PPC32)(stwu,Ra_addr)\n");
2440 return False;
2441 }
sewardjc7cd2142005-09-09 22:31:49 +00002442 DIP("stwu r%u,%d(r%u)\n", Rs_addr, simm16, Ra_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002443 putIReg( Ra_addr, mkexpr(EA_imm) );
cerioned623db2005-06-20 12:42:04 +00002444 storeBE( mkexpr(EA_imm), mkexpr(Rs) );
cerionb85e8bb2005-02-16 08:54:33 +00002445 break;
2446
2447 /* X Form */
2448 case 0x1F:
2449 if (b0 != 0) {
2450 vex_printf("dis_int_store(PPC32)(0x1F,b0)\n");
2451 return False;
2452 }
cerion7c1dd1b2005-02-22 18:39:18 +00002453 assign( EA_reg, binop(Iop_Add32, mkexpr(Ra_or_0), mkexpr(Rb)) );
cerion44997f22005-01-31 18:45:59 +00002454
cerionb85e8bb2005-02-16 08:54:33 +00002455 switch (opc2) {
cerione9d361a2005-03-04 17:35:29 +00002456 case 0x0F7: // stbux (Store B with Update Indexed, PPC32 p511)
cerionb85e8bb2005-02-16 08:54:33 +00002457 if (Ra_addr == 0) {
2458 vex_printf("dis_int_store(PPC32)(stbux,Ra_addr)\n");
2459 return False;
2460 }
sewardjc7cd2142005-09-09 22:31:49 +00002461 DIP("stbux r%u,r%u,r%u\n", Rs_addr, Ra_addr, Rb_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002462 putIReg( Ra_addr, mkexpr(EA_reg) );
sewardjb51f0f42005-07-18 11:38:02 +00002463 storeBE( mkexpr(EA_reg), unop(Iop_32to8, mkexpr(Rs)) );
cerionb85e8bb2005-02-16 08:54:33 +00002464 break;
2465
cerione9d361a2005-03-04 17:35:29 +00002466 case 0x0D7: // stbx (Store B Indexed, PPC32 p512)
sewardjc7cd2142005-09-09 22:31:49 +00002467 DIP("stbx r%u,r%u,r%u\n", Rs_addr, Ra_addr, Rb_addr);
sewardjb51f0f42005-07-18 11:38:02 +00002468 storeBE( mkexpr(EA_reg), unop(Iop_32to8, mkexpr(Rs)) );
cerionb85e8bb2005-02-16 08:54:33 +00002469 break;
2470
cerioncb14e732005-09-09 16:38:19 +00002471 case 0x1B7: // sthux (Store HW with Update Indexed, PPC32 p525)
2472 if (Ra_addr == 0) {
2473 vex_printf("dis_int_store(PPC32)(sthux,Ra_addr)\n");
2474 return False;
2475 }
sewardjc7cd2142005-09-09 22:31:49 +00002476 DIP("sthux r%u,r%u,r%u\n", Rs_addr, Ra_addr, Rb_addr);
cerioncb14e732005-09-09 16:38:19 +00002477 putIReg( Ra_addr, mkexpr(EA_reg) );
2478 storeBE( mkexpr(EA_reg), unop(Iop_32to16, mkexpr(Rs)) );
2479 break;
cerionb85e8bb2005-02-16 08:54:33 +00002480
cerione9d361a2005-03-04 17:35:29 +00002481 case 0x197: // sthx (Store HW Indexed, PPC32 p526)
sewardjc7cd2142005-09-09 22:31:49 +00002482 DIP("sthx r%u,r%u,r%u\n", Rs_addr, Ra_addr, Rb_addr);
sewardjb51f0f42005-07-18 11:38:02 +00002483 storeBE( mkexpr(EA_reg), unop(Iop_32to16, mkexpr(Rs)) );
cerionb85e8bb2005-02-16 08:54:33 +00002484 break;
2485
cerione9d361a2005-03-04 17:35:29 +00002486 case 0x0B7: // stwux (Store W with Update Indexed, PPC32 p535)
cerionb85e8bb2005-02-16 08:54:33 +00002487 if (Ra_addr == 0) {
2488 vex_printf("dis_int_store(PPC32)(stwux,Ra_addr)\n");
2489 return False;
2490 }
sewardjc7cd2142005-09-09 22:31:49 +00002491 DIP("stwux r%u,r%u,r%u\n", Rs_addr, Ra_addr, Rb_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002492 putIReg( Ra_addr, mkexpr(EA_reg) );
cerioned623db2005-06-20 12:42:04 +00002493 storeBE( mkexpr(EA_reg), mkexpr(Rs) );
cerionb85e8bb2005-02-16 08:54:33 +00002494 break;
cerion44997f22005-01-31 18:45:59 +00002495
cerione9d361a2005-03-04 17:35:29 +00002496 case 0x097: // stwx (Store W Indexed, PPC32 p536)
sewardjc7cd2142005-09-09 22:31:49 +00002497 DIP("stwx r%u,r%u,r%u\n", Rs_addr, Ra_addr, Rb_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002498 storeBE( mkexpr(EA_reg), mkexpr(Rs) );
2499 break;
2500
2501 default:
2502 vex_printf("dis_int_store(PPC32)(opc2)\n");
2503 return False;
2504 }
2505 break;
2506 default:
2507 vex_printf("dis_int_store(PPC32)(opc1)\n");
2508 return False;
2509 }
2510 return True;
ceriond23be4e2005-01-31 07:23:07 +00002511}
2512
2513
2514
sewardj7787af42005-08-04 18:32:19 +00002515/*
2516 Integer Load/Store Multiple Instructions
2517*/
2518static Bool dis_int_ldst_mult ( UInt theInstr )
2519{
2520 /* D-Form */
2521 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
2522 UChar Rd_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
2523 UChar Rs_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
2524 UChar Ra_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
2525 UInt d_imm = (theInstr >> 0) & 0xFFFF; /* theInstr[0:15] */
2526
2527 UInt exts_d_imm = extend_s_16to32(d_imm);
2528 UInt reg_idx = 0;
2529 UInt offset = 0;
2530
2531 IRTemp Ra = newTemp(Ity_I32);
2532 IRTemp EA = newTemp(Ity_I32);
2533
2534 IRExpr* irx_addr;
2535
2536 if (Ra_addr == 0) {
2537 assign( EA, binop(Iop_Add32, mkU32(0), mkU32(exts_d_imm)) );
2538 } else {
2539 assign( Ra, getIReg(Ra_addr) );
2540 assign( EA, binop(Iop_Add32, mkexpr(Ra), mkU32(exts_d_imm)) );
2541 }
2542
2543 switch (opc1) {
2544 case 0x2E: // lmw (Load Multiple Word, PPC32 p454)
2545 if (Ra_addr >= Rd_addr) {
2546 vex_printf("dis_int_ldst_mult(PPC32)(lmw,Ra_addr)\n");
2547 return False;
2548 }
2549 DIP("lmw r%d,%d(r%d)\n", Rd_addr, (Int)d_imm, Ra_addr);
2550 for (reg_idx = Rd_addr; reg_idx <= 31; reg_idx++) {
2551 irx_addr = binop(Iop_Add32, mkexpr(EA), mkU32(offset));
2552 putIReg( reg_idx, loadBE(Ity_I32, irx_addr ) );
2553 offset += 4;
2554 }
2555 break;
2556
2557 case 0x2F: // stmw (Store Multiple Word, PPC32 p527)
2558 DIP("stmw r%d,%d(r%d)\n", Rs_addr, (Int)d_imm, Ra_addr);
2559 for (reg_idx = Rs_addr; reg_idx <= 31; reg_idx++) {
2560 irx_addr = binop(Iop_Add32, mkexpr(EA), mkU32(offset));
2561 storeBE( irx_addr, getIReg(reg_idx) );
2562 offset += 4;
2563 }
2564 break;
2565
2566 default:
2567 vex_printf("dis_int_ldst_mult(PPC32)(opc1)\n");
2568 return False;
2569 }
2570 return True;
2571}
2572
2573
2574
sewardj87e651f2005-09-09 08:31:18 +00002575/*
2576 Integer Load/Store String Instructions
2577*/
2578static
2579void generate_lsw_sequence ( IRTemp tNBytes, // # bytes, :: Ity_I32
2580 IRTemp EA, // EA
2581 Int rD, // first dst register
2582 Int maxBytes, // 32 or 128
2583 Addr32 NIA ) // where next?
2584{
2585 Int i, shift = 24;
2586 IRExpr* e_nbytes = mkexpr(tNBytes);
2587 IRExpr* e_EA = mkexpr(EA);
2588
sewardj5876fa12005-09-09 09:35:29 +00002589 vassert(rD >= 0 && rD < 32);
sewardj87e651f2005-09-09 08:31:18 +00002590 rD--; if (rD < 0) rD = 31;
2591
2592 for (i = 0; i < maxBytes; i++) {
2593
2594 /* if (nBytes < (i+1)) goto NIA; */
2595 stmt( IRStmt_Exit( binop(Iop_CmpLT32U, e_nbytes, mkU32(i+1)),
2596 Ijk_Boring,
2597 IRConst_U32(NIA)) );
2598 /* when crossing into a new dest register, set it to zero. */
2599 if ((i % 4) == 0) {
2600 rD++; if (rD == 32) rD = 0;
2601 putIReg(rD, mkU32(0));
2602 shift = 24;
2603 }
2604 /* rD |= (8Uto32(*(EA+i))) << shift */
2605 vassert(shift == 0 || shift == 8 || shift == 16 || shift == 24);
2606 putIReg(
2607 rD,
2608 binop(Iop_Or32,
2609 getIReg(rD),
2610 binop(Iop_Shl32,
2611 unop(Iop_8Uto32,
2612 loadBE(Ity_I8,
2613 binop(Iop_Add32, e_EA, mkU32(i)))),
sewardjc7cd2142005-09-09 22:31:49 +00002614 mkU8(toUChar(shift)))
sewardj87e651f2005-09-09 08:31:18 +00002615 ));
2616 shift -= 8;
2617 }
2618}
2619
sewardj5876fa12005-09-09 09:35:29 +00002620static
2621void generate_stsw_sequence ( IRTemp tNBytes, // # bytes, :: Ity_I32
2622 IRTemp EA, // EA
2623 Int rS, // first src register
2624 Int maxBytes, // 32 or 128
2625 Addr32 NIA ) // where next?
2626{
2627 Int i, shift = 24;
2628 IRExpr* e_nbytes = mkexpr(tNBytes);
2629 IRExpr* e_EA = mkexpr(EA);
2630
2631 vassert(rS >= 0 && rS < 32);
2632 rS--; if (rS < 0) rS = 31;
2633
2634 for (i = 0; i < maxBytes; i++) {
2635 /* if (nBytes < (i+1)) goto NIA; */
2636 stmt( IRStmt_Exit( binop(Iop_CmpLT32U, e_nbytes, mkU32(i+1)),
2637 Ijk_Boring,
2638 IRConst_U32(NIA)) );
2639 /* check for crossing into a new src register. */
2640 if ((i % 4) == 0) {
2641 rS++; if (rS == 32) rS = 0;
2642 shift = 24;
2643 }
2644 /* *(EA+i) = 32to8(rS >> shift) */
2645 vassert(shift == 0 || shift == 8 || shift == 16 || shift == 24);
2646 storeBE(
2647 binop(Iop_Add32, e_EA, mkU32(i)),
2648 unop(Iop_32to8,
sewardjc7cd2142005-09-09 22:31:49 +00002649 binop(Iop_Shr32, getIReg(rS), mkU8(toUChar(shift))))
sewardj5876fa12005-09-09 09:35:29 +00002650 );
2651 shift -= 8;
2652 }
2653}
2654
sewardj87e651f2005-09-09 08:31:18 +00002655
2656static Bool dis_int_ldst_str ( UInt theInstr, /*OUT*/Bool* stopHere )
2657{
2658 /* X-Form */
2659 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
2660 UChar Rd_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
2661 UChar Rs_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
2662 UChar Ra_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
2663 UChar NumBytes = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
2664 UChar Rb_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
2665 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
2666 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
2667
sewardj0f2c5402005-09-09 09:50:34 +00002668 IRTemp t_EA = newTemp(Ity_I32);
sewardj87e651f2005-09-09 08:31:18 +00002669 IRTemp t_nbytes = IRTemp_INVALID;
sewardj87e651f2005-09-09 08:31:18 +00002670
2671 *stopHere = False;
2672
2673 if (opc1 != 0x1F || b0 != 0) {
2674 vex_printf("dis_int_ldst_str(PPC32)(opc1)\n");
2675 return False;
2676 }
2677
2678 switch (opc2) {
2679 case 0x255: // lswi (Load String Word Immediate, PPC32 p455)
2680 /* NB: does not reject the case where RA is in the range of
2681 registers to be loaded. It should. */
2682 DIP("lswi r%d,r%d,%d\n", Rd_addr, Ra_addr, NumBytes);
2683 assign( t_EA, ea_rA_or_zero(Ra_addr) );
2684 if (NumBytes == 8) {
2685 /* Special case hack */
2686 /* Rd = Mem[EA]; (Rd+1)%32 = Mem[EA+4] */
2687 putIReg( Rd_addr,
2688 loadBE(Ity_I32, mkexpr(t_EA)) );
sewardj87e651f2005-09-09 08:31:18 +00002689 putIReg( (Rd_addr+1) % 32,
2690 loadBE(Ity_I32, binop(Iop_Add32, mkexpr(t_EA), mkU32(4))) );
2691 } else {
2692 t_nbytes = newTemp(Ity_I32);
2693 assign( t_nbytes, mkU32(NumBytes==0 ? 32 : NumBytes) );
2694 generate_lsw_sequence( t_nbytes, t_EA, Rd_addr,
2695 32, guest_CIA_curr_instr+4 );
2696 *stopHere = True;
2697 }
2698 return True;
2699
2700 case 0x215: // lswx (Load String Word Indexed, PPC32 p456)
2701 /* NB: does not reject the case where RA is in the range of
2702 registers to be loaded. It should. Although considering
2703 that that can only be detected at run time, it's not easy to
2704 do so. */
2705 if (Rd_addr == Ra_addr || Rd_addr == Rb_addr)
2706 return False;
2707 if (Rd_addr == 0 && Ra_addr == 0)
2708 return False;
2709 DIP("lswx r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
2710 t_nbytes = newTemp(Ity_I32);
2711 assign( t_EA, ea_standard(Ra_addr,Rb_addr) );
2712 assign( t_nbytes, unop( Iop_8Uto32,
2713 IRExpr_Get( OFFB_XER_BC, Ity_I8 )));
2714 generate_lsw_sequence( t_nbytes, t_EA, Rd_addr,
2715 128, guest_CIA_curr_instr+4 );
2716 *stopHere = True;
2717 return True;
2718
sewardj5876fa12005-09-09 09:35:29 +00002719 case 0x2D5: // stswi (Store String Word Immediate, PPC32 p528)
2720 DIP("stswi r%d,r%d,%d\n", Rs_addr, Ra_addr, NumBytes);
2721 assign( t_EA, ea_rA_or_zero(Ra_addr) );
2722 if (NumBytes == 8) {
2723 /* Special case hack */
2724 /* Mem[EA] = Rd; Mem[EA+4] = (Rd+1)%32 */
2725 storeBE( mkexpr(t_EA),
2726 getIReg(Rd_addr) );
2727 storeBE( binop(Iop_Add32, mkexpr(t_EA), mkU32(4)),
2728 getIReg((Rd_addr+1) % 32) );
2729 } else {
2730 t_nbytes = newTemp(Ity_I32);
2731 assign( t_nbytes, mkU32(NumBytes==0 ? 32 : NumBytes) );
2732 generate_stsw_sequence( t_nbytes, t_EA, Rd_addr,
2733 32, guest_CIA_curr_instr+4 );
2734 *stopHere = True;
2735 }
2736 return True;
2737
sewardj5876fa12005-09-09 09:35:29 +00002738 case 0x295: // stswx (Store String Word Indexed, PPC32 p529)
2739 DIP("stswx r%d,r%d,r%d\n", Rs_addr, Ra_addr, Rb_addr);
2740 t_nbytes = newTemp(Ity_I32);
2741 assign( t_EA, ea_standard(Ra_addr,Rb_addr) );
2742 assign( t_nbytes, unop( Iop_8Uto32,
2743 IRExpr_Get( OFFB_XER_BC, Ity_I8 )));
2744 generate_stsw_sequence( t_nbytes, t_EA, Rs_addr,
2745 128, guest_CIA_curr_instr+4 );
2746 *stopHere = True;
2747 return True;
sewardj87e651f2005-09-09 08:31:18 +00002748
2749 default:
2750 vex_printf("dis_int_ldst_str(PPC32)(opc2)\n");
2751 return False;
2752 }
2753 return True;
2754}
2755
cerion094d1392005-06-20 13:45:57 +00002756
sewardjb51f0f42005-07-18 11:38:02 +00002757/* ------------------------------------------------------------------
2758 Integer Branch Instructions
2759 ------------------------------------------------------------------ */
cerion645c9302005-01-31 10:09:59 +00002760
cerion45552a92005-02-03 18:20:22 +00002761/*
2762 Branch helper function
2763 ok = BO[2] | ((CTR[0] != 0) ^ BO[1])
sewardjb51f0f42005-07-18 11:38:02 +00002764 Returns an I32 which is 0x00000000 if the ctr condition failed
2765 and 0xFFFFFFFF otherwise.
cerion45552a92005-02-03 18:20:22 +00002766*/
sewardjb51f0f42005-07-18 11:38:02 +00002767static IRExpr* /* :: Ity_I32 */ branch_ctr_ok( UInt BO )
cerion45552a92005-02-03 18:20:22 +00002768{
sewardjb51f0f42005-07-18 11:38:02 +00002769 IRTemp ok = newTemp(Ity_I32);
cerioned623db2005-06-20 12:42:04 +00002770
cerionb85e8bb2005-02-16 08:54:33 +00002771 if ((BO >> 2) & 1) {
sewardjb51f0f42005-07-18 11:38:02 +00002772 assign( ok, mkU32(0xFFFFFFFF) );
cerionb85e8bb2005-02-16 08:54:33 +00002773 } else {
cerionb85e8bb2005-02-16 08:54:33 +00002774 if ((BO >> 1) & 1) {
sewardjb51f0f42005-07-18 11:38:02 +00002775 assign( ok, unop( Iop_1Sto32,
2776 binop( Iop_CmpEQ32,
2777 getSPR( PPC32_SPR_CTR ), mkU32(0))) );
cerionb85e8bb2005-02-16 08:54:33 +00002778 } else {
sewardjb51f0f42005-07-18 11:38:02 +00002779 assign( ok, unop( Iop_1Sto32,
2780 binop( Iop_CmpNE32,
2781 getSPR( PPC32_SPR_CTR ), mkU32(0))) );
cerionb85e8bb2005-02-16 08:54:33 +00002782 }
2783 }
2784 return mkexpr(ok);
cerion45552a92005-02-03 18:20:22 +00002785}
2786
sewardjb51f0f42005-07-18 11:38:02 +00002787
cerion45552a92005-02-03 18:20:22 +00002788/*
sewardjb51f0f42005-07-18 11:38:02 +00002789 Branch helper function cond_ok = BO[4] | (CR[BI] == BO[3])
2790 Returns an I32 which is either 0 if the condition failed or
2791 some arbitrary nonzero value otherwise. */
2792
2793static IRExpr* /* :: Ity_I32 */ branch_cond_ok( UInt BO, UInt BI )
cerion45552a92005-02-03 18:20:22 +00002794{
sewardjb51f0f42005-07-18 11:38:02 +00002795 Int where;
2796 IRTemp res = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00002797 IRTemp cr_bi = newTemp(Ity_I32);
2798
sewardjb51f0f42005-07-18 11:38:02 +00002799 if ((BO >> 4) & 1) {
2800 assign( res, mkU32(1) );
cerionb85e8bb2005-02-16 08:54:33 +00002801 } else {
sewardjb51f0f42005-07-18 11:38:02 +00002802 // ok = (CR[BI] == BO[3]) Note, the following relies on
2803 // getCRbit_anywhere returning a value which
2804 // is either zero or has exactly 1 bit set.
2805 assign( cr_bi, getCRbit_anywhere( BI, &where ) );
cerione9d361a2005-03-04 17:35:29 +00002806
2807 if ((BO >> 3) & 1) {
sewardjb51f0f42005-07-18 11:38:02 +00002808 /* We can use cr_bi as-is. */
2809 assign( res, mkexpr(cr_bi) );
cerione9d361a2005-03-04 17:35:29 +00002810 } else {
sewardjb51f0f42005-07-18 11:38:02 +00002811 /* We have to invert the sense of the information held in
2812 cr_bi. For that we need to know which bit
2813 getCRbit_somewhere regards as significant. */
2814 assign( res, binop(Iop_Xor32, mkexpr(cr_bi), mkU32(1<<where)) );
cerionb85e8bb2005-02-16 08:54:33 +00002815 }
2816 }
sewardjb51f0f42005-07-18 11:38:02 +00002817 return mkexpr(res);
cerion45552a92005-02-03 18:20:22 +00002818}
2819
2820
cerion3d870a32005-03-18 12:23:33 +00002821/*
2822 Integer Branch Instructions
2823*/
sewardj9e6491a2005-07-02 19:24:10 +00002824static Bool dis_branch ( UInt theInstr, DisResult* dres )
cerion91ad5362005-01-27 23:02:41 +00002825{
cerionb85e8bb2005-02-16 08:54:33 +00002826 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
2827 UChar BO = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
2828 UChar BI = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
2829 UInt BD = (theInstr >> 2) & 0x3FFF; /* theInstr[2:15] */
2830 UChar b11to15 = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
2831 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
2832 UInt LI_24 = (theInstr >> 2) & 0xFFFFFF; /* theInstr[2:25] */
2833 UChar flag_AA = toUChar((theInstr >> 1) & 1); /* theInstr[1] */
2834 UChar flag_LK = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
2835
cerion4561acb2005-02-21 14:07:48 +00002836 Int exts_BD = (Int)extend_s_16to32(BD << 2);
cerion6b30d852005-06-24 11:25:46 +00002837 Int exts_LI = (Int)extend_s_26to32(LI_24 << 2);
cerionb85e8bb2005-02-16 08:54:33 +00002838
2839 Addr32 nia = 0;
2840
sewardjb51f0f42005-07-18 11:38:02 +00002841 // IRTemp ctr = newTemp(Ity_I32);
2842 // IRTemp lr = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00002843 IRTemp ir_nia = newTemp(Ity_I32);
2844 IRTemp do_branch = newTemp(Ity_I32);
sewardjb51f0f42005-07-18 11:38:02 +00002845 IRTemp ctr_ok = newTemp(Ity_I32);
2846 IRTemp cond_ok = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00002847
sewardjb51f0f42005-07-18 11:38:02 +00002848// assign( ctr, getSPR( PPC32_SPR_CTR ) );
cerion4561acb2005-02-21 14:07:48 +00002849
cerionb85e8bb2005-02-16 08:54:33 +00002850 /* Hack to pass through code that just wants to read the PC */
2851 if (theInstr == 0x429F0005) {
sewardjb51f0f42005-07-18 11:38:02 +00002852 DIP("bcl 0x%x, 0x%x (a.k.a mr lr,cia+4)\n", BO, BI);
2853 putSPR( PPC32_SPR_LR, mkU32(guest_CIA_curr_instr + 4) );
cerionb85e8bb2005-02-16 08:54:33 +00002854 return True;
sewardjb51f0f42005-07-18 11:38:02 +00002855 }
cerion45552a92005-02-03 18:20:22 +00002856
cerionb85e8bb2005-02-16 08:54:33 +00002857 switch (opc1) {
cerione9d361a2005-03-04 17:35:29 +00002858 case 0x12: // b (Branch, PPC32 p360)
cerion4561acb2005-02-21 14:07:48 +00002859 if (flag_AA) {
2860 nia = (UInt)exts_LI;
2861 } else {
sewardj9e6491a2005-07-02 19:24:10 +00002862 nia = (UInt)((Int)guest_CIA_curr_instr + exts_LI);
cerionb85e8bb2005-02-16 08:54:33 +00002863 }
cerione9d361a2005-03-04 17:35:29 +00002864 DIP("b%s%s 0x%x\n", flag_LK ? "l" : "", flag_AA ? "a" : "", nia);
2865
cerionb85e8bb2005-02-16 08:54:33 +00002866 if (flag_LK) {
sewardjb51f0f42005-07-18 11:38:02 +00002867 putSPR( PPC32_SPR_LR, mkU32(guest_CIA_curr_instr + 4) );
cerione9d361a2005-03-04 17:35:29 +00002868 }
cerionb85e8bb2005-02-16 08:54:33 +00002869 irbb->jumpkind = flag_LK ? Ijk_Call : Ijk_Boring;
2870 irbb->next = mkU32(nia);
cerionb85e8bb2005-02-16 08:54:33 +00002871 break;
2872
cerione9d361a2005-03-04 17:35:29 +00002873 case 0x10: // bc (Branch Conditional, PPC32 p361)
cerionb85e8bb2005-02-16 08:54:33 +00002874 DIP("bc%s%s 0x%x, 0x%x, 0x%x\n",
cerion4561acb2005-02-21 14:07:48 +00002875 flag_LK ? "l" : "", flag_AA ? "a" : "", BO, BI, exts_BD);
cerionb85e8bb2005-02-16 08:54:33 +00002876
2877 if (!(BO & 0x4)) {
sewardjb51f0f42005-07-18 11:38:02 +00002878 putSPR( PPC32_SPR_CTR,
2879 binop(Iop_Sub32, getSPR( PPC32_SPR_CTR ), mkU32(1)) );
cerionb85e8bb2005-02-16 08:54:33 +00002880 }
sewardjb51f0f42005-07-18 11:38:02 +00002881
2882 /* This is a bit subtle. ctr_ok is either all 0s or all 1s.
2883 cond_ok is either zero or nonzero, since that's the cheapest
2884 way to compute it. Anding them together gives a value which
2885 is either zero or non zero and so that's what we must test
2886 for in the IRStmt_Exit. */
2887 assign( ctr_ok, branch_ctr_ok( BO ) );
cerionb85e8bb2005-02-16 08:54:33 +00002888 assign( cond_ok, branch_cond_ok( BO, BI ) );
sewardjb51f0f42005-07-18 11:38:02 +00002889 assign( do_branch,
2890 binop(Iop_And32, mkexpr(cond_ok), mkexpr(ctr_ok)) );
2891
cerion4561acb2005-02-21 14:07:48 +00002892 if (flag_AA) {
2893 nia = (UInt)exts_BD;
2894 } else {
sewardj9e6491a2005-07-02 19:24:10 +00002895 nia = (UInt)((Int)guest_CIA_curr_instr + exts_BD);
cerionb85e8bb2005-02-16 08:54:33 +00002896 }
cerionb85e8bb2005-02-16 08:54:33 +00002897 if (flag_LK) {
sewardjb51f0f42005-07-18 11:38:02 +00002898 putSPR( PPC32_SPR_LR, mkU32(guest_CIA_curr_instr + 4) );
cerionb85e8bb2005-02-16 08:54:33 +00002899 }
2900
sewardjb51f0f42005-07-18 11:38:02 +00002901 stmt( IRStmt_Exit( binop(Iop_CmpNE32, mkexpr(do_branch), mkU32(0)),
cerionb85e8bb2005-02-16 08:54:33 +00002902 flag_LK ? Ijk_Call : Ijk_Boring,
2903 IRConst_U32(nia) ));
2904
2905 irbb->jumpkind = Ijk_Boring;
sewardj9e6491a2005-07-02 19:24:10 +00002906 irbb->next = mkU32(guest_CIA_curr_instr + 4);
cerionb85e8bb2005-02-16 08:54:33 +00002907 break;
2908
2909 case 0x13:
2910 if (b11to15!=0) {
2911 vex_printf("dis_int_branch(PPC32)(0x13,b11to15)\n");
2912 return False;
2913 }
cerion91ad5362005-01-27 23:02:41 +00002914
cerionb85e8bb2005-02-16 08:54:33 +00002915 switch (opc2) {
cerione9d361a2005-03-04 17:35:29 +00002916 case 0x210: // bcctr (Branch Cond. to Count Register, PPC32 p363)
cerionb85e8bb2005-02-16 08:54:33 +00002917 if ((BO & 0x4) == 0) { // "decrement and test CTR" option invalid
2918 vex_printf("dis_int_branch(PPC32)(bcctr,BO)\n");
2919 return False;
2920 }
ceriona31e8b52005-02-21 16:30:45 +00002921 DIP("bcctr%s 0x%x, 0x%x\n", flag_LK ? "l" : "", BO, BI);
cerionb85e8bb2005-02-16 08:54:33 +00002922
2923 assign( cond_ok, branch_cond_ok( BO, BI ) );
2924
sewardjb51f0f42005-07-18 11:38:02 +00002925 assign( ir_nia,
2926 binop(Iop_And32, mkU32(0xFFFFFFFC),
2927 getSPR( PPC32_SPR_CTR ) ));
cerionb85e8bb2005-02-16 08:54:33 +00002928
2929 if (flag_LK) {
sewardjb51f0f42005-07-18 11:38:02 +00002930 putSPR( PPC32_SPR_LR, mkU32(guest_CIA_curr_instr + 4) );
cerionb85e8bb2005-02-16 08:54:33 +00002931 }
2932
sewardjb51f0f42005-07-18 11:38:02 +00002933 stmt( IRStmt_Exit(
2934 binop(Iop_CmpEQ32, mkexpr(cond_ok), mkU32(0)),
2935 Ijk_Boring,
2936 IRConst_U32(guest_CIA_curr_instr + 4)
2937 ));
cerionb85e8bb2005-02-16 08:54:33 +00002938
2939 irbb->jumpkind = flag_LK ? Ijk_Call : Ijk_Boring;
2940 irbb->next = mkexpr(ir_nia);
2941 break;
2942
cerione9d361a2005-03-04 17:35:29 +00002943 case 0x010: // bclr (Branch Cond. to Link Register, PPC32 p365)
sewardjb51f0f42005-07-18 11:38:02 +00002944
2945 if ((BO & 0x14 /* 1z1zz */) == 0x14 && flag_LK == 0) {
cerion225a0342005-09-12 20:49:09 +00002946 DIP("blr\n");
sewardjb51f0f42005-07-18 11:38:02 +00002947 } else {
2948 DIP("bclr%s 0x%x, 0x%x\n", flag_LK ? "l" : "", BO, BI);
2949 }
cerion91ad5362005-01-27 23:02:41 +00002950
cerionb85e8bb2005-02-16 08:54:33 +00002951 if (!(BO & 0x4)) {
sewardjb51f0f42005-07-18 11:38:02 +00002952 putSPR( PPC32_SPR_CTR,
2953 binop(Iop_Sub32, getSPR( PPC32_SPR_CTR ), mkU32(1)) );
cerionb85e8bb2005-02-16 08:54:33 +00002954 }
2955
sewardjb51f0f42005-07-18 11:38:02 +00002956 /* See comments above for 'bc' about this */
2957 assign( ctr_ok, branch_ctr_ok( BO ) );
2958 assign( cond_ok, branch_cond_ok( BO, BI ) );
2959 assign( do_branch,
2960 binop(Iop_And32, mkexpr(cond_ok), mkexpr(ctr_ok)) );
cerionb85e8bb2005-02-16 08:54:33 +00002961
2962 assign( ir_nia, binop(Iop_And32,
sewardjb51f0f42005-07-18 11:38:02 +00002963 getSPR( PPC32_SPR_LR ),
cerionb85e8bb2005-02-16 08:54:33 +00002964 mkU32(0xFFFFFFFC)) );
2965 if (flag_LK) {
sewardjb51f0f42005-07-18 11:38:02 +00002966 putSPR( PPC32_SPR_LR, mkU32(guest_CIA_curr_instr + 4) );
cerionb85e8bb2005-02-16 08:54:33 +00002967 }
sewardjb51f0f42005-07-18 11:38:02 +00002968
2969 stmt( IRStmt_Exit(
2970 binop(Iop_CmpEQ32, mkexpr(do_branch), mkU32(0)),
2971 Ijk_Boring,
2972 IRConst_U32(guest_CIA_curr_instr + 4)
2973 ));
2974
2975 irbb->jumpkind = flag_LK ? Ijk_Call : Ijk_Ret;
cerionb85e8bb2005-02-16 08:54:33 +00002976 irbb->next = mkexpr(ir_nia);
2977 break;
2978
2979 default:
2980 vex_printf("dis_int_branch(PPC32)(opc2)\n");
2981 return False;
2982 }
2983 break;
2984 default:
2985 vex_printf("dis_int_branch(PPC32)(opc1)\n");
2986 return False;
2987 }
cerion91ad5362005-01-27 23:02:41 +00002988
sewardj9e6491a2005-07-02 19:24:10 +00002989 dres->whatNext = Dis_StopHere;
cerionb85e8bb2005-02-16 08:54:33 +00002990 return True;
cerion91ad5362005-01-27 23:02:41 +00002991}
2992
2993
2994
cerion3d870a32005-03-18 12:23:33 +00002995/*
2996 Condition Register Logical Instructions
2997*/
cerion3007c7f2005-02-23 23:13:29 +00002998static Bool dis_cond_logic ( UInt theInstr )
2999{
3000 /* XL-Form */
3001 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
3002 UChar crbD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
3003 UChar crfD_addr = toUChar((theInstr >> 23) & 0x7); /* theInstr[23:25] */
3004 UChar crbA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
3005 UChar crfS_addr = toUChar((theInstr >> 18) & 0x7); /* theInstr[18:20] */
3006 UChar crbB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
3007 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
3008 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
3009
3010 IRTemp crbD = newTemp(Ity_I32);
3011 IRTemp crbA = newTemp(Ity_I32);
3012 IRTemp crbB = newTemp(Ity_I32);
3013
3014 if (opc1 != 19 || b0 != 0) {
3015 vex_printf("dis_cond_logic(PPC32)(opc1)\n");
3016 return False;
3017 }
3018
cerione9d361a2005-03-04 17:35:29 +00003019 if (opc2 == 0) { // mcrf (Move Cond Reg Field, PPC32 p464)
cerion3007c7f2005-02-23 23:13:29 +00003020 if (((crbD_addr & 0x3) != 0) ||
cerioned623db2005-06-20 12:42:04 +00003021 ((crbA_addr & 0x3) != 0) || (crbB_addr != 0))
cerion3007c7f2005-02-23 23:13:29 +00003022 return False;
sewardjb51f0f42005-07-18 11:38:02 +00003023 DIP("mcrf cr%d,cr%d\n", crfD_addr, crfS_addr);
3024 putCR0( crfD_addr, getCR0( crfS_addr) );
3025 putCR321( crfD_addr, getCR321(crfS_addr) );
cerion3007c7f2005-02-23 23:13:29 +00003026 } else {
sewardjb51f0f42005-07-18 11:38:02 +00003027 assign( crbA, getCRbit(crbA_addr) );
ceriona50fde52005-07-01 21:16:10 +00003028 if (crbA_addr == crbB_addr)
sewardjb51f0f42005-07-18 11:38:02 +00003029 crbB = crbA;
ceriona50fde52005-07-01 21:16:10 +00003030 else
sewardjb51f0f42005-07-18 11:38:02 +00003031 assign( crbB, getCRbit(crbB_addr) );
cerion3007c7f2005-02-23 23:13:29 +00003032
3033 switch (opc2) {
sewardj7c2dc712005-09-08 17:33:27 +00003034 case 0x101: // crand (Cond Reg AND, PPC32 p372)
3035 DIP("crand crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
3036 assign( crbD, binop(Iop_And32, mkexpr(crbA), mkexpr(crbB)) );
3037 break;
sewardj7787af42005-08-04 18:32:19 +00003038 case 0x081: // crandc (Cond Reg AND w. Complement, PPC32 p373)
3039 DIP("crandc crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
3040 assign( crbD, binop(Iop_And32,
3041 mkexpr(crbA),
3042 unop(Iop_Not32, mkexpr(crbB))) );
3043 break;
sewardje14bb9f2005-07-22 09:39:02 +00003044 case 0x121: // creqv (Cond Reg Equivalent, PPC32 p374)
3045 DIP("creqv crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
3046 assign( crbD, unop(Iop_Not32,
3047 binop(Iop_Xor32, mkexpr(crbA), mkexpr(crbB))) );
3048 break;
sewardj7c2dc712005-09-08 17:33:27 +00003049 case 0x0E1: // crnand (Cond Reg NAND, PPC32 p375)
3050 DIP("crnand crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
3051 assign( crbD, unop(Iop_Not32,
3052 binop(Iop_And32, mkexpr(crbA), mkexpr(crbB))) );
3053 break;
cerione9d361a2005-03-04 17:35:29 +00003054 case 0x021: // crnor (Cond Reg NOR, PPC32 p376)
cerion3007c7f2005-02-23 23:13:29 +00003055 DIP("crnor crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
3056 assign( crbD, unop(Iop_Not32,
3057 binop(Iop_Or32, mkexpr(crbA), mkexpr(crbB))) );
3058 break;
cerione9d361a2005-03-04 17:35:29 +00003059 case 0x1C1: // cror (Cond Reg OR, PPC32 p377)
cerion3007c7f2005-02-23 23:13:29 +00003060 DIP("cror crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
3061 assign( crbD, binop(Iop_Or32, mkexpr(crbA), mkexpr(crbB)) );
3062 break;
sewardj7c2dc712005-09-08 17:33:27 +00003063 case 0x1A1: // crorc (Cond Reg OR w. Complement, PPC32 p378)
3064 DIP("crorc crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
3065 assign( crbD, binop(Iop_Or32,
3066 mkexpr(crbA),
3067 unop(Iop_Not32, mkexpr(crbB))) );
3068 break;
cerione9d361a2005-03-04 17:35:29 +00003069 case 0x0C1: // crxor (Cond Reg XOR, PPC32 p379)
cerion3007c7f2005-02-23 23:13:29 +00003070 DIP("crxor crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
3071 assign( crbD, binop(Iop_Xor32, mkexpr(crbA), mkexpr(crbB)) );
3072 break;
cerion3007c7f2005-02-23 23:13:29 +00003073 default:
3074 vex_printf("dis_cond_logic(PPC32)(opc2)\n");
3075 return False;
3076 }
3077
sewardjb51f0f42005-07-18 11:38:02 +00003078 putCRbit( crbD_addr, mkexpr(crbD) );
cerion3007c7f2005-02-23 23:13:29 +00003079 }
3080 return True;
3081}
3082
3083
cerion3d870a32005-03-18 12:23:33 +00003084/*
3085 System Linkage Instructions
3086*/
sewardj9e6491a2005-07-02 19:24:10 +00003087static Bool dis_syslink ( UInt theInstr, DisResult* dres )
cerion8c3adda2005-01-31 11:54:05 +00003088{
cerionb85e8bb2005-02-16 08:54:33 +00003089 if (theInstr != 0x44000002) {
3090 vex_printf("dis_int_syslink(PPC32)(theInstr)\n");
3091 return False;
3092 }
cerione1d857b2005-02-04 18:29:05 +00003093
cerione9d361a2005-03-04 17:35:29 +00003094 // sc (System Call, PPC32 p504)
cerionb85e8bb2005-02-16 08:54:33 +00003095 DIP("sc\n");
3096
3097 /* It's important that all ArchRegs carry their up-to-date value
3098 at this point. So we declare an end-of-block here, which
3099 forces any TempRegs caching ArchRegs to be flushed. */
sewardj9e6491a2005-07-02 19:24:10 +00003100 irbb->next = mkU32( guest_CIA_curr_instr + 4 );
cerionb85e8bb2005-02-16 08:54:33 +00003101 irbb->jumpkind = Ijk_Syscall;
3102
sewardj9e6491a2005-07-02 19:24:10 +00003103 dres->whatNext = Dis_StopHere;
cerionb85e8bb2005-02-16 08:54:33 +00003104 return True;
cerion8c3adda2005-01-31 11:54:05 +00003105}
3106
cerion3d870a32005-03-18 12:23:33 +00003107
3108/*
3109 Memory Synchronization Instructions
3110*/
cerion8c3adda2005-01-31 11:54:05 +00003111static Bool dis_memsync ( UInt theInstr )
3112{
cerionb85e8bb2005-02-16 08:54:33 +00003113 /* X-Form, XL-Form */
3114 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
3115 UInt b11to25 = (theInstr >> 11) & 0x7FFF; /* theInstr[11:25] */
3116 UChar Rd_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
3117 UChar Rs_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
3118 UChar Ra_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
3119 UChar Rb_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
3120 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
3121 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
3122
3123 IRTemp EA = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00003124 IRTemp Rs = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00003125
3126 switch (opc1) {
sewardjafe85832005-09-09 10:25:39 +00003127 /* XL-Form */
cerione9d361a2005-03-04 17:35:29 +00003128 case 0x13: // isync (Instruction Synchronize, PPC32 p432)
cerionb85e8bb2005-02-16 08:54:33 +00003129 if (opc2 != 0x096) {
3130 vex_printf("dis_int_memsync(PPC32)(0x13,opc2)\n");
3131 return False;
3132 }
3133 if (b11to25 != 0 || b0 != 0) {
3134 vex_printf("dis_int_memsync(PPC32)(0x13,b11to25|b0)\n");
3135 return False;
3136 }
3137 DIP("isync\n");
cerionb85e8bb2005-02-16 08:54:33 +00003138 stmt( IRStmt_MFence() );
3139 break;
cerion8c3adda2005-01-31 11:54:05 +00003140
cerionb85e8bb2005-02-16 08:54:33 +00003141 /* X-Form */
3142 case 0x1F:
3143 switch (opc2) {
sewardj7787af42005-08-04 18:32:19 +00003144 case 0x356: // eieio (Enforce In-Order Execution of I/O, PPC32 p394)
3145 if (b11to25 != 0 || b0 != 0) {
3146 vex_printf("dis_int_memsync(PPC32)(eiei0,b11to25|b0)\n");
3147 return False;
3148 }
3149 DIP("eieio\n");
3150 /* Insert a memory fence, just to be on the safe side. */
3151 stmt( IRStmt_MFence() );
3152 break;
cerion8c3adda2005-01-31 11:54:05 +00003153
cerione9d361a2005-03-04 17:35:29 +00003154 case 0x014: // lwarx (Load Word and Reserve Indexed, PPC32 p458)
cerionb85e8bb2005-02-16 08:54:33 +00003155 if (b0 != 0) {
3156 vex_printf("dis_int_memsync(PPC32)(lwarx,b0)\n");
3157 return False;
3158 }
3159 DIP("lwarx r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
sewardjafe85832005-09-09 10:25:39 +00003160 assign( EA, ea_standard(Ra_addr, Rb_addr) );
cerionb85e8bb2005-02-16 08:54:33 +00003161 putIReg( Rd_addr, loadBE(Ity_I32, mkexpr(EA)) );
sewardj7787af42005-08-04 18:32:19 +00003162 /* Take a reservation */
3163 stmt( IRStmt_Put( OFFB_RESVN, mkexpr(EA) ));
cerionb85e8bb2005-02-16 08:54:33 +00003164 break;
3165
sewardj7787af42005-08-04 18:32:19 +00003166 case 0x096: {
3167 // stwcx. (Store Word Conditional Indexed, PPC32 p532)
sewardj7787af42005-08-04 18:32:19 +00003168 IRTemp resaddr = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00003169 if (b0 != 1) {
3170 vex_printf("dis_int_memsync(PPC32)(stwcx.,b0)\n");
3171 return False;
3172 }
3173 DIP("stwcx. r%d,r%d,r%d\n", Rs_addr, Ra_addr, Rb_addr);
cerionb85e8bb2005-02-16 08:54:33 +00003174 assign( Rs, getIReg(Rs_addr) );
sewardjafe85832005-09-09 10:25:39 +00003175 assign( EA, ea_standard(Ra_addr, Rb_addr) );
3176
sewardj7787af42005-08-04 18:32:19 +00003177 /* First set up as if the reservation failed */
3178 // Set CR0[LT GT EQ S0] = 0b000 || XER[SO]
3179 putCR321(0, mkU8(0<<1));
3180 putCR0(0, getXER_SO());
3181
3182 /* Get the reservation address into a temporary, then
3183 clear it. */
3184 assign( resaddr, IRExpr_Get(OFFB_RESVN, Ity_I32) );
3185 stmt( IRStmt_Put( OFFB_RESVN, mkU32(0) ));
3186
3187 /* Skip the rest if the reservation really did fail. */
3188 stmt( IRStmt_Exit(
3189 binop(Iop_CmpNE32, mkexpr(resaddr),
3190 mkexpr(EA)),
sewardj7787af42005-08-04 18:32:19 +00003191 Ijk_Boring,
3192 IRConst_U32(guest_CIA_curr_instr + 4)
3193 )
3194 );
3195
3196 /* Success? Do the store */
cerionb85e8bb2005-02-16 08:54:33 +00003197 storeBE( mkexpr(EA), mkexpr(Rs) );
3198
sewardjb51f0f42005-07-18 11:38:02 +00003199 // Set CR0[LT GT EQ S0] = 0b001 || XER[SO]
3200 putCR321(0, mkU8(1<<1));
cerionb85e8bb2005-02-16 08:54:33 +00003201 break;
sewardj7787af42005-08-04 18:32:19 +00003202 }
3203
cerione9d361a2005-03-04 17:35:29 +00003204 case 0x256: // sync (Synchronize, PPC32 p543)
cerionb85e8bb2005-02-16 08:54:33 +00003205 if (b11to25 != 0 || b0 != 0) {
3206 vex_printf("dis_int_memsync(PPC32)(sync,b11to25|b0)\n");
3207 return False;
3208 }
3209 DIP("sync\n");
3210 /* Insert a memory fence. It's sometimes important that these
3211 are carried through to the generated code. */
3212 stmt( IRStmt_MFence() );
3213 break;
3214
3215 default:
3216 vex_printf("dis_int_memsync(PPC32)(opc2)\n");
3217 return False;
3218 }
3219 break;
cerion8c3adda2005-01-31 11:54:05 +00003220
cerionb85e8bb2005-02-16 08:54:33 +00003221 default:
3222 vex_printf("dis_int_memsync(PPC32)(opc1)\n");
3223 return False;
3224 }
3225 return True;
cerion8c3adda2005-01-31 11:54:05 +00003226}
3227
3228
3229
cerion3d870a32005-03-18 12:23:33 +00003230/*
3231 Integer Shift Instructions
3232*/
cerion645c9302005-01-31 10:09:59 +00003233static Bool dis_int_shift ( UInt theInstr )
3234{
cerionb85e8bb2005-02-16 08:54:33 +00003235 /* X-Form */
3236 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
3237 UChar Rs_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
3238 UChar Ra_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
3239 UChar Rb_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
3240 UChar sh_imm = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
3241 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
3242 UChar flag_Rc = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
3243
cerionb85e8bb2005-02-16 08:54:33 +00003244 IRTemp sh_amt = newTemp(Ity_I8);
cerionb85e8bb2005-02-16 08:54:33 +00003245 IRTemp rb_b5 = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00003246 IRTemp Rs = newTemp(Ity_I32);
3247 IRTemp Rs_sh = newTemp(Ity_I32);
3248 IRTemp Ra = newTemp(Ity_I32);
3249 IRTemp Rb = newTemp(Ity_I32);
sewardj20ef5472005-07-21 14:48:31 +00003250 IRTemp sh_amt32 = newTemp(Ity_I32);
3251 IRTemp outofrange = newTemp(Ity_I8);
cerionb85e8bb2005-02-16 08:54:33 +00003252
3253 assign( Rs, getIReg(Rs_addr) );
3254 assign( Rb, getIReg(Rb_addr) );
3255
3256 if (opc1 == 0x1F) {
3257 switch (opc2) {
cerione9d361a2005-03-04 17:35:29 +00003258 case 0x018: // slw (Shift Left Word, PPC32 p505)
cerionb85e8bb2005-02-16 08:54:33 +00003259 DIP("slw%s r%d,r%d,r%d\n", flag_Rc ? "." : "",
3260 Ra_addr, Rs_addr, Rb_addr);
3261 assign( sh_amt, binop(Iop_And8, mkU8(0x1F),
3262 unop(Iop_32to8, mkexpr(Rb))) );
cerion3a589ea2005-03-14 16:30:09 +00003263 assign( Rs_sh, binop(Iop_Shl32, mkexpr(Rs), mkexpr(sh_amt)) );
3264 assign( rb_b5, binop(Iop_And32, mkexpr(Rb), mkU32(1<<5)) );
3265 assign( Ra, IRExpr_Mux0X( unop(Iop_32to8, mkexpr(rb_b5)),
3266 mkexpr(Rs_sh), mkU32(0) ));
cerionb85e8bb2005-02-16 08:54:33 +00003267 break;
3268
cerione9d361a2005-03-04 17:35:29 +00003269 case 0x318: // sraw (Shift Right Algebraic Word, PPC32 p506)
cerionb85e8bb2005-02-16 08:54:33 +00003270 DIP("sraw%s r%d,r%d,r%d\n", flag_Rc ? "." : "",
3271 Ra_addr, Rs_addr, Rb_addr);
3272
sewardj20ef5472005-07-21 14:48:31 +00003273 /* JRS: my reading of the (poorly worded) PPC32 doc p506 is:
3274 amt = Rb & 63
3275 Ra = Sar32( Rs, amt > 31 ? 31 : amt )
3276 XER.CA = amt > 31 ? sign-of-Rs : (computation as per srawi)
3277 */
3278 assign( sh_amt32, binop(Iop_And32, mkU32(0x3F), mkexpr(Rb)) );
3279 assign( outofrange,
3280 unop( Iop_1Uto8,
3281 binop(Iop_CmpLT32U, mkU32(31), mkexpr(sh_amt32)) ));
3282 assign( Ra,
3283 binop( Iop_Sar32,
3284 mkexpr(Rs),
3285 unop( Iop_32to8,
3286 IRExpr_Mux0X( mkexpr(outofrange),
3287 mkexpr(sh_amt32),
3288 mkU32(31)) ))
3289 );
3290 set_XER_CA( PPC32G_FLAG_OP_SRAW,
3291 mkexpr(Ra), mkexpr(Rs), mkexpr(sh_amt32),
3292 get_XER_CA() );
cerionb85e8bb2005-02-16 08:54:33 +00003293 break;
3294
cerione9d361a2005-03-04 17:35:29 +00003295 case 0x338: // srawi (Shift Right Algebraic Word Immediate, PPC32 p507)
cerionb85e8bb2005-02-16 08:54:33 +00003296 DIP("srawi%s r%d,r%d,%d\n", flag_Rc ? "." : "",
3297 Ra_addr, Rs_addr, sh_imm);
sewardj20ef5472005-07-21 14:48:31 +00003298 vassert(sh_imm < 32);
cerionb85e8bb2005-02-16 08:54:33 +00003299 assign( sh_amt, mkU8(sh_imm) );
sewardj20ef5472005-07-21 14:48:31 +00003300 assign( Ra, binop(Iop_Sar32, mkexpr(Rs), mkexpr(sh_amt)) );
3301 set_XER_CA( PPC32G_FLAG_OP_SRAWI,
3302 mkexpr(Ra), mkexpr(Rs), mkU32(sh_imm),
3303 get_XER_CA() );
cerionb85e8bb2005-02-16 08:54:33 +00003304 break;
3305
cerione9d361a2005-03-04 17:35:29 +00003306 case 0x218: // srw (Shift Right Word, PPC32 p508)
cerionb85e8bb2005-02-16 08:54:33 +00003307 DIP("srw%s r%d,r%d,r%d\n", flag_Rc ? "." : "",
3308 Ra_addr, Rs_addr, Rb_addr);
3309 assign( sh_amt, binop(Iop_And8, mkU8(0x1F),
cerion3a589ea2005-03-14 16:30:09 +00003310 unop(Iop_32to8, mkexpr(Rb))) );
cerionb85e8bb2005-02-16 08:54:33 +00003311 assign( Rs_sh, binop(Iop_Shr32, mkexpr(Rs), mkexpr(sh_amt)) );
3312 assign( rb_b5, binop(Iop_And32, mkexpr(Rb), mkU32(1<<5)) );
3313 assign( Ra, IRExpr_Mux0X( unop(Iop_32to8, mkexpr(rb_b5)),
cerion2ee871e2005-03-01 09:32:01 +00003314 mkexpr(Rs_sh), mkU32(0) ));
cerionb85e8bb2005-02-16 08:54:33 +00003315 break;
3316
3317 default:
3318 vex_printf("dis_int_shift(PPC32)(opc2)\n");
3319 return False;
3320 }
3321 } else {
3322 vex_printf("dis_int_shift(PPC32)(opc1)\n");
3323 return False;
3324 }
cerion0d330c52005-02-28 16:43:16 +00003325
3326 putIReg( Ra_addr, mkexpr(Ra) );
cerionb85e8bb2005-02-16 08:54:33 +00003327
cerionb85e8bb2005-02-16 08:54:33 +00003328 if (flag_Rc) {
sewardj20ef5472005-07-21 14:48:31 +00003329 set_CR0( mkexpr(Ra) );
cerionb85e8bb2005-02-16 08:54:33 +00003330 }
3331 return True;
cerion645c9302005-01-31 10:09:59 +00003332}
3333
3334
3335
sewardj602857d2005-09-06 09:10:09 +00003336/*
3337 Integer Load/Store Reverse Instructions
3338*/
sewardjfb957972005-09-08 17:53:03 +00003339static IRExpr* /* :: Ity_I32 */ gen_byterev32 ( IRTemp t )
3340{
3341 vassert(typeOfIRTemp(irbb->tyenv, t) == Ity_I32);
3342 return
3343 binop(Iop_Or32,
3344 binop(Iop_Shl32, mkexpr(t), mkU8(24)),
3345 binop(Iop_Or32,
3346 binop(Iop_And32, binop(Iop_Shl32, mkexpr(t), mkU8(8)),
3347 mkU32(0x00FF0000)),
3348 binop(Iop_Or32,
3349 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t), mkU8(8)),
3350 mkU32(0x0000FF00)),
3351 binop(Iop_And32, binop(Iop_Shr32, mkexpr(t), mkU8(24)),
3352 mkU32(0x000000FF) )
3353 )));
3354}
3355
sewardj602857d2005-09-06 09:10:09 +00003356static Bool dis_int_ldst_rev ( UInt theInstr )
3357{
3358 /* X-Form */
3359 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
3360 UChar Rd_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
sewardjafe85832005-09-09 10:25:39 +00003361 UChar Rs_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
sewardj602857d2005-09-06 09:10:09 +00003362 UChar Ra_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
3363 UChar Rb_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
3364 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
3365 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
3366
3367 IRTemp EA = newTemp(Ity_I32);
sewardj602857d2005-09-06 09:10:09 +00003368 IRTemp w1 = newTemp(Ity_I32);
3369 IRTemp w2 = newTemp(Ity_I32);
3370
3371 if (opc1 != 0x1F || b0 != 0) {
3372 vex_printf("dis_int_ldst_rev(PPC32)(opc1|b0)\n");
3373 return False;
3374 }
sewardjafe85832005-09-09 10:25:39 +00003375
3376 assign( EA, ea_standard(Ra_addr, Rb_addr) );
sewardj602857d2005-09-06 09:10:09 +00003377
3378 switch (opc2) {
sewardjb51f0f42005-07-18 11:38:02 +00003379//zz case 0x316: // lhbrx (Load Half Word Byte-Reverse Indexed, PPC32 p449)
3380//zz vassert(0);
3381//zz
3382//zz DIP("lhbrx r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
3383//zz assign( byte0, loadBE(Ity_I8, mkexpr(EA)) );
3384//zz assign( byte1, loadBE(Ity_I8, binop(Iop_Add32, mkexpr(EA),mkU32(1))) );
3385//zz assign( Rd, binop(Iop_Or32,
3386//zz binop(Iop_Shl32, mkexpr(byte1), mkU8(8)),
3387//zz mkexpr(byte0)) );
3388//zz putIReg( Rd_addr, mkexpr(Rd));
3389//zz break;
sewardj602857d2005-09-06 09:10:09 +00003390
sewardjfb957972005-09-08 17:53:03 +00003391 case 0x216: // lwbrx (Load Word Byte-Reverse Indexed, PPC32 p459)
3392 DIP("lwbrx r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
3393 assign( w1, loadBE(Ity_I32, mkexpr(EA)) );
3394 assign( w2, gen_byterev32(w1) );
3395 putIReg( Rd_addr, mkexpr(w2));
3396 break;
sewardj602857d2005-09-06 09:10:09 +00003397
sewardjb51f0f42005-07-18 11:38:02 +00003398//zz case 0x396: // sthbrx (Store Half Word Byte-Reverse Indexed, PPC32 p523)
3399//zz vassert(0);
3400//zz
3401//zz DIP("sthbrx r%d,r%d,r%d\n", Rs_addr, Ra_addr, Rb_addr);
3402//zz assign( Rs, getIReg(Rs_addr) );
3403//zz assign( byte0, binop(Iop_And32, mkexpr(Rs), mkU32(0x00FF)) );
3404//zz assign( byte1, binop(Iop_And32, mkexpr(Rs), mkU32(0xFF00)) );
3405//zz
3406//zz assign( tmp16,
3407//zz unop(Iop_32to16,
3408//zz binop(Iop_Or32,
3409//zz binop(Iop_Shl32, mkexpr(byte0), mkU8(8)),
3410//zz binop(Iop_Shr32, mkexpr(byte1), mkU8(8)))) );
3411//zz storeBE( mkexpr(EA), getIReg(tmp16) );
3412//zz break;
sewardj602857d2005-09-06 09:10:09 +00003413
sewardjfb957972005-09-08 17:53:03 +00003414 case 0x296: // stwbrx (Store Word Byte-Reverse Indexed, PPC32 p531)
sewardjafe85832005-09-09 10:25:39 +00003415 DIP("stwbrx r%d,r%d,r%d\n", Rs_addr, Ra_addr, Rb_addr);
3416 assign( w1, getIReg(Rs_addr) );
sewardjfb957972005-09-08 17:53:03 +00003417 storeBE( mkexpr(EA), gen_byterev32(w1) );
3418 break;
3419
3420 default:
3421 vex_printf("dis_int_ldst_rev(PPC32)(opc2)\n");
3422 return False;
sewardj602857d2005-09-06 09:10:09 +00003423 }
3424 return True;
3425}
cerion645c9302005-01-31 10:09:59 +00003426
3427
3428
cerion3d870a32005-03-18 12:23:33 +00003429/*
3430 Processor Control Instructions
3431*/
cerion8c3adda2005-01-31 11:54:05 +00003432static Bool dis_proc_ctl ( UInt theInstr )
3433{
cerionb85e8bb2005-02-16 08:54:33 +00003434 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
3435
3436 /* X-Form */
cerioncb14e732005-09-09 16:38:19 +00003437 UChar crfD = toUChar((theInstr >> 23) & 0x7); /* theInstr[23:25] */
3438 UChar b21to22 = toUChar((theInstr >> 21) & 0x3); /* theInstr[21:22] */
cerionb85e8bb2005-02-16 08:54:33 +00003439 UChar Rd_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
3440 UInt b11to20 = (theInstr >> 11) & 0x3FF; /* theInstr[11:20] */
3441
3442 /* XFX-Form */
3443 UChar Rs_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
3444 UInt SPR = (theInstr >> 11) & 0x3FF; /* theInstr[11:20] */
sewardj73a91972005-09-06 10:25:46 +00003445 UInt TBR = (theInstr >> 11) & 0x3FF; /* theInstr[11:20] */
cerionb85e8bb2005-02-16 08:54:33 +00003446 UChar b20 = toUChar((theInstr >> 11) & 0x1); /* theInstr[11] */
3447 UInt CRM = (theInstr >> 12) & 0xFF; /* theInstr[12:19] */
3448 UChar b11 = toUChar((theInstr >> 11) & 0x1); /* theInstr[20] */
3449
3450 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
3451 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
3452
3453 UInt SPR_flipped = ((SPR & 0x1F) << 5) | ((SPR >> 5) & 0x1F);
cerione9d361a2005-03-04 17:35:29 +00003454
3455 IRTemp Rs = newTemp(Ity_I32);
sewardj7f080782005-07-27 00:22:15 +00003456//uu IRTemp tmp = newTemp(Ity_I32);
cerion48090c02005-02-24 11:19:51 +00003457
sewardj73a91972005-09-06 10:25:46 +00003458 /* Reorder TBR field as per PPC32 p475 */
3459 TBR = ((TBR & 31) << 5) | ((TBR >> 5) & 31);
3460
cerionb85e8bb2005-02-16 08:54:33 +00003461 assign( Rs, getIReg(Rs_addr) );
3462
3463 if (opc1 != 0x1F || b0 != 0) {
3464 vex_printf("dis_proc_ctl(PPC32)(opc1|b0)\n");
3465 return False;
3466 }
3467
3468 switch (opc2) {
cerioncb14e732005-09-09 16:38:19 +00003469 /* X-Form */
sewardj55ccc3e2005-09-09 19:45:02 +00003470 case 0x200: { // mcrxr (Move to Condition Register from XER, PPC32 p466)
3471 IRTemp xer_0to3 = newTemp(Ity_I8);
cerioncb14e732005-09-09 16:38:19 +00003472 if (b21to22 != 0 || b11to20 != 0) {
3473 vex_printf("dis_proc_ctl(PPC32)(mcrxr,b21to22|b11to20)\n");
3474 return False;
3475 }
3476 DIP("mcrxr crf%d\n", crfD);
cerioncb14e732005-09-09 16:38:19 +00003477
sewardj55ccc3e2005-09-09 19:45:02 +00003478 /* Compute XER[0-3] (the top 4 bits of XER) into the bottom
cerion225a0342005-09-12 20:49:09 +00003479 4 bits of xer_0to3. */
sewardj55ccc3e2005-09-09 19:45:02 +00003480 assign(
3481 xer_0to3,
3482 unop(Iop_32to8,
3483 binop(
3484 Iop_Or32,
3485 binop(
3486 Iop_Or32,
3487 binop( Iop_Shl32,
3488 binop( Iop_And32,
3489 unop( Iop_8Uto32,
3490 IRExpr_Get( OFFB_XER_SO, Ity_I8 )),
3491 mkU32(1)),
3492 mkU8(31 -28)),
3493 binop( Iop_Shl32,
3494 binop( Iop_And32,
3495 unop( Iop_8Uto32,
3496 IRExpr_Get( OFFB_XER_OV, Ity_I8 )),
3497 mkU32(1)),
3498 mkU8(30 -28))
3499 ),
3500 binop( Iop_Shl32,
3501 binop( Iop_And32,
3502 unop( Iop_8Uto32,
3503 IRExpr_Get( OFFB_XER_CA, Ity_I8 )),
3504 mkU32(1)),
3505 mkU8(29 -28))
3506 )
3507 )
3508 );
3509
3510 putCR321( crfD, binop(Iop_And8, mkexpr(xer_0to3), mkU8(7<<1)) );
3511 putCR0 ( crfD, binop(Iop_And8, mkexpr(xer_0to3), mkU8(1)) );
3512
3513 // Clear XER[0-3]
cerioncb14e732005-09-09 16:38:19 +00003514 stmt( IRStmt_Put( OFFB_XER_SO, mkU8(0) ) );
3515 stmt( IRStmt_Put( OFFB_XER_OV, mkU8(0) ) );
3516 stmt( IRStmt_Put( OFFB_XER_CA, mkU8(0) ) );
3517 break;
sewardj55ccc3e2005-09-09 19:45:02 +00003518 }
cerionb85e8bb2005-02-16 08:54:33 +00003519
cerione9d361a2005-03-04 17:35:29 +00003520 case 0x013: // mfcr (Move from Condition Register, PPC32 p467)
cerionb85e8bb2005-02-16 08:54:33 +00003521 if (b11to20 != 0) {
3522 vex_printf("dis_proc_ctl(PPC32)(mfcr,b11to20)\n");
3523 return False;
3524 }
sewardjb51f0f42005-07-18 11:38:02 +00003525 DIP("mfcr r%d\n", Rd_addr);
3526 putIReg( Rd_addr, getEntireCR() );
cerionb85e8bb2005-02-16 08:54:33 +00003527 break;
3528
3529 /* XFX-Form */
cerione9d361a2005-03-04 17:35:29 +00003530 case 0x153: // mfspr (Move from Special-Purpose Register, PPC32 p470)
cerionb85e8bb2005-02-16 08:54:33 +00003531
3532 switch (SPR_flipped) { // Choose a register...
sewardj20ef5472005-07-21 14:48:31 +00003533
3534 case 0x1:
3535 DIP("mfxer r%d\n", Rd_addr);
3536 /* sheesh [kebab] */
3537 putIReg(
3538 Rd_addr,
3539 binop(
3540 Iop_Or32,
3541 binop(
3542 Iop_Or32,
3543 binop( Iop_Shl32,
3544 binop( Iop_And32,
3545 unop( Iop_8Uto32,
3546 IRExpr_Get( OFFB_XER_SO, Ity_I8 )),
3547 mkU32(1)),
3548 mkU8(31)),
3549 binop( Iop_Shl32,
3550 binop( Iop_And32,
3551 unop( Iop_8Uto32,
3552 IRExpr_Get( OFFB_XER_OV, Ity_I8 )),
3553 mkU32(1)),
3554 mkU8(30))
3555 ),
3556 binop(
3557 Iop_Or32,
3558 binop( Iop_Shl32,
3559 binop( Iop_And32,
3560 unop( Iop_8Uto32,
3561 IRExpr_Get( OFFB_XER_CA, Ity_I8 )),
3562 mkU32(1)),
3563 mkU8(29)),
3564 binop( Iop_And32,
3565 unop( Iop_8Uto32,
3566 IRExpr_Get( OFFB_XER_BC, Ity_I8 )),
3567 mkU32(0xFF))
3568 )
3569 )
3570 );
3571 break;
3572
sewardjb51f0f42005-07-18 11:38:02 +00003573 case 0x8:
3574 DIP("mflr r%d\n", Rd_addr);
3575 putIReg( Rd_addr, getSPR( PPC32_SPR_LR ) );
3576 break;
3577 case 0x9:
3578 DIP("mfctr r%d\n", Rd_addr);
3579 putIReg( Rd_addr, getSPR( PPC32_SPR_CTR ) );
3580 break;
3581 case 0x100:
3582 DIP("mfvrsave r%d\n", Rd_addr);
3583 putIReg( Rd_addr, getSPR( PPC32_SPR_VRSAVE ) );
3584 break;
ceriona982c052005-06-28 17:23:09 +00003585
sewardjb51f0f42005-07-18 11:38:02 +00003586 case 0x012: case 0x013: case 0x016:
3587 case 0x019: case 0x01A: case 0x01B:
3588 case 0x110: case 0x111: case 0x112: case 0x113:
3589 // case 0x118: // 64bit only
3590 case 0x11A: case 0x11F:
3591 case 0x210: case 0x211: case 0x212: case 0x213:
3592 case 0x214: case 0x215: case 0x216: case 0x217:
3593 case 0x218: case 0x219: case 0x21A: case 0x21B:
3594 case 0x21C: case 0x21D: case 0x21E: case 0x21F:
3595 case 0x3F5:
3596 vex_printf("dis_proc_ctl(PPC32)(mfspr) - supervisor level op\n");
3597 return False;
cerion45552a92005-02-03 18:20:22 +00003598
sewardjb51f0f42005-07-18 11:38:02 +00003599 default:
3600 vex_printf("dis_proc_ctl(PPC32)(mfspr,SPR_flipped)(0x%x)\n",
3601 SPR_flipped);
3602 return False;
cerionb85e8bb2005-02-16 08:54:33 +00003603 }
3604 break;
3605
sewardj73a91972005-09-06 10:25:46 +00003606 case 0x173: { // mftb (Move from Time Base, PPC32 p475)
3607 IRTemp val = newTemp(Ity_I64);
3608 IRExpr** args = mkIRExprVec_0();
3609 IRDirty* d = unsafeIRDirty_1_N (
3610 val,
3611 0/*regparms*/,
3612 "ppc32g_dirtyhelper_MFTB",
3613 &ppc32g_dirtyhelper_MFTB,
3614 args
3615 );
3616 /* execute the dirty call, dumping the result in val. */
3617 stmt( IRStmt_Dirty(d) );
3618
3619 switch (TBR) {
3620 case 269:
3621 putIReg( Rd_addr, unop(Iop_64HIto32, mkexpr(val)) );
3622 DIP("mftbu r%d", Rd_addr);
3623 break;
3624 case 268:
3625 putIReg( Rd_addr, unop(Iop_64to32, mkexpr(val)) );
3626 DIP("mftb r%d", Rd_addr);
3627 break;
3628 default:
3629 return False; /* illegal instruction */
3630 }
3631 break;
3632 }
3633
sewardjb51f0f42005-07-18 11:38:02 +00003634 case 0x090: // mtcrf (Move to Condition Register Fields, PPC32 p477)
cerionb85e8bb2005-02-16 08:54:33 +00003635 if (b11 != 0 || b20 != 0) {
3636 vex_printf("dis_proc_ctl(PPC32)(mtcrf,b11|b20)\n");
3637 return False;
3638 }
3639 DIP("mtcrf 0x%x,r%d\n", CRM, Rs_addr);
sewardjb51f0f42005-07-18 11:38:02 +00003640 putCRfields ( mkexpr(Rs), CRM );
cerionb85e8bb2005-02-16 08:54:33 +00003641 break;
cerione9d361a2005-03-04 17:35:29 +00003642
3643 case 0x1D3: // mtspr (Move to Special-Purpose Register, PPC32 p483)
cerionb85e8bb2005-02-16 08:54:33 +00003644
3645 switch (SPR_flipped) { // Choose a register...
sewardj20ef5472005-07-21 14:48:31 +00003646 case 0x1:
3647 DIP("mtxer r%d\n", Rs_addr);
sewardj0e88d8f2005-07-21 16:58:55 +00003648 stmt(IRStmt_Put(
sewardj20ef5472005-07-21 14:48:31 +00003649 OFFB_XER_SO,
3650 unop( Iop_32to8,
3651 binop( Iop_And32,
sewardj0e88d8f2005-07-21 16:58:55 +00003652 binop(Iop_Shr32, mkexpr(Rs), mkU8(31)),
sewardj20ef5472005-07-21 14:48:31 +00003653 mkU32(1)) )
sewardj0e88d8f2005-07-21 16:58:55 +00003654 ));
3655 stmt(IRStmt_Put(
sewardj20ef5472005-07-21 14:48:31 +00003656 OFFB_XER_OV,
3657 unop( Iop_32to8,
3658 binop( Iop_And32,
sewardj0e88d8f2005-07-21 16:58:55 +00003659 binop(Iop_Shr32, mkexpr(Rs), mkU8(30)),
sewardj20ef5472005-07-21 14:48:31 +00003660 mkU32(1)) )
sewardj0e88d8f2005-07-21 16:58:55 +00003661 ));
3662 stmt(IRStmt_Put(
sewardj20ef5472005-07-21 14:48:31 +00003663 OFFB_XER_CA,
3664 unop( Iop_32to8,
3665 binop( Iop_And32,
sewardj0e88d8f2005-07-21 16:58:55 +00003666 binop(Iop_Shr32, mkexpr(Rs), mkU8(29)),
sewardj20ef5472005-07-21 14:48:31 +00003667 mkU32(1)) )
sewardj0e88d8f2005-07-21 16:58:55 +00003668 ));
3669 stmt(IRStmt_Put(
sewardj20ef5472005-07-21 14:48:31 +00003670 OFFB_XER_BC,
3671 unop( Iop_32to8,
sewardj0e88d8f2005-07-21 16:58:55 +00003672 binop( Iop_And32, mkexpr(Rs), mkU32(0xFF)) )
3673 ));
sewardj20ef5472005-07-21 14:48:31 +00003674 break;
sewardjb51f0f42005-07-18 11:38:02 +00003675 case 0x8:
3676 DIP("mtlr r%d\n", Rs_addr);
3677 putSPR( PPC32_SPR_LR, mkexpr(Rs) );
3678 break;
3679 case 0x9:
3680 DIP("mtctr r%d\n", Rs_addr);
3681 putSPR( PPC32_SPR_CTR, mkexpr(Rs) );
3682 break;
3683 case 0x100:
3684 DIP("mtvrsave r%d\n", Rs_addr);
3685 putSPR( PPC32_SPR_VRSAVE, mkexpr(Rs) );
3686 break;
3687//zz
3688//zz case 0x012: case 0x013: case 0x016:
3689//zz case 0x019: case 0x01A: case 0x01B:
3690//zz case 0x110: case 0x111: case 0x112: case 0x113:
3691//zz // case 0x118: // 64bit only
3692//zz case 0x11A: case 0x11C: case 0x11D:
3693//zz case 0x210: case 0x211: case 0x212: case 0x213:
3694//zz case 0x214: case 0x215: case 0x216: case 0x217:
3695//zz case 0x218: case 0x219: case 0x21A: case 0x21B:
3696//zz case 0x21C: case 0x21D: case 0x21E: case 0x21F:
3697//zz case 0x3F5:
3698//zz vex_printf("dis_proc_ctl(PPC32)(mtspr) - supervisor level op\n");
3699//zz return False;
cerion8c3adda2005-01-31 11:54:05 +00003700
sewardjb51f0f42005-07-18 11:38:02 +00003701 default:
sewardjc7cd2142005-09-09 22:31:49 +00003702 vex_printf("dis_proc_ctl(PPC32)(mtspr,SPR_flipped)(%u)\n",
sewardjb51f0f42005-07-18 11:38:02 +00003703 SPR_flipped);
3704 return False;
cerionb85e8bb2005-02-16 08:54:33 +00003705 }
3706 break;
3707
3708 default:
3709 vex_printf("dis_proc_ctl(PPC32)(opc2)\n");
3710 return False;
3711 }
3712 return True;
cerion8c3adda2005-01-31 11:54:05 +00003713}
3714
3715
cerion3d870a32005-03-18 12:23:33 +00003716/*
3717 Cache Management Instructions
3718*/
sewardjd94b73a2005-06-30 12:08:48 +00003719static Bool dis_cache_manage ( UInt theInstr,
sewardj9e6491a2005-07-02 19:24:10 +00003720 DisResult* dres,
sewardjd94b73a2005-06-30 12:08:48 +00003721 VexArchInfo* guest_archinfo )
cerion8c3adda2005-01-31 11:54:05 +00003722{
cerionb85e8bb2005-02-16 08:54:33 +00003723 /* X-Form */
3724 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
3725 UChar b21to25 = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
3726 UChar Ra_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
3727 UChar Rb_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
3728 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
3729 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
sewardjb51f0f42005-07-18 11:38:02 +00003730 Int lineszB = guest_archinfo->ppc32_cache_line_szB;
cerion094d1392005-06-20 13:45:57 +00003731
cerionb85e8bb2005-02-16 08:54:33 +00003732 if (opc1 != 0x1F || b21to25 != 0 || b0 != 0) {
3733 vex_printf("dis_cache_manage(PPC32)(opc1|b21to25|b0)\n");
3734 return False;
3735 }
sewardjd94b73a2005-06-30 12:08:48 +00003736
3737 /* stay sane .. */
3738 vassert(lineszB == 32 || lineszB == 128);
cerionb85e8bb2005-02-16 08:54:33 +00003739
3740 switch (opc2) {
sewardjb51f0f42005-07-18 11:38:02 +00003741//zz case 0x2F6: // dcba (Data Cache Block Allocate, PPC32 p380)
3742//zz vassert(0); /* AWAITING TEST CASE */
3743//zz DIP("dcba r%d,r%d\n", Ra_addr, Rb_addr);
3744//zz if (0) vex_printf("vex ppc32->IR: kludged dcba\n");
3745//zz break;
sewardj20ef5472005-07-21 14:48:31 +00003746
3747 case 0x056: // dcbf (Data Cache Block Flush, PPC32 p382)
3748 DIP("dcbf r%d,r%d\n", Ra_addr, Rb_addr);
3749 /* nop as far as vex is concerned */
3750 if (0) vex_printf("vex ppc32->IR: kludged dcbf\n");
3751 break;
cerionb85e8bb2005-02-16 08:54:33 +00003752
cerione9d361a2005-03-04 17:35:29 +00003753 case 0x036: // dcbst (Data Cache Block Store, PPC32 p384)
cerionb85e8bb2005-02-16 08:54:33 +00003754 DIP("dcbst r%d,r%d\n", Ra_addr, Rb_addr);
sewardjb51f0f42005-07-18 11:38:02 +00003755 /* nop as far as vex is concerned */
cerionb85e8bb2005-02-16 08:54:33 +00003756 break;
cerion8c3adda2005-01-31 11:54:05 +00003757
cerione9d361a2005-03-04 17:35:29 +00003758 case 0x116: // dcbt (Data Cache Block Touch, PPC32 p385)
cerionb85e8bb2005-02-16 08:54:33 +00003759 DIP("dcbt r%d,r%d\n", Ra_addr, Rb_addr);
sewardjb51f0f42005-07-18 11:38:02 +00003760 /* nop as far as vex is concerned */
cerionb85e8bb2005-02-16 08:54:33 +00003761 break;
3762
cerione9d361a2005-03-04 17:35:29 +00003763 case 0x0F6: // dcbtst (Data Cache Block Touch for Store, PPC32 p386)
cerionb85e8bb2005-02-16 08:54:33 +00003764 DIP("dcbtst r%d,r%d\n", Ra_addr, Rb_addr);
sewardjb51f0f42005-07-18 11:38:02 +00003765 /* nop as far as vex is concerned */
cerionb85e8bb2005-02-16 08:54:33 +00003766 break;
3767
cerion094d1392005-06-20 13:45:57 +00003768 case 0x3F6: { // dcbz (Data Cache Block Clear to Zero, PPC32 p387)
sewardjd94b73a2005-06-30 12:08:48 +00003769 /* Clear all bytes in cache block at (rA|0) + rB. */
cerion094d1392005-06-20 13:45:57 +00003770 IRTemp EA = newTemp(Ity_I32);
3771 IRTemp addr = newTemp(Ity_I32);
3772 IRExpr* irx_addr;
cerion094d1392005-06-20 13:45:57 +00003773 UInt i;
cerionb85e8bb2005-02-16 08:54:33 +00003774 DIP("dcbz r%d,r%d\n", Ra_addr, Rb_addr);
cerion094d1392005-06-20 13:45:57 +00003775 assign( EA,
3776 binop( Iop_Add32,
3777 getIReg(Rb_addr),
3778 Ra_addr==0 ? mkU32(0) : getIReg(Ra_addr)) );
3779
3780 /* Round EA down to the start of the containing block. */
3781 assign( addr,
3782 binop( Iop_And32,
3783 mkexpr(EA),
sewardjd94b73a2005-06-30 12:08:48 +00003784 mkU32( ~(lineszB-1) )) );
cerion094d1392005-06-20 13:45:57 +00003785
sewardjd94b73a2005-06-30 12:08:48 +00003786 for (i = 0; i < lineszB / 4; i++) {
3787 irx_addr = binop( Iop_Add32, mkexpr(addr), mkU32(i*4) );
3788 storeBE( irx_addr, mkU32(0) );
cerion094d1392005-06-20 13:45:57 +00003789 }
cerionb85e8bb2005-02-16 08:54:33 +00003790 break;
cerion094d1392005-06-20 13:45:57 +00003791 }
cerion8c3adda2005-01-31 11:54:05 +00003792
sewardj7ce9d152005-03-15 16:54:13 +00003793 case 0x3D6: {
3794 // icbi (Instruction Cache Block Invalidate, PPC32 p431)
3795 /* Invalidate all translations containing code from the cache
sewardjd94b73a2005-06-30 12:08:48 +00003796 block at (rA|0) + rB. */
sewardj7ce9d152005-03-15 16:54:13 +00003797 IRTemp addr = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00003798 DIP("icbi r%d,r%d\n", Ra_addr, Rb_addr);
sewardj7ce9d152005-03-15 16:54:13 +00003799
3800 assign( addr,
3801 binop( Iop_Add32,
3802 getIReg(Rb_addr),
3803 Ra_addr==0 ? mkU32(0) : getIReg(Ra_addr)) );
3804
3805 /* Round addr down to the start of the containing block. */
3806 stmt( IRStmt_Put(
3807 OFFB_TISTART,
3808 binop( Iop_And32,
3809 mkexpr(addr),
sewardjd94b73a2005-06-30 12:08:48 +00003810 mkU32( ~(lineszB-1) ))) );
sewardj7ce9d152005-03-15 16:54:13 +00003811
sewardjd94b73a2005-06-30 12:08:48 +00003812 stmt( IRStmt_Put(OFFB_TILEN, mkU32(lineszB) ) );
sewardj7ce9d152005-03-15 16:54:13 +00003813
sewardja8078f62005-03-15 18:27:40 +00003814 /* be paranoid ... */
3815 stmt( IRStmt_MFence() );
3816
sewardj7ce9d152005-03-15 16:54:13 +00003817 irbb->jumpkind = Ijk_TInval;
sewardj9e6491a2005-07-02 19:24:10 +00003818 irbb->next = mkU32(guest_CIA_curr_instr + 4);
3819 dres->whatNext = Dis_StopHere;
cerionb85e8bb2005-02-16 08:54:33 +00003820 break;
sewardj7ce9d152005-03-15 16:54:13 +00003821 }
cerion8c3adda2005-01-31 11:54:05 +00003822
cerionb85e8bb2005-02-16 08:54:33 +00003823 default:
3824 vex_printf("dis_cache_manage(PPC32)(opc2)\n");
3825 return False;
3826 }
3827 return True;
cerion8c3adda2005-01-31 11:54:05 +00003828}
3829
3830
sewardje14bb9f2005-07-22 09:39:02 +00003831/*------------------------------------------------------------*/
3832/*--- Floating Point Helpers ---*/
3833/*------------------------------------------------------------*/
3834
3835/* --- Set the emulation-warning pseudo-register. --- */
3836
3837static void put_emwarn ( IRExpr* e /* :: Ity_I32 */ )
3838{
3839 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I32);
3840 stmt( IRStmt_Put( OFFB_EMWARN, e ) );
3841}
3842
3843/* --------- Synthesise a 2-bit FPU rounding mode. --------- */
3844/* Produces a value in 0 .. 3, which is encoded as per the type
3845 IRRoundingMode. PPC32RoundingMode encoding is different to
3846 IRRoundingMode, so need to map it.
3847*/
3848static IRExpr* /* :: Ity_I32 */ get_roundingmode ( void )
3849{
3850/*
3851 rounding mode | PPC | IR
3852 ------------------------
3853 to nearest | 00 | 00
3854 to zero | 01 | 11
3855 to +infinity | 10 | 10
3856 to -infinity | 11 | 01
3857*/
3858 IRTemp rm_PPC32 = newTemp(Ity_I32);
3859 assign( rm_PPC32, getReg_masked( PPC32_SPR_FPSCR, MASK_FPSCR_RN ) );
3860
3861 // rm_IR = XOR( rm_PPC32, (rm_PPC32 << 1) & 2)
3862 return binop(Iop_Xor32, mkexpr(rm_PPC32),
3863 binop(Iop_And32, mkU32(2),
3864 binop(Iop_Shl32, mkexpr(rm_PPC32), mkU8(1))));
3865}
3866
3867/* Round float to single precision
3868 - returns type Ity_F64 */
3869static IRExpr* roundToSgl ( IRExpr* src )
3870{
3871 return unop(Iop_F32toF64, binop(Iop_F64toF32, get_roundingmode(), src));
3872}
cerion094d1392005-06-20 13:45:57 +00003873
3874
cerion3d870a32005-03-18 12:23:33 +00003875/*------------------------------------------------------------*/
3876/*--- Floating Point Instruction Translation ---*/
3877/*------------------------------------------------------------*/
3878
3879/*
3880 Floating Point Load Instructions
3881*/
3882static Bool dis_fp_load ( UInt theInstr )
3883{
3884 /* X-Form */
cerion094d1392005-06-20 13:45:57 +00003885 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
3886 UChar frD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
3887 UChar rA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
3888 UChar rB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
3889 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
3890 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
cerion3d870a32005-03-18 12:23:33 +00003891
3892 /* D-Form */
cerion094d1392005-06-20 13:45:57 +00003893 UInt d_imm = (theInstr >> 0) & 0xFFFF; /* theInstr[0:15] */
3894
sewardjdb36c0f2005-07-03 00:05:31 +00003895 Int exts_d_imm = extend_s_16to32(d_imm);
cerion094d1392005-06-20 13:45:57 +00003896
3897 IRTemp EA = newTemp(Ity_I32);
3898 IRTemp rA = newTemp(Ity_I32);
3899 IRTemp rB = newTemp(Ity_I32);
3900 IRTemp rA_or_0 = newTemp(Ity_I32);
3901
3902 assign( rA, getIReg(rA_addr) );
3903 assign( rB, getIReg(rB_addr) );
sewardjafe85832005-09-09 10:25:39 +00003904 assign( rA_or_0, ea_rA_or_zero(rA_addr) );
cerion3d870a32005-03-18 12:23:33 +00003905
3906 switch(opc1) {
sewardje14bb9f2005-07-22 09:39:02 +00003907 case 0x30: // lfs (Load Float Single, PPC32 p441)
3908 DIP("lfs fr%d,%d(r%d)\n", frD_addr, exts_d_imm, rA_addr);
3909 assign( EA, binop(Iop_Add32, mkU32(exts_d_imm), mkexpr(rA_or_0)) );
3910 putFReg( frD_addr, unop(Iop_F32toF64, loadBE(Ity_F32, mkexpr(EA))) );
3911 break;
3912
sewardjb51f0f42005-07-18 11:38:02 +00003913//zz case 0x31: // lfsu (Load Float Single with Update, PPC32 p442)
3914//zz if (rA_addr == 0) {
3915//zz vex_printf("dis_fp_load(PPC32)(instr,lfsu)\n");
3916//zz return False;
3917//zz }
3918//zz DIP("lfsu fr%d,%d(r%d)\n", frD_addr, exts_d_imm, rA_addr);
3919//zz assign( EA, binop(Iop_Add32, mkU32(exts_d_imm), mkexpr(rA)) );
3920//zz putFReg( frD_addr, unop(Iop_F32toF64, loadBE(Ity_F32, mkexpr(EA))) );
3921//zz putIReg( rA_addr, mkexpr(EA) );
3922//zz break;
cerion094d1392005-06-20 13:45:57 +00003923
3924 case 0x32: // lfd (Load Float Double, PPC32 p437)
sewardjdb36c0f2005-07-03 00:05:31 +00003925 DIP("lfd fr%d,%d(r%d)\n", frD_addr, exts_d_imm, rA_addr);
cerion094d1392005-06-20 13:45:57 +00003926 assign( EA, binop(Iop_Add32, mkU32(exts_d_imm), mkexpr(rA_or_0)) );
3927 putFReg( frD_addr, loadBE(Ity_F64, mkexpr(EA)) );
3928 break;
cerion3d870a32005-03-18 12:23:33 +00003929
sewardj0e2cc672005-07-29 21:58:51 +00003930 case 0x33: // lfdu (Load Float Double with Update, PPC32 p438)
3931 if (rA_addr == 0) {
3932 vex_printf("dis_fp_load(PPC32)(instr,lfdu)\n");
3933 return False;
3934 }
3935 DIP("lfdu fr%d,%d(r%d)\n", frD_addr, exts_d_imm, rA_addr);
3936 assign( EA, binop(Iop_Add32, mkU32(exts_d_imm), mkexpr(rA)) );
3937 putFReg( frD_addr, loadBE(Ity_F64, mkexpr(EA)) );
3938 putIReg( rA_addr, mkexpr(EA) );
3939 break;
sewardje14bb9f2005-07-22 09:39:02 +00003940
3941 case 0x1F:
3942 if (b0 != 0) {
3943 vex_printf("dis_fp_load(PPC32)(instr,b0)\n");
3944 return False;
3945 }
3946
3947 switch(opc2) {
3948 case 0x217: // lfsx (Load Float Single Indexed, PPC32 p444)
3949 DIP("lfsx fr%d,r%d,r%d\n", frD_addr, rA_addr, rB_addr);
3950 assign( EA, binop(Iop_Add32, mkexpr(rB), mkexpr(rA_or_0)) );
3951 putFReg( frD_addr, unop( Iop_F32toF64,
3952 loadBE(Ity_F32, mkexpr(EA))) );
3953 break;
3954
sewardj0e2cc672005-07-29 21:58:51 +00003955 case 0x237: // lfsux (Load Float Single with Update Indexed, PPC32 p443)
3956 if (rA_addr == 0) {
3957 vex_printf("dis_fp_load(PPC32)(instr,lfsux)\n");
3958 return False;
3959 }
3960 DIP("lfsux fr%d,r%d,r%d\n", frD_addr, rA_addr, rB_addr);
3961 assign( EA, binop(Iop_Add32, mkexpr(rB), mkexpr(rA)) );
3962 putFReg( frD_addr, unop(Iop_F32toF64, loadBE(Ity_F32, mkexpr(EA))) );
3963 putIReg( rA_addr, mkexpr(EA) );
3964 break;
sewardje14bb9f2005-07-22 09:39:02 +00003965
3966 case 0x257: // lfdx (Load Float Double Indexed, PPC32 p440)
3967 DIP("lfdx fr%d,r%d,r%d\n", frD_addr, rA_addr, rB_addr);
3968 assign( EA, binop(Iop_Add32, mkexpr(rB), mkexpr(rA_or_0)) );
3969 putFReg( frD_addr, loadBE(Ity_F64, mkexpr(EA)) );
3970 break;
3971
sewardj0e2cc672005-07-29 21:58:51 +00003972 case 0x277: // lfdux (Load Float Double with Update Indexed, PPC32 p439)
3973 if (rA_addr == 0) {
3974 vex_printf("dis_fp_load(PPC32)(instr,lfdux)\n");
3975 return False;
3976 }
3977 DIP("lfdux fr%d,r%d,r%d\n", frD_addr, rA_addr, rB_addr);
3978 assign( EA, binop(Iop_Add32, mkexpr(rB), mkexpr(rA)) );
3979 putFReg( frD_addr, loadBE(Ity_F64, mkexpr(EA)) );
3980 putIReg( rA_addr, mkexpr(EA) );
3981 break;
sewardje14bb9f2005-07-22 09:39:02 +00003982
3983 default:
3984 vex_printf("dis_fp_load(PPC32)(opc2)\n");
3985 return False;
3986 }
3987 break;
cerion3d870a32005-03-18 12:23:33 +00003988
3989 default:
3990 vex_printf("dis_fp_load(PPC32)(opc1)\n");
3991 return False;
3992 }
3993 return True;
3994}
3995
3996
3997
3998/*
3999 Floating Point Store Instructions
4000*/
4001static Bool dis_fp_store ( UInt theInstr )
4002{
4003 /* X-Form */
cerion094d1392005-06-20 13:45:57 +00004004 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
4005 UChar frS_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
4006 UChar rA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
4007 UChar rB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
4008 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
4009 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
cerion3d870a32005-03-18 12:23:33 +00004010
4011 /* D-Form */
cerion094d1392005-06-20 13:45:57 +00004012 UInt d_imm = (theInstr >> 0) & 0xFFFF; /* theInstr[0:15] */
4013
sewardjdb36c0f2005-07-03 00:05:31 +00004014 Int exts_d_imm = extend_s_16to32(d_imm);
cerion094d1392005-06-20 13:45:57 +00004015
4016 IRTemp EA = newTemp(Ity_I32);
4017 IRTemp frS = newTemp(Ity_F64);
4018 IRTemp rA = newTemp(Ity_I32);
4019 IRTemp rB = newTemp(Ity_I32);
4020 IRTemp rA_or_0 = newTemp(Ity_I32);
4021
4022 assign( frS, getFReg(frS_addr) );
4023 assign( rA, getIReg(rA_addr) );
4024 assign( rB, getIReg(rB_addr) );
sewardjafe85832005-09-09 10:25:39 +00004025 assign( rA_or_0, ea_rA_or_zero(rA_addr) );
cerion3d870a32005-03-18 12:23:33 +00004026
4027 switch(opc1) {
sewardje14bb9f2005-07-22 09:39:02 +00004028
4029 case 0x34: // stfs (Store Float Single, PPC32 p518)
4030 DIP("stfs fr%d,%d(r%d)\n", frS_addr, exts_d_imm, rA_addr);
4031 assign( EA, binop(Iop_Add32, mkU32(exts_d_imm), mkexpr(rA_or_0)) );
4032 storeBE( mkexpr(EA),
4033 binop(Iop_F64toF32, get_roundingmode(), mkexpr(frS)) );
4034 break;
4035
sewardjb51f0f42005-07-18 11:38:02 +00004036//zz case 0x35: // stfsu (Store Float Single with Update, PPC32 p519)
4037//zz if (rA_addr == 0) {
4038//zz vex_printf("dis_fp_store(PPC32)(instr,stfsu)\n");
4039//zz return False;
4040//zz }
4041//zz DIP("stfsu fr%d,%d(r%d)\n", frS_addr, exts_d_imm, rA_addr);
4042//zz assign( EA, binop(Iop_Add32, mkU32(exts_d_imm), mkexpr(rA)) );
4043//zz storeBE( mkexpr(EA),
4044//zz binop(Iop_F64toF32, get_roundingmode(), mkexpr(frS)) );
4045//zz putIReg( rA_addr, mkexpr(EA) );
4046//zz break;
cerion3d870a32005-03-18 12:23:33 +00004047
cerion094d1392005-06-20 13:45:57 +00004048 case 0x36: // stfd (Store Float Double, PPC32 p513)
sewardjdb36c0f2005-07-03 00:05:31 +00004049 DIP("stfd fr%d,%d(r%d)\n", frS_addr, exts_d_imm, rA_addr);
cerion094d1392005-06-20 13:45:57 +00004050 assign( EA, binop(Iop_Add32, mkU32(exts_d_imm), mkexpr(rA_or_0)) );
4051 storeBE( mkexpr(EA), mkexpr(frS) );
4052 break;
cerion3d870a32005-03-18 12:23:33 +00004053
sewardje14bb9f2005-07-22 09:39:02 +00004054 case 0x37: // stfdu (Store Float Double with Update, PPC32 p514)
4055 if (rA_addr == 0) {
4056 vex_printf("dis_fp_store(PPC32)(instr,stfdu)\n");
4057 return False;
4058 }
4059 DIP("stfdu fr%d,%d(r%d)\n", frS_addr, exts_d_imm, rA_addr);
4060 assign( EA, binop(Iop_Add32, mkU32(exts_d_imm), mkexpr(rA)) );
4061 storeBE( mkexpr(EA), mkexpr(frS) );
4062 putIReg( rA_addr, mkexpr(EA) );
4063 break;
4064
4065 case 0x1F:
4066 if (b0 != 0) {
4067 vex_printf("dis_fp_store(PPC32)(instr,b0)\n");
4068 return False;
4069 }
4070
4071 switch(opc2) {
4072 case 0x297: // stfsx (Store Float Single Indexed, PPC32 p521)
4073 DIP("stfsx fr%d,r%d,r%d\n", frS_addr, rA_addr, rB_addr);
4074 assign( EA, binop(Iop_Add32, mkexpr(rB), mkexpr(rA_or_0)) );
4075 storeBE( mkexpr(EA),
4076 binop(Iop_F64toF32, get_roundingmode(), mkexpr(frS)) );
4077 break;
4078
sewardjb51f0f42005-07-18 11:38:02 +00004079//zz case 0x2B7: // stfsux (Store Float Single with Update Indexed, PPC32 p520)
4080//zz if (rA_addr == 0) {
4081//zz vex_printf("dis_fp_store(PPC32)(instr,stfsux)\n");
4082//zz return False;
4083//zz }
4084//zz DIP("stfsux fr%d,r%d,r%d\n", frS_addr, rA_addr, rB_addr);
4085//zz assign( EA, binop(Iop_Add32, mkexpr(rB), mkexpr(rA)) );
4086//zz storeBE( mkexpr(EA),
4087//zz binop(Iop_F64toF32, get_roundingmode(), mkexpr(frS)) );
4088//zz putIReg( rA_addr, mkexpr(EA) );
4089//zz break;
sewardje14bb9f2005-07-22 09:39:02 +00004090
4091 case 0x2D7: // stfdx (Store Float Double Indexed, PPC32 p516)
4092 DIP("stfdx fr%d,r%d,r%d\n", frS_addr, rA_addr, rB_addr);
4093 assign( EA, binop(Iop_Add32, mkexpr(rB), mkexpr(rA_or_0)) );
4094 storeBE( mkexpr(EA), mkexpr(frS) );
4095 break;
4096
sewardj5f63c0c2005-09-09 10:36:55 +00004097 case 0x2F7: // stfdux (Store Float Double with Update Indexed, PPC32 p515)
4098 if (rA_addr == 0) {
4099 vex_printf("dis_fp_store(PPC32)(instr,stfdux)\n");
4100 return False;
4101 }
4102 DIP("stfdux fr%d,r%d,r%d\n", frS_addr, rA_addr, rB_addr);
4103 assign( EA, binop(Iop_Add32, mkexpr(rB), mkexpr(rA)) );
4104 storeBE( mkexpr(EA), mkexpr(frS) );
4105 putIReg( rA_addr, mkexpr(EA) );
4106 break;
4107
sewardjb51f0f42005-07-18 11:38:02 +00004108//zz case 0x3D7: // stfiwx (Store Float as Int, Indexed, PPC32 p517)
4109//zz DIP("stfiwx fr%d,r%d,r%d\n", frS_addr, rA_addr, rB_addr);
4110//zz assign( EA, binop(Iop_Add32, mkexpr(rB), mkexpr(rA_or_0)) );
4111//zz storeBE( mkexpr(EA),
4112//zz unop(Iop_64to32, unop(Iop_ReinterpF64asI64, mkexpr(frS))) );
4113//zz break;
sewardje14bb9f2005-07-22 09:39:02 +00004114
4115 default:
4116 vex_printf("dis_fp_store(PPC32)(opc2)\n");
4117 return False;
4118 }
4119 break;
cerion3d870a32005-03-18 12:23:33 +00004120
4121 default:
4122 vex_printf("dis_fp_store(PPC32)(opc1)\n");
4123 return False;
4124 }
4125 return True;
4126}
4127
4128
4129
4130/*
4131 Floating Point Arith Instructions
4132*/
4133static Bool dis_fp_arith ( UInt theInstr )
4134{
4135 /* A-Form */
4136 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
4137 UChar frD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
4138 UChar frA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
4139 UChar frB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
4140 UChar frC_addr = toUChar((theInstr >> 6) & 0x1F); /* theInstr[6:10] */
4141 UChar opc2 = toUChar((theInstr >> 1) & 0x1F); /* theInstr[1:5] */
4142 UChar flag_Rc = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
cerion094d1392005-06-20 13:45:57 +00004143 // Note: flag_Rc ignored as fp exceptions not supported.
4144
4145 IRTemp frD = newTemp(Ity_F64);
4146 IRTemp frA = newTemp(Ity_F64);
4147 IRTemp frB = newTemp(Ity_F64);
4148 IRTemp frC = newTemp(Ity_F64);
4149
4150 assign( frA, getFReg(frA_addr));
4151 assign( frB, getFReg(frB_addr));
4152 assign( frC, getFReg(frC_addr));
cerion3d870a32005-03-18 12:23:33 +00004153
4154 switch (opc1) {
sewardje14bb9f2005-07-22 09:39:02 +00004155 case 0x3B:
4156 switch (opc2) {
4157 case 0x12: // fdivs (Floating Divide Single, PPC32 p407)
4158 if (frC_addr != 0) {
4159 vex_printf("dis_fp_arith(PPC32)(instr,fdivs)\n");
4160 return False;
4161 }
4162 DIP("fdivs%s fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4163 frD_addr, frA_addr, frB_addr);
4164 assign( frD, roundToSgl( binop(Iop_DivF64, mkexpr(frA), mkexpr(frB)) ));
4165 break;
4166
4167 case 0x14: // fsubs (Floating Subtract Single, PPC32 p430)
4168 if (frC_addr != 0) {
4169 vex_printf("dis_fp_arith(PPC32)(instr,fsubs)\n");
4170 return False;
4171 }
4172 DIP("fsubs%s fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4173 frD_addr, frA_addr, frB_addr);
4174 assign( frD, roundToSgl(
4175 binop(Iop_SubF64, mkexpr(frA), mkexpr(frB)) ));
4176 break;
4177
4178 case 0x15: // fadds (Floating Add Single, PPC32 p401)
4179 if (frC_addr != 0) {
4180 vex_printf("dis_fp_arith(PPC32)(instr,fadds)\n");
4181 return False;
4182 }
4183 DIP("fadds%s fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4184 frD_addr, frA_addr, frB_addr);
4185 assign( frD, roundToSgl(
4186 binop(Iop_AddF64, mkexpr(frA), mkexpr(frB)) ));
4187 break;
4188
sewardjb51f0f42005-07-18 11:38:02 +00004189//zz case 0x16: // fsqrts (Floating SqRt (Single-Precision), PPC32 p428)
4190//zz if (frA_addr != 0 || frC_addr != 0) {
4191//zz vex_printf("dis_fp_arith(PPC32)(instr,fsqrts)\n");
4192//zz return False;
4193//zz }
4194//zz DIP("fsqrts%s fr%d,fr%d\n", flag_Rc ? "." : "",
4195//zz frD_addr, frB_addr);
4196//zz assign( frD, roundToSgl( unop(Iop_SqrtF64, mkexpr(frB)) ));
4197//zz break;
sewardje14bb9f2005-07-22 09:39:02 +00004198
sewardjb51f0f42005-07-18 11:38:02 +00004199//zz case 0x18: // fres (Floating Reciprocal Estimate Single, PPC32 p421)
4200//zz if (frA_addr != 0 || frC_addr != 0) {
4201//zz vex_printf("dis_fp_arith(PPC32)(instr,fres)\n");
4202//zz return False;
4203//zz }
4204//zz DIP("fres%s fr%d,fr%d\n", flag_Rc ? "." : "",
4205//zz frD_addr, frB_addr);
4206//zz DIP(" => not implemented\n");
4207//zz // CAB: Can we use one of the 128 bit SIMD Iop_Recip32F ops?
4208//zz return False;
sewardje14bb9f2005-07-22 09:39:02 +00004209
4210 case 0x19: // fmuls (Floating Multiply Single, PPC32 p414)
4211 if (frB_addr != 0) {
4212 vex_printf("dis_fp_arith(PPC32)(instr,fmuls)\n");
4213 return False;
4214 }
4215 DIP("fmuls%s fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4216 frD_addr, frA_addr, frC_addr);
4217 assign( frD, roundToSgl( binop(Iop_MulF64, mkexpr(frA), mkexpr(frC)) ));
4218 break;
4219
4220 default:
4221 vex_printf("dis_fp_arith(PPC32)(3B: opc2)\n");
4222 return False;
4223 }
4224 break;
cerion094d1392005-06-20 13:45:57 +00004225
cerion3d870a32005-03-18 12:23:33 +00004226 case 0x3F:
4227 switch (opc2) {
sewardje14bb9f2005-07-22 09:39:02 +00004228 case 0x12: // fdiv (Floating Divide (Double-Precision), PPC32 p406)
4229 if (frC_addr != 0) {
4230 vex_printf("dis_fp_arith(PPC32)(instr,fdiv)\n");
4231 return False;
4232 }
4233 DIP("fdiv%s fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4234 frD_addr, frA_addr, frB_addr);
4235 assign( frD, binop( Iop_DivF64, mkexpr(frA), mkexpr(frB) ) );
4236 break;
4237
4238 case 0x14: // fsub (Floating Subtract (Double-Precision), PPC32 p429)
4239 if (frC_addr != 0) {
4240 vex_printf("dis_fp_arith(PPC32)(instr,fsub)\n");
4241 return False;
4242 }
4243 DIP("fsub%s fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4244 frD_addr, frA_addr, frB_addr);
4245 assign( frD, binop( Iop_SubF64, mkexpr(frA), mkexpr(frB) ) );
4246 break;
cerion3d870a32005-03-18 12:23:33 +00004247
4248 case 0x15: // fadd (Floating Add (Double-Precision), PPC32 p400)
4249 if (frC_addr != 0) {
cerion094d1392005-06-20 13:45:57 +00004250 vex_printf("dis_fp_arith(PPC32)(instr,fadd)\n");
cerion3d870a32005-03-18 12:23:33 +00004251 return False;
4252 }
4253 DIP("fadd%s fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4254 frD_addr, frA_addr, frB_addr);
cerion094d1392005-06-20 13:45:57 +00004255 assign( frD, binop( Iop_AddF64, mkexpr(frA), mkexpr(frB) ) );
4256 break;
cerion3d870a32005-03-18 12:23:33 +00004257
sewardjb51f0f42005-07-18 11:38:02 +00004258//zz case 0x16: // fsqrt (Floating SqRt (Double-Precision), PPC32 p427)
4259//zz if (frA_addr != 0 || frC_addr != 0) {
4260//zz vex_printf("dis_fp_arith(PPC32)(instr,fsqrt)\n");
4261//zz return False;
4262//zz }
4263//zz DIP("fsqrt%s fr%d,fr%d\n", flag_Rc ? "." : "",
4264//zz frD_addr, frB_addr);
4265//zz assign( frD, unop( Iop_SqrtF64, mkexpr(frB) ) );
4266//zz break;
sewardje14bb9f2005-07-22 09:39:02 +00004267
4268 case 0x17: { // fsel (Floating Select, PPC32 p426)
4269 IRTemp cc = newTemp(Ity_I32);
4270 IRTemp cc_b0 = newTemp(Ity_I32);
4271
4272 DIP("fsel%s fr%d,fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4273 frD_addr, frA_addr, frC_addr, frB_addr);
4274
4275 // cc: UN == 0x41, LT == 0x01, GT == 0x00, EQ == 0x40
4276 // => GT|EQ == (cc & 0x1 == 0)
4277 assign( cc, binop(Iop_CmpF64, mkexpr(frA), IRExpr_Const(IRConst_F64(0))) );
4278 assign( cc_b0, binop(Iop_And32, mkexpr(cc), mkU32(1)) );
4279
4280 // frD = (frA >= 0.0) ? frC : frB
4281 // = (cc_b0 == 0) ? frC : frB
4282 assign( frD,
4283 IRExpr_Mux0X(
4284 unop(Iop_1Uto8,
4285 binop(Iop_CmpEQ32, mkexpr(cc_b0), mkU32(0))),
4286 mkexpr(frB),
4287 mkexpr(frC) ));
4288 break;
4289 }
4290
4291 case 0x19: // fmul (Floating Multiply (Double Precision), PPC32 p413)
4292 if (frB_addr != 0) {
4293 vex_printf("dis_fp_arith(PPC32)(instr,fmul)\n");
4294 return False;
4295 }
4296 DIP("fmul%s fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4297 frD_addr, frA_addr, frC_addr);
4298 assign( frD, binop( Iop_MulF64, mkexpr(frA), mkexpr(frC) ) );
4299 break;
4300
sewardjb51f0f42005-07-18 11:38:02 +00004301//zz case 0x1A: // frsqrte (Floating Reciprocal SqRt Estimate, PPC32 p424)
4302//zz if (frA_addr != 0 || frC_addr != 0) {
4303//zz vex_printf("dis_fp_arith(PPC32)(instr,frsqrte)\n");
4304//zz return False;
4305//zz }
4306//zz DIP("frsqrte%s fr%d,fr%d\n", flag_Rc ? "." : "",
4307//zz frD_addr, frB_addr);
4308//zz DIP(" => not implemented\n");
4309//zz // CAB: Iop_SqrtF64, then one of the 128 bit SIMD Iop_Recip32F ops?
4310//zz return False;
cerion3d870a32005-03-18 12:23:33 +00004311
4312 default:
4313 vex_printf("dis_fp_arith(PPC32)(3F: opc2)\n");
4314 return False;
4315 }
cerion094d1392005-06-20 13:45:57 +00004316 break;
4317
cerion3d870a32005-03-18 12:23:33 +00004318 default:
4319 vex_printf("dis_fp_arith(PPC32)(opc1)\n");
4320 return False;
4321 }
cerion094d1392005-06-20 13:45:57 +00004322
4323 putFReg( frD_addr, mkexpr(frD) );
cerion3d870a32005-03-18 12:23:33 +00004324 return True;
4325}
4326
4327
4328
sewardje14bb9f2005-07-22 09:39:02 +00004329/*
4330 Floating Point Mult-Add Instructions
4331*/
4332static Bool dis_fp_multadd ( UInt theInstr )
4333{
4334 /* A-Form */
4335 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
4336 UChar frD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
4337 UChar frA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
4338 UChar frB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
4339 UChar frC_addr = toUChar((theInstr >> 6) & 0x1F); /* theInstr[6:10] */
4340 UChar opc2 = toUChar((theInstr >> 1) & 0x1F); /* theInstr[1:5] */
4341 UChar flag_Rc = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
4342
4343 IRTemp frD = newTemp(Ity_F64);
4344 IRTemp frA = newTemp(Ity_F64);
4345 IRTemp frB = newTemp(Ity_F64);
4346 IRTemp frC = newTemp(Ity_F64);
4347
4348 assign( frA, getFReg(frA_addr));
4349 assign( frB, getFReg(frB_addr));
4350 assign( frC, getFReg(frC_addr));
4351
4352 switch (opc1) {
4353 case 0x3B:
4354 switch (opc2) {
4355 case 0x1C: // fmsubs (Floating Mult-Subtr Single, PPC32 p412)
4356 DIP("fmsubs%s fr%d,fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4357 frD_addr, frA_addr, frC_addr, frB_addr);
4358 assign( frD, roundToSgl(
4359 binop( Iop_SubF64,
4360 binop(Iop_MulF64, mkexpr(frA), mkexpr(frC)),
4361 mkexpr(frB)) ));
4362 break;
4363
4364 case 0x1D: // fmadds (Floating Mult-Add Single, PPC32 p409)
4365 DIP("fmadds%s fr%d,fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4366 frD_addr, frA_addr, frC_addr, frB_addr);
4367 assign( frD, roundToSgl(
4368 binop( Iop_AddF64,
4369 binop(Iop_MulF64, mkexpr(frA), mkexpr(frC)),
4370 mkexpr(frB)) ));
4371 break;
4372
4373 case 0x1E: // fnmsubs (Float Neg Mult-Subtr Single, PPC32 p420)
4374 DIP("fnmsubs%s fr%d,fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4375 frD_addr, frA_addr, frC_addr, frB_addr);
4376 assign( frD, roundToSgl(
4377 unop(Iop_NegF64,
4378 binop(Iop_SubF64,
4379 binop(Iop_MulF64, mkexpr(frA), mkexpr(frC)),
4380 mkexpr(frB))) ));
4381 break;
4382
4383 case 0x1F: // fnmadds (Floating Negative Multiply-Add Single, PPC32 p418)
4384 DIP("fnmadds%s fr%d,fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4385 frD_addr, frA_addr, frC_addr, frB_addr);
4386 assign( frD, roundToSgl(
4387 unop(Iop_NegF64,
4388 binop(Iop_AddF64,
4389 binop(Iop_MulF64, mkexpr(frA), mkexpr(frC)),
4390 mkexpr(frB))) ));
4391 break;
4392
4393 default:
4394 vex_printf("dis_fp_multadd(PPC32)(3B: opc2)\n");
4395 return False;
4396 }
4397 break;
4398
4399 case 0x3F:
4400 switch (opc2) {
4401 case 0x1C: // fmsub (Float Mult-Subtr (Double Precision), PPC32 p411)
4402 DIP("fmsub%s fr%d,fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4403 frD_addr, frA_addr, frC_addr, frB_addr);
4404 assign( frD, binop( Iop_SubF64,
4405 binop( Iop_MulF64, mkexpr(frA), mkexpr(frC) ),
4406 mkexpr(frB) ));
4407 break;
4408
4409 case 0x1D: // fmadd (Float Mult-Add (Double Precision), PPC32 p408)
4410 DIP("fmadd%s fr%d,fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4411 frD_addr, frA_addr, frC_addr, frB_addr);
4412 assign( frD, binop( Iop_AddF64,
4413 binop( Iop_MulF64, mkexpr(frA), mkexpr(frC) ),
4414 mkexpr(frB) ));
4415 break;
4416
sewardj0e2cc672005-07-29 21:58:51 +00004417 case 0x1E: // fnmsub (Float Neg Mult-Subtr (Double Precision), PPC32 p419)
4418 DIP("fnmsub%s fr%d,fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4419 frD_addr, frA_addr, frC_addr, frB_addr);
4420 assign( frD, unop( Iop_NegF64,
4421 binop( Iop_SubF64,
4422 binop( Iop_MulF64, mkexpr(frA), mkexpr(frC) ),
4423 mkexpr(frB) )));
4424 break;
4425
4426 case 0x1F: // fnmadd (Float Neg Mult-Add (Double Precision), PPC32 p417)
4427 DIP("fnmadd%s fr%d,fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4428 frD_addr, frA_addr, frC_addr, frB_addr);
4429 assign( frD, unop( Iop_NegF64,
4430 binop( Iop_AddF64,
4431 binop( Iop_MulF64, mkexpr(frA), mkexpr(frC) ),
4432 mkexpr(frB) )));
4433 break;
sewardje14bb9f2005-07-22 09:39:02 +00004434
4435 default:
4436 vex_printf("dis_fp_multadd(PPC32)(3F: opc2)\n");
4437 return False;
4438 }
4439 break;
4440
4441 default:
4442 vex_printf("dis_fp_multadd(PPC32)(opc1)\n");
4443 return False;
4444 }
4445
4446 putFReg( frD_addr, mkexpr(frD) );
4447 return True;
4448}
4449
4450
4451
4452/*
4453 Floating Point Compare Instructions
4454*/
4455static Bool dis_fp_cmp ( UInt theInstr )
4456{
4457 /* X-Form */
4458 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
4459 UChar crfD = toUChar((theInstr >> 23) & 0x7); /* theInstr[23:25] */
4460 UChar b21to22 = toUChar((theInstr >> 21) & 0x3); /* theInstr[21:22] */
4461 UChar frA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
4462 UChar frB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
4463 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
4464 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
4465
4466 IRTemp ccIR = newTemp(Ity_I32);
4467 IRTemp ccPPC32 = newTemp(Ity_I32);
4468
4469#if 0
4470 IRTemp cc_lt = newTemp(Ity_I32);
4471 IRTemp cc_gt = newTemp(Ity_I32);
4472 IRTemp cc_eq = newTemp(Ity_I32);
4473 IRTemp cc_un = newTemp(Ity_I32);
4474#endif
4475
4476 IRTemp frA = newTemp(Ity_F64);
4477 IRTemp frB = newTemp(Ity_F64);
4478// IRExpr* irx;
4479
4480 if (opc1 != 0x3F || b21to22 != 0 || b0 != 0) {
4481 vex_printf("dis_fp_cmp(PPC32)(instr)\n");
4482 return False;
4483 }
4484
4485 assign( frA, getFReg(frA_addr));
4486 assign( frB, getFReg(frB_addr));
4487
4488 assign( ccIR, binop(Iop_CmpF64, mkexpr(frA), mkexpr(frB)) );
4489
4490 /* Map compare result from IR to PPC32 */
4491 /*
4492 FP cmp result | PPC | IR
4493 --------------------------
4494 UN | 0x1 | 0x45
4495 EQ | 0x2 | 0x40
4496 GT | 0x4 | 0x00
4497 LT | 0x8 | 0x01
4498 */
4499
4500 // ccPPC32 = Shl(1, (0x2 & ~(ccIR>>5)) || (0x1 & (XOR(ccIR, ccIR>>6))))
4501 assign(
4502 ccPPC32,
4503 binop(Iop_Shl32, mkU32(1),
4504 unop(Iop_32to8,
4505 binop(Iop_Or32,
4506 binop(Iop_And32, mkU32(2),
4507 unop(Iop_Not32,
4508 binop(Iop_Shr32, mkexpr(ccIR), mkU8(5)))),
4509 binop(Iop_And32, mkU32(1),
4510 binop(Iop_Xor32, mkexpr(ccIR),
4511 binop(Iop_Shr32, mkexpr(ccIR), mkU8(6)))))))
4512 );
4513
4514 putCR0( crfD, unop( Iop_32to8,
4515 binop(Iop_And32, mkexpr(ccPPC32), mkU32(1))) );
4516 putCR321( crfD, unop( Iop_32to8,
4517 binop(Iop_And32, mkexpr(ccPPC32), mkU32(7<<1))) );
4518
4519 // CAB: Useful to support writing cc to FPSCR->FPCC ?
4520 // putReg_field( PPC32_SPR_FPSCR, mkexpr(ccPPC32), 3 );
4521
4522 // Note: Differences between fcmpu and fcmpo are only
4523 // in exception flag settings, which aren't supported anyway...
4524 opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
4525 switch (opc2) {
4526 case 0x000: // fcmpu (Floating Compare Unordered, PPC32 p403)
4527 DIP("fcmpu crf%d,fr%d,fr%d\n", crfD, frA_addr, frB_addr);
4528 break;
4529
4530 case 0x020: // fcmpo (Floating Compare Ordered, PPC32 p402)
4531 DIP("fcmpo crf%d,fr%d,fr%d\n", crfD, frA_addr, frB_addr);
4532 break;
4533 default:
4534 vex_printf("dis_fp_cmp(PPC32)(opc2)\n");
4535 return False;
4536 }
4537 return True;
4538}
4539
4540
4541
4542/*
4543 Floating Point Rounding/Conversion Instructions
4544*/
4545static Bool dis_fp_round ( UInt theInstr )
4546{
4547 /* X-Form */
4548 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
4549 UChar frD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
4550 UChar b16to20 = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
4551 UChar frB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
4552 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
4553 UChar flag_Rc = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
4554
4555 IRTemp frD = newTemp(Ity_F64);
4556 IRTemp frB = newTemp(Ity_F64);
4557 IRTemp r_tmp = newTemp(Ity_I32);
4558
4559 if (opc1 != 0x3F || b16to20 != 0) {
4560 vex_printf("dis_fp_round(PPC32)(instr)\n");
4561 return False;
4562 }
4563
4564 assign( frB, getFReg(frB_addr));
4565
4566 opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
4567
4568 switch (opc2) {
4569
4570 case 0x00C: // frsp (Floating Round to Single, PPC32 p423)
4571 DIP("frsp%s fr%d,fr%d\n", flag_Rc ? "." : "", frD_addr, frB_addr);
4572 assign( frD, roundToSgl( mkexpr(frB) ));
4573 break;
4574
sewardj5f63c0c2005-09-09 10:36:55 +00004575 case 0x00E: // fctiw (Floating Conv to Int, PPC32 p404)
4576 DIP("fctiw%s fr%d,fr%d\n", flag_Rc ? "." : "", frD_addr, frB_addr);
4577 assign( r_tmp, binop(Iop_F64toI32, get_roundingmode(), mkexpr(frB)) );
4578 assign( frD, unop( Iop_ReinterpI64asF64,
4579 unop( Iop_32Uto64, mkexpr(r_tmp))));
4580 break;
sewardje14bb9f2005-07-22 09:39:02 +00004581
4582 case 0x00F: // fctiwz (Floating Conv to Int, Round to Zero, PPC32 p405)
4583 DIP("fctiwz%s fr%d,fr%d\n", flag_Rc ? "." : "", frD_addr, frB_addr);
4584 assign( r_tmp, binop(Iop_F64toI32, mkU32(0x3), mkexpr(frB)) );
4585 assign( frD, unop( Iop_ReinterpI64asF64,
4586 unop( Iop_32Uto64, mkexpr(r_tmp))));
4587 break;
4588
4589 default:
4590 vex_printf("dis_fp_round(PPC32)(opc2)\n");
4591 return False;
4592 }
4593
4594 putFReg( frD_addr, mkexpr(frD) );
4595 return True;
4596}
4597
4598
4599
4600/*
4601 Floating Point Move Instructions
4602*/
4603static Bool dis_fp_move ( UInt theInstr )
4604{
4605 /* X-Form */
4606 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
4607 UChar frD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
4608 UChar b16to20 = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
4609 UChar frB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
4610 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
4611 UChar flag_Rc = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
4612
4613 IRTemp frD = newTemp(Ity_F64);
4614 IRTemp frB = newTemp(Ity_F64);
4615
4616 if (opc1 != 0x3F || b16to20 != 0) {
4617 vex_printf("dis_fp_move(PPC32)(instr)\n");
4618 return False;
4619 }
4620
4621 assign( frB, getFReg(frB_addr));
4622
4623 opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
4624
4625 switch (opc2) {
4626
4627 case 0x028: // fneg (Floating Negate, PPC32 p416)
4628 DIP("fneg%s fr%d,fr%d\n", flag_Rc ? "." : "", frD_addr, frB_addr);
4629 assign( frD, unop( Iop_NegF64, mkexpr(frB) ));
4630 break;
4631
4632 case 0x048: // fmr (Floating Move Register, PPC32 p410)
4633 DIP("fmr%s fr%d,fr%d\n", flag_Rc ? "." : "", frD_addr, frB_addr);
4634 assign( frD, mkexpr(frB) );
4635 break;
4636
sewardj0e2cc672005-07-29 21:58:51 +00004637 case 0x088: // fnabs (Floating Negative Absolute Value, PPC32 p415)
4638 DIP("fnabs%s fr%d,fr%d\n", flag_Rc ? "." : "", frD_addr, frB_addr);
4639 assign( frD, unop( Iop_NegF64, unop( Iop_AbsF64, mkexpr(frB) )));
4640 break;
sewardje14bb9f2005-07-22 09:39:02 +00004641
4642 case 0x108: // fabs (Floating Absolute Value, PPC32 p399)
4643 DIP("fabs%s fr%d,fr%d\n", flag_Rc ? "." : "", frD_addr, frB_addr);
4644 assign( frD, unop( Iop_AbsF64, mkexpr(frB) ));
4645 break;
4646
4647 default:
4648 vex_printf("dis_fp_move(PPC32)(opc2)\n");
4649 return False;
4650 }
4651
4652 putFReg( frD_addr, mkexpr(frD) );
4653 return True;
4654}
4655
4656
4657
4658/*
4659 Floating Point Status/Control Register Instructions
4660*/
4661static Bool dis_fp_scr ( UInt theInstr )
4662{
4663 /* X-Form */
4664 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
4665 /* Too many forms - see each switch case */
4666 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
4667 UChar flag_Rc = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
4668
4669 if (opc1 != 0x3F) {
4670 vex_printf("dis_fp_scr(PPC32)(instr)\n");
4671 return False;
4672 }
4673
4674 switch (opc2) {
sewardjb51f0f42005-07-18 11:38:02 +00004675//zz case 0x026: { // mtfsb1 (Move to FPSCR Bit 1, PPC32 p479)
4676//zz // Bit crbD of the FPSCR is set.
4677//zz UChar crbD = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
4678//zz UInt b11to20 = (theInstr >> 11) & 0x3FF; /* theInstr[11:20] */
4679//zz
4680//zz if (b11to20 != 0) {
4681//zz vex_printf("dis_fp_scr(PPC32)(instr,mtfsb1)\n");
4682//zz return False;
4683//zz }
4684//zz DIP("mtfsb1%s crb%d \n", flag_Rc ? "." : "", crbD);
4685//zz putReg_bit( PPC32_SPR_FPSCR, mkU32(1), 31-crbD );
4686//zz break;
4687//zz }
4688//zz
4689//zz case 0x040: { // mcrfs (Move to Condition Register from FPSCR, PPC32 p465)
4690//zz UChar crfD = toUChar((theInstr >> 23) & 0x7); /* theInstr[23:25] */
4691//zz UChar b21to22 = toUChar((theInstr >> 21) & 0x3); /* theInstr[21:22] */
4692//zz UChar crfS = toUChar((theInstr >> 18) & 0x7); /* theInstr[18:20] */
4693//zz UChar b11to17 = toUChar((theInstr >> 11) & 0x7F); /* theInstr[11:17] */
4694//zz
4695//zz IRTemp tmp = newTemp(Ity_I32);
4696//zz
4697//zz if (b21to22 != 0 || b11to17 != 0 || flag_Rc != 0) {
4698//zz vex_printf("dis_fp_scr(PPC32)(instr,mcrfs)\n");
4699//zz return False;
4700//zz }
4701//zz DIP("mcrfs crf%d,crf%d\n", crfD, crfS);
4702//zz assign( tmp, getReg_field( PPC32_SPR_FPSCR, 7-crfS ) );
4703//zz putReg_field( PPC32_SPR_CR, mkexpr(tmp), 7-crfD );
4704//zz break;
4705//zz }
sewardj0e2cc672005-07-29 21:58:51 +00004706
4707 case 0x046: { // mtfsb0 (Move to FPSCR Bit 0, PPC32 p478)
4708 // Bit crbD of the FPSCR is cleared.
4709 UChar crbD = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
4710 UInt b11to20 = (theInstr >> 11) & 0x3FF; /* theInstr[11:20] */
4711
4712 if (b11to20 != 0) {
4713 vex_printf("dis_fp_scr(PPC32)(instr,mtfsb0)\n");
4714 return False;
4715 }
4716 DIP("mtfsb0%s crb%d\n", flag_Rc ? "." : "", crbD);
4717 putReg_bit( PPC32_SPR_FPSCR, mkU32(0), 31-crbD );
4718 break;
4719 }
4720
4721 case 0x086: { // mtfsfi (Move to FPSCR Field Immediate, PPC32 p481)
4722 UChar crfD = toUChar((theInstr >> 23) & 0x7); /* theInstr[23:25] */
4723 UChar b16to22 = toUChar((theInstr >> 16) & 0x7F); /* theInstr[16:22] */
4724 UChar IMM = toUChar((theInstr >> 12) & 0xF); /* theInstr[11:15] */
4725 UChar b11 = toUChar((theInstr >> 11) & 0x1); /* theInstr[11] */
4726
4727 if (b16to22 != 0 || b11 != 0) {
4728 vex_printf("dis_fp_scr(PPC32)(instr,mtfsfi)\n");
4729 return False;
4730 }
4731 DIP("mtfsfi%s crf%d,%d\n", flag_Rc ? "." : "", crfD, IMM);
4732 putReg_field( PPC32_SPR_FPSCR, mkU32(IMM), 7-crfD );
4733 break;
4734 }
sewardje14bb9f2005-07-22 09:39:02 +00004735
4736 case 0x247: { // mffs (Move from FPSCR, PPC32 p468)
4737 UChar frD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
4738 UInt b11to20 = (theInstr >> 11) & 0x3FF; /* theInstr[11:20] */
4739
4740 if (b11to20 != 0) {
4741 vex_printf("dis_fp_scr(PPC32)(instr,mffs)\n");
4742 return False;
4743 }
4744 DIP("mffs%s fr%d\n", flag_Rc ? "." : "", frD_addr);
4745 putFReg( frD_addr, unop( Iop_ReinterpI64asF64,
4746 unop( Iop_32Uto64,
4747 getReg_masked( PPC32_SPR_FPSCR, 0x3 ) )));
4748 break;
4749 }
4750
4751 case 0x2C7: { // mtfsf (Move to FPSCR Fields, PPC32 p480)
4752 UChar b25 = toUChar((theInstr >> 25) & 0x1); /* theInstr[25] */
4753 UChar FM = toUChar((theInstr >> 17) & 0xFF); /* theInstr[17:24] */
4754 UChar b16 = toUChar((theInstr >> 16) & 0x1); /* theInstr[16] */
4755 UChar frB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
4756 IRTemp frB = newTemp(Ity_F64);
4757 IRTemp rB_32 = newTemp(Ity_I32);
4758 Int mask = 0;
4759 Int i = 0;
4760
4761 if (b25 != 0 || b16 != 0) {
4762 vex_printf("dis_fp_scr(PPC32)(instr,mtfsf)\n");
4763 return False;
4764 }
4765 DIP("mtfsf%s %d,fr%d\n", flag_Rc ? "." : "", FM, frB_addr);
4766 assign( frB, getFReg(frB_addr));
4767 assign( rB_32, unop( Iop_64to32,
4768 unop( Iop_ReinterpF64asI64, mkexpr(frB) )));
4769 // Build 32bit mask from FM:
4770 for (i=0; i<8; i++) {
4771 if ((FM & (1<<(7-i))) == 1) {
4772 mask |= 0xF << (7-i);
4773 }
4774 }
4775 putReg_masked( PPC32_SPR_FPSCR, mkexpr(rB_32), mask );
4776 break;
4777 }
4778
4779 default:
4780 vex_printf("dis_fp_scr(PPC32)(opc2)\n");
4781 return False;
4782 }
4783 return True;
4784}
4785
4786
4787
cerion32aad402005-09-10 12:02:24 +00004788/*------------------------------------------------------------*/
4789/*--- AltiVec Instruction Translation ---*/
4790/*------------------------------------------------------------*/
4791
4792/*
4793 Altivec Cache Control Instructions (Data Streams)
4794*/
4795static Bool dis_av_datastream ( UInt theInstr )
4796{
4797 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
4798 UChar flag_T = toUChar((theInstr >> 25) & 0x1); /* theInstr[25] */
4799 UChar flag_A = toUChar((theInstr >> 25) & 0x1); /* theInstr[25] */
4800 UChar b23to24 = toUChar((theInstr >> 23) & 0x3); /* theInstr[23:24] */
4801 UChar STRM = toUChar((theInstr >> 21) & 0x3); /* theInstr[21:22] */
4802 UChar rA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
4803 UChar rB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
4804 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
4805 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
4806
4807 if (opc1 != 0x1F || b23to24 != 0 || b0 != 0) {
4808 vex_printf("dis_av_datastream(PPC32)(instr)\n");
4809 return False;
4810 }
4811
4812 switch (opc2) {
4813 case 0x156: // dst (Data Stream Touch, AV p115)
4814 DIP("dst%s r%d,r%d,%d\n", flag_T ? "t" : "", rA_addr, rB_addr, STRM);
4815 DIP(" => not implemented\n");
4816 return False;
4817
4818 case 0x176: // dstst (Data Stream Touch for Store, AV p117)
4819 DIP("dstst%s r%d,r%d,%d\n", flag_T ? "t" : "", rA_addr, rB_addr, STRM);
4820 DIP(" => not implemented\n");
4821 return False;
4822
4823 case 0x336: // dss (Data Stream Stop, AV p114)
4824 if (rA_addr != 0 || rB_addr != 0) {
4825 vex_printf("dis_av_datastream(PPC32)(opc2,dst)\n");
4826 return False;
4827 }
4828 if (flag_A == 0) {
4829 DIP("dss %d\n", STRM);
4830 DIP(" => not implemented\n");
4831 } else {
4832 DIP("dssall\n");
4833 DIP(" => not implemented\n");
4834 }
4835 return False;
4836
4837 default:
4838 vex_printf("dis_av_datastream(PPC32)(opc2)\n");
4839 return False;
4840 }
4841 return True;
4842}
4843
4844/*
4845 AltiVec Processor Control Instructions
4846*/
4847static Bool dis_av_procctl ( UInt theInstr )
4848{
4849 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
4850 UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
4851 UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
4852 UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
4853 UInt opc2 = (theInstr >> 0) & 0x7FF; /* theInstr[0:10] */
4854
4855 if (opc1 != 0x4) {
4856 vex_printf("dis_av_procctl(PPC32)(instr)\n");
4857 return False;
4858 }
4859
4860 switch (opc2) {
4861 case 0x604: // mfvscr (Move from VSCR, AV p129)
4862 if (vA_addr != 0 || vB_addr != 0) {
4863 vex_printf("dis_av_procctl(PPC32)(opc2,dst)\n");
4864 return False;
4865 }
4866 DIP("mfvscr v%d\n", vD_addr);
cerion225a0342005-09-12 20:49:09 +00004867 putVReg( vD_addr, unop(Iop_32UtoV128, getSPR( PPC32_SPR_VSCR )) );
4868 break;
cerion32aad402005-09-10 12:02:24 +00004869
cerion225a0342005-09-12 20:49:09 +00004870 case 0x644: { // mtvscr (Move to VSCR, AV p130)
cerion32aad402005-09-10 12:02:24 +00004871 if (vD_addr != 0 || vA_addr != 0) {
4872 vex_printf("dis_av_procctl(PPC32)(opc2,dst)\n");
4873 return False;
4874 }
4875 DIP("mtvscr v%d\n", vB_addr);
cerion225a0342005-09-12 20:49:09 +00004876 IRTemp vB = newTemp(Ity_V128);
4877 assign( vB, getVReg(vB_addr));
4878 putSPR( PPC32_SPR_VSCR, unop(Iop_V128to32, mkexpr(vB)) );
4879 break;
4880 }
cerion32aad402005-09-10 12:02:24 +00004881 default:
4882 vex_printf("dis_av_procctl(PPC32)(opc2)\n");
4883 return False;
4884 }
4885 return True;
4886}
ceriona982c052005-06-28 17:23:09 +00004887
4888/*
4889 AltiVec Load Instructions
4890*/
4891static Bool dis_av_load ( UInt theInstr )
4892{
4893 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
4894 UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
4895 UChar rA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
4896 UChar rB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
4897 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
4898 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
4899
ceriona50fde52005-07-01 21:16:10 +00004900 IRTemp EA = newTemp(Ity_I32);
4901 IRTemp EA_aligned = newTemp(Ity_I32);
4902
ceriona982c052005-06-28 17:23:09 +00004903 if (opc1 != 0x1F || b0 != 0) {
4904 vex_printf("dis_av_load(PPC32)(instr)\n");
4905 return False;
4906 }
4907
sewardjafe85832005-09-09 10:25:39 +00004908 assign( EA, ea_standard(rA_addr, rB_addr) );
ceriona50fde52005-07-01 21:16:10 +00004909
ceriona982c052005-06-28 17:23:09 +00004910 switch (opc2) {
4911
cerion6f6c6a02005-09-13 18:41:09 +00004912 case 0x006: { // lvsl (Load Vector for Shift Left, AV p123)
cerion32aad402005-09-10 12:02:24 +00004913 DIP("lvsl v%d,r%d,r%d\n", vD_addr, rA_addr, rB_addr);
cerion6f6c6a02005-09-13 18:41:09 +00004914 IRExpr** args = mkIRExprVec_3(mkU32(vD_addr), mkexpr(EA), mkU32(0));
4915 IRDirty* d = unsafeIRDirty_0_N (
4916 0/*regparms*/,
4917 "ppc32g_dirtyhelper_LVS",
4918 &ppc32g_dirtyhelper_LVS,
4919 args );
4920 /* declare guest state effects */
4921 d->needsBBP = True;
4922 d->nFxState = 1;
4923 d->fxState[0].fx = Ifx_Write;
4924 d->fxState[0].offset = vectorGuestRegOffset(vD_addr);
4925 d->fxState[0].size = sizeof(U128);
cerion32aad402005-09-10 12:02:24 +00004926
cerion6f6c6a02005-09-13 18:41:09 +00004927 /* execute the dirty call, side-effecting guest state */
4928 stmt( IRStmt_Dirty(d) );
4929 break;
4930 }
4931 case 0x026: { // lvsr (Load Vector for Shift Right, AV p125)
cerion32aad402005-09-10 12:02:24 +00004932 DIP("lvsr v%d,r%d,r%d\n", vD_addr, rA_addr, rB_addr);
cerion6f6c6a02005-09-13 18:41:09 +00004933 IRExpr** args = mkIRExprVec_3(mkU32(vD_addr), mkexpr(EA), mkU32(1));
4934 IRDirty* d = unsafeIRDirty_0_N (
4935 0/*regparms*/,
4936 "ppc32g_dirtyhelper_LVS",
4937 &ppc32g_dirtyhelper_LVS,
4938 args );
4939 /* declare guest state effects */
4940 d->needsBBP = True;
4941 d->nFxState = 1;
4942 d->fxState[0].fx = Ifx_Write;
4943 d->fxState[0].offset = vectorGuestRegOffset(vD_addr);
4944 d->fxState[0].size = sizeof(U128);
cerion32aad402005-09-10 12:02:24 +00004945
cerion6f6c6a02005-09-13 18:41:09 +00004946 /* execute the dirty call, side-effecting guest state */
4947 stmt( IRStmt_Dirty(d) );
4948 break;
4949 }
cerion32aad402005-09-10 12:02:24 +00004950 case 0x007: // lvebx (Load Vector Element Byte Indexed, AV p119)
4951 DIP("lvebx v%d,r%d,r%d\n", vD_addr, rA_addr, rB_addr);
cerion61c92742005-09-14 22:59:26 +00004952 /* loads addressed byte into vector[EA[0:3]
4953 since all other destination bytes are undefined,
4954 can simply load entire vector from 16-aligned EA */
4955 assign( EA_aligned, binop( Iop_And32, mkexpr(EA), mkU32(0xFFFFFFF0) ));
4956 putVReg( vD_addr, loadBE(Ity_V128, mkexpr(EA_aligned)) );
4957 break;
cerion32aad402005-09-10 12:02:24 +00004958
4959 case 0x027: // lvehx (Load Vector Element Half Word Indexed, AV p121)
4960 DIP("lvehx v%d,r%d,r%d\n", vD_addr, rA_addr, rB_addr);
cerion61c92742005-09-14 22:59:26 +00004961 /* see note for lvebx */
4962 assign( EA_aligned, binop( Iop_And32, mkexpr(EA), mkU32(0xFFFFFFF0) ));
4963 putVReg( vD_addr, loadBE(Ity_V128, mkexpr(EA_aligned)) );
4964 break;
cerion32aad402005-09-10 12:02:24 +00004965
4966 case 0x047: // lvewx (Load Vector Element Word Indexed, AV p122)
4967 DIP("lvewx v%d,r%d,r%d\n", vD_addr, rA_addr, rB_addr);
cerion61c92742005-09-14 22:59:26 +00004968 /* see note for lvebx */
4969 assign( EA_aligned, binop( Iop_And32, mkexpr(EA), mkU32(0xFFFFFFF0) ));
4970 putVReg( vD_addr, loadBE(Ity_V128, mkexpr(EA_aligned)) );
4971 break;
ceriona982c052005-06-28 17:23:09 +00004972
4973 case 0x067: // lvx (Load Vector Indexed, AV p127)
4974 DIP("lvx v%d,r%d,r%d\n", vD_addr, rA_addr, rB_addr);
ceriona50fde52005-07-01 21:16:10 +00004975 assign( EA_aligned, binop( Iop_And32, mkexpr(EA), mkU32(0xFFFFFFF0) ));
4976 putVReg( vD_addr, loadBE(Ity_V128, mkexpr(EA_aligned)) );
4977 break;
ceriona982c052005-06-28 17:23:09 +00004978
cerion32aad402005-09-10 12:02:24 +00004979 case 0x167: // lvxl (Load Vector Indexed LRU, AV p128)
4980 // XXX: lvxl gives explicit control over cache block replacement
4981 DIP("lvxl v%d,r%d,r%d\n", vD_addr, rA_addr, rB_addr);
4982 DIP(" => not implemented\n");
4983 return False;
ceriona982c052005-06-28 17:23:09 +00004984
4985 default:
4986 vex_printf("dis_av_load(PPC32)(opc2)\n");
4987 return False;
4988 }
4989 return True;
4990}
4991
4992/*
4993 AltiVec Store Instructions
4994*/
4995static Bool dis_av_store ( UInt theInstr )
4996{
4997 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
4998 UChar vS_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
4999 UChar rA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5000 UChar rB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
5001 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
5002 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
5003
cerion225a0342005-09-12 20:49:09 +00005004 // IRTemp rA = newTemp(Ity_I32);
5005 // IRTemp rB = newTemp(Ity_I32);
ceriona982c052005-06-28 17:23:09 +00005006 IRTemp vS = newTemp(Ity_V128);
5007 IRTemp EA = newTemp(Ity_I32);
5008 IRTemp EA_aligned = newTemp(Ity_I32);
5009
cerion225a0342005-09-12 20:49:09 +00005010 // assign( rA, getIReg(rA_addr));
5011 // assign( rB, getIReg(rB_addr));
ceriona982c052005-06-28 17:23:09 +00005012 assign( vS, getVReg(vS_addr));
5013
sewardjafe85832005-09-09 10:25:39 +00005014 assign( EA, ea_standard(rA_addr, rB_addr) );
ceriona982c052005-06-28 17:23:09 +00005015
5016 if (opc1 != 0x1F || b0 != 0) {
5017 vex_printf("dis_av_store(PPC32)(instr)\n");
5018 return False;
5019 }
5020
5021 switch (opc2) {
cerion61c92742005-09-14 22:59:26 +00005022 case 0x087: { // stvebx (Store Vector Byte Indexed, AV p131)
cerion32aad402005-09-10 12:02:24 +00005023 DIP("stvebx v%d,r%d,r%d\n", vS_addr, rA_addr, rB_addr);
cerion61c92742005-09-14 22:59:26 +00005024 IRTemp eb = newTemp(Ity_I8);
5025 IRTemp idx = newTemp(Ity_I8);
5026 assign( eb, binop(Iop_And8, mkU8(0xF),
5027 unop(Iop_32to8, mkexpr(EA) )) );
5028 assign( idx, binop(Iop_Shl8, binop(Iop_Sub8, mkU8(15), mkexpr(eb)),
5029 mkU8(3)) );
5030 storeBE( mkexpr(EA),
5031 unop(Iop_32to8, unop(Iop_V128to32,
5032 binop(Iop_ShrV128, mkexpr(vS), mkexpr(idx)))) );
5033 break;
5034 }
5035 case 0x0A7: { // stvehx (Store Vector Half Word Indexed, AV p132)
5036 IRTemp eb = newTemp(Ity_I8);
5037 IRTemp idx = newTemp(Ity_I8);
cerion32aad402005-09-10 12:02:24 +00005038 DIP("stvehx v%d,r%d,r%d\n", vS_addr, rA_addr, rB_addr);
cerion61c92742005-09-14 22:59:26 +00005039 assign( EA_aligned, binop( Iop_And32, mkexpr(EA), mkU32(0xFFFFFFFE) ));
5040 assign( eb, binop(Iop_And8, mkU8(0xF),
5041 unop(Iop_32to8, mkexpr(EA_aligned) )) );
5042 assign( idx, binop(Iop_Shl8, binop(Iop_Sub8, mkU8(14), mkexpr(eb)),
5043 mkU8(3)) );
5044 storeBE( mkexpr(EA_aligned),
5045 unop(Iop_32to16, unop(Iop_V128to32,
5046 binop(Iop_ShrV128, mkexpr(vS), mkexpr(idx)))) );
5047 break;
5048 }
5049 case 0x0C7: { // stvewx (Store Vector Word Indexed, AV p133)
cerion32aad402005-09-10 12:02:24 +00005050 DIP("stvewx v%d,r%d,r%d\n", vS_addr, rA_addr, rB_addr);
cerion61c92742005-09-14 22:59:26 +00005051 IRTemp eb = newTemp(Ity_I8);
5052 IRTemp idx = newTemp(Ity_I8);
5053 assign( EA_aligned, binop( Iop_And32, mkexpr(EA), mkU32(0xFFFFFFFC) ));
5054 assign( eb, binop(Iop_And8, mkU8(0xF),
5055 unop(Iop_32to8, mkexpr(EA_aligned) )) );
5056 assign( idx, binop(Iop_Shl8, binop(Iop_Sub8, mkU8(12), mkexpr(eb)),
5057 mkU8(3)) );
5058 storeBE( mkexpr(EA_aligned),
5059 unop(Iop_V128to32,
5060 binop(Iop_ShrV128, mkexpr(vS), mkexpr(idx))) );
5061 break;
5062 }
cerion32aad402005-09-10 12:02:24 +00005063
5064// EA_aligned = EA & 0xFFFF_FFFC
5065// eb = EA_aligned & 0xF;
5066// STORE(vS[eb*8:eb*8+31], 4, EA_aligned);
ceriona982c052005-06-28 17:23:09 +00005067
5068 case 0x0E7: // stvx (Store Vector Indexed, AV p134)
5069 DIP("stvx v%d,r%d,r%d\n", vS_addr, rA_addr, rB_addr);
5070 assign( EA_aligned, binop( Iop_And32, mkexpr(EA), mkU32(0xFFFFFFF0) ));
5071 storeBE( mkexpr(EA_aligned), mkexpr(vS) );
5072 break;
5073
cerion32aad402005-09-10 12:02:24 +00005074 case 0x1E7: // stvxl (Store Vector Indexed LRU, AV p135)
5075 // XXX: stvxl can give explicit control over cache block replacement
5076 DIP("stvxl v%d,r%d,r%d\n", vS_addr, rA_addr, rB_addr);
5077 DIP(" => not implemented\n");
5078 return False;
5079
5080// EA_aligned = EA & 0xFFFF_FFF0;
5081// STORE(vS, 16, EA);
ceriona982c052005-06-28 17:23:09 +00005082
5083 default:
5084 vex_printf("dis_av_store(PPC32)(opc2)\n");
5085 return False;
5086 }
5087 return True;
5088}
5089
cerion32aad402005-09-10 12:02:24 +00005090/*
5091 AltiVec Arithmetic Instructions
5092*/
5093static Bool dis_av_arith ( UInt theInstr )
5094{
5095 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
5096 UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
5097 UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5098 UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
5099 UInt opc2 = (theInstr >> 0) & 0x7FF; /* theInstr[0:10] */
5100
ceriond3e52412005-09-14 21:15:40 +00005101 IRTemp vA = newTemp(Ity_V128);
5102 IRTemp vB = newTemp(Ity_V128);
5103 assign( vA, getVReg(vA_addr));
5104 assign( vB, getVReg(vB_addr));
5105
cerion32aad402005-09-10 12:02:24 +00005106 if (opc1 != 0x4) {
5107 vex_printf("dis_av_arith(PPC32)(opc1 != 0x4)\n");
5108 return False;
5109 }
5110
5111 switch (opc2) {
5112 /* Add */
ceriond3e52412005-09-14 21:15:40 +00005113 case 0x180: { // vaddcuw (Add Carryout Unsigned Word, AV p136)
cerion32aad402005-09-10 12:02:24 +00005114 DIP("vaddcuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005115 /* unsigned_ov(x+y) = (y >u not(x)) */
ceriond3e52412005-09-14 21:15:40 +00005116 putVReg( vD_addr, binop(Iop_ShrN32x4,
cerion36991ef2005-09-15 12:42:16 +00005117 binop(Iop_CmpGT32Ux4, mkexpr(vB),
5118 unop(Iop_NotV128, mkexpr(vA))),
ceriond3e52412005-09-14 21:15:40 +00005119 mkU8(31)) );
5120 break;
5121 }
cerion32aad402005-09-10 12:02:24 +00005122 case 0x000: // vaddubm (Add Unsigned Byte Modulo, AV p141)
5123 DIP("vaddubm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005124 putVReg( vD_addr, binop(Iop_Add8x16, mkexpr(vA), mkexpr(vB)) );
5125 break;
5126
cerion32aad402005-09-10 12:02:24 +00005127 case 0x040: // vadduhm (Add Unsigned Half Word Modulo, AV p143)
5128 DIP("vadduhm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005129 putVReg( vD_addr, binop(Iop_Add16x8, mkexpr(vA), mkexpr(vB)) );
5130 break;
5131
cerion32aad402005-09-10 12:02:24 +00005132 case 0x080: // vadduwm (Add Unsigned Word Modulo, AV p145)
5133 DIP("vadduwm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005134 putVReg( vD_addr, binop(Iop_Add32x4, mkexpr(vA), mkexpr(vB)) );
5135 break;
5136
cerion32aad402005-09-10 12:02:24 +00005137 case 0x200: // vaddubs (Add Unsigned Byte Saturate, AV p142)
5138 DIP("vaddubs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005139 putVReg( vD_addr, binop(Iop_QAdd8Ux16, mkexpr(vA), mkexpr(vB)) );
5140 // TODO: set VSCR[SAT], perhaps via new primop: Iop_SatOfQAdd8Ux16
5141 break;
5142
cerion32aad402005-09-10 12:02:24 +00005143 case 0x240: // vadduhs (Add Unsigned Half Word Saturate, AV p144)
5144 DIP("vadduhs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005145 putVReg( vD_addr, binop(Iop_QAdd16Ux8, mkexpr(vA), mkexpr(vB)) );
5146 // TODO: set VSCR[SAT]
5147 break;
5148
cerion32aad402005-09-10 12:02:24 +00005149 case 0x280: // vadduws (Add Unsigned Word Saturate, AV p146)
5150 DIP("vadduws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005151 putVReg( vD_addr, binop(Iop_QAdd32Ux4, mkexpr(vA), mkexpr(vB)) );
5152 // TODO: set VSCR[SAT]
5153 break;
5154
cerion32aad402005-09-10 12:02:24 +00005155 case 0x300: // vaddsbs (Add Signed Byte Saturate, AV p138)
5156 DIP("vaddsbs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005157 putVReg( vD_addr, binop(Iop_QAdd8Sx16, mkexpr(vA), mkexpr(vB)) );
5158 // TODO: set VSCR[SAT]
5159 break;
5160
cerion32aad402005-09-10 12:02:24 +00005161 case 0x340: // vaddshs (Add Signed Half Word Saturate, AV p139)
5162 DIP("vaddshs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005163 putVReg( vD_addr, binop(Iop_QAdd16Sx8, mkexpr(vA), mkexpr(vB)) );
5164 // TODO: set VSCR[SAT]
5165 break;
5166
cerion32aad402005-09-10 12:02:24 +00005167 case 0x380: // vaddsws (Add Signed Word Saturate, AV p140)
5168 DIP("vaddsws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005169 putVReg( vD_addr, binop(Iop_QAdd32Sx4, mkexpr(vA), mkexpr(vB)) );
5170 // TODO: set VSCR[SAT]
5171 break;
5172
5173
cerion32aad402005-09-10 12:02:24 +00005174 /* Subtract */
cerion36991ef2005-09-15 12:42:16 +00005175 case 0x580: { // vsubcuw (Subtract Carryout Unsigned Word, AV p260)
cerion32aad402005-09-10 12:02:24 +00005176 DIP("vsubcuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005177 /* unsigned_ov(x-y) = (y >u x) */
5178 putVReg( vD_addr, binop(Iop_ShrN32x4,
5179 unop(Iop_NotV128,
5180 binop(Iop_CmpGT32Ux4, mkexpr(vB),
5181 mkexpr(vA))),
5182 mkU8(31)) );
5183 break;
5184 }
cerion32aad402005-09-10 12:02:24 +00005185 case 0x400: // vsububm (Subtract Unsigned Byte Modulo, AV p265)
5186 DIP("vsububm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005187 putVReg( vD_addr, binop(Iop_Sub8x16, mkexpr(vA), mkexpr(vB)) );
5188 break;
5189
cerion32aad402005-09-10 12:02:24 +00005190 case 0x440: // vsubuhm (Subtract Unsigned Half Word Modulo, AV p267)
5191 DIP("vsubuhm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005192 putVReg( vD_addr, binop(Iop_Sub16x8, mkexpr(vA), mkexpr(vB)) );
5193 break;
5194
cerion32aad402005-09-10 12:02:24 +00005195 case 0x480: // vsubuwm (Subtract Unsigned Word Modulo, AV p269)
5196 DIP("vsubuwm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005197 putVReg( vD_addr, binop(Iop_Sub32x4, mkexpr(vA), mkexpr(vB)) );
5198 break;
5199
cerion32aad402005-09-10 12:02:24 +00005200 case 0x600: // vsububs (Subtract Unsigned Byte Saturate, AV p266)
5201 DIP("vsububs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005202 putVReg( vD_addr, binop(Iop_QSub8Ux16, mkexpr(vA), mkexpr(vB)) );
5203 // TODO: set VSCR[SAT]
5204 break;
5205
cerion32aad402005-09-10 12:02:24 +00005206 case 0x640: // vsubuhs (Subtract Unsigned Half Word Saturate, AV p268)
5207 DIP("vsubuhs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005208 putVReg( vD_addr, binop(Iop_QSub16Ux8, mkexpr(vA), mkexpr(vB)) );
5209 // TODO: set VSCR[SAT]
5210 break;
5211
cerion32aad402005-09-10 12:02:24 +00005212 case 0x680: // vsubuws (Subtract Unsigned Word Saturate, AV p270)
5213 DIP("vsubuws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005214 putVReg( vD_addr, binop(Iop_QSub32Ux4, mkexpr(vA), mkexpr(vB)) );
5215 // TODO: set VSCR[SAT]
5216 break;
5217
cerion32aad402005-09-10 12:02:24 +00005218 case 0x700: // vsubsbs (Subtract Signed Byte Saturate, AV p262)
5219 DIP("vsubsbs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005220 putVReg( vD_addr, binop(Iop_QSub8Sx16, mkexpr(vA), mkexpr(vB)) );
5221 // TODO: set VSCR[SAT]
5222 break;
5223
cerion32aad402005-09-10 12:02:24 +00005224 case 0x740: // vsubshs (Subtract Signed Half Word Saturate, AV p263)
5225 DIP("vsubshs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005226 putVReg( vD_addr, binop(Iop_QSub16Sx8, mkexpr(vA), mkexpr(vB)) );
5227 // TODO: set VSCR[SAT]
5228 break;
5229
cerion32aad402005-09-10 12:02:24 +00005230 case 0x780: // vsubsws (Subtract Signed Word Saturate, AV p264)
5231 DIP("vsubsws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005232 putVReg( vD_addr, binop(Iop_QSub32Sx4, mkexpr(vA), mkexpr(vB)) );
5233 // TODO: set VSCR[SAT]
5234 break;
cerion32aad402005-09-10 12:02:24 +00005235
5236
5237 /* Maximum */
5238 case 0x002: // vmaxub (Maximum Unsigned Byte, AV p182)
5239 DIP("vmaxub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005240 putVReg( vD_addr, binop(Iop_Max8Ux16, mkexpr(vA), mkexpr(vB)) );
5241 break;
cerion32aad402005-09-10 12:02:24 +00005242
5243 case 0x042: // vmaxuh (Maximum Unsigned Half Word, AV p183)
5244 DIP("vmaxuh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005245 putVReg( vD_addr, binop(Iop_Max16Ux8, mkexpr(vA), mkexpr(vB)) );
5246 break;
cerion32aad402005-09-10 12:02:24 +00005247
5248 case 0x082: // vmaxuw (Maximum Unsigned Word, AV p184)
5249 DIP("vmaxuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005250 putVReg( vD_addr, binop(Iop_Max32Ux4, mkexpr(vA), mkexpr(vB)) );
5251 break;
cerion32aad402005-09-10 12:02:24 +00005252
5253 case 0x102: // vmaxsb (Maximum Signed Byte, AV p179)
5254 DIP("vmaxsb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005255 putVReg( vD_addr, binop(Iop_Max8Sx16, mkexpr(vA), mkexpr(vB)) );
5256 break;
cerion32aad402005-09-10 12:02:24 +00005257
5258 case 0x142: // vmaxsh (Maximum Signed Half Word, AV p180)
5259 DIP("vmaxsh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005260 putVReg( vD_addr, binop(Iop_Max16Sx8, mkexpr(vA), mkexpr(vB)) );
5261 break;
cerion32aad402005-09-10 12:02:24 +00005262
5263 case 0x182: // vmaxsw (Maximum Signed Word, AV p181)
5264 DIP("vmaxsw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005265 putVReg( vD_addr, binop(Iop_Max32Sx4, mkexpr(vA), mkexpr(vB)) );
5266 break;
cerion32aad402005-09-10 12:02:24 +00005267
5268
5269 /* Minimum */
5270 case 0x202: // vminub (Minimum Unsigned Byte, AV p191)
5271 DIP("vminub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005272 putVReg( vD_addr, binop(Iop_Min8Ux16, mkexpr(vA), mkexpr(vB)) );
5273 break;
cerion32aad402005-09-10 12:02:24 +00005274
5275 case 0x242: // vminuh (Minimum Unsigned Half Word, AV p192)
5276 DIP("vminuh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005277 putVReg( vD_addr, binop(Iop_Min16Ux8, mkexpr(vA), mkexpr(vB)) );
5278 break;
cerion32aad402005-09-10 12:02:24 +00005279
5280 case 0x282: // vminuw (Minimum Unsigned Word, AV p193)
5281 DIP("vminuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005282 putVReg( vD_addr, binop(Iop_Min32Ux4, mkexpr(vA), mkexpr(vB)) );
5283 break;
cerion32aad402005-09-10 12:02:24 +00005284
5285 case 0x302: // vminsb (Minimum Signed Byte, AV p188)
5286 DIP("vminsb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005287 putVReg( vD_addr, binop(Iop_Min8Sx16, mkexpr(vA), mkexpr(vB)) );
5288 break;
cerion32aad402005-09-10 12:02:24 +00005289
5290 case 0x342: // vminsh (Minimum Signed Half Word, AV p189)
5291 DIP("vminsh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005292 putVReg( vD_addr, binop(Iop_Min16Sx8, mkexpr(vA), mkexpr(vB)) );
5293 break;
cerion32aad402005-09-10 12:02:24 +00005294
5295 case 0x382: // vminsw (Minimum Signed Word, AV p190)
5296 DIP("vminsw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005297 putVReg( vD_addr, binop(Iop_Min32Sx4, mkexpr(vA), mkexpr(vB)) );
5298 break;
5299
cerion32aad402005-09-10 12:02:24 +00005300
5301 /* Average */
5302 case 0x402: // vavgub (Average Unsigned Byte, AV p152)
5303 DIP("vavgub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005304 putVReg( vD_addr, binop(Iop_Avg8Ux16, mkexpr(vA), mkexpr(vB)) );
5305 break;
cerion32aad402005-09-10 12:02:24 +00005306
5307 case 0x442: // vavguh (Average Unsigned Half Word, AV p153)
5308 DIP("vavguh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005309 putVReg( vD_addr, binop(Iop_Avg16Ux8, mkexpr(vA), mkexpr(vB)) );
5310 break;
cerion32aad402005-09-10 12:02:24 +00005311
5312 case 0x482: // vavguw (Average Unsigned Word, AV p154)
5313 DIP("vavguw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005314 putVReg( vD_addr, binop(Iop_Avg32Ux4, mkexpr(vA), mkexpr(vB)) );
5315 break;
cerion32aad402005-09-10 12:02:24 +00005316
5317 case 0x502: // vavgsb (Average Signed Byte, AV p149)
5318 DIP("vavgsb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005319 putVReg( vD_addr, binop(Iop_Avg8Sx16, mkexpr(vA), mkexpr(vB)) );
5320 break;
cerion32aad402005-09-10 12:02:24 +00005321
5322 case 0x542: // vavgsh (Average Signed Half Word, AV p150)
5323 DIP("vavgsh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005324 putVReg( vD_addr, binop(Iop_Avg16Sx8, mkexpr(vA), mkexpr(vB)) );
5325 break;
cerion32aad402005-09-10 12:02:24 +00005326
5327 case 0x582: // vavgsw (Average Signed Word, AV p151)
5328 DIP("vavgsw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005329 putVReg( vD_addr, binop(Iop_Avg32Sx4, mkexpr(vA), mkexpr(vB)) );
5330 break;
cerion32aad402005-09-10 12:02:24 +00005331
5332
5333 /* Multiply */
5334 case 0x008: // vmuloub (Multiply Odd Unsigned Byte, AV p213)
5335 DIP("vmuloub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005336 putVReg( vD_addr, binop(Iop_MulLo16Ux8, mkexpr(vA), mkexpr(vB)) );
5337 break;
cerion32aad402005-09-10 12:02:24 +00005338
5339 case 0x048: // vmulouh (Multiply Odd Unsigned Half Word, AV p214)
5340 DIP("vmulouh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005341 putVReg( vD_addr, binop(Iop_MulLo32Ux4, mkexpr(vA), mkexpr(vB)) );
5342 break;
cerion32aad402005-09-10 12:02:24 +00005343
5344 case 0x108: // vmulosb (Multiply Odd Signed Byte, AV p211)
5345 DIP("vmulosb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005346 putVReg( vD_addr, binop(Iop_MulLo16Sx8, mkexpr(vA), mkexpr(vB)) );
5347 break;
cerion32aad402005-09-10 12:02:24 +00005348
5349 case 0x148: // vmulosh (Multiply Odd Signed Half Word, AV p212)
5350 DIP("vmulosh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005351 putVReg( vD_addr, binop(Iop_MulLo32Sx4, mkexpr(vA), mkexpr(vB)) );
5352 break;
cerion32aad402005-09-10 12:02:24 +00005353
5354 case 0x208: // vmuleub (Multiply Even Unsigned Byte, AV p209)
5355 DIP("vmuleub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005356 putVReg( vD_addr, binop(Iop_MulHi16Ux8, mkexpr(vA), mkexpr(vB)) );
5357 break;
cerion32aad402005-09-10 12:02:24 +00005358
5359 case 0x248: // vmuleuh (Multiply Even Unsigned Half Word, AV p210)
5360 DIP("vmuleuh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005361 putVReg( vD_addr, binop(Iop_MulHi32Ux4, mkexpr(vA), mkexpr(vB)) );
5362 break;
cerion32aad402005-09-10 12:02:24 +00005363
5364 case 0x308: // vmulesb (Multiply Even Signed Byte, AV p207)
5365 DIP("vmulesb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005366 putVReg( vD_addr, binop(Iop_MulHi16Sx8, mkexpr(vA), mkexpr(vB)) );
5367 break;
cerion32aad402005-09-10 12:02:24 +00005368
5369 case 0x348: // vmulesh (Multiply Even Signed Half Word, AV p208)
5370 DIP("vmulesh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion36991ef2005-09-15 12:42:16 +00005371 putVReg( vD_addr, binop(Iop_MulHi32Sx4, mkexpr(vA), mkexpr(vB)) );
5372 break;
cerion32aad402005-09-10 12:02:24 +00005373
5374
5375 /* Sum Across Partial */
5376 case 0x608: // vsum4ubs (Sum Partial (1/4) UB Saturate, AV p275)
5377 DIP("vsum4ubs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5378 DIP(" => not implemented\n");
5379 return False;
5380
5381 case 0x708: // vsum4sbs (Sum Partial (1/4) SB Saturate, AV p273)
5382 DIP("vsum4sbs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5383 DIP(" => not implemented\n");
5384 return False;
5385
5386 case 0x648: // vsum4shs (Sum Partial (1/4) SHW Saturate, AV p274)
5387 DIP("vsum4shs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5388 DIP(" => not implemented\n");
5389 return False;
5390
5391 case 0x688: // vsum2sws (Sum Partial (1/2) SW Saturate, AV p272)
5392 DIP("vsum2sws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5393 DIP(" => not implemented\n");
5394 return False;
5395
5396 case 0x788: // vsumsws (Sum SW Saturate, AV p271)
5397 DIP("vsumsws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5398 DIP(" => not implemented\n");
5399 return False;
5400
5401 default:
5402 vex_printf("dis_av_arith(PPC32)(opc2=0x%x)\n", opc2);
5403 return False;
5404 }
5405 return True;
5406}
5407
5408/*
5409 AltiVec Logic Instructions
5410*/
5411static Bool dis_av_logic ( UInt theInstr )
5412{
5413 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
5414 UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
5415 UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5416 UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
5417 UInt opc2 = (theInstr >> 0) & 0x7FF; /* theInstr[0:10] */
5418
cerion225a0342005-09-12 20:49:09 +00005419 IRTemp vA = newTemp(Ity_V128);
5420 IRTemp vB = newTemp(Ity_V128);
5421 assign( vA, getVReg(vA_addr));
5422 assign( vB, getVReg(vB_addr));
5423
cerion32aad402005-09-10 12:02:24 +00005424 if (opc1 != 0x4) {
5425 vex_printf("dis_av_logic(PPC32)(opc1 != 0x4)\n");
5426 return False;
5427 }
5428
5429 switch (opc2) {
5430 case 0x404: // vand (And, AV p147)
5431 DIP("vand v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion225a0342005-09-12 20:49:09 +00005432 putVReg( vD_addr, binop(Iop_AndV128, mkexpr(vA), mkexpr(vB)) );
5433 break;
cerion32aad402005-09-10 12:02:24 +00005434
5435 case 0x444: // vandc (And, AV p148)
5436 DIP("vandc v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion6e7a0ea2005-09-13 13:34:09 +00005437 putVReg( vD_addr, binop(Iop_AndV128, mkexpr(vA),
5438 unop(Iop_NotV128, mkexpr(vB))) );
5439 break;
cerion32aad402005-09-10 12:02:24 +00005440
5441 case 0x484: // vor (Or, AV p217)
5442 DIP("vor v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion225a0342005-09-12 20:49:09 +00005443 putVReg( vD_addr, binop(Iop_OrV128, mkexpr(vA), mkexpr(vB)) );
5444 break;
cerion32aad402005-09-10 12:02:24 +00005445
5446 case 0x4C4: // vxor (Xor, AV p282)
5447 DIP("vxor v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion225a0342005-09-12 20:49:09 +00005448 putVReg( vD_addr, binop(Iop_XorV128, mkexpr(vA), mkexpr(vB)) );
5449 break;
cerion32aad402005-09-10 12:02:24 +00005450
5451 case 0x504: // vnor (Nor, AV p216)
5452 DIP("vnor v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion6e7a0ea2005-09-13 13:34:09 +00005453 putVReg( vD_addr,
5454 unop(Iop_NotV128, binop(Iop_OrV128, mkexpr(vA), mkexpr(vB))) );
5455 break;
cerion32aad402005-09-10 12:02:24 +00005456
5457 default:
5458 vex_printf("dis_av_logic(PPC32)(opc2=0x%x)\n", opc2);
5459 return False;
5460 }
5461 return True;
5462}
5463
5464/*
5465 AltiVec Compare Instructions
5466*/
5467static Bool dis_av_cmp ( UInt theInstr )
5468{
5469 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
5470 UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
5471 UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5472 UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
5473 UChar flag_Rc = toUChar((theInstr >> 10) & 0x1); /* theInstr[10] */
5474 UInt opc2 = (theInstr >> 0) & 0x3FF; /* theInstr[0:9] */
5475
cerion0c439222005-09-15 14:22:58 +00005476 IRTemp vA = newTemp(Ity_V128);
5477 IRTemp vB = newTemp(Ity_V128);
5478 IRTemp vD = newTemp(Ity_V128);
5479 assign( vA, getVReg(vA_addr));
5480 assign( vB, getVReg(vB_addr));
5481
cerion32aad402005-09-10 12:02:24 +00005482 if (opc1 != 0x4) {
5483 vex_printf("dis_av_cmp(PPC32)(instr)\n");
5484 return False;
5485 }
5486
5487 switch (opc2) {
5488 case 0x006: // vcmpequb (Compare Equal-to Unsigned B, AV p160)
5489 DIP("vcmpequb%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
cerion0c439222005-09-15 14:22:58 +00005490 assign( vD, binop(Iop_CmpEQ8x16, mkexpr(vA), mkexpr(vB)) );
5491 break;
cerion32aad402005-09-10 12:02:24 +00005492
5493 case 0x046: // vcmpequh (Compare Equal-to Unsigned HW, AV p161)
5494 DIP("vcmpequh%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
cerion0c439222005-09-15 14:22:58 +00005495 assign( vD, binop(Iop_CmpEQ16x8, mkexpr(vA), mkexpr(vB)) );
5496 break;
cerion32aad402005-09-10 12:02:24 +00005497
5498 case 0x086: // vcmpequw (Compare Equal-to Unsigned W, AV p162)
5499 DIP("vcmpequw%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
cerion0c439222005-09-15 14:22:58 +00005500 assign( vD, binop(Iop_CmpEQ32x4, mkexpr(vA), mkexpr(vB)) );
5501 break;
cerion32aad402005-09-10 12:02:24 +00005502
5503 case 0x206: // vcmpgtub (Compare Greater-than Unsigned B, AV p168)
5504 DIP("vcmpgtub%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
cerion0c439222005-09-15 14:22:58 +00005505 assign( vD, binop(Iop_CmpGT8Ux16, mkexpr(vA), mkexpr(vB)) );
5506 break;
cerion32aad402005-09-10 12:02:24 +00005507
5508 case 0x246: // vcmpgtuh (Compare Greater-than Unsigned HW, AV p169)
5509 DIP("vcmpgtuh%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
cerion0c439222005-09-15 14:22:58 +00005510 assign( vD, binop(Iop_CmpGT16Ux8, mkexpr(vA), mkexpr(vB)) );
5511 break;
cerion32aad402005-09-10 12:02:24 +00005512
5513 case 0x286: // vcmpgtuw (Compare Greater-than Unsigned W, AV p170)
5514 DIP("vcmpgtuw%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
cerion0c439222005-09-15 14:22:58 +00005515 assign( vD, binop(Iop_CmpGT32Ux4, mkexpr(vA), mkexpr(vB)) );
5516 break;
cerion32aad402005-09-10 12:02:24 +00005517
5518 case 0x306: // vcmpgtsb (Compare Greater-than Signed B, AV p165)
5519 DIP("vcmpgtsb%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
cerion0c439222005-09-15 14:22:58 +00005520 assign( vD, binop(Iop_CmpGT8Sx16, mkexpr(vA), mkexpr(vB)) );
5521 break;
cerion32aad402005-09-10 12:02:24 +00005522
5523 case 0x346: // vcmpgtsh (Compare Greater-than Signed HW, AV p166)
5524 DIP("vcmpgtsh%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
cerion0c439222005-09-15 14:22:58 +00005525 assign( vD, binop(Iop_CmpGT16Sx8, mkexpr(vA), mkexpr(vB)) );
5526 break;
cerion32aad402005-09-10 12:02:24 +00005527
5528 case 0x386: // vcmpgtsw (Compare Greater-than Signed W, AV p167)
5529 DIP("vcmpgtsw%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
cerion0c439222005-09-15 14:22:58 +00005530 assign( vD, binop(Iop_CmpGT32Sx4, mkexpr(vA), mkexpr(vB)) );
5531 break;
cerion32aad402005-09-10 12:02:24 +00005532
5533 default:
5534 vex_printf("dis_av_cmp(PPC32)(opc2)\n");
5535 return False;
5536 }
cerion0c439222005-09-15 14:22:58 +00005537
5538 putVReg( vD_addr, mkexpr(vD) );
5539
5540 if (flag_Rc) {
5541 set_AV_CR6( mkexpr(vD) );
5542 }
cerion32aad402005-09-10 12:02:24 +00005543 return True;
5544}
5545
5546/*
5547 AltiVec Multiply-Sum Instructions
5548*/
5549static Bool dis_av_multarith ( UInt theInstr )
5550{
5551 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
5552 UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
5553 UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5554 UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
5555 UChar vC_addr = toUChar((theInstr >> 6) & 0x1F); /* theInstr[6:10] */
5556 UChar opc2 = toUChar((theInstr >> 0) & 0x3F); /* theInstr[0:5] */
5557
5558 if (opc1 != 0x4) {
5559 vex_printf("dis_av_multarith(PPC32)(instr)\n");
5560 return False;
5561 }
5562
5563 switch (opc2) {
5564
5565 /* Multiply-Add */
5566 case 0x20: // vmhaddshs (Multiply High, Add Signed HW Saturate, AV p185)
5567 DIP("vmhaddshs v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
5568 DIP(" => not implemented\n");
5569 return False;
5570
5571 case 0x21: // vmhraddshs (Multiply High Round, Add Signed HW Saturate, AV p186)
5572 DIP("vmhraddshs v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
5573 DIP(" => not implemented\n");
5574 return False;
5575
5576 case 0x22: // vmladduhm (Multiply Low, Add Unsigned HW Modulo, AV p194)
5577 DIP("vmladduhm v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
5578 DIP(" => not implemented\n");
5579 return False;
5580
5581
5582 /* Multiply-Sum */
5583 case 0x24: // vmsumubm (Multiply Sum Unsigned B Modulo, AV p204)
5584 DIP("vmsumubm v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
5585 DIP(" => not implemented\n");
5586 return False;
5587
5588 case 0x25: // vmsummbm (Multiply Sum Mixed-Sign B Modulo, AV p201)
5589 DIP("vmsummbm v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
5590 DIP(" => not implemented\n");
5591 return False;
5592
5593 case 0x26: // vmsumuhm (Multiply Sum Unsigned HW Modulo, AV p205)
5594 DIP("vmsumuhm v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
5595 DIP(" => not implemented\n");
5596 return False;
5597
5598 case 0x27: // vmsumuhs (Multiply Sum Unsigned HW Saturate, AV p206)
5599 DIP("vmsumuhs v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
5600 DIP(" => not implemented\n");
5601 return False;
5602
5603 case 0x28: // vmsumshm (Multiply Sum Signed HW Modulo, AV p202)
5604 DIP("vmsumshm v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
5605 DIP(" => not implemented\n");
5606 return False;
5607
5608 case 0x29: // vmsumshs (Multiply Sum Signed HW Saturate, AV p203)
5609 DIP("vmsumshs v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
5610 DIP(" => not implemented\n");
5611 return False;
5612
5613 default:
5614 vex_printf("dis_av_multarith(PPC32)(opc2)\n");
5615 return False;
5616 }
5617 return True;
5618}
5619
5620/*
5621 AltiVec Shift/Rotate Instructions
5622*/
5623static Bool dis_av_shift ( UInt theInstr )
5624{
5625 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
5626 UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
5627 UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5628 UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
5629 UInt opc2 = (theInstr >> 0) & 0x7FF; /* theInstr[0:10] */
5630
cerion27b3d7e2005-09-14 20:35:47 +00005631 IRTemp vA = newTemp(Ity_V128);
5632 IRTemp vB = newTemp(Ity_V128);
5633 assign( vA, getVReg(vA_addr));
5634 assign( vB, getVReg(vB_addr));
5635
cerion32aad402005-09-10 12:02:24 +00005636 if (opc1 != 0x4){
5637 vex_printf("dis_av_shift(PPC32)(instr)\n");
5638 return False;
5639 }
5640
5641 switch (opc2) {
5642 /* Rotate */
5643 case 0x004: // vrlb (Rotate Left Integer B, AV p234)
5644 DIP("vrlb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5645 DIP(" => not implemented\n");
5646 return False;
5647
5648 case 0x044: // vrlh (Rotate Left Integer HW, AV p235)
5649 DIP("vrlh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5650 DIP(" => not implemented\n");
5651 return False;
5652
5653 case 0x084: // vrlw (Rotate Left Integer W, AV p236)
5654 DIP("vrlw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5655 DIP(" => not implemented\n");
5656 return False;
5657
5658
5659 /* Shift Left */
5660 case 0x104: // vslb (Shift Left Integer B, AV p240)
5661 DIP("vslb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5662 DIP(" => not implemented\n");
5663 return False;
5664
5665 case 0x144: // vslh (Shift Left Integer HW, AV p242)
5666 DIP("vslh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5667 DIP(" => not implemented\n");
5668 return False;
5669
5670 case 0x184: // vslw (Shift Left Integer W, AV p244)
5671 DIP("vslw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5672 DIP(" => not implemented\n");
5673 return False;
5674
5675 case 0x1C4: // vsl (Shift Left, AV p239)
5676 DIP("vsl v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5677 DIP(" => not implemented\n");
5678 return False;
5679
5680 case 0x40C: // vslo (Shift Left by Octet, AV p243)
5681 DIP("vslo v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5682 DIP(" => not implemented\n");
5683 return False;
5684
5685 /* Shift Right */
5686 case 0x204: // vsrb (Shift Right B, AV p256)
5687 DIP("vsrb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5688 DIP(" => not implemented\n");
5689 return False;
5690
5691 case 0x244: // vsrh (Shift Right HW, AV p257)
5692 DIP("vsrh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5693 DIP(" => not implemented\n");
5694 return False;
5695
5696 case 0x284: // vsrw (Shift Right W, AV p259)
5697 DIP("vsrw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5698 DIP(" => not implemented\n");
5699 return False;
5700
cerion27b3d7e2005-09-14 20:35:47 +00005701 case 0x2C4: { // vsr (Shift Right, AV p251)
cerion32aad402005-09-10 12:02:24 +00005702 DIP("vsr v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
cerion27b3d7e2005-09-14 20:35:47 +00005703 IRTemp sh = newTemp(Ity_I8);
5704 assign( sh, binop(Iop_And8, mkU8(0x7),
5705 unop(Iop_32to8,
5706 unop(Iop_V128to32, mkexpr(vB)))) );
5707 putVReg( vD_addr,
5708 binop(Iop_ShrV128, mkexpr(vA), mkexpr(sh)) );
5709 break;
5710 }
cerion32aad402005-09-10 12:02:24 +00005711 case 0x304: // vsrab (Shift Right Algebraic B, AV p253)
5712 DIP("vsrab v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5713 DIP(" => not implemented\n");
5714 return False;
5715
5716 case 0x344: // vsrah (Shift Right Algebraic HW, AV p254)
5717 DIP("vsrah v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5718 DIP(" => not implemented\n");
5719 return False;
5720
5721 case 0x384: // vsraw (Shift Right Algebraic W, AV p255)
5722 DIP("vsraw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5723 DIP(" => not implemented\n");
5724 return False;
5725
5726 case 0x44C: // vsro (Shift Right by Octet, AV p258)
5727 DIP("vsro v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5728 DIP(" => not implemented\n");
5729 return False;
5730
5731 default:
5732 vex_printf("dis_av_shift(PPC32)(opc2)\n");
5733 return False;
5734 }
5735 return True;
5736}
5737
5738/*
5739 AltiVec Permute Instructions
5740*/
5741static Bool dis_av_permute ( UInt theInstr )
5742{
5743 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
5744 UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
5745 UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5746 UChar UIMM_5 = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5747 UChar SIMM_5 = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5748 UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
5749 UChar vC_addr = toUChar((theInstr >> 6) & 0x1F); /* theInstr[6:10] */
5750 UChar b10 = toUChar((theInstr >> 10) & 0x1); /* theInstr[10] */
5751 UChar SHB_uimm4 = toUChar((theInstr >> 6) & 0xF); /* theInstr[6:9] */
5752 UInt opc2 = (theInstr >> 0) & 0x3F; /* theInstr[0:5] */
5753
5754 UChar SIMM_8 = extend_s_5to8(SIMM_5);
5755
cerion6e7a0ea2005-09-13 13:34:09 +00005756 IRTemp vA = newTemp(Ity_V128);
5757 IRTemp vB = newTemp(Ity_V128);
5758 IRTemp vC = newTemp(Ity_V128);
5759 assign( vA, getVReg(vA_addr));
5760 assign( vB, getVReg(vB_addr));
5761 assign( vC, getVReg(vC_addr));
5762
cerion32aad402005-09-10 12:02:24 +00005763 if (opc1 != 0x4) {
5764 vex_printf("dis_av_permute(PPC32)(instr)\n");
5765 return False;
5766 }
5767
5768 switch (opc2) {
5769 case 0x2A: // vsel (Conditional Select, AV p238)
5770 DIP("vsel v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
cerion6e7a0ea2005-09-13 13:34:09 +00005771 /* vD = (vA & ~vC) | (vB & vC) */
5772 putVReg( vD_addr, binop(Iop_OrV128,
5773 binop(Iop_AndV128, mkexpr(vA), unop(Iop_NotV128, mkexpr(vC))),
5774 binop(Iop_AndV128, mkexpr(vB), mkexpr(vC))) );
5775 return True;
cerion32aad402005-09-10 12:02:24 +00005776
5777 case 0x2B: // vperm (Permute, AV p218)
5778 DIP("vperm v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
5779 DIP(" => not implemented\n");
5780 return False;
5781
5782 case 0x2C: // vsldoi (Shift Left Double by Octet Imm, AV p241)
5783 if (b10 != 0) {
5784 vex_printf("dis_av_permute(PPC32)(vsldoi)\n");
5785 return False;
5786 }
5787 DIP("vsldoi v%d,v%d,v%d,%d\n", vD_addr, vA_addr, vB_addr, SHB_uimm4);
5788 DIP(" => not implemented\n");
5789 return False;
5790
5791 default:
5792 break; // Fall through...
5793 }
5794
5795 opc2 = (theInstr) & 0x7FF; /* theInstr[0:10] */
5796 switch (opc2) {
5797
5798 /* Merge */
5799 case 0x00C: // vmrghb (Merge High B, AV p195)
5800 DIP("vmrghb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5801 DIP(" => not implemented\n");
5802 return False;
5803
5804 case 0x04C: // vmrghh (Merge High HW, AV p196)
5805 DIP("vmrghh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5806 DIP(" => not implemented\n");
5807 return False;
5808
5809 case 0x08C: // vmrghw (Merge High W, AV p197)
5810 DIP("vmrghw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5811 DIP(" => not implemented\n");
5812 return False;
5813
5814 case 0x10C: // vmrglb (Merge Low B, AV p198)
5815 DIP("vmrglb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5816 DIP(" => not implemented\n");
5817 return False;
5818
5819 case 0x14C: // vmrglh (Merge Low HW, AV p199)
5820 DIP("vmrglh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5821 DIP(" => not implemented\n");
5822 return False;
5823
5824 case 0x18C: // vmrglw (Merge Low W, AV p200)
5825 DIP("vmrglw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5826 DIP(" => not implemented\n");
5827 return False;
5828
5829 /* Splat */
5830 case 0x20C: // vspltb (Splat Byte, AV p245)
5831 DIP("vspltb v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
5832 DIP(" => not implemented\n");
5833 return False;
5834
5835 case 0x24C: // vsplth (Splat Half Word, AV p246)
5836 DIP("vsplth v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
5837 DIP(" => not implemented\n");
5838 return False;
5839
cerion27b3d7e2005-09-14 20:35:47 +00005840 case 0x28C: { // vspltw (Splat Word, AV p250)
cerion32aad402005-09-10 12:02:24 +00005841 DIP("vspltw v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
cerion27b3d7e2005-09-14 20:35:47 +00005842 /* vD = Dup32x4( vB[UIMM_5] ) */
5843 unsigned int sh_uimm = (3-UIMM_5)*32;
5844 putVReg( vD_addr, unop(Iop_Dup32x4,
5845 unop(Iop_V128to32,
5846 binop(Iop_ShrV128, mkexpr(vB), mkU8(sh_uimm)))) );
5847 break;
5848 }
cerion32aad402005-09-10 12:02:24 +00005849 case 0x30C: // vspltisb (Splat Immediate Signed B, AV p247)
5850 DIP("vspltisb v%d,%d\n", vD_addr, (Char)SIMM_8);
5851 DIP(" => not implemented\n");
5852 return False;
5853
5854 case 0x34C: // vspltish (Splat Immediate Signed HW, AV p248)
5855 DIP("vspltish v%d,%d\n", vD_addr, (Char)SIMM_8);
5856 DIP(" => not implemented\n");
5857 return False;
5858
5859 case 0x38C: // vspltisw (Splat Immediate Signed W, AV p249)
5860 DIP("vspltisw v%d,%d\n", vD_addr, (Char)SIMM_8);
5861 DIP(" => not implemented\n");
5862 return False;
5863
5864 default:
5865 vex_printf("dis_av_permute(PPC32)(opc2)\n");
5866 return False;
5867 }
5868 return True;
5869}
5870
5871/*
5872 AltiVec Pack/Unpack Instructions
5873*/
5874static Bool dis_av_pack ( UInt theInstr )
5875{
5876 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
5877 UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
5878 UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5879 UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
5880 UInt opc2 = (theInstr >> 0) & 0x7FF; /* theInstr[0:10] */
5881
5882 if (opc1 != 0x4) {
5883 vex_printf("dis_av_pack(PPC32)(instr)\n");
5884 return False;
5885 }
5886
5887 switch (opc2) {
5888 /* Packing */
5889 case 0x00E: // vpkuhum (Pack Unsigned HW Unsigned Modulo, AV p224)
5890 DIP("vpkuhum v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5891 DIP(" => not implemented\n");
5892 return False;
5893
5894 case 0x04E: // vpkuwum (Pack Unsigned W Unsigned Modulo, AV p226)
5895 DIP("vpkuwum v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5896 DIP(" => not implemented\n");
5897 return False;
5898
5899 case 0x08E: // vpkuhus (Pack Unsigned HW Unsigned Saturate, AV p225)
5900 DIP("vpkuhus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5901 DIP(" => not implemented\n");
5902 return False;
5903
5904 case 0x0CE: // vpkuwus (Pack Unsigned W Unsigned Saturate, AV p227)
5905 DIP("vpkuwus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5906 DIP(" => not implemented\n");
5907 return False;
5908
5909 case 0x10E: // vpkshus (Pack Signed HW Unsigned Saturate, AV p221)
5910 DIP("vpkshus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5911 DIP(" => not implemented\n");
5912 return False;
5913
5914 case 0x14E: // vpkswus (Pack Signed W Unsigned Saturate, AV p223)
5915 DIP("vpkswus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5916 DIP(" => not implemented\n");
5917 return False;
5918
5919 case 0x18E: // vpkshss (Pack Signed HW Signed Saturate, AV p220)
5920 DIP("vpkshss v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5921 DIP(" => not implemented\n");
5922 return False;
5923
5924 case 0x1CE: // vpkswss (Pack Signed W Signed Saturate, AV p222)
5925 DIP("vpkswss v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5926 DIP(" => not implemented\n");
5927 return False;
5928
5929 case 0x30E: // vpkpx (Pack Pixel, AV p219)
5930 DIP("vpkpx v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5931 DIP(" => not implemented\n");
5932 return False;
5933
5934 default:
5935 break; // Fall through...
5936 }
5937
5938
5939 if (vA_addr != 0) {
5940 vex_printf("dis_av_pack(PPC32)(vA_addr)\n");
5941 return False;
5942 }
5943
5944 switch (opc2) {
5945 /* Unpacking */
5946 case 0x20E: // vupkhsb (Unpack High Signed B, AV p277)
5947 DIP("vupkhsb v%d,v%d\n", vD_addr, vB_addr);
5948 DIP(" => not implemented\n");
5949 return False;
5950
5951 case 0x24E: // vupkhsh (Unpack High Signed HW, AV p278)
5952 DIP("vupkhsh v%d,v%d\n", vD_addr, vB_addr);
5953 DIP(" => not implemented\n");
5954 return False;
5955
5956 case 0x28E: // vupklsb (Unpack Low Signed B, AV p280)
5957 DIP("vupklsb v%d,v%d\n", vD_addr, vB_addr);
5958 DIP(" => not implemented\n");
5959 return False;
5960
5961 case 0x2CE: // vupklsh (Unpack Low Signed HW, AV p281)
5962 DIP("vupklsh v%d,v%d\n", vD_addr, vB_addr);
5963 DIP(" => not implemented\n");
5964 return False;
5965
5966 case 0x34E: // vupkhpx (Unpack High Pixel16, AV p276)
5967 DIP("vupkhpx v%d,v%d\n", vD_addr, vB_addr);
5968 DIP(" => not implemented\n");
5969 return False;
5970
5971 case 0x3CE: // vupklpx (Unpack Low Pixel16, AV p279)
5972 DIP("vupklpx v%d,v%d\n", vD_addr, vB_addr);
5973 DIP(" => not implemented\n");
5974 return False;
5975
5976 default:
5977 vex_printf("dis_av_pack(PPC32)(opc2)\n");
5978 return False;
5979 }
5980 return True;
5981}
5982
5983
5984/*
5985 AltiVec Floating Point Arithmetic Instructions
5986*/
5987static Bool dis_av_fp_arith ( UInt theInstr )
5988{
5989 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
5990 UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
5991 UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5992 UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
5993 UChar vC_addr = toUChar((theInstr >> 6) & 0x1F); /* theInstr[6:10] */
5994 UInt opc2=0;
5995
5996 if (opc1 != 0x4) {
5997 vex_printf("dis_av_fp_arith(PPC32)(instr)\n");
5998 return False;
5999 }
6000
6001 opc2 = (theInstr) & 0x3F; /* theInstr[0:5] */
6002 switch (opc2) {
6003 case 0x2E: // vmaddfp (Multiply Add FP, AV p177)
6004 DIP("vmaddfp v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vC_addr, vB_addr);
6005 DIP(" => not implemented\n");
6006 return False;
6007
6008 case 0x2F: // vnmsubfp (Negative Multiply-Subtract FP, AV p215)
6009 DIP("vnmsubfp v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vC_addr, vB_addr);
6010 DIP(" => not implemented\n");
6011 return False;
6012
6013 default:
6014 break; // Fall through...
6015 }
6016
6017 opc2 = (theInstr) & 0x7FF; /* theInstr[0:10] */
6018 switch (opc2) {
6019 case 0x00A: // vaddfp (Add FP, AV p137)
6020 DIP("vaddfp v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
6021 DIP(" => not implemented\n");
6022 return False;
6023
6024 case 0x04A: // vsubfp (Subtract FP, AV p261)
6025 DIP("vsubfp v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
6026 DIP(" => not implemented\n");
6027 return False;
6028
6029 case 0x40A: // vmaxfp (Maximum FP, AV p178)
6030 DIP("vmaxfp v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
6031 DIP(" => not implemented\n");
6032 return False;
6033
6034 case 0x44A: // vminfp (Minimum FP, AV p187)
6035 DIP("vminfp v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
6036 DIP(" => not implemented\n");
6037 return False;
6038
6039 default:
6040 break; // Fall through...
6041 }
6042
6043
6044 if (vA_addr != 0) {
6045 vex_printf("dis_av_fp_arith(PPC32)(vA_addr)\n");
6046 return False;
6047 }
6048
6049 switch (opc2) {
6050 case 0x10A: // vrefp (Reciprocal Esimate FP, AV p228)
6051 DIP("vrefp v%d,v%d\n", vD_addr, vB_addr);
6052 DIP(" => not implemented\n");
6053 return False;
6054
6055 case 0x14A: // vrsqrtefp (Reciprocal Square Root Estimate FP, AV p237)
6056 DIP("vrsqrtefp v%d,v%d\n", vD_addr, vB_addr);
6057 DIP(" => not implemented\n");
6058 return False;
6059
6060 case 0x18A: // vexptefp (2 Raised to the Exp Est FP, AV p173)
6061 DIP("vexptefp v%d,v%d\n", vD_addr, vB_addr);
6062 DIP(" => not implemented\n");
6063 return False;
6064
6065 case 0x1CA: // vlogefp (Log2 Estimate FP, AV p175)
6066 DIP("vlogefp v%d,v%d\n", vD_addr, vB_addr);
6067 DIP(" => not implemented\n");
6068 return False;
6069
6070 default:
6071 vex_printf("dis_av_fp_arith(PPC32)(opc2=0x%x)\n",opc2);
6072 return False;
6073 }
6074 return True;
6075}
6076
6077/*
6078 AltiVec Floating Point Compare Instructions
6079*/
6080static Bool dis_av_fp_cmp ( UInt theInstr )
6081{
6082 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
6083 UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
6084 UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
6085 UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
6086 UChar flag_Rc = toUChar((theInstr >> 10) & 0x1); /* theInstr[10] */
6087 UInt opc2 = (theInstr >> 0) & 0x3FF; /* theInstr[0:9] */
6088
6089 if (opc1 != 0x4) {
6090 vex_printf("dis_av_fp_cmp(PPC32)(instr)\n");
6091 return False;
6092 }
6093
6094 switch (opc2) {
6095 case 0x0C6: // vcmpeqfp (Compare Equal-to FP, AV p159)
6096 DIP("vcmpeqfp%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
6097 DIP(" => not implemented\n");
6098 return False;
6099
6100 case 0x1C6: // vcmpgefp (Compare Greater-than-or-Equal-to FP, AV p163)
6101 DIP("vcmpgefp%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
6102 DIP(" => not implemented\n");
6103 return False;
6104
6105 case 0x2C6: // vcmpgtfp (Compare Greater-than FP, AV p164)
6106 DIP("vcmpgtfp%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
6107 DIP(" => not implemented\n");
6108 return False;
6109
6110 case 0x3C6: // vcmpbfp (Compare Bounds FP, AV p157)
6111 DIP("vcmpbfp%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
6112 DIP(" => not implemented\n");
6113 return False;
6114
6115 default:
6116 vex_printf("dis_av_fp_cmp(PPC32)(opc2)\n");
6117 return False;
6118 }
6119 return True;
6120}
6121
6122/*
6123 AltiVec Floating Point Convert/Round Instructions
6124*/
6125static Bool dis_av_fp_convert ( UInt theInstr )
6126{
6127 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
6128 UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
6129 UChar UIMM_5 = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
6130 UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
6131 UInt opc2 = (theInstr >> 0) & 0x7FF; /* theInstr[0:10] */
6132
6133 if (opc1 != 0x4) {
6134 vex_printf("dis_av_fp_convert(PPC32)(instr)\n");
6135 return False;
6136 }
6137
6138 switch (opc2) {
6139 case 0x30A: // vcfux (Convert from Unsigned Fixed-Point W, AV p156)
6140 DIP("vcfux v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
6141 DIP(" => not implemented\n");
6142 return False;
6143
6144 case 0x34A: // vcfsx (Convert from Signed Fixed-Point W, AV p155)
6145 DIP("vcfsx v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
6146 DIP(" => not implemented\n");
6147 return False;
6148
6149 case 0x38A: // vctuxs (Convert to Unsigned Fixed-Point W Saturate, AV p172)
6150 DIP("vctuxs v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
6151 DIP(" => not implemented\n");
6152 return False;
6153
6154 case 0x3CA: // vctsxs (Convert to Signed Fixed-Point W Saturate, AV p171)
6155 DIP("vctsxs v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
6156 DIP(" => not implemented\n");
6157 return False;
6158
6159 default:
6160 break; // Fall through...
6161 }
6162
6163 if (UIMM_5 != 0) {
6164 vex_printf("dis_av_fp_convert(PPC32)(UIMM_5)\n");
6165 return False;
6166 }
6167
6168 switch (opc2) {
6169 case 0x20A: // vrfin (Round to FP Integer Nearest, AV p231)
6170 DIP("vrfin v%d,v%d\n", vD_addr, vB_addr);
6171 DIP(" => not implemented\n");
6172 return False;
6173
6174 case 0x24A: // vrfiz (Round to FP Integer toward zero, AV p233)
6175 DIP("vrfiz v%d,v%d\n", vD_addr, vB_addr);
6176 DIP(" => not implemented\n");
6177 return False;
6178
6179 case 0x28A: // vrfip (Round to FP Integer toward +inf, AV p232)
6180 DIP("vrfip v%d,v%d\n", vD_addr, vB_addr);
6181 DIP(" => not implemented\n");
6182 return False;
6183
6184 case 0x2CA: // vrfim (Round to FP Integer toward -inf, AV p230)
6185 DIP("vrfim v%d,v%d\n", vD_addr, vB_addr);
6186 DIP(" => not implemented\n");
6187 return False;
6188
6189 default:
6190 vex_printf("dis_av_fp_convert(PPC32)(opc2)\n");
6191 return False;
6192 }
6193 return True;
6194}
cerion3d870a32005-03-18 12:23:33 +00006195
6196
cerion91ad5362005-01-27 23:02:41 +00006197
6198
6199
6200
cerion896a1372005-01-25 12:24:25 +00006201/*------------------------------------------------------------*/
6202/*--- Disassemble a single instruction ---*/
6203/*------------------------------------------------------------*/
6204
6205/* Disassemble a single instruction into IR. The instruction
sewardj9e6491a2005-07-02 19:24:10 +00006206 is located in host memory at &guest_code[delta]. */
6207
6208static
6209DisResult disInstr_PPC32_WRK (
6210 Bool put_IP,
6211 Bool (*resteerOkFn) ( Addr64 ),
6212 Long delta64,
6213 VexArchInfo* archinfo
6214 )
cerion896a1372005-01-25 12:24:25 +00006215{
sewardj9e6491a2005-07-02 19:24:10 +00006216 UChar opc1;
6217 UInt opc2;
6218 DisResult dres;
cerion896a1372005-01-25 12:24:25 +00006219 UInt theInstr;
6220
sewardj9e6491a2005-07-02 19:24:10 +00006221 /* The running delta */
6222 Int delta = (Int)delta64;
6223
6224 /* Set result defaults. */
6225 dres.whatNext = Dis_Continue;
6226 dres.len = 0;
6227 dres.continueAt = 0;
cerion896a1372005-01-25 12:24:25 +00006228
cerion1515db92005-01-25 17:21:23 +00006229 /* At least this is simple on PPC32: insns are all 4 bytes long, and
cerion896a1372005-01-25 12:24:25 +00006230 4-aligned. So just fish the whole thing out of memory right now
6231 and have done. */
cerioncf004462005-01-31 15:24:55 +00006232 theInstr = getUIntBigendianly( (UChar*)(&guest_code[delta]) );
cerion896a1372005-01-25 12:24:25 +00006233
sewardjb51f0f42005-07-18 11:38:02 +00006234 DIP("\t0x%x: ", guest_CIA_curr_instr);
6235
6236 /* We may be asked to update the guest CIA before going further. */
6237 if (put_IP)
6238 putSPR( PPC32_SPR_CIA, mkU32(guest_CIA_curr_instr) );
cerion896a1372005-01-25 12:24:25 +00006239
cerion896a1372005-01-25 12:24:25 +00006240 /* Spot the client-request magic sequence. */
6241 // Essentially a v. unlikely sequence of noops that we can catch
6242 {
sewardj2f52de42005-07-03 01:51:29 +00006243 UChar* code = (UChar*)(&guest_code[delta]);
cerion896a1372005-01-25 12:24:25 +00006244
6245 /* Spot this:
sewardj2f52de42005-07-03 01:51:29 +00006246 0x7C03D808 tw 0,3,27 => trap word if (0) => nop
cerionb85e8bb2005-02-16 08:54:33 +00006247 0x5400E800 rlwinm 0,0,29,0,0 => r0 = rotl(r0,29)
6248 0x54001800 rlwinm 0,0,3,0,0 => r0 = rotl(r0,3)
6249 0x54006800 rlwinm 0,0,13,0,0 => r0 = rotl(r0,13)
6250 0x54009800 rlwinm 0,0,19,0,0 => r0 = rotl(r0,19)
cerion0fe6b7e2005-06-20 16:28:32 +00006251 0x60000000 nop
cerion896a1372005-01-25 12:24:25 +00006252 */
sewardj2f52de42005-07-03 01:51:29 +00006253 if (getUIntBigendianly(code+ 0) == 0x7C03D808 &&
6254 getUIntBigendianly(code+ 4) == 0x5400E800 &&
6255 getUIntBigendianly(code+ 8) == 0x54001800 &&
6256 getUIntBigendianly(code+12) == 0x54006800 &&
6257 getUIntBigendianly(code+16) == 0x54009800 &&
6258 getUIntBigendianly(code+20) == 0x60000000) {
cerion84ad6162005-06-23 15:25:57 +00006259 DIP("%%r3 = client_request ( %%r31 )\n");
sewardj9e6491a2005-07-02 19:24:10 +00006260 dres.len = 24;
cerioned623db2005-06-20 12:42:04 +00006261 delta += 24;
6262
sewardj9e6491a2005-07-02 19:24:10 +00006263 irbb->next = mkU32(guest_CIA_bbstart+delta);
cerionb85e8bb2005-02-16 08:54:33 +00006264 irbb->jumpkind = Ijk_ClientReq;
sewardj9e6491a2005-07-02 19:24:10 +00006265 dres.whatNext = Dis_StopHere;
cerion896a1372005-01-25 12:24:25 +00006266 goto decode_success;
6267 }
6268 }
6269
6270
sewardjc7cd2142005-09-09 22:31:49 +00006271 opc1 = toUChar(ifieldOPC(theInstr));
sewardjb51f0f42005-07-18 11:38:02 +00006272 opc2 = ifieldOPClo10(theInstr);
cerion932ad942005-01-30 10:18:50 +00006273
cerion225a0342005-09-12 20:49:09 +00006274#if 0 //PPC32_TOIR_DEBUG
cerion45552a92005-02-03 18:20:22 +00006275 vex_printf("\ndisInstr(ppc32): instr: 0x%x\n", theInstr);
6276 vex_printf("disInstr(ppc32): instr: ");
6277 vex_printf_binary( theInstr, 32, True );
6278 vex_printf("\n");
cerion45552a92005-02-03 18:20:22 +00006279#endif
cerione9d361a2005-03-04 17:35:29 +00006280
cerion45552a92005-02-03 18:20:22 +00006281
cerion91ad5362005-01-27 23:02:41 +00006282 // Note: all 'reserved' bits must be cleared, else invalid
6283 switch (opc1) {
cerion896a1372005-01-25 12:24:25 +00006284
cerione9d361a2005-03-04 17:35:29 +00006285 /* Integer Arithmetic Instructions */
6286 case 0x0C: case 0x0D: case 0x0E: // addic, addic., addi
6287 case 0x0F: case 0x07: case 0x08: // addis, mulli, subfic
6288 if (dis_int_arith( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006289 goto decode_failure;
cerion7aa4bbc2005-01-29 09:32:07 +00006290
cerione9d361a2005-03-04 17:35:29 +00006291 /* Integer Compare Instructions */
6292 case 0x0B: case 0x0A: // cmpi, cmpli
6293 if (dis_int_cmp( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006294 goto decode_failure;
cerion7aa4bbc2005-01-29 09:32:07 +00006295
cerione9d361a2005-03-04 17:35:29 +00006296 /* Integer Logical Instructions */
6297 case 0x1C: case 0x1D: case 0x18: // andi., andis., ori
6298 case 0x19: case 0x1A: case 0x1B: // oris, xori, xoris
6299 if (dis_int_logic( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006300 goto decode_failure;
cerion7aa4bbc2005-01-29 09:32:07 +00006301
cerione9d361a2005-03-04 17:35:29 +00006302 /* Integer Rotate Instructions */
6303 case 0x14: case 0x15: case 0x17: // rlwimi, rlwinm, rlwnm
6304 if (dis_int_rot( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006305 goto decode_failure;
cerion645c9302005-01-31 10:09:59 +00006306
cerione9d361a2005-03-04 17:35:29 +00006307 /* Integer Load Instructions */
6308 case 0x22: case 0x23: case 0x2A: // lbz, lbzu, lha
6309 case 0x2B: case 0x28: case 0x29: // lhau, lhz, lhzu
6310 case 0x20: case 0x21: // lwz, lwzu
6311 if (dis_int_load( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006312 goto decode_failure;
cerion645c9302005-01-31 10:09:59 +00006313
cerione9d361a2005-03-04 17:35:29 +00006314 /* Integer Store Instructions */
6315 case 0x26: case 0x27: case 0x2C: // stb, stbu, sth
6316 case 0x2D: case 0x24: case 0x25: // sthu, stw, stwu
6317 if (dis_int_store( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006318 goto decode_failure;
ceriond23be4e2005-01-31 07:23:07 +00006319
sewardj7787af42005-08-04 18:32:19 +00006320 /* Integer Load and Store Multiple Instructions */
6321 case 0x2E: case 0x2F: // lmw, stmw
6322 if (dis_int_ldst_mult( theInstr )) goto decode_success;
6323 goto decode_failure;
cerion645c9302005-01-31 10:09:59 +00006324
cerione9d361a2005-03-04 17:35:29 +00006325 /* Branch Instructions */
6326 case 0x12: case 0x10: // b, bc
sewardj9e6491a2005-07-02 19:24:10 +00006327 if (dis_branch(theInstr, &dres)) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006328 goto decode_failure;
cerion896a1372005-01-25 12:24:25 +00006329
cerione9d361a2005-03-04 17:35:29 +00006330 /* System Linkage Instructions */
cerion8c3adda2005-01-31 11:54:05 +00006331 case 0x11: // sc
sewardj9e6491a2005-07-02 19:24:10 +00006332 if (dis_syslink(theInstr, &dres)) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006333 goto decode_failure;
cerion26d07b22005-02-02 17:13:28 +00006334
sewardjb51f0f42005-07-18 11:38:02 +00006335//zz /* Trap Instructions */
6336//zz case 0x03: // twi
6337//zz DIP("trap op (twi) => not implemented\n");
6338//zz goto decode_failure;
cerion8c3adda2005-01-31 11:54:05 +00006339
cerion3d870a32005-03-18 12:23:33 +00006340 /* Floating Point Load Instructions */
cerion094d1392005-06-20 13:45:57 +00006341 case 0x30: case 0x31: case 0x32: // lfs, lfsu, lfd
6342 case 0x33: // lfdu
cerion3d870a32005-03-18 12:23:33 +00006343 if (dis_fp_load( theInstr )) goto decode_success;
cerione9d361a2005-03-04 17:35:29 +00006344 goto decode_failure;
cerion995bc362005-02-03 11:03:31 +00006345
cerion3d870a32005-03-18 12:23:33 +00006346 /* Floating Point Store Instructions */
6347 case 0x34: case 0x35: case 0x36: // stfsx, stfsux, stfdx
6348 case 0x37: // stfdux
6349 if (dis_fp_store( theInstr )) goto decode_success;
6350 goto decode_failure;
6351
sewardje14bb9f2005-07-22 09:39:02 +00006352 case 0x3B:
6353 opc2 = (theInstr >> 1) & 0x1F; /* theInstr[1:5] */
6354 switch (opc2) {
6355 /* Floating Point Arith Instructions */
6356 case 0x12: case 0x14: case 0x15: // fdivs, fsubs, fadds
6357 case 0x16: case 0x18: case 0x19: // fsqrts, fres, fmuls
6358 if (dis_fp_arith(theInstr)) goto decode_success;
6359 goto decode_failure;
6360
6361 /* Floating Point Mult-Add Instructions */
6362 case 0x1C: case 0x1D: case 0x1E: // fmsubs, fmadds, fnmsubs
6363 case 0x1F: // fnmadds
6364 if (dis_fp_multadd(theInstr)) goto decode_success;
6365 goto decode_failure;
6366
6367 default:
6368 goto decode_failure;
6369 }
6370 break;
cerion3d870a32005-03-18 12:23:33 +00006371
6372 case 0x3F:
6373 /* Instrs using opc[1:5] never overlap with instrs using opc[1:10],
6374 so we can simply fall through the first switch statement */
6375
6376 opc2 = (theInstr >> 1) & 0x1F; /* theInstr[1:5] */
6377 switch (opc2) {
sewardjb51f0f42005-07-18 11:38:02 +00006378 /* Floating Point Arith Instructions */
6379 case 0x12: case 0x14: case 0x15: // fdiv, fsub, fadd
6380 case 0x16: case 0x17: case 0x19: // fsqrt, fsel, fmul
6381 case 0x1A: // frsqrte
6382 if (dis_fp_arith(theInstr)) goto decode_success;
6383 goto decode_failure;
cerion3d870a32005-03-18 12:23:33 +00006384
sewardje14bb9f2005-07-22 09:39:02 +00006385 /* Floating Point Mult-Add Instructions */
6386 case 0x1C: case 0x1D: case 0x1E: // fmsub, fmadd, fnmsub
6387 case 0x1F: // fnmadd
6388 if (dis_fp_multadd(theInstr)) goto decode_success;
6389 goto decode_failure;
6390
sewardjb51f0f42005-07-18 11:38:02 +00006391 default:
6392 break; // Fall through
cerion3d870a32005-03-18 12:23:33 +00006393 }
6394
sewardje14bb9f2005-07-22 09:39:02 +00006395 opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
6396 switch (opc2) {
6397 /* Floating Point Compare Instructions */
6398 case 0x000: // fcmpu
6399 case 0x020: // fcmpo
6400 if (dis_fp_cmp(theInstr)) goto decode_success;
6401 goto decode_failure;
6402
6403 /* Floating Point Rounding/Conversion Instructions */
6404 case 0x00C: // frsp
6405 case 0x00E: // fctiw
6406 case 0x00F: // fctiwz
6407 if (dis_fp_round(theInstr)) goto decode_success;
6408 goto decode_failure;
6409
6410 /* Floating Point Move Instructions */
6411 case 0x028: // fneg
6412 case 0x048: // fmr
6413 case 0x088: // fnabs
6414 case 0x108: // fabs
6415 if (dis_fp_move( theInstr )) goto decode_success;
6416 goto decode_failure;
6417
sewardjb51f0f42005-07-18 11:38:02 +00006418//zz /* Floating Point Status/Control Register Instructions */
6419//zz case 0x026: // mtfsb1
6420//zz case 0x040: // mcrfs
sewardje14bb9f2005-07-22 09:39:02 +00006421 case 0x046: // mtfsb0
6422 case 0x086: // mtfsfi
6423 case 0x247: // mffs
6424 case 0x2C7: // mtfsf
6425 if (dis_fp_scr( theInstr )) goto decode_success;
6426 goto decode_failure;
6427 default:
6428 goto decode_failure;
6429 }
cerion3d870a32005-03-18 12:23:33 +00006430 break;
cerion91ad5362005-01-27 23:02:41 +00006431
6432 case 0x13:
cerionb85e8bb2005-02-16 08:54:33 +00006433 switch (opc2) {
cerion91ad5362005-01-27 23:02:41 +00006434
sewardjb51f0f42005-07-18 11:38:02 +00006435 /* Condition Register Logical Instructions */
6436 case 0x101: case 0x081: case 0x121: // crand, crandc, creqv
6437 case 0x0E1: case 0x021: case 0x1C1: // crnand, crnor, cror
6438 case 0x1A1: case 0x0C1: case 0x000: // crorc, crxor, mcrf
6439 if (dis_cond_logic( theInstr )) goto decode_success;
6440 goto decode_failure;
cerion26d07b22005-02-02 17:13:28 +00006441
sewardjb51f0f42005-07-18 11:38:02 +00006442 /* Branch Instructions */
6443 case 0x210: case 0x010: // bcctr, bclr
6444 if (dis_branch(theInstr, &dres)) goto decode_success;
6445 goto decode_failure;
cerion91ad5362005-01-27 23:02:41 +00006446
sewardjb51f0f42005-07-18 11:38:02 +00006447 /* Memory Synchronization Instructions */
6448 case 0x096: // isync
6449 if (dis_memsync( theInstr )) goto decode_success;
6450 goto decode_failure;
cerionb85e8bb2005-02-16 08:54:33 +00006451
sewardjb51f0f42005-07-18 11:38:02 +00006452 default:
6453 goto decode_failure;
cerionb85e8bb2005-02-16 08:54:33 +00006454 }
6455 break;
cerion91ad5362005-01-27 23:02:41 +00006456
6457
cerionb85e8bb2005-02-16 08:54:33 +00006458 case 0x1F:
cerione9d361a2005-03-04 17:35:29 +00006459
6460 /* For arith instns, bit10 is the OE flag (overflow enable) */
6461
cerionb85e8bb2005-02-16 08:54:33 +00006462 opc2 = (theInstr >> 1) & 0x1FF; /* theInstr[1:9] */
6463 switch (opc2) {
sewardjb51f0f42005-07-18 11:38:02 +00006464 /* Integer Arithmetic Instructions */
6465 case 0x10A: case 0x00A: case 0x08A: // add, addc, adde
6466 case 0x0EA: case 0x0CA: case 0x1EB: // addme, addze, divw
6467 case 0x1CB: case 0x04B: case 0x00B: // divwu, mulhw, mulhwu
6468 case 0x0EB: case 0x068: case 0x028: // mullw, neg, subf
6469 case 0x008: case 0x088: case 0x0E8: // subfc, subfe, subfme
6470 case 0x0C8: // subfze
6471 if (dis_int_arith( theInstr )) goto decode_success;
6472 goto decode_failure;
6473 default:
6474 break; // Fall through...
cerionb85e8bb2005-02-16 08:54:33 +00006475 }
cerion91ad5362005-01-27 23:02:41 +00006476
cerione9d361a2005-03-04 17:35:29 +00006477 /* All remaining opcodes use full 10 bits. */
6478
cerionb85e8bb2005-02-16 08:54:33 +00006479 opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
6480 switch (opc2) {
cerione9d361a2005-03-04 17:35:29 +00006481 /* Integer Compare Instructions */
6482 case 0x000: case 0x020: // cmp, cmpl
6483 if (dis_int_cmp( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006484 goto decode_failure;
cerion7aa4bbc2005-01-29 09:32:07 +00006485
cerione9d361a2005-03-04 17:35:29 +00006486 /* Integer Logical Instructions */
6487 case 0x01C: case 0x03C: case 0x01A: // and, andc, cntlzw
6488 case 0x11C: case 0x3BA: case 0x39A: // eqv, extsb, extsh
6489 case 0x1DC: case 0x07C: case 0x1BC: // nand, nor, or
6490 case 0x19C: case 0x13C: // orc, xor
6491 if (dis_int_logic( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006492 goto decode_failure;
cerion932ad942005-01-30 10:18:50 +00006493
cerione9d361a2005-03-04 17:35:29 +00006494 /* Integer Shift Instructions */
6495 case 0x018: case 0x318: case 0x338: // slw, sraw, srawi
6496 case 0x218: // srw
6497 if (dis_int_shift( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006498 goto decode_failure;
cerion7aa4bbc2005-01-29 09:32:07 +00006499
cerione9d361a2005-03-04 17:35:29 +00006500 /* Integer Load Instructions */
6501 case 0x057: case 0x077: case 0x157: // lbzx, lbzux, lhax
6502 case 0x177: case 0x117: case 0x137: // lhaux, lhzx, lhzux
6503 case 0x017: case 0x037: // lwzx, lwzux
6504 if (dis_int_load( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006505 goto decode_failure;
cerion7aa4bbc2005-01-29 09:32:07 +00006506
sewardjb51f0f42005-07-18 11:38:02 +00006507 /* Integer Store Instructions */
cerione9d361a2005-03-04 17:35:29 +00006508 case 0x0F7: case 0x0D7: case 0x1B7: // stbux, stbx, sthux
6509 case 0x197: case 0x0B7: case 0x097: // sthx, stwux, stwx
6510 if (dis_int_store( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006511 goto decode_failure;
cerion91ad5362005-01-27 23:02:41 +00006512
sewardj602857d2005-09-06 09:10:09 +00006513 /* Integer Load and Store with Byte Reverse Instructions */
6514 case 0x316: case 0x216: case 0x396: // lhbrx, lwbrx, sthbrx
6515 case 0x296: // stwbrx
6516 if (dis_int_ldst_rev( theInstr )) goto decode_success;
6517 goto decode_failure;
6518
sewardj87e651f2005-09-09 08:31:18 +00006519 /* Integer Load and Store String Instructions */
6520 case 0x255: case 0x215: case 0x2D5: // lswi, lswx, stswi
6521 case 0x295: { // stswx
6522 Bool stopHere = False;
6523 Bool ok = dis_int_ldst_str( theInstr, &stopHere );
6524 if (!ok) goto decode_failure;
6525 if (stopHere) {
6526 irbb->next = mkU32(guest_CIA_curr_instr+4);
6527 irbb->jumpkind = Ijk_Boring;
6528 dres.whatNext = Dis_StopHere;
6529 }
6530 goto decode_success;
6531 }
cerion645c9302005-01-31 10:09:59 +00006532
cerione9d361a2005-03-04 17:35:29 +00006533 /* Memory Synchronization Instructions */
6534 case 0x356: case 0x014: case 0x096: // eieio, lwarx, stwcx.
6535 case 0x256: // sync
6536 if (dis_memsync( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006537 goto decode_failure;
6538
cerione9d361a2005-03-04 17:35:29 +00006539 /* Processor Control Instructions */
6540 case 0x200: case 0x013: case 0x153: // mcrxr, mfcr, mfspr
6541 case 0x173: case 0x090: case 0x1D3: // mftb, mtcrf, mtspr
6542 if (dis_proc_ctl( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006543 goto decode_failure;
cerion645c9302005-01-31 10:09:59 +00006544
cerione9d361a2005-03-04 17:35:29 +00006545 /* Cache Management Instructions */
6546 case 0x2F6: case 0x056: case 0x036: // dcba, dcbf, dcbst
6547 case 0x116: case 0x0F6: case 0x3F6: // dcbt, dcbtst, dcbz
6548 case 0x3D6: // icbi
sewardj9e6491a2005-07-02 19:24:10 +00006549 if (dis_cache_manage( theInstr, &dres, archinfo ))
sewardjd94b73a2005-06-30 12:08:48 +00006550 goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006551 goto decode_failure;
ceriond23be4e2005-01-31 07:23:07 +00006552
sewardjb51f0f42005-07-18 11:38:02 +00006553//zz /* External Control Instructions */
6554//zz case 0x136: case 0x1B6: // eciwx, ecowx
6555//zz DIP("external control op => not implemented\n");
6556//zz goto decode_failure;
6557//zz
6558//zz /* Trap Instructions */
6559//zz case 0x004: // tw
6560//zz DIP("trap op (tw) => not implemented\n");
6561//zz goto decode_failure;
sewardje14bb9f2005-07-22 09:39:02 +00006562
6563 /* Floating Point Load Instructions */
6564 case 0x217: case 0x237: case 0x257: // lfsx, lfsux, lfdx
6565 case 0x277: // lfdux
6566 if (dis_fp_load( theInstr )) goto decode_success;
6567 goto decode_failure;
6568
6569 /* Floating Point Store Instructions */
6570 case 0x297: case 0x2B7: case 0x2D7: // stfs, stfsu, stfd
6571 case 0x2F7: case 0x3D7: // stfdu, stfiwx
6572 if (dis_fp_store( theInstr )) goto decode_success;
6573 goto decode_failure;
6574
6575
cerion32aad402005-09-10 12:02:24 +00006576 /* AltiVec instructions */
6577
6578 /* AV Cache Control - Data streams */
6579 case 0x156: case 0x176: case 0x336: // dst, dstst, dss
6580 if (dis_av_datastream( theInstr )) goto decode_success;
6581 goto decode_failure;
ceriona982c052005-06-28 17:23:09 +00006582
6583 /* AV Load */
6584 case 0x006: case 0x026: // lvsl, lvsr
6585 case 0x007: case 0x027: case 0x047: // lvebx, lvehx, lvewx
6586 case 0x067: case 0x167: // lvx, lvxl
6587 if (dis_av_load( theInstr )) goto decode_success;
6588 goto decode_failure;
6589
6590 /* AV Store */
6591 case 0x087: case 0x0A7: case 0x0C7: // stvebx, stvehx, stvewx
6592 case 0x0E7: case 0x1E7: // stvx, stvxl
6593 if (dis_av_store( theInstr )) goto decode_success;
6594 goto decode_failure;
6595
6596 default:
6597 goto decode_failure;
6598 }
6599 break;
6600
6601
cerion32aad402005-09-10 12:02:24 +00006602 case 0x04:
6603 /* AltiVec instructions */
6604
6605 opc2 = (theInstr) & 0x3F; /* theInstr[0:5] */
6606 switch (opc2) {
6607 /* AV Mult-Add, Mult-Sum */
6608 case 0x20: case 0x21: case 0x22: // vmhaddshs, vmhraddshs, vmladduhm
6609 case 0x24: case 0x25: case 0x26: // vmsumubm, vmsummbm, vmsumuhm
6610 case 0x27: case 0x28: case 0x29: // vmsumuhs, vmsumshm, vmsumshs
6611 if (dis_av_multarith( theInstr )) goto decode_success;
6612 goto decode_failure;
6613
6614 /* AV Permutations */
6615 case 0x2A: // vsel
6616 case 0x2B: // vperm
6617 if (dis_av_permute( theInstr )) goto decode_success;
6618 goto decode_failure;
6619
6620 /* AV Shift */
6621 case 0x2C: // vsldoi
6622 if (dis_av_shift( theInstr )) goto decode_success;
6623 goto decode_failure;
6624
6625 /* AV Floating Point Mult-Add/Sub */
6626 case 0x2E: case 0x2F: // vmaddfp, vnmsubfp
6627 if (dis_av_fp_arith( theInstr )) goto decode_success;
6628 goto decode_failure;
6629
6630 default:
6631 break; // Fall through...
6632 }
6633
6634 opc2 = (theInstr) & 0x7FF; /* theInstr[0:10] */
6635 switch (opc2) {
6636 /* AV Arithmetic */
6637 case 0x180: // vaddcuw
6638 case 0x000: case 0x040: case 0x080: // vaddubm, vadduhm, vadduwm
6639 case 0x200: case 0x240: case 0x280: // vaddubs, vadduhs, vadduws
6640 case 0x300: case 0x340: case 0x380: // vaddsbs, vaddshs, vaddsws
6641 case 0x580: // vsubcuw
6642 case 0x400: case 0x440: case 0x480: // vsububm, vsubuhm, vsubuwm
6643 case 0x600: case 0x640: case 0x680: // vsububs, vsubuhs, vsubuws
6644 case 0x700: case 0x740: case 0x780: // vsubsbs, vsubshs, vsubsws
6645 case 0x402: case 0x442: case 0x482: // vavgub, vavguh, vavguw
6646 case 0x502: case 0x542: case 0x582: // vavgsb, vavgsh, vavgsw
6647 case 0x002: case 0x042: case 0x082: // vmaxub, vmaxuh, vmaxuw
6648 case 0x102: case 0x142: case 0x182: // vmaxsb, vmaxsh, vmaxsw
6649 case 0x202: case 0x242: case 0x282: // vminub, vminuh, vminuw
6650 case 0x302: case 0x342: case 0x382: // vminsb, vminsh, vminsw
6651 case 0x008: case 0x048: // vmuloub, vmulouh
6652 case 0x108: case 0x148: // vmulosb, vmulosh
6653 case 0x208: case 0x248: // vmuleub, vmuleuh
6654 case 0x308: case 0x348: // vmulesb, vmulesh
6655 case 0x608: case 0x708: case 0x648: // vsum4ubs, vsum4sbs, vsum4shs
6656 case 0x688: case 0x788: // vsum2sws, vsumsws
6657 if (dis_av_arith( theInstr )) goto decode_success;
6658 goto decode_failure;
6659
6660 /* AV Rotate, Shift */
6661 case 0x004: case 0x044: case 0x084: // vrlb, vrlh, vrlw
6662 case 0x104: case 0x144: case 0x184: // vslb, vslh, vslw
6663 case 0x204: case 0x244: case 0x284: // vsrb, vsrh, vsrw
6664 case 0x304: case 0x344: case 0x384: // vsrab, vsrah, vsraw
6665 case 0x1C4: case 0x2C4: // vsl, vsr
6666 case 0x40C: case 0x44C: // vslo, vsro
6667 if (dis_av_shift( theInstr )) goto decode_success;
6668 goto decode_failure;
6669
6670 /* AV Logic */
6671 case 0x404: case 0x444: case 0x484: // vand, vandc, vor
6672 case 0x4C4: case 0x504: // vxor, vnor
6673 if (dis_av_logic( theInstr )) goto decode_success;
6674 goto decode_failure;
6675
6676 /* AV Processor Control */
6677 case 0x604: case 0x644: // mfvscr, mtvscr
6678 if (dis_av_procctl( theInstr )) goto decode_success;
6679 goto decode_failure;
6680
6681 /* AV Floating Point Arithmetic */
6682 case 0x00A: case 0x04A: // vaddfp, vsubfp
6683 case 0x10A: case 0x14A: case 0x18A: // vrefp, vrsqrtefp, vexptefp
6684 case 0x1CA: // vlogefp
6685 case 0x40A: case 0x44A: // vmaxfp, vminfp
6686 if (dis_av_fp_arith( theInstr )) goto decode_success;
6687 goto decode_failure;
6688
6689 /* AV Floating Point Round/Convert */
6690 case 0x20A: case 0x24A: case 0x28A: // vrfin, vrfiz, vrfip
6691 case 0x2CA: // vrfim
6692 case 0x30A: case 0x34A: case 0x38A: // vcfux, vcfsx, vctuxs
6693 case 0x3CA: // vctsxs
6694 if (dis_av_fp_convert( theInstr )) goto decode_success;
6695 goto decode_failure;
6696
6697 /* AV Merge, Splat */
6698 case 0x00C: case 0x04C: case 0x08C: // vmrghb, vmrghh, vmrghw
6699 case 0x10C: case 0x14C: case 0x18C: // vmrglb, vmrglh, vmrglw
6700 case 0x20C: case 0x24C: case 0x28C: // vspltb, vsplth, vspltw
6701 case 0x30C: case 0x34C: case 0x38C: // vspltisb, vspltish, vspltisw
6702 if (dis_av_permute( theInstr )) goto decode_success;
6703 goto decode_failure;
6704
6705 /* AV Pack, Unpack */
6706 case 0x00E: case 0x04E: case 0x08E: // vpkuhum, vpkuwum, vpkuhus
6707 case 0x0CE: // vpkuwus
6708 case 0x10E: case 0x14E: case 0x18E: // vpkshus, vpkswus, vpkshss
6709 case 0x1CE: // vpkswss
6710 case 0x20E: case 0x24E: case 0x28E: // vupkhsb, vupkhsh, vupklsb
6711 case 0x2CE: // vupklsh
6712 case 0x30E: case 0x34E: case 0x3CE: // vpkpx, vupkhpx, vupklpx
6713 if (dis_av_pack( theInstr )) goto decode_success;
6714 goto decode_failure;
6715
6716 default:
6717 break; // Fall through...
6718 }
6719
6720 opc2 = (theInstr) & 0x3FF; /* theInstr[0:9] (Bit 10 = Rc)*/
6721 switch (opc2) {
6722
6723 /* AV Compare */
6724 case 0x006: case 0x046: case 0x086: // vcmpequb, vcmpequh, vcmpequw
6725 case 0x206: case 0x246: case 0x286: // vcmpgtub, vcmpgtuh, vcmpgtuw
6726 case 0x306: case 0x346: case 0x386: // vcmpgtsb, vcmpgtsh, vcmpgtsw
6727 if (dis_av_cmp( theInstr )) goto decode_success;
6728 goto decode_failure;
6729
6730 /* AV Floating Point Compare */
6731 case 0x0C6: case 0x1C6: case 0x2C6: // vcmpeqfp, vcmpgefp, vcmpgtfp
6732 case 0x3C6: // vcmpbfp
6733 if (dis_av_fp_cmp( theInstr )) goto decode_success;
6734 goto decode_failure;
6735
6736 default:
6737 goto decode_failure;
6738 }
6739 break;
cerion7aa4bbc2005-01-29 09:32:07 +00006740
cerion896a1372005-01-25 12:24:25 +00006741 default:
6742 decode_failure:
6743 /* All decode failures end up here. */
cerion225a0342005-09-12 20:49:09 +00006744 opc2 = (theInstr) & 0x7FF;
cerion1515db92005-01-25 17:21:23 +00006745 vex_printf("disInstr(ppc32): unhandled instruction: "
cerion896a1372005-01-25 12:24:25 +00006746 "0x%x\n", theInstr);
sewardjc7cd2142005-09-09 22:31:49 +00006747 vex_printf(" primary %d(0x%x), secondary %u(0x%x)\n",
sewardjb51f0f42005-07-18 11:38:02 +00006748 opc1, opc1, opc2, opc2);
cerionb85e8bb2005-02-16 08:54:33 +00006749
cerione9d361a2005-03-04 17:35:29 +00006750#if PPC32_TOIR_DEBUG
cerion995bc362005-02-03 11:03:31 +00006751 vex_printf("disInstr(ppc32): instr: ");
6752 vex_printf_binary( theInstr, 32, True );
6753 vex_printf("\n");
6754
6755 vex_printf("disInstr(ppc32): opcode1: ");
6756 vex_printf_binary( opc1, 6, False );
6757 vex_printf("\n");
6758
6759 vex_printf("disInstr(ppc32): opcode2: ");
6760 vex_printf_binary( opc2, 10, False );
cerion45552a92005-02-03 18:20:22 +00006761 vex_printf("\n\n");
6762#endif
cerion995bc362005-02-03 11:03:31 +00006763
6764
sewardj01a9e802005-02-01 20:46:00 +00006765 /* Tell the dispatcher that this insn cannot be decoded, and so has
6766 not been executed, and (is currently) the next to be executed.
6767 CIA should be up-to-date since it made so at the start of each
6768 insn, but nevertheless be paranoid and update it again right
6769 now. */
sewardjb51f0f42005-07-18 11:38:02 +00006770 putSPR( PPC32_SPR_CIA, mkU32(guest_CIA_curr_instr) );
sewardj9e6491a2005-07-02 19:24:10 +00006771 irbb->next = mkU32(guest_CIA_curr_instr);
sewardj01a9e802005-02-01 20:46:00 +00006772 irbb->jumpkind = Ijk_NoDecode;
sewardj9e6491a2005-07-02 19:24:10 +00006773 dres.whatNext = Dis_StopHere;
6774 dres.len = 0;
6775 return dres;
cerion896a1372005-01-25 12:24:25 +00006776
6777 } /* switch (opc) for the main (primary) opcode switch. */
6778
6779 decode_success:
6780 /* All decode successes end up here. */
cerion896a1372005-01-25 12:24:25 +00006781 DIP("\n");
6782
sewardj9e6491a2005-07-02 19:24:10 +00006783 dres.len = 4;
6784 return dres;
cerion896a1372005-01-25 12:24:25 +00006785}
6786
6787#undef DIP
6788#undef DIS
6789
sewardj9e6491a2005-07-02 19:24:10 +00006790
6791/*------------------------------------------------------------*/
6792/*--- Top-level fn ---*/
6793/*------------------------------------------------------------*/
6794
6795/* Disassemble a single instruction into IR. The instruction
6796 is located in host memory at &guest_code[delta]. */
6797
6798DisResult disInstr_PPC32 ( IRBB* irbb_IN,
6799 Bool put_IP,
6800 Bool (*resteerOkFn) ( Addr64 ),
6801 UChar* guest_code_IN,
6802 Long delta,
6803 Addr64 guest_IP,
6804 VexArchInfo* archinfo,
6805 Bool host_bigendian_IN )
6806{
6807 DisResult dres;
6808
6809 /* Set globals (see top of this file) */
6810 guest_code = guest_code_IN;
6811 irbb = irbb_IN;
6812 host_is_bigendian = host_bigendian_IN;
6813 guest_CIA_curr_instr = (Addr32)guest_IP;
6814 guest_CIA_bbstart = (Addr32)toUInt(guest_IP - delta);
6815
6816 dres = disInstr_PPC32_WRK ( put_IP, resteerOkFn,
6817 delta, archinfo );
6818
6819 return dres;
6820}
6821
6822
sewardjc808ef72005-08-18 11:50:43 +00006823/*------------------------------------------------------------*/
6824/*--- Unused stuff ---*/
6825/*------------------------------------------------------------*/
6826
6827///* A potentially more memcheck-friendly implementation of Clz32, with
6828// the boundary case Clz32(0) = 32, which is what ppc requires. */
6829//
6830//static IRExpr* /* :: Ity_I32 */ verbose_Clz32 ( IRTemp arg )
6831//{
6832// /* Welcome ... to SSA R Us. */
6833// IRTemp n1 = newTemp(Ity_I32);
6834// IRTemp n2 = newTemp(Ity_I32);
6835// IRTemp n3 = newTemp(Ity_I32);
6836// IRTemp n4 = newTemp(Ity_I32);
6837// IRTemp n5 = newTemp(Ity_I32);
6838// IRTemp n6 = newTemp(Ity_I32);
6839// IRTemp n7 = newTemp(Ity_I32);
6840// IRTemp n8 = newTemp(Ity_I32);
6841// IRTemp n9 = newTemp(Ity_I32);
6842// IRTemp n10 = newTemp(Ity_I32);
6843// IRTemp n11 = newTemp(Ity_I32);
6844// IRTemp n12 = newTemp(Ity_I32);
6845//
6846// /* First, propagate the most significant 1-bit into all lower
6847// positions in the word. */
6848// /* unsigned int clz ( unsigned int n )
6849// {
6850// n |= (n >> 1);
6851// n |= (n >> 2);
6852// n |= (n >> 4);
6853// n |= (n >> 8);
6854// n |= (n >> 16);
6855// return bitcount(~n);
6856// }
6857// */
6858// assign(n1, mkexpr(arg));
6859// assign(n2, binop(Iop_Or32, mkexpr(n1), binop(Iop_Shr32, mkexpr(n1), mkU8(1))));
6860// assign(n3, binop(Iop_Or32, mkexpr(n2), binop(Iop_Shr32, mkexpr(n2), mkU8(2))));
6861// assign(n4, binop(Iop_Or32, mkexpr(n3), binop(Iop_Shr32, mkexpr(n3), mkU8(4))));
6862// assign(n5, binop(Iop_Or32, mkexpr(n4), binop(Iop_Shr32, mkexpr(n4), mkU8(8))));
6863// assign(n6, binop(Iop_Or32, mkexpr(n5), binop(Iop_Shr32, mkexpr(n5), mkU8(16))));
6864// /* This gives a word of the form 0---01---1. Now invert it, giving
6865// a word of the form 1---10---0, then do a population-count idiom
6866// (to count the 1s, which is the number of leading zeroes, or 32
6867// if the original word was 0. */
6868// assign(n7, unop(Iop_Not32, mkexpr(n6)));
6869//
6870// /* unsigned int bitcount ( unsigned int n )
6871// {
6872// n = n - ((n >> 1) & 0x55555555);
6873// n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
6874// n = (n + (n >> 4)) & 0x0F0F0F0F;
6875// n = n + (n >> 8);
6876// n = (n + (n >> 16)) & 0x3F;
6877// return n;
6878// }
6879// */
6880// assign(n8,
6881// binop(Iop_Sub32,
6882// mkexpr(n7),
6883// binop(Iop_And32,
6884// binop(Iop_Shr32, mkexpr(n7), mkU8(1)),
6885// mkU32(0x55555555))));
6886// assign(n9,
6887// binop(Iop_Add32,
6888// binop(Iop_And32, mkexpr(n8), mkU32(0x33333333)),
6889// binop(Iop_And32,
6890// binop(Iop_Shr32, mkexpr(n8), mkU8(2)),
6891// mkU32(0x33333333))));
6892// assign(n10,
6893// binop(Iop_And32,
6894// binop(Iop_Add32,
6895// mkexpr(n9),
6896// binop(Iop_Shr32, mkexpr(n9), mkU8(4))),
6897// mkU32(0x0F0F0F0F)));
6898// assign(n11,
6899// binop(Iop_Add32,
6900// mkexpr(n10),
6901// binop(Iop_Shr32, mkexpr(n10), mkU8(8))));
6902// assign(n12,
6903// binop(Iop_Add32,
6904// mkexpr(n11),
6905// binop(Iop_Shr32, mkexpr(n11), mkU8(16))));
6906// return
6907// binop(Iop_And32, mkexpr(n12), mkU32(0x3F));
6908//}
6909
cerion896a1372005-01-25 12:24:25 +00006910/*--------------------------------------------------------------------*/
cerion1515db92005-01-25 17:21:23 +00006911/*--- end guest-ppc32/toIR.c ---*/
cerion896a1372005-01-25 12:24:25 +00006912/*--------------------------------------------------------------------*/