blob: 92a17cdf5e7ea382cbc66f35b67462f6d4403414 [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 ---*/
sewardj496a58d2005-03-20 18:44:44 +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
sewardj496a58d2005-03-20 18:44:44 +000013 Copyright (C) 2004-2005 OpenWorks LLP.
cerion896a1372005-01-25 12:24:25 +000014
15 This program is free software; you can redistribute it and/or modify
16 it under the terms of the GNU General Public License as published by
17 the Free Software Foundation; Version 2 dated June 1991 of the
18 license.
19
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or liability
23 for damages. See the GNU General Public License for more details.
24
25 Neither the names of the U.S. Department of Energy nor the
26 University of California nor the names of its contributors may be
27 used to endorse or promote products derived from this software
28 without prior written permission.
29
30 You should have received a copy of the GNU General Public License
31 along with this program; if not, write to the Free Software
32 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
33 USA.
34*/
35
sewardjb51f0f42005-07-18 11:38:02 +000036/* TODO 2005 07 15:
37
sewardje14bb9f2005-07-22 09:39:02 +000038 Get rid of all vestiges of flag helper fns.
sewardjb51f0f42005-07-18 11:38:02 +000039
sewardje14bb9f2005-07-22 09:39:02 +000040 Spot rlwini cases which are simply left/right shifts and
41 emit Shl32/Shr32 accordingly.
42
43 Move mtxer/mfxer code into its own function.
sewardjb51f0f42005-07-18 11:38:02 +000044*/
45
46
cerion1515db92005-01-25 17:21:23 +000047/* Translates PPC32 code to IR. */
cerion896a1372005-01-25 12:24:25 +000048
cerion645c9302005-01-31 10:09:59 +000049/* References
ceriona982c052005-06-28 17:23:09 +000050
51#define PPC32
cerion645c9302005-01-31 10:09:59 +000052 "PowerPC Microprocessor Family:
cerione9d361a2005-03-04 17:35:29 +000053 The Programming Environments for 32-Bit Microprocessors"
54 02/21/2000
55 http://www-3.ibm.com/chips/techlib/techlib.nsf/techdocs/852569B20050FF778525699600719DF2
56
ceriona982c052005-06-28 17:23:09 +000057#define AV
58 "PowerPC Microprocessor Family:
59 AltiVec(TM) Technology Programming Environments Manual"
60 07/10/2003
61 http://www-3.ibm.com/chips/techlib/techlib.nsf/techdocs/FBFA164F824370F987256D6A006F424D
62
cerione9d361a2005-03-04 17:35:29 +000063 Other refs:
64 "PowerPC Microprocessor Family:
cerion645c9302005-01-31 10:09:59 +000065 Programming Environments Manual for 64 and 32-Bit Microprocessors
66 Version 2.0"
cerion26d07b22005-02-02 17:13:28 +000067 06/10/2003
cerion645c9302005-01-31 10:09:59 +000068 http://www-3.ibm.com/chips/techlib/techlib.nsf/techdocs/F6153E213FDD912E87256D49006C6541
69*/
70
cerion896a1372005-01-25 12:24:25 +000071#include "libvex_basictypes.h"
72#include "libvex_ir.h"
73#include "libvex.h"
cerion1515db92005-01-25 17:21:23 +000074#include "libvex_guest_ppc32.h"
cerion896a1372005-01-25 12:24:25 +000075
76#include "main/vex_util.h"
77#include "main/vex_globals.h"
sewardj9e6491a2005-07-02 19:24:10 +000078#include "guest-generic/bb_to_IR.h"
cerion1515db92005-01-25 17:21:23 +000079#include "guest-ppc32/gdefs.h"
cerion896a1372005-01-25 12:24:25 +000080
81
82/*------------------------------------------------------------*/
83/*--- Globals ---*/
84/*------------------------------------------------------------*/
85
sewardj9e6491a2005-07-02 19:24:10 +000086/* These are set at the start of the translation of an insn, right
87 down in disInstr_PPC32, so that we don't have to pass them around
88 endlessly. They are all constant during the translation of any
89 given insn. */
cerion896a1372005-01-25 12:24:25 +000090
cerioned623db2005-06-20 12:42:04 +000091/* We need to know this to do sub-register accesses correctly. */
cerioned623db2005-06-20 12:42:04 +000092static Bool host_is_bigendian;
93
cerion896a1372005-01-25 12:24:25 +000094/* Pointer to the guest code area. */
cerion896a1372005-01-25 12:24:25 +000095static UChar* guest_code;
96
97/* The guest address corresponding to guest_code[0]. */
sewardj9e6491a2005-07-02 19:24:10 +000098static Addr32 guest_CIA_bbstart;
cerion896a1372005-01-25 12:24:25 +000099
sewardj01a9e802005-02-01 20:46:00 +0000100/* The guest address for the instruction currently being
101 translated. */
sewardj9e6491a2005-07-02 19:24:10 +0000102static Addr32 guest_CIA_curr_instr;
sewardj01a9e802005-02-01 20:46:00 +0000103
cerion896a1372005-01-25 12:24:25 +0000104/* The IRBB* into which we're generating code. */
105static IRBB* irbb;
106
107
108/*------------------------------------------------------------*/
109/*--- Debugging output ---*/
110/*------------------------------------------------------------*/
111
cerione9d361a2005-03-04 17:35:29 +0000112#define PPC32_TOIR_DEBUG 0
113
cerion896a1372005-01-25 12:24:25 +0000114#define DIP(format, args...) \
115 if (vex_traceflags & VEX_TRACE_FE) \
116 vex_printf(format, ## args)
117
118#define DIS(buf, format, args...) \
119 if (vex_traceflags & VEX_TRACE_FE) \
120 vex_sprintf(buf, format, ## args)
121
122
cerion896a1372005-01-25 12:24:25 +0000123/*------------------------------------------------------------*/
cerion38674602005-02-08 02:19:25 +0000124/*--- Offsets of various parts of the ppc32 guest state. ---*/
cerion896a1372005-01-25 12:24:25 +0000125/*------------------------------------------------------------*/
126
cerion91ad5362005-01-27 23:02:41 +0000127#define OFFB_CIA offsetof(VexGuestPPC32State,guest_CIA)
128#define OFFB_LR offsetof(VexGuestPPC32State,guest_LR)
129#define OFFB_CTR offsetof(VexGuestPPC32State,guest_CTR)
130
sewardjb51f0f42005-07-18 11:38:02 +0000131#define OFFB_XER_SO offsetof(VexGuestPPC32State,guest_XER_SO)
sewardj20ef5472005-07-21 14:48:31 +0000132#define OFFB_XER_OV offsetof(VexGuestPPC32State,guest_XER_OV)
sewardjb51f0f42005-07-18 11:38:02 +0000133#define OFFB_XER_CA offsetof(VexGuestPPC32State,guest_XER_CA)
sewardj20ef5472005-07-21 14:48:31 +0000134#define OFFB_XER_BC offsetof(VexGuestPPC32State,guest_XER_BC)
cerion91ad5362005-01-27 23:02:41 +0000135
cerion094d1392005-06-20 13:45:57 +0000136#define OFFB_FPROUND offsetof(VexGuestPPC32State,guest_FPROUND)
137
ceriona982c052005-06-28 17:23:09 +0000138#define OFFB_VRSAVE offsetof(VexGuestPPC32State,guest_VRSAVE)
139#define OFFB_VSCR offsetof(VexGuestPPC32State,guest_VSCR)
140
cerion094d1392005-06-20 13:45:57 +0000141#define OFFB_EMWARN offsetof(VexGuestPPC32State,guest_EMWARN)
142
sewardj7ce9d152005-03-15 16:54:13 +0000143#define OFFB_TISTART offsetof(VexGuestPPC32State,guest_TISTART)
144#define OFFB_TILEN offsetof(VexGuestPPC32State,guest_TILEN)
cerion91ad5362005-01-27 23:02:41 +0000145
146
cerion38674602005-02-08 02:19:25 +0000147/*------------------------------------------------------------*/
sewardjb51f0f42005-07-18 11:38:02 +0000148/*--- Extract instruction fields --- */
cerion38674602005-02-08 02:19:25 +0000149/*------------------------------------------------------------*/
cerione9d361a2005-03-04 17:35:29 +0000150
sewardjb51f0f42005-07-18 11:38:02 +0000151/* Extract primary opcode, instr[31:26] */
152static UInt ifieldOPC ( UInt instr ) {
153 return (instr >> 26) & 0x3F;
154}
cerione9d361a2005-03-04 17:35:29 +0000155
sewardjb51f0f42005-07-18 11:38:02 +0000156/* Extract 10-bit secondary opcode, instr[11:1] */
157static UInt ifieldOPClo10 ( UInt instr) {
158 return (instr >> 1 ) & 0x3FF;
159}
cerione9d361a2005-03-04 17:35:29 +0000160
sewardjb51f0f42005-07-18 11:38:02 +0000161/* Extract RD (destination register) field, instr[25:21] */
162static UInt ifieldRD ( UInt instr ) {
163 return (instr >> 21) & 0x1F;
164}
cerion094d1392005-06-20 13:45:57 +0000165
sewardjb51f0f42005-07-18 11:38:02 +0000166/* Extract RA (first source register) field, instr[20:16] */
167static UInt ifieldRA ( UInt instr ) {
168 return (instr >> 16) & 0x1F;
169}
170
171/* Extract RB (first source register) field, instr[15:11] */
172static UInt ifieldRB ( UInt instr ) {
173 return (instr >> 11) & 0x1F;
174}
175
176/* Extract bottom bit (Rc?) from instr */
177static UInt ifieldBIT0 ( UInt instr ) {
178 return instr & 1;
179}
180
181/* Extract lower half of instruction and sign extent to 32 bits */
182static Int ifieldSIMM16 ( UInt instr ) {
183 Int i = instr & 0xFFFF;
184 return (i << 16) >> 16;
185}
186
187
188//zz /*------------------------------------------------------------*/
189//zz /*--- Abstract register interface (non-gpr|fpr) --- */
190//zz /*------------------------------------------------------------*/
191//zz
192//zz /* Offsets of bitfields within various ppc32 registers */
193//zz #define SHIFT_XER_SO 31
194//zz #define SHIFT_XER_OV 30
195//zz #define SHIFT_XER_CA 29
196//zz #define SHIFT_XER_BC 0
197//zz
198//zz #define SHIFT_CR_LT 8
199//zz #define SHIFT_CR_GT 4
200//zz #define SHIFT_CR_EQ 2
201//zz #define SHIFT_CR_SO 1
sewardje14bb9f2005-07-22 09:39:02 +0000202
203#define SHIFT_FPSCR_RN 0
204#define MASK_FPSCR_RN (3 << SHIFT_FPSCR_RN)
205
sewardjb51f0f42005-07-18 11:38:02 +0000206//zz #define SHIFT_VSCR_NJ 16
207//zz #define SHIFT_VSCR_SAT 0
ceriona982c052005-06-28 17:23:09 +0000208
cerion094d1392005-06-20 13:45:57 +0000209
cerione9d361a2005-03-04 17:35:29 +0000210// Special purpose (i.e. non-gpr/fpr) registers
211typedef enum {
212 PPC32_SPR_CIA, // Current Instruction Address
213 PPC32_SPR_LR, // Link Register
214 PPC32_SPR_CTR, // Count Register
sewardjb51f0f42005-07-18 11:38:02 +0000215//zz PPC32_SPR_XER, // Summary Overflow
216//zz PPC32_SPR_CR, // Condition Register
sewardje14bb9f2005-07-22 09:39:02 +0000217 PPC32_SPR_FPSCR, // Floating Point Status/Control Register
ceriona982c052005-06-28 17:23:09 +0000218 PPC32_SPR_VRSAVE, // Vector Save/Restore Register
sewardjb51f0f42005-07-18 11:38:02 +0000219//zz PPC32_SPR_VSCR, // Vector Status and Control Register
sewardje14bb9f2005-07-22 09:39:02 +0000220 PPC32_SPR_MAX
cerione9d361a2005-03-04 17:35:29 +0000221} PPC32SPR;
222
sewardjb51f0f42005-07-18 11:38:02 +0000223//zz /*
224//zz Note on FPSCR: Floating Point Status and Control Register
225//zz
226//zz We're only keeping hold of fp rounding-mode bits, via guest_FPROUND
227//zz The rest of the FPSCR is set to 0x0, which corresponds to
228//zz 'all exceptions masked'
229//zz
230//zz FPSCR[29:31] => Exception Summaries
231//zz FPSCR[17:28] => Exceptions
232//zz FPSCR[16] => FPRF::Class Descriptor
233//zz FPSCR[12:15] => FPRF::Condition Code
234//zz FPSCR[11] => Unused (0)
235//zz FPSCR[8:10] => Exceptions
236//zz FPSCR[3:7] => Exception Control
237//zz FPSCR[2] => Non-IEEE mode
238//zz FPSCR[0:1] => Rounding Mode
239//zz
240//zz CAB: Perhaps necessary to record writes to FPRF ?
241//zz Set by dis_fp_cmp() instrs, also some fp arith/round/conv instrs.
242//zz Tested using dis_fp_scr(): e.g fpscr->cr, branch conditional...
243//zz */
244//zz
245//zz
246//zz /* Gets from SPR (non-GPR|FPR) registers */
247//zz static IRExpr* getReg_masked ( PPC32SPR reg, UInt mask );
248static IRExpr* getSPR ( PPC32SPR reg );
249//zz static IRExpr* getReg_field ( PPC32SPR reg, UInt field_idx );
250//zz static IRExpr* getReg_bit ( PPC32SPR reg, UInt bit_idx );
251//zz
252//zz /* Puts to SPR (non-GPR|FPR) registers */
253//zz static void putReg_masked ( PPC32SPR reg, IRExpr* src, UInt mask );
254static void putSPR ( PPC32SPR reg, IRExpr* src );
255//zz static void putReg_field ( PPC32SPR reg, IRExpr* src, UInt field_idx );
256//zz static void putReg_bit ( PPC32SPR reg, IRExpr* src, UInt bit_idx );
sewardje14bb9f2005-07-22 09:39:02 +0000257
258/* FP Helpers */
259static void put_emwarn ( IRExpr* e /* :: Ity_I32 */ );
cerion094d1392005-06-20 13:45:57 +0000260
cerion38674602005-02-08 02:19:25 +0000261
262
263
264/*------------------------------------------------------------*/
265/*--- Misc Helpers ---*/
266/*------------------------------------------------------------*/
267
268static UInt MASK( UInt begin, UInt end )
269{
cerionb85e8bb2005-02-16 08:54:33 +0000270 UInt m1 = ((UInt)(-1)) << begin;
271 UInt m2 = ((UInt)(-1)) << (end + 1);
272 UInt mask = m1 ^ m2;
273 if (begin > end) mask = ~mask; // wrap mask
274 return mask;
cerion38674602005-02-08 02:19:25 +0000275}
276
sewardjb51f0f42005-07-18 11:38:02 +0000277//zz #if PPC32_TOIR_DEBUG
278//zz static void vex_printf_binary( UInt x, UInt len, Bool spaces )
279//zz {
280//zz UInt i;
281//zz vassert(len > 0 && len <= 32);
282//zz
283//zz for (i=len; i>0; i--) {
284//zz vex_printf("%d", ((x & (1<<(len-1))) != 0) );
285//zz x = x << 1;
286//zz if (((i-1)%4)==0 && (i > 1) && spaces) {
287//zz vex_printf(" ");
288//zz }
289//zz }
290//zz }
291//zz #endif
cerion38674602005-02-08 02:19:25 +0000292
cerion896a1372005-01-25 12:24:25 +0000293
cerion896a1372005-01-25 12:24:25 +0000294/*------------------------------------------------------------*/
295/*--- Helper bits and pieces for deconstructing the ---*/
sewardj684aa952005-01-30 12:52:14 +0000296/*--- ppc32 insn stream. ---*/
cerion896a1372005-01-25 12:24:25 +0000297/*------------------------------------------------------------*/
298
299/* Add a statement to the list held by "irbb". */
300static void stmt ( IRStmt* st )
301{
302 addStmtToIRBB( irbb, st );
303}
304
cerion896a1372005-01-25 12:24:25 +0000305/* Generate a new temporary of the given type. */
306static IRTemp newTemp ( IRType ty )
307{
sewardj496a58d2005-03-20 18:44:44 +0000308 vassert(isPlausibleIRType(ty));
cerion896a1372005-01-25 12:24:25 +0000309 return newIRTemp( irbb->tyenv, ty );
310}
cerion896a1372005-01-25 12:24:25 +0000311
sewardjb51f0f42005-07-18 11:38:02 +0000312//zz /* Various simple conversions */
313//zz
314//zz static UChar extend_s_5to8 ( UChar x )
315//zz {
316//zz return toUChar((((Int)x) << 27) >> 27);
317//zz }
318//zz
319//zz #if 0
320//zz static UInt extend_s_8to32( UInt x )
321//zz {
322//zz return (UInt)((((Int)x) << 24) >> 24);
323//zz }
324//zz #endif
cerion91ad5362005-01-27 23:02:41 +0000325
cerion896a1372005-01-25 12:24:25 +0000326static UInt extend_s_16to32 ( UInt x )
327{
328 return (UInt)((((Int)x) << 16) >> 16);
329}
cerion896a1372005-01-25 12:24:25 +0000330
cerion6b30d852005-06-24 11:25:46 +0000331static UInt extend_s_26to32 ( UInt x )
cerion896a1372005-01-25 12:24:25 +0000332{
cerion6b30d852005-06-24 11:25:46 +0000333 return (UInt)((((Int)x) << 6) >> 6);
cerion896a1372005-01-25 12:24:25 +0000334}
cerion896a1372005-01-25 12:24:25 +0000335
sewardj684aa952005-01-30 12:52:14 +0000336/* Do a big-endian load of a 32-bit word, regardless of the endianness
337 of the underlying host. */
cerioncf004462005-01-31 15:24:55 +0000338static UInt getUIntBigendianly ( UChar* p )
sewardj684aa952005-01-30 12:52:14 +0000339{
cerioncf004462005-01-31 15:24:55 +0000340 UInt w = 0;
sewardj684aa952005-01-30 12:52:14 +0000341 w = (w << 8) | p[0];
342 w = (w << 8) | p[1];
343 w = (w << 8) | p[2];
344 w = (w << 8) | p[3];
345 return w;
346}
347
cerion896a1372005-01-25 12:24:25 +0000348
349/*------------------------------------------------------------*/
350/*--- Helpers for constructing IR. ---*/
351/*------------------------------------------------------------*/
352
cerion896a1372005-01-25 12:24:25 +0000353static void assign ( IRTemp dst, IRExpr* e )
354{
355 stmt( IRStmt_Tmp(dst, e) );
356}
357
cerionae694622005-01-28 17:52:47 +0000358static void storeBE ( IRExpr* addr, IRExpr* data )
cerion896a1372005-01-25 12:24:25 +0000359{
sewardjaf1ceca2005-06-30 23:31:27 +0000360 stmt( IRStmt_Store(Iend_BE,addr,data) );
cerion896a1372005-01-25 12:24:25 +0000361}
362
363static IRExpr* unop ( IROp op, IRExpr* a )
364{
365 return IRExpr_Unop(op, a);
366}
367
368static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
369{
370 return IRExpr_Binop(op, a1, a2);
371}
372
373static IRExpr* mkexpr ( IRTemp tmp )
374{
375 return IRExpr_Tmp(tmp);
376}
377
cerion45552a92005-02-03 18:20:22 +0000378static IRExpr* mkU1 ( UInt i )
379{
380 vassert(i < 2);
sewardj684c0372005-02-07 02:33:58 +0000381 return IRExpr_Const(IRConst_U1( toBool(i) ));
cerion45552a92005-02-03 18:20:22 +0000382}
383
sewardj684c0372005-02-07 02:33:58 +0000384static IRExpr* mkU8 ( UChar i )
cerion896a1372005-01-25 12:24:25 +0000385{
cerion896a1372005-01-25 12:24:25 +0000386 return IRExpr_Const(IRConst_U8(i));
387}
cerion896a1372005-01-25 12:24:25 +0000388
cerion896a1372005-01-25 12:24:25 +0000389static IRExpr* mkU32 ( UInt i )
390{
391 return IRExpr_Const(IRConst_U32(i));
392}
393
cerionae694622005-01-28 17:52:47 +0000394static IRExpr* loadBE ( IRType ty, IRExpr* data )
cerion896a1372005-01-25 12:24:25 +0000395{
sewardjaf1ceca2005-06-30 23:31:27 +0000396 return IRExpr_Load(Iend_BE,ty,data);
cerion896a1372005-01-25 12:24:25 +0000397}
cerion896a1372005-01-25 12:24:25 +0000398
sewardj20ef5472005-07-21 14:48:31 +0000399static IRExpr* mkOR1 ( IRExpr* arg1, IRExpr* arg2 )
400{
401 vassert(typeOfIRExpr(irbb->tyenv, arg1) == Ity_I1);
402 vassert(typeOfIRExpr(irbb->tyenv, arg2) == Ity_I1);
403 return
404 unop(Iop_32to1, binop(Iop_Or32, unop(Iop_1Uto32, arg1),
405 unop(Iop_1Uto32, arg2)));
406}
407
408static IRExpr* mkAND1 ( IRExpr* arg1, IRExpr* arg2 )
409{
410 vassert(typeOfIRExpr(irbb->tyenv, arg1) == Ity_I1);
411 vassert(typeOfIRExpr(irbb->tyenv, arg2) == Ity_I1);
412 return
413 unop(Iop_32to1, binop(Iop_And32, unop(Iop_1Uto32, arg1),
414 unop(Iop_1Uto32, arg2)));
415}
sewardjb51f0f42005-07-18 11:38:02 +0000416
417static Int integerGuestRegOffset ( UInt archreg )
cerion45b70ff2005-01-31 17:03:25 +0000418{
sewardjb51f0f42005-07-18 11:38:02 +0000419 vassert(archreg < 32);
420
421 // jrs: probably not necessary; only matters if we reference sub-parts
422 // of the ppc32 registers, but that isn't the case
423 // later: this might affect Altivec though?
424 vassert(host_is_bigendian);
425
426 switch (archreg) {
427 case 0: return offsetof(VexGuestPPC32State, guest_GPR0);
428 case 1: return offsetof(VexGuestPPC32State, guest_GPR1);
429 case 2: return offsetof(VexGuestPPC32State, guest_GPR2);
430 case 3: return offsetof(VexGuestPPC32State, guest_GPR3);
431 case 4: return offsetof(VexGuestPPC32State, guest_GPR4);
432 case 5: return offsetof(VexGuestPPC32State, guest_GPR5);
433 case 6: return offsetof(VexGuestPPC32State, guest_GPR6);
434 case 7: return offsetof(VexGuestPPC32State, guest_GPR7);
435 case 8: return offsetof(VexGuestPPC32State, guest_GPR8);
436 case 9: return offsetof(VexGuestPPC32State, guest_GPR9);
437 case 10: return offsetof(VexGuestPPC32State, guest_GPR10);
438 case 11: return offsetof(VexGuestPPC32State, guest_GPR11);
439 case 12: return offsetof(VexGuestPPC32State, guest_GPR12);
440 case 13: return offsetof(VexGuestPPC32State, guest_GPR13);
441 case 14: return offsetof(VexGuestPPC32State, guest_GPR14);
442 case 15: return offsetof(VexGuestPPC32State, guest_GPR15);
443 case 16: return offsetof(VexGuestPPC32State, guest_GPR16);
444 case 17: return offsetof(VexGuestPPC32State, guest_GPR17);
445 case 18: return offsetof(VexGuestPPC32State, guest_GPR18);
446 case 19: return offsetof(VexGuestPPC32State, guest_GPR19);
447 case 20: return offsetof(VexGuestPPC32State, guest_GPR20);
448 case 21: return offsetof(VexGuestPPC32State, guest_GPR21);
449 case 22: return offsetof(VexGuestPPC32State, guest_GPR22);
450 case 23: return offsetof(VexGuestPPC32State, guest_GPR23);
451 case 24: return offsetof(VexGuestPPC32State, guest_GPR24);
452 case 25: return offsetof(VexGuestPPC32State, guest_GPR25);
453 case 26: return offsetof(VexGuestPPC32State, guest_GPR26);
454 case 27: return offsetof(VexGuestPPC32State, guest_GPR27);
455 case 28: return offsetof(VexGuestPPC32State, guest_GPR28);
456 case 29: return offsetof(VexGuestPPC32State, guest_GPR29);
457 case 30: return offsetof(VexGuestPPC32State, guest_GPR30);
458 case 31: return offsetof(VexGuestPPC32State, guest_GPR31);
459 default: break;
460 }
461 vpanic("integerGuestRegOffset(ppc32,be)"); /*notreached*/
462}
463
464static IRExpr* getIReg ( UInt archreg )
465{
466 vassert(archreg < 32);
467 return IRExpr_Get( integerGuestRegOffset(archreg), Ity_I32 );
468}
469
470/* Ditto, but write to a reg instead. */
471static void putIReg ( UInt archreg, IRExpr* e )
472{
473 vassert(archreg < 32);
474 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I32);
475 stmt( IRStmt_Put(integerGuestRegOffset(archreg), e) );
476}
477
478
479static Int floatGuestRegOffset ( UInt archreg )
480{
481 vassert(archreg < 32);
482
483 switch (archreg) {
484 case 0: return offsetof(VexGuestPPC32State, guest_FPR0);
485 case 1: return offsetof(VexGuestPPC32State, guest_FPR1);
486 case 2: return offsetof(VexGuestPPC32State, guest_FPR2);
487 case 3: return offsetof(VexGuestPPC32State, guest_FPR3);
488 case 4: return offsetof(VexGuestPPC32State, guest_FPR4);
489 case 5: return offsetof(VexGuestPPC32State, guest_FPR5);
490 case 6: return offsetof(VexGuestPPC32State, guest_FPR6);
491 case 7: return offsetof(VexGuestPPC32State, guest_FPR7);
492 case 8: return offsetof(VexGuestPPC32State, guest_FPR8);
493 case 9: return offsetof(VexGuestPPC32State, guest_FPR9);
494 case 10: return offsetof(VexGuestPPC32State, guest_FPR10);
495 case 11: return offsetof(VexGuestPPC32State, guest_FPR11);
496 case 12: return offsetof(VexGuestPPC32State, guest_FPR12);
497 case 13: return offsetof(VexGuestPPC32State, guest_FPR13);
498 case 14: return offsetof(VexGuestPPC32State, guest_FPR14);
499 case 15: return offsetof(VexGuestPPC32State, guest_FPR15);
500 case 16: return offsetof(VexGuestPPC32State, guest_FPR16);
501 case 17: return offsetof(VexGuestPPC32State, guest_FPR17);
502 case 18: return offsetof(VexGuestPPC32State, guest_FPR18);
503 case 19: return offsetof(VexGuestPPC32State, guest_FPR19);
504 case 20: return offsetof(VexGuestPPC32State, guest_FPR20);
505 case 21: return offsetof(VexGuestPPC32State, guest_FPR21);
506 case 22: return offsetof(VexGuestPPC32State, guest_FPR22);
507 case 23: return offsetof(VexGuestPPC32State, guest_FPR23);
508 case 24: return offsetof(VexGuestPPC32State, guest_FPR24);
509 case 25: return offsetof(VexGuestPPC32State, guest_FPR25);
510 case 26: return offsetof(VexGuestPPC32State, guest_FPR26);
511 case 27: return offsetof(VexGuestPPC32State, guest_FPR27);
512 case 28: return offsetof(VexGuestPPC32State, guest_FPR28);
513 case 29: return offsetof(VexGuestPPC32State, guest_FPR29);
514 case 30: return offsetof(VexGuestPPC32State, guest_FPR30);
515 case 31: return offsetof(VexGuestPPC32State, guest_FPR31);
516 default: break;
517 }
518 vpanic("floatGuestRegOffset(ppc32)"); /*notreached*/
519}
520
521static IRExpr* getFReg ( UInt archreg )
522{
523 vassert(archreg < 32);
524 return IRExpr_Get( floatGuestRegOffset(archreg), Ity_F64 );
525}
526
527/* Ditto, but write to a reg instead. */
528static void putFReg ( UInt archreg, IRExpr* e )
529{
530 vassert(archreg < 32);
531 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_F64);
532 stmt( IRStmt_Put(floatGuestRegOffset(archreg), e) );
533}
534
535
536static Int vectorGuestRegOffset ( UInt archreg )
537{
538 vassert(archreg < 32);
539
540 switch (archreg) {
541 case 0: return offsetof(VexGuestPPC32State, guest_VR0);
542 case 1: return offsetof(VexGuestPPC32State, guest_VR1);
543 case 2: return offsetof(VexGuestPPC32State, guest_VR2);
544 case 3: return offsetof(VexGuestPPC32State, guest_VR3);
545 case 4: return offsetof(VexGuestPPC32State, guest_VR4);
546 case 5: return offsetof(VexGuestPPC32State, guest_VR5);
547 case 6: return offsetof(VexGuestPPC32State, guest_VR6);
548 case 7: return offsetof(VexGuestPPC32State, guest_VR7);
549 case 8: return offsetof(VexGuestPPC32State, guest_VR8);
550 case 9: return offsetof(VexGuestPPC32State, guest_VR9);
551 case 10: return offsetof(VexGuestPPC32State, guest_VR10);
552 case 11: return offsetof(VexGuestPPC32State, guest_VR11);
553 case 12: return offsetof(VexGuestPPC32State, guest_VR12);
554 case 13: return offsetof(VexGuestPPC32State, guest_VR13);
555 case 14: return offsetof(VexGuestPPC32State, guest_VR14);
556 case 15: return offsetof(VexGuestPPC32State, guest_VR15);
557 case 16: return offsetof(VexGuestPPC32State, guest_VR16);
558 case 17: return offsetof(VexGuestPPC32State, guest_VR17);
559 case 18: return offsetof(VexGuestPPC32State, guest_VR18);
560 case 19: return offsetof(VexGuestPPC32State, guest_VR19);
561 case 20: return offsetof(VexGuestPPC32State, guest_VR20);
562 case 21: return offsetof(VexGuestPPC32State, guest_VR21);
563 case 22: return offsetof(VexGuestPPC32State, guest_VR22);
564 case 23: return offsetof(VexGuestPPC32State, guest_VR23);
565 case 24: return offsetof(VexGuestPPC32State, guest_VR24);
566 case 25: return offsetof(VexGuestPPC32State, guest_VR25);
567 case 26: return offsetof(VexGuestPPC32State, guest_VR26);
568 case 27: return offsetof(VexGuestPPC32State, guest_VR27);
569 case 28: return offsetof(VexGuestPPC32State, guest_VR28);
570 case 29: return offsetof(VexGuestPPC32State, guest_VR29);
571 case 30: return offsetof(VexGuestPPC32State, guest_VR30);
572 case 31: return offsetof(VexGuestPPC32State, guest_VR31);
573 default: break;
574 }
575 vpanic("vextorGuestRegOffset(ppc32)"); /*notreached*/
576}
577
578static IRExpr* getVReg ( UInt archreg )
579{
580 vassert(archreg < 32);
581 return IRExpr_Get( vectorGuestRegOffset(archreg), Ity_V128 );
582}
583
584/* Ditto, but write to a reg instead. */
585static void putVReg ( UInt archreg, IRExpr* e )
586{
587 vassert(archreg < 32);
588 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_V128);
589 stmt( IRStmt_Put(vectorGuestRegOffset(archreg), e) );
590}
591
592static Int guestCR321offset ( UInt cr )
593{
594 switch (cr) {
595 case 0: return offsetof(VexGuestPPC32State, guest_CR0_321 );
596 case 1: return offsetof(VexGuestPPC32State, guest_CR1_321 );
597 case 2: return offsetof(VexGuestPPC32State, guest_CR2_321 );
598 case 3: return offsetof(VexGuestPPC32State, guest_CR3_321 );
599 case 4: return offsetof(VexGuestPPC32State, guest_CR4_321 );
600 case 5: return offsetof(VexGuestPPC32State, guest_CR5_321 );
601 case 6: return offsetof(VexGuestPPC32State, guest_CR6_321 );
602 case 7: return offsetof(VexGuestPPC32State, guest_CR7_321 );
603 default: vpanic("guestCR321offset(ppc32)");
604 }
605}
606
607static Int guestCR0offset ( UInt cr )
608{
609 switch (cr) {
610 case 0: return offsetof(VexGuestPPC32State, guest_CR0_0 );
611 case 1: return offsetof(VexGuestPPC32State, guest_CR1_0 );
612 case 2: return offsetof(VexGuestPPC32State, guest_CR2_0 );
613 case 3: return offsetof(VexGuestPPC32State, guest_CR3_0 );
614 case 4: return offsetof(VexGuestPPC32State, guest_CR4_0 );
615 case 5: return offsetof(VexGuestPPC32State, guest_CR5_0 );
616 case 6: return offsetof(VexGuestPPC32State, guest_CR6_0 );
617 case 7: return offsetof(VexGuestPPC32State, guest_CR7_0 );
618 default: vpanic("guestCR3offset(ppc32)");
619 }
620}
621
622static void putCR321 ( UInt cr, IRExpr* e )
623{
624 vassert(cr < 8);
625 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I8);
626 stmt( IRStmt_Put(guestCR321offset(cr), e) );
627}
628
629static void putCR0 ( UInt cr, IRExpr* e )
630{
631 vassert(cr < 8);
632 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I8);
633 stmt( IRStmt_Put(guestCR0offset(cr), e) );
634}
635
636static IRExpr* /* :: Ity_I8 */ getCR0 ( UInt cr )
637{
638 vassert(cr < 8);
639 return IRExpr_Get(guestCR0offset(cr), Ity_I8);
640}
641
642static IRExpr* /* :: Ity_I8 */ getCR321 ( UInt cr )
643{
644 vassert(cr < 8);
645 return IRExpr_Get(guestCR321offset(cr), Ity_I8);
646}
647
648static IRExpr* /* :: Ity_I8 */ getXER_SO ( void )
649{
650 return IRExpr_Get( OFFB_XER_SO, Ity_I8 );
651}
652
653// ROTL(src32, rot_amt5)
sewardjc9659532005-07-21 21:33:57 +0000654static IRExpr* ROTL32 ( IRExpr* src, IRExpr* rot_amt )
sewardjb51f0f42005-07-18 11:38:02 +0000655{
sewardjc9659532005-07-21 21:33:57 +0000656 IRExpr* masked;
cerionb85e8bb2005-02-16 08:54:33 +0000657 vassert(typeOfIRExpr(irbb->tyenv,src) == Ity_I32);
sewardjc9659532005-07-21 21:33:57 +0000658 vassert(typeOfIRExpr(irbb->tyenv,rot_amt) == Ity_I32);
sewardjb51f0f42005-07-18 11:38:02 +0000659
sewardjc9659532005-07-21 21:33:57 +0000660 masked
661 = unop(Iop_32to8, binop(Iop_And32, rot_amt, mkU32(31)));
sewardjb51f0f42005-07-18 11:38:02 +0000662
cerionb85e8bb2005-02-16 08:54:33 +0000663 // (src << rot_amt) | (src >> (32-rot_amt))
sewardjc9659532005-07-21 21:33:57 +0000664 /* Note: the MuxOX is not merely an optimisation; it's needed
665 because otherwise the Shr32 is a shift by the word size when
666 masked denotes zero. For rotates by immediates, a lot of
667 this junk gets folded out. */
668 return
669 IRExpr_Mux0X(
670 masked,
671 /* zero rotate. */
672 src,
673 /* non-zero rotate */
674 binop( Iop_Or32,
675 binop(Iop_Shl32, src, masked),
676 binop(Iop_Shr32, src, binop(Iop_Sub8, mkU8(32), masked))
677 )
678 );
cerion45b70ff2005-01-31 17:03:25 +0000679}
cerion896a1372005-01-25 12:24:25 +0000680
681
cerion896a1372005-01-25 12:24:25 +0000682/*------------------------------------------------------------*/
sewardjb51f0f42005-07-18 11:38:02 +0000683/*--- Helpers for condition codes. ---*/
cerion896a1372005-01-25 12:24:25 +0000684/*------------------------------------------------------------*/
685
sewardjb51f0f42005-07-18 11:38:02 +0000686/* Condition register layout.
cerion896a1372005-01-25 12:24:25 +0000687
sewardjb51f0f42005-07-18 11:38:02 +0000688 In the hardware, CR is laid out like this. The leftmost end is the
689 most significant bit in the register; however the IBM documentation
690 numbers the bits backwards for some reason.
691
692 CR0 CR1 .......... CR6 CR7
693 0 .. 3 ....................... 28 .. 31 (IBM bit numbering)
694 31 28 3 0 (normal bit numbering)
695
696 Each CR field is 4 bits:
697
698 < > == SO
699
700 Hence in IBM's notation, BI=0 indicates CR7.SO, BI=1 is CR7.==,
701 etc.
702
703 Indexing from BI to guest state:
704
705 let n = BI / 4
706 off = BI % 4
707 this references CR n:
708
709 off==3 -> guest_CRn_SO
710 off==2 -> guest_CRn_123 >> 1
711 off==1 -> guest_CRn_123 >> 2
712 off==0 -> guest_CRn_123 >> 3
713
714 Bear in mind the only significant bit in guest_CRn_SO is bit 0
715 (normal notation) and in guest_CRn_123 the significant bits are
716 3, 2 and 1 (normal notation).
717*/
718/* Fetch the specified CR bit (as per IBM/hardware notation) and
719 return it at the bottom of an I32; the top 31 bits are guaranteed
720 to be zero. */
721static IRExpr* /* :: Ity_I32 */ getCRbit ( UInt bi )
cerion896a1372005-01-25 12:24:25 +0000722{
sewardjb51f0f42005-07-18 11:38:02 +0000723 UInt n = bi / 4;
724 UInt off = bi % 4;
725 vassert(bi < 32);
726 if (off == 3) {
727 /* Fetch the SO bit for this CR field */
728 /* Note: And32 is redundant paranoia iff guest state only has 0
729 or 1 in that slot. */
730 return binop(Iop_And32, unop(Iop_8Uto32, getCR0(n)), mkU32(1));
731 } else {
732 /* Fetch the <, > or == bit for this CR field */
733 return binop( Iop_And32,
734 binop( Iop_Shr32,
735 unop(Iop_8Uto32, getCR321(n)),
736 mkU8(3-off) ),
737 mkU32(1) );
738 }
cerion91ad5362005-01-27 23:02:41 +0000739}
740
sewardjb51f0f42005-07-18 11:38:02 +0000741/* Dually, write the least significant bit of BIT to the specified CR
742 bit. Indexing as per getCRbit. */
743static void putCRbit ( UInt bi, IRExpr* bit )
744{
745 IRExpr* safe;
746 vassert(typeOfIRExpr(irbb->tyenv,bit) == Ity_I32);
747 safe = binop(Iop_And32, bit, mkU32(1));
748 UInt n = bi / 4;
749 UInt off = bi % 4;
750 vassert(bi < 32);
751 if (off == 3) {
752 /* This is the SO bit for this CR field */
753 putCR0(n, unop(Iop_32to8, safe));
754 } else {
755 off = 3 - off;
756 vassert(off == 1 || off == 2 || off == 3);
757 putCR321(
758 n,
759 unop( Iop_32to8,
760 binop( Iop_Or32,
761 /* old value with field masked out */
762 binop(Iop_And32, unop(Iop_8Uto32, getCR321(n)),
763 mkU32(~(1 << off))),
764 /* new value in the right place */
765 binop(Iop_Shl32, safe, mkU8(off))
766 )
767 )
768 );
769 }
770}
771
772
773/* Fetch the specified CR bit (as per IBM/hardware notation) and
774 return it somewhere in an I32; it does not matter where, but
775 whichever bit it is, all other bits are guaranteed to be zero. In
776 other words, the I32-typed expression will be zero if the bit is
777 zero and nonzero if the bit is 1. Write into *where the index
778 of where the bit will be. */
779
780static IRExpr* /* :: Ity_I32 */ getCRbit_anywhere ( UInt bi, Int* where )
781{
782 UInt n = bi / 4;
783 UInt off = bi % 4;
784 vassert(bi < 32);
785 if (off == 3) {
786 /* Fetch the SO bit for this CR field */
787 /* Note: And32 is redundant paranoia iff guest state only has 0
788 or 1 in that slot. */
789 *where = 0;
790 return binop(Iop_And32, unop(Iop_8Uto32, getCR0(n)), mkU32(1));
791 } else {
792 /* Fetch the <, > or == bit for this CR field */
793 *where = 3-off;
794 return binop( Iop_And32,
795 unop(Iop_8Uto32, getCR321(n)),
796 mkU32(1 << (3-off)) );
797 }
798}
799
800
801/* Synthesise the entire CR into a single word. Expensive. */
802
803static IRExpr* /* :: Ity_I32 */ getEntireCR ( void )
804{
805# define FIELD(_n) \
806 binop(Iop_Shl32, \
807 unop(Iop_8Uto32, \
808 binop(Iop_Or8, \
809 binop(Iop_And8, getCR321(_n), mkU8(7<<1)), \
810 binop(Iop_And8, getCR0(_n), mkU8(1)) \
811 ) \
812 ), \
813 mkU8(4 * (7-(_n))) \
814 )
815
816 return binop(Iop_Or32,
817 binop(Iop_Or32,
818 binop(Iop_Or32, FIELD(0), FIELD(1)),
819 binop(Iop_Or32, FIELD(2), FIELD(3))
820 ),
821 binop(Iop_Or32,
822 binop(Iop_Or32, FIELD(4), FIELD(5)),
823 binop(Iop_Or32, FIELD(6), FIELD(7))
824 )
825 );
826# undef FIELD
827}
828
829static void putCRfields ( IRExpr* w32, UInt mask )
830{
831 IRTemp t;
832 Int cr;
833 vassert(typeOfIRExpr(irbb->tyenv,w32) == Ity_I32);
834 vassert(mask < 256);
835 for (cr = 0; cr < 8; cr++) {
836 if ((mask & (1 << (7-cr))) == 0)
837 continue;
838 t = newTemp(Ity_I32);
839 assign( t, binop(Iop_Shr32, w32, mkU8(4*(7-cr))) );
840 putCR0( cr, unop(Iop_32to8,
841 binop(Iop_And32, mkexpr(t), mkU32(1))) );
842 putCR321( cr, unop(Iop_32to8,
843 binop(Iop_And32, mkexpr(t), mkU32(7<<1))) );
844 }
845}
846
847
848//zz /* -------------- Evaluating the flags-thunk. -------------- */
849//zz
850//zz /* Calculate CR7 (IBM CR0) conditional flags */
851//zz static IRExpr* mk_ppc32g_calculate_cr7 ( void )
852//zz {
853//zz IRExpr** args =
854//zz mkIRExprVec_3( IRExpr_Get(OFFB_CC_OP, Ity_I32),
855//zz IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
856//zz IRExpr_Get(OFFB_CC_DEP2, Ity_I32) );
857//zz IRExpr* call
858//zz = mkIRExprCCall(
859//zz Ity_I32,
860//zz 0/*regparm*/,
861//zz "ppc32g_calculate_cr7", &ppc32g_calculate_cr7,
862//zz args
863//zz );
864//zz
865//zz // TODO
866//zz // 02/02/05 - leaving definedness stuff 'till get memcheck working well.
867//zz
868//zz /* Exclude OP from definedness checking. We're only
869//zz interested in DEP1 and DEP2. */
870//zz // call->Iex.CCall.cee->mcx_mask = 1;
871//zz
872//zz return call;
873//zz }
874//zz
875//zz /* Calculate XER_OV flag */
876//zz static IRExpr* mk_ppc32g_calculate_xer_ov ( UInt op, IRExpr* res,
877//zz IRExpr* argL, IRExpr* argR )
878//zz {
879//zz IRExpr** args;
880//zz IRExpr* call;
881//zz vassert(op < PPC32G_FLAG_OP_NUMBER);
882//zz vassert(typeOfIRExpr(irbb->tyenv,res) == Ity_I32);
883//zz vassert(typeOfIRExpr(irbb->tyenv,argL) == Ity_I32);
884//zz vassert(typeOfIRExpr(irbb->tyenv,argR) == Ity_I32);
885//zz
886//zz args = mkIRExprVec_4( mkU32(op), res, argL, argR );
887//zz
888//zz call
889//zz = mkIRExprCCall(
890//zz Ity_I32,
891//zz 0/*regparm*/,
892//zz "ppc32g_calculate_xer_ov", &ppc32g_calculate_xer_ov,
893//zz args
894//zz );
895//zz return binop(Iop_And32, mkU32(1), call);
896//zz }
897
898/* Calculate XER_CA flag. RES is the result of applying OP to ARGL
899 and ARGR, and OLDCA is the old carry flag. The latter may be zero
900 if it is known that OP does not need to consult it. */
901
902static IRExpr* mk_ppc32g_calculate_xer_ca ( UInt op,
903 IRExpr* res,
904 IRExpr* argL,
905 IRExpr* argR,
906 IRExpr* oldca )
cerion91ad5362005-01-27 23:02:41 +0000907{
sewardj9a036bf2005-03-14 18:19:08 +0000908 IRExpr** args;
909 IRExpr* call;
cerion38674602005-02-08 02:19:25 +0000910 vassert(op < PPC32G_FLAG_OP_NUMBER);
sewardjb51f0f42005-07-18 11:38:02 +0000911 vassert(typeOfIRExpr(irbb->tyenv,res) == Ity_I32);
912 vassert(typeOfIRExpr(irbb->tyenv,argL) == Ity_I32);
913 vassert(typeOfIRExpr(irbb->tyenv,argR) == Ity_I32);
914 vassert(typeOfIRExpr(irbb->tyenv,oldca) == Ity_I32);
cerion62bec572005-02-01 21:29:39 +0000915
sewardjb51f0f42005-07-18 11:38:02 +0000916 args = mkIRExprVec_5( mkU32(op), res, argL, argR, oldca );
cerion995bc362005-02-03 11:03:31 +0000917
sewardj9a036bf2005-03-14 18:19:08 +0000918 call
cerion91ad5362005-01-27 23:02:41 +0000919 = mkIRExprCCall(
920 Ity_I32,
921 0/*regparm*/,
922 "ppc32g_calculate_xer_ca", &ppc32g_calculate_xer_ca,
923 args
924 );
cerion7342c372005-03-03 17:36:23 +0000925 return binop(Iop_And32, mkU32(1), call);
cerion91ad5362005-01-27 23:02:41 +0000926}
927
928
sewardjb51f0f42005-07-18 11:38:02 +0000929/* Set the CR0 flags following an arithmetic operation.
930 (Condition Register CR0 Field Definition, PPC32 p60)
cerion896a1372005-01-25 12:24:25 +0000931*/
sewardj20ef5472005-07-21 14:48:31 +0000932static void set_CR0 ( IRExpr* result )
cerion896a1372005-01-25 12:24:25 +0000933{
cerion62bec572005-02-01 21:29:39 +0000934 vassert(typeOfIRExpr(irbb->tyenv,result) == Ity_I32);
sewardjb51f0f42005-07-18 11:38:02 +0000935 putCR321( 0, unop(Iop_32to8,
936 binop(Iop_CmpORD32S, result, mkU32(0))) );
937 putCR0( 0, getXER_SO() );
cerion896a1372005-01-25 12:24:25 +0000938}
cerion896a1372005-01-25 12:24:25 +0000939
sewardj20ef5472005-07-21 14:48:31 +0000940
941/* RES is the result of doing OP on ARGL and ARGR. Set %XER.OV and
942 %XER.SO accordingly. */
943
944static void set_XER_OV( UInt op, IRExpr* res,
945 IRExpr* argL, IRExpr* argR )
946{
947 IRTemp t64;
948 IRExpr* xer_ov;
949 vassert(op < PPC32G_FLAG_OP_NUMBER);
950 vassert(typeOfIRExpr(irbb->tyenv,res) == Ity_I32);
951 vassert(typeOfIRExpr(irbb->tyenv,argL) == Ity_I32);
952 vassert(typeOfIRExpr(irbb->tyenv,argR) == Ity_I32);
953
954# define INT32_MIN 0x80000000
955
956# define XOR2(_aa,_bb) \
957 binop(Iop_Xor32,(_aa),(_bb))
958
959# define XOR3(_cc,_dd,_ee) \
960 binop(Iop_Xor32,binop(Iop_Xor32,(_cc),(_dd)),(_ee))
961
962# define AND3(_ff,_gg,_hh) \
963 binop(Iop_And32,binop(Iop_And32,(_ff),(_gg)),(_hh))
964
965#define NOT(_jj) \
966 unop(Iop_Not32, (_jj))
967
968 switch (op) {
969
970 case /* 0 */ PPC32G_FLAG_OP_ADD:
971 case /* 1 */ PPC32G_FLAG_OP_ADDE:
972 /* (argL^argR^-1) & (argL^res) & (1<<31) ?1:0 */
973 // i.e. ((both_same_sign) & (sign_changed) & (sign_mask))
974 xer_ov
975 = AND3( XOR3(argL,argR,mkU32(-1)),
976 XOR2(argL,res),
977 mkU32(INT32_MIN) );
978 /* xer_ov can only be 0 or 1<<31 */
979 xer_ov
980 = binop(Iop_Shr32, xer_ov, mkU8(31) );
981 break;
982
983 case /* 2 */ PPC32G_FLAG_OP_DIVW:
984 /* (argL == INT32_MIN && argR == -1) || argR == 0 */
985 xer_ov
986 = mkOR1(
987 mkAND1(
988 binop(Iop_CmpEQ32, argL, mkU32(INT32_MIN)),
989 binop(Iop_CmpEQ32, argR, mkU32(-1))
990 ),
991 binop(Iop_CmpEQ32, argR, mkU32(0) )
992 );
993 xer_ov
994 = unop(Iop_1Uto32, xer_ov);
995 break;
996
997 case /* 3 */ PPC32G_FLAG_OP_DIVWU:
998 /* argR == 0 */
999 xer_ov
1000 = unop(Iop_1Uto32, binop(Iop_CmpEQ32, argR, mkU32(0)));
1001 break;
1002
1003 case /* 4 */ PPC32G_FLAG_OP_MULLW:
1004 /* OV true if result can't be represented in 32 bits
1005 i.e sHi != sign extension of sLo */
1006 t64 = newTemp(Ity_I64);
sewardj6fa6bf12005-07-21 17:07:18 +00001007 assign( t64, binop(Iop_MullS32, argL, argR) );
sewardj20ef5472005-07-21 14:48:31 +00001008 xer_ov
1009 = binop( Iop_CmpNE32,
1010 unop(Iop_64HIto32, mkexpr(t64)),
1011 binop( Iop_Sar32,
1012 unop(Iop_64to32, mkexpr(t64)),
1013 mkU8(31))
1014 );
1015 xer_ov
1016 = unop(Iop_1Uto32, xer_ov);
1017 break;
1018
1019 case /* 5 */ PPC32G_FLAG_OP_NEG:
1020 /* argL == INT32_MIN */
1021 xer_ov
1022 = unop( Iop_1Uto32,
1023 binop(Iop_CmpEQ32, argL, mkU32(INT32_MIN)) );
1024 break;
1025
1026 case /* 6 */ PPC32G_FLAG_OP_SUBF:
1027 case /* 7 */ PPC32G_FLAG_OP_SUBFC:
1028 case /* 8 */ PPC32G_FLAG_OP_SUBFE:
1029 /* ((~argL)^argR^-1) & ((~argL)^res) & (1<<31) ?1:0; */
1030 xer_ov
1031 = AND3( XOR3(NOT(argL),argR,mkU32(-1)),
1032 XOR2(NOT(argL),res),
1033 mkU32(INT32_MIN) );
1034 /* xer_ov can only be 0 or 1<<31 */
1035 xer_ov
1036 = binop(Iop_Shr32, xer_ov, mkU8(31) );
1037 break;
1038
1039 default:
1040 vex_printf("set_XER_OV: op = %d\n", op);
1041 vpanic("set_XER_OV(ppc32)");
1042 }
1043
1044 /* xer_ov MUST denote either 0 or 1, no other value allowed */
1045 stmt( IRStmt_Put( OFFB_XER_OV, unop(Iop_32to8, xer_ov) ) );
1046
1047 /* Update the summary overflow */
1048 stmt( IRStmt_Put(
1049 OFFB_XER_SO,
1050 binop(Iop_Or8, IRExpr_Get( OFFB_XER_SO, Ity_I8 ),
1051 IRExpr_Get( OFFB_XER_OV, Ity_I8 ) )
1052 ));
1053
1054# undef INT32_MIN
1055# undef AND3
1056# undef XOR3
1057# undef XOR2
1058# undef NOT
1059}
1060
cerion38674602005-02-08 02:19:25 +00001061
sewardjb51f0f42005-07-18 11:38:02 +00001062/* RES is the result of doing OP on ARGL and ARGR with the old %XER.CA
1063 value being OLDCA. Set %XER.CA accordingly. */
cerione9d361a2005-03-04 17:35:29 +00001064
sewardjb51f0f42005-07-18 11:38:02 +00001065static void set_XER_CA( UInt op,
1066 IRExpr* res,
1067 IRExpr* argL,
1068 IRExpr* argR,
1069 IRExpr* oldca )
cerion38674602005-02-08 02:19:25 +00001070{
sewardj9a036bf2005-03-14 18:19:08 +00001071 IRExpr* xer_ca;
cerionb85e8bb2005-02-16 08:54:33 +00001072 vassert(op < PPC32G_FLAG_OP_NUMBER);
sewardjb51f0f42005-07-18 11:38:02 +00001073 vassert(typeOfIRExpr(irbb->tyenv,res) == Ity_I32);
1074 vassert(typeOfIRExpr(irbb->tyenv,argL) == Ity_I32);
1075 vassert(typeOfIRExpr(irbb->tyenv,argR) == Ity_I32);
1076 vassert(typeOfIRExpr(irbb->tyenv,oldca) == Ity_I32);
cerion70e24122005-03-16 00:27:37 +00001077
sewardj20ef5472005-07-21 14:48:31 +00001078 /* Incoming oldca is assumed to hold the values 0 or 1 only. This
1079 seems reasonable given that it's always generated by
1080 get_XER_CA(), which masks it accordingly. In any case it being
1081 0 or 1 is an invariant of the ppc32 guest state representation;
1082 if it has any other value, that invariant has been violated. */
cerione9d361a2005-03-04 17:35:29 +00001083
sewardj20ef5472005-07-21 14:48:31 +00001084 switch (op) {
1085
1086 case /* 0 */ PPC32G_FLAG_OP_ADD:
1087 /* res <u argL */
1088 xer_ca
1089 = unop(Iop_1Uto32, binop(Iop_CmpLT32U, res, argL));
1090 break;
1091
1092 case /* 1 */ PPC32G_FLAG_OP_ADDE:
1093 /* res <u argL || (old_ca==1 && res==argL) */
1094 xer_ca
1095 = mkOR1(
1096 binop(Iop_CmpLT32U, res, argL),
1097 mkAND1(
1098 binop(Iop_CmpEQ32, oldca, mkU32(1)),
1099 binop(Iop_CmpEQ32, res, argL)
1100 )
1101 );
1102 xer_ca
1103 = unop(Iop_1Uto32, xer_ca);
1104 break;
1105
1106 case /* 8 */ PPC32G_FLAG_OP_SUBFE:
1107 /* res <u argR || (old_ca==1 && res==argR) */
1108 xer_ca
1109 = mkOR1(
1110 binop(Iop_CmpLT32U, res, argR),
1111 mkAND1(
1112 binop(Iop_CmpEQ32, oldca, mkU32(1)),
1113 binop(Iop_CmpEQ32, res, argR)
1114 )
1115 );
1116 xer_ca
1117 = unop(Iop_1Uto32, xer_ca);
1118 break;
1119
1120 case /* 7 */ PPC32G_FLAG_OP_SUBFC:
1121 case /* 9 */ PPC32G_FLAG_OP_SUBFI:
1122 /* res <=u argR */
1123 xer_ca
1124 = unop(Iop_1Uto32, binop(Iop_CmpLE32U, res, argR));
1125 break;
1126
1127 case /* 10 */ PPC32G_FLAG_OP_SRAW:
1128 /* The shift amount is guaranteed to be in 0 .. 63 inclusive.
1129 If it is <= 31, behave like SRAWI; else XER.CA is the sign
1130 bit of argL. */
1131 /* This term valid for shift amount < 32 only */
1132 xer_ca
1133 = binop(
1134 Iop_And32,
1135 binop(Iop_Sar32, argL, mkU8(31)),
1136 binop( Iop_And32,
1137 argL,
1138 binop( Iop_Sub32,
1139 binop(Iop_Shl32, mkU32(1), unop(Iop_32to8,argR)),
1140 mkU32(1) )
1141 )
1142 );
1143 xer_ca
1144 = IRExpr_Mux0X(
1145 /* shift amt > 31 ? */
1146 unop(Iop_1Uto8, binop(Iop_CmpLT32U, mkU32(31), argR)),
1147 /* no -- be like srawi */
1148 unop(Iop_1Uto32, binop(Iop_CmpNE32, xer_ca, mkU32(0))),
1149 /* yes -- get sign bit of argL */
1150 binop(Iop_Shr32, argL, mkU8(31))
1151 );
1152 break;
1153
1154 case /* 11 */ PPC32G_FLAG_OP_SRAWI:
1155 /* xer_ca is 1 iff src was negative and bits_shifted_out !=
1156 0. Since the shift amount is known to be in the range
1157 0 .. 31 inclusive the following seems viable:
1158 xer.ca == 1 iff the following is nonzero:
1159 (argL >>s 31) -- either all 0s or all 1s
1160 & (argL & (1<<argR)-1) -- the stuff shifted out */
1161 xer_ca
1162 = binop(
1163 Iop_And32,
1164 binop(Iop_Sar32, argL, mkU8(31)),
1165 binop( Iop_And32,
1166 argL,
1167 binop( Iop_Sub32,
1168 binop(Iop_Shl32, mkU32(1), unop(Iop_32to8,argR)),
1169 mkU32(1) )
1170 )
1171 );
1172 xer_ca
1173 = unop(Iop_1Uto32, binop(Iop_CmpNE32, xer_ca, mkU32(0)));
1174 break;
1175
1176 default:
1177 vex_printf("set_XER_CA: op = %d\n", op);
1178 vpanic("set_XER_CA(ppc32)");
1179 }
1180
1181 /* xer_ca MUST denote either 0 or 1, no other value allowed */
1182 stmt( IRStmt_Put( OFFB_XER_CA, unop(Iop_32to8, xer_ca) ) );
sewardjb51f0f42005-07-18 11:38:02 +00001183}
1184
1185static IRExpr* /* :: Ity_I32 */ get_XER_CA ( void )
1186{
1187 return binop( Iop_And32,
1188 unop( Iop_8Uto32,
1189 IRExpr_Get(OFFB_XER_CA, Ity_I8) ),
1190 mkU32(1) );
cerion38674602005-02-08 02:19:25 +00001191}
1192
cerion896a1372005-01-25 12:24:25 +00001193
1194
sewardje14bb9f2005-07-22 09:39:02 +00001195/*------------------------------------------------------------*/
1196/*--- Abstract register interface --- */
1197/*------------------------------------------------------------*/
1198
1199/* Get a masked word from the given reg */
1200static IRExpr* getReg_masked ( PPC32SPR reg, UInt mask )
1201{
1202 IRTemp val = newTemp(Ity_I32);
1203 vassert( reg < PPC32_SPR_MAX );
1204
1205 switch (reg) {
1206
1207 case PPC32_SPR_FPSCR: {
1208 vassert((mask & 0x3) == 0x3 || (mask & 0x3) == 0x0);
1209 vassert((mask & 0xF000) == 0xF000 || (mask & 0xF000) == 0x0);
1210 /* all masks now refer to valid fields */
1211
1212 /* Vex-generated code expects to run with the FPSCR set as follows:
1213 all exceptions masked, round-to-nearest.
1214 This corresponds to a FPSCR value of 0x0. */
1215
1216 /* We're only keeping track of the rounding mode,
1217 so if the mask isn't asking for this, just return 0x0 */
1218 if (mask & 0x3) {
1219 assign( val, IRExpr_Get(OFFB_FPROUND, Ity_I32) );
1220 } else {
1221 assign( val, mkU32(0x0) );
1222 }
1223 break;
1224 }
1225
sewardjb51f0f42005-07-18 11:38:02 +00001226//zz case PPC32_SPR_VRSAVE:
1227//zz assign( val, IRExpr_Get(OFFB_VRSAVE, Ity_I32) );
1228//zz break;
1229//zz
1230//zz case PPC32_SPR_VSCR:
1231//zz // All other bits are 'Reserved'. Returning zero for these bits.
1232//zz mask = mask & 0x00010001;
1233//zz assign( val, IRExpr_Get(OFFB_VSCR, Ity_I32) );
1234//zz break;
sewardje14bb9f2005-07-22 09:39:02 +00001235
1236 default:
1237 vpanic("getReg(ppc32)");
1238 }
1239
1240 if (mask != 0xFFFFFFFF) {
1241 return binop(Iop_And32, mkexpr(val), mkU32(mask));
1242 } else {
1243 return mkexpr(val);
1244 }
1245}
1246
sewardjb51f0f42005-07-18 11:38:02 +00001247//zz /* Get word from the given reg */
1248//zz static IRExpr* getReg ( PPC32SPR reg )
1249//zz {
1250//zz vassert( reg < PPC32_SPR_MAX );
1251//zz return getReg_masked( reg, 0xFFFFFFFF );
1252//zz }
1253//zz
1254//zz /* Get a right-shifted nibble from given reg[field_idx]
1255//zz returns zero padded word */
1256//zz static IRExpr* getReg_field ( PPC32SPR reg, UInt field_idx )
1257//zz {
1258//zz IRExpr* fld;
1259//zz vassert( field_idx < 8 );
1260//zz vassert( reg < PPC32_SPR_MAX );
1261//zz
1262//zz fld = getReg_masked( reg, (0xF << (field_idx*4)) );
1263//zz
1264//zz if (field_idx != 0) {
1265//zz fld = binop(Iop_Shr32, fld, mkU8(toUChar(field_idx * 4)));
1266//zz }
1267//zz return fld;
1268//zz }
1269//zz
1270//zz /* Get a right-shifted bit from given reg[bit_idx]
1271//zz returns zero padded word */
1272//zz static IRExpr* getReg_bit ( PPC32SPR reg, UInt bit_idx )
1273//zz {
1274//zz IRExpr* val;
1275//zz vassert( bit_idx < 32 );
1276//zz vassert( reg < PPC32_SPR_MAX );
1277//zz
1278//zz val = getReg_masked( reg, 1<<bit_idx );
1279//zz
1280//zz if (bit_idx != 0) {
1281//zz val = binop(Iop_Shr32, val, mkU8(toUChar(bit_idx)));
1282//zz }
1283//zz return val;
1284//zz }
sewardje14bb9f2005-07-22 09:39:02 +00001285
1286
1287
1288/* Write masked src to the given reg */
1289static void putReg_masked ( PPC32SPR reg, IRExpr* src, UInt mask )
1290{
1291 vassert( reg < PPC32_SPR_MAX );
1292 vassert( typeOfIRExpr(irbb->tyenv,src ) == Ity_I32 );
1293
1294 switch (reg) {
sewardjb51f0f42005-07-18 11:38:02 +00001295//zz case PPC32_SPR_CIA:
1296//zz vassert(mask == 0xFFFFFFFF); // Only ever need whole reg
1297//zz stmt( IRStmt_Put( OFFB_CIA, src ) );
1298//zz break;
sewardje14bb9f2005-07-22 09:39:02 +00001299
1300 case PPC32_SPR_FPSCR:
1301 vassert((mask & 0x3) == 0x3 || (mask & 0x3) == 0x0);
1302 vassert((mask & 0xF000) == 0xF000 || (mask & 0xF000) == 0x0);
1303 /* all masks now refer to valid fields */
1304
1305 /* Allow writes to Rounding Mode */
1306 if (mask & 0x3) {
1307 stmt( IRStmt_Put( OFFB_FPROUND,
1308 binop(Iop_And32, src, mkU32(0x3)) ));
1309 }
1310
1311 /*
1312 Give EmWarn for attempted writes to:
1313 - Exception Controls
1314 - Non-IEEE Mode
1315 */
1316 if (mask & 0xFC) { // Exception Control, Non-IEE mode
1317 VexEmWarn ew = EmWarn_PPC32exns;
1318
1319 /* If any of the src::exception_control bits are actually set,
1320 side-exit to the next insn, reporting the warning,
1321 so that Valgrind's dispatcher sees the warning. */
1322 put_emwarn( mkU32(ew) );
1323 stmt(
1324 IRStmt_Exit(
1325 binop(Iop_CmpNE32, mkU32(ew), mkU32(EmWarn_NONE)),
1326 Ijk_EmWarn,
1327 IRConst_U32(guest_CIA_curr_instr + 4)
1328 )
1329 );
1330 }
1331
1332 /*
1333 Ignore all other writes
1334 */
1335 break;
1336
sewardjb51f0f42005-07-18 11:38:02 +00001337//zz case PPC32_SPR_VRSAVE:
1338//zz vassert(mask == 0xFFFFFFFF); // Only ever need whole reg
1339//zz stmt( IRStmt_Put( OFFB_VRSAVE, src ) );
1340//zz break;
1341//zz
1342//zz case PPC32_SPR_VSCR:
1343//zz //CAB: There are only 2 valid bits in VSCR - maybe split into two vars...
1344//zz
1345//zz // All other bits are 'Reserved'. Ignoring writes to these bits.
1346//zz stmt( IRStmt_Put( OFFB_VSCR,
1347//zz binop(Iop_Or32,
1348//zz binop(Iop_And32, src, mkU32(mask & 0x00010001)),
1349//zz getReg_masked( PPC32_SPR_VSCR, (~mask & 0x00010001) ))));
1350//zz break;
1351//zz }
sewardje14bb9f2005-07-22 09:39:02 +00001352
1353 default:
1354 vpanic("putReg(ppc32)");
1355 }
1356}
1357
sewardjb51f0f42005-07-18 11:38:02 +00001358//zz /* Write src to the given reg */
1359//zz static void putReg ( PPC32SPR reg, IRExpr* src )
1360//zz {
1361//zz vassert( typeOfIRExpr(irbb->tyenv,src ) == Ity_I32 );
1362//zz vassert( reg < PPC32_SPR_MAX );
1363//zz putReg_masked( reg, src, 0xFFFFFFFF );
1364//zz }
cerion62bec572005-02-01 21:29:39 +00001365
sewardjb51f0f42005-07-18 11:38:02 +00001366static void putSPR ( PPC32SPR reg, IRExpr* src )
cerion76222262005-02-05 13:45:57 +00001367{
sewardjb51f0f42005-07-18 11:38:02 +00001368 vassert( typeOfIRExpr(irbb->tyenv,src ) == Ity_I32 );
cerionb85e8bb2005-02-16 08:54:33 +00001369 switch (reg) {
sewardjb51f0f42005-07-18 11:38:02 +00001370 case PPC32_SPR_CIA:
1371 stmt( IRStmt_Put( OFFB_CIA, src ) );
1372 break;
1373 case PPC32_SPR_LR:
1374 stmt( IRStmt_Put( OFFB_LR, src ) );
1375 break;
1376 case PPC32_SPR_CTR:
1377 stmt( IRStmt_Put( OFFB_CTR, src ) );
1378 break;
1379 case PPC32_SPR_VRSAVE:
1380 stmt( IRStmt_Put( OFFB_VRSAVE, src ) );
1381 break;
1382 default:
1383 vpanic("putSPR(ppc32)");
cerion3007c7f2005-02-23 23:13:29 +00001384 }
cerion76222262005-02-05 13:45:57 +00001385}
cerion38674602005-02-08 02:19:25 +00001386
sewardjb51f0f42005-07-18 11:38:02 +00001387static IRExpr* /* :: Ity_I32 */ getSPR ( PPC32SPR reg )
cerion38674602005-02-08 02:19:25 +00001388{
cerionb85e8bb2005-02-16 08:54:33 +00001389 switch (reg) {
sewardjb51f0f42005-07-18 11:38:02 +00001390 case PPC32_SPR_LR:
1391 return IRExpr_Get( OFFB_LR, Ity_I32 );
1392 case PPC32_SPR_CTR:
1393 return IRExpr_Get( OFFB_CTR, Ity_I32 );
1394 case PPC32_SPR_VRSAVE:
1395 return IRExpr_Get( OFFB_VRSAVE, Ity_I32 );
1396 default:
1397 vpanic("getSPR(ppc32)");
cerione9d361a2005-03-04 17:35:29 +00001398 }
cerion76222262005-02-05 13:45:57 +00001399}
1400
sewardjb51f0f42005-07-18 11:38:02 +00001401//zz
1402//zz /* Write least-significant nibble of src to reg[field_idx] */
1403//zz static void putReg_field ( PPC32SPR reg, IRExpr* src, UInt field_idx )
1404//zz {
1405//zz vassert( typeOfIRExpr(irbb->tyenv,src ) == Ity_I32 );
1406//zz vassert( field_idx < 8 );
1407//zz vassert( reg < PPC32_SPR_MAX );
1408//zz
1409//zz if (field_idx != 0) {
1410//zz src = binop(Iop_Shl32, src, mkU8(toUChar(field_idx * 4)));
1411//zz }
1412//zz putReg_masked( reg, src, (0xF << (field_idx*4)) );
1413//zz }
1414//zz
1415//zz /* Write least-significant bit of src to reg[bit_idx] */
1416//zz static void putReg_bit ( PPC32SPR reg, IRExpr* src, UInt bit_idx )
1417//zz {
1418//zz vassert( typeOfIRExpr(irbb->tyenv,src ) == Ity_I32 );
1419//zz vassert( bit_idx < 32 );
1420//zz vassert( reg < PPC32_SPR_MAX );
1421//zz
1422//zz if (bit_idx != 0) {
1423//zz src = binop(Iop_Shl32, src, mkU8(toUChar(bit_idx)));
1424//zz }
1425//zz putReg_masked( reg, src, (1<<bit_idx) );
1426//zz }
cerion76222262005-02-05 13:45:57 +00001427
1428
cerione9d361a2005-03-04 17:35:29 +00001429/*------------------------------------------------------------*/
cerion3d870a32005-03-18 12:23:33 +00001430/*--- Integer Instruction Translation --- */
cerione9d361a2005-03-04 17:35:29 +00001431/*------------------------------------------------------------*/
cerion896a1372005-01-25 12:24:25 +00001432
cerion91ad5362005-01-27 23:02:41 +00001433/*
1434 Integer Arithmetic Instructions
1435*/
cerion645c9302005-01-31 10:09:59 +00001436static Bool dis_int_arith ( UInt theInstr )
cerion91ad5362005-01-27 23:02:41 +00001437{
cerionb85e8bb2005-02-16 08:54:33 +00001438 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
1439 UChar Rd_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
1440 UChar Ra_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
1441
1442 /* D-Form */
1443 UInt SIMM_16 = (theInstr >> 0) & 0xFFFF; /* theInstr[0:15] */
1444
1445 /* XO-Form */
1446 UChar Rb_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
1447 UChar flag_OE = toUChar((theInstr >> 10) & 1); /* theInstr[10] */
1448 UInt opc2 = (theInstr >> 1) & 0x1FF; /* theInstr[1:9] */
1449 UChar flag_Rc = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
1450
1451 UInt EXTS_SIMM = 0;
1452
1453 IRTemp Ra = newTemp(Ity_I32);
1454 IRTemp Rb = newTemp(Ity_I32);
1455 IRTemp Rd = newTemp(Ity_I32);
1456 IRTemp res64 = newTemp(Ity_I64); // multiplies need this.
cerion70e24122005-03-16 00:27:37 +00001457
sewardjb51f0f42005-07-18 11:38:02 +00001458//zz UInt flag_op = PPC32G_FLAG_OP_NUMBER;
cerionb85e8bb2005-02-16 08:54:33 +00001459 Bool do_rc = False;
cerion91ad5362005-01-27 23:02:41 +00001460
cerionb85e8bb2005-02-16 08:54:33 +00001461 assign( Ra, getIReg(Ra_addr) );
1462 assign( Rb, getIReg(Rb_addr) ); // XO-Form: Rd, Ra, Rb
1463 EXTS_SIMM = extend_s_16to32(SIMM_16); // D-Form: Rd, Ra, EXTS(SIMM)
cerion932ad942005-01-30 10:18:50 +00001464
sewardjb51f0f42005-07-18 11:38:02 +00001465//zz assign( xer_ca, getReg_bit( PPC32_SPR_XER, SHIFT_XER_CA ) );
1466
cerionb85e8bb2005-02-16 08:54:33 +00001467 switch (opc1) {
cerionb85e8bb2005-02-16 08:54:33 +00001468 /* D-Form */
cerione9d361a2005-03-04 17:35:29 +00001469 case 0x0C: // addic (Add Immediate Carrying, PPC32 p351
cerion3007c7f2005-02-23 23:13:29 +00001470 DIP("addic r%d,r%d,0x%x\n", Rd_addr, Ra_addr, EXTS_SIMM);
cerion4561acb2005-02-21 14:07:48 +00001471 assign( Rd, binop( Iop_Add32, mkexpr(Ra), mkU32(EXTS_SIMM) ) );
sewardjb51f0f42005-07-18 11:38:02 +00001472 set_XER_CA( PPC32G_FLAG_OP_ADD,
1473 mkexpr(Rd), mkexpr(Ra), mkU32(EXTS_SIMM),
1474 mkU32(0)/*old xer.ca, which is ignored*/ );
cerion4561acb2005-02-21 14:07:48 +00001475 break;
sewardjb51f0f42005-07-18 11:38:02 +00001476
cerione9d361a2005-03-04 17:35:29 +00001477 case 0x0D: // addic. (Add Immediate Carrying and Record, PPC32 p352)
cerion3007c7f2005-02-23 23:13:29 +00001478 DIP("addic. r%d,r%d,0x%x\n", Rd_addr, Ra_addr, EXTS_SIMM);
cerion4561acb2005-02-21 14:07:48 +00001479 assign( Rd, binop( Iop_Add32, mkexpr(Ra), mkU32(EXTS_SIMM) ) );
sewardjb51f0f42005-07-18 11:38:02 +00001480 set_XER_CA( PPC32G_FLAG_OP_ADD,
1481 mkexpr(Rd), mkexpr(Ra), mkU32(EXTS_SIMM),
1482 mkU32(0)/*old xer.ca, which is ignored*/ );
cerion70e24122005-03-16 00:27:37 +00001483 do_rc = True; // Always record to CR
cerion4561acb2005-02-21 14:07:48 +00001484 flag_Rc = 1;
1485 break;
1486
cerione9d361a2005-03-04 17:35:29 +00001487 case 0x0E: // addi (Add Immediate, PPC32 p350)
cerionb85e8bb2005-02-16 08:54:33 +00001488 // li rD,val == addi rD,0,val
1489 // la disp(rA) == addi rD,rA,disp
cerionb85e8bb2005-02-16 08:54:33 +00001490 if ( Ra_addr == 0 ) {
sewardjb51f0f42005-07-18 11:38:02 +00001491 DIP("li r%d,%d\n", Rd_addr, EXTS_SIMM);
cerionb85e8bb2005-02-16 08:54:33 +00001492 assign( Rd, mkU32(EXTS_SIMM) );
1493 } else {
sewardjb51f0f42005-07-18 11:38:02 +00001494 DIP("addi r%d,r%d,0x%x\n", Rd_addr, Ra_addr, SIMM_16);
cerionb85e8bb2005-02-16 08:54:33 +00001495 assign( Rd, binop( Iop_Add32, mkexpr(Ra), mkU32(EXTS_SIMM) ) );
1496 }
1497 break;
cerion91ad5362005-01-27 23:02:41 +00001498
cerione9d361a2005-03-04 17:35:29 +00001499 case 0x0F: // addis (Add Immediate Shifted, PPC32 p353)
cerionb85e8bb2005-02-16 08:54:33 +00001500 // lis rD,val == addis rD,0,val
cerionb85e8bb2005-02-16 08:54:33 +00001501 if ( Ra_addr == 0 ) {
sewardjb51f0f42005-07-18 11:38:02 +00001502 DIP("lis r%d,%d\n", Rd_addr, SIMM_16);
cerion7c1dd1b2005-02-22 18:39:18 +00001503 assign( Rd, mkU32(SIMM_16 << 16) );
cerionb85e8bb2005-02-16 08:54:33 +00001504 } else {
sewardjb51f0f42005-07-18 11:38:02 +00001505 DIP("addis r%d,r%d,0x%x\n", Rd_addr, Ra_addr, SIMM_16);
cerion7c1dd1b2005-02-22 18:39:18 +00001506 assign( Rd, binop(Iop_Add32, mkexpr(Ra), mkU32(SIMM_16 << 16)) );
cerionb85e8bb2005-02-16 08:54:33 +00001507 }
1508 break;
cerion91ad5362005-01-27 23:02:41 +00001509
cerione9d361a2005-03-04 17:35:29 +00001510 case 0x07: // mulli (Multiply Low Immediate, PPC32 p490)
cerionb85e8bb2005-02-16 08:54:33 +00001511 DIP("mulli r%d,r%d,0x%x\n", Rd_addr, Ra_addr, SIMM_16);
1512 assign( res64, binop(Iop_MullS32, mkexpr(Ra), mkU32(EXTS_SIMM)) );
1513 assign( Rd, unop(Iop_64to32, mkexpr(res64)) );
1514 break;
cerion38674602005-02-08 02:19:25 +00001515
cerione9d361a2005-03-04 17:35:29 +00001516 case 0x08: // subfic (Subtract from Immediate Carrying, PPC32 p540)
cerionb85e8bb2005-02-16 08:54:33 +00001517 DIP("subfic r%d,r%d,0x%x\n", Rd_addr, Ra_addr, SIMM_16);
cerion01908472005-02-25 16:43:08 +00001518 // rD = exts_simm - rA
cerion9d88da62005-02-25 10:23:46 +00001519 assign( Rd, binop(Iop_Sub32, mkU32(EXTS_SIMM), mkexpr(Ra)) );
sewardjb51f0f42005-07-18 11:38:02 +00001520 set_XER_CA( PPC32G_FLAG_OP_SUBFI,
1521 mkexpr(Rd), mkexpr(Ra), mkU32(EXTS_SIMM),
1522 mkU32(0)/*old xer.ca, which is ignored*/ );
cerionb85e8bb2005-02-16 08:54:33 +00001523 break;
cerion38674602005-02-08 02:19:25 +00001524
cerionb85e8bb2005-02-16 08:54:33 +00001525 /* XO-Form */
1526 case 0x1F:
cerionb85e8bb2005-02-16 08:54:33 +00001527 do_rc = True; // All below record to CR
1528
1529 switch (opc2) {
cerione9d361a2005-03-04 17:35:29 +00001530 case 0x10A: // add (Add, PPC32 p347)
cerionb85e8bb2005-02-16 08:54:33 +00001531 DIP("add%s%s r%d,r%d,r%d\n",
1532 flag_OE ? "o" : "", flag_Rc ? "." : "",
1533 Rd_addr, Ra_addr, Rb_addr);
1534 assign( Rd, binop(Iop_Add32, mkexpr(Ra), mkexpr(Rb)) );
cerion70e24122005-03-16 00:27:37 +00001535 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001536 set_XER_OV( PPC32G_FLAG_OP_ADD,
1537 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb) );
cerion70e24122005-03-16 00:27:37 +00001538 }
cerionb85e8bb2005-02-16 08:54:33 +00001539 break;
cerion91ad5362005-01-27 23:02:41 +00001540
cerione9d361a2005-03-04 17:35:29 +00001541 case 0x00A: // addc (Add Carrying, PPC32 p348)
cerionb85e8bb2005-02-16 08:54:33 +00001542 DIP("addc%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)) );
sewardjb51f0f42005-07-18 11:38:02 +00001546 set_XER_CA( PPC32G_FLAG_OP_ADD,
1547 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb),
1548 mkU32(0)/*old xer.ca, which is ignored*/ );
cerion70e24122005-03-16 00:27:37 +00001549 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001550 set_XER_OV( PPC32G_FLAG_OP_ADD,
1551 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb) );
cerion70e24122005-03-16 00:27:37 +00001552 }
cerionb85e8bb2005-02-16 08:54:33 +00001553 break;
1554
sewardjb51f0f42005-07-18 11:38:02 +00001555 case 0x08A: { // adde (Add Extended, PPC32 p349)
1556 IRTemp old_xer_ca = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00001557 DIP("adde%s%s r%d,r%d,r%d\n",
1558 flag_OE ? "o" : "", flag_Rc ? "." : "",
1559 Rd_addr, Ra_addr, Rb_addr);
1560 // rD = rA + rB + XER[CA]
sewardjb51f0f42005-07-18 11:38:02 +00001561 assign( old_xer_ca, get_XER_CA() );
cerionb85e8bb2005-02-16 08:54:33 +00001562 assign( Rd, binop(Iop_Add32, mkexpr(Ra),
sewardjb51f0f42005-07-18 11:38:02 +00001563 binop(Iop_Add32, mkexpr(Rb), mkexpr(old_xer_ca))) );
1564 set_XER_CA( PPC32G_FLAG_OP_ADDE,
1565 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb),
1566 mkexpr(old_xer_ca) );
cerion70e24122005-03-16 00:27:37 +00001567 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001568 set_XER_OV( PPC32G_FLAG_OP_ADDE,
1569 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb) );
cerion70e24122005-03-16 00:27:37 +00001570 }
cerionb85e8bb2005-02-16 08:54:33 +00001571 break;
sewardjb51f0f42005-07-18 11:38:02 +00001572 }
1573
1574 case 0x0EA: { // addme (Add to Minus One Extended, PPC32 p354)
1575 IRTemp old_xer_ca = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00001576 if (Rb_addr != 0) {
1577 vex_printf("dis_int_arith(PPC32)(addme,Rb_addr)\n");
1578 return False;
1579 }
1580 DIP("addme%s%s r%d,r%d,r%d\n",
1581 flag_OE ? "o" : "", flag_Rc ? "." : "",
1582 Rd_addr, Ra_addr, Rb_addr);
cerion70e24122005-03-16 00:27:37 +00001583 // rD = rA + (-1) + XER[CA]
1584 // => Just another form of adde
sewardjb51f0f42005-07-18 11:38:02 +00001585 assign( old_xer_ca, get_XER_CA() );
cerionb85e8bb2005-02-16 08:54:33 +00001586 assign( Rd, binop(Iop_Add32, mkexpr(Ra),
sewardjb51f0f42005-07-18 11:38:02 +00001587 binop(Iop_Add32, mkU32(-1), mkexpr(old_xer_ca)) ));
1588 set_XER_CA( PPC32G_FLAG_OP_ADDE,
1589 mkexpr(Rd), mkexpr(Ra), mkU32(-1),
1590 mkexpr(old_xer_ca) );
cerion70e24122005-03-16 00:27:37 +00001591 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001592 set_XER_OV( PPC32G_FLAG_OP_ADDE,
1593 mkexpr(Rd), mkexpr(Ra), mkU32(-1) );
cerion70e24122005-03-16 00:27:37 +00001594 }
cerionb85e8bb2005-02-16 08:54:33 +00001595 break;
sewardjb51f0f42005-07-18 11:38:02 +00001596 }
1597
1598 case 0x0CA: { // addze (Add to Zero Extended, PPC32 p355)
1599 IRTemp old_xer_ca = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00001600 if (Rb_addr != 0) {
1601 vex_printf("dis_int_arith(PPC32)(addze,Rb_addr)\n");
1602 return False;
1603 }
1604 DIP("addze%s%s r%d,r%d,r%d\n",
1605 flag_OE ? "o" : "", flag_Rc ? "." : "",
1606 Rd_addr, Ra_addr, Rb_addr);
cerion70e24122005-03-16 00:27:37 +00001607 // rD = rA + (0) + XER[CA]
1608 // => Just another form of adde
sewardjb51f0f42005-07-18 11:38:02 +00001609 assign( old_xer_ca, get_XER_CA() );
1610 assign( Rd, binop(Iop_Add32, mkexpr(Ra), mkexpr(old_xer_ca)) );
1611 set_XER_CA( PPC32G_FLAG_OP_ADDE,
1612 mkexpr(Rd), mkexpr(Ra), mkU32(0),
1613 mkexpr(old_xer_ca) );
cerion70e24122005-03-16 00:27:37 +00001614 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001615 set_XER_OV( PPC32G_FLAG_OP_ADDE,
1616 mkexpr(Rd), mkexpr(Ra), mkU32(0) );
cerion70e24122005-03-16 00:27:37 +00001617 }
cerionb85e8bb2005-02-16 08:54:33 +00001618 break;
sewardjb51f0f42005-07-18 11:38:02 +00001619 }
cerion91ad5362005-01-27 23:02:41 +00001620
cerione9d361a2005-03-04 17:35:29 +00001621 case 0x1EB: // divw (Divide Word, PPC32 p388)
cerionb85e8bb2005-02-16 08:54:33 +00001622 DIP("divw%s%s r%d,r%d,r%d\n",
1623 flag_OE ? "o" : "", flag_Rc ? "." : "",
1624 Rd_addr, Ra_addr, Rb_addr);
1625 assign( Rd, binop(Iop_DivS32, mkexpr(Ra), mkexpr(Rb)) );
cerion70e24122005-03-16 00:27:37 +00001626 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001627 set_XER_OV( PPC32G_FLAG_OP_DIVW,
1628 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb) );
cerion70e24122005-03-16 00:27:37 +00001629 }
cerionb85e8bb2005-02-16 08:54:33 +00001630 /* Note:
1631 if (0x8000_0000 / -1) or (x / 0)
1632 => Rd=undef, if(flag_Rc) CR7=undef, if(flag_OE) XER_OV=1
1633 => But _no_ exception raised. */
1634 break;
cerion91ad5362005-01-27 23:02:41 +00001635
cerione9d361a2005-03-04 17:35:29 +00001636 case 0x1CB: // divwu (Divide Word Unsigned, PPC32 p389)
cerionb85e8bb2005-02-16 08:54:33 +00001637 DIP("divwu%s%s r%d,r%d,r%d\n",
1638 flag_OE ? "o" : "", flag_Rc ? "." : "",
1639 Rd_addr, Ra_addr, Rb_addr);
1640 assign( Rd, binop(Iop_DivU32, mkexpr(Ra), mkexpr(Rb)) );
cerion70e24122005-03-16 00:27:37 +00001641 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001642 set_XER_OV( PPC32G_FLAG_OP_DIVWU,
1643 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb) );
cerion70e24122005-03-16 00:27:37 +00001644 }
cerionb85e8bb2005-02-16 08:54:33 +00001645 /* Note: ditto comment divw, for (x / 0) */
1646 break;
cerion91ad5362005-01-27 23:02:41 +00001647
cerione9d361a2005-03-04 17:35:29 +00001648 case 0x04B: // mulhw (Multiply High Word, PPC32 p488)
cerionb85e8bb2005-02-16 08:54:33 +00001649 if (flag_OE != 0) {
1650 vex_printf("dis_int_arith(PPC32)(mulhw,flag_OE)\n");
1651 return False;
1652 }
1653 DIP("mulhw%s r%d,r%d,r%d\n", flag_Rc ? "." : "",
1654 Rd_addr, Ra_addr, Rb_addr);
1655 assign( res64, binop(Iop_MullS32, mkexpr(Ra), mkexpr(Rb)) );
1656 assign( Rd, unop(Iop_64HIto32, mkexpr(res64)) );
1657 break;
cerionc19d5e12005-02-01 15:56:25 +00001658
cerione9d361a2005-03-04 17:35:29 +00001659 case 0x00B: // mulhwu (Multiply High Word Unsigned, PPC32 p489)
cerionb85e8bb2005-02-16 08:54:33 +00001660 if (flag_OE != 0) {
1661 vex_printf("dis_int_arith(PPC32)(mulhwu,flag_OE)\n");
1662 return False;
1663 }
1664 DIP("mulhwu%s r%d,r%d,r%d\n", flag_Rc ? "." : "",
1665 Rd_addr, Ra_addr, Rb_addr);
1666 assign( res64, binop(Iop_MullU32, mkexpr(Ra), mkexpr(Rb)) );
1667 assign( Rd, unop(Iop_64HIto32, mkexpr(res64)) );
1668 break;
1669
cerione9d361a2005-03-04 17:35:29 +00001670 case 0x0EB: // mullw (Multiply Low Word, PPC32 p491)
cerionb85e8bb2005-02-16 08:54:33 +00001671 DIP("mullw%s%s r%d,r%d,r%d\n",
1672 flag_OE ? "o" : "", flag_Rc ? "." : "",
1673 Rd_addr, Ra_addr, Rb_addr);
1674 assign( res64, binop(Iop_MullU32, mkexpr(Ra), mkexpr(Rb)) );
1675 assign( Rd, unop(Iop_64to32, mkexpr(res64)) );
cerion70e24122005-03-16 00:27:37 +00001676 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001677 set_XER_OV( PPC32G_FLAG_OP_MULLW,
1678 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb) );
cerion70e24122005-03-16 00:27:37 +00001679 }
cerionb85e8bb2005-02-16 08:54:33 +00001680 break;
cerionc19d5e12005-02-01 15:56:25 +00001681
cerione9d361a2005-03-04 17:35:29 +00001682 case 0x068: // neg (Negate, PPC32 p493)
cerionb85e8bb2005-02-16 08:54:33 +00001683 if (Rb_addr != 0) {
1684 vex_printf("dis_int_arith(PPC32)(neg,Rb_addr)\n");
1685 return False;
1686 }
1687 DIP("neg%s%s r%d,r%d\n",
1688 flag_OE ? "o" : "", flag_Rc ? "." : "",
1689 Rd_addr, Ra_addr);
1690 // rD = (log not)rA + 1
1691 assign( Rd, binop(Iop_Add32,
1692 unop(Iop_Not32, mkexpr(Ra)), mkU32(1)) );
cerion70e24122005-03-16 00:27:37 +00001693 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001694 set_XER_OV( PPC32G_FLAG_OP_NEG,
1695 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb) );
cerion70e24122005-03-16 00:27:37 +00001696 }
cerionb85e8bb2005-02-16 08:54:33 +00001697 break;
cerion91ad5362005-01-27 23:02:41 +00001698
cerione9d361a2005-03-04 17:35:29 +00001699 case 0x028: // subf (Subtract From, PPC32 p537)
cerionb85e8bb2005-02-16 08:54:33 +00001700 DIP("subf%s%s r%d,r%d,r%d\n",
1701 flag_OE ? "o" : "", flag_Rc ? "." : "",
1702 Rd_addr, Ra_addr, Rb_addr);
cerion01908472005-02-25 16:43:08 +00001703 // rD = rB - rA
1704 assign( Rd, binop(Iop_Sub32, mkexpr(Rb), mkexpr(Ra)) );
cerion70e24122005-03-16 00:27:37 +00001705 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001706 set_XER_OV( PPC32G_FLAG_OP_SUBF,
1707 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb) );
cerion70e24122005-03-16 00:27:37 +00001708 }
cerionb85e8bb2005-02-16 08:54:33 +00001709 break;
cerion38674602005-02-08 02:19:25 +00001710
cerione9d361a2005-03-04 17:35:29 +00001711 case 0x008: // subfc (Subtract from Carrying, PPC32 p538)
cerionb85e8bb2005-02-16 08:54:33 +00001712 DIP("subfc%s%s r%d,r%d,r%d\n",
1713 flag_OE ? "o" : "", flag_Rc ? "." : "",
1714 Rd_addr, Ra_addr, Rb_addr);
cerion01908472005-02-25 16:43:08 +00001715 // rD = rB - rA
1716 assign( Rd, binop(Iop_Sub32, mkexpr(Rb), mkexpr(Ra)) );
sewardjb51f0f42005-07-18 11:38:02 +00001717 set_XER_CA( PPC32G_FLAG_OP_SUBFC,
1718 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb),
1719 mkU32(0)/*old xer.ca, which is ignored*/ );
cerion70e24122005-03-16 00:27:37 +00001720 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001721 set_XER_OV( PPC32G_FLAG_OP_SUBFC,
1722 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb) );
cerion70e24122005-03-16 00:27:37 +00001723 }
cerionb85e8bb2005-02-16 08:54:33 +00001724 break;
1725
sewardjb51f0f42005-07-18 11:38:02 +00001726 case 0x088: {// subfe (Subtract from Extended, PPC32 p539)
1727 IRTemp old_xer_ca = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00001728 DIP("subfe%s%s r%d,r%d,r%d\n",
1729 flag_OE ? "o" : "", flag_Rc ? "." : "",
1730 Rd_addr, Ra_addr, Rb_addr);
1731 // rD = (log not)rA + rB + XER[CA]
sewardjb51f0f42005-07-18 11:38:02 +00001732 assign( old_xer_ca, get_XER_CA() );
cerionb85e8bb2005-02-16 08:54:33 +00001733 assign( Rd, binop(Iop_Add32, unop(Iop_Not32, mkexpr(Ra)),
sewardjb51f0f42005-07-18 11:38:02 +00001734 binop(Iop_Add32, mkexpr(Rb), mkexpr(old_xer_ca))) );
1735 set_XER_CA( PPC32G_FLAG_OP_SUBFE,
1736 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb),
1737 mkexpr(old_xer_ca) );
cerion70e24122005-03-16 00:27:37 +00001738 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001739 set_XER_OV( PPC32G_FLAG_OP_SUBFE,
1740 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb) );
cerion70e24122005-03-16 00:27:37 +00001741 }
cerionb85e8bb2005-02-16 08:54:33 +00001742 break;
sewardjb51f0f42005-07-18 11:38:02 +00001743 }
1744
sewardj20ef5472005-07-21 14:48:31 +00001745 case 0x0E8: { // subfme (Subtract from Minus One Extended, PPC32 p541)
1746 IRTemp old_xer_ca = newTemp(Ity_I32);
1747 if (Rb_addr != 0) {
1748 vex_printf("dis_int_arith(PPC32)(subfme,Rb_addr)\n");
1749 return False;
1750 }
1751 DIP("subfme%s%s r%d,r%d\n",
1752 flag_OE ? "o" : "", flag_Rc ? "." : "",
1753 Rd_addr, Ra_addr);
1754 // rD = (log not)rA + (-1) + XER[CA]
1755 // => Just another form of subfe
1756 assign( old_xer_ca, get_XER_CA() );
1757 assign( Rd, binop(Iop_Add32, unop(Iop_Not32, mkexpr(Ra)),
1758 binop(Iop_Add32, mkU32(-1), mkexpr(old_xer_ca))) );
1759 set_XER_CA( PPC32G_FLAG_OP_SUBFE,
1760 mkexpr(Rd), mkexpr(Ra), mkU32(-1),
1761 mkexpr(old_xer_ca) );
1762 if (flag_OE) {
1763 set_XER_OV( PPC32G_FLAG_OP_SUBFE,
1764 mkexpr(Rd), mkexpr(Ra), mkU32(-1) );
1765 }
1766 break;
1767 }
1768
sewardjb51f0f42005-07-18 11:38:02 +00001769 case 0x0C8: { // subfze (Subtract from Zero Extended, PPC32 p542)
1770 IRTemp old_xer_ca = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00001771 if (Rb_addr != 0) {
1772 vex_printf("dis_int_arith(PPC32)(subfze,Rb_addr)\n");
1773 return False;
1774 }
1775 DIP("subfze%s%s r%d,r%d\n",
1776 flag_OE ? "o" : "", flag_Rc ? "." : "",
1777 Rd_addr, Ra_addr);
cerion70e24122005-03-16 00:27:37 +00001778 // rD = (log not)rA + (0) + XER[CA]
1779 // => Just another form of subfe
sewardjb51f0f42005-07-18 11:38:02 +00001780 assign( old_xer_ca, get_XER_CA() );
1781 assign( Rd, binop(Iop_Add32,
1782 unop(Iop_Not32, mkexpr(Ra)), mkexpr(old_xer_ca)) );
1783 set_XER_CA( PPC32G_FLAG_OP_SUBFE,
1784 mkexpr(Rd), mkexpr(Ra), mkU32(0),
1785 mkexpr(old_xer_ca) );
cerion70e24122005-03-16 00:27:37 +00001786 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001787 set_XER_OV( PPC32G_FLAG_OP_SUBFE,
1788 mkexpr(Rd), mkexpr(Ra), mkU32(0) );
cerion70e24122005-03-16 00:27:37 +00001789 }
cerionb85e8bb2005-02-16 08:54:33 +00001790 break;
sewardjb51f0f42005-07-18 11:38:02 +00001791 }
cerionae694622005-01-28 17:52:47 +00001792
cerionb85e8bb2005-02-16 08:54:33 +00001793 default:
1794 vex_printf("dis_int_arith(PPC32)(opc2)\n");
1795 return False;
1796 }
1797 break;
1798 default:
1799 vex_printf("dis_int_arith(PPC32)(opc1)\n");
1800 return False;
1801 }
cerion91ad5362005-01-27 23:02:41 +00001802
cerionb85e8bb2005-02-16 08:54:33 +00001803 putIReg( Rd_addr, mkexpr(Rd) );
cerionb85e8bb2005-02-16 08:54:33 +00001804 if (do_rc && flag_Rc) {
sewardj20ef5472005-07-21 14:48:31 +00001805 set_CR0( mkexpr(Rd) );
cerionb85e8bb2005-02-16 08:54:33 +00001806 }
1807 return True;
cerion91ad5362005-01-27 23:02:41 +00001808}
1809
1810
1811
cerion3d870a32005-03-18 12:23:33 +00001812/*
1813 Integer Compare Instructions
1814*/
cerion7aa4bbc2005-01-29 09:32:07 +00001815static Bool dis_int_cmp ( UInt theInstr )
1816{
cerionb85e8bb2005-02-16 08:54:33 +00001817 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
1818 UChar crfD = toUChar((theInstr >> 23) & 0x7); /* theInstr[23:25] */
1819 UChar b9 = toUChar((theInstr >> 22) & 0x1); /* theInstr[22] */
1820 UChar flag_L = toUChar((theInstr >> 21) & 0x1); /* theInstr[21] */
1821 UChar Ra_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
1822
1823 /* D-Form */
cerionb85e8bb2005-02-16 08:54:33 +00001824 UInt UIMM_16 = (theInstr >> 0) & 0xFFFF; /* theInstr[0:15] */
1825
1826 /* X-Form */
1827 UChar Rb_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
1828 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
1829 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
1830
1831 UInt EXTS_SIMM = 0;
cerione9d361a2005-03-04 17:35:29 +00001832 IRTemp Ra = newTemp(Ity_I32);
1833 IRTemp Rb = newTemp(Ity_I32);
1834 IRTemp xer_so = newTemp(Ity_I32);
1835 IRTemp cr7 = newTemp(Ity_I32);
1836 IRTemp mux1 = newTemp(Ity_I32);
1837 IRTemp mux2 = newTemp(Ity_I32);
cerion70e24122005-03-16 00:27:37 +00001838 IRExpr* irx_cmp_lt;
1839 IRExpr* irx_cmp_eq;
cerion7aa4bbc2005-01-29 09:32:07 +00001840
cerionb85e8bb2005-02-16 08:54:33 +00001841 assign( Ra, getIReg(Ra_addr) );
1842
1843 if (flag_L==1) { // L==1 invalid for 32 bit.
1844 vex_printf("dis_int_cmp(PPC32)(flag_L)\n");
1845 return False;
1846 }
1847
1848 if (b9 != 0) {
1849 vex_printf("dis_int_cmp(PPC32)(b9)\n");
1850 return False;
1851 }
1852
1853 switch (opc1) {
sewardjb51f0f42005-07-18 11:38:02 +00001854 case 0x0B: // cmpi (Compare Immediate, PPC32 p368)
1855 EXTS_SIMM = extend_s_16to32(UIMM_16);
1856 DIP("cmp cr%d,r%d,%d\n", crfD, Ra_addr, EXTS_SIMM);
1857 putCR321( crfD, unop(Iop_32to8,
1858 binop(Iop_CmpORD32S, mkexpr(Ra),
1859 mkU32(EXTS_SIMM))) );
1860 putCR0( crfD, getXER_SO() );
1861 break;
1862
1863 case 0x0A: // cmpli (Compare Logical Immediate, PPC32 p370)
1864 DIP("cmpli cr%d,r%d,0x%x\n", crfD, Ra_addr, UIMM_16);
1865 putCR321( crfD, unop(Iop_32to8,
1866 binop(Iop_CmpORD32U, mkexpr(Ra),
1867 mkU32(UIMM_16))) );
1868 putCR0( crfD, getXER_SO() );
1869 break;
cerionb85e8bb2005-02-16 08:54:33 +00001870
1871 /* X Form */
1872 case 0x1F:
1873 if (b0 != 0) {
1874 vex_printf("dis_int_cmp(PPC32)(0x1F,b0)\n");
1875 return False;
1876 }
cerione9d361a2005-03-04 17:35:29 +00001877 assign( Rb, getIReg(Rb_addr) );
sewardjb51f0f42005-07-18 11:38:02 +00001878//zz irx_cmp_eq = binop(Iop_CmpEQ32, mkexpr(Ra), mkexpr(Rb));
cerion7aa4bbc2005-01-29 09:32:07 +00001879
cerionb85e8bb2005-02-16 08:54:33 +00001880 switch (opc2) {
sewardjb51f0f42005-07-18 11:38:02 +00001881 case 0x000: // cmp (Compare, PPC32 p367)
1882 DIP("cmp cr%d,r%d,r%d\n", crfD, Ra_addr, Rb_addr);
1883 putCR321( crfD, unop(Iop_32to8,
1884 binop(Iop_CmpORD32S, mkexpr(Ra), mkexpr(Rb))) );
1885 putCR0( crfD, getXER_SO() );
1886 break;
cerionb85e8bb2005-02-16 08:54:33 +00001887
sewardjb51f0f42005-07-18 11:38:02 +00001888 case 0x020: // cmpl (Compare Logical, PPC32 p369)
1889 DIP("cmpl cr%d,r%d,r%d\n", crfD, Ra_addr, Rb_addr);
1890 putCR321( crfD, unop(Iop_32to8,
1891 binop(Iop_CmpORD32U, mkexpr(Ra), mkexpr(Rb))) );
1892 putCR0( crfD, getXER_SO() );
1893 break;
cerion7aa4bbc2005-01-29 09:32:07 +00001894
sewardjb51f0f42005-07-18 11:38:02 +00001895 default:
1896 vex_printf("dis_int_cmp(PPC32)(opc2)\n");
1897 return False;
cerionb85e8bb2005-02-16 08:54:33 +00001898 }
1899 break;
cerion7aa4bbc2005-01-29 09:32:07 +00001900
cerionb85e8bb2005-02-16 08:54:33 +00001901 default:
1902 vex_printf("dis_int_cmp(PPC32)(opc1)\n");
1903 return False;
1904 }
1905
sewardjb51f0f42005-07-18 11:38:02 +00001906//zz irx_cmp_lt = unop(Iop_1Uto8, irx_cmp_lt);
1907//zz irx_cmp_eq = unop(Iop_1Uto8, irx_cmp_eq);
1908//zz
1909//zz // mux_shift_bit = (argL < argR) ? LT : GT (or EQ...)
1910//zz assign( mux1, IRExpr_Mux0X( irx_cmp_lt, mkU32(SHIFT_CR_GT), mkU32(SHIFT_CR_LT) ));
1911//zz
1912//zz // mux_shift_bit = (argL == argR) ? EQ : GT|LT
1913//zz assign( mux2, IRExpr_Mux0X( irx_cmp_eq, mkexpr(mux1), mkU32(SHIFT_CR_EQ) ));
1914//zz
1915//zz assign( xer_so, getReg_bit( PPC32_SPR_XER, SHIFT_XER_SO ) );
1916//zz assign( cr7, binop(Iop_Or32, mkexpr(mux2), mkexpr(xer_so)) );
1917//zz putReg_field( PPC32_SPR_CR, mkexpr(cr7), 7-crfD );
1918//zz return True;
cerionb85e8bb2005-02-16 08:54:33 +00001919 return True;
cerion7aa4bbc2005-01-29 09:32:07 +00001920}
1921
1922
cerion3d870a32005-03-18 12:23:33 +00001923/*
1924 Integer Logical Instructions
1925*/
cerion7aa4bbc2005-01-29 09:32:07 +00001926static Bool dis_int_logic ( UInt theInstr )
1927{
cerionb85e8bb2005-02-16 08:54:33 +00001928 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
1929 UChar Rs_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
1930 UChar Ra_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
1931
1932 /* D-Form */
1933 UInt UIMM_16 = (theInstr >> 0) & 0xFFFF; /* theInstr[0:15] */
1934
1935 /* X-Form */
1936 UChar Rb_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
1937 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
1938 UChar flag_Rc = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
1939
1940 Bool do_rc = False;
1941
1942 IRTemp Rs = newTemp(Ity_I32);
1943 IRTemp Ra = newTemp(Ity_I32);
1944 IRTemp Rb = newTemp(Ity_I32);
1945 IRTemp Sign = newTemp(Ity_I32);
cerione9d361a2005-03-04 17:35:29 +00001946 IRExpr* irx;
cerionb85e8bb2005-02-16 08:54:33 +00001947
ceriona31e8b52005-02-21 16:30:45 +00001948 assign( Rs, getIReg(Rs_addr) );
1949 assign( Rb, getIReg(Rb_addr) );
cerionb85e8bb2005-02-16 08:54:33 +00001950
1951 switch (opc1) {
cerione9d361a2005-03-04 17:35:29 +00001952 case 0x1C: // andi. (AND Immediate, PPC32 p358)
cerion4561acb2005-02-21 14:07:48 +00001953 DIP("andi. r%d,r%d,0x%x\n", Ra_addr, Rs_addr, UIMM_16);
cerionb85e8bb2005-02-16 08:54:33 +00001954 assign( Ra, binop(Iop_And32, mkexpr(Rs), mkU32(UIMM_16)) );
cerion70e24122005-03-16 00:27:37 +00001955 do_rc = True; // Always record to CR
cerionb85e8bb2005-02-16 08:54:33 +00001956 flag_Rc = 1;
1957 break;
1958
cerione9d361a2005-03-04 17:35:29 +00001959 case 0x1D: // andis. (AND Immediate Shifted, PPC32 p359)
cerionb85e8bb2005-02-16 08:54:33 +00001960 DIP("andis r%d,r%d,0x%x\n", Ra_addr, Rs_addr, UIMM_16);
1961 assign( Ra, binop(Iop_And32, mkexpr(Rs), mkU32(UIMM_16 << 16)) );
cerion70e24122005-03-16 00:27:37 +00001962 do_rc = True; // Always record to CR
cerionb85e8bb2005-02-16 08:54:33 +00001963 flag_Rc = 1;
1964 break;
cerion7aa4bbc2005-01-29 09:32:07 +00001965
cerione9d361a2005-03-04 17:35:29 +00001966 case 0x18: // ori (OR Immediate, PPC32 p497)
cerionb85e8bb2005-02-16 08:54:33 +00001967 DIP("ori r%d,r%d,0x%x\n", Ra_addr, Rs_addr, UIMM_16);
cerion70e24122005-03-16 00:27:37 +00001968 assign( Ra, binop(Iop_Or32, mkexpr(Rs), mkU32(UIMM_16)) );
cerionb85e8bb2005-02-16 08:54:33 +00001969 break;
cerion7aa4bbc2005-01-29 09:32:07 +00001970
cerione9d361a2005-03-04 17:35:29 +00001971 case 0x19: // oris (OR Immediate Shifted, PPC32 p498)
cerionb85e8bb2005-02-16 08:54:33 +00001972 DIP("oris r%d,r%d,0x%x\n", Ra_addr, Rs_addr, UIMM_16);
cerion70e24122005-03-16 00:27:37 +00001973 assign( Ra, binop(Iop_Or32, mkexpr(Rs), mkU32(UIMM_16 << 16)) );
cerionb85e8bb2005-02-16 08:54:33 +00001974 break;
cerionaabdfbf2005-01-29 12:56:15 +00001975
cerione9d361a2005-03-04 17:35:29 +00001976 case 0x1A: // xori (XOR Immediate, PPC32 p550)
cerionb85e8bb2005-02-16 08:54:33 +00001977 DIP("xori r%d,r%d,0x%x\n", Ra_addr, Rs_addr, UIMM_16);
cerion70e24122005-03-16 00:27:37 +00001978 assign( Ra, binop(Iop_Xor32, mkexpr(Rs), mkU32(UIMM_16)) );
cerionb85e8bb2005-02-16 08:54:33 +00001979 break;
cerion38674602005-02-08 02:19:25 +00001980
cerione9d361a2005-03-04 17:35:29 +00001981 case 0x1B: // xoris (XOR Immediate Shifted, PPC32 p551)
cerionb85e8bb2005-02-16 08:54:33 +00001982 DIP("xoris r%d,r%d,0x%x\n", Ra_addr, Rs_addr, UIMM_16);
cerion70e24122005-03-16 00:27:37 +00001983 assign( Ra, binop(Iop_Xor32, mkexpr(Rs), mkU32(UIMM_16 << 16)) );
cerionb85e8bb2005-02-16 08:54:33 +00001984 break;
cerionaabdfbf2005-01-29 12:56:15 +00001985
cerionb85e8bb2005-02-16 08:54:33 +00001986 /* X Form */
1987 case 0x1F:
cerion70e24122005-03-16 00:27:37 +00001988 do_rc = True; // All below record to CR
1989
cerionb85e8bb2005-02-16 08:54:33 +00001990 switch (opc2) {
sewardjb51f0f42005-07-18 11:38:02 +00001991 case 0x01C: // and (AND, PPC32 p356)
1992 DIP("and%s r%d,r%d,r%d\n",
1993 flag_Rc ? "." : "", Ra_addr, Rs_addr, Rb_addr);
1994 assign(Ra, binop(Iop_And32, mkexpr(Rs), mkexpr(Rb)));
1995 break;
cerionb85e8bb2005-02-16 08:54:33 +00001996
sewardjb51f0f42005-07-18 11:38:02 +00001997 case 0x03C: // andc (AND with Complement, PPC32 p357)
1998 DIP("andc%s r%d,r%d,r%d\n",
1999 flag_Rc ? "." : "", Ra_addr, Rs_addr, Rb_addr);
2000 assign(Ra, binop(Iop_And32, mkexpr(Rs),
2001 unop(Iop_Not32, mkexpr(Rb))));
2002 break;
2003
2004 case 0x01A: // cntlzw (Count Leading Zeros Word, PPC32 p371)
2005 if (Rb_addr!=0) {
2006 vex_printf("dis_int_logic(PPC32)(cntlzw,Rb_addr)\n");
2007 return False;
2008 }
2009 DIP("cntlzw%s r%d,r%d\n",
2010 flag_Rc ? "." : "", Ra_addr, Rs_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002011
sewardjb51f0f42005-07-18 11:38:02 +00002012 // Iop_Clz32 undefined for arg==0, so deal with that case:
2013 irx = binop(Iop_CmpNE32, mkexpr(Rs), mkU32(0));
2014 assign(Ra, IRExpr_Mux0X( unop(Iop_1Uto8, irx),
2015 mkU32(32),
2016 unop(Iop_Clz32, mkexpr(Rs)) ));
2017 break;
cerion7aa4bbc2005-01-29 09:32:07 +00002018
sewardj20ef5472005-07-21 14:48:31 +00002019 case 0x11C: // eqv (Equivalent, PPC32 p396)
2020 DIP("eqv%s r%d,r%d,r%d\n",
2021 flag_Rc ? "." : "", Ra_addr, Rs_addr, Rb_addr);
2022 assign( Ra, unop(Iop_Not32, binop(Iop_Xor32,
2023 mkexpr(Rs), mkexpr(Rb))) );
2024 break;
cerion7aa4bbc2005-01-29 09:32:07 +00002025
cerione9d361a2005-03-04 17:35:29 +00002026 case 0x3BA: // extsb (Extend Sign Byte, PPC32 p397
cerionb85e8bb2005-02-16 08:54:33 +00002027 if (Rb_addr!=0) {
2028 vex_printf("dis_int_logic(PPC32)(extsb,Rb_addr)\n");
2029 return False;
2030 }
2031 DIP("extsb%s r%d,r%d\n",
2032 flag_Rc ? "." : "", Ra_addr, Rs_addr);
sewardjb51f0f42005-07-18 11:38:02 +00002033 assign( Ra, unop(Iop_8Sto32, unop(Iop_32to8, mkexpr(Rs))) );
cerionb85e8bb2005-02-16 08:54:33 +00002034 break;
cerion7aa4bbc2005-01-29 09:32:07 +00002035
cerione9d361a2005-03-04 17:35:29 +00002036 case 0x39A: // extsh (Extend Sign Half Word, PPC32 p398)
cerionb85e8bb2005-02-16 08:54:33 +00002037 if (Rb_addr!=0) {
2038 vex_printf("dis_int_logic(PPC32)(extsh,Rb_addr)\n");
2039 return False;
2040 }
2041 DIP("extsh%s r%d,r%d\n",
2042 flag_Rc ? "." : "", Ra_addr, Rs_addr);
sewardjb51f0f42005-07-18 11:38:02 +00002043 assign( Ra, unop(Iop_16Sto32, unop(Iop_32to16, mkexpr(Rs))) );
cerionb85e8bb2005-02-16 08:54:33 +00002044 break;
cerion7aa4bbc2005-01-29 09:32:07 +00002045
cerione9d361a2005-03-04 17:35:29 +00002046 case 0x1DC: // nand (NAND, PPC32 p492)
cerionb85e8bb2005-02-16 08:54:33 +00002047 DIP("nand%s r%d,r%d,r%d\n",
2048 flag_Rc ? "." : "", Ra_addr, Rs_addr, Rb_addr);
2049 assign( Ra, unop(Iop_Not32,
2050 binop(Iop_And32, mkexpr(Rs), mkexpr(Rb))) );
2051 break;
2052
cerione9d361a2005-03-04 17:35:29 +00002053 case 0x07C: // nor (NOR, PPC32 p494)
cerionb85e8bb2005-02-16 08:54:33 +00002054 DIP("nor%s r%d,r%d,r%d\n",
2055 flag_Rc ? "." : "", Ra_addr, Rs_addr, Rb_addr);
2056 assign( Ra, unop(Iop_Not32,
2057 binop(Iop_Or32, mkexpr(Rs), mkexpr(Rb))) );
2058 break;
cerion7aa4bbc2005-01-29 09:32:07 +00002059
cerione9d361a2005-03-04 17:35:29 +00002060 case 0x1BC: // or (OR, PPC32 p495)
sewardjb51f0f42005-07-18 11:38:02 +00002061 if ((!flag_Rc) && Rs_addr == Rb_addr) {
2062 DIP("mr r%d,r%d\n", Ra_addr, Rs_addr);
2063 assign( Ra, mkexpr(Rs) );
2064 } else {
2065 DIP("or%s r%d,r%d,r%d\n",
2066 flag_Rc ? "." : "", Ra_addr, Rs_addr, Rb_addr);
2067 assign( Ra, binop(Iop_Or32, mkexpr(Rs), mkexpr(Rb)) );
2068 }
cerionb85e8bb2005-02-16 08:54:33 +00002069 break;
cerion7aa4bbc2005-01-29 09:32:07 +00002070
cerione9d361a2005-03-04 17:35:29 +00002071 case 0x19C: // orc (OR with Complement, PPC32 p496)
cerionb85e8bb2005-02-16 08:54:33 +00002072 DIP("orc%s r%d,r%d,r%d\n",
2073 flag_Rc ? "." : "", Ra_addr, Rs_addr, Rb_addr);
2074 assign( Ra, binop(Iop_Or32, mkexpr(Rs),
2075 unop(Iop_Not32, mkexpr(Rb))) );
2076 break;
2077
cerione9d361a2005-03-04 17:35:29 +00002078 case 0x13C: // xor (XOR, PPC32 p549)
cerionb85e8bb2005-02-16 08:54:33 +00002079 DIP("xor%s r%d,r%d,r%d\n",
2080 flag_Rc ? "." : "", Ra_addr, Rs_addr, Rb_addr);
2081 assign( Ra, binop(Iop_Xor32, mkexpr(Rs), mkexpr(Rb)) );
2082 break;
cerion7aa4bbc2005-01-29 09:32:07 +00002083
cerionb85e8bb2005-02-16 08:54:33 +00002084 default:
2085 vex_printf("dis_int_logic(PPC32)(opc2)\n");
2086 return False;
2087 }
cerionb85e8bb2005-02-16 08:54:33 +00002088 break;
2089
2090 default:
2091 vex_printf("dis_int_logic(PPC32)(opc1)\n");
2092 return False;
2093 }
cerion70e24122005-03-16 00:27:37 +00002094
2095 putIReg( Ra_addr, mkexpr(Ra) );
cerionb85e8bb2005-02-16 08:54:33 +00002096 if (do_rc && flag_Rc) {
sewardj20ef5472005-07-21 14:48:31 +00002097 set_CR0( mkexpr(Ra) );
cerionb85e8bb2005-02-16 08:54:33 +00002098 }
2099 return True;
cerion645c9302005-01-31 10:09:59 +00002100}
2101
2102
2103
cerion3d870a32005-03-18 12:23:33 +00002104/*
2105 Integer Rotate Instructions
2106*/
cerion645c9302005-01-31 10:09:59 +00002107static Bool dis_int_rot ( UInt theInstr )
2108{
cerionb85e8bb2005-02-16 08:54:33 +00002109 /* M-Form */
2110 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
2111 UChar Rs_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
2112 UChar Ra_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
2113 UChar Rb_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
2114 UChar sh_imm = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
2115 UChar MaskBegin = toUChar((theInstr >> 6) & 0x1F); /* theInstr[6:10] */
2116 UChar MaskEnd = toUChar((theInstr >> 1) & 0x1F); /* theInstr[1:5] */
2117 UChar flag_Rc = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
2118
cerion239e2e42005-02-24 16:59:17 +00002119 UInt mask = MASK(31-MaskEnd, 31-MaskBegin);
cerionb85e8bb2005-02-16 08:54:33 +00002120 IRTemp Rs = newTemp(Ity_I32);
2121 IRTemp Ra = newTemp(Ity_I32);
2122 IRTemp Rb = newTemp(Ity_I32);
2123
2124 assign( Rs, getIReg(Rs_addr) );
2125 assign( Rb, getIReg(Rb_addr) );
cerione9d361a2005-03-04 17:35:29 +00002126
cerionb85e8bb2005-02-16 08:54:33 +00002127 switch (opc1) {
sewardjc9659532005-07-21 21:33:57 +00002128 case 0x14:
2129 // rlwimi (Rotate Left Word Immediate then Mask Insert, PPC32 p500)
sewardjdb36c0f2005-07-03 00:05:31 +00002130 DIP("rlwimi%s r%d,r%d,%d,%d,%d\n", flag_Rc ? "." : "",
cerionb85e8bb2005-02-16 08:54:33 +00002131 Ra_addr, Rs_addr, sh_imm, MaskBegin, MaskEnd);
2132 // Ra = (ROTL(Rs, Imm) & mask) | (Ra & ~mask);
2133 assign( Ra, binop(Iop_Or32,
2134 binop(Iop_And32, mkU32(mask),
sewardjc9659532005-07-21 21:33:57 +00002135 ROTL32(mkexpr(Rs), mkU32(sh_imm))),
cerionb85e8bb2005-02-16 08:54:33 +00002136 binop(Iop_And32, getIReg(Ra_addr), mkU32(~mask))) );
2137 break;
cerion645c9302005-01-31 10:09:59 +00002138
sewardjc9659532005-07-21 21:33:57 +00002139 case 0x15:
2140 // rlwinm (Rotate Left Word Immediate then AND with Mask, PPC32 p501)
sewardjdb36c0f2005-07-03 00:05:31 +00002141 DIP("rlwinm%s r%d,r%d,%d,%d,%d\n", flag_Rc ? "." : "",
cerionb85e8bb2005-02-16 08:54:33 +00002142 Ra_addr, Rs_addr, sh_imm, MaskBegin, MaskEnd);
2143 // Ra = ROTL(Rs, Imm) & mask
sewardjc9659532005-07-21 21:33:57 +00002144 assign( Ra, binop(Iop_And32, ROTL32(mkexpr(Rs), mkU32(sh_imm)),
sewardjb51f0f42005-07-18 11:38:02 +00002145 mkU32(mask)) );
cerionb85e8bb2005-02-16 08:54:33 +00002146 break;
cerion45b70ff2005-01-31 17:03:25 +00002147
sewardjc9659532005-07-21 21:33:57 +00002148 case 0x17:
2149 // rlwnm (Rotate Left Word then AND with Mask, PPC32 p503
2150 DIP("rlwnm%s r%d,r%d,r%d,%d,%d\n", flag_Rc ? "." : "",
2151 Ra_addr, Rs_addr, Rb_addr, MaskBegin, MaskEnd);
2152 // Ra = ROTL(Rs, Rb[0-4]) & mask
2153 // note, ROTL32 does the masking, so we don't do it here
2154 assign( Ra, binop(Iop_And32, ROTL32(mkexpr(Rs), mkexpr(Rb)),
2155 mkU32(mask)) );
2156 break;
cerion45b70ff2005-01-31 17:03:25 +00002157
cerionb85e8bb2005-02-16 08:54:33 +00002158 default:
2159 vex_printf("dis_int_rot(PPC32)(opc1)\n");
2160 return False;
2161 }
cerion645c9302005-01-31 10:09:59 +00002162
cerionb85e8bb2005-02-16 08:54:33 +00002163 putIReg( Ra_addr, mkexpr(Ra) );
2164 if (flag_Rc) {
sewardj20ef5472005-07-21 14:48:31 +00002165 set_CR0( mkexpr(Ra) );
cerionb85e8bb2005-02-16 08:54:33 +00002166 }
2167 return True;
cerion645c9302005-01-31 10:09:59 +00002168}
2169
2170
2171
cerion3d870a32005-03-18 12:23:33 +00002172/*
2173 Integer Load Instructions
2174*/
cerion645c9302005-01-31 10:09:59 +00002175static Bool dis_int_load ( UInt theInstr )
2176{
cerionb85e8bb2005-02-16 08:54:33 +00002177 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
2178 UChar Rd_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
2179 UChar Ra_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
2180
2181 /* D-Form */
2182 UInt d_imm = (theInstr >> 0) & 0xFFFF; /* theInstr[0:15] */
2183
2184 /* X-Form */
2185 UChar Rb_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
2186 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
2187 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
2188
2189 UInt exts_d_imm = extend_s_16to32(d_imm);
2190
2191 IRTemp Ra_or_0 = newTemp(Ity_I32);
2192 IRTemp EA_imm = newTemp(Ity_I32);
2193 IRTemp EA_reg = newTemp(Ity_I32);
2194 IRTemp Ra = newTemp(Ity_I32);
2195 IRTemp Rb = newTemp(Ity_I32);
2196
2197 assign( Ra, getIReg(Ra_addr) );
2198 assign( Rb, getIReg(Rb_addr) );
2199
cerione9d361a2005-03-04 17:35:29 +00002200 assign( Ra_or_0, ((Ra_addr == 0) ? mkU32(0) : mkexpr(Ra)) );
2201
ceriond05ee442005-02-16 18:05:16 +00002202 assign( EA_imm, binop(Iop_Add32, mkexpr(Ra_or_0), mkU32(exts_d_imm)) );
cerionb85e8bb2005-02-16 08:54:33 +00002203
2204 switch (opc1) {
cerione9d361a2005-03-04 17:35:29 +00002205 case 0x22: // lbz (Load B & Zero, PPC32 p433)
sewardjb51f0f42005-07-18 11:38:02 +00002206 DIP("lbz r%d,%d(r%d)\n", Rd_addr, exts_d_imm, Ra_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002207 putIReg( Rd_addr, unop(Iop_8Uto32,
2208 loadBE(Ity_I8, mkexpr(EA_imm))) );
2209 break;
2210
cerione9d361a2005-03-04 17:35:29 +00002211 case 0x23: // lbzu (Load B & Zero with Update, PPC32 p434)
cerionb85e8bb2005-02-16 08:54:33 +00002212 if (Ra_addr == 0 || Ra_addr == Rd_addr) {
2213 vex_printf("dis_int_load(PPC32)(lbzu,Ra_addr|Rd_addr)\n");
2214 return False;
2215 }
sewardjb51f0f42005-07-18 11:38:02 +00002216 DIP("lbzu r%d,%d(r%d)\n", Rd_addr, exts_d_imm, Ra_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002217 putIReg( Rd_addr, unop(Iop_8Uto32,
2218 loadBE(Ity_I8, mkexpr(EA_imm))) );
2219 putIReg( Ra_addr, mkexpr(EA_imm) );
2220 break;
2221
cerione9d361a2005-03-04 17:35:29 +00002222 case 0x2A: // lha (Load HW Algebraic, PPC32 p445)
sewardjb51f0f42005-07-18 11:38:02 +00002223 DIP("lha r%d,%d(r%d)\n", Rd_addr, exts_d_imm, Ra_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002224 putIReg( Rd_addr, unop(Iop_16Sto32,
2225 loadBE(Ity_I16, mkexpr(EA_imm))) );
2226 break;
cerion645c9302005-01-31 10:09:59 +00002227
sewardjb51f0f42005-07-18 11:38:02 +00002228//zz case 0x2B: // lhau (Load HW Algebraic with Update, PPC32 p446)
2229//zz if (Ra_addr == 0 || Ra_addr == Rd_addr) {
2230//zz vex_printf("dis_int_load(PPC32)(lhau,Ra_addr|Rd_addr)\n");
2231//zz return False;
2232//zz }
2233//zz DIP("lhau r%d,%d(r%d)\n", Rd_addr, (Int)d_imm, Ra_addr);
2234//zz putIReg( Rd_addr, unop(Iop_16Sto32,
2235//zz loadBE(Ity_I16, mkexpr(EA_imm))) );
2236//zz putIReg( Ra_addr, mkexpr(EA_imm) );
2237//zz break;
cerionb85e8bb2005-02-16 08:54:33 +00002238
cerione9d361a2005-03-04 17:35:29 +00002239 case 0x28: // lhz (Load HW & Zero, PPC32 p450)
sewardjb51f0f42005-07-18 11:38:02 +00002240 DIP("lhz r%d,%d(r%d)\n", Rd_addr, exts_d_imm, Ra_addr);
cerione67534c2005-02-25 20:47:36 +00002241 putIReg( Rd_addr, unop(Iop_16Uto32,
cerionb85e8bb2005-02-16 08:54:33 +00002242 loadBE(Ity_I16, mkexpr(EA_imm))) );
2243 break;
2244
sewardjb51f0f42005-07-18 11:38:02 +00002245//zz case 0x29: // lhzu (Load HW & and Zero with Update, PPC32 p451)
2246//zz if (Ra_addr == 0 || Ra_addr == Rd_addr) {
2247//zz vex_printf("dis_int_load(PPC32)(lhzu,Ra_addr|Rd_addr)\n");
2248//zz return False;
2249//zz }
2250//zz DIP("lhzu r%d,%d(r%d)\n", Rd_addr, (Int)d_imm, Ra_addr);
2251//zz putIReg( Rd_addr, unop(Iop_16Uto32,
2252//zz loadBE(Ity_I16, mkexpr(EA_imm))) );
2253//zz putIReg( Ra_addr, mkexpr(EA_imm) );
2254//zz break;
cerion645c9302005-01-31 10:09:59 +00002255
cerione9d361a2005-03-04 17:35:29 +00002256 case 0x20: // lwz (Load W & Zero, PPC32 p460)
sewardjb51f0f42005-07-18 11:38:02 +00002257 DIP("lwz r%d,%d(r%d)\n", Rd_addr, exts_d_imm, Ra_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002258 putIReg( Rd_addr, loadBE(Ity_I32, mkexpr(EA_imm)) );
2259 break;
2260
cerione9d361a2005-03-04 17:35:29 +00002261 case 0x21: // lwzu (Load W & Zero with Update, PPC32 p461))
cerionb85e8bb2005-02-16 08:54:33 +00002262 if (Ra_addr == 0 || Ra_addr == Rd_addr) {
2263 vex_printf("dis_int_load(PPC32)(lwzu,Ra_addr|Rd_addr)\n");
2264 return False;
2265 }
sewardjb51f0f42005-07-18 11:38:02 +00002266 DIP("lwzu r%d,%d(r%d)\n", Rd_addr, exts_d_imm, Ra_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002267 putIReg( Rd_addr, loadBE(Ity_I32, mkexpr(EA_imm)) );
2268 putIReg( Ra_addr, mkexpr(EA_imm) );
2269 break;
2270
2271 /* X Form */
2272 case 0x1F:
2273 if (b0 != 0) {
2274 vex_printf("dis_int_load(PPC32)(Ox1F,b0)\n");
2275 return False;
2276 }
cerion7c1dd1b2005-02-22 18:39:18 +00002277 assign( EA_reg, binop(Iop_Add32, mkexpr(Ra_or_0), mkexpr(Rb)) );
cerion645c9302005-01-31 10:09:59 +00002278
cerionb85e8bb2005-02-16 08:54:33 +00002279 switch (opc2) {
cerione9d361a2005-03-04 17:35:29 +00002280 case 0x077: // lbzux (Load B & Zero with Update Indexed, PPC32 p435)
cerionb85e8bb2005-02-16 08:54:33 +00002281 DIP("lbzux r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
2282 if (Ra_addr == 0 || Ra_addr == Rd_addr) {
2283 vex_printf("dis_int_load(PPC32)(lwzux,Ra_addr|Rd_addr)\n");
2284 return False;
2285 }
2286 putIReg( Rd_addr, unop(Iop_8Uto32,
2287 loadBE(Ity_I8, mkexpr(EA_reg))) );
2288 putIReg( Ra_addr, mkexpr(EA_reg) );
2289 break;
2290
cerione9d361a2005-03-04 17:35:29 +00002291 case 0x057: // lbzx (Load B & Zero Indexed, PPC32 p436)
cerionb85e8bb2005-02-16 08:54:33 +00002292 DIP("lbzx r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
2293 putIReg( Rd_addr, unop(Iop_8Uto32,
2294 loadBE(Ity_I8, mkexpr(EA_reg))) );
2295 break;
2296
sewardjb51f0f42005-07-18 11:38:02 +00002297//zz case 0x177: // lhaux (Load HW Algebraic with Update Indexed, PPC32 p447)
2298//zz if (Ra_addr == 0 || Ra_addr == Rd_addr) {
2299//zz vex_printf("dis_int_load(PPC32)(lhaux,Ra_addr|Rd_addr)\n");
2300//zz return False;
2301//zz }
2302//zz DIP("lhaux r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
2303//zz putIReg( Rd_addr, unop(Iop_16Sto32,
2304//zz loadBE(Ity_I16, mkexpr(EA_reg))) );
2305//zz putIReg( Ra_addr, mkexpr(EA_reg) );
2306//zz break;
cerionb85e8bb2005-02-16 08:54:33 +00002307
cerione9d361a2005-03-04 17:35:29 +00002308 case 0x157: // lhax (Load HW Algebraic Indexed, PPC32 p448)
cerionb85e8bb2005-02-16 08:54:33 +00002309 DIP("lhax r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
2310 putIReg( Rd_addr, unop(Iop_16Sto32,
2311 loadBE(Ity_I16, mkexpr(EA_reg))) );
2312 break;
2313
cerione9d361a2005-03-04 17:35:29 +00002314 case 0x137: // lhzux (Load HW & Zero with Update Indexed, PPC32 p452)
cerionb85e8bb2005-02-16 08:54:33 +00002315 if (Ra_addr == 0 || Ra_addr == Rd_addr) {
2316 vex_printf("dis_int_load(PPC32)(lhzux,Ra_addr|Rd_addr)\n");
2317 return False;
2318 }
2319 DIP("lhzux r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
cerione67534c2005-02-25 20:47:36 +00002320 putIReg( Rd_addr, unop(Iop_16Uto32,
cerionb85e8bb2005-02-16 08:54:33 +00002321 loadBE(Ity_I16, mkexpr(EA_reg))) );
2322 putIReg( Ra_addr, mkexpr(EA_reg) );
2323 break;
2324
cerione9d361a2005-03-04 17:35:29 +00002325 case 0x117: // lhzx (Load HW & Zero Indexed, PPC32 p453)
cerionb85e8bb2005-02-16 08:54:33 +00002326 DIP("lhzx r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
cerione67534c2005-02-25 20:47:36 +00002327 putIReg( Rd_addr, unop(Iop_16Uto32,
cerionb85e8bb2005-02-16 08:54:33 +00002328 loadBE(Ity_I16, mkexpr(EA_reg))) );
2329 break;
cerion44997f22005-01-31 18:45:59 +00002330
sewardjb51f0f42005-07-18 11:38:02 +00002331//zz case 0x037: // lwzux (Load W & Zero with Update Indexed, PPC32 p462)
2332//zz if (Ra_addr == 0 || Ra_addr == Rd_addr) {
2333//zz vex_printf("dis_int_load(PPC32)(lwzux,Ra_addr|Rd_addr)\n");
2334//zz return False;
2335//zz }
2336//zz DIP("lwzux r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
2337//zz putIReg( Rd_addr, loadBE(Ity_I32, mkexpr(EA_reg)) );
2338//zz putIReg( Ra_addr, mkexpr(EA_reg) );
2339//zz break;
cerionb85e8bb2005-02-16 08:54:33 +00002340
cerione9d361a2005-03-04 17:35:29 +00002341 case 0x017: // lwzx (Load W & Zero Indexed, PPC32 p463)
cerionb85e8bb2005-02-16 08:54:33 +00002342 DIP("lwzx r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
2343 putIReg( Rd_addr, loadBE(Ity_I32, mkexpr(EA_reg)) );
2344 break;
cerion44997f22005-01-31 18:45:59 +00002345
cerionb85e8bb2005-02-16 08:54:33 +00002346 default:
2347 vex_printf("dis_int_load(PPC32)(opc2)\n");
2348 return False;
2349 }
2350 break;
2351 default:
2352 vex_printf("dis_int_load(PPC32)(opc1)\n");
2353 return False;
2354 }
2355 return True;
cerion7aa4bbc2005-01-29 09:32:07 +00002356}
2357
2358
2359
cerion3d870a32005-03-18 12:23:33 +00002360/*
2361 Integer Store Instructions
2362*/
ceriond23be4e2005-01-31 07:23:07 +00002363static Bool dis_int_store ( UInt theInstr )
2364{
sewardjb51f0f42005-07-18 11:38:02 +00002365 UInt opc1 = ifieldOPC(theInstr); /* theInstr[26:31] */
2366 UInt Rs_addr = ifieldRD(theInstr); /* theInstr[21:25] */
2367 UInt Ra_addr = ifieldRA(theInstr); /* theInstr[16:20] */
cerionb85e8bb2005-02-16 08:54:33 +00002368
2369 /* D-Form */
sewardjb51f0f42005-07-18 11:38:02 +00002370 Int simm16 = ifieldSIMM16(theInstr); /* theInstr[0:15] */
cerionb85e8bb2005-02-16 08:54:33 +00002371
2372 /* X-Form */
sewardjb51f0f42005-07-18 11:38:02 +00002373 UInt Rb_addr = ifieldRB(theInstr); /* theInstr[11:15] */
2374 UInt opc2 = ifieldOPClo10(theInstr); /* theInstr[1:10] */
2375 UInt b0 = ifieldBIT0(theInstr); /* theInstr[0] */
2376
cerionb85e8bb2005-02-16 08:54:33 +00002377 IRTemp Ra = newTemp(Ity_I32);
2378 IRTemp Ra_or_0 = newTemp(Ity_I32);
2379 IRTemp Rb = newTemp(Ity_I32);
2380 IRTemp Rs = newTemp(Ity_I32);
sewardjb51f0f42005-07-18 11:38:02 +00002381// IRTemp Rs_8 = newTemp(Ity_I8);
2382//IRTemp Rs_16 = newTemp(Ity_I16);
cerionb85e8bb2005-02-16 08:54:33 +00002383 IRTemp EA_imm = newTemp(Ity_I32);
2384 IRTemp EA_reg = newTemp(Ity_I32);
2385
2386 assign( Ra, getIReg(Ra_addr) );
2387 assign( Rb, getIReg(Rb_addr) );
2388 assign( Rs, getIReg(Rs_addr) );
sewardjb51f0f42005-07-18 11:38:02 +00002389 //assign( Rs_8, unop(Iop_32to8, mkexpr(Rs)) );
2390 //assign( Rs_16, unop(Iop_32to16, mkexpr(Rs)) );
cerionb85e8bb2005-02-16 08:54:33 +00002391
2392 if (Ra_addr == 0) {
2393 assign( Ra_or_0, mkU32(0) );
2394 } else {
2395 assign( Ra_or_0, mkexpr(Ra) );
2396 }
sewardjb51f0f42005-07-18 11:38:02 +00002397 assign( EA_imm, binop(Iop_Add32, mkexpr(Ra_or_0), mkU32(simm16)) );
cerionb85e8bb2005-02-16 08:54:33 +00002398
2399 switch (opc1) {
sewardjb51f0f42005-07-18 11:38:02 +00002400 case 0x26: // stb (Store B, PPC32 p509)
2401 DIP("stb r%d,%d(r%d)\n", Rs_addr, simm16, Ra_addr);
2402 storeBE( mkexpr(EA_imm), unop(Iop_32to8, mkexpr(Rs)) );
2403 break;
2404
cerione9d361a2005-03-04 17:35:29 +00002405 case 0x27: // stbu (Store B with Update, PPC32 p510)
cerionb85e8bb2005-02-16 08:54:33 +00002406 if (Ra_addr == 0 ) {
2407 vex_printf("dis_int_store(PPC32)(stbu,Ra_addr)\n");
2408 return False;
2409 }
sewardjb51f0f42005-07-18 11:38:02 +00002410 DIP("stbu r%d,%d(r%d)\n", Rs_addr, simm16, Ra_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002411 putIReg( Ra_addr, mkexpr(EA_imm) );
sewardjb51f0f42005-07-18 11:38:02 +00002412 storeBE( mkexpr(EA_imm), unop(Iop_32to8, mkexpr(Rs)) );
cerionb85e8bb2005-02-16 08:54:33 +00002413 break;
ceriond23be4e2005-01-31 07:23:07 +00002414
cerione9d361a2005-03-04 17:35:29 +00002415 case 0x2C: // sth (Store HW, PPC32 p522)
sewardjb51f0f42005-07-18 11:38:02 +00002416 DIP("sth r%d,%d(r%d)\n", Rs_addr, simm16, Ra_addr);
2417 storeBE( mkexpr(EA_imm), unop(Iop_32to16, mkexpr(Rs)) );
cerionb85e8bb2005-02-16 08:54:33 +00002418 break;
2419
cerione9d361a2005-03-04 17:35:29 +00002420 case 0x2D: // sthu (Store HW with Update, PPC32 p524)
cerionb85e8bb2005-02-16 08:54:33 +00002421 if (Ra_addr == 0) {
2422 vex_printf("dis_int_store(PPC32)(sthu,Ra_addr)\n");
2423 return False;
2424 }
sewardjb51f0f42005-07-18 11:38:02 +00002425 DIP("sthu r%d,%d(r%d)\n", Rs_addr, simm16, Ra_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002426 putIReg( Ra_addr, mkexpr(EA_imm) );
sewardjb51f0f42005-07-18 11:38:02 +00002427 storeBE( mkexpr(EA_imm), unop(Iop_32to16, mkexpr(Rs)) );
cerionb85e8bb2005-02-16 08:54:33 +00002428 break;
ceriond23be4e2005-01-31 07:23:07 +00002429
cerione9d361a2005-03-04 17:35:29 +00002430 case 0x24: // stw (Store W, PPC32 p530)
sewardjb51f0f42005-07-18 11:38:02 +00002431 DIP("stw r%d,%d(r%d)\n", Rs_addr, simm16, Ra_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002432 storeBE( mkexpr(EA_imm), mkexpr(Rs) );
2433 break;
ceriond23be4e2005-01-31 07:23:07 +00002434
cerione9d361a2005-03-04 17:35:29 +00002435 case 0x25: // stwu (Store W with Update, PPC32 p534)
cerionb85e8bb2005-02-16 08:54:33 +00002436 if (Ra_addr == 0) {
2437 vex_printf("dis_int_store(PPC32)(stwu,Ra_addr)\n");
2438 return False;
2439 }
sewardjb51f0f42005-07-18 11:38:02 +00002440 DIP("stwu r%d,%d(r%d)\n", Rs_addr, simm16, Ra_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002441 putIReg( Ra_addr, mkexpr(EA_imm) );
cerioned623db2005-06-20 12:42:04 +00002442 storeBE( mkexpr(EA_imm), mkexpr(Rs) );
cerionb85e8bb2005-02-16 08:54:33 +00002443 break;
2444
2445 /* X Form */
2446 case 0x1F:
2447 if (b0 != 0) {
2448 vex_printf("dis_int_store(PPC32)(0x1F,b0)\n");
2449 return False;
2450 }
cerion7c1dd1b2005-02-22 18:39:18 +00002451 assign( EA_reg, binop(Iop_Add32, mkexpr(Ra_or_0), mkexpr(Rb)) );
cerion44997f22005-01-31 18:45:59 +00002452
cerionb85e8bb2005-02-16 08:54:33 +00002453 switch (opc2) {
cerione9d361a2005-03-04 17:35:29 +00002454 case 0x0F7: // stbux (Store B with Update Indexed, PPC32 p511)
cerionb85e8bb2005-02-16 08:54:33 +00002455 if (Ra_addr == 0) {
2456 vex_printf("dis_int_store(PPC32)(stbux,Ra_addr)\n");
2457 return False;
2458 }
2459 DIP("stbux r%d,r%d,r%d\n", Rs_addr, Ra_addr, Rb_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002460 putIReg( Ra_addr, mkexpr(EA_reg) );
sewardjb51f0f42005-07-18 11:38:02 +00002461 storeBE( mkexpr(EA_reg), unop(Iop_32to8, mkexpr(Rs)) );
cerionb85e8bb2005-02-16 08:54:33 +00002462 break;
2463
cerione9d361a2005-03-04 17:35:29 +00002464 case 0x0D7: // stbx (Store B Indexed, PPC32 p512)
cerionb85e8bb2005-02-16 08:54:33 +00002465 DIP("stbx r%d,r%d,r%d\n", Rs_addr, Ra_addr, Rb_addr);
sewardjb51f0f42005-07-18 11:38:02 +00002466 storeBE( mkexpr(EA_reg), unop(Iop_32to8, mkexpr(Rs)) );
cerionb85e8bb2005-02-16 08:54:33 +00002467 break;
2468
sewardjb51f0f42005-07-18 11:38:02 +00002469//zz case 0x1B7: // sthux (Store HW with Update Indexed, PPC32 p525)
2470//zz if (Ra_addr == 0) {
2471//zz vex_printf("dis_int_store(PPC32)(sthux,Ra_addr)\n");
2472//zz return False;
2473//zz }
2474//zz DIP("sthux r%d,r%d,r%d\n", Rs_addr, Ra_addr, Rb_addr);
2475//zz putIReg( Ra_addr, mkexpr(EA_reg) );
2476//zz storeBE( mkexpr(EA_reg), mkexpr(Rs_16) );
2477//zz break;
cerionb85e8bb2005-02-16 08:54:33 +00002478
cerione9d361a2005-03-04 17:35:29 +00002479 case 0x197: // sthx (Store HW Indexed, PPC32 p526)
cerionb85e8bb2005-02-16 08:54:33 +00002480 DIP("sthx r%d,r%d,r%d\n", Rs_addr, Ra_addr, Rb_addr);
sewardjb51f0f42005-07-18 11:38:02 +00002481 storeBE( mkexpr(EA_reg), unop(Iop_32to16, mkexpr(Rs)) );
cerionb85e8bb2005-02-16 08:54:33 +00002482 break;
2483
cerione9d361a2005-03-04 17:35:29 +00002484 case 0x0B7: // stwux (Store W with Update Indexed, PPC32 p535)
cerionb85e8bb2005-02-16 08:54:33 +00002485 if (Ra_addr == 0) {
2486 vex_printf("dis_int_store(PPC32)(stwux,Ra_addr)\n");
2487 return False;
2488 }
2489 DIP("stwux r%d,r%d,r%d\n", Rs_addr, Ra_addr, Rb_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002490 putIReg( Ra_addr, mkexpr(EA_reg) );
cerioned623db2005-06-20 12:42:04 +00002491 storeBE( mkexpr(EA_reg), mkexpr(Rs) );
cerionb85e8bb2005-02-16 08:54:33 +00002492 break;
cerion44997f22005-01-31 18:45:59 +00002493
cerione9d361a2005-03-04 17:35:29 +00002494 case 0x097: // stwx (Store W Indexed, PPC32 p536)
cerionb85e8bb2005-02-16 08:54:33 +00002495 DIP("stwx r%d,r%d,r%d\n", Rs_addr, Ra_addr, Rb_addr);
2496 storeBE( mkexpr(EA_reg), mkexpr(Rs) );
2497 break;
2498
2499 default:
2500 vex_printf("dis_int_store(PPC32)(opc2)\n");
2501 return False;
2502 }
2503 break;
2504 default:
2505 vex_printf("dis_int_store(PPC32)(opc1)\n");
2506 return False;
2507 }
2508 return True;
ceriond23be4e2005-01-31 07:23:07 +00002509}
2510
2511
2512
sewardjb51f0f42005-07-18 11:38:02 +00002513//zz /*
2514//zz Integer Load/Store Multiple Instructions
2515//zz */
2516//zz static Bool dis_int_ldst_mult ( UInt theInstr )
2517//zz {
2518//zz /* D-Form */
2519//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
2520//zz UChar Rd_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
2521//zz UChar Rs_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
2522//zz UChar Ra_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
2523//zz UInt d_imm = (theInstr >> 0) & 0xFFFF; /* theInstr[0:15] */
2524//zz
2525//zz UInt exts_d_imm = extend_s_16to32(d_imm);
2526//zz UInt reg_idx = 0;
2527//zz UInt offset = 0;
2528//zz
2529//zz IRTemp Ra = newTemp(Ity_I32);
2530//zz IRTemp EA = newTemp(Ity_I32);
2531//zz
2532//zz IRExpr* irx_addr;
2533//zz
2534//zz if (Ra_addr == 0) {
2535//zz assign( EA, binop(Iop_Add32, mkU32(0), mkU32(exts_d_imm)) );
2536//zz } else {
2537//zz assign( Ra, getIReg(Ra_addr) );
2538//zz assign( EA, binop(Iop_Add32, mkexpr(Ra), mkU32(exts_d_imm)) );
2539//zz }
2540//zz
2541//zz switch (opc1) {
2542//zz case 0x2E: // lmw (Load Multiple Word, PPC32 p454)
2543//zz vassert(1);
2544//zz
2545//zz if (Ra_addr >= Rd_addr) {
2546//zz vex_printf("dis_int_ldst_mult(PPC32)(lmw,Ra_addr)\n");
2547//zz return False;
2548//zz }
2549//zz DIP("lmw r%d,%d(r%d)\n", Rd_addr, (Int)d_imm, Ra_addr);
2550//zz for (reg_idx = Rd_addr; reg_idx<=31; reg_idx++) {
2551//zz irx_addr = binop(Iop_Add32, mkexpr(EA), mkU32(offset));
2552//zz putIReg( reg_idx, loadBE(Ity_I32, irx_addr ) );
2553//zz offset +=4;
2554//zz }
2555//zz break;
2556//zz
2557//zz case 0x2F: // stmw (Store Multiple Word, PPC32 p527)
2558//zz vassert(1);
2559//zz
2560//zz DIP("stmw r%d,%d(r%d)\n", Rs_addr, (Int)d_imm, Ra_addr);
2561//zz for (reg_idx = Rs_addr; reg_idx<=31; reg_idx++) {
2562//zz irx_addr = binop(Iop_Add32, mkexpr(EA), mkU32(offset));
2563//zz storeBE( irx_addr, getIReg(reg_idx) );
2564//zz offset +=4;
2565//zz }
2566//zz break;
2567//zz
2568//zz default:
2569//zz vex_printf("dis_int_ldst_mult(PPC32)(opc1)\n");
2570//zz return False;
2571//zz }
2572//zz return True;
2573//zz }
2574//zz
2575//zz
2576//zz
2577//zz /*
2578//zz Integer Load/Store String Instructions
2579//zz */
2580//zz static Bool dis_int_ldst_str ( UInt theInstr )
2581//zz {
2582//zz /* X-Form */
2583//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
2584//zz UChar Rd_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
2585//zz UChar Rs_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
2586//zz UChar Ra_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
2587//zz UChar NumBytes = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
2588//zz UChar Rb_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
2589//zz UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
2590//zz UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
2591//zz
2592//zz UInt reg_idx, bit_idx, n_byte;
2593//zz UInt EA_offset = 0;
2594//zz UInt n_regs, reg_first, reg_last;
2595//zz
2596//zz IRTemp Ra = newTemp(Ity_I32);
2597//zz // IRTemp Rb = newTemp(Ity_I32);
2598//zz IRTemp EA = newTemp(Ity_I32);
2599//zz IRTemp b_EA = newTemp(Ity_I32);
2600//zz IRExpr* irx_byte;
2601//zz IRExpr* irx_shl;
2602//zz
2603//zz if (Ra_addr == 0) {
2604//zz assign( b_EA, mkU32(0) );
2605//zz } else {
2606//zz assign( Ra, getIReg(Ra_addr) );
2607//zz assign( b_EA, mkexpr(Ra) );
2608//zz }
2609//zz
2610//zz if (opc1 != 0x1F || b0 != 0) {
2611//zz vex_printf("dis_int_ldst_str(PPC32)(opc1)\n");
2612//zz return False;
2613//zz }
2614//zz
2615//zz switch (opc2) {
2616//zz case 0x255: // lswi (Load String Word Immediate, PPC32 p455)
2617//zz
2618//zz if (NumBytes == 8) {
2619//zz /* Special case hack */
2620//zz /* Rd = Mem[EA]; (Rd+1)%32 = Mem[EA+4] */
2621//zz DIP("lswi r%d,r%d,%d\n", Rd_addr, Ra_addr, NumBytes);
2622//zz putIReg( Rd_addr,
2623//zz loadBE(Ity_I32, mkexpr(b_EA)) );
2624//zz
2625//zz putIReg( (Rd_addr+1) % 32,
2626//zz loadBE(Ity_I32, binop(Iop_Add32, mkexpr(b_EA), mkU32(4))) );
2627//zz return True;
2628//zz }
2629//zz
2630//zz /* else too difficult */
2631//zz return False;
2632//zz vassert(0);
2633//zz
2634//zz n_regs = (NumBytes / 4) + (NumBytes%4 == 0 ? 0:1); // ceil(nb/4)
2635//zz reg_first = Rd_addr;
2636//zz reg_last = Rd_addr + n_regs - 1;
2637//zz
2638//zz if (reg_last < reg_first) {
2639//zz if (Ra_addr >= reg_first || Ra_addr <= reg_last) {
2640//zz vex_printf("dis_int_ldst_str(PPC32)(lswi,Ra_addr,1)\n");
2641//zz return False;
2642//zz }
2643//zz } else {
2644//zz if (Ra_addr >= reg_first && Ra_addr <= reg_last) {
2645//zz vex_printf("dis_int_ldst_str(PPC32)(lswi,Ra_addr,2)\n");
2646//zz return False;
2647//zz }
2648//zz }
2649//zz DIP("lswi r%d,r%d,%d\n", Rd_addr, Ra_addr, NumBytes);
2650//zz
2651//zz assign( EA, mkexpr(b_EA) );
2652//zz
2653//zz bit_idx = 0;
2654//zz reg_idx = Rd_addr - 1;
2655//zz n_byte = NumBytes;
2656//zz if (n_byte == 0) { n_byte = 32; }
2657//zz
2658//zz for (; n_byte>0; n_byte--) {
2659//zz if (bit_idx == 0) {
2660//zz reg_idx++;
2661//zz if (reg_idx == 32) reg_idx = 0;
2662//zz putIReg( reg_idx, mkU32(0) );
2663//zz }
2664//zz irx_byte = loadBE(Ity_I8, binop(Iop_Add32,
2665//zz mkexpr(EA),
2666//zz mkU32(EA_offset)));
2667//zz irx_shl = binop(Iop_Shl32, irx_byte,
2668//zz mkU8(toUChar(24 - bit_idx)));
2669//zz putIReg( reg_idx, binop(Iop_Or32, getIReg(reg_idx), irx_shl) );
2670//zz bit_idx += 8;
2671//zz if (bit_idx == 32) { bit_idx = 0; }
2672//zz EA_offset++;
2673//zz }
2674//zz break;
2675//zz
2676//zz case 0x215: // lswx (Load String Word Indexed, PPC32 p456)
2677//zz vassert(0);
2678//zz
2679//zz DIP("lswx r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
2680//zz return False;
2681//zz
2682//zz case 0x2D5: // stswi (Store String Word Immediate, PPC32 p528)
2683//zz
2684//zz if (NumBytes == 8) {
2685//zz /* Special case hack */
2686//zz /* Mem[EA] = Rd; Mem[EA+4] = (Rd+1)%32 */
2687//zz DIP("stswi r%d,r%d,%d\n", Rs_addr, Ra_addr, NumBytes);
2688//zz storeBE( mkexpr(b_EA),
2689//zz getIReg(Rd_addr) );
2690//zz storeBE( binop(Iop_Add32, mkexpr(b_EA), mkU32(4)),
2691//zz getIReg((Rd_addr+1) % 32) );
2692//zz return True;
2693//zz }
2694//zz
2695//zz /* else too difficult */
2696//zz return False;
2697//zz
2698//zz vassert(0);
2699//zz
2700//zz DIP("stswi r%d,r%d,%d\n", Rs_addr, Ra_addr, NumBytes);
2701//zz if (Ra_addr == 0) {
2702//zz assign( EA, mkU32(0) );
2703//zz } else {
2704//zz assign( EA, mkexpr(b_EA) );
2705//zz }
2706//zz
2707//zz n_byte = NumBytes;
2708//zz if (n_byte == 0) { n_byte = 32; }
2709//zz reg_idx = Rs_addr - 1;
2710//zz bit_idx = 0;
2711//zz
2712//zz for (; n_byte>0; n_byte--) {
2713//zz if (bit_idx == 0) {
2714//zz reg_idx++;
2715//zz if (reg_idx==32) reg_idx = 0;
2716//zz }
2717//zz irx_byte = unop(Iop_32to8,
2718//zz binop(Iop_Shr32,
2719//zz getIReg(reg_idx),
2720//zz mkU8(toUChar(24 - bit_idx))));
2721//zz storeBE( binop(Iop_Add32, mkexpr(EA), mkU32(EA_offset)),
2722//zz irx_byte );
2723//zz
2724//zz bit_idx += 8;
2725//zz if (bit_idx == 32) { bit_idx = 0; }
2726//zz EA_offset++;
2727//zz }
2728//zz break;
2729//zz
2730//zz case 0x295: // stswx (Store String Word Indexed, PPC32 p529)
2731//zz vassert(0);
2732//zz
2733//zz DIP("stswx r%d,r%d,r%d\n", Rs_addr, Ra_addr, Rb_addr);
2734//zz return False;
2735//zz #if 0
2736//zz // CAB: Might something like this work ?
2737//zz // won't produce very nice code (ir_ctr will get _rather_ long...), but hey.
2738//zz // or perhaps arrays of IRTemp...
2739//zz assign( NumBytes, AND(get(xer_bc), 0x1F) );
2740//zz IRExpr* irx_ea;
2741//zz IRExpr* irx_orig_byte;
2742//zz IRExpr* irx_tostore;
2743//zz IRExpr* ir_ctr = mkU8(0);
2744//zz Uint EA_offset = 0;
2745//zz UInt start = Rs_addr;
2746//zz UInt reg_idx;
2747//zz UInt i;
2748//zz for (i=0; i<128; i++) {
2749//zz bit_idx = (i % 4) * 8;
2750//zz reg_idx = (i / 4) + start;
2751//zz reg_idx = reg_idx % 32;
2752//zz word = getIReg(reg_idx);
2753//zz byte = get_byte(word, bit_idx);
2754//zz
2755//zz irx_ea = (EA + EA_offset);
2756//zz irx_orig_byte = loadBE(Ity_I8, irx_ea);
2757//zz irx_tostore = IRExpr_Mux0X( (ir_ctr <= NumBytes),
2758//zz irx_orig_byte,
2759//zz mkexpr(byte0) );
2760//zz storeBE( irx_ea, irx_tostore );
2761//zz
2762//zz ir_ctr = binop(Iop_And8, ir_ctr, mkU8(1));
2763//zz EA_offset++;
2764//zz }
2765//zz break;
2766//zz #endif
2767//zz
2768//zz default:
2769//zz vex_printf("dis_int_ldst_str(PPC32)(opc2)\n");
2770//zz return False;
2771//zz }
2772//zz return True;
2773//zz }
2774//zz
2775//zz
cerion094d1392005-06-20 13:45:57 +00002776
sewardjb51f0f42005-07-18 11:38:02 +00002777/* ------------------------------------------------------------------
2778 Integer Branch Instructions
2779 ------------------------------------------------------------------ */
cerion645c9302005-01-31 10:09:59 +00002780
cerion45552a92005-02-03 18:20:22 +00002781/*
2782 Branch helper function
2783 ok = BO[2] | ((CTR[0] != 0) ^ BO[1])
sewardjb51f0f42005-07-18 11:38:02 +00002784 Returns an I32 which is 0x00000000 if the ctr condition failed
2785 and 0xFFFFFFFF otherwise.
cerion45552a92005-02-03 18:20:22 +00002786*/
sewardjb51f0f42005-07-18 11:38:02 +00002787static IRExpr* /* :: Ity_I32 */ branch_ctr_ok( UInt BO )
cerion45552a92005-02-03 18:20:22 +00002788{
sewardjb51f0f42005-07-18 11:38:02 +00002789 IRTemp ok = newTemp(Ity_I32);
cerioned623db2005-06-20 12:42:04 +00002790
cerionb85e8bb2005-02-16 08:54:33 +00002791 if ((BO >> 2) & 1) {
sewardjb51f0f42005-07-18 11:38:02 +00002792 assign( ok, mkU32(0xFFFFFFFF) );
cerionb85e8bb2005-02-16 08:54:33 +00002793 } else {
cerionb85e8bb2005-02-16 08:54:33 +00002794 if ((BO >> 1) & 1) {
sewardjb51f0f42005-07-18 11:38:02 +00002795 assign( ok, unop( Iop_1Sto32,
2796 binop( Iop_CmpEQ32,
2797 getSPR( PPC32_SPR_CTR ), mkU32(0))) );
cerionb85e8bb2005-02-16 08:54:33 +00002798 } else {
sewardjb51f0f42005-07-18 11:38:02 +00002799 assign( ok, unop( Iop_1Sto32,
2800 binop( Iop_CmpNE32,
2801 getSPR( PPC32_SPR_CTR ), mkU32(0))) );
cerionb85e8bb2005-02-16 08:54:33 +00002802 }
2803 }
2804 return mkexpr(ok);
cerion45552a92005-02-03 18:20:22 +00002805}
2806
sewardjb51f0f42005-07-18 11:38:02 +00002807
cerion45552a92005-02-03 18:20:22 +00002808/*
sewardjb51f0f42005-07-18 11:38:02 +00002809 Branch helper function cond_ok = BO[4] | (CR[BI] == BO[3])
2810 Returns an I32 which is either 0 if the condition failed or
2811 some arbitrary nonzero value otherwise. */
2812
2813static IRExpr* /* :: Ity_I32 */ branch_cond_ok( UInt BO, UInt BI )
cerion45552a92005-02-03 18:20:22 +00002814{
sewardjb51f0f42005-07-18 11:38:02 +00002815 Int where;
2816 IRTemp res = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00002817 IRTemp cr_bi = newTemp(Ity_I32);
2818
sewardjb51f0f42005-07-18 11:38:02 +00002819 if ((BO >> 4) & 1) {
2820 assign( res, mkU32(1) );
cerionb85e8bb2005-02-16 08:54:33 +00002821 } else {
sewardjb51f0f42005-07-18 11:38:02 +00002822 // ok = (CR[BI] == BO[3]) Note, the following relies on
2823 // getCRbit_anywhere returning a value which
2824 // is either zero or has exactly 1 bit set.
2825 assign( cr_bi, getCRbit_anywhere( BI, &where ) );
cerione9d361a2005-03-04 17:35:29 +00002826
2827 if ((BO >> 3) & 1) {
sewardjb51f0f42005-07-18 11:38:02 +00002828 /* We can use cr_bi as-is. */
2829 assign( res, mkexpr(cr_bi) );
cerione9d361a2005-03-04 17:35:29 +00002830 } else {
sewardjb51f0f42005-07-18 11:38:02 +00002831 /* We have to invert the sense of the information held in
2832 cr_bi. For that we need to know which bit
2833 getCRbit_somewhere regards as significant. */
2834 assign( res, binop(Iop_Xor32, mkexpr(cr_bi), mkU32(1<<where)) );
cerionb85e8bb2005-02-16 08:54:33 +00002835 }
2836 }
sewardjb51f0f42005-07-18 11:38:02 +00002837 return mkexpr(res);
cerion45552a92005-02-03 18:20:22 +00002838}
2839
2840
cerion3d870a32005-03-18 12:23:33 +00002841/*
2842 Integer Branch Instructions
2843*/
sewardj9e6491a2005-07-02 19:24:10 +00002844static Bool dis_branch ( UInt theInstr, DisResult* dres )
cerion91ad5362005-01-27 23:02:41 +00002845{
cerionb85e8bb2005-02-16 08:54:33 +00002846 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
2847 UChar BO = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
2848 UChar BI = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
2849 UInt BD = (theInstr >> 2) & 0x3FFF; /* theInstr[2:15] */
2850 UChar b11to15 = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
2851 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
2852 UInt LI_24 = (theInstr >> 2) & 0xFFFFFF; /* theInstr[2:25] */
2853 UChar flag_AA = toUChar((theInstr >> 1) & 1); /* theInstr[1] */
2854 UChar flag_LK = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
2855
cerion4561acb2005-02-21 14:07:48 +00002856 Int exts_BD = (Int)extend_s_16to32(BD << 2);
cerion6b30d852005-06-24 11:25:46 +00002857 Int exts_LI = (Int)extend_s_26to32(LI_24 << 2);
cerionb85e8bb2005-02-16 08:54:33 +00002858
2859 Addr32 nia = 0;
2860
sewardjb51f0f42005-07-18 11:38:02 +00002861 // IRTemp ctr = newTemp(Ity_I32);
2862 // IRTemp lr = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00002863 IRTemp ir_nia = newTemp(Ity_I32);
2864 IRTemp do_branch = newTemp(Ity_I32);
sewardjb51f0f42005-07-18 11:38:02 +00002865 IRTemp ctr_ok = newTemp(Ity_I32);
2866 IRTemp cond_ok = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00002867
sewardjb51f0f42005-07-18 11:38:02 +00002868// assign( ctr, getSPR( PPC32_SPR_CTR ) );
cerion4561acb2005-02-21 14:07:48 +00002869
cerionb85e8bb2005-02-16 08:54:33 +00002870 /* Hack to pass through code that just wants to read the PC */
2871 if (theInstr == 0x429F0005) {
sewardjb51f0f42005-07-18 11:38:02 +00002872 DIP("bcl 0x%x, 0x%x (a.k.a mr lr,cia+4)\n", BO, BI);
2873 putSPR( PPC32_SPR_LR, mkU32(guest_CIA_curr_instr + 4) );
cerionb85e8bb2005-02-16 08:54:33 +00002874 return True;
sewardjb51f0f42005-07-18 11:38:02 +00002875 }
cerion45552a92005-02-03 18:20:22 +00002876
cerionb85e8bb2005-02-16 08:54:33 +00002877 switch (opc1) {
cerione9d361a2005-03-04 17:35:29 +00002878 case 0x12: // b (Branch, PPC32 p360)
cerion4561acb2005-02-21 14:07:48 +00002879 if (flag_AA) {
2880 nia = (UInt)exts_LI;
2881 } else {
sewardj9e6491a2005-07-02 19:24:10 +00002882 nia = (UInt)((Int)guest_CIA_curr_instr + exts_LI);
cerionb85e8bb2005-02-16 08:54:33 +00002883 }
cerione9d361a2005-03-04 17:35:29 +00002884 DIP("b%s%s 0x%x\n", flag_LK ? "l" : "", flag_AA ? "a" : "", nia);
2885
cerionb85e8bb2005-02-16 08:54:33 +00002886 if (flag_LK) {
sewardjb51f0f42005-07-18 11:38:02 +00002887 putSPR( PPC32_SPR_LR, mkU32(guest_CIA_curr_instr + 4) );
cerione9d361a2005-03-04 17:35:29 +00002888 }
cerionb85e8bb2005-02-16 08:54:33 +00002889 irbb->jumpkind = flag_LK ? Ijk_Call : Ijk_Boring;
2890 irbb->next = mkU32(nia);
cerionb85e8bb2005-02-16 08:54:33 +00002891 break;
2892
cerione9d361a2005-03-04 17:35:29 +00002893 case 0x10: // bc (Branch Conditional, PPC32 p361)
cerionb85e8bb2005-02-16 08:54:33 +00002894 DIP("bc%s%s 0x%x, 0x%x, 0x%x\n",
cerion4561acb2005-02-21 14:07:48 +00002895 flag_LK ? "l" : "", flag_AA ? "a" : "", BO, BI, exts_BD);
cerionb85e8bb2005-02-16 08:54:33 +00002896
2897 if (!(BO & 0x4)) {
sewardjb51f0f42005-07-18 11:38:02 +00002898 putSPR( PPC32_SPR_CTR,
2899 binop(Iop_Sub32, getSPR( PPC32_SPR_CTR ), mkU32(1)) );
cerionb85e8bb2005-02-16 08:54:33 +00002900 }
sewardjb51f0f42005-07-18 11:38:02 +00002901
2902 /* This is a bit subtle. ctr_ok is either all 0s or all 1s.
2903 cond_ok is either zero or nonzero, since that's the cheapest
2904 way to compute it. Anding them together gives a value which
2905 is either zero or non zero and so that's what we must test
2906 for in the IRStmt_Exit. */
2907 assign( ctr_ok, branch_ctr_ok( BO ) );
cerionb85e8bb2005-02-16 08:54:33 +00002908 assign( cond_ok, branch_cond_ok( BO, BI ) );
sewardjb51f0f42005-07-18 11:38:02 +00002909 assign( do_branch,
2910 binop(Iop_And32, mkexpr(cond_ok), mkexpr(ctr_ok)) );
2911
cerion4561acb2005-02-21 14:07:48 +00002912 if (flag_AA) {
2913 nia = (UInt)exts_BD;
2914 } else {
sewardj9e6491a2005-07-02 19:24:10 +00002915 nia = (UInt)((Int)guest_CIA_curr_instr + exts_BD);
cerionb85e8bb2005-02-16 08:54:33 +00002916 }
cerionb85e8bb2005-02-16 08:54:33 +00002917 if (flag_LK) {
sewardjb51f0f42005-07-18 11:38:02 +00002918 putSPR( PPC32_SPR_LR, mkU32(guest_CIA_curr_instr + 4) );
cerionb85e8bb2005-02-16 08:54:33 +00002919 }
2920
sewardjb51f0f42005-07-18 11:38:02 +00002921 stmt( IRStmt_Exit( binop(Iop_CmpNE32, mkexpr(do_branch), mkU32(0)),
cerionb85e8bb2005-02-16 08:54:33 +00002922 flag_LK ? Ijk_Call : Ijk_Boring,
2923 IRConst_U32(nia) ));
2924
2925 irbb->jumpkind = Ijk_Boring;
sewardj9e6491a2005-07-02 19:24:10 +00002926 irbb->next = mkU32(guest_CIA_curr_instr + 4);
cerionb85e8bb2005-02-16 08:54:33 +00002927 break;
2928
2929 case 0x13:
2930 if (b11to15!=0) {
2931 vex_printf("dis_int_branch(PPC32)(0x13,b11to15)\n");
2932 return False;
2933 }
cerion91ad5362005-01-27 23:02:41 +00002934
cerionb85e8bb2005-02-16 08:54:33 +00002935 switch (opc2) {
cerione9d361a2005-03-04 17:35:29 +00002936 case 0x210: // bcctr (Branch Cond. to Count Register, PPC32 p363)
cerionb85e8bb2005-02-16 08:54:33 +00002937 if ((BO & 0x4) == 0) { // "decrement and test CTR" option invalid
2938 vex_printf("dis_int_branch(PPC32)(bcctr,BO)\n");
2939 return False;
2940 }
ceriona31e8b52005-02-21 16:30:45 +00002941 DIP("bcctr%s 0x%x, 0x%x\n", flag_LK ? "l" : "", BO, BI);
cerionb85e8bb2005-02-16 08:54:33 +00002942
2943 assign( cond_ok, branch_cond_ok( BO, BI ) );
2944
sewardjb51f0f42005-07-18 11:38:02 +00002945 assign( ir_nia,
2946 binop(Iop_And32, mkU32(0xFFFFFFFC),
2947 getSPR( PPC32_SPR_CTR ) ));
cerionb85e8bb2005-02-16 08:54:33 +00002948
2949 if (flag_LK) {
sewardjb51f0f42005-07-18 11:38:02 +00002950 putSPR( PPC32_SPR_LR, mkU32(guest_CIA_curr_instr + 4) );
cerionb85e8bb2005-02-16 08:54:33 +00002951 }
2952
sewardjb51f0f42005-07-18 11:38:02 +00002953 stmt( IRStmt_Exit(
2954 binop(Iop_CmpEQ32, mkexpr(cond_ok), mkU32(0)),
2955 Ijk_Boring,
2956 IRConst_U32(guest_CIA_curr_instr + 4)
2957 ));
cerionb85e8bb2005-02-16 08:54:33 +00002958
2959 irbb->jumpkind = flag_LK ? Ijk_Call : Ijk_Boring;
2960 irbb->next = mkexpr(ir_nia);
2961 break;
2962
cerione9d361a2005-03-04 17:35:29 +00002963 case 0x010: // bclr (Branch Cond. to Link Register, PPC32 p365)
sewardjb51f0f42005-07-18 11:38:02 +00002964
2965 if ((BO & 0x14 /* 1z1zz */) == 0x14 && flag_LK == 0) {
2966 DIP("blr");
2967 } else {
2968 DIP("bclr%s 0x%x, 0x%x\n", flag_LK ? "l" : "", BO, BI);
2969 }
cerion91ad5362005-01-27 23:02:41 +00002970
cerionb85e8bb2005-02-16 08:54:33 +00002971 if (!(BO & 0x4)) {
sewardjb51f0f42005-07-18 11:38:02 +00002972 putSPR( PPC32_SPR_CTR,
2973 binop(Iop_Sub32, getSPR( PPC32_SPR_CTR ), mkU32(1)) );
cerionb85e8bb2005-02-16 08:54:33 +00002974 }
2975
sewardjb51f0f42005-07-18 11:38:02 +00002976 /* See comments above for 'bc' about this */
2977 assign( ctr_ok, branch_ctr_ok( BO ) );
2978 assign( cond_ok, branch_cond_ok( BO, BI ) );
2979 assign( do_branch,
2980 binop(Iop_And32, mkexpr(cond_ok), mkexpr(ctr_ok)) );
cerionb85e8bb2005-02-16 08:54:33 +00002981
2982 assign( ir_nia, binop(Iop_And32,
sewardjb51f0f42005-07-18 11:38:02 +00002983 getSPR( PPC32_SPR_LR ),
cerionb85e8bb2005-02-16 08:54:33 +00002984 mkU32(0xFFFFFFFC)) );
2985 if (flag_LK) {
sewardjb51f0f42005-07-18 11:38:02 +00002986 putSPR( PPC32_SPR_LR, mkU32(guest_CIA_curr_instr + 4) );
cerionb85e8bb2005-02-16 08:54:33 +00002987 }
sewardjb51f0f42005-07-18 11:38:02 +00002988
2989 stmt( IRStmt_Exit(
2990 binop(Iop_CmpEQ32, mkexpr(do_branch), mkU32(0)),
2991 Ijk_Boring,
2992 IRConst_U32(guest_CIA_curr_instr + 4)
2993 ));
2994
2995 irbb->jumpkind = flag_LK ? Ijk_Call : Ijk_Ret;
cerionb85e8bb2005-02-16 08:54:33 +00002996 irbb->next = mkexpr(ir_nia);
2997 break;
2998
2999 default:
3000 vex_printf("dis_int_branch(PPC32)(opc2)\n");
3001 return False;
3002 }
3003 break;
3004 default:
3005 vex_printf("dis_int_branch(PPC32)(opc1)\n");
3006 return False;
3007 }
cerion91ad5362005-01-27 23:02:41 +00003008
sewardj9e6491a2005-07-02 19:24:10 +00003009 dres->whatNext = Dis_StopHere;
cerionb85e8bb2005-02-16 08:54:33 +00003010 return True;
cerion91ad5362005-01-27 23:02:41 +00003011}
3012
3013
3014
cerion3d870a32005-03-18 12:23:33 +00003015/*
3016 Condition Register Logical Instructions
3017*/
cerion3007c7f2005-02-23 23:13:29 +00003018static Bool dis_cond_logic ( UInt theInstr )
3019{
3020 /* XL-Form */
3021 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
3022 UChar crbD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
3023 UChar crfD_addr = toUChar((theInstr >> 23) & 0x7); /* theInstr[23:25] */
3024 UChar crbA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
3025 UChar crfS_addr = toUChar((theInstr >> 18) & 0x7); /* theInstr[18:20] */
3026 UChar crbB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
3027 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
3028 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
3029
3030 IRTemp crbD = newTemp(Ity_I32);
3031 IRTemp crbA = newTemp(Ity_I32);
3032 IRTemp crbB = newTemp(Ity_I32);
cerione9d361a2005-03-04 17:35:29 +00003033 IRTemp tmp = newTemp(Ity_I32);
cerion3007c7f2005-02-23 23:13:29 +00003034
3035 if (opc1 != 19 || b0 != 0) {
3036 vex_printf("dis_cond_logic(PPC32)(opc1)\n");
3037 return False;
3038 }
3039
cerione9d361a2005-03-04 17:35:29 +00003040 if (opc2 == 0) { // mcrf (Move Cond Reg Field, PPC32 p464)
cerion3007c7f2005-02-23 23:13:29 +00003041 if (((crbD_addr & 0x3) != 0) ||
cerioned623db2005-06-20 12:42:04 +00003042 ((crbA_addr & 0x3) != 0) || (crbB_addr != 0))
cerion3007c7f2005-02-23 23:13:29 +00003043 return False;
sewardjb51f0f42005-07-18 11:38:02 +00003044 DIP("mcrf cr%d,cr%d\n", crfD_addr, crfS_addr);
3045 putCR0( crfD_addr, getCR0( crfS_addr) );
3046 putCR321( crfD_addr, getCR321(crfS_addr) );
cerion3007c7f2005-02-23 23:13:29 +00003047 } else {
sewardjb51f0f42005-07-18 11:38:02 +00003048 assign( crbA, getCRbit(crbA_addr) );
ceriona50fde52005-07-01 21:16:10 +00003049 if (crbA_addr == crbB_addr)
sewardjb51f0f42005-07-18 11:38:02 +00003050 crbB = crbA;
ceriona50fde52005-07-01 21:16:10 +00003051 else
sewardjb51f0f42005-07-18 11:38:02 +00003052 assign( crbB, getCRbit(crbB_addr) );
cerion3007c7f2005-02-23 23:13:29 +00003053
3054 switch (opc2) {
sewardjb51f0f42005-07-18 11:38:02 +00003055//zz case 0x101: // crand (Cond Reg AND, PPC32 p372)
3056//zz DIP("crand crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
3057//zz assign( crbD, binop(Iop_And32, mkexpr(crbA), mkexpr(crbB)) );
3058//zz break;
3059//zz case 0x081: // crandc (Cond Reg AND w. Complement, PPC32 p373)
3060//zz DIP("crandc crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
3061//zz assign( crbD, binop(Iop_And32, mkexpr(crbA),
3062//zz unop(Iop_Not32, mkexpr(crbB))) );
3063//zz break;
sewardje14bb9f2005-07-22 09:39:02 +00003064 case 0x121: // creqv (Cond Reg Equivalent, PPC32 p374)
3065 DIP("creqv crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
3066 assign( crbD, unop(Iop_Not32,
3067 binop(Iop_Xor32, mkexpr(crbA), mkexpr(crbB))) );
3068 break;
sewardjb51f0f42005-07-18 11:38:02 +00003069//zz case 0x0E1: // crnand (Cond Reg NAND, PPC32 p375)
3070//zz DIP("crnand crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
3071//zz assign( crbD, unop(Iop_Not32,
3072//zz binop(Iop_And32, mkexpr(crbA), mkexpr(crbB))) );
3073//zz break;
cerione9d361a2005-03-04 17:35:29 +00003074 case 0x021: // crnor (Cond Reg NOR, PPC32 p376)
cerion3007c7f2005-02-23 23:13:29 +00003075 DIP("crnor crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
3076 assign( crbD, unop(Iop_Not32,
3077 binop(Iop_Or32, mkexpr(crbA), mkexpr(crbB))) );
3078 break;
cerione9d361a2005-03-04 17:35:29 +00003079 case 0x1C1: // cror (Cond Reg OR, PPC32 p377)
cerion3007c7f2005-02-23 23:13:29 +00003080 DIP("cror crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
3081 assign( crbD, binop(Iop_Or32, mkexpr(crbA), mkexpr(crbB)) );
3082 break;
sewardjb51f0f42005-07-18 11:38:02 +00003083//zz case 0x1A1: // crorc (Cond Reg OR w. Complement, PPC32 p378)
3084//zz DIP("crorc crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
3085//zz assign( crbD, binop(Iop_Or32, mkexpr(crbA),
3086//zz unop(Iop_Not32, mkexpr(crbB))) );
3087//zz break;
cerione9d361a2005-03-04 17:35:29 +00003088 case 0x0C1: // crxor (Cond Reg XOR, PPC32 p379)
cerion3007c7f2005-02-23 23:13:29 +00003089 DIP("crxor crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
3090 assign( crbD, binop(Iop_Xor32, mkexpr(crbA), mkexpr(crbB)) );
3091 break;
3092
3093 default:
3094 vex_printf("dis_cond_logic(PPC32)(opc2)\n");
3095 return False;
3096 }
3097
sewardjb51f0f42005-07-18 11:38:02 +00003098 putCRbit( crbD_addr, mkexpr(crbD) );
cerion3007c7f2005-02-23 23:13:29 +00003099 }
3100 return True;
3101}
3102
3103
cerion3d870a32005-03-18 12:23:33 +00003104/*
3105 System Linkage Instructions
3106*/
sewardj9e6491a2005-07-02 19:24:10 +00003107static Bool dis_syslink ( UInt theInstr, DisResult* dres )
cerion8c3adda2005-01-31 11:54:05 +00003108{
cerionb85e8bb2005-02-16 08:54:33 +00003109 if (theInstr != 0x44000002) {
3110 vex_printf("dis_int_syslink(PPC32)(theInstr)\n");
3111 return False;
3112 }
cerione1d857b2005-02-04 18:29:05 +00003113
cerione9d361a2005-03-04 17:35:29 +00003114 // sc (System Call, PPC32 p504)
cerionb85e8bb2005-02-16 08:54:33 +00003115 DIP("sc\n");
3116
3117 /* It's important that all ArchRegs carry their up-to-date value
3118 at this point. So we declare an end-of-block here, which
3119 forces any TempRegs caching ArchRegs to be flushed. */
sewardj9e6491a2005-07-02 19:24:10 +00003120 irbb->next = mkU32( guest_CIA_curr_instr + 4 );
cerionb85e8bb2005-02-16 08:54:33 +00003121 irbb->jumpkind = Ijk_Syscall;
3122
sewardj9e6491a2005-07-02 19:24:10 +00003123 dres->whatNext = Dis_StopHere;
cerionb85e8bb2005-02-16 08:54:33 +00003124 return True;
cerion8c3adda2005-01-31 11:54:05 +00003125}
3126
cerion3d870a32005-03-18 12:23:33 +00003127
3128/*
3129 Memory Synchronization Instructions
3130*/
cerion8c3adda2005-01-31 11:54:05 +00003131static Bool dis_memsync ( UInt theInstr )
3132{
cerionb85e8bb2005-02-16 08:54:33 +00003133 /* X-Form, XL-Form */
3134 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
3135 UInt b11to25 = (theInstr >> 11) & 0x7FFF; /* theInstr[11:25] */
3136 UChar Rd_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
3137 UChar Rs_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
3138 UChar Ra_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
3139 UChar Rb_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
3140 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
3141 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
3142
3143 IRTemp EA = newTemp(Ity_I32);
3144 IRTemp Ra = newTemp(Ity_I32);
3145 IRTemp Rb = newTemp(Ity_I32);
3146 IRTemp Rs = newTemp(Ity_I32);
cerione9d361a2005-03-04 17:35:29 +00003147 IRTemp xer_so = newTemp(Ity_I32);
3148 IRTemp cr_f7 = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00003149
3150 switch (opc1) {
cerion8c3adda2005-01-31 11:54:05 +00003151 /* XL-Form */
cerione9d361a2005-03-04 17:35:29 +00003152 case 0x13: // isync (Instruction Synchronize, PPC32 p432)
cerionb85e8bb2005-02-16 08:54:33 +00003153 if (opc2 != 0x096) {
3154 vex_printf("dis_int_memsync(PPC32)(0x13,opc2)\n");
3155 return False;
3156 }
3157 if (b11to25 != 0 || b0 != 0) {
3158 vex_printf("dis_int_memsync(PPC32)(0x13,b11to25|b0)\n");
3159 return False;
3160 }
3161 DIP("isync\n");
cerionb85e8bb2005-02-16 08:54:33 +00003162 stmt( IRStmt_MFence() );
3163 break;
cerion8c3adda2005-01-31 11:54:05 +00003164
cerionb85e8bb2005-02-16 08:54:33 +00003165 /* X-Form */
3166 case 0x1F:
3167 switch (opc2) {
sewardjb51f0f42005-07-18 11:38:02 +00003168//zz case 0x356: // eieio (Enforce In-Order Execution of I/O, PPC32 p394)
3169//zz vassert(0);
3170//zz
3171//zz if (b11to25 != 0 || b0 != 0) {
3172//zz vex_printf("dis_int_memsync(PPC32)(eiei0,b11to25|b0)\n");
3173//zz return False;
3174//zz }
3175//zz DIP("eieio\n");
3176//zz return False;
cerion8c3adda2005-01-31 11:54:05 +00003177
cerione9d361a2005-03-04 17:35:29 +00003178 case 0x014: // lwarx (Load Word and Reserve Indexed, PPC32 p458)
cerionb85e8bb2005-02-16 08:54:33 +00003179 /* Note: RESERVE, RESERVE_ADDR not implemented.
3180 stwcx. is assumed to be always successful
3181 */
3182 if (b0 != 0) {
3183 vex_printf("dis_int_memsync(PPC32)(lwarx,b0)\n");
3184 return False;
3185 }
3186 DIP("lwarx r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
3187 assign( Rb, getIReg(Rb_addr) );
3188 if (Ra_addr == 0) {
3189 assign( EA, mkexpr(Rb) );
3190 } else {
3191 assign( Ra, getIReg(Ra_addr) );
ceriond7978992005-07-04 11:47:44 +00003192 assign( EA, binop(Iop_Add32, mkexpr(Ra), mkexpr(Rb)) );
cerionb85e8bb2005-02-16 08:54:33 +00003193 }
3194 putIReg( Rd_addr, loadBE(Ity_I32, mkexpr(EA)) );
3195 break;
3196
cerione9d361a2005-03-04 17:35:29 +00003197 case 0x096: // stwcx. (Store Word Conditional Indexed, PPC32 p532)
cerionb85e8bb2005-02-16 08:54:33 +00003198 /* Note: RESERVE, RESERVE_ADDR not implemented.
3199 stwcx. is assumed to be always successful
3200 */
3201 if (b0 != 1) {
3202 vex_printf("dis_int_memsync(PPC32)(stwcx.,b0)\n");
3203 return False;
3204 }
3205 DIP("stwcx. r%d,r%d,r%d\n", Rs_addr, Ra_addr, Rb_addr);
3206
3207 assign( Rb, getIReg(Rb_addr) );
3208 assign( Rs, getIReg(Rs_addr) );
3209 if (Ra_addr == 0) {
3210 assign( EA, mkexpr(Rb) );
3211 } else {
3212 assign( Ra, getIReg(Ra_addr) );
ceriond7978992005-07-04 11:47:44 +00003213 assign( EA, binop(Iop_Add32, mkexpr(Ra), mkexpr(Rb)) );
cerionb85e8bb2005-02-16 08:54:33 +00003214 }
3215 storeBE( mkexpr(EA), mkexpr(Rs) );
3216
sewardjb51f0f42005-07-18 11:38:02 +00003217 // Set CR0[LT GT EQ S0] = 0b001 || XER[SO]
3218 putCR321(0, mkU8(1<<1));
3219 putCR0(0, getXER_SO());
cerionb85e8bb2005-02-16 08:54:33 +00003220 break;
3221
cerione9d361a2005-03-04 17:35:29 +00003222 case 0x256: // sync (Synchronize, PPC32 p543)
cerionb85e8bb2005-02-16 08:54:33 +00003223 if (b11to25 != 0 || b0 != 0) {
3224 vex_printf("dis_int_memsync(PPC32)(sync,b11to25|b0)\n");
3225 return False;
3226 }
3227 DIP("sync\n");
3228 /* Insert a memory fence. It's sometimes important that these
3229 are carried through to the generated code. */
3230 stmt( IRStmt_MFence() );
3231 break;
3232
3233 default:
3234 vex_printf("dis_int_memsync(PPC32)(opc2)\n");
3235 return False;
3236 }
3237 break;
cerion8c3adda2005-01-31 11:54:05 +00003238
cerionb85e8bb2005-02-16 08:54:33 +00003239 default:
3240 vex_printf("dis_int_memsync(PPC32)(opc1)\n");
3241 return False;
3242 }
3243 return True;
cerion8c3adda2005-01-31 11:54:05 +00003244}
3245
3246
3247
cerion3d870a32005-03-18 12:23:33 +00003248/*
3249 Integer Shift Instructions
3250*/
cerion645c9302005-01-31 10:09:59 +00003251static Bool dis_int_shift ( UInt theInstr )
3252{
cerionb85e8bb2005-02-16 08:54:33 +00003253 /* X-Form */
3254 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
3255 UChar Rs_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
3256 UChar Ra_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
3257 UChar Rb_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
3258 UChar sh_imm = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
3259 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
3260 UChar flag_Rc = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
3261
cerion70e24122005-03-16 00:27:37 +00003262 UInt flag_op = PPC32G_FLAG_OP_NUMBER;
cerionb85e8bb2005-02-16 08:54:33 +00003263
3264 IRTemp sh_amt = newTemp(Ity_I8);
3265 IRTemp sign = newTemp(Ity_I32);
3266 IRTemp rb_b5 = newTemp(Ity_I32);
3267 IRTemp sext = newTemp(Ity_I32);
3268 IRTemp Rs = newTemp(Ity_I32);
3269 IRTemp Rs_sh = newTemp(Ity_I32);
cerion87d34ca2005-03-03 02:17:06 +00003270 IRTemp Rs_msk = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00003271 IRTemp Ra = newTemp(Ity_I32);
3272 IRTemp Rb = newTemp(Ity_I32);
3273 IRTemp mask = newTemp(Ity_I32);
sewardj20ef5472005-07-21 14:48:31 +00003274 IRTemp sh_amt32 = newTemp(Ity_I32);
3275 IRTemp outofrange = newTemp(Ity_I8);
cerionb85e8bb2005-02-16 08:54:33 +00003276
3277 assign( Rs, getIReg(Rs_addr) );
3278 assign( Rb, getIReg(Rb_addr) );
3279
3280 if (opc1 == 0x1F) {
3281 switch (opc2) {
cerione9d361a2005-03-04 17:35:29 +00003282 case 0x018: // slw (Shift Left Word, PPC32 p505)
cerionb85e8bb2005-02-16 08:54:33 +00003283 DIP("slw%s r%d,r%d,r%d\n", flag_Rc ? "." : "",
3284 Ra_addr, Rs_addr, Rb_addr);
3285 assign( sh_amt, binop(Iop_And8, mkU8(0x1F),
3286 unop(Iop_32to8, mkexpr(Rb))) );
cerion3a589ea2005-03-14 16:30:09 +00003287 assign( Rs_sh, binop(Iop_Shl32, mkexpr(Rs), mkexpr(sh_amt)) );
3288 assign( rb_b5, binop(Iop_And32, mkexpr(Rb), mkU32(1<<5)) );
3289 assign( Ra, IRExpr_Mux0X( unop(Iop_32to8, mkexpr(rb_b5)),
3290 mkexpr(Rs_sh), mkU32(0) ));
cerionb85e8bb2005-02-16 08:54:33 +00003291 break;
3292
cerione9d361a2005-03-04 17:35:29 +00003293 case 0x318: // sraw (Shift Right Algebraic Word, PPC32 p506)
cerionb85e8bb2005-02-16 08:54:33 +00003294 DIP("sraw%s r%d,r%d,r%d\n", flag_Rc ? "." : "",
3295 Ra_addr, Rs_addr, Rb_addr);
3296
sewardj20ef5472005-07-21 14:48:31 +00003297 /* JRS: my reading of the (poorly worded) PPC32 doc p506 is:
3298 amt = Rb & 63
3299 Ra = Sar32( Rs, amt > 31 ? 31 : amt )
3300 XER.CA = amt > 31 ? sign-of-Rs : (computation as per srawi)
3301 */
3302 assign( sh_amt32, binop(Iop_And32, mkU32(0x3F), mkexpr(Rb)) );
3303 assign( outofrange,
3304 unop( Iop_1Uto8,
3305 binop(Iop_CmpLT32U, mkU32(31), mkexpr(sh_amt32)) ));
3306 assign( Ra,
3307 binop( Iop_Sar32,
3308 mkexpr(Rs),
3309 unop( Iop_32to8,
3310 IRExpr_Mux0X( mkexpr(outofrange),
3311 mkexpr(sh_amt32),
3312 mkU32(31)) ))
3313 );
3314 set_XER_CA( PPC32G_FLAG_OP_SRAW,
3315 mkexpr(Ra), mkexpr(Rs), mkexpr(sh_amt32),
3316 get_XER_CA() );
cerionb85e8bb2005-02-16 08:54:33 +00003317 break;
3318
cerione9d361a2005-03-04 17:35:29 +00003319 case 0x338: // srawi (Shift Right Algebraic Word Immediate, PPC32 p507)
cerionb85e8bb2005-02-16 08:54:33 +00003320 DIP("srawi%s r%d,r%d,%d\n", flag_Rc ? "." : "",
3321 Ra_addr, Rs_addr, sh_imm);
sewardj20ef5472005-07-21 14:48:31 +00003322 vassert(sh_imm < 32);
cerionb85e8bb2005-02-16 08:54:33 +00003323 assign( sh_amt, mkU8(sh_imm) );
sewardj20ef5472005-07-21 14:48:31 +00003324 assign( Ra, binop(Iop_Sar32, mkexpr(Rs), mkexpr(sh_amt)) );
3325 set_XER_CA( PPC32G_FLAG_OP_SRAWI,
3326 mkexpr(Ra), mkexpr(Rs), mkU32(sh_imm),
3327 get_XER_CA() );
cerionb85e8bb2005-02-16 08:54:33 +00003328 break;
3329
cerione9d361a2005-03-04 17:35:29 +00003330 case 0x218: // srw (Shift Right Word, PPC32 p508)
cerionb85e8bb2005-02-16 08:54:33 +00003331 DIP("srw%s r%d,r%d,r%d\n", flag_Rc ? "." : "",
3332 Ra_addr, Rs_addr, Rb_addr);
3333 assign( sh_amt, binop(Iop_And8, mkU8(0x1F),
cerion3a589ea2005-03-14 16:30:09 +00003334 unop(Iop_32to8, mkexpr(Rb))) );
cerionb85e8bb2005-02-16 08:54:33 +00003335 assign( Rs_sh, binop(Iop_Shr32, mkexpr(Rs), mkexpr(sh_amt)) );
3336 assign( rb_b5, binop(Iop_And32, mkexpr(Rb), mkU32(1<<5)) );
3337 assign( Ra, IRExpr_Mux0X( unop(Iop_32to8, mkexpr(rb_b5)),
cerion2ee871e2005-03-01 09:32:01 +00003338 mkexpr(Rs_sh), mkU32(0) ));
cerionb85e8bb2005-02-16 08:54:33 +00003339 break;
3340
3341 default:
3342 vex_printf("dis_int_shift(PPC32)(opc2)\n");
3343 return False;
3344 }
3345 } else {
3346 vex_printf("dis_int_shift(PPC32)(opc1)\n");
3347 return False;
3348 }
cerion0d330c52005-02-28 16:43:16 +00003349
3350 putIReg( Ra_addr, mkexpr(Ra) );
cerionb85e8bb2005-02-16 08:54:33 +00003351
cerionb85e8bb2005-02-16 08:54:33 +00003352 if (flag_Rc) {
sewardj20ef5472005-07-21 14:48:31 +00003353 set_CR0( mkexpr(Ra) );
cerionb85e8bb2005-02-16 08:54:33 +00003354 }
3355 return True;
cerion645c9302005-01-31 10:09:59 +00003356}
3357
3358
3359
sewardjb51f0f42005-07-18 11:38:02 +00003360//zz /*
3361//zz Integer Load/Store Reverse Instructions
3362//zz */
3363//zz static Bool dis_int_ldst_rev ( UInt theInstr )
3364//zz {
3365//zz /* X-Form */
3366//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
3367//zz UChar Rd_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
3368//zz UChar Rs_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
3369//zz UChar Ra_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
3370//zz UChar Rb_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
3371//zz UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
3372//zz UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
3373//zz
3374//zz IRTemp EA = newTemp(Ity_I32);
3375//zz IRTemp Rd = newTemp(Ity_I32);
3376//zz IRTemp Rs = newTemp(Ity_I32);
3377//zz IRTemp byte0 = newTemp(Ity_I32);
3378//zz IRTemp byte1 = newTemp(Ity_I32);
3379//zz IRTemp byte2 = newTemp(Ity_I32);
3380//zz IRTemp byte3 = newTemp(Ity_I32);
3381//zz IRTemp tmp16 = newTemp(Ity_I16);
3382//zz IRTemp tmp32 = newTemp(Ity_I32);
3383//zz
3384//zz if (opc1 != 0x1F || b0 != 0) {
3385//zz vex_printf("dis_int_ldst_rev(PPC32)(opc1|b0)\n");
3386//zz return False;
3387//zz }
3388//zz
3389//zz if (Ra_addr == 0) {
3390//zz assign( EA, getIReg(Rb_addr));
3391//zz } else {
3392//zz assign( EA, binop(Iop_Add32, getIReg(Ra_addr), getIReg(Rb_addr)) );
3393//zz }
3394//zz
3395//zz switch (opc2) {
3396//zz case 0x316: // lhbrx (Load Half Word Byte-Reverse Indexed, PPC32 p449)
3397//zz vassert(0);
3398//zz
3399//zz DIP("lhbrx r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
3400//zz assign( byte0, loadBE(Ity_I8, mkexpr(EA)) );
3401//zz assign( byte1, loadBE(Ity_I8, binop(Iop_Add32, mkexpr(EA),mkU32(1))) );
3402//zz assign( Rd, binop(Iop_Or32,
3403//zz binop(Iop_Shl32, mkexpr(byte1), mkU8(8)),
3404//zz mkexpr(byte0)) );
3405//zz putIReg( Rd_addr, mkexpr(Rd));
3406//zz break;
3407//zz
3408//zz case 0x216: // lwbrx (Load Word Byte-Reverse Indexed, PPC32 p459)
3409//zz vassert(0);
3410//zz
3411//zz DIP("lwbrx r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
3412//zz assign( byte0, loadBE(Ity_I8, mkexpr(EA)) );
3413//zz assign( byte1, loadBE(Ity_I8, binop(Iop_Add32, mkexpr(EA),mkU32(1))) );
3414//zz assign( byte2, loadBE(Ity_I8, binop(Iop_Add32, mkexpr(EA),mkU32(2))) );
3415//zz assign( byte3, loadBE(Ity_I8, binop(Iop_Add32, mkexpr(EA),mkU32(3))) );
3416//zz assign( Rd, binop(Iop_Or32,
3417//zz binop(Iop_Or32,
3418//zz binop(Iop_Shl32, mkexpr(byte3), mkU8(24)),
3419//zz binop(Iop_Shl32, mkexpr(byte2), mkU8(16))),
3420//zz binop(Iop_Or32,
3421//zz binop(Iop_Shl32, mkexpr(byte1), mkU8(8)),
3422//zz mkexpr(byte0))) );
3423//zz putIReg( Rd_addr, mkexpr(Rd));
3424//zz break;
3425//zz
3426//zz case 0x396: // sthbrx (Store Half Word Byte-Reverse Indexed, PPC32 p523)
3427//zz vassert(0);
3428//zz
3429//zz DIP("sthbrx r%d,r%d,r%d\n", Rs_addr, Ra_addr, Rb_addr);
3430//zz assign( Rs, getIReg(Rs_addr) );
3431//zz assign( byte0, binop(Iop_And32, mkexpr(Rs), mkU32(0x00FF)) );
3432//zz assign( byte1, binop(Iop_And32, mkexpr(Rs), mkU32(0xFF00)) );
3433//zz
3434//zz assign( tmp16,
3435//zz unop(Iop_32to16,
3436//zz binop(Iop_Or32,
3437//zz binop(Iop_Shl32, mkexpr(byte0), mkU8(8)),
3438//zz binop(Iop_Shr32, mkexpr(byte1), mkU8(8)))) );
3439//zz storeBE( mkexpr(EA), getIReg(tmp16) );
3440//zz break;
3441//zz
3442//zz case 0x296: // stwbrx (Store Word Byte-Reverse Indexed, PPC32 p531)
3443//zz vassert(0);
3444//zz
3445//zz DIP("stwbrx r%d,r%d,r%d\n", Rs_addr, Ra_addr, Rb_addr);
3446//zz assign( Rs, getIReg(Rs_addr) );
3447//zz assign( byte0, binop(Iop_And32, mkexpr(Rs), mkU32(0x000000FF)) );
3448//zz assign( byte1, binop(Iop_And32, mkexpr(Rs), mkU32(0x0000FF00)) );
3449//zz assign( byte2, binop(Iop_And32, mkexpr(Rs), mkU32(0x00FF0000)) );
3450//zz assign( byte3, binop(Iop_And32, mkexpr(Rs), mkU32(0xFF000000)) );
3451//zz
3452//zz assign( tmp32,
3453//zz binop(Iop_Or32,
3454//zz binop(Iop_Or32,
3455//zz binop(Iop_Shl32, mkexpr(byte0), mkU8(24)),
3456//zz binop(Iop_Shl32, mkexpr(byte1), mkU8(8))),
3457//zz binop(Iop_Or32,
3458//zz binop(Iop_Shr32, mkexpr(byte2), mkU8(8)),
3459//zz binop(Iop_Shr32, mkexpr(byte3), mkU8(24)))) );
3460//zz storeBE( mkexpr(EA), mkexpr(tmp32) );
3461//zz break;
3462//zz
3463//zz default:
3464//zz vex_printf("dis_int_ldst_rev(PPC32)(opc2)\n");
3465//zz return False;
3466//zz }
3467//zz return True;
3468//zz }
cerion645c9302005-01-31 10:09:59 +00003469
3470
3471
cerion3d870a32005-03-18 12:23:33 +00003472/*
3473 Processor Control Instructions
3474*/
cerion8c3adda2005-01-31 11:54:05 +00003475static Bool dis_proc_ctl ( UInt theInstr )
3476{
cerionb85e8bb2005-02-16 08:54:33 +00003477 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
3478
3479 /* X-Form */
3480 UChar crfD = toUChar((theInstr >> 23) & 0x7); /* theInstr[23:25] */
3481 UChar b21to22 = toUChar((theInstr >> 21) & 0x3); /* theInstr[21:22] */
3482 UChar Rd_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
3483 UInt b11to20 = (theInstr >> 11) & 0x3FF; /* theInstr[11:20] */
3484
3485 /* XFX-Form */
3486 UChar Rs_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
3487 UInt SPR = (theInstr >> 11) & 0x3FF; /* theInstr[11:20] */
3488 UInt TBR = (theInstr >> 11) & 0x3FF; /* theInstr[11:20] */
3489 UChar b20 = toUChar((theInstr >> 11) & 0x1); /* theInstr[11] */
3490 UInt CRM = (theInstr >> 12) & 0xFF; /* theInstr[12:19] */
3491 UChar b11 = toUChar((theInstr >> 11) & 0x1); /* theInstr[20] */
3492
3493 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
3494 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
3495
3496 UInt SPR_flipped = ((SPR & 0x1F) << 5) | ((SPR >> 5) & 0x1F);
cerione9d361a2005-03-04 17:35:29 +00003497
3498 IRTemp Rs = newTemp(Ity_I32);
3499 IRTemp tmp = newTemp(Ity_I32);
cerion48090c02005-02-24 11:19:51 +00003500
cerionb85e8bb2005-02-16 08:54:33 +00003501 assign( Rs, getIReg(Rs_addr) );
3502
3503 if (opc1 != 0x1F || b0 != 0) {
3504 vex_printf("dis_proc_ctl(PPC32)(opc1|b0)\n");
3505 return False;
3506 }
3507
3508 switch (opc2) {
sewardjb51f0f42005-07-18 11:38:02 +00003509//zz /* X-Form */
3510//zz case 0x200: // mcrxr (Move to Condition Register from XER, PPC32 p466)
3511//zz if (b21to22 != 0 || b11to20 != 0) {
3512//zz vex_printf("dis_proc_ctl(PPC32)(mcrxr,b21to22|b11to20)\n");
3513//zz return False;
3514//zz }
3515//zz DIP("mcrxr crf%d\n", crfD);
3516//zz
3517//zz // CR[7-crfD] = XER[28-31]
3518//zz assign( tmp, getReg_field( PPC32_SPR_XER, 7 ) );
3519//zz putReg_field( PPC32_SPR_CR, mkexpr(tmp), 7-crfD );
3520//zz
3521//zz // Clear XER[28 - 31]
3522//zz putReg_field( PPC32_SPR_XER, mkU32(0), 7 );
3523//zz break;
cerionb85e8bb2005-02-16 08:54:33 +00003524
cerione9d361a2005-03-04 17:35:29 +00003525 case 0x013: // mfcr (Move from Condition Register, PPC32 p467)
cerionb85e8bb2005-02-16 08:54:33 +00003526 if (b11to20 != 0) {
3527 vex_printf("dis_proc_ctl(PPC32)(mfcr,b11to20)\n");
3528 return False;
3529 }
sewardjb51f0f42005-07-18 11:38:02 +00003530 DIP("mfcr r%d\n", Rd_addr);
3531 putIReg( Rd_addr, getEntireCR() );
cerionb85e8bb2005-02-16 08:54:33 +00003532 break;
3533
3534 /* XFX-Form */
cerione9d361a2005-03-04 17:35:29 +00003535 case 0x153: // mfspr (Move from Special-Purpose Register, PPC32 p470)
cerionb85e8bb2005-02-16 08:54:33 +00003536
3537 switch (SPR_flipped) { // Choose a register...
sewardj20ef5472005-07-21 14:48:31 +00003538
3539 case 0x1:
3540 DIP("mfxer r%d\n", Rd_addr);
3541 /* sheesh [kebab] */
3542 putIReg(
3543 Rd_addr,
3544 binop(
3545 Iop_Or32,
3546 binop(
3547 Iop_Or32,
3548 binop( Iop_Shl32,
3549 binop( Iop_And32,
3550 unop( Iop_8Uto32,
3551 IRExpr_Get( OFFB_XER_SO, Ity_I8 )),
3552 mkU32(1)),
3553 mkU8(31)),
3554 binop( Iop_Shl32,
3555 binop( Iop_And32,
3556 unop( Iop_8Uto32,
3557 IRExpr_Get( OFFB_XER_OV, Ity_I8 )),
3558 mkU32(1)),
3559 mkU8(30))
3560 ),
3561 binop(
3562 Iop_Or32,
3563 binop( Iop_Shl32,
3564 binop( Iop_And32,
3565 unop( Iop_8Uto32,
3566 IRExpr_Get( OFFB_XER_CA, Ity_I8 )),
3567 mkU32(1)),
3568 mkU8(29)),
3569 binop( Iop_And32,
3570 unop( Iop_8Uto32,
3571 IRExpr_Get( OFFB_XER_BC, Ity_I8 )),
3572 mkU32(0xFF))
3573 )
3574 )
3575 );
3576 break;
3577
sewardjb51f0f42005-07-18 11:38:02 +00003578 case 0x8:
3579 DIP("mflr r%d\n", Rd_addr);
3580 putIReg( Rd_addr, getSPR( PPC32_SPR_LR ) );
3581 break;
3582 case 0x9:
3583 DIP("mfctr r%d\n", Rd_addr);
3584 putIReg( Rd_addr, getSPR( PPC32_SPR_CTR ) );
3585 break;
3586 case 0x100:
3587 DIP("mfvrsave r%d\n", Rd_addr);
3588 putIReg( Rd_addr, getSPR( PPC32_SPR_VRSAVE ) );
3589 break;
ceriona982c052005-06-28 17:23:09 +00003590
sewardjb51f0f42005-07-18 11:38:02 +00003591 case 0x012: case 0x013: case 0x016:
3592 case 0x019: case 0x01A: case 0x01B:
3593 case 0x110: case 0x111: case 0x112: case 0x113:
3594 // case 0x118: // 64bit only
3595 case 0x11A: case 0x11F:
3596 case 0x210: case 0x211: case 0x212: case 0x213:
3597 case 0x214: case 0x215: case 0x216: case 0x217:
3598 case 0x218: case 0x219: case 0x21A: case 0x21B:
3599 case 0x21C: case 0x21D: case 0x21E: case 0x21F:
3600 case 0x3F5:
3601 vex_printf("dis_proc_ctl(PPC32)(mfspr) - supervisor level op\n");
3602 return False;
cerion45552a92005-02-03 18:20:22 +00003603
sewardjb51f0f42005-07-18 11:38:02 +00003604 default:
3605 vex_printf("dis_proc_ctl(PPC32)(mfspr,SPR_flipped)(0x%x)\n",
3606 SPR_flipped);
3607 return False;
cerionb85e8bb2005-02-16 08:54:33 +00003608 }
3609 break;
3610
sewardjb51f0f42005-07-18 11:38:02 +00003611//zz case 0x173: // mftb (Move from Time Base, PPC32 p475)
3612//zz vassert(0);
3613//zz
3614//zz DIP("mftb r%d,0x%x\n", Rd_addr, TBR);
3615//zz return False;
cerionb85e8bb2005-02-16 08:54:33 +00003616
sewardjb51f0f42005-07-18 11:38:02 +00003617 case 0x090: // mtcrf (Move to Condition Register Fields, PPC32 p477)
cerionb85e8bb2005-02-16 08:54:33 +00003618 if (b11 != 0 || b20 != 0) {
3619 vex_printf("dis_proc_ctl(PPC32)(mtcrf,b11|b20)\n");
3620 return False;
3621 }
3622 DIP("mtcrf 0x%x,r%d\n", CRM, Rs_addr);
sewardjb51f0f42005-07-18 11:38:02 +00003623 putCRfields ( mkexpr(Rs), CRM );
cerionb85e8bb2005-02-16 08:54:33 +00003624 break;
cerione9d361a2005-03-04 17:35:29 +00003625
3626 case 0x1D3: // mtspr (Move to Special-Purpose Register, PPC32 p483)
cerionb85e8bb2005-02-16 08:54:33 +00003627
3628 switch (SPR_flipped) { // Choose a register...
sewardj20ef5472005-07-21 14:48:31 +00003629 case 0x1:
3630 DIP("mtxer r%d\n", Rs_addr);
sewardj0e88d8f2005-07-21 16:58:55 +00003631 stmt(IRStmt_Put(
sewardj20ef5472005-07-21 14:48:31 +00003632 OFFB_XER_SO,
3633 unop( Iop_32to8,
3634 binop( Iop_And32,
sewardj0e88d8f2005-07-21 16:58:55 +00003635 binop(Iop_Shr32, mkexpr(Rs), mkU8(31)),
sewardj20ef5472005-07-21 14:48:31 +00003636 mkU32(1)) )
sewardj0e88d8f2005-07-21 16:58:55 +00003637 ));
3638 stmt(IRStmt_Put(
sewardj20ef5472005-07-21 14:48:31 +00003639 OFFB_XER_OV,
3640 unop( Iop_32to8,
3641 binop( Iop_And32,
sewardj0e88d8f2005-07-21 16:58:55 +00003642 binop(Iop_Shr32, mkexpr(Rs), mkU8(30)),
sewardj20ef5472005-07-21 14:48:31 +00003643 mkU32(1)) )
sewardj0e88d8f2005-07-21 16:58:55 +00003644 ));
3645 stmt(IRStmt_Put(
sewardj20ef5472005-07-21 14:48:31 +00003646 OFFB_XER_CA,
3647 unop( Iop_32to8,
3648 binop( Iop_And32,
sewardj0e88d8f2005-07-21 16:58:55 +00003649 binop(Iop_Shr32, mkexpr(Rs), mkU8(29)),
sewardj20ef5472005-07-21 14:48:31 +00003650 mkU32(1)) )
sewardj0e88d8f2005-07-21 16:58:55 +00003651 ));
3652 stmt(IRStmt_Put(
sewardj20ef5472005-07-21 14:48:31 +00003653 OFFB_XER_BC,
3654 unop( Iop_32to8,
sewardj0e88d8f2005-07-21 16:58:55 +00003655 binop( Iop_And32, mkexpr(Rs), mkU32(0xFF)) )
3656 ));
sewardj20ef5472005-07-21 14:48:31 +00003657 break;
sewardjb51f0f42005-07-18 11:38:02 +00003658 case 0x8:
3659 DIP("mtlr r%d\n", Rs_addr);
3660 putSPR( PPC32_SPR_LR, mkexpr(Rs) );
3661 break;
3662 case 0x9:
3663 DIP("mtctr r%d\n", Rs_addr);
3664 putSPR( PPC32_SPR_CTR, mkexpr(Rs) );
3665 break;
3666 case 0x100:
3667 DIP("mtvrsave r%d\n", Rs_addr);
3668 putSPR( PPC32_SPR_VRSAVE, mkexpr(Rs) );
3669 break;
3670//zz
3671//zz case 0x012: case 0x013: case 0x016:
3672//zz case 0x019: case 0x01A: case 0x01B:
3673//zz case 0x110: case 0x111: case 0x112: case 0x113:
3674//zz // case 0x118: // 64bit only
3675//zz case 0x11A: case 0x11C: case 0x11D:
3676//zz case 0x210: case 0x211: case 0x212: case 0x213:
3677//zz case 0x214: case 0x215: case 0x216: case 0x217:
3678//zz case 0x218: case 0x219: case 0x21A: case 0x21B:
3679//zz case 0x21C: case 0x21D: case 0x21E: case 0x21F:
3680//zz case 0x3F5:
3681//zz vex_printf("dis_proc_ctl(PPC32)(mtspr) - supervisor level op\n");
3682//zz return False;
cerion8c3adda2005-01-31 11:54:05 +00003683
sewardjb51f0f42005-07-18 11:38:02 +00003684 default:
3685 vex_printf("dis_proc_ctl(PPC32)(mtspr,SPR_flipped)(%d)\n",
3686 SPR_flipped);
3687 return False;
cerionb85e8bb2005-02-16 08:54:33 +00003688 }
3689 break;
3690
3691 default:
3692 vex_printf("dis_proc_ctl(PPC32)(opc2)\n");
3693 return False;
3694 }
3695 return True;
cerion8c3adda2005-01-31 11:54:05 +00003696}
3697
3698
cerion3d870a32005-03-18 12:23:33 +00003699/*
3700 Cache Management Instructions
3701*/
sewardjd94b73a2005-06-30 12:08:48 +00003702static Bool dis_cache_manage ( UInt theInstr,
sewardj9e6491a2005-07-02 19:24:10 +00003703 DisResult* dres,
sewardjd94b73a2005-06-30 12:08:48 +00003704 VexArchInfo* guest_archinfo )
cerion8c3adda2005-01-31 11:54:05 +00003705{
cerionb85e8bb2005-02-16 08:54:33 +00003706 /* X-Form */
3707 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
3708 UChar b21to25 = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
3709 UChar Ra_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
3710 UChar Rb_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
3711 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
3712 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
sewardjb51f0f42005-07-18 11:38:02 +00003713 Int lineszB = guest_archinfo->ppc32_cache_line_szB;
cerion094d1392005-06-20 13:45:57 +00003714
cerionb85e8bb2005-02-16 08:54:33 +00003715 if (opc1 != 0x1F || b21to25 != 0 || b0 != 0) {
3716 vex_printf("dis_cache_manage(PPC32)(opc1|b21to25|b0)\n");
3717 return False;
3718 }
sewardjd94b73a2005-06-30 12:08:48 +00003719
3720 /* stay sane .. */
3721 vassert(lineszB == 32 || lineszB == 128);
cerionb85e8bb2005-02-16 08:54:33 +00003722
3723 switch (opc2) {
sewardjb51f0f42005-07-18 11:38:02 +00003724//zz case 0x2F6: // dcba (Data Cache Block Allocate, PPC32 p380)
3725//zz vassert(0); /* AWAITING TEST CASE */
3726//zz DIP("dcba r%d,r%d\n", Ra_addr, Rb_addr);
3727//zz if (0) vex_printf("vex ppc32->IR: kludged dcba\n");
3728//zz break;
sewardj20ef5472005-07-21 14:48:31 +00003729
3730 case 0x056: // dcbf (Data Cache Block Flush, PPC32 p382)
3731 DIP("dcbf r%d,r%d\n", Ra_addr, Rb_addr);
3732 /* nop as far as vex is concerned */
3733 if (0) vex_printf("vex ppc32->IR: kludged dcbf\n");
3734 break;
cerionb85e8bb2005-02-16 08:54:33 +00003735
cerione9d361a2005-03-04 17:35:29 +00003736 case 0x036: // dcbst (Data Cache Block Store, PPC32 p384)
cerionb85e8bb2005-02-16 08:54:33 +00003737 DIP("dcbst r%d,r%d\n", Ra_addr, Rb_addr);
sewardjb51f0f42005-07-18 11:38:02 +00003738 /* nop as far as vex is concerned */
cerionb85e8bb2005-02-16 08:54:33 +00003739 break;
cerion8c3adda2005-01-31 11:54:05 +00003740
cerione9d361a2005-03-04 17:35:29 +00003741 case 0x116: // dcbt (Data Cache Block Touch, PPC32 p385)
cerionb85e8bb2005-02-16 08:54:33 +00003742 DIP("dcbt r%d,r%d\n", Ra_addr, Rb_addr);
sewardjb51f0f42005-07-18 11:38:02 +00003743 /* nop as far as vex is concerned */
cerionb85e8bb2005-02-16 08:54:33 +00003744 break;
3745
cerione9d361a2005-03-04 17:35:29 +00003746 case 0x0F6: // dcbtst (Data Cache Block Touch for Store, PPC32 p386)
cerionb85e8bb2005-02-16 08:54:33 +00003747 DIP("dcbtst r%d,r%d\n", Ra_addr, Rb_addr);
sewardjb51f0f42005-07-18 11:38:02 +00003748 /* nop as far as vex is concerned */
cerionb85e8bb2005-02-16 08:54:33 +00003749 break;
3750
cerion094d1392005-06-20 13:45:57 +00003751 case 0x3F6: { // dcbz (Data Cache Block Clear to Zero, PPC32 p387)
sewardjd94b73a2005-06-30 12:08:48 +00003752 /* Clear all bytes in cache block at (rA|0) + rB. */
cerion094d1392005-06-20 13:45:57 +00003753 IRTemp EA = newTemp(Ity_I32);
3754 IRTemp addr = newTemp(Ity_I32);
3755 IRExpr* irx_addr;
cerion094d1392005-06-20 13:45:57 +00003756 UInt i;
cerionb85e8bb2005-02-16 08:54:33 +00003757 DIP("dcbz r%d,r%d\n", Ra_addr, Rb_addr);
cerion094d1392005-06-20 13:45:57 +00003758 assign( EA,
3759 binop( Iop_Add32,
3760 getIReg(Rb_addr),
3761 Ra_addr==0 ? mkU32(0) : getIReg(Ra_addr)) );
3762
3763 /* Round EA down to the start of the containing block. */
3764 assign( addr,
3765 binop( Iop_And32,
3766 mkexpr(EA),
sewardjd94b73a2005-06-30 12:08:48 +00003767 mkU32( ~(lineszB-1) )) );
cerion094d1392005-06-20 13:45:57 +00003768
sewardjd94b73a2005-06-30 12:08:48 +00003769 for (i = 0; i < lineszB / 4; i++) {
3770 irx_addr = binop( Iop_Add32, mkexpr(addr), mkU32(i*4) );
3771 storeBE( irx_addr, mkU32(0) );
cerion094d1392005-06-20 13:45:57 +00003772 }
cerionb85e8bb2005-02-16 08:54:33 +00003773 break;
cerion094d1392005-06-20 13:45:57 +00003774 }
cerion8c3adda2005-01-31 11:54:05 +00003775
sewardj7ce9d152005-03-15 16:54:13 +00003776 case 0x3D6: {
3777 // icbi (Instruction Cache Block Invalidate, PPC32 p431)
3778 /* Invalidate all translations containing code from the cache
sewardjd94b73a2005-06-30 12:08:48 +00003779 block at (rA|0) + rB. */
sewardj7ce9d152005-03-15 16:54:13 +00003780 IRTemp addr = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00003781 DIP("icbi r%d,r%d\n", Ra_addr, Rb_addr);
sewardj7ce9d152005-03-15 16:54:13 +00003782
3783 assign( addr,
3784 binop( Iop_Add32,
3785 getIReg(Rb_addr),
3786 Ra_addr==0 ? mkU32(0) : getIReg(Ra_addr)) );
3787
3788 /* Round addr down to the start of the containing block. */
3789 stmt( IRStmt_Put(
3790 OFFB_TISTART,
3791 binop( Iop_And32,
3792 mkexpr(addr),
sewardjd94b73a2005-06-30 12:08:48 +00003793 mkU32( ~(lineszB-1) ))) );
sewardj7ce9d152005-03-15 16:54:13 +00003794
sewardjd94b73a2005-06-30 12:08:48 +00003795 stmt( IRStmt_Put(OFFB_TILEN, mkU32(lineszB) ) );
sewardj7ce9d152005-03-15 16:54:13 +00003796
sewardja8078f62005-03-15 18:27:40 +00003797 /* be paranoid ... */
3798 stmt( IRStmt_MFence() );
3799
sewardj7ce9d152005-03-15 16:54:13 +00003800 irbb->jumpkind = Ijk_TInval;
sewardj9e6491a2005-07-02 19:24:10 +00003801 irbb->next = mkU32(guest_CIA_curr_instr + 4);
3802 dres->whatNext = Dis_StopHere;
cerionb85e8bb2005-02-16 08:54:33 +00003803 break;
sewardj7ce9d152005-03-15 16:54:13 +00003804 }
cerion8c3adda2005-01-31 11:54:05 +00003805
cerionb85e8bb2005-02-16 08:54:33 +00003806 default:
3807 vex_printf("dis_cache_manage(PPC32)(opc2)\n");
3808 return False;
3809 }
3810 return True;
cerion8c3adda2005-01-31 11:54:05 +00003811}
3812
3813
sewardje14bb9f2005-07-22 09:39:02 +00003814/*------------------------------------------------------------*/
3815/*--- Floating Point Helpers ---*/
3816/*------------------------------------------------------------*/
3817
3818/* --- Set the emulation-warning pseudo-register. --- */
3819
3820static void put_emwarn ( IRExpr* e /* :: Ity_I32 */ )
3821{
3822 vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_I32);
3823 stmt( IRStmt_Put( OFFB_EMWARN, e ) );
3824}
3825
3826/* --------- Synthesise a 2-bit FPU rounding mode. --------- */
3827/* Produces a value in 0 .. 3, which is encoded as per the type
3828 IRRoundingMode. PPC32RoundingMode encoding is different to
3829 IRRoundingMode, so need to map it.
3830*/
3831static IRExpr* /* :: Ity_I32 */ get_roundingmode ( void )
3832{
3833/*
3834 rounding mode | PPC | IR
3835 ------------------------
3836 to nearest | 00 | 00
3837 to zero | 01 | 11
3838 to +infinity | 10 | 10
3839 to -infinity | 11 | 01
3840*/
3841 IRTemp rm_PPC32 = newTemp(Ity_I32);
3842 assign( rm_PPC32, getReg_masked( PPC32_SPR_FPSCR, MASK_FPSCR_RN ) );
3843
3844 // rm_IR = XOR( rm_PPC32, (rm_PPC32 << 1) & 2)
3845 return binop(Iop_Xor32, mkexpr(rm_PPC32),
3846 binop(Iop_And32, mkU32(2),
3847 binop(Iop_Shl32, mkexpr(rm_PPC32), mkU8(1))));
3848}
3849
3850/* Round float to single precision
3851 - returns type Ity_F64 */
3852static IRExpr* roundToSgl ( IRExpr* src )
3853{
3854 return unop(Iop_F32toF64, binop(Iop_F64toF32, get_roundingmode(), src));
3855}
cerion094d1392005-06-20 13:45:57 +00003856
3857
cerion3d870a32005-03-18 12:23:33 +00003858/*------------------------------------------------------------*/
3859/*--- Floating Point Instruction Translation ---*/
3860/*------------------------------------------------------------*/
3861
3862/*
3863 Floating Point Load Instructions
3864*/
3865static Bool dis_fp_load ( UInt theInstr )
3866{
3867 /* X-Form */
cerion094d1392005-06-20 13:45:57 +00003868 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
3869 UChar frD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
3870 UChar rA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
3871 UChar rB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
3872 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
3873 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
cerion3d870a32005-03-18 12:23:33 +00003874
3875 /* D-Form */
cerion094d1392005-06-20 13:45:57 +00003876 UInt d_imm = (theInstr >> 0) & 0xFFFF; /* theInstr[0:15] */
3877
sewardjdb36c0f2005-07-03 00:05:31 +00003878 Int exts_d_imm = extend_s_16to32(d_imm);
cerion094d1392005-06-20 13:45:57 +00003879
3880 IRTemp EA = newTemp(Ity_I32);
3881 IRTemp rA = newTemp(Ity_I32);
3882 IRTemp rB = newTemp(Ity_I32);
3883 IRTemp rA_or_0 = newTemp(Ity_I32);
3884
3885 assign( rA, getIReg(rA_addr) );
3886 assign( rB, getIReg(rB_addr) );
3887 assign( rA_or_0, (rA_addr == 0) ? mkU32(0) : mkexpr(rA) );
cerion3d870a32005-03-18 12:23:33 +00003888
3889 switch(opc1) {
sewardje14bb9f2005-07-22 09:39:02 +00003890 case 0x30: // lfs (Load Float Single, PPC32 p441)
3891 DIP("lfs fr%d,%d(r%d)\n", frD_addr, exts_d_imm, rA_addr);
3892 assign( EA, binop(Iop_Add32, mkU32(exts_d_imm), mkexpr(rA_or_0)) );
3893 putFReg( frD_addr, unop(Iop_F32toF64, loadBE(Ity_F32, mkexpr(EA))) );
3894 break;
3895
sewardjb51f0f42005-07-18 11:38:02 +00003896//zz case 0x31: // lfsu (Load Float Single with Update, PPC32 p442)
3897//zz if (rA_addr == 0) {
3898//zz vex_printf("dis_fp_load(PPC32)(instr,lfsu)\n");
3899//zz return False;
3900//zz }
3901//zz DIP("lfsu fr%d,%d(r%d)\n", frD_addr, exts_d_imm, rA_addr);
3902//zz assign( EA, binop(Iop_Add32, mkU32(exts_d_imm), mkexpr(rA)) );
3903//zz putFReg( frD_addr, unop(Iop_F32toF64, loadBE(Ity_F32, mkexpr(EA))) );
3904//zz putIReg( rA_addr, mkexpr(EA) );
3905//zz break;
cerion094d1392005-06-20 13:45:57 +00003906
3907 case 0x32: // lfd (Load Float Double, PPC32 p437)
sewardjdb36c0f2005-07-03 00:05:31 +00003908 DIP("lfd fr%d,%d(r%d)\n", frD_addr, exts_d_imm, rA_addr);
cerion094d1392005-06-20 13:45:57 +00003909 assign( EA, binop(Iop_Add32, mkU32(exts_d_imm), mkexpr(rA_or_0)) );
3910 putFReg( frD_addr, loadBE(Ity_F64, mkexpr(EA)) );
3911 break;
cerion3d870a32005-03-18 12:23:33 +00003912
sewardjb51f0f42005-07-18 11:38:02 +00003913//zz case 0x33: // lfdu (Load Float Double with Update, PPC32 p438)
3914//zz if (rA_addr == 0) {
3915//zz vex_printf("dis_fp_load(PPC32)(instr,lfdu)\n");
3916//zz return False;
3917//zz }
3918//zz DIP("lfdu 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, loadBE(Ity_F64, mkexpr(EA)) );
3921//zz putIReg( rA_addr, mkexpr(EA) );
3922//zz break;
sewardje14bb9f2005-07-22 09:39:02 +00003923
3924 case 0x1F:
3925 if (b0 != 0) {
3926 vex_printf("dis_fp_load(PPC32)(instr,b0)\n");
3927 return False;
3928 }
3929
3930 switch(opc2) {
3931 case 0x217: // lfsx (Load Float Single Indexed, PPC32 p444)
3932 DIP("lfsx fr%d,r%d,r%d\n", frD_addr, rA_addr, rB_addr);
3933 assign( EA, binop(Iop_Add32, mkexpr(rB), mkexpr(rA_or_0)) );
3934 putFReg( frD_addr, unop( Iop_F32toF64,
3935 loadBE(Ity_F32, mkexpr(EA))) );
3936 break;
3937
sewardjb51f0f42005-07-18 11:38:02 +00003938//zz case 0x237: // lfsux (Load Float Single with Update Indexed, PPC32 p443)
3939//zz if (rA_addr == 0) {
3940//zz vex_printf("dis_fp_load(PPC32)(instr,lfsux)\n");
3941//zz return False;
3942//zz }
3943//zz DIP("lfsux fr%d,r%d,r%d\n", frD_addr, rA_addr, rB_addr);
3944//zz assign( EA, binop(Iop_Add32, mkexpr(rB), mkexpr(rA)) );
3945//zz putFReg( frD_addr, unop(Iop_F32toF64, loadBE(Ity_F32, mkexpr(EA))) );
3946//zz putIReg( rA_addr, mkexpr(EA) );
3947//zz break;
sewardje14bb9f2005-07-22 09:39:02 +00003948
3949 case 0x257: // lfdx (Load Float Double Indexed, PPC32 p440)
3950 DIP("lfdx fr%d,r%d,r%d\n", frD_addr, rA_addr, rB_addr);
3951 assign( EA, binop(Iop_Add32, mkexpr(rB), mkexpr(rA_or_0)) );
3952 putFReg( frD_addr, loadBE(Ity_F64, mkexpr(EA)) );
3953 break;
3954
sewardjb51f0f42005-07-18 11:38:02 +00003955//zz case 0x277: // lfdux (Load Float Double with Update Indexed, PPC32 p439)
3956//zz if (rA_addr == 0) {
3957//zz vex_printf("dis_fp_load(PPC32)(instr,lfdux)\n");
3958//zz return False;
3959//zz }
3960//zz DIP("lfdux fr%d,r%d,r%d\n", frD_addr, rA_addr, rB_addr);
3961//zz assign( EA, binop(Iop_Add32, mkexpr(rB), mkexpr(rA)) );
3962//zz putFReg( frD_addr, loadBE(Ity_F64, mkexpr(EA)) );
3963//zz putIReg( rA_addr, mkexpr(EA) );
3964//zz break;
sewardje14bb9f2005-07-22 09:39:02 +00003965
3966 default:
3967 vex_printf("dis_fp_load(PPC32)(opc2)\n");
3968 return False;
3969 }
3970 break;
cerion3d870a32005-03-18 12:23:33 +00003971
3972 default:
3973 vex_printf("dis_fp_load(PPC32)(opc1)\n");
3974 return False;
3975 }
3976 return True;
3977}
3978
3979
3980
3981/*
3982 Floating Point Store Instructions
3983*/
3984static Bool dis_fp_store ( UInt theInstr )
3985{
3986 /* X-Form */
cerion094d1392005-06-20 13:45:57 +00003987 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
3988 UChar frS_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
3989 UChar rA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
3990 UChar rB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
3991 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
3992 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
cerion3d870a32005-03-18 12:23:33 +00003993
3994 /* D-Form */
cerion094d1392005-06-20 13:45:57 +00003995 UInt d_imm = (theInstr >> 0) & 0xFFFF; /* theInstr[0:15] */
3996
sewardjdb36c0f2005-07-03 00:05:31 +00003997 Int exts_d_imm = extend_s_16to32(d_imm);
cerion094d1392005-06-20 13:45:57 +00003998
3999 IRTemp EA = newTemp(Ity_I32);
4000 IRTemp frS = newTemp(Ity_F64);
4001 IRTemp rA = newTemp(Ity_I32);
4002 IRTemp rB = newTemp(Ity_I32);
4003 IRTemp rA_or_0 = newTemp(Ity_I32);
4004
4005 assign( frS, getFReg(frS_addr) );
4006 assign( rA, getIReg(rA_addr) );
4007 assign( rB, getIReg(rB_addr) );
4008 assign( rA_or_0, (rA_addr == 0) ? mkU32(0) : mkexpr(rA) );
cerion3d870a32005-03-18 12:23:33 +00004009
4010 switch(opc1) {
sewardje14bb9f2005-07-22 09:39:02 +00004011
4012 case 0x34: // stfs (Store Float Single, PPC32 p518)
4013 DIP("stfs fr%d,%d(r%d)\n", frS_addr, exts_d_imm, rA_addr);
4014 assign( EA, binop(Iop_Add32, mkU32(exts_d_imm), mkexpr(rA_or_0)) );
4015 storeBE( mkexpr(EA),
4016 binop(Iop_F64toF32, get_roundingmode(), mkexpr(frS)) );
4017 break;
4018
sewardjb51f0f42005-07-18 11:38:02 +00004019//zz case 0x35: // stfsu (Store Float Single with Update, PPC32 p519)
4020//zz if (rA_addr == 0) {
4021//zz vex_printf("dis_fp_store(PPC32)(instr,stfsu)\n");
4022//zz return False;
4023//zz }
4024//zz DIP("stfsu fr%d,%d(r%d)\n", frS_addr, exts_d_imm, rA_addr);
4025//zz assign( EA, binop(Iop_Add32, mkU32(exts_d_imm), mkexpr(rA)) );
4026//zz storeBE( mkexpr(EA),
4027//zz binop(Iop_F64toF32, get_roundingmode(), mkexpr(frS)) );
4028//zz putIReg( rA_addr, mkexpr(EA) );
4029//zz break;
cerion3d870a32005-03-18 12:23:33 +00004030
cerion094d1392005-06-20 13:45:57 +00004031 case 0x36: // stfd (Store Float Double, PPC32 p513)
sewardjdb36c0f2005-07-03 00:05:31 +00004032 DIP("stfd fr%d,%d(r%d)\n", frS_addr, exts_d_imm, rA_addr);
cerion094d1392005-06-20 13:45:57 +00004033 assign( EA, binop(Iop_Add32, mkU32(exts_d_imm), mkexpr(rA_or_0)) );
4034 storeBE( mkexpr(EA), mkexpr(frS) );
4035 break;
cerion3d870a32005-03-18 12:23:33 +00004036
sewardje14bb9f2005-07-22 09:39:02 +00004037 case 0x37: // stfdu (Store Float Double with Update, PPC32 p514)
4038 if (rA_addr == 0) {
4039 vex_printf("dis_fp_store(PPC32)(instr,stfdu)\n");
4040 return False;
4041 }
4042 DIP("stfdu fr%d,%d(r%d)\n", frS_addr, exts_d_imm, rA_addr);
4043 assign( EA, binop(Iop_Add32, mkU32(exts_d_imm), mkexpr(rA)) );
4044 storeBE( mkexpr(EA), mkexpr(frS) );
4045 putIReg( rA_addr, mkexpr(EA) );
4046 break;
4047
4048 case 0x1F:
4049 if (b0 != 0) {
4050 vex_printf("dis_fp_store(PPC32)(instr,b0)\n");
4051 return False;
4052 }
4053
4054 switch(opc2) {
4055 case 0x297: // stfsx (Store Float Single Indexed, PPC32 p521)
4056 DIP("stfsx fr%d,r%d,r%d\n", frS_addr, rA_addr, rB_addr);
4057 assign( EA, binop(Iop_Add32, mkexpr(rB), mkexpr(rA_or_0)) );
4058 storeBE( mkexpr(EA),
4059 binop(Iop_F64toF32, get_roundingmode(), mkexpr(frS)) );
4060 break;
4061
sewardjb51f0f42005-07-18 11:38:02 +00004062//zz case 0x2B7: // stfsux (Store Float Single with Update Indexed, PPC32 p520)
4063//zz if (rA_addr == 0) {
4064//zz vex_printf("dis_fp_store(PPC32)(instr,stfsux)\n");
4065//zz return False;
4066//zz }
4067//zz DIP("stfsux fr%d,r%d,r%d\n", frS_addr, rA_addr, rB_addr);
4068//zz assign( EA, binop(Iop_Add32, mkexpr(rB), mkexpr(rA)) );
4069//zz storeBE( mkexpr(EA),
4070//zz binop(Iop_F64toF32, get_roundingmode(), mkexpr(frS)) );
4071//zz putIReg( rA_addr, mkexpr(EA) );
4072//zz break;
sewardje14bb9f2005-07-22 09:39:02 +00004073
4074 case 0x2D7: // stfdx (Store Float Double Indexed, PPC32 p516)
4075 DIP("stfdx fr%d,r%d,r%d\n", frS_addr, rA_addr, rB_addr);
4076 assign( EA, binop(Iop_Add32, mkexpr(rB), mkexpr(rA_or_0)) );
4077 storeBE( mkexpr(EA), mkexpr(frS) );
4078 break;
4079
sewardjb51f0f42005-07-18 11:38:02 +00004080//zz case 0x2F7: // stfdux (Store Float Double with Update Indexed, PPC32 p515)
4081//zz if (rA_addr == 0) {
4082//zz vex_printf("dis_fp_store(PPC32)(instr,stfdux)\n");
4083//zz return False;
4084//zz }
4085//zz DIP("stfdux fr%d,r%d,r%d\n", frS_addr, rA_addr, rB_addr);
4086//zz assign( EA, binop(Iop_Add32, mkexpr(rB), mkexpr(rA)) );
4087//zz storeBE( mkexpr(EA), mkexpr(frS) );
4088//zz putIReg( rA_addr, mkexpr(EA) );
4089//zz break;
4090//zz
4091//zz case 0x3D7: // stfiwx (Store Float as Int, Indexed, PPC32 p517)
4092//zz DIP("stfiwx fr%d,r%d,r%d\n", frS_addr, rA_addr, rB_addr);
4093//zz assign( EA, binop(Iop_Add32, mkexpr(rB), mkexpr(rA_or_0)) );
4094//zz storeBE( mkexpr(EA),
4095//zz unop(Iop_64to32, unop(Iop_ReinterpF64asI64, mkexpr(frS))) );
4096//zz break;
sewardje14bb9f2005-07-22 09:39:02 +00004097
4098 default:
4099 vex_printf("dis_fp_store(PPC32)(opc2)\n");
4100 return False;
4101 }
4102 break;
cerion3d870a32005-03-18 12:23:33 +00004103
4104 default:
4105 vex_printf("dis_fp_store(PPC32)(opc1)\n");
4106 return False;
4107 }
4108 return True;
4109}
4110
4111
4112
4113/*
4114 Floating Point Arith Instructions
4115*/
4116static Bool dis_fp_arith ( UInt theInstr )
4117{
4118 /* A-Form */
4119 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
4120 UChar frD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
4121 UChar frA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
4122 UChar frB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
4123 UChar frC_addr = toUChar((theInstr >> 6) & 0x1F); /* theInstr[6:10] */
4124 UChar opc2 = toUChar((theInstr >> 1) & 0x1F); /* theInstr[1:5] */
4125 UChar flag_Rc = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
cerion094d1392005-06-20 13:45:57 +00004126 // Note: flag_Rc ignored as fp exceptions not supported.
4127
4128 IRTemp frD = newTemp(Ity_F64);
4129 IRTemp frA = newTemp(Ity_F64);
4130 IRTemp frB = newTemp(Ity_F64);
4131 IRTemp frC = newTemp(Ity_F64);
4132
4133 assign( frA, getFReg(frA_addr));
4134 assign( frB, getFReg(frB_addr));
4135 assign( frC, getFReg(frC_addr));
cerion3d870a32005-03-18 12:23:33 +00004136
4137 switch (opc1) {
sewardje14bb9f2005-07-22 09:39:02 +00004138 case 0x3B:
4139 switch (opc2) {
4140 case 0x12: // fdivs (Floating Divide Single, PPC32 p407)
4141 if (frC_addr != 0) {
4142 vex_printf("dis_fp_arith(PPC32)(instr,fdivs)\n");
4143 return False;
4144 }
4145 DIP("fdivs%s fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4146 frD_addr, frA_addr, frB_addr);
4147 assign( frD, roundToSgl( binop(Iop_DivF64, mkexpr(frA), mkexpr(frB)) ));
4148 break;
4149
4150 case 0x14: // fsubs (Floating Subtract Single, PPC32 p430)
4151 if (frC_addr != 0) {
4152 vex_printf("dis_fp_arith(PPC32)(instr,fsubs)\n");
4153 return False;
4154 }
4155 DIP("fsubs%s fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4156 frD_addr, frA_addr, frB_addr);
4157 assign( frD, roundToSgl(
4158 binop(Iop_SubF64, mkexpr(frA), mkexpr(frB)) ));
4159 break;
4160
4161 case 0x15: // fadds (Floating Add Single, PPC32 p401)
4162 if (frC_addr != 0) {
4163 vex_printf("dis_fp_arith(PPC32)(instr,fadds)\n");
4164 return False;
4165 }
4166 DIP("fadds%s fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4167 frD_addr, frA_addr, frB_addr);
4168 assign( frD, roundToSgl(
4169 binop(Iop_AddF64, mkexpr(frA), mkexpr(frB)) ));
4170 break;
4171
sewardjb51f0f42005-07-18 11:38:02 +00004172//zz case 0x16: // fsqrts (Floating SqRt (Single-Precision), PPC32 p428)
4173//zz if (frA_addr != 0 || frC_addr != 0) {
4174//zz vex_printf("dis_fp_arith(PPC32)(instr,fsqrts)\n");
4175//zz return False;
4176//zz }
4177//zz DIP("fsqrts%s fr%d,fr%d\n", flag_Rc ? "." : "",
4178//zz frD_addr, frB_addr);
4179//zz assign( frD, roundToSgl( unop(Iop_SqrtF64, mkexpr(frB)) ));
4180//zz break;
sewardje14bb9f2005-07-22 09:39:02 +00004181
sewardjb51f0f42005-07-18 11:38:02 +00004182//zz case 0x18: // fres (Floating Reciprocal Estimate Single, PPC32 p421)
4183//zz if (frA_addr != 0 || frC_addr != 0) {
4184//zz vex_printf("dis_fp_arith(PPC32)(instr,fres)\n");
4185//zz return False;
4186//zz }
4187//zz DIP("fres%s fr%d,fr%d\n", flag_Rc ? "." : "",
4188//zz frD_addr, frB_addr);
4189//zz DIP(" => not implemented\n");
4190//zz // CAB: Can we use one of the 128 bit SIMD Iop_Recip32F ops?
4191//zz return False;
sewardje14bb9f2005-07-22 09:39:02 +00004192
4193 case 0x19: // fmuls (Floating Multiply Single, PPC32 p414)
4194 if (frB_addr != 0) {
4195 vex_printf("dis_fp_arith(PPC32)(instr,fmuls)\n");
4196 return False;
4197 }
4198 DIP("fmuls%s fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4199 frD_addr, frA_addr, frC_addr);
4200 assign( frD, roundToSgl( binop(Iop_MulF64, mkexpr(frA), mkexpr(frC)) ));
4201 break;
4202
4203 default:
4204 vex_printf("dis_fp_arith(PPC32)(3B: opc2)\n");
4205 return False;
4206 }
4207 break;
cerion094d1392005-06-20 13:45:57 +00004208
cerion3d870a32005-03-18 12:23:33 +00004209 case 0x3F:
4210 switch (opc2) {
sewardje14bb9f2005-07-22 09:39:02 +00004211 case 0x12: // fdiv (Floating Divide (Double-Precision), PPC32 p406)
4212 if (frC_addr != 0) {
4213 vex_printf("dis_fp_arith(PPC32)(instr,fdiv)\n");
4214 return False;
4215 }
4216 DIP("fdiv%s fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4217 frD_addr, frA_addr, frB_addr);
4218 assign( frD, binop( Iop_DivF64, mkexpr(frA), mkexpr(frB) ) );
4219 break;
4220
4221 case 0x14: // fsub (Floating Subtract (Double-Precision), PPC32 p429)
4222 if (frC_addr != 0) {
4223 vex_printf("dis_fp_arith(PPC32)(instr,fsub)\n");
4224 return False;
4225 }
4226 DIP("fsub%s fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4227 frD_addr, frA_addr, frB_addr);
4228 assign( frD, binop( Iop_SubF64, mkexpr(frA), mkexpr(frB) ) );
4229 break;
cerion3d870a32005-03-18 12:23:33 +00004230
4231 case 0x15: // fadd (Floating Add (Double-Precision), PPC32 p400)
4232 if (frC_addr != 0) {
cerion094d1392005-06-20 13:45:57 +00004233 vex_printf("dis_fp_arith(PPC32)(instr,fadd)\n");
cerion3d870a32005-03-18 12:23:33 +00004234 return False;
4235 }
4236 DIP("fadd%s fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4237 frD_addr, frA_addr, frB_addr);
cerion094d1392005-06-20 13:45:57 +00004238 assign( frD, binop( Iop_AddF64, mkexpr(frA), mkexpr(frB) ) );
4239 break;
cerion3d870a32005-03-18 12:23:33 +00004240
sewardjb51f0f42005-07-18 11:38:02 +00004241//zz case 0x16: // fsqrt (Floating SqRt (Double-Precision), PPC32 p427)
4242//zz if (frA_addr != 0 || frC_addr != 0) {
4243//zz vex_printf("dis_fp_arith(PPC32)(instr,fsqrt)\n");
4244//zz return False;
4245//zz }
4246//zz DIP("fsqrt%s fr%d,fr%d\n", flag_Rc ? "." : "",
4247//zz frD_addr, frB_addr);
4248//zz assign( frD, unop( Iop_SqrtF64, mkexpr(frB) ) );
4249//zz break;
sewardje14bb9f2005-07-22 09:39:02 +00004250
4251 case 0x17: { // fsel (Floating Select, PPC32 p426)
4252 IRTemp cc = newTemp(Ity_I32);
4253 IRTemp cc_b0 = newTemp(Ity_I32);
4254
4255 DIP("fsel%s fr%d,fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4256 frD_addr, frA_addr, frC_addr, frB_addr);
4257
4258 // cc: UN == 0x41, LT == 0x01, GT == 0x00, EQ == 0x40
4259 // => GT|EQ == (cc & 0x1 == 0)
4260 assign( cc, binop(Iop_CmpF64, mkexpr(frA), IRExpr_Const(IRConst_F64(0))) );
4261 assign( cc_b0, binop(Iop_And32, mkexpr(cc), mkU32(1)) );
4262
4263 // frD = (frA >= 0.0) ? frC : frB
4264 // = (cc_b0 == 0) ? frC : frB
4265 assign( frD,
4266 IRExpr_Mux0X(
4267 unop(Iop_1Uto8,
4268 binop(Iop_CmpEQ32, mkexpr(cc_b0), mkU32(0))),
4269 mkexpr(frB),
4270 mkexpr(frC) ));
4271 break;
4272 }
4273
4274 case 0x19: // fmul (Floating Multiply (Double Precision), PPC32 p413)
4275 if (frB_addr != 0) {
4276 vex_printf("dis_fp_arith(PPC32)(instr,fmul)\n");
4277 return False;
4278 }
4279 DIP("fmul%s fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4280 frD_addr, frA_addr, frC_addr);
4281 assign( frD, binop( Iop_MulF64, mkexpr(frA), mkexpr(frC) ) );
4282 break;
4283
sewardjb51f0f42005-07-18 11:38:02 +00004284//zz case 0x1A: // frsqrte (Floating Reciprocal SqRt Estimate, PPC32 p424)
4285//zz if (frA_addr != 0 || frC_addr != 0) {
4286//zz vex_printf("dis_fp_arith(PPC32)(instr,frsqrte)\n");
4287//zz return False;
4288//zz }
4289//zz DIP("frsqrte%s fr%d,fr%d\n", flag_Rc ? "." : "",
4290//zz frD_addr, frB_addr);
4291//zz DIP(" => not implemented\n");
4292//zz // CAB: Iop_SqrtF64, then one of the 128 bit SIMD Iop_Recip32F ops?
4293//zz return False;
cerion3d870a32005-03-18 12:23:33 +00004294
4295 default:
4296 vex_printf("dis_fp_arith(PPC32)(3F: opc2)\n");
4297 return False;
4298 }
cerion094d1392005-06-20 13:45:57 +00004299 break;
4300
cerion3d870a32005-03-18 12:23:33 +00004301 default:
4302 vex_printf("dis_fp_arith(PPC32)(opc1)\n");
4303 return False;
4304 }
cerion094d1392005-06-20 13:45:57 +00004305
4306 putFReg( frD_addr, mkexpr(frD) );
cerion3d870a32005-03-18 12:23:33 +00004307 return True;
4308}
4309
4310
4311
sewardje14bb9f2005-07-22 09:39:02 +00004312/*
4313 Floating Point Mult-Add Instructions
4314*/
4315static Bool dis_fp_multadd ( UInt theInstr )
4316{
4317 /* A-Form */
4318 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
4319 UChar frD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
4320 UChar frA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
4321 UChar frB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
4322 UChar frC_addr = toUChar((theInstr >> 6) & 0x1F); /* theInstr[6:10] */
4323 UChar opc2 = toUChar((theInstr >> 1) & 0x1F); /* theInstr[1:5] */
4324 UChar flag_Rc = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
4325
4326 IRTemp frD = newTemp(Ity_F64);
4327 IRTemp frA = newTemp(Ity_F64);
4328 IRTemp frB = newTemp(Ity_F64);
4329 IRTemp frC = newTemp(Ity_F64);
4330
4331 assign( frA, getFReg(frA_addr));
4332 assign( frB, getFReg(frB_addr));
4333 assign( frC, getFReg(frC_addr));
4334
4335 switch (opc1) {
4336 case 0x3B:
4337 switch (opc2) {
4338 case 0x1C: // fmsubs (Floating Mult-Subtr Single, PPC32 p412)
4339 DIP("fmsubs%s fr%d,fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4340 frD_addr, frA_addr, frC_addr, frB_addr);
4341 assign( frD, roundToSgl(
4342 binop( Iop_SubF64,
4343 binop(Iop_MulF64, mkexpr(frA), mkexpr(frC)),
4344 mkexpr(frB)) ));
4345 break;
4346
4347 case 0x1D: // fmadds (Floating Mult-Add Single, PPC32 p409)
4348 DIP("fmadds%s fr%d,fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4349 frD_addr, frA_addr, frC_addr, frB_addr);
4350 assign( frD, roundToSgl(
4351 binop( Iop_AddF64,
4352 binop(Iop_MulF64, mkexpr(frA), mkexpr(frC)),
4353 mkexpr(frB)) ));
4354 break;
4355
4356 case 0x1E: // fnmsubs (Float Neg Mult-Subtr Single, PPC32 p420)
4357 DIP("fnmsubs%s fr%d,fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4358 frD_addr, frA_addr, frC_addr, frB_addr);
4359 assign( frD, roundToSgl(
4360 unop(Iop_NegF64,
4361 binop(Iop_SubF64,
4362 binop(Iop_MulF64, mkexpr(frA), mkexpr(frC)),
4363 mkexpr(frB))) ));
4364 break;
4365
4366 case 0x1F: // fnmadds (Floating Negative Multiply-Add Single, PPC32 p418)
4367 DIP("fnmadds%s fr%d,fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4368 frD_addr, frA_addr, frC_addr, frB_addr);
4369 assign( frD, roundToSgl(
4370 unop(Iop_NegF64,
4371 binop(Iop_AddF64,
4372 binop(Iop_MulF64, mkexpr(frA), mkexpr(frC)),
4373 mkexpr(frB))) ));
4374 break;
4375
4376 default:
4377 vex_printf("dis_fp_multadd(PPC32)(3B: opc2)\n");
4378 return False;
4379 }
4380 break;
4381
4382 case 0x3F:
4383 switch (opc2) {
4384 case 0x1C: // fmsub (Float Mult-Subtr (Double Precision), PPC32 p411)
4385 DIP("fmsub%s fr%d,fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4386 frD_addr, frA_addr, frC_addr, frB_addr);
4387 assign( frD, binop( Iop_SubF64,
4388 binop( Iop_MulF64, mkexpr(frA), mkexpr(frC) ),
4389 mkexpr(frB) ));
4390 break;
4391
4392 case 0x1D: // fmadd (Float Mult-Add (Double Precision), PPC32 p408)
4393 DIP("fmadd%s fr%d,fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4394 frD_addr, frA_addr, frC_addr, frB_addr);
4395 assign( frD, binop( Iop_AddF64,
4396 binop( Iop_MulF64, mkexpr(frA), mkexpr(frC) ),
4397 mkexpr(frB) ));
4398 break;
4399
sewardjb51f0f42005-07-18 11:38:02 +00004400//zz case 0x1E: // fnmsub (Float Neg Mult-Subtr (Double Precision), PPC32 p419)
4401//zz DIP("fnmsub%s fr%d,fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4402//zz frD_addr, frA_addr, frC_addr, frB_addr);
4403//zz assign( frD, unop( Iop_NegF64,
4404//zz binop( Iop_SubF64,
4405//zz binop( Iop_MulF64, mkexpr(frA), mkexpr(frC) ),
4406//zz mkexpr(frB) )));
4407//zz break;
4408//zz
4409//zz case 0x1F: // fnmadd (Float Neg Mult-Add (Double Precision), PPC32 p417)
4410//zz DIP("fnmadd%s fr%d,fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4411//zz frD_addr, frA_addr, frC_addr, frB_addr);
4412//zz assign( frD, unop( Iop_NegF64,
4413//zz binop( Iop_AddF64,
4414//zz binop( Iop_MulF64, mkexpr(frA), mkexpr(frC) ),
4415//zz mkexpr(frB) )));
4416//zz break;
sewardje14bb9f2005-07-22 09:39:02 +00004417
4418 default:
4419 vex_printf("dis_fp_multadd(PPC32)(3F: opc2)\n");
4420 return False;
4421 }
4422 break;
4423
4424 default:
4425 vex_printf("dis_fp_multadd(PPC32)(opc1)\n");
4426 return False;
4427 }
4428
4429 putFReg( frD_addr, mkexpr(frD) );
4430 return True;
4431}
4432
4433
4434
4435/*
4436 Floating Point Compare Instructions
4437*/
4438static Bool dis_fp_cmp ( UInt theInstr )
4439{
4440 /* X-Form */
4441 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
4442 UChar crfD = toUChar((theInstr >> 23) & 0x7); /* theInstr[23:25] */
4443 UChar b21to22 = toUChar((theInstr >> 21) & 0x3); /* theInstr[21:22] */
4444 UChar frA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
4445 UChar frB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
4446 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
4447 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
4448
4449 IRTemp ccIR = newTemp(Ity_I32);
4450 IRTemp ccPPC32 = newTemp(Ity_I32);
4451
4452#if 0
4453 IRTemp cc_lt = newTemp(Ity_I32);
4454 IRTemp cc_gt = newTemp(Ity_I32);
4455 IRTemp cc_eq = newTemp(Ity_I32);
4456 IRTemp cc_un = newTemp(Ity_I32);
4457#endif
4458
4459 IRTemp frA = newTemp(Ity_F64);
4460 IRTemp frB = newTemp(Ity_F64);
4461// IRExpr* irx;
4462
4463 if (opc1 != 0x3F || b21to22 != 0 || b0 != 0) {
4464 vex_printf("dis_fp_cmp(PPC32)(instr)\n");
4465 return False;
4466 }
4467
4468 assign( frA, getFReg(frA_addr));
4469 assign( frB, getFReg(frB_addr));
4470
4471 assign( ccIR, binop(Iop_CmpF64, mkexpr(frA), mkexpr(frB)) );
4472
4473 /* Map compare result from IR to PPC32 */
4474 /*
4475 FP cmp result | PPC | IR
4476 --------------------------
4477 UN | 0x1 | 0x45
4478 EQ | 0x2 | 0x40
4479 GT | 0x4 | 0x00
4480 LT | 0x8 | 0x01
4481 */
4482
4483 // ccPPC32 = Shl(1, (0x2 & ~(ccIR>>5)) || (0x1 & (XOR(ccIR, ccIR>>6))))
4484 assign(
4485 ccPPC32,
4486 binop(Iop_Shl32, mkU32(1),
4487 unop(Iop_32to8,
4488 binop(Iop_Or32,
4489 binop(Iop_And32, mkU32(2),
4490 unop(Iop_Not32,
4491 binop(Iop_Shr32, mkexpr(ccIR), mkU8(5)))),
4492 binop(Iop_And32, mkU32(1),
4493 binop(Iop_Xor32, mkexpr(ccIR),
4494 binop(Iop_Shr32, mkexpr(ccIR), mkU8(6)))))))
4495 );
4496
4497 putCR0( crfD, unop( Iop_32to8,
4498 binop(Iop_And32, mkexpr(ccPPC32), mkU32(1))) );
4499 putCR321( crfD, unop( Iop_32to8,
4500 binop(Iop_And32, mkexpr(ccPPC32), mkU32(7<<1))) );
4501
4502 // CAB: Useful to support writing cc to FPSCR->FPCC ?
4503 // putReg_field( PPC32_SPR_FPSCR, mkexpr(ccPPC32), 3 );
4504
4505 // Note: Differences between fcmpu and fcmpo are only
4506 // in exception flag settings, which aren't supported anyway...
4507 opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
4508 switch (opc2) {
4509 case 0x000: // fcmpu (Floating Compare Unordered, PPC32 p403)
4510 DIP("fcmpu crf%d,fr%d,fr%d\n", crfD, frA_addr, frB_addr);
4511 break;
4512
4513 case 0x020: // fcmpo (Floating Compare Ordered, PPC32 p402)
4514 DIP("fcmpo crf%d,fr%d,fr%d\n", crfD, frA_addr, frB_addr);
4515 break;
4516 default:
4517 vex_printf("dis_fp_cmp(PPC32)(opc2)\n");
4518 return False;
4519 }
4520 return True;
4521}
4522
4523
4524
4525/*
4526 Floating Point Rounding/Conversion Instructions
4527*/
4528static Bool dis_fp_round ( UInt theInstr )
4529{
4530 /* X-Form */
4531 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
4532 UChar frD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
4533 UChar b16to20 = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
4534 UChar frB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
4535 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
4536 UChar flag_Rc = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
4537
4538 IRTemp frD = newTemp(Ity_F64);
4539 IRTemp frB = newTemp(Ity_F64);
4540 IRTemp r_tmp = newTemp(Ity_I32);
4541
4542 if (opc1 != 0x3F || b16to20 != 0) {
4543 vex_printf("dis_fp_round(PPC32)(instr)\n");
4544 return False;
4545 }
4546
4547 assign( frB, getFReg(frB_addr));
4548
4549 opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
4550
4551 switch (opc2) {
4552
4553 case 0x00C: // frsp (Floating Round to Single, PPC32 p423)
4554 DIP("frsp%s fr%d,fr%d\n", flag_Rc ? "." : "", frD_addr, frB_addr);
4555 assign( frD, roundToSgl( mkexpr(frB) ));
4556 break;
4557
sewardjb51f0f42005-07-18 11:38:02 +00004558//zz case 0x00E: // fctiw (Floating Conv to Int, PPC32 p404)
4559//zz DIP("fctiw%s fr%d,fr%d\n", flag_Rc ? "." : "", frD_addr, frB_addr);
4560//zz assign( r_tmp, binop(Iop_F64toI32, get_roundingmode(), mkexpr(frB)) );
4561//zz assign( frD, unop( Iop_ReinterpI64asF64,
4562//zz unop( Iop_32Uto64, mkexpr(r_tmp))));
4563//zz break;
sewardje14bb9f2005-07-22 09:39:02 +00004564
4565 case 0x00F: // fctiwz (Floating Conv to Int, Round to Zero, PPC32 p405)
4566 DIP("fctiwz%s fr%d,fr%d\n", flag_Rc ? "." : "", frD_addr, frB_addr);
4567 assign( r_tmp, binop(Iop_F64toI32, mkU32(0x3), mkexpr(frB)) );
4568 assign( frD, unop( Iop_ReinterpI64asF64,
4569 unop( Iop_32Uto64, mkexpr(r_tmp))));
4570 break;
4571
4572 default:
4573 vex_printf("dis_fp_round(PPC32)(opc2)\n");
4574 return False;
4575 }
4576
4577 putFReg( frD_addr, mkexpr(frD) );
4578 return True;
4579}
4580
4581
4582
4583/*
4584 Floating Point Move Instructions
4585*/
4586static Bool dis_fp_move ( UInt theInstr )
4587{
4588 /* X-Form */
4589 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
4590 UChar frD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
4591 UChar b16to20 = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
4592 UChar frB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
4593 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
4594 UChar flag_Rc = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
4595
4596 IRTemp frD = newTemp(Ity_F64);
4597 IRTemp frB = newTemp(Ity_F64);
4598
4599 if (opc1 != 0x3F || b16to20 != 0) {
4600 vex_printf("dis_fp_move(PPC32)(instr)\n");
4601 return False;
4602 }
4603
4604 assign( frB, getFReg(frB_addr));
4605
4606 opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
4607
4608 switch (opc2) {
4609
4610 case 0x028: // fneg (Floating Negate, PPC32 p416)
4611 DIP("fneg%s fr%d,fr%d\n", flag_Rc ? "." : "", frD_addr, frB_addr);
4612 assign( frD, unop( Iop_NegF64, mkexpr(frB) ));
4613 break;
4614
4615 case 0x048: // fmr (Floating Move Register, PPC32 p410)
4616 DIP("fmr%s fr%d,fr%d\n", flag_Rc ? "." : "", frD_addr, frB_addr);
4617 assign( frD, mkexpr(frB) );
4618 break;
4619
sewardjb51f0f42005-07-18 11:38:02 +00004620//zz case 0x088: // fnabs (Floating Negative Absolute Value, PPC32 p415)
4621//zz DIP("fnabs%s fr%d,fr%d\n", flag_Rc ? "." : "", frD_addr, frB_addr);
4622//zz assign( frD, unop( Iop_NegF64, unop( Iop_AbsF64, mkexpr(frB) )));
4623//zz break;
sewardje14bb9f2005-07-22 09:39:02 +00004624
4625 case 0x108: // fabs (Floating Absolute Value, PPC32 p399)
4626 DIP("fabs%s fr%d,fr%d\n", flag_Rc ? "." : "", frD_addr, frB_addr);
4627 assign( frD, unop( Iop_AbsF64, mkexpr(frB) ));
4628 break;
4629
4630 default:
4631 vex_printf("dis_fp_move(PPC32)(opc2)\n");
4632 return False;
4633 }
4634
4635 putFReg( frD_addr, mkexpr(frD) );
4636 return True;
4637}
4638
4639
4640
4641/*
4642 Floating Point Status/Control Register Instructions
4643*/
4644static Bool dis_fp_scr ( UInt theInstr )
4645{
4646 /* X-Form */
4647 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
4648 /* Too many forms - see each switch case */
4649 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
4650 UChar flag_Rc = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
4651
4652 if (opc1 != 0x3F) {
4653 vex_printf("dis_fp_scr(PPC32)(instr)\n");
4654 return False;
4655 }
4656
4657 switch (opc2) {
sewardjb51f0f42005-07-18 11:38:02 +00004658//zz case 0x026: { // mtfsb1 (Move to FPSCR Bit 1, PPC32 p479)
4659//zz // Bit crbD of the FPSCR is set.
4660//zz UChar crbD = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
4661//zz UInt b11to20 = (theInstr >> 11) & 0x3FF; /* theInstr[11:20] */
4662//zz
4663//zz if (b11to20 != 0) {
4664//zz vex_printf("dis_fp_scr(PPC32)(instr,mtfsb1)\n");
4665//zz return False;
4666//zz }
4667//zz DIP("mtfsb1%s crb%d \n", flag_Rc ? "." : "", crbD);
4668//zz putReg_bit( PPC32_SPR_FPSCR, mkU32(1), 31-crbD );
4669//zz break;
4670//zz }
4671//zz
4672//zz case 0x040: { // mcrfs (Move to Condition Register from FPSCR, PPC32 p465)
4673//zz UChar crfD = toUChar((theInstr >> 23) & 0x7); /* theInstr[23:25] */
4674//zz UChar b21to22 = toUChar((theInstr >> 21) & 0x3); /* theInstr[21:22] */
4675//zz UChar crfS = toUChar((theInstr >> 18) & 0x7); /* theInstr[18:20] */
4676//zz UChar b11to17 = toUChar((theInstr >> 11) & 0x7F); /* theInstr[11:17] */
4677//zz
4678//zz IRTemp tmp = newTemp(Ity_I32);
4679//zz
4680//zz if (b21to22 != 0 || b11to17 != 0 || flag_Rc != 0) {
4681//zz vex_printf("dis_fp_scr(PPC32)(instr,mcrfs)\n");
4682//zz return False;
4683//zz }
4684//zz DIP("mcrfs crf%d,crf%d\n", crfD, crfS);
4685//zz assign( tmp, getReg_field( PPC32_SPR_FPSCR, 7-crfS ) );
4686//zz putReg_field( PPC32_SPR_CR, mkexpr(tmp), 7-crfD );
4687//zz break;
4688//zz }
4689//zz
4690//zz case 0x046: { // mtfsb0 (Move to FPSCR Bit 0, PPC32 p478)
4691//zz // Bit crbD of the FPSCR is cleared.
4692//zz UChar crbD = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
4693//zz UInt b11to20 = (theInstr >> 11) & 0x3FF; /* theInstr[11:20] */
4694//zz
4695//zz if (b11to20 != 0) {
4696//zz vex_printf("dis_fp_scr(PPC32)(instr,mtfsb0)\n");
4697//zz return False;
4698//zz }
4699//zz DIP("mtfsb0%s crb%d\n", flag_Rc ? "." : "", crbD);
4700//zz putReg_bit( PPC32_SPR_FPSCR, mkU32(0), 31-crbD );
4701//zz break;
4702//zz }
4703//zz
4704//zz case 0x086: { // mtfsfi (Move to FPSCR Field Immediate, PPC32 p481)
4705//zz UChar crfD = toUChar((theInstr >> 23) & 0x7); /* theInstr[23:25] */
4706//zz UChar b16to22 = toUChar((theInstr >> 16) & 0x7F); /* theInstr[16:22] */
4707//zz UChar IMM = toUChar((theInstr >> 12) & 0xF); /* theInstr[11:15] */
4708//zz UChar b11 = toUChar((theInstr >> 11) & 0x1); /* theInstr[11] */
4709//zz
4710//zz if (b16to22 != 0 || b11 != 0) {
4711//zz vex_printf("dis_fp_scr(PPC32)(instr,mtfsfi)\n");
4712//zz return False;
4713//zz }
4714//zz DIP("mtfsfi%s crf%d,%d\n", flag_Rc ? "." : "", crfD, IMM);
4715//zz putReg_field( PPC32_SPR_FPSCR, mkU32(IMM), 7-crfD );
4716//zz break;
4717//zz }
sewardje14bb9f2005-07-22 09:39:02 +00004718
4719 case 0x247: { // mffs (Move from FPSCR, PPC32 p468)
4720 UChar frD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
4721 UInt b11to20 = (theInstr >> 11) & 0x3FF; /* theInstr[11:20] */
4722
4723 if (b11to20 != 0) {
4724 vex_printf("dis_fp_scr(PPC32)(instr,mffs)\n");
4725 return False;
4726 }
4727 DIP("mffs%s fr%d\n", flag_Rc ? "." : "", frD_addr);
4728 putFReg( frD_addr, unop( Iop_ReinterpI64asF64,
4729 unop( Iop_32Uto64,
4730 getReg_masked( PPC32_SPR_FPSCR, 0x3 ) )));
4731 break;
4732 }
4733
4734 case 0x2C7: { // mtfsf (Move to FPSCR Fields, PPC32 p480)
4735 UChar b25 = toUChar((theInstr >> 25) & 0x1); /* theInstr[25] */
4736 UChar FM = toUChar((theInstr >> 17) & 0xFF); /* theInstr[17:24] */
4737 UChar b16 = toUChar((theInstr >> 16) & 0x1); /* theInstr[16] */
4738 UChar frB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
4739 IRTemp frB = newTemp(Ity_F64);
4740 IRTemp rB_32 = newTemp(Ity_I32);
4741 Int mask = 0;
4742 Int i = 0;
4743
4744 if (b25 != 0 || b16 != 0) {
4745 vex_printf("dis_fp_scr(PPC32)(instr,mtfsf)\n");
4746 return False;
4747 }
4748 DIP("mtfsf%s %d,fr%d\n", flag_Rc ? "." : "", FM, frB_addr);
4749 assign( frB, getFReg(frB_addr));
4750 assign( rB_32, unop( Iop_64to32,
4751 unop( Iop_ReinterpF64asI64, mkexpr(frB) )));
4752 // Build 32bit mask from FM:
4753 for (i=0; i<8; i++) {
4754 if ((FM & (1<<(7-i))) == 1) {
4755 mask |= 0xF << (7-i);
4756 }
4757 }
4758 putReg_masked( PPC32_SPR_FPSCR, mkexpr(rB_32), mask );
4759 break;
4760 }
4761
4762 default:
4763 vex_printf("dis_fp_scr(PPC32)(opc2)\n");
4764 return False;
4765 }
4766 return True;
4767}
4768
4769
4770
sewardjb51f0f42005-07-18 11:38:02 +00004771//zz /*------------------------------------------------------------*/
4772//zz /*--- AltiVec Instruction Translation ---*/
4773//zz /*------------------------------------------------------------*/
4774//zz
4775//zz /*
4776//zz Altivec Cache Control Instructions (Data Streams)
4777//zz */
4778//zz static Bool dis_av_datastream ( UInt theInstr )
4779//zz {
4780//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
4781//zz UChar flag_T = toUChar((theInstr >> 25) & 0x1); /* theInstr[25] */
4782//zz UChar flag_A = toUChar((theInstr >> 25) & 0x1); /* theInstr[25] */
4783//zz UChar b23to24 = toUChar((theInstr >> 23) & 0x3); /* theInstr[23:24] */
4784//zz UChar STRM = toUChar((theInstr >> 21) & 0x3); /* theInstr[21:22] */
4785//zz UChar rA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
4786//zz UChar rB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
4787//zz UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
4788//zz UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
4789//zz
4790//zz if (opc1 != 0x1F || b23to24 != 0 || b0 != 0) {
4791//zz vex_printf("dis_av_datastream(PPC32)(instr)\n");
4792//zz return False;
4793//zz }
4794//zz
4795//zz switch (opc2) {
4796//zz case 0x156: // dst (Data Stream Touch, AV p115)
4797//zz DIP("dst%s r%d,r%d,%d\n", flag_T ? "t" : "", rA_addr, rB_addr, STRM);
4798//zz DIP(" => not implemented\n");
4799//zz return False;
4800//zz
4801//zz case 0x176: // dstst (Data Stream Touch for Store, AV p117)
4802//zz DIP("dstst%s r%d,r%d,%d\n", flag_T ? "t" : "", rA_addr, rB_addr, STRM);
4803//zz DIP(" => not implemented\n");
4804//zz return False;
4805//zz
4806//zz case 0x336: // dss (Data Stream Stop, AV p114)
4807//zz if (rA_addr != 0 || rB_addr != 0) {
4808//zz vex_printf("dis_av_datastream(PPC32)(opc2,dst)\n");
4809//zz return False;
4810//zz }
4811//zz if (flag_A == 0) {
4812//zz DIP("dss %d\n", STRM);
4813//zz DIP(" => not implemented\n");
4814//zz } else {
4815//zz DIP("dssall\n");
4816//zz DIP(" => not implemented\n");
4817//zz }
4818//zz return False;
4819//zz
4820//zz default:
4821//zz vex_printf("dis_av_datastream(PPC32)(opc2)\n");
4822//zz return False;
4823//zz }
4824//zz return True;
4825//zz }
4826//zz
4827//zz /*
4828//zz AltiVec Processor Control Instructions
4829//zz */
4830//zz static Bool dis_av_procctl ( UInt theInstr )
4831//zz {
4832//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
4833//zz UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
4834//zz UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
4835//zz UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
4836//zz UInt opc2 = (theInstr >> 0) & 0x7FF; /* theInstr[0:10] */
4837//zz
4838//zz if (opc1 != 0x4) {
4839//zz vex_printf("dis_av_procctl(PPC32)(instr)\n");
4840//zz return False;
4841//zz }
4842//zz
4843//zz switch (opc2) {
4844//zz case 0x604: // mfvscr (Move from VSCR, AV p129)
4845//zz if (vA_addr != 0 || vB_addr != 0) {
4846//zz vex_printf("dis_av_procctl(PPC32)(opc2,dst)\n");
4847//zz return False;
4848//zz }
4849//zz DIP("mfvscr v%d\n", vD_addr);
4850//zz DIP(" => not implemented\n");
4851//zz return False;
4852//zz
4853//zz case 0x644: // mtvscr (Move to VSCR, AV p130)
4854//zz if (vD_addr != 0 || vA_addr != 0) {
4855//zz vex_printf("dis_av_procctl(PPC32)(opc2,dst)\n");
4856//zz return False;
4857//zz }
4858//zz DIP("mtvscr v%d\n", vB_addr);
4859//zz DIP(" => not implemented\n");
4860//zz return False;
4861//zz
4862//zz default:
4863//zz vex_printf("dis_av_procctl(PPC32)(opc2)\n");
4864//zz return False;
4865//zz }
4866//zz return True;
4867//zz }
ceriona982c052005-06-28 17:23:09 +00004868
4869/*
4870 AltiVec Load Instructions
4871*/
4872static Bool dis_av_load ( UInt theInstr )
4873{
4874 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
4875 UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
4876 UChar rA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
4877 UChar rB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
4878 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
4879 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
4880
ceriona50fde52005-07-01 21:16:10 +00004881 IRTemp EA = newTemp(Ity_I32);
4882 IRTemp EA_aligned = newTemp(Ity_I32);
4883
ceriona982c052005-06-28 17:23:09 +00004884 if (opc1 != 0x1F || b0 != 0) {
4885 vex_printf("dis_av_load(PPC32)(instr)\n");
4886 return False;
4887 }
4888
ceriona50fde52005-07-01 21:16:10 +00004889 assign( EA, binop(Iop_Add32,
4890 ((rA_addr == 0) ? mkU32(0) : getIReg(rA_addr)),
4891 getIReg(rB_addr) ));
4892
ceriona982c052005-06-28 17:23:09 +00004893 switch (opc2) {
4894
sewardjb51f0f42005-07-18 11:38:02 +00004895//zz case 0x006: // lvsl (Load Vector for Shift Left, AV p123)
4896//zz DIP("lvsl v%d,r%d,r%d\n", vD_addr, rA_addr, rB_addr);
4897//zz DIP(" => not implemented\n");
4898//zz return False;
4899//zz
4900//zz case 0x026: // lvsr (Load Vector for Shift Right, AV p125)
4901//zz DIP("lvsr v%d,r%d,r%d\n", vD_addr, rA_addr, rB_addr);
4902//zz DIP(" => not implemented\n");
4903//zz return False;
4904//zz
4905//zz case 0x007: // lvebx (Load Vector Element Byte Indexed, AV p119)
4906//zz DIP("lvebx v%d,r%d,r%d\n", vD_addr, rA_addr, rB_addr);
4907//zz DIP(" => not implemented\n");
4908//zz return False;
4909//zz
4910//zz case 0x027: // lvehx (Load Vector Element Half Word Indexed, AV p121)
4911//zz DIP("lvehx v%d,r%d,r%d\n", vD_addr, rA_addr, rB_addr);
4912//zz DIP(" => not implemented\n");
4913//zz return False;
4914//zz
4915//zz case 0x047: // lvewx (Load Vector Element Word Indexed, AV p122)
4916//zz DIP("lvewx v%d,r%d,r%d\n", vD_addr, rA_addr, rB_addr);
4917//zz DIP(" => not implemented\n");
4918//zz return False;
ceriona982c052005-06-28 17:23:09 +00004919
4920 case 0x067: // lvx (Load Vector Indexed, AV p127)
4921 DIP("lvx v%d,r%d,r%d\n", vD_addr, rA_addr, rB_addr);
ceriona50fde52005-07-01 21:16:10 +00004922 assign( EA_aligned, binop( Iop_And32, mkexpr(EA), mkU32(0xFFFFFFF0) ));
4923 putVReg( vD_addr, loadBE(Ity_V128, mkexpr(EA_aligned)) );
4924 break;
ceriona982c052005-06-28 17:23:09 +00004925
sewardjb51f0f42005-07-18 11:38:02 +00004926//zz case 0x167: // lvxl (Load Vector Indexed LRU, AV p128)
4927//zz // XXX: lvxl gives explicit control over cache block replacement
4928//zz DIP("lvxl v%d,r%d,r%d\n", vD_addr, rA_addr, rB_addr);
4929//zz DIP(" => not implemented\n");
4930//zz return False;
ceriona982c052005-06-28 17:23:09 +00004931
4932 default:
4933 vex_printf("dis_av_load(PPC32)(opc2)\n");
4934 return False;
4935 }
4936 return True;
4937}
4938
4939/*
4940 AltiVec Store Instructions
4941*/
4942static Bool dis_av_store ( UInt theInstr )
4943{
4944 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
4945 UChar vS_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
4946 UChar rA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
4947 UChar rB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
4948 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
4949 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
4950
4951 IRTemp rA = newTemp(Ity_I32);
4952 IRTemp rB = newTemp(Ity_I32);
4953 IRTemp vS = newTemp(Ity_V128);
4954 IRTemp EA = newTemp(Ity_I32);
4955 IRTemp EA_aligned = newTemp(Ity_I32);
4956
4957 assign( rA, getIReg(rA_addr));
4958 assign( rB, getIReg(rB_addr));
4959 assign( vS, getVReg(vS_addr));
4960
4961 if (rA_addr == 0) {
4962 assign( EA, mkexpr(rB) );
4963 } else {
4964 assign( EA, binop(Iop_Add32, mkexpr(rA), mkexpr(rB)) );
4965 }
4966
4967 if (opc1 != 0x1F || b0 != 0) {
4968 vex_printf("dis_av_store(PPC32)(instr)\n");
4969 return False;
4970 }
4971
4972 switch (opc2) {
sewardjb51f0f42005-07-18 11:38:02 +00004973//zz case 0x087: // stvebx (Store Vector Byte Indexed, AV p131)
4974//zz DIP("stvebx v%d,r%d,r%d\n", vS_addr, rA_addr, rB_addr);
4975//zz DIP(" => not implemented\n");
4976//zz return False;
4977//zz
4978//zz // eb = EA & 0xF;
4979//zz // STORE(vS[eb*8:eb*8+7], 1, EA);
4980//zz // storeBE( mkexpr(EA), mkexpr(vS) );
4981//zz
4982//zz case 0x0A7: // stvehx (Store Vector Half Word Indexed, AV p132)
4983//zz DIP("stvehx v%d,r%d,r%d\n", vS_addr, rA_addr, rB_addr);
4984//zz DIP(" => not implemented\n");
4985//zz return False;
4986//zz
4987//zz // EA_aligned = EA & 0xFFFF_FFFE
4988//zz // eb = EA_aligned & 0xF;
4989//zz // STORE(vS[eb*8:eb*8+15], 2, EA_aligned);
4990//zz
4991//zz case 0x0C7: // stvewx (Store Vector Word Indexed, AV p133)
4992//zz DIP("stvewx v%d,r%d,r%d\n", vS_addr, rA_addr, rB_addr);
4993//zz DIP(" => not implemented\n");
4994//zz return False;
4995//zz
4996//zz // EA_aligned = EA & 0xFFFF_FFFC
4997//zz // eb = EA_aligned & 0xF;
4998//zz // STORE(vS[eb*8:eb*8+31], 4, EA_aligned);
ceriona982c052005-06-28 17:23:09 +00004999
5000 case 0x0E7: // stvx (Store Vector Indexed, AV p134)
5001 DIP("stvx v%d,r%d,r%d\n", vS_addr, rA_addr, rB_addr);
5002 assign( EA_aligned, binop( Iop_And32, mkexpr(EA), mkU32(0xFFFFFFF0) ));
5003 storeBE( mkexpr(EA_aligned), mkexpr(vS) );
5004 break;
5005
sewardjb51f0f42005-07-18 11:38:02 +00005006//zz case 0x1E7: // stvxl (Store Vector Indexed LRU, AV p135)
5007//zz // XXX: stvxl can give explicit control over cache block replacement
5008//zz DIP("stvxl v%d,r%d,r%d\n", vS_addr, rA_addr, rB_addr);
5009//zz DIP(" => not implemented\n");
5010//zz return False;
5011//zz
5012//zz // EA_aligned = EA & 0xFFFF_FFF0;
5013//zz // STORE(vS, 16, EA);
ceriona982c052005-06-28 17:23:09 +00005014
5015 default:
5016 vex_printf("dis_av_store(PPC32)(opc2)\n");
5017 return False;
5018 }
5019 return True;
5020}
5021
sewardjb51f0f42005-07-18 11:38:02 +00005022//zz /*
5023//zz AltiVec Arithmetic Instructions
5024//zz */
5025//zz static Bool dis_av_arith ( UInt theInstr )
5026//zz {
5027//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
5028//zz UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
5029//zz UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5030//zz UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
5031//zz UInt opc2 = (theInstr >> 0) & 0x7FF; /* theInstr[0:10] */
5032//zz
5033//zz if (opc1 != 0x4) {
5034//zz vex_printf("dis_av_arith(PPC32)(opc1 != 0x4)\n");
5035//zz return False;
5036//zz }
5037//zz
5038//zz switch (opc2) {
5039//zz /* Add */
5040//zz case 0x180: // vaddcuw (Add Carryout Unsigned Word, AV p136)
5041//zz DIP("vaddcuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5042//zz DIP(" => not implemented\n");
5043//zz return False;
5044//zz
5045//zz case 0x000: // vaddubm (Add Unsigned Byte Modulo, AV p141)
5046//zz DIP("vaddubm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5047//zz DIP(" => not implemented\n");
5048//zz return False;
5049//zz
5050//zz case 0x040: // vadduhm (Add Unsigned Half Word Modulo, AV p143)
5051//zz DIP("vadduhm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5052//zz DIP(" => not implemented\n");
5053//zz return False;
5054//zz
5055//zz case 0x080: // vadduwm (Add Unsigned Word Modulo, AV p145)
5056//zz DIP("vadduwm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5057//zz DIP(" => not implemented\n");
5058//zz return False;
5059//zz
5060//zz case 0x200: // vaddubs (Add Unsigned Byte Saturate, AV p142)
5061//zz DIP("vaddubs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5062//zz DIP(" => not implemented\n");
5063//zz return False;
5064//zz
5065//zz case 0x240: // vadduhs (Add Unsigned Half Word Saturate, AV p144)
5066//zz DIP("vadduhs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5067//zz DIP(" => not implemented\n");
5068//zz return False;
5069//zz
5070//zz case 0x280: // vadduws (Add Unsigned Word Saturate, AV p146)
5071//zz DIP("vadduws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5072//zz DIP(" => not implemented\n");
5073//zz return False;
5074//zz
5075//zz case 0x300: // vaddsbs (Add Signed Byte Saturate, AV p138)
5076//zz DIP("vaddsbs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5077//zz DIP(" => not implemented\n");
5078//zz return False;
5079//zz
5080//zz case 0x340: // vaddshs (Add Signed Half Word Saturate, AV p139)
5081//zz DIP("vaddshs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5082//zz DIP(" => not implemented\n");
5083//zz return False;
5084//zz
5085//zz case 0x380: // vaddsws (Add Signed Word Saturate, AV p140)
5086//zz DIP("vaddsws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5087//zz DIP(" => not implemented\n");
5088//zz return False;
5089//zz
5090//zz /* Subtract */
5091//zz case 0x580: // vsubcuw (Subtract Carryout Unsigned Word, AV p260)
5092//zz DIP("vsubcuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5093//zz DIP(" => not implemented\n");
5094//zz return False;
5095//zz
5096//zz case 0x400: // vsububm (Subtract Unsigned Byte Modulo, AV p265)
5097//zz DIP("vsububm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5098//zz DIP(" => not implemented\n");
5099//zz return False;
5100//zz
5101//zz case 0x440: // vsubuhm (Subtract Unsigned Half Word Modulo, AV p267)
5102//zz DIP("vsubuhm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5103//zz DIP(" => not implemented\n");
5104//zz return False;
5105//zz
5106//zz case 0x480: // vsubuwm (Subtract Unsigned Word Modulo, AV p269)
5107//zz DIP("vsubuwm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5108//zz DIP(" => not implemented\n");
5109//zz return False;
5110//zz
5111//zz case 0x600: // vsububs (Subtract Unsigned Byte Saturate, AV p266)
5112//zz DIP("vsububs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5113//zz DIP(" => not implemented\n");
5114//zz return False;
5115//zz
5116//zz case 0x640: // vsubuhs (Subtract Unsigned Half Word Saturate, AV p268)
5117//zz DIP("vsubuhs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5118//zz DIP(" => not implemented\n");
5119//zz return False;
5120//zz
5121//zz case 0x680: // vsubuws (Subtract Unsigned Word Saturate, AV p270)
5122//zz DIP("vsubuws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5123//zz DIP(" => not implemented\n");
5124//zz return False;
5125//zz
5126//zz case 0x700: // vsubsbs (Subtract Signed Byte Saturate, AV p262)
5127//zz DIP("vsubsbs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5128//zz DIP(" => not implemented\n");
5129//zz return False;
5130//zz
5131//zz case 0x740: // vsubshs (Subtract Signed Half Word Saturate, AV p263)
5132//zz DIP("vsubshs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5133//zz DIP(" => not implemented\n");
5134//zz return False;
5135//zz
5136//zz case 0x780: // vsubsws (Subtract Signed Word Saturate, AV p264)
5137//zz DIP("vsubsws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5138//zz DIP(" => not implemented\n");
5139//zz return False;
5140//zz
5141//zz
5142//zz /* Maximum */
5143//zz case 0x002: // vmaxub (Maximum Unsigned Byte, AV p182)
5144//zz DIP("vmaxub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5145//zz DIP(" => not implemented\n");
5146//zz return False;
5147//zz
5148//zz case 0x042: // vmaxuh (Maximum Unsigned Half Word, AV p183)
5149//zz DIP("vmaxuh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5150//zz DIP(" => not implemented\n");
5151//zz return False;
5152//zz
5153//zz case 0x082: // vmaxuw (Maximum Unsigned Word, AV p184)
5154//zz DIP("vmaxuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5155//zz DIP(" => not implemented\n");
5156//zz return False;
5157//zz
5158//zz case 0x102: // vmaxsb (Maximum Signed Byte, AV p179)
5159//zz DIP("vmaxsb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5160//zz DIP(" => not implemented\n");
5161//zz return False;
5162//zz
5163//zz case 0x142: // vmaxsh (Maximum Signed Half Word, AV p180)
5164//zz DIP("vmaxsh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5165//zz DIP(" => not implemented\n");
5166//zz return False;
5167//zz
5168//zz case 0x182: // vmaxsw (Maximum Signed Word, AV p181)
5169//zz DIP("vmaxsw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5170//zz DIP(" => not implemented\n");
5171//zz return False;
5172//zz
5173//zz
5174//zz /* Minimum */
5175//zz case 0x202: // vminub (Minimum Unsigned Byte, AV p191)
5176//zz DIP("vminub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5177//zz DIP(" => not implemented\n");
5178//zz return False;
5179//zz
5180//zz case 0x242: // vminuh (Minimum Unsigned Half Word, AV p192)
5181//zz DIP("vminuh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5182//zz DIP(" => not implemented\n");
5183//zz return False;
5184//zz
5185//zz case 0x282: // vminuw (Minimum Unsigned Word, AV p193)
5186//zz DIP("vminuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5187//zz DIP(" => not implemented\n");
5188//zz return False;
5189//zz
5190//zz case 0x302: // vminsb (Minimum Signed Byte, AV p188)
5191//zz DIP("vminsb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5192//zz DIP(" => not implemented\n");
5193//zz return False;
5194//zz
5195//zz case 0x342: // vminsh (Minimum Signed Half Word, AV p189)
5196//zz DIP("vminsh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5197//zz DIP(" => not implemented\n");
5198//zz return False;
5199//zz
5200//zz case 0x382: // vminsw (Minimum Signed Word, AV p190)
5201//zz DIP("vminsw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5202//zz DIP(" => not implemented\n");
5203//zz return False;
5204//zz
5205//zz
5206//zz /* Average */
5207//zz case 0x402: // vavgub (Average Unsigned Byte, AV p152)
5208//zz DIP("vavgub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5209//zz DIP(" => not implemented\n");
5210//zz return False;
5211//zz
5212//zz case 0x442: // vavguh (Average Unsigned Half Word, AV p153)
5213//zz DIP("vavguh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5214//zz DIP(" => not implemented\n");
5215//zz return False;
5216//zz
5217//zz case 0x482: // vavguw (Average Unsigned Word, AV p154)
5218//zz DIP("vavguw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5219//zz DIP(" => not implemented\n");
5220//zz return False;
5221//zz
5222//zz case 0x502: // vavgsb (Average Signed Byte, AV p149)
5223//zz DIP("vavgsb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5224//zz DIP(" => not implemented\n");
5225//zz return False;
5226//zz
5227//zz case 0x542: // vavgsh (Average Signed Half Word, AV p150)
5228//zz DIP("vavgsh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5229//zz DIP(" => not implemented\n");
5230//zz return False;
5231//zz
5232//zz case 0x582: // vavgsw (Average Signed Word, AV p151)
5233//zz DIP("vavgsw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5234//zz DIP(" => not implemented\n");
5235//zz return False;
5236//zz
5237//zz
5238//zz /* Multiply */
5239//zz case 0x008: // vmuloub (Multiply Odd Unsigned Byte, AV p213)
5240//zz DIP("vmuloub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5241//zz DIP(" => not implemented\n");
5242//zz return False;
5243//zz
5244//zz case 0x048: // vmulouh (Multiply Odd Unsigned Half Word, AV p214)
5245//zz DIP("vmulouh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5246//zz DIP(" => not implemented\n");
5247//zz return False;
5248//zz
5249//zz case 0x108: // vmulosb (Multiply Odd Signed Byte, AV p211)
5250//zz DIP("vmulosb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5251//zz DIP(" => not implemented\n");
5252//zz return False;
5253//zz
5254//zz case 0x148: // vmulosh (Multiply Odd Signed Half Word, AV p212)
5255//zz DIP("vmulosh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5256//zz DIP(" => not implemented\n");
5257//zz return False;
5258//zz
5259//zz case 0x208: // vmuleub (Multiply Even Unsigned Byte, AV p209)
5260//zz DIP("vmuleub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5261//zz DIP(" => not implemented\n");
5262//zz return False;
5263//zz
5264//zz case 0x248: // vmuleuh (Multiply Even Unsigned Half Word, AV p210)
5265//zz DIP("vmuleuh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5266//zz DIP(" => not implemented\n");
5267//zz return False;
5268//zz
5269//zz case 0x308: // vmulesb (Multiply Even Signed Byte, AV p207)
5270//zz DIP("vmulesb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5271//zz DIP(" => not implemented\n");
5272//zz return False;
5273//zz
5274//zz case 0x348: // vmulesh (Multiply Even Signed Half Word, AV p208)
5275//zz DIP("vmulesh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5276//zz DIP(" => not implemented\n");
5277//zz return False;
5278//zz
5279//zz
5280//zz /* Sum Across Partial */
5281//zz case 0x608: // vsum4ubs (Sum Partial (1/4) UB Saturate, AV p275)
5282//zz DIP("vsum4ubs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5283//zz DIP(" => not implemented\n");
5284//zz return False;
5285//zz
5286//zz case 0x708: // vsum4sbs (Sum Partial (1/4) SB Saturate, AV p273)
5287//zz DIP("vsum4sbs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5288//zz DIP(" => not implemented\n");
5289//zz return False;
5290//zz
5291//zz case 0x648: // vsum4shs (Sum Partial (1/4) SHW Saturate, AV p274)
5292//zz DIP("vsum4shs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5293//zz DIP(" => not implemented\n");
5294//zz return False;
5295//zz
5296//zz case 0x688: // vsum2sws (Sum Partial (1/2) SW Saturate, AV p272)
5297//zz DIP("vsum2sws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5298//zz DIP(" => not implemented\n");
5299//zz return False;
5300//zz
5301//zz case 0x788: // vsumsws (Sum SW Saturate, AV p271)
5302//zz DIP("vsumsws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5303//zz DIP(" => not implemented\n");
5304//zz return False;
5305//zz
5306//zz default:
5307//zz vex_printf("dis_av_arith(PPC32)(opc2=0x%x)\n", opc2);
5308//zz return False;
5309//zz }
5310//zz return True;
5311//zz }
5312//zz
5313//zz /*
5314//zz AltiVec Logic Instructions
5315//zz */
5316//zz static Bool dis_av_logic ( UInt theInstr )
5317//zz {
5318//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
5319//zz UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
5320//zz UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5321//zz UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
5322//zz UInt opc2 = (theInstr >> 0) & 0x7FF; /* theInstr[0:10] */
5323//zz
5324//zz if (opc1 != 0x4) {
5325//zz vex_printf("dis_av_logic(PPC32)(opc1 != 0x4)\n");
5326//zz return False;
5327//zz }
5328//zz
5329//zz switch (opc2) {
5330//zz case 0x404: // vand (And, AV p147)
5331//zz DIP("vand v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5332//zz DIP(" => not implemented\n");
5333//zz return False;
5334//zz
5335//zz case 0x444: // vandc (And, AV p148)
5336//zz DIP("vandc v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5337//zz DIP(" => not implemented\n");
5338//zz return False;
5339//zz
5340//zz case 0x484: // vor (Or, AV p217)
5341//zz DIP("vor v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5342//zz DIP(" => not implemented\n");
5343//zz return False;
5344//zz
5345//zz case 0x4C4: // vxor (Xor, AV p282)
5346//zz DIP("vxor v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5347//zz DIP(" => not implemented\n");
5348//zz return False;
5349//zz
5350//zz case 0x504: // vnor (Nor, AV p216)
5351//zz DIP("vnor v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5352//zz DIP(" => not implemented\n");
5353//zz return False;
5354//zz
5355//zz default:
5356//zz vex_printf("dis_av_logic(PPC32)(opc2=0x%x)\n", opc2);
5357//zz return False;
5358//zz }
5359//zz return True;
5360//zz }
5361//zz
5362//zz /*
5363//zz AltiVec Compare Instructions
5364//zz */
5365//zz static Bool dis_av_cmp ( UInt theInstr )
5366//zz {
5367//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
5368//zz UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
5369//zz UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5370//zz UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
5371//zz UChar flag_Rc = toUChar((theInstr >> 10) & 0x1); /* theInstr[10] */
5372//zz UInt opc2 = (theInstr >> 0) & 0x3FF; /* theInstr[0:9] */
5373//zz
5374//zz if (opc1 != 0x4) {
5375//zz vex_printf("dis_av_cmp(PPC32)(instr)\n");
5376//zz return False;
5377//zz }
5378//zz
5379//zz switch (opc2) {
5380//zz case 0x006: // vcmpequb (Compare Equal-to Unsigned B, AV p160)
5381//zz DIP("vcmpequb%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
5382//zz DIP(" => not implemented\n");
5383//zz return False;
5384//zz
5385//zz case 0x046: // vcmpequh (Compare Equal-to Unsigned HW, AV p161)
5386//zz DIP("vcmpequh%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
5387//zz DIP(" => not implemented\n");
5388//zz return False;
5389//zz
5390//zz case 0x086: // vcmpequw (Compare Equal-to Unsigned W, AV p162)
5391//zz DIP("vcmpequw%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
5392//zz DIP(" => not implemented\n");
5393//zz return False;
5394//zz
5395//zz case 0x206: // vcmpgtub (Compare Greater-than Unsigned B, AV p168)
5396//zz DIP("vcmpgtub%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
5397//zz DIP(" => not implemented\n");
5398//zz return False;
5399//zz
5400//zz case 0x246: // vcmpgtuh (Compare Greater-than Unsigned HW, AV p169)
5401//zz DIP("vcmpgtuh%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
5402//zz DIP(" => not implemented\n");
5403//zz return False;
5404//zz
5405//zz case 0x286: // vcmpgtuw (Compare Greater-than Unsigned W, AV p170)
5406//zz DIP("vcmpgtuw%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
5407//zz DIP(" => not implemented\n");
5408//zz return False;
5409//zz
5410//zz case 0x306: // vcmpgtsb (Compare Greater-than Signed B, AV p165)
5411//zz DIP("vcmpgtsb%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
5412//zz DIP(" => not implemented\n");
5413//zz return False;
5414//zz
5415//zz case 0x346: // vcmpgtsh (Compare Greater-than Signed HW, AV p166)
5416//zz DIP("vcmpgtsh%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
5417//zz DIP(" => not implemented\n");
5418//zz return False;
5419//zz
5420//zz case 0x386: // vcmpgtsw (Compare Greater-than Signed W, AV p167)
5421//zz DIP("vcmpgtsw%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
5422//zz DIP(" => not implemented\n");
5423//zz return False;
5424//zz
5425//zz default:
5426//zz vex_printf("dis_av_cmp(PPC32)(opc2)\n");
5427//zz return False;
5428//zz }
5429//zz return True;
5430//zz }
5431//zz
5432//zz /*
5433//zz AltiVec Multiply-Sum Instructions
5434//zz */
5435//zz static Bool dis_av_multarith ( UInt theInstr )
5436//zz {
5437//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
5438//zz UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
5439//zz UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5440//zz UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
5441//zz UChar vC_addr = toUChar((theInstr >> 6) & 0x1F); /* theInstr[6:10] */
5442//zz UChar opc2 = toUChar((theInstr >> 0) & 0x3F); /* theInstr[0:5] */
5443//zz
5444//zz if (opc1 != 0x4) {
5445//zz vex_printf("dis_av_multarith(PPC32)(instr)\n");
5446//zz return False;
5447//zz }
5448//zz
5449//zz switch (opc2) {
5450//zz
5451//zz /* Multiply-Add */
5452//zz case 0x20: // vmhaddshs (Multiply High, Add Signed HW Saturate, AV p185)
5453//zz DIP("vmhaddshs v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
5454//zz DIP(" => not implemented\n");
5455//zz return False;
5456//zz
5457//zz case 0x21: // vmhraddshs (Multiply High Round, Add Signed HW Saturate, AV p186)
5458//zz DIP("vmhraddshs v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
5459//zz DIP(" => not implemented\n");
5460//zz return False;
5461//zz
5462//zz case 0x22: // vmladduhm (Multiply Low, Add Unsigned HW Modulo, AV p194)
5463//zz DIP("vmladduhm v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
5464//zz DIP(" => not implemented\n");
5465//zz return False;
5466//zz
5467//zz
5468//zz /* Multiply-Sum */
5469//zz case 0x24: // vmsumubm (Multiply Sum Unsigned B Modulo, AV p204)
5470//zz DIP("vmsumubm v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
5471//zz DIP(" => not implemented\n");
5472//zz return False;
5473//zz
5474//zz case 0x25: // vmsummbm (Multiply Sum Mixed-Sign B Modulo, AV p201)
5475//zz DIP("vmsummbm v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
5476//zz DIP(" => not implemented\n");
5477//zz return False;
5478//zz
5479//zz case 0x26: // vmsumuhm (Multiply Sum Unsigned HW Modulo, AV p205)
5480//zz DIP("vmsumuhm v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
5481//zz DIP(" => not implemented\n");
5482//zz return False;
5483//zz
5484//zz case 0x27: // vmsumuhs (Multiply Sum Unsigned HW Saturate, AV p206)
5485//zz DIP("vmsumuhs v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
5486//zz DIP(" => not implemented\n");
5487//zz return False;
5488//zz
5489//zz case 0x28: // vmsumshm (Multiply Sum Signed HW Modulo, AV p202)
5490//zz DIP("vmsumshm v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
5491//zz DIP(" => not implemented\n");
5492//zz return False;
5493//zz
5494//zz case 0x29: // vmsumshs (Multiply Sum Signed HW Saturate, AV p203)
5495//zz DIP("vmsumshs v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
5496//zz DIP(" => not implemented\n");
5497//zz return False;
5498//zz
5499//zz default:
5500//zz vex_printf("dis_av_multarith(PPC32)(opc2)\n");
5501//zz return False;
5502//zz }
5503//zz return True;
5504//zz }
5505//zz
5506//zz /*
5507//zz AltiVec Shift/Rotate Instructions
5508//zz */
5509//zz static Bool dis_av_shift ( UInt theInstr )
5510//zz {
5511//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
5512//zz UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
5513//zz UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5514//zz UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
5515//zz UInt opc2 = (theInstr >> 0) & 0x7FF; /* theInstr[0:10] */
5516//zz
5517//zz if (opc1 != 0x4){
5518//zz vex_printf("dis_av_shift(PPC32)(instr)\n");
5519//zz return False;
5520//zz }
5521//zz
5522//zz switch (opc2) {
5523//zz /* Rotate */
5524//zz case 0x004: // vrlb (Rotate Left Integer B, AV p234)
5525//zz DIP("vrlb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5526//zz DIP(" => not implemented\n");
5527//zz return False;
5528//zz
5529//zz case 0x044: // vrlh (Rotate Left Integer HW, AV p235)
5530//zz DIP("vrlh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5531//zz DIP(" => not implemented\n");
5532//zz return False;
5533//zz
5534//zz case 0x084: // vrlw (Rotate Left Integer W, AV p236)
5535//zz DIP("vrlw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5536//zz DIP(" => not implemented\n");
5537//zz return False;
5538//zz
5539//zz
5540//zz /* Shift Left */
5541//zz case 0x104: // vslb (Shift Left Integer B, AV p240)
5542//zz DIP("vslb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5543//zz DIP(" => not implemented\n");
5544//zz return False;
5545//zz
5546//zz case 0x144: // vslh (Shift Left Integer HW, AV p242)
5547//zz DIP("vslh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5548//zz DIP(" => not implemented\n");
5549//zz return False;
5550//zz
5551//zz case 0x184: // vslw (Shift Left Integer W, AV p244)
5552//zz DIP("vslw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5553//zz DIP(" => not implemented\n");
5554//zz return False;
5555//zz
5556//zz case 0x1C4: // vsl (Shift Left, AV p239)
5557//zz DIP("vsl v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5558//zz DIP(" => not implemented\n");
5559//zz return False;
5560//zz
5561//zz case 0x40C: // vslo (Shift Left by Octet, AV p243)
5562//zz DIP("vslo v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5563//zz DIP(" => not implemented\n");
5564//zz return False;
5565//zz
5566//zz /* Shift Right */
5567//zz case 0x204: // vsrb (Shift Right B, AV p256)
5568//zz DIP("vsrb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5569//zz DIP(" => not implemented\n");
5570//zz return False;
5571//zz
5572//zz case 0x244: // vsrh (Shift Right HW, AV p257)
5573//zz DIP("vsrh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5574//zz DIP(" => not implemented\n");
5575//zz return False;
5576//zz
5577//zz case 0x284: // vsrw (Shift Right W, AV p259)
5578//zz DIP("vsrw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5579//zz DIP(" => not implemented\n");
5580//zz return False;
5581//zz
5582//zz case 0x2C4: // vsr (Shift Right, AV p252)
5583//zz DIP("vsr v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5584//zz DIP(" => not implemented\n");
5585//zz return False;
5586//zz
5587//zz case 0x304: // vsrab (Shift Right Algebraic B, AV p253)
5588//zz DIP("vsrab v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5589//zz DIP(" => not implemented\n");
5590//zz return False;
5591//zz
5592//zz case 0x344: // vsrah (Shift Right Algebraic HW, AV p254)
5593//zz DIP("vsrah v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5594//zz DIP(" => not implemented\n");
5595//zz return False;
5596//zz
5597//zz case 0x384: // vsraw (Shift Right Algebraic W, AV p255)
5598//zz DIP("vsraw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5599//zz DIP(" => not implemented\n");
5600//zz return False;
5601//zz
5602//zz case 0x44C: // vsro (Shift Right by Octet, AV p258)
5603//zz DIP("vsro v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5604//zz DIP(" => not implemented\n");
5605//zz return False;
5606//zz
5607//zz default:
5608//zz vex_printf("dis_av_shift(PPC32)(opc2)\n");
5609//zz return False;
5610//zz }
5611//zz return True;
5612//zz }
5613//zz
5614//zz /*
5615//zz AltiVec Permute Instructions
5616//zz */
5617//zz static Bool dis_av_permute ( UInt theInstr )
5618//zz {
5619//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
5620//zz UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
5621//zz UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5622//zz UChar UIMM_5 = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5623//zz UChar SIMM_5 = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5624//zz UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
5625//zz UChar vC_addr = toUChar((theInstr >> 6) & 0x1F); /* theInstr[6:10] */
5626//zz UChar b10 = toUChar((theInstr >> 10) & 0x1); /* theInstr[10] */
5627//zz UChar SHB_uimm4 = toUChar((theInstr >> 6) & 0xF); /* theInstr[6:9] */
5628//zz UInt opc2 = (theInstr >> 0) & 0x3F; /* theInstr[0:5] */
5629//zz
5630//zz UChar SIMM_8 = extend_s_5to8(SIMM_5);
5631//zz
5632//zz if (opc1 != 0x4) {
5633//zz vex_printf("dis_av_permute(PPC32)(instr)\n");
5634//zz return False;
5635//zz }
5636//zz
5637//zz switch (opc2) {
5638//zz case 0x2A: // vsel (Conditional Select, AV p238)
5639//zz DIP("vsel v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
5640//zz DIP(" => not implemented\n");
5641//zz return False;
5642//zz
5643//zz case 0x2B: // vperm (Permute, AV p218)
5644//zz DIP("vperm v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
5645//zz DIP(" => not implemented\n");
5646//zz return False;
5647//zz
5648//zz case 0x2C: // vsldoi (Shift Left Double by Octet Imm, AV p241)
5649//zz if (b10 != 0) {
5650//zz vex_printf("dis_av_permute(PPC32)(vsldoi)\n");
5651//zz return False;
5652//zz }
5653//zz DIP("vsldoi v%d,v%d,v%d,%d\n", vD_addr, vA_addr, vB_addr, SHB_uimm4);
5654//zz DIP(" => not implemented\n");
5655//zz return False;
5656//zz
5657//zz default:
5658//zz break; // Fall through...
5659//zz }
5660//zz
5661//zz opc2 = (theInstr) & 0x7FF; /* theInstr[0:10] */
5662//zz switch (opc2) {
5663//zz
5664//zz /* Merge */
5665//zz case 0x00C: // vmrghb (Merge High B, AV p195)
5666//zz DIP("vmrghb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5667//zz DIP(" => not implemented\n");
5668//zz return False;
5669//zz
5670//zz case 0x04C: // vmrghh (Merge High HW, AV p196)
5671//zz DIP("vmrghh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5672//zz DIP(" => not implemented\n");
5673//zz return False;
5674//zz
5675//zz case 0x08C: // vmrghw (Merge High W, AV p197)
5676//zz DIP("vmrghw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5677//zz DIP(" => not implemented\n");
5678//zz return False;
5679//zz
5680//zz case 0x10C: // vmrglb (Merge Low B, AV p198)
5681//zz DIP("vmrglb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5682//zz DIP(" => not implemented\n");
5683//zz return False;
5684//zz
5685//zz case 0x14C: // vmrglh (Merge Low HW, AV p199)
5686//zz DIP("vmrglh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5687//zz DIP(" => not implemented\n");
5688//zz return False;
5689//zz
5690//zz case 0x18C: // vmrglw (Merge Low W, AV p200)
5691//zz DIP("vmrglw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5692//zz DIP(" => not implemented\n");
5693//zz return False;
5694//zz
5695//zz /* Splat */
5696//zz case 0x20C: // vspltb (Splat Byte, AV p245)
5697//zz DIP("vspltb v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
5698//zz DIP(" => not implemented\n");
5699//zz return False;
5700//zz
5701//zz case 0x24C: // vsplth (Splat Half Word, AV p246)
5702//zz DIP("vsplth v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
5703//zz DIP(" => not implemented\n");
5704//zz return False;
5705//zz
5706//zz case 0x28C: // vspltw (Splat Word, AV p250)
5707//zz DIP("vspltw v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
5708//zz DIP(" => not implemented\n");
5709//zz return False;
5710//zz
5711//zz case 0x30C: // vspltisb (Splat Immediate Signed B, AV p247)
5712//zz DIP("vspltisb v%d,%d\n", vD_addr, (Char)SIMM_8);
5713//zz DIP(" => not implemented\n");
5714//zz return False;
5715//zz
5716//zz case 0x34C: // vspltish (Splat Immediate Signed HW, AV p248)
5717//zz DIP("vspltish v%d,%d\n", vD_addr, (Char)SIMM_8);
5718//zz DIP(" => not implemented\n");
5719//zz return False;
5720//zz
5721//zz case 0x38C: // vspltisw (Splat Immediate Signed W, AV p249)
5722//zz DIP("vspltisw v%d,%d\n", vD_addr, (Char)SIMM_8);
5723//zz DIP(" => not implemented\n");
5724//zz return False;
5725//zz
5726//zz default:
5727//zz vex_printf("dis_av_permute(PPC32)(opc2)\n");
5728//zz return False;
5729//zz }
5730//zz return True;
5731//zz }
5732//zz
5733//zz /*
5734//zz AltiVec Pack/Unpack Instructions
5735//zz */
5736//zz static Bool dis_av_pack ( UInt theInstr )
5737//zz {
5738//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
5739//zz UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
5740//zz UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5741//zz UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
5742//zz UInt opc2 = (theInstr >> 0) & 0x7FF; /* theInstr[0:10] */
5743//zz
5744//zz if (opc1 != 0x4) {
5745//zz vex_printf("dis_av_pack(PPC32)(instr)\n");
5746//zz return False;
5747//zz }
5748//zz
5749//zz switch (opc2) {
5750//zz /* Packing */
5751//zz case 0x00E: // vpkuhum (Pack Unsigned HW Unsigned Modulo, AV p224)
5752//zz DIP("vpkuhum v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5753//zz DIP(" => not implemented\n");
5754//zz return False;
5755//zz
5756//zz case 0x04E: // vpkuwum (Pack Unsigned W Unsigned Modulo, AV p226)
5757//zz DIP("vpkuwum v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5758//zz DIP(" => not implemented\n");
5759//zz return False;
5760//zz
5761//zz case 0x08E: // vpkuhus (Pack Unsigned HW Unsigned Saturate, AV p225)
5762//zz DIP("vpkuhus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5763//zz DIP(" => not implemented\n");
5764//zz return False;
5765//zz
5766//zz case 0x0CE: // vpkuwus (Pack Unsigned W Unsigned Saturate, AV p227)
5767//zz DIP("vpkuwus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5768//zz DIP(" => not implemented\n");
5769//zz return False;
5770//zz
5771//zz case 0x10E: // vpkshus (Pack Signed HW Unsigned Saturate, AV p221)
5772//zz DIP("vpkshus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5773//zz DIP(" => not implemented\n");
5774//zz return False;
5775//zz
5776//zz case 0x14E: // vpkswus (Pack Signed W Unsigned Saturate, AV p223)
5777//zz DIP("vpkswus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5778//zz DIP(" => not implemented\n");
5779//zz return False;
5780//zz
5781//zz case 0x18E: // vpkshss (Pack Signed HW Signed Saturate, AV p220)
5782//zz DIP("vpkshss v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5783//zz DIP(" => not implemented\n");
5784//zz return False;
5785//zz
5786//zz case 0x1CE: // vpkswss (Pack Signed W Signed Saturate, AV p222)
5787//zz DIP("vpkswss v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5788//zz DIP(" => not implemented\n");
5789//zz return False;
5790//zz
5791//zz case 0x30E: // vpkpx (Pack Pixel, AV p219)
5792//zz DIP("vpkpx v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5793//zz DIP(" => not implemented\n");
5794//zz return False;
5795//zz
5796//zz default:
5797//zz break; // Fall through...
5798//zz }
5799//zz
5800//zz
5801//zz if (vA_addr != 0) {
5802//zz vex_printf("dis_av_pack(PPC32)(vA_addr)\n");
5803//zz return False;
5804//zz }
5805//zz
5806//zz switch (opc2) {
5807//zz /* Unpacking */
5808//zz case 0x20E: // vupkhsb (Unpack High Signed B, AV p277)
5809//zz DIP("vupkhsb v%d,v%d\n", vD_addr, vB_addr);
5810//zz DIP(" => not implemented\n");
5811//zz return False;
5812//zz
5813//zz case 0x24E: // vupkhsh (Unpack High Signed HW, AV p278)
5814//zz DIP("vupkhsh v%d,v%d\n", vD_addr, vB_addr);
5815//zz DIP(" => not implemented\n");
5816//zz return False;
5817//zz
5818//zz case 0x28E: // vupklsb (Unpack Low Signed B, AV p280)
5819//zz DIP("vupklsb v%d,v%d\n", vD_addr, vB_addr);
5820//zz DIP(" => not implemented\n");
5821//zz return False;
5822//zz
5823//zz case 0x2CE: // vupklsh (Unpack Low Signed HW, AV p281)
5824//zz DIP("vupklsh v%d,v%d\n", vD_addr, vB_addr);
5825//zz DIP(" => not implemented\n");
5826//zz return False;
5827//zz
5828//zz case 0x34E: // vupkhpx (Unpack High Pixel16, AV p276)
5829//zz DIP("vupkhpx v%d,v%d\n", vD_addr, vB_addr);
5830//zz DIP(" => not implemented\n");
5831//zz return False;
5832//zz
5833//zz case 0x3CE: // vupklpx (Unpack Low Pixel16, AV p279)
5834//zz DIP("vupklpx v%d,v%d\n", vD_addr, vB_addr);
5835//zz DIP(" => not implemented\n");
5836//zz return False;
5837//zz
5838//zz default:
5839//zz vex_printf("dis_av_pack(PPC32)(opc2)\n");
5840//zz return False;
5841//zz }
5842//zz return True;
5843//zz }
5844//zz
5845//zz
5846//zz /*
5847//zz AltiVec Floating Point Arithmetic Instructions
5848//zz */
5849//zz static Bool dis_av_fp_arith ( UInt theInstr )
5850//zz {
5851//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
5852//zz UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
5853//zz UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5854//zz UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
5855//zz UChar vC_addr = toUChar((theInstr >> 6) & 0x1F); /* theInstr[6:10] */
5856//zz UInt opc2=0;
5857//zz
5858//zz if (opc1 != 0x4) {
5859//zz vex_printf("dis_av_fp_arith(PPC32)(instr)\n");
5860//zz return False;
5861//zz }
5862//zz
5863//zz opc2 = (theInstr) & 0x3F; /* theInstr[0:5] */
5864//zz switch (opc2) {
5865//zz case 0x2E: // vmaddfp (Multiply Add FP, AV p177)
5866//zz DIP("vmaddfp v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vC_addr, vB_addr);
5867//zz DIP(" => not implemented\n");
5868//zz return False;
5869//zz
5870//zz case 0x2F: // vnmsubfp (Negative Multiply-Subtract FP, AV p215)
5871//zz DIP("vnmsubfp v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vC_addr, vB_addr);
5872//zz DIP(" => not implemented\n");
5873//zz return False;
5874//zz
5875//zz default:
5876//zz break; // Fall through...
5877//zz }
5878//zz
5879//zz opc2 = (theInstr) & 0x7FF; /* theInstr[0:10] */
5880//zz switch (opc2) {
5881//zz case 0x00A: // vaddfp (Add FP, AV p137)
5882//zz DIP("vaddfp v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5883//zz DIP(" => not implemented\n");
5884//zz return False;
5885//zz
5886//zz case 0x04A: // vsubfp (Subtract FP, AV p261)
5887//zz DIP("vsubfp v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5888//zz DIP(" => not implemented\n");
5889//zz return False;
5890//zz
5891//zz case 0x40A: // vmaxfp (Maximum FP, AV p178)
5892//zz DIP("vmaxfp v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5893//zz DIP(" => not implemented\n");
5894//zz return False;
5895//zz
5896//zz case 0x44A: // vminfp (Minimum FP, AV p187)
5897//zz DIP("vminfp v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5898//zz DIP(" => not implemented\n");
5899//zz return False;
5900//zz
5901//zz default:
5902//zz break; // Fall through...
5903//zz }
5904//zz
5905//zz
5906//zz if (vA_addr != 0) {
5907//zz vex_printf("dis_av_fp_arith(PPC32)(vA_addr)\n");
5908//zz return False;
5909//zz }
5910//zz
5911//zz switch (opc2) {
5912//zz case 0x10A: // vrefp (Reciprocal Esimate FP, AV p228)
5913//zz DIP("vrefp v%d,v%d\n", vD_addr, vB_addr);
5914//zz DIP(" => not implemented\n");
5915//zz return False;
5916//zz
5917//zz case 0x14A: // vrsqrtefp (Reciprocal Square Root Estimate FP, AV p237)
5918//zz DIP("vrsqrtefp v%d,v%d\n", vD_addr, vB_addr);
5919//zz DIP(" => not implemented\n");
5920//zz return False;
5921//zz
5922//zz case 0x18A: // vexptefp (2 Raised to the Exp Est FP, AV p173)
5923//zz DIP("vexptefp v%d,v%d\n", vD_addr, vB_addr);
5924//zz DIP(" => not implemented\n");
5925//zz return False;
5926//zz
5927//zz case 0x1CA: // vlogefp (Log2 Estimate FP, AV p175)
5928//zz DIP("vlogefp v%d,v%d\n", vD_addr, vB_addr);
5929//zz DIP(" => not implemented\n");
5930//zz return False;
5931//zz
5932//zz default:
5933//zz vex_printf("dis_av_fp_arith(PPC32)(opc2=0x%x)\n",opc2);
5934//zz return False;
5935//zz }
5936//zz return True;
5937//zz }
5938//zz
5939//zz /*
5940//zz AltiVec Floating Point Compare Instructions
5941//zz */
5942//zz static Bool dis_av_fp_cmp ( UInt theInstr )
5943//zz {
5944//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
5945//zz UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
5946//zz UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5947//zz UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
5948//zz UChar flag_Rc = toUChar((theInstr >> 10) & 0x1); /* theInstr[10] */
5949//zz UInt opc2 = (theInstr >> 0) & 0x3FF; /* theInstr[0:9] */
5950//zz
5951//zz if (opc1 != 0x4) {
5952//zz vex_printf("dis_av_fp_cmp(PPC32)(instr)\n");
5953//zz return False;
5954//zz }
5955//zz
5956//zz switch (opc2) {
5957//zz case 0x0C6: // vcmpeqfp (Compare Equal-to FP, AV p159)
5958//zz DIP("vcmpeqfp%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
5959//zz DIP(" => not implemented\n");
5960//zz return False;
5961//zz
5962//zz case 0x1C6: // vcmpgefp (Compare Greater-than-or-Equal-to FP, AV p163)
5963//zz DIP("vcmpgefp%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
5964//zz DIP(" => not implemented\n");
5965//zz return False;
5966//zz
5967//zz case 0x2C6: // vcmpgtfp (Compare Greater-than FP, AV p164)
5968//zz DIP("vcmpgtfp%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
5969//zz DIP(" => not implemented\n");
5970//zz return False;
5971//zz
5972//zz case 0x3C6: // vcmpbfp (Compare Bounds FP, AV p157)
5973//zz DIP("vcmpbfp%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
5974//zz DIP(" => not implemented\n");
5975//zz return False;
5976//zz
5977//zz default:
5978//zz vex_printf("dis_av_fp_cmp(PPC32)(opc2)\n");
5979//zz return False;
5980//zz }
5981//zz return True;
5982//zz }
5983//zz
5984//zz /*
5985//zz AltiVec Floating Point Convert/Round Instructions
5986//zz */
5987//zz static Bool dis_av_fp_convert ( UInt theInstr )
5988//zz {
5989//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
5990//zz UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
5991//zz UChar UIMM_5 = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5992//zz UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
5993//zz UInt opc2 = (theInstr >> 0) & 0x7FF; /* theInstr[0:10] */
5994//zz
5995//zz if (opc1 != 0x4) {
5996//zz vex_printf("dis_av_fp_convert(PPC32)(instr)\n");
5997//zz return False;
5998//zz }
5999//zz
6000//zz switch (opc2) {
6001//zz case 0x30A: // vcfux (Convert from Unsigned Fixed-Point W, AV p156)
6002//zz DIP("vcfux v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
6003//zz DIP(" => not implemented\n");
6004//zz return False;
6005//zz
6006//zz case 0x34A: // vcfsx (Convert from Signed Fixed-Point W, AV p155)
6007//zz DIP("vcfsx v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
6008//zz DIP(" => not implemented\n");
6009//zz return False;
6010//zz
6011//zz case 0x38A: // vctuxs (Convert to Unsigned Fixed-Point W Saturate, AV p172)
6012//zz DIP("vctuxs v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
6013//zz DIP(" => not implemented\n");
6014//zz return False;
6015//zz
6016//zz case 0x3CA: // vctsxs (Convert to Signed Fixed-Point W Saturate, AV p171)
6017//zz DIP("vctsxs v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
6018//zz DIP(" => not implemented\n");
6019//zz return False;
6020//zz
6021//zz default:
6022//zz break; // Fall through...
6023//zz }
6024//zz
6025//zz if (UIMM_5 != 0) {
6026//zz vex_printf("dis_av_fp_convert(PPC32)(UIMM_5)\n");
6027//zz return False;
6028//zz }
6029//zz
6030//zz switch (opc2) {
6031//zz case 0x20A: // vrfin (Round to FP Integer Nearest, AV p231)
6032//zz DIP("vrfin v%d,v%d\n", vD_addr, vB_addr);
6033//zz DIP(" => not implemented\n");
6034//zz return False;
6035//zz
6036//zz case 0x24A: // vrfiz (Round to FP Integer toward zero, AV p233)
6037//zz DIP("vrfiz v%d,v%d\n", vD_addr, vB_addr);
6038//zz DIP(" => not implemented\n");
6039//zz return False;
6040//zz
6041//zz case 0x28A: // vrfip (Round to FP Integer toward +inf, AV p232)
6042//zz DIP("vrfip v%d,v%d\n", vD_addr, vB_addr);
6043//zz DIP(" => not implemented\n");
6044//zz return False;
6045//zz
6046//zz case 0x2CA: // vrfim (Round to FP Integer toward -inf, AV p230)
6047//zz DIP("vrfim v%d,v%d\n", vD_addr, vB_addr);
6048//zz DIP(" => not implemented\n");
6049//zz return False;
6050//zz
6051//zz default:
6052//zz vex_printf("dis_av_fp_convert(PPC32)(opc2)\n");
6053//zz return False;
6054//zz }
6055//zz return True;
6056//zz }
cerion3d870a32005-03-18 12:23:33 +00006057
6058
cerion91ad5362005-01-27 23:02:41 +00006059
6060
6061
6062
cerion896a1372005-01-25 12:24:25 +00006063/*------------------------------------------------------------*/
6064/*--- Disassemble a single instruction ---*/
6065/*------------------------------------------------------------*/
6066
6067/* Disassemble a single instruction into IR. The instruction
sewardj9e6491a2005-07-02 19:24:10 +00006068 is located in host memory at &guest_code[delta]. */
6069
6070static
6071DisResult disInstr_PPC32_WRK (
6072 Bool put_IP,
6073 Bool (*resteerOkFn) ( Addr64 ),
6074 Long delta64,
6075 VexArchInfo* archinfo
6076 )
cerion896a1372005-01-25 12:24:25 +00006077{
sewardj9e6491a2005-07-02 19:24:10 +00006078 UChar opc1;
6079 UInt opc2;
6080 DisResult dres;
cerion896a1372005-01-25 12:24:25 +00006081 UInt theInstr;
6082
sewardj9e6491a2005-07-02 19:24:10 +00006083 /* The running delta */
6084 Int delta = (Int)delta64;
6085
6086 /* Set result defaults. */
6087 dres.whatNext = Dis_Continue;
6088 dres.len = 0;
6089 dres.continueAt = 0;
cerion896a1372005-01-25 12:24:25 +00006090
cerion1515db92005-01-25 17:21:23 +00006091 /* At least this is simple on PPC32: insns are all 4 bytes long, and
cerion896a1372005-01-25 12:24:25 +00006092 4-aligned. So just fish the whole thing out of memory right now
6093 and have done. */
cerioncf004462005-01-31 15:24:55 +00006094 theInstr = getUIntBigendianly( (UChar*)(&guest_code[delta]) );
cerion896a1372005-01-25 12:24:25 +00006095
sewardjb51f0f42005-07-18 11:38:02 +00006096 DIP("\t0x%x: ", guest_CIA_curr_instr);
6097
6098 /* We may be asked to update the guest CIA before going further. */
6099 if (put_IP)
6100 putSPR( PPC32_SPR_CIA, mkU32(guest_CIA_curr_instr) );
cerion896a1372005-01-25 12:24:25 +00006101
cerion896a1372005-01-25 12:24:25 +00006102 /* Spot the client-request magic sequence. */
6103 // Essentially a v. unlikely sequence of noops that we can catch
6104 {
sewardj2f52de42005-07-03 01:51:29 +00006105 UChar* code = (UChar*)(&guest_code[delta]);
cerion896a1372005-01-25 12:24:25 +00006106
6107 /* Spot this:
sewardj2f52de42005-07-03 01:51:29 +00006108 0x7C03D808 tw 0,3,27 => trap word if (0) => nop
cerionb85e8bb2005-02-16 08:54:33 +00006109 0x5400E800 rlwinm 0,0,29,0,0 => r0 = rotl(r0,29)
6110 0x54001800 rlwinm 0,0,3,0,0 => r0 = rotl(r0,3)
6111 0x54006800 rlwinm 0,0,13,0,0 => r0 = rotl(r0,13)
6112 0x54009800 rlwinm 0,0,19,0,0 => r0 = rotl(r0,19)
cerion0fe6b7e2005-06-20 16:28:32 +00006113 0x60000000 nop
cerion896a1372005-01-25 12:24:25 +00006114 */
sewardj2f52de42005-07-03 01:51:29 +00006115 if (getUIntBigendianly(code+ 0) == 0x7C03D808 &&
6116 getUIntBigendianly(code+ 4) == 0x5400E800 &&
6117 getUIntBigendianly(code+ 8) == 0x54001800 &&
6118 getUIntBigendianly(code+12) == 0x54006800 &&
6119 getUIntBigendianly(code+16) == 0x54009800 &&
6120 getUIntBigendianly(code+20) == 0x60000000) {
cerion84ad6162005-06-23 15:25:57 +00006121 DIP("%%r3 = client_request ( %%r31 )\n");
sewardj9e6491a2005-07-02 19:24:10 +00006122 dres.len = 24;
cerioned623db2005-06-20 12:42:04 +00006123 delta += 24;
6124
sewardj9e6491a2005-07-02 19:24:10 +00006125 irbb->next = mkU32(guest_CIA_bbstart+delta);
cerionb85e8bb2005-02-16 08:54:33 +00006126 irbb->jumpkind = Ijk_ClientReq;
sewardj9e6491a2005-07-02 19:24:10 +00006127 dres.whatNext = Dis_StopHere;
cerion896a1372005-01-25 12:24:25 +00006128 goto decode_success;
6129 }
6130 }
6131
6132
sewardjb51f0f42005-07-18 11:38:02 +00006133 opc1 = ifieldOPC(theInstr);
6134 opc2 = ifieldOPClo10(theInstr);
cerion932ad942005-01-30 10:18:50 +00006135
cerione9d361a2005-03-04 17:35:29 +00006136#if PPC32_TOIR_DEBUG
cerion45552a92005-02-03 18:20:22 +00006137 vex_printf("\ndisInstr(ppc32): instr: 0x%x\n", theInstr);
6138 vex_printf("disInstr(ppc32): instr: ");
6139 vex_printf_binary( theInstr, 32, True );
6140 vex_printf("\n");
cerion45552a92005-02-03 18:20:22 +00006141#endif
cerione9d361a2005-03-04 17:35:29 +00006142
cerion45552a92005-02-03 18:20:22 +00006143
cerion91ad5362005-01-27 23:02:41 +00006144 // Note: all 'reserved' bits must be cleared, else invalid
6145 switch (opc1) {
cerion896a1372005-01-25 12:24:25 +00006146
cerione9d361a2005-03-04 17:35:29 +00006147 /* Integer Arithmetic Instructions */
6148 case 0x0C: case 0x0D: case 0x0E: // addic, addic., addi
6149 case 0x0F: case 0x07: case 0x08: // addis, mulli, subfic
6150 if (dis_int_arith( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006151 goto decode_failure;
cerion7aa4bbc2005-01-29 09:32:07 +00006152
cerione9d361a2005-03-04 17:35:29 +00006153 /* Integer Compare Instructions */
6154 case 0x0B: case 0x0A: // cmpi, cmpli
6155 if (dis_int_cmp( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006156 goto decode_failure;
cerion7aa4bbc2005-01-29 09:32:07 +00006157
cerione9d361a2005-03-04 17:35:29 +00006158 /* Integer Logical Instructions */
6159 case 0x1C: case 0x1D: case 0x18: // andi., andis., ori
6160 case 0x19: case 0x1A: case 0x1B: // oris, xori, xoris
6161 if (dis_int_logic( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006162 goto decode_failure;
cerion7aa4bbc2005-01-29 09:32:07 +00006163
cerione9d361a2005-03-04 17:35:29 +00006164 /* Integer Rotate Instructions */
6165 case 0x14: case 0x15: case 0x17: // rlwimi, rlwinm, rlwnm
6166 if (dis_int_rot( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006167 goto decode_failure;
cerion645c9302005-01-31 10:09:59 +00006168
cerione9d361a2005-03-04 17:35:29 +00006169 /* Integer Load Instructions */
6170 case 0x22: case 0x23: case 0x2A: // lbz, lbzu, lha
6171 case 0x2B: case 0x28: case 0x29: // lhau, lhz, lhzu
6172 case 0x20: case 0x21: // lwz, lwzu
6173 if (dis_int_load( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006174 goto decode_failure;
cerion645c9302005-01-31 10:09:59 +00006175
cerione9d361a2005-03-04 17:35:29 +00006176 /* Integer Store Instructions */
6177 case 0x26: case 0x27: case 0x2C: // stb, stbu, sth
6178 case 0x2D: case 0x24: case 0x25: // sthu, stw, stwu
6179 if (dis_int_store( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006180 goto decode_failure;
ceriond23be4e2005-01-31 07:23:07 +00006181
sewardjb51f0f42005-07-18 11:38:02 +00006182//zz /* Integer Load and Store Multiple Instructions */
6183//zz case 0x2E: case 0x2F: // lmw, stmw
6184//zz if (dis_int_ldst_mult( theInstr )) goto decode_success;
6185//zz goto decode_failure;
cerion645c9302005-01-31 10:09:59 +00006186
cerione9d361a2005-03-04 17:35:29 +00006187 /* Branch Instructions */
6188 case 0x12: case 0x10: // b, bc
sewardj9e6491a2005-07-02 19:24:10 +00006189 if (dis_branch(theInstr, &dres)) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006190 goto decode_failure;
cerion896a1372005-01-25 12:24:25 +00006191
cerione9d361a2005-03-04 17:35:29 +00006192 /* System Linkage Instructions */
cerion8c3adda2005-01-31 11:54:05 +00006193 case 0x11: // sc
sewardj9e6491a2005-07-02 19:24:10 +00006194 if (dis_syslink(theInstr, &dres)) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006195 goto decode_failure;
cerion26d07b22005-02-02 17:13:28 +00006196
sewardjb51f0f42005-07-18 11:38:02 +00006197//zz /* Trap Instructions */
6198//zz case 0x03: // twi
6199//zz DIP("trap op (twi) => not implemented\n");
6200//zz goto decode_failure;
cerion8c3adda2005-01-31 11:54:05 +00006201
cerion3d870a32005-03-18 12:23:33 +00006202 /* Floating Point Load Instructions */
cerion094d1392005-06-20 13:45:57 +00006203 case 0x30: case 0x31: case 0x32: // lfs, lfsu, lfd
6204 case 0x33: // lfdu
cerion3d870a32005-03-18 12:23:33 +00006205 if (dis_fp_load( theInstr )) goto decode_success;
cerione9d361a2005-03-04 17:35:29 +00006206 goto decode_failure;
cerion995bc362005-02-03 11:03:31 +00006207
cerion3d870a32005-03-18 12:23:33 +00006208 /* Floating Point Store Instructions */
6209 case 0x34: case 0x35: case 0x36: // stfsx, stfsux, stfdx
6210 case 0x37: // stfdux
6211 if (dis_fp_store( theInstr )) goto decode_success;
6212 goto decode_failure;
6213
sewardje14bb9f2005-07-22 09:39:02 +00006214 case 0x3B:
6215 opc2 = (theInstr >> 1) & 0x1F; /* theInstr[1:5] */
6216 switch (opc2) {
6217 /* Floating Point Arith Instructions */
6218 case 0x12: case 0x14: case 0x15: // fdivs, fsubs, fadds
6219 case 0x16: case 0x18: case 0x19: // fsqrts, fres, fmuls
6220 if (dis_fp_arith(theInstr)) goto decode_success;
6221 goto decode_failure;
6222
6223 /* Floating Point Mult-Add Instructions */
6224 case 0x1C: case 0x1D: case 0x1E: // fmsubs, fmadds, fnmsubs
6225 case 0x1F: // fnmadds
6226 if (dis_fp_multadd(theInstr)) goto decode_success;
6227 goto decode_failure;
6228
6229 default:
6230 goto decode_failure;
6231 }
6232 break;
cerion3d870a32005-03-18 12:23:33 +00006233
6234 case 0x3F:
6235 /* Instrs using opc[1:5] never overlap with instrs using opc[1:10],
6236 so we can simply fall through the first switch statement */
6237
6238 opc2 = (theInstr >> 1) & 0x1F; /* theInstr[1:5] */
6239 switch (opc2) {
sewardjb51f0f42005-07-18 11:38:02 +00006240 /* Floating Point Arith Instructions */
6241 case 0x12: case 0x14: case 0x15: // fdiv, fsub, fadd
6242 case 0x16: case 0x17: case 0x19: // fsqrt, fsel, fmul
6243 case 0x1A: // frsqrte
6244 if (dis_fp_arith(theInstr)) goto decode_success;
6245 goto decode_failure;
cerion3d870a32005-03-18 12:23:33 +00006246
sewardje14bb9f2005-07-22 09:39:02 +00006247 /* Floating Point Mult-Add Instructions */
6248 case 0x1C: case 0x1D: case 0x1E: // fmsub, fmadd, fnmsub
6249 case 0x1F: // fnmadd
6250 if (dis_fp_multadd(theInstr)) goto decode_success;
6251 goto decode_failure;
6252
sewardjb51f0f42005-07-18 11:38:02 +00006253 default:
6254 break; // Fall through
cerion3d870a32005-03-18 12:23:33 +00006255 }
6256
sewardje14bb9f2005-07-22 09:39:02 +00006257 opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
6258 switch (opc2) {
6259 /* Floating Point Compare Instructions */
6260 case 0x000: // fcmpu
6261 case 0x020: // fcmpo
6262 if (dis_fp_cmp(theInstr)) goto decode_success;
6263 goto decode_failure;
6264
6265 /* Floating Point Rounding/Conversion Instructions */
6266 case 0x00C: // frsp
6267 case 0x00E: // fctiw
6268 case 0x00F: // fctiwz
6269 if (dis_fp_round(theInstr)) goto decode_success;
6270 goto decode_failure;
6271
6272 /* Floating Point Move Instructions */
6273 case 0x028: // fneg
6274 case 0x048: // fmr
6275 case 0x088: // fnabs
6276 case 0x108: // fabs
6277 if (dis_fp_move( theInstr )) goto decode_success;
6278 goto decode_failure;
6279
sewardjb51f0f42005-07-18 11:38:02 +00006280//zz /* Floating Point Status/Control Register Instructions */
6281//zz case 0x026: // mtfsb1
6282//zz case 0x040: // mcrfs
sewardje14bb9f2005-07-22 09:39:02 +00006283 case 0x046: // mtfsb0
6284 case 0x086: // mtfsfi
6285 case 0x247: // mffs
6286 case 0x2C7: // mtfsf
6287 if (dis_fp_scr( theInstr )) goto decode_success;
6288 goto decode_failure;
6289 default:
6290 goto decode_failure;
6291 }
cerion3d870a32005-03-18 12:23:33 +00006292 break;
cerion91ad5362005-01-27 23:02:41 +00006293
6294 case 0x13:
cerionb85e8bb2005-02-16 08:54:33 +00006295 switch (opc2) {
cerion91ad5362005-01-27 23:02:41 +00006296
sewardjb51f0f42005-07-18 11:38:02 +00006297 /* Condition Register Logical Instructions */
6298 case 0x101: case 0x081: case 0x121: // crand, crandc, creqv
6299 case 0x0E1: case 0x021: case 0x1C1: // crnand, crnor, cror
6300 case 0x1A1: case 0x0C1: case 0x000: // crorc, crxor, mcrf
6301 if (dis_cond_logic( theInstr )) goto decode_success;
6302 goto decode_failure;
cerion26d07b22005-02-02 17:13:28 +00006303
sewardjb51f0f42005-07-18 11:38:02 +00006304 /* Branch Instructions */
6305 case 0x210: case 0x010: // bcctr, bclr
6306 if (dis_branch(theInstr, &dres)) goto decode_success;
6307 goto decode_failure;
cerion91ad5362005-01-27 23:02:41 +00006308
sewardjb51f0f42005-07-18 11:38:02 +00006309 /* Memory Synchronization Instructions */
6310 case 0x096: // isync
6311 if (dis_memsync( theInstr )) goto decode_success;
6312 goto decode_failure;
cerionb85e8bb2005-02-16 08:54:33 +00006313
sewardjb51f0f42005-07-18 11:38:02 +00006314 default:
6315 goto decode_failure;
cerionb85e8bb2005-02-16 08:54:33 +00006316 }
6317 break;
cerion91ad5362005-01-27 23:02:41 +00006318
6319
cerionb85e8bb2005-02-16 08:54:33 +00006320 case 0x1F:
cerione9d361a2005-03-04 17:35:29 +00006321
6322 /* For arith instns, bit10 is the OE flag (overflow enable) */
6323
cerionb85e8bb2005-02-16 08:54:33 +00006324 opc2 = (theInstr >> 1) & 0x1FF; /* theInstr[1:9] */
6325 switch (opc2) {
sewardjb51f0f42005-07-18 11:38:02 +00006326 /* Integer Arithmetic Instructions */
6327 case 0x10A: case 0x00A: case 0x08A: // add, addc, adde
6328 case 0x0EA: case 0x0CA: case 0x1EB: // addme, addze, divw
6329 case 0x1CB: case 0x04B: case 0x00B: // divwu, mulhw, mulhwu
6330 case 0x0EB: case 0x068: case 0x028: // mullw, neg, subf
6331 case 0x008: case 0x088: case 0x0E8: // subfc, subfe, subfme
6332 case 0x0C8: // subfze
6333 if (dis_int_arith( theInstr )) goto decode_success;
6334 goto decode_failure;
6335 default:
6336 break; // Fall through...
cerionb85e8bb2005-02-16 08:54:33 +00006337 }
cerion91ad5362005-01-27 23:02:41 +00006338
cerione9d361a2005-03-04 17:35:29 +00006339 /* All remaining opcodes use full 10 bits. */
6340
cerionb85e8bb2005-02-16 08:54:33 +00006341 opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
6342 switch (opc2) {
cerione9d361a2005-03-04 17:35:29 +00006343 /* Integer Compare Instructions */
6344 case 0x000: case 0x020: // cmp, cmpl
6345 if (dis_int_cmp( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006346 goto decode_failure;
cerion7aa4bbc2005-01-29 09:32:07 +00006347
cerione9d361a2005-03-04 17:35:29 +00006348 /* Integer Logical Instructions */
6349 case 0x01C: case 0x03C: case 0x01A: // and, andc, cntlzw
6350 case 0x11C: case 0x3BA: case 0x39A: // eqv, extsb, extsh
6351 case 0x1DC: case 0x07C: case 0x1BC: // nand, nor, or
6352 case 0x19C: case 0x13C: // orc, xor
6353 if (dis_int_logic( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006354 goto decode_failure;
cerion932ad942005-01-30 10:18:50 +00006355
cerione9d361a2005-03-04 17:35:29 +00006356 /* Integer Shift Instructions */
6357 case 0x018: case 0x318: case 0x338: // slw, sraw, srawi
6358 case 0x218: // srw
6359 if (dis_int_shift( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006360 goto decode_failure;
cerion7aa4bbc2005-01-29 09:32:07 +00006361
cerione9d361a2005-03-04 17:35:29 +00006362 /* Integer Load Instructions */
6363 case 0x057: case 0x077: case 0x157: // lbzx, lbzux, lhax
6364 case 0x177: case 0x117: case 0x137: // lhaux, lhzx, lhzux
6365 case 0x017: case 0x037: // lwzx, lwzux
6366 if (dis_int_load( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006367 goto decode_failure;
cerion7aa4bbc2005-01-29 09:32:07 +00006368
sewardjb51f0f42005-07-18 11:38:02 +00006369 /* Integer Store Instructions */
cerione9d361a2005-03-04 17:35:29 +00006370 case 0x0F7: case 0x0D7: case 0x1B7: // stbux, stbx, sthux
6371 case 0x197: case 0x0B7: case 0x097: // sthx, stwux, stwx
6372 if (dis_int_store( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006373 goto decode_failure;
cerion91ad5362005-01-27 23:02:41 +00006374
sewardjb51f0f42005-07-18 11:38:02 +00006375//zz /* Integer Load and Store with Byte Reverse Instructions */
6376//zz case 0x316: case 0x216: case 0x396: // lhbrx, lwbrx, sthbrx
6377//zz case 0x296: // stwbrx
6378//zz if (dis_int_ldst_rev( theInstr )) goto decode_success;
6379//zz goto decode_failure;
6380//zz
6381//zz /* Integer Load and Store String Instructions */
6382//zz case 0x255: case 0x215: case 0x2D5: // lswi, lswx, stswi
6383//zz case 0x295: // stswx
6384//zz if (dis_int_ldst_str( theInstr )) goto decode_success;
6385//zz goto decode_failure;
cerion645c9302005-01-31 10:09:59 +00006386
cerione9d361a2005-03-04 17:35:29 +00006387 /* Memory Synchronization Instructions */
6388 case 0x356: case 0x014: case 0x096: // eieio, lwarx, stwcx.
6389 case 0x256: // sync
6390 if (dis_memsync( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006391 goto decode_failure;
6392
cerione9d361a2005-03-04 17:35:29 +00006393 /* Processor Control Instructions */
6394 case 0x200: case 0x013: case 0x153: // mcrxr, mfcr, mfspr
6395 case 0x173: case 0x090: case 0x1D3: // mftb, mtcrf, mtspr
6396 if (dis_proc_ctl( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006397 goto decode_failure;
cerion645c9302005-01-31 10:09:59 +00006398
cerione9d361a2005-03-04 17:35:29 +00006399 /* Cache Management Instructions */
6400 case 0x2F6: case 0x056: case 0x036: // dcba, dcbf, dcbst
6401 case 0x116: case 0x0F6: case 0x3F6: // dcbt, dcbtst, dcbz
6402 case 0x3D6: // icbi
sewardj9e6491a2005-07-02 19:24:10 +00006403 if (dis_cache_manage( theInstr, &dres, archinfo ))
sewardjd94b73a2005-06-30 12:08:48 +00006404 goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006405 goto decode_failure;
ceriond23be4e2005-01-31 07:23:07 +00006406
sewardjb51f0f42005-07-18 11:38:02 +00006407//zz /* External Control Instructions */
6408//zz case 0x136: case 0x1B6: // eciwx, ecowx
6409//zz DIP("external control op => not implemented\n");
6410//zz goto decode_failure;
6411//zz
6412//zz /* Trap Instructions */
6413//zz case 0x004: // tw
6414//zz DIP("trap op (tw) => not implemented\n");
6415//zz goto decode_failure;
sewardje14bb9f2005-07-22 09:39:02 +00006416
6417 /* Floating Point Load Instructions */
6418 case 0x217: case 0x237: case 0x257: // lfsx, lfsux, lfdx
6419 case 0x277: // lfdux
6420 if (dis_fp_load( theInstr )) goto decode_success;
6421 goto decode_failure;
6422
6423 /* Floating Point Store Instructions */
6424 case 0x297: case 0x2B7: case 0x2D7: // stfs, stfsu, stfd
6425 case 0x2F7: case 0x3D7: // stfdu, stfiwx
6426 if (dis_fp_store( theInstr )) goto decode_success;
6427 goto decode_failure;
6428
6429
sewardjb51f0f42005-07-18 11:38:02 +00006430//zz /* AltiVec instructions */
6431//zz
6432//zz /* AV Cache Control - Data streams */
6433//zz case 0x156: case 0x176: case 0x336: // dst, dstst, dss
6434//zz if (dis_av_datastream( theInstr )) goto decode_success;
6435//zz goto decode_failure;
ceriona982c052005-06-28 17:23:09 +00006436
6437 /* AV Load */
6438 case 0x006: case 0x026: // lvsl, lvsr
6439 case 0x007: case 0x027: case 0x047: // lvebx, lvehx, lvewx
6440 case 0x067: case 0x167: // lvx, lvxl
6441 if (dis_av_load( theInstr )) goto decode_success;
6442 goto decode_failure;
6443
6444 /* AV Store */
6445 case 0x087: case 0x0A7: case 0x0C7: // stvebx, stvehx, stvewx
6446 case 0x0E7: case 0x1E7: // stvx, stvxl
6447 if (dis_av_store( theInstr )) goto decode_success;
6448 goto decode_failure;
6449
6450 default:
6451 goto decode_failure;
6452 }
6453 break;
6454
6455
sewardjb51f0f42005-07-18 11:38:02 +00006456//zz case 0x04:
6457//zz /* AltiVec instructions */
6458//zz
6459//zz opc2 = (theInstr) & 0x3F; /* theInstr[0:5] */
6460//zz switch (opc2) {
6461//zz /* AV Mult-Add, Mult-Sum */
6462//zz case 0x20: case 0x21: case 0x22: // vmhaddshs, vmhraddshs, vmladduhm
6463//zz case 0x24: case 0x25: case 0x26: // vmsumubm, vmsummbm, vmsumuhm
6464//zz case 0x27: case 0x28: case 0x29: // vmsumuhs, vmsumshm, vmsumshs
6465//zz if (dis_av_multarith( theInstr )) goto decode_success;
6466//zz goto decode_failure;
6467//zz
6468//zz /* AV Permutations */
6469//zz case 0x2A: // vsel
6470//zz case 0x2B: // vperm
6471//zz if (dis_av_permute( theInstr )) goto decode_success;
6472//zz goto decode_failure;
6473//zz
6474//zz /* AV Shift */
6475//zz case 0x2C: // vsldoi
6476//zz if (dis_av_shift( theInstr )) goto decode_success;
6477//zz goto decode_failure;
6478//zz
6479//zz /* AV Floating Point Mult-Add/Sub */
6480//zz case 0x2E: case 0x2F: // vmaddfp, vnmsubfp
6481//zz if (dis_av_fp_arith( theInstr )) goto decode_success;
6482//zz goto decode_failure;
6483//zz
6484//zz default:
6485//zz break; // Fall through...
6486//zz }
6487//zz
6488//zz opc2 = (theInstr) & 0x7FF; /* theInstr[0:10] */
6489//zz switch (opc2) {
6490//zz /* AV Arithmetic */
6491//zz case 0x180: // vaddcuw
6492//zz case 0x000: case 0x040: case 0x080: // vaddubm, vadduhm, vadduwm
6493//zz case 0x200: case 0x240: case 0x280: // vaddubs, vadduhs, vadduws
6494//zz case 0x300: case 0x340: case 0x380: // vaddsbs, vaddshs, vaddsws
6495//zz case 0x580: // vsubcuw
6496//zz case 0x400: case 0x440: case 0x480: // vsububm, vsubuhm, vsubuwm
6497//zz case 0x600: case 0x640: case 0x680: // vsububs, vsubuhs, vsubuws
6498//zz case 0x700: case 0x740: case 0x780: // vsubsbs, vsubshs, vsubsws
6499//zz case 0x402: case 0x442: case 0x482: // vavgub, vavguh, vavguw
6500//zz case 0x502: case 0x542: case 0x582: // vavgsb, vavgsh, vavgsw
6501//zz case 0x002: case 0x042: case 0x082: // vmaxub, vmaxuh, vmaxuw
6502//zz case 0x102: case 0x142: case 0x182: // vmaxsb, vmaxsh, vmaxsw
6503//zz case 0x202: case 0x242: case 0x282: // vminub, vminuh, vminuw
6504//zz case 0x302: case 0x342: case 0x382: // vminsb, vminsh, vminsw
6505//zz case 0x008: case 0x048: // vmuloub, vmulouh
6506//zz case 0x108: case 0x148: // vmulosb, vmulosh
6507//zz case 0x208: case 0x248: // vmuleub, vmuleuh
6508//zz case 0x308: case 0x348: // vmulesb, vmulesh
6509//zz case 0x608: case 0x708: case 0x648: // vsum4ubs, vsum4sbs, vsum4shs
6510//zz case 0x688: case 0x788: // vsum2sws, vsumsws
6511//zz if (dis_av_arith( theInstr )) goto decode_success;
6512//zz goto decode_failure;
6513//zz
6514//zz /* AV Rotate, Shift */
6515//zz case 0x004: case 0x044: case 0x084: // vrlb, vrlh, vrlw
6516//zz case 0x104: case 0x144: case 0x184: // vslb, vslh, vslw
6517//zz case 0x204: case 0x244: case 0x284: // vsrb, vsrh, vsrw
6518//zz case 0x304: case 0x344: case 0x384: // vsrab, vsrah, vsraw
6519//zz case 0x1C4: case 0x2C4: // vsl, vsr
6520//zz case 0x40C: case 0x44C: // vslo, vsro
6521//zz if (dis_av_shift( theInstr )) goto decode_success;
6522//zz goto decode_failure;
6523//zz
6524//zz /* AV Logic */
6525//zz case 0x404: case 0x444: case 0x484: // vand, vandc, vor
6526//zz case 0x4C4: case 0x504: // vxor, vnor
6527//zz if (dis_av_logic( theInstr )) goto decode_success;
6528//zz goto decode_failure;
6529//zz
6530//zz /* AV Processor Control */
6531//zz case 0x604: case 0x644: // mfvscr, mtvscr
6532//zz if (dis_av_procctl( theInstr )) goto decode_success;
6533//zz goto decode_failure;
6534//zz
6535//zz /* AV Floating Point Arithmetic */
6536//zz case 0x00A: case 0x04A: // vaddfp, vsubfp
6537//zz case 0x10A: case 0x14A: case 0x18A: // vrefp, vrsqrtefp, vexptefp
6538//zz case 0x1CA: // vlogefp
6539//zz case 0x40A: case 0x44A: // vmaxfp, vminfp
6540//zz if (dis_av_fp_arith( theInstr )) goto decode_success;
6541//zz goto decode_failure;
6542//zz
6543//zz /* AV Floating Point Round/Convert */
6544//zz case 0x20A: case 0x24A: case 0x28A: // vrfin, vrfiz, vrfip
6545//zz case 0x2CA: // vrfim
6546//zz case 0x30A: case 0x34A: case 0x38A: // vcfux, vcfsx, vctuxs
6547//zz case 0x3CA: // vctsxs
6548//zz if (dis_av_fp_convert( theInstr )) goto decode_success;
6549//zz goto decode_failure;
6550//zz
6551//zz /* AV Merge, Splat */
6552//zz case 0x00C: case 0x04C: case 0x08C: // vmrghb, vmrghh, vmrghw
6553//zz case 0x10C: case 0x14C: case 0x18C: // vmrglb, vmrglh, vmrglw
6554//zz case 0x20C: case 0x24C: case 0x28C: // vspltb, vsplth, vspltw
6555//zz case 0x30C: case 0x34C: case 0x38C: // vspltisb, vspltish, vspltisw
6556//zz if (dis_av_permute( theInstr )) goto decode_success;
6557//zz goto decode_failure;
6558//zz
6559//zz /* AV Pack, Unpack */
6560//zz case 0x00E: case 0x04E: case 0x08E: // vpkuhum, vpkuwum, vpkuhus
6561//zz case 0x0CE: // vpkuwus
6562//zz case 0x10E: case 0x14E: case 0x18E: // vpkshus, vpkswus, vpkshss
6563//zz case 0x1CE: // vpkswss
6564//zz case 0x20E: case 0x24E: case 0x28E: // vupkhsb, vupkhsh, vupklsb
6565//zz case 0x2CE: // vupklsh
6566//zz case 0x30E: case 0x34E: case 0x3CE: // vpkpx, vupkhpx, vupklpx
6567//zz if (dis_av_pack( theInstr )) goto decode_success;
6568//zz goto decode_failure;
6569//zz
6570//zz default:
6571//zz break; // Fall through...
6572//zz }
6573//zz
6574//zz opc2 = (theInstr) & 0x3FF; /* theInstr[0:9] (Bit 10 = Rc)*/
6575//zz switch (opc2) {
6576//zz
6577//zz /* AV Compare */
6578//zz case 0x006: case 0x046: case 0x086: // vcmpequb, vcmpequh, vcmpequw
6579//zz case 0x206: case 0x246: case 0x286: // vcmpgtub, vcmpgtuh, vcmpgtuw
6580//zz case 0x306: case 0x346: case 0x386: // vcmpgtsb, vcmpgtsh, vcmpgtsw
6581//zz if (dis_av_cmp( theInstr )) goto decode_success;
6582//zz goto decode_failure;
6583//zz
6584//zz /* AV Floating Point Compare */
6585//zz case 0x0C6: case 0x1C6: case 0x2C6: // vcmpeqfp, vcmpgefp, vcmpgtfp
6586//zz case 0x3C6: // vcmpbfp
6587//zz if (dis_av_fp_cmp( theInstr )) goto decode_success;
6588//zz goto decode_failure;
6589//zz
6590//zz default:
6591//zz goto decode_failure;
6592//zz }
6593//zz break;
cerion7aa4bbc2005-01-29 09:32:07 +00006594
cerion896a1372005-01-25 12:24:25 +00006595 default:
6596 decode_failure:
6597 /* All decode failures end up here. */
cerion1515db92005-01-25 17:21:23 +00006598 vex_printf("disInstr(ppc32): unhandled instruction: "
cerion896a1372005-01-25 12:24:25 +00006599 "0x%x\n", theInstr);
sewardjb51f0f42005-07-18 11:38:02 +00006600 vex_printf(" primary %d(0x%x), secondary %d(0x%x)\n",
6601 opc1, opc1, opc2, opc2);
cerionb85e8bb2005-02-16 08:54:33 +00006602
cerione9d361a2005-03-04 17:35:29 +00006603#if PPC32_TOIR_DEBUG
cerion995bc362005-02-03 11:03:31 +00006604 vex_printf("disInstr(ppc32): instr: ");
6605 vex_printf_binary( theInstr, 32, True );
6606 vex_printf("\n");
6607
6608 vex_printf("disInstr(ppc32): opcode1: ");
6609 vex_printf_binary( opc1, 6, False );
6610 vex_printf("\n");
6611
6612 vex_printf("disInstr(ppc32): opcode2: ");
6613 vex_printf_binary( opc2, 10, False );
cerion45552a92005-02-03 18:20:22 +00006614 vex_printf("\n\n");
6615#endif
cerion995bc362005-02-03 11:03:31 +00006616
6617
sewardj01a9e802005-02-01 20:46:00 +00006618 /* Tell the dispatcher that this insn cannot be decoded, and so has
6619 not been executed, and (is currently) the next to be executed.
6620 CIA should be up-to-date since it made so at the start of each
6621 insn, but nevertheless be paranoid and update it again right
6622 now. */
sewardjb51f0f42005-07-18 11:38:02 +00006623 putSPR( PPC32_SPR_CIA, mkU32(guest_CIA_curr_instr) );
sewardj9e6491a2005-07-02 19:24:10 +00006624 irbb->next = mkU32(guest_CIA_curr_instr);
sewardj01a9e802005-02-01 20:46:00 +00006625 irbb->jumpkind = Ijk_NoDecode;
sewardj9e6491a2005-07-02 19:24:10 +00006626 dres.whatNext = Dis_StopHere;
6627 dres.len = 0;
sewardjb51f0f42005-07-18 11:38:02 +00006628vassert(0);
sewardj9e6491a2005-07-02 19:24:10 +00006629 return dres;
cerion896a1372005-01-25 12:24:25 +00006630
6631 } /* switch (opc) for the main (primary) opcode switch. */
6632
6633 decode_success:
6634 /* All decode successes end up here. */
cerion896a1372005-01-25 12:24:25 +00006635 DIP("\n");
6636
sewardj9e6491a2005-07-02 19:24:10 +00006637 dres.len = 4;
6638 return dres;
cerion896a1372005-01-25 12:24:25 +00006639}
6640
6641#undef DIP
6642#undef DIS
6643
sewardj9e6491a2005-07-02 19:24:10 +00006644
6645/*------------------------------------------------------------*/
6646/*--- Top-level fn ---*/
6647/*------------------------------------------------------------*/
6648
6649/* Disassemble a single instruction into IR. The instruction
6650 is located in host memory at &guest_code[delta]. */
6651
6652DisResult disInstr_PPC32 ( IRBB* irbb_IN,
6653 Bool put_IP,
6654 Bool (*resteerOkFn) ( Addr64 ),
6655 UChar* guest_code_IN,
6656 Long delta,
6657 Addr64 guest_IP,
6658 VexArchInfo* archinfo,
6659 Bool host_bigendian_IN )
6660{
6661 DisResult dres;
6662
6663 /* Set globals (see top of this file) */
6664 guest_code = guest_code_IN;
6665 irbb = irbb_IN;
6666 host_is_bigendian = host_bigendian_IN;
6667 guest_CIA_curr_instr = (Addr32)guest_IP;
6668 guest_CIA_bbstart = (Addr32)toUInt(guest_IP - delta);
6669
6670 dres = disInstr_PPC32_WRK ( put_IP, resteerOkFn,
6671 delta, archinfo );
6672
6673 return dres;
6674}
6675
6676
cerion896a1372005-01-25 12:24:25 +00006677/*--------------------------------------------------------------------*/
cerion1515db92005-01-25 17:21:23 +00006678/*--- end guest-ppc32/toIR.c ---*/
cerion896a1372005-01-25 12:24:25 +00006679/*--------------------------------------------------------------------*/