blob: f9df56696a2cb6f5a12ccaa6d4a9496b4779076e [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
38 make srawi etc use Sar32
39
40 inline ppc32g_calculate_xer_ca; calling it out of line is a net
41 performance loss and obscures from memcheck what's really happening
42*/
43
44
cerion1515db92005-01-25 17:21:23 +000045/* Translates PPC32 code to IR. */
cerion896a1372005-01-25 12:24:25 +000046
cerion645c9302005-01-31 10:09:59 +000047/* References
ceriona982c052005-06-28 17:23:09 +000048
49#define PPC32
cerion645c9302005-01-31 10:09:59 +000050 "PowerPC Microprocessor Family:
cerione9d361a2005-03-04 17:35:29 +000051 The Programming Environments for 32-Bit Microprocessors"
52 02/21/2000
53 http://www-3.ibm.com/chips/techlib/techlib.nsf/techdocs/852569B20050FF778525699600719DF2
54
ceriona982c052005-06-28 17:23:09 +000055#define AV
56 "PowerPC Microprocessor Family:
57 AltiVec(TM) Technology Programming Environments Manual"
58 07/10/2003
59 http://www-3.ibm.com/chips/techlib/techlib.nsf/techdocs/FBFA164F824370F987256D6A006F424D
60
cerione9d361a2005-03-04 17:35:29 +000061 Other refs:
62 "PowerPC Microprocessor Family:
cerion645c9302005-01-31 10:09:59 +000063 Programming Environments Manual for 64 and 32-Bit Microprocessors
64 Version 2.0"
cerion26d07b22005-02-02 17:13:28 +000065 06/10/2003
cerion645c9302005-01-31 10:09:59 +000066 http://www-3.ibm.com/chips/techlib/techlib.nsf/techdocs/F6153E213FDD912E87256D49006C6541
67*/
68
cerion896a1372005-01-25 12:24:25 +000069#include "libvex_basictypes.h"
70#include "libvex_ir.h"
71#include "libvex.h"
cerion1515db92005-01-25 17:21:23 +000072#include "libvex_guest_ppc32.h"
cerion896a1372005-01-25 12:24:25 +000073
74#include "main/vex_util.h"
75#include "main/vex_globals.h"
sewardj9e6491a2005-07-02 19:24:10 +000076#include "guest-generic/bb_to_IR.h"
cerion1515db92005-01-25 17:21:23 +000077#include "guest-ppc32/gdefs.h"
cerion896a1372005-01-25 12:24:25 +000078
79
80/*------------------------------------------------------------*/
81/*--- Globals ---*/
82/*------------------------------------------------------------*/
83
sewardj9e6491a2005-07-02 19:24:10 +000084/* These are set at the start of the translation of an insn, right
85 down in disInstr_PPC32, so that we don't have to pass them around
86 endlessly. They are all constant during the translation of any
87 given insn. */
cerion896a1372005-01-25 12:24:25 +000088
cerioned623db2005-06-20 12:42:04 +000089/* We need to know this to do sub-register accesses correctly. */
cerioned623db2005-06-20 12:42:04 +000090static Bool host_is_bigendian;
91
cerion896a1372005-01-25 12:24:25 +000092/* Pointer to the guest code area. */
cerion896a1372005-01-25 12:24:25 +000093static UChar* guest_code;
94
95/* The guest address corresponding to guest_code[0]. */
sewardj9e6491a2005-07-02 19:24:10 +000096static Addr32 guest_CIA_bbstart;
cerion896a1372005-01-25 12:24:25 +000097
sewardj01a9e802005-02-01 20:46:00 +000098/* The guest address for the instruction currently being
99 translated. */
sewardj9e6491a2005-07-02 19:24:10 +0000100static Addr32 guest_CIA_curr_instr;
sewardj01a9e802005-02-01 20:46:00 +0000101
cerion896a1372005-01-25 12:24:25 +0000102/* The IRBB* into which we're generating code. */
103static IRBB* irbb;
104
105
106/*------------------------------------------------------------*/
107/*--- Debugging output ---*/
108/*------------------------------------------------------------*/
109
cerione9d361a2005-03-04 17:35:29 +0000110#define PPC32_TOIR_DEBUG 0
111
cerion896a1372005-01-25 12:24:25 +0000112#define DIP(format, args...) \
113 if (vex_traceflags & VEX_TRACE_FE) \
114 vex_printf(format, ## args)
115
116#define DIS(buf, format, args...) \
117 if (vex_traceflags & VEX_TRACE_FE) \
118 vex_sprintf(buf, format, ## args)
119
120
cerion896a1372005-01-25 12:24:25 +0000121/*------------------------------------------------------------*/
cerion38674602005-02-08 02:19:25 +0000122/*--- Offsets of various parts of the ppc32 guest state. ---*/
cerion896a1372005-01-25 12:24:25 +0000123/*------------------------------------------------------------*/
124
cerion91ad5362005-01-27 23:02:41 +0000125#define OFFB_CIA offsetof(VexGuestPPC32State,guest_CIA)
126#define OFFB_LR offsetof(VexGuestPPC32State,guest_LR)
127#define OFFB_CTR offsetof(VexGuestPPC32State,guest_CTR)
128
sewardjb51f0f42005-07-18 11:38:02 +0000129#define OFFB_XER_SO offsetof(VexGuestPPC32State,guest_XER_SO)
sewardj20ef5472005-07-21 14:48:31 +0000130#define OFFB_XER_OV offsetof(VexGuestPPC32State,guest_XER_OV)
sewardjb51f0f42005-07-18 11:38:02 +0000131#define OFFB_XER_CA offsetof(VexGuestPPC32State,guest_XER_CA)
sewardj20ef5472005-07-21 14:48:31 +0000132#define OFFB_XER_BC offsetof(VexGuestPPC32State,guest_XER_BC)
cerion91ad5362005-01-27 23:02:41 +0000133
cerion094d1392005-06-20 13:45:57 +0000134#define OFFB_FPROUND offsetof(VexGuestPPC32State,guest_FPROUND)
135
ceriona982c052005-06-28 17:23:09 +0000136#define OFFB_VRSAVE offsetof(VexGuestPPC32State,guest_VRSAVE)
137#define OFFB_VSCR offsetof(VexGuestPPC32State,guest_VSCR)
138
cerion094d1392005-06-20 13:45:57 +0000139#define OFFB_EMWARN offsetof(VexGuestPPC32State,guest_EMWARN)
140
sewardj7ce9d152005-03-15 16:54:13 +0000141#define OFFB_TISTART offsetof(VexGuestPPC32State,guest_TISTART)
142#define OFFB_TILEN offsetof(VexGuestPPC32State,guest_TILEN)
cerion91ad5362005-01-27 23:02:41 +0000143
144
cerion38674602005-02-08 02:19:25 +0000145/*------------------------------------------------------------*/
sewardjb51f0f42005-07-18 11:38:02 +0000146/*--- Extract instruction fields --- */
cerion38674602005-02-08 02:19:25 +0000147/*------------------------------------------------------------*/
cerione9d361a2005-03-04 17:35:29 +0000148
sewardjb51f0f42005-07-18 11:38:02 +0000149/* Extract primary opcode, instr[31:26] */
150static UInt ifieldOPC ( UInt instr ) {
151 return (instr >> 26) & 0x3F;
152}
cerione9d361a2005-03-04 17:35:29 +0000153
sewardjb51f0f42005-07-18 11:38:02 +0000154/* Extract 10-bit secondary opcode, instr[11:1] */
155static UInt ifieldOPClo10 ( UInt instr) {
156 return (instr >> 1 ) & 0x3FF;
157}
cerione9d361a2005-03-04 17:35:29 +0000158
sewardjb51f0f42005-07-18 11:38:02 +0000159/* Extract RD (destination register) field, instr[25:21] */
160static UInt ifieldRD ( UInt instr ) {
161 return (instr >> 21) & 0x1F;
162}
cerion094d1392005-06-20 13:45:57 +0000163
sewardjb51f0f42005-07-18 11:38:02 +0000164/* Extract RA (first source register) field, instr[20:16] */
165static UInt ifieldRA ( UInt instr ) {
166 return (instr >> 16) & 0x1F;
167}
168
169/* Extract RB (first source register) field, instr[15:11] */
170static UInt ifieldRB ( UInt instr ) {
171 return (instr >> 11) & 0x1F;
172}
173
174/* Extract bottom bit (Rc?) from instr */
175static UInt ifieldBIT0 ( UInt instr ) {
176 return instr & 1;
177}
178
179/* Extract lower half of instruction and sign extent to 32 bits */
180static Int ifieldSIMM16 ( UInt instr ) {
181 Int i = instr & 0xFFFF;
182 return (i << 16) >> 16;
183}
184
185
186//zz /*------------------------------------------------------------*/
187//zz /*--- Abstract register interface (non-gpr|fpr) --- */
188//zz /*------------------------------------------------------------*/
189//zz
190//zz /* Offsets of bitfields within various ppc32 registers */
191//zz #define SHIFT_XER_SO 31
192//zz #define SHIFT_XER_OV 30
193//zz #define SHIFT_XER_CA 29
194//zz #define SHIFT_XER_BC 0
195//zz
196//zz #define SHIFT_CR_LT 8
197//zz #define SHIFT_CR_GT 4
198//zz #define SHIFT_CR_EQ 2
199//zz #define SHIFT_CR_SO 1
200//zz
201//zz #define SHIFT_FPSCR_RN 0
202//zz #define MASK_FPSCR_RN (3 << SHIFT_FPSCR_RN)
203//zz
204//zz #define SHIFT_VSCR_NJ 16
205//zz #define SHIFT_VSCR_SAT 0
ceriona982c052005-06-28 17:23:09 +0000206
cerion094d1392005-06-20 13:45:57 +0000207
cerione9d361a2005-03-04 17:35:29 +0000208// Special purpose (i.e. non-gpr/fpr) registers
209typedef enum {
210 PPC32_SPR_CIA, // Current Instruction Address
211 PPC32_SPR_LR, // Link Register
212 PPC32_SPR_CTR, // Count Register
sewardjb51f0f42005-07-18 11:38:02 +0000213//zz PPC32_SPR_XER, // Summary Overflow
214//zz PPC32_SPR_CR, // Condition Register
215//zz PPC32_SPR_FPSCR, // Floating Point Status/Control Register
ceriona982c052005-06-28 17:23:09 +0000216 PPC32_SPR_VRSAVE, // Vector Save/Restore Register
sewardjb51f0f42005-07-18 11:38:02 +0000217//zz PPC32_SPR_VSCR, // Vector Status and Control Register
218//zz PPC32_SPR_MAX
cerione9d361a2005-03-04 17:35:29 +0000219} PPC32SPR;
220
sewardjb51f0f42005-07-18 11:38:02 +0000221//zz /*
222//zz Note on FPSCR: Floating Point Status and Control Register
223//zz
224//zz We're only keeping hold of fp rounding-mode bits, via guest_FPROUND
225//zz The rest of the FPSCR is set to 0x0, which corresponds to
226//zz 'all exceptions masked'
227//zz
228//zz FPSCR[29:31] => Exception Summaries
229//zz FPSCR[17:28] => Exceptions
230//zz FPSCR[16] => FPRF::Class Descriptor
231//zz FPSCR[12:15] => FPRF::Condition Code
232//zz FPSCR[11] => Unused (0)
233//zz FPSCR[8:10] => Exceptions
234//zz FPSCR[3:7] => Exception Control
235//zz FPSCR[2] => Non-IEEE mode
236//zz FPSCR[0:1] => Rounding Mode
237//zz
238//zz CAB: Perhaps necessary to record writes to FPRF ?
239//zz Set by dis_fp_cmp() instrs, also some fp arith/round/conv instrs.
240//zz Tested using dis_fp_scr(): e.g fpscr->cr, branch conditional...
241//zz */
242//zz
243//zz
244//zz /* Gets from SPR (non-GPR|FPR) registers */
245//zz static IRExpr* getReg_masked ( PPC32SPR reg, UInt mask );
246static IRExpr* getSPR ( PPC32SPR reg );
247//zz static IRExpr* getReg_field ( PPC32SPR reg, UInt field_idx );
248//zz static IRExpr* getReg_bit ( PPC32SPR reg, UInt bit_idx );
249//zz
250//zz /* Puts to SPR (non-GPR|FPR) registers */
251//zz static void putReg_masked ( PPC32SPR reg, IRExpr* src, UInt mask );
252static void putSPR ( PPC32SPR reg, IRExpr* src );
253//zz static void putReg_field ( PPC32SPR reg, IRExpr* src, UInt field_idx );
254//zz static void putReg_bit ( PPC32SPR reg, IRExpr* src, UInt bit_idx );
255//zz
256//zz /* FP Helpers */
257//zz static void put_emwarn ( IRExpr* e /* :: Ity_I32 */ );
cerion094d1392005-06-20 13:45:57 +0000258
cerion38674602005-02-08 02:19:25 +0000259
260
261
262/*------------------------------------------------------------*/
263/*--- Misc Helpers ---*/
264/*------------------------------------------------------------*/
265
266static UInt MASK( UInt begin, UInt end )
267{
cerionb85e8bb2005-02-16 08:54:33 +0000268 UInt m1 = ((UInt)(-1)) << begin;
269 UInt m2 = ((UInt)(-1)) << (end + 1);
270 UInt mask = m1 ^ m2;
271 if (begin > end) mask = ~mask; // wrap mask
272 return mask;
cerion38674602005-02-08 02:19:25 +0000273}
274
sewardjb51f0f42005-07-18 11:38:02 +0000275//zz #if PPC32_TOIR_DEBUG
276//zz static void vex_printf_binary( UInt x, UInt len, Bool spaces )
277//zz {
278//zz UInt i;
279//zz vassert(len > 0 && len <= 32);
280//zz
281//zz for (i=len; i>0; i--) {
282//zz vex_printf("%d", ((x & (1<<(len-1))) != 0) );
283//zz x = x << 1;
284//zz if (((i-1)%4)==0 && (i > 1) && spaces) {
285//zz vex_printf(" ");
286//zz }
287//zz }
288//zz }
289//zz #endif
cerion38674602005-02-08 02:19:25 +0000290
cerion896a1372005-01-25 12:24:25 +0000291
cerion896a1372005-01-25 12:24:25 +0000292/*------------------------------------------------------------*/
293/*--- Helper bits and pieces for deconstructing the ---*/
sewardj684aa952005-01-30 12:52:14 +0000294/*--- ppc32 insn stream. ---*/
cerion896a1372005-01-25 12:24:25 +0000295/*------------------------------------------------------------*/
296
297/* Add a statement to the list held by "irbb". */
298static void stmt ( IRStmt* st )
299{
300 addStmtToIRBB( irbb, st );
301}
302
cerion896a1372005-01-25 12:24:25 +0000303/* Generate a new temporary of the given type. */
304static IRTemp newTemp ( IRType ty )
305{
sewardj496a58d2005-03-20 18:44:44 +0000306 vassert(isPlausibleIRType(ty));
cerion896a1372005-01-25 12:24:25 +0000307 return newIRTemp( irbb->tyenv, ty );
308}
cerion896a1372005-01-25 12:24:25 +0000309
sewardjb51f0f42005-07-18 11:38:02 +0000310//zz /* Various simple conversions */
311//zz
312//zz static UChar extend_s_5to8 ( UChar x )
313//zz {
314//zz return toUChar((((Int)x) << 27) >> 27);
315//zz }
316//zz
317//zz #if 0
318//zz static UInt extend_s_8to32( UInt x )
319//zz {
320//zz return (UInt)((((Int)x) << 24) >> 24);
321//zz }
322//zz #endif
cerion91ad5362005-01-27 23:02:41 +0000323
cerion896a1372005-01-25 12:24:25 +0000324static UInt extend_s_16to32 ( UInt x )
325{
326 return (UInt)((((Int)x) << 16) >> 16);
327}
cerion896a1372005-01-25 12:24:25 +0000328
cerion6b30d852005-06-24 11:25:46 +0000329static UInt extend_s_26to32 ( UInt x )
cerion896a1372005-01-25 12:24:25 +0000330{
cerion6b30d852005-06-24 11:25:46 +0000331 return (UInt)((((Int)x) << 6) >> 6);
cerion896a1372005-01-25 12:24:25 +0000332}
cerion896a1372005-01-25 12:24:25 +0000333
sewardj684aa952005-01-30 12:52:14 +0000334/* Do a big-endian load of a 32-bit word, regardless of the endianness
335 of the underlying host. */
cerioncf004462005-01-31 15:24:55 +0000336static UInt getUIntBigendianly ( UChar* p )
sewardj684aa952005-01-30 12:52:14 +0000337{
cerioncf004462005-01-31 15:24:55 +0000338 UInt w = 0;
sewardj684aa952005-01-30 12:52:14 +0000339 w = (w << 8) | p[0];
340 w = (w << 8) | p[1];
341 w = (w << 8) | p[2];
342 w = (w << 8) | p[3];
343 return w;
344}
345
cerion896a1372005-01-25 12:24:25 +0000346
347/*------------------------------------------------------------*/
348/*--- Helpers for constructing IR. ---*/
349/*------------------------------------------------------------*/
350
cerion896a1372005-01-25 12:24:25 +0000351static void assign ( IRTemp dst, IRExpr* e )
352{
353 stmt( IRStmt_Tmp(dst, e) );
354}
355
cerionae694622005-01-28 17:52:47 +0000356static void storeBE ( IRExpr* addr, IRExpr* data )
cerion896a1372005-01-25 12:24:25 +0000357{
sewardjaf1ceca2005-06-30 23:31:27 +0000358 stmt( IRStmt_Store(Iend_BE,addr,data) );
cerion896a1372005-01-25 12:24:25 +0000359}
360
361static IRExpr* unop ( IROp op, IRExpr* a )
362{
363 return IRExpr_Unop(op, a);
364}
365
366static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
367{
368 return IRExpr_Binop(op, a1, a2);
369}
370
371static IRExpr* mkexpr ( IRTemp tmp )
372{
373 return IRExpr_Tmp(tmp);
374}
375
cerion45552a92005-02-03 18:20:22 +0000376static IRExpr* mkU1 ( UInt i )
377{
378 vassert(i < 2);
sewardj684c0372005-02-07 02:33:58 +0000379 return IRExpr_Const(IRConst_U1( toBool(i) ));
cerion45552a92005-02-03 18:20:22 +0000380}
381
sewardj684c0372005-02-07 02:33:58 +0000382static IRExpr* mkU8 ( UChar i )
cerion896a1372005-01-25 12:24:25 +0000383{
cerion896a1372005-01-25 12:24:25 +0000384 return IRExpr_Const(IRConst_U8(i));
385}
cerion896a1372005-01-25 12:24:25 +0000386
cerion896a1372005-01-25 12:24:25 +0000387static IRExpr* mkU32 ( UInt i )
388{
389 return IRExpr_Const(IRConst_U32(i));
390}
391
cerionae694622005-01-28 17:52:47 +0000392static IRExpr* loadBE ( IRType ty, IRExpr* data )
cerion896a1372005-01-25 12:24:25 +0000393{
sewardjaf1ceca2005-06-30 23:31:27 +0000394 return IRExpr_Load(Iend_BE,ty,data);
cerion896a1372005-01-25 12:24:25 +0000395}
cerion896a1372005-01-25 12:24:25 +0000396
sewardj20ef5472005-07-21 14:48:31 +0000397static IRExpr* mkOR1 ( IRExpr* arg1, IRExpr* arg2 )
398{
399 vassert(typeOfIRExpr(irbb->tyenv, arg1) == Ity_I1);
400 vassert(typeOfIRExpr(irbb->tyenv, arg2) == Ity_I1);
401 return
402 unop(Iop_32to1, binop(Iop_Or32, unop(Iop_1Uto32, arg1),
403 unop(Iop_1Uto32, arg2)));
404}
405
406static IRExpr* mkAND1 ( IRExpr* arg1, IRExpr* arg2 )
407{
408 vassert(typeOfIRExpr(irbb->tyenv, arg1) == Ity_I1);
409 vassert(typeOfIRExpr(irbb->tyenv, arg2) == Ity_I1);
410 return
411 unop(Iop_32to1, binop(Iop_And32, unop(Iop_1Uto32, arg1),
412 unop(Iop_1Uto32, arg2)));
413}
sewardjb51f0f42005-07-18 11:38:02 +0000414
415static Int integerGuestRegOffset ( UInt archreg )
cerion45b70ff2005-01-31 17:03:25 +0000416{
sewardjb51f0f42005-07-18 11:38:02 +0000417 vassert(archreg < 32);
418
419 // jrs: probably not necessary; only matters if we reference sub-parts
420 // of the ppc32 registers, but that isn't the case
421 // later: this might affect Altivec though?
422 vassert(host_is_bigendian);
423
424 switch (archreg) {
425 case 0: return offsetof(VexGuestPPC32State, guest_GPR0);
426 case 1: return offsetof(VexGuestPPC32State, guest_GPR1);
427 case 2: return offsetof(VexGuestPPC32State, guest_GPR2);
428 case 3: return offsetof(VexGuestPPC32State, guest_GPR3);
429 case 4: return offsetof(VexGuestPPC32State, guest_GPR4);
430 case 5: return offsetof(VexGuestPPC32State, guest_GPR5);
431 case 6: return offsetof(VexGuestPPC32State, guest_GPR6);
432 case 7: return offsetof(VexGuestPPC32State, guest_GPR7);
433 case 8: return offsetof(VexGuestPPC32State, guest_GPR8);
434 case 9: return offsetof(VexGuestPPC32State, guest_GPR9);
435 case 10: return offsetof(VexGuestPPC32State, guest_GPR10);
436 case 11: return offsetof(VexGuestPPC32State, guest_GPR11);
437 case 12: return offsetof(VexGuestPPC32State, guest_GPR12);
438 case 13: return offsetof(VexGuestPPC32State, guest_GPR13);
439 case 14: return offsetof(VexGuestPPC32State, guest_GPR14);
440 case 15: return offsetof(VexGuestPPC32State, guest_GPR15);
441 case 16: return offsetof(VexGuestPPC32State, guest_GPR16);
442 case 17: return offsetof(VexGuestPPC32State, guest_GPR17);
443 case 18: return offsetof(VexGuestPPC32State, guest_GPR18);
444 case 19: return offsetof(VexGuestPPC32State, guest_GPR19);
445 case 20: return offsetof(VexGuestPPC32State, guest_GPR20);
446 case 21: return offsetof(VexGuestPPC32State, guest_GPR21);
447 case 22: return offsetof(VexGuestPPC32State, guest_GPR22);
448 case 23: return offsetof(VexGuestPPC32State, guest_GPR23);
449 case 24: return offsetof(VexGuestPPC32State, guest_GPR24);
450 case 25: return offsetof(VexGuestPPC32State, guest_GPR25);
451 case 26: return offsetof(VexGuestPPC32State, guest_GPR26);
452 case 27: return offsetof(VexGuestPPC32State, guest_GPR27);
453 case 28: return offsetof(VexGuestPPC32State, guest_GPR28);
454 case 29: return offsetof(VexGuestPPC32State, guest_GPR29);
455 case 30: return offsetof(VexGuestPPC32State, guest_GPR30);
456 case 31: return offsetof(VexGuestPPC32State, guest_GPR31);
457 default: break;
458 }
459 vpanic("integerGuestRegOffset(ppc32,be)"); /*notreached*/
460}
461
462static IRExpr* getIReg ( UInt archreg )
463{
464 vassert(archreg < 32);
465 return IRExpr_Get( integerGuestRegOffset(archreg), Ity_I32 );
466}
467
468/* Ditto, but write to a reg instead. */
469static void putIReg ( UInt archreg, IRExpr* e )
470{
471 vassert(archreg < 32);
472 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I32);
473 stmt( IRStmt_Put(integerGuestRegOffset(archreg), e) );
474}
475
476
477static Int floatGuestRegOffset ( UInt archreg )
478{
479 vassert(archreg < 32);
480
481 switch (archreg) {
482 case 0: return offsetof(VexGuestPPC32State, guest_FPR0);
483 case 1: return offsetof(VexGuestPPC32State, guest_FPR1);
484 case 2: return offsetof(VexGuestPPC32State, guest_FPR2);
485 case 3: return offsetof(VexGuestPPC32State, guest_FPR3);
486 case 4: return offsetof(VexGuestPPC32State, guest_FPR4);
487 case 5: return offsetof(VexGuestPPC32State, guest_FPR5);
488 case 6: return offsetof(VexGuestPPC32State, guest_FPR6);
489 case 7: return offsetof(VexGuestPPC32State, guest_FPR7);
490 case 8: return offsetof(VexGuestPPC32State, guest_FPR8);
491 case 9: return offsetof(VexGuestPPC32State, guest_FPR9);
492 case 10: return offsetof(VexGuestPPC32State, guest_FPR10);
493 case 11: return offsetof(VexGuestPPC32State, guest_FPR11);
494 case 12: return offsetof(VexGuestPPC32State, guest_FPR12);
495 case 13: return offsetof(VexGuestPPC32State, guest_FPR13);
496 case 14: return offsetof(VexGuestPPC32State, guest_FPR14);
497 case 15: return offsetof(VexGuestPPC32State, guest_FPR15);
498 case 16: return offsetof(VexGuestPPC32State, guest_FPR16);
499 case 17: return offsetof(VexGuestPPC32State, guest_FPR17);
500 case 18: return offsetof(VexGuestPPC32State, guest_FPR18);
501 case 19: return offsetof(VexGuestPPC32State, guest_FPR19);
502 case 20: return offsetof(VexGuestPPC32State, guest_FPR20);
503 case 21: return offsetof(VexGuestPPC32State, guest_FPR21);
504 case 22: return offsetof(VexGuestPPC32State, guest_FPR22);
505 case 23: return offsetof(VexGuestPPC32State, guest_FPR23);
506 case 24: return offsetof(VexGuestPPC32State, guest_FPR24);
507 case 25: return offsetof(VexGuestPPC32State, guest_FPR25);
508 case 26: return offsetof(VexGuestPPC32State, guest_FPR26);
509 case 27: return offsetof(VexGuestPPC32State, guest_FPR27);
510 case 28: return offsetof(VexGuestPPC32State, guest_FPR28);
511 case 29: return offsetof(VexGuestPPC32State, guest_FPR29);
512 case 30: return offsetof(VexGuestPPC32State, guest_FPR30);
513 case 31: return offsetof(VexGuestPPC32State, guest_FPR31);
514 default: break;
515 }
516 vpanic("floatGuestRegOffset(ppc32)"); /*notreached*/
517}
518
519static IRExpr* getFReg ( UInt archreg )
520{
521 vassert(archreg < 32);
522 return IRExpr_Get( floatGuestRegOffset(archreg), Ity_F64 );
523}
524
525/* Ditto, but write to a reg instead. */
526static void putFReg ( UInt archreg, IRExpr* e )
527{
528 vassert(archreg < 32);
529 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_F64);
530 stmt( IRStmt_Put(floatGuestRegOffset(archreg), e) );
531}
532
533
534static Int vectorGuestRegOffset ( UInt archreg )
535{
536 vassert(archreg < 32);
537
538 switch (archreg) {
539 case 0: return offsetof(VexGuestPPC32State, guest_VR0);
540 case 1: return offsetof(VexGuestPPC32State, guest_VR1);
541 case 2: return offsetof(VexGuestPPC32State, guest_VR2);
542 case 3: return offsetof(VexGuestPPC32State, guest_VR3);
543 case 4: return offsetof(VexGuestPPC32State, guest_VR4);
544 case 5: return offsetof(VexGuestPPC32State, guest_VR5);
545 case 6: return offsetof(VexGuestPPC32State, guest_VR6);
546 case 7: return offsetof(VexGuestPPC32State, guest_VR7);
547 case 8: return offsetof(VexGuestPPC32State, guest_VR8);
548 case 9: return offsetof(VexGuestPPC32State, guest_VR9);
549 case 10: return offsetof(VexGuestPPC32State, guest_VR10);
550 case 11: return offsetof(VexGuestPPC32State, guest_VR11);
551 case 12: return offsetof(VexGuestPPC32State, guest_VR12);
552 case 13: return offsetof(VexGuestPPC32State, guest_VR13);
553 case 14: return offsetof(VexGuestPPC32State, guest_VR14);
554 case 15: return offsetof(VexGuestPPC32State, guest_VR15);
555 case 16: return offsetof(VexGuestPPC32State, guest_VR16);
556 case 17: return offsetof(VexGuestPPC32State, guest_VR17);
557 case 18: return offsetof(VexGuestPPC32State, guest_VR18);
558 case 19: return offsetof(VexGuestPPC32State, guest_VR19);
559 case 20: return offsetof(VexGuestPPC32State, guest_VR20);
560 case 21: return offsetof(VexGuestPPC32State, guest_VR21);
561 case 22: return offsetof(VexGuestPPC32State, guest_VR22);
562 case 23: return offsetof(VexGuestPPC32State, guest_VR23);
563 case 24: return offsetof(VexGuestPPC32State, guest_VR24);
564 case 25: return offsetof(VexGuestPPC32State, guest_VR25);
565 case 26: return offsetof(VexGuestPPC32State, guest_VR26);
566 case 27: return offsetof(VexGuestPPC32State, guest_VR27);
567 case 28: return offsetof(VexGuestPPC32State, guest_VR28);
568 case 29: return offsetof(VexGuestPPC32State, guest_VR29);
569 case 30: return offsetof(VexGuestPPC32State, guest_VR30);
570 case 31: return offsetof(VexGuestPPC32State, guest_VR31);
571 default: break;
572 }
573 vpanic("vextorGuestRegOffset(ppc32)"); /*notreached*/
574}
575
576static IRExpr* getVReg ( UInt archreg )
577{
578 vassert(archreg < 32);
579 return IRExpr_Get( vectorGuestRegOffset(archreg), Ity_V128 );
580}
581
582/* Ditto, but write to a reg instead. */
583static void putVReg ( UInt archreg, IRExpr* e )
584{
585 vassert(archreg < 32);
586 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_V128);
587 stmt( IRStmt_Put(vectorGuestRegOffset(archreg), e) );
588}
589
590static Int guestCR321offset ( UInt cr )
591{
592 switch (cr) {
593 case 0: return offsetof(VexGuestPPC32State, guest_CR0_321 );
594 case 1: return offsetof(VexGuestPPC32State, guest_CR1_321 );
595 case 2: return offsetof(VexGuestPPC32State, guest_CR2_321 );
596 case 3: return offsetof(VexGuestPPC32State, guest_CR3_321 );
597 case 4: return offsetof(VexGuestPPC32State, guest_CR4_321 );
598 case 5: return offsetof(VexGuestPPC32State, guest_CR5_321 );
599 case 6: return offsetof(VexGuestPPC32State, guest_CR6_321 );
600 case 7: return offsetof(VexGuestPPC32State, guest_CR7_321 );
601 default: vpanic("guestCR321offset(ppc32)");
602 }
603}
604
605static Int guestCR0offset ( UInt cr )
606{
607 switch (cr) {
608 case 0: return offsetof(VexGuestPPC32State, guest_CR0_0 );
609 case 1: return offsetof(VexGuestPPC32State, guest_CR1_0 );
610 case 2: return offsetof(VexGuestPPC32State, guest_CR2_0 );
611 case 3: return offsetof(VexGuestPPC32State, guest_CR3_0 );
612 case 4: return offsetof(VexGuestPPC32State, guest_CR4_0 );
613 case 5: return offsetof(VexGuestPPC32State, guest_CR5_0 );
614 case 6: return offsetof(VexGuestPPC32State, guest_CR6_0 );
615 case 7: return offsetof(VexGuestPPC32State, guest_CR7_0 );
616 default: vpanic("guestCR3offset(ppc32)");
617 }
618}
619
620static void putCR321 ( UInt cr, IRExpr* e )
621{
622 vassert(cr < 8);
623 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I8);
624 stmt( IRStmt_Put(guestCR321offset(cr), e) );
625}
626
627static void putCR0 ( UInt cr, IRExpr* e )
628{
629 vassert(cr < 8);
630 vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I8);
631 stmt( IRStmt_Put(guestCR0offset(cr), e) );
632}
633
634static IRExpr* /* :: Ity_I8 */ getCR0 ( UInt cr )
635{
636 vassert(cr < 8);
637 return IRExpr_Get(guestCR0offset(cr), Ity_I8);
638}
639
640static IRExpr* /* :: Ity_I8 */ getCR321 ( UInt cr )
641{
642 vassert(cr < 8);
643 return IRExpr_Get(guestCR321offset(cr), Ity_I8);
644}
645
646static IRExpr* /* :: Ity_I8 */ getXER_SO ( void )
647{
648 return IRExpr_Get( OFFB_XER_SO, Ity_I8 );
649}
650
651// ROTL(src32, rot_amt5)
652static IRExpr* ROTL32 ( IRExpr* src, Int rot_amt )
653{
cerionb85e8bb2005-02-16 08:54:33 +0000654 vassert(typeOfIRExpr(irbb->tyenv,src) == Ity_I32);
sewardjb51f0f42005-07-18 11:38:02 +0000655 vassert(rot_amt >= 0 && rot_amt < 32);
656
657 if (rot_amt == 0)
658 return src;
659
660 vassert(rot_amt > 0 && rot_amt < 32);
661
cerionb85e8bb2005-02-16 08:54:33 +0000662 // (src << rot_amt) | (src >> (32-rot_amt))
663 return binop(Iop_Or32,
sewardjb51f0f42005-07-18 11:38:02 +0000664 binop(Iop_Shl32, src, mkU8(rot_amt)),
665 binop(Iop_Shr32, src, mkU8(32-rot_amt)));
cerion45b70ff2005-01-31 17:03:25 +0000666}
cerion896a1372005-01-25 12:24:25 +0000667
668
669
cerion896a1372005-01-25 12:24:25 +0000670/*------------------------------------------------------------*/
sewardjb51f0f42005-07-18 11:38:02 +0000671/*--- Helpers for condition codes. ---*/
cerion896a1372005-01-25 12:24:25 +0000672/*------------------------------------------------------------*/
673
sewardjb51f0f42005-07-18 11:38:02 +0000674/* Condition register layout.
cerion896a1372005-01-25 12:24:25 +0000675
sewardjb51f0f42005-07-18 11:38:02 +0000676 In the hardware, CR is laid out like this. The leftmost end is the
677 most significant bit in the register; however the IBM documentation
678 numbers the bits backwards for some reason.
679
680 CR0 CR1 .......... CR6 CR7
681 0 .. 3 ....................... 28 .. 31 (IBM bit numbering)
682 31 28 3 0 (normal bit numbering)
683
684 Each CR field is 4 bits:
685
686 < > == SO
687
688 Hence in IBM's notation, BI=0 indicates CR7.SO, BI=1 is CR7.==,
689 etc.
690
691 Indexing from BI to guest state:
692
693 let n = BI / 4
694 off = BI % 4
695 this references CR n:
696
697 off==3 -> guest_CRn_SO
698 off==2 -> guest_CRn_123 >> 1
699 off==1 -> guest_CRn_123 >> 2
700 off==0 -> guest_CRn_123 >> 3
701
702 Bear in mind the only significant bit in guest_CRn_SO is bit 0
703 (normal notation) and in guest_CRn_123 the significant bits are
704 3, 2 and 1 (normal notation).
705*/
706/* Fetch the specified CR bit (as per IBM/hardware notation) and
707 return it at the bottom of an I32; the top 31 bits are guaranteed
708 to be zero. */
709static IRExpr* /* :: Ity_I32 */ getCRbit ( UInt bi )
cerion896a1372005-01-25 12:24:25 +0000710{
sewardjb51f0f42005-07-18 11:38:02 +0000711 UInt n = bi / 4;
712 UInt off = bi % 4;
713 vassert(bi < 32);
714 if (off == 3) {
715 /* Fetch the SO bit for this CR field */
716 /* Note: And32 is redundant paranoia iff guest state only has 0
717 or 1 in that slot. */
718 return binop(Iop_And32, unop(Iop_8Uto32, getCR0(n)), mkU32(1));
719 } else {
720 /* Fetch the <, > or == bit for this CR field */
721 return binop( Iop_And32,
722 binop( Iop_Shr32,
723 unop(Iop_8Uto32, getCR321(n)),
724 mkU8(3-off) ),
725 mkU32(1) );
726 }
cerion91ad5362005-01-27 23:02:41 +0000727}
728
sewardjb51f0f42005-07-18 11:38:02 +0000729/* Dually, write the least significant bit of BIT to the specified CR
730 bit. Indexing as per getCRbit. */
731static void putCRbit ( UInt bi, IRExpr* bit )
732{
733 IRExpr* safe;
734 vassert(typeOfIRExpr(irbb->tyenv,bit) == Ity_I32);
735 safe = binop(Iop_And32, bit, mkU32(1));
736 UInt n = bi / 4;
737 UInt off = bi % 4;
738 vassert(bi < 32);
739 if (off == 3) {
740 /* This is the SO bit for this CR field */
741 putCR0(n, unop(Iop_32to8, safe));
742 } else {
743 off = 3 - off;
744 vassert(off == 1 || off == 2 || off == 3);
745 putCR321(
746 n,
747 unop( Iop_32to8,
748 binop( Iop_Or32,
749 /* old value with field masked out */
750 binop(Iop_And32, unop(Iop_8Uto32, getCR321(n)),
751 mkU32(~(1 << off))),
752 /* new value in the right place */
753 binop(Iop_Shl32, safe, mkU8(off))
754 )
755 )
756 );
757 }
758}
759
760
761/* Fetch the specified CR bit (as per IBM/hardware notation) and
762 return it somewhere in an I32; it does not matter where, but
763 whichever bit it is, all other bits are guaranteed to be zero. In
764 other words, the I32-typed expression will be zero if the bit is
765 zero and nonzero if the bit is 1. Write into *where the index
766 of where the bit will be. */
767
768static IRExpr* /* :: Ity_I32 */ getCRbit_anywhere ( UInt bi, Int* where )
769{
770 UInt n = bi / 4;
771 UInt off = bi % 4;
772 vassert(bi < 32);
773 if (off == 3) {
774 /* Fetch the SO bit for this CR field */
775 /* Note: And32 is redundant paranoia iff guest state only has 0
776 or 1 in that slot. */
777 *where = 0;
778 return binop(Iop_And32, unop(Iop_8Uto32, getCR0(n)), mkU32(1));
779 } else {
780 /* Fetch the <, > or == bit for this CR field */
781 *where = 3-off;
782 return binop( Iop_And32,
783 unop(Iop_8Uto32, getCR321(n)),
784 mkU32(1 << (3-off)) );
785 }
786}
787
788
789/* Synthesise the entire CR into a single word. Expensive. */
790
791static IRExpr* /* :: Ity_I32 */ getEntireCR ( void )
792{
793# define FIELD(_n) \
794 binop(Iop_Shl32, \
795 unop(Iop_8Uto32, \
796 binop(Iop_Or8, \
797 binop(Iop_And8, getCR321(_n), mkU8(7<<1)), \
798 binop(Iop_And8, getCR0(_n), mkU8(1)) \
799 ) \
800 ), \
801 mkU8(4 * (7-(_n))) \
802 )
803
804 return binop(Iop_Or32,
805 binop(Iop_Or32,
806 binop(Iop_Or32, FIELD(0), FIELD(1)),
807 binop(Iop_Or32, FIELD(2), FIELD(3))
808 ),
809 binop(Iop_Or32,
810 binop(Iop_Or32, FIELD(4), FIELD(5)),
811 binop(Iop_Or32, FIELD(6), FIELD(7))
812 )
813 );
814# undef FIELD
815}
816
817static void putCRfields ( IRExpr* w32, UInt mask )
818{
819 IRTemp t;
820 Int cr;
821 vassert(typeOfIRExpr(irbb->tyenv,w32) == Ity_I32);
822 vassert(mask < 256);
823 for (cr = 0; cr < 8; cr++) {
824 if ((mask & (1 << (7-cr))) == 0)
825 continue;
826 t = newTemp(Ity_I32);
827 assign( t, binop(Iop_Shr32, w32, mkU8(4*(7-cr))) );
828 putCR0( cr, unop(Iop_32to8,
829 binop(Iop_And32, mkexpr(t), mkU32(1))) );
830 putCR321( cr, unop(Iop_32to8,
831 binop(Iop_And32, mkexpr(t), mkU32(7<<1))) );
832 }
833}
834
835
836//zz /* -------------- Evaluating the flags-thunk. -------------- */
837//zz
838//zz /* Calculate CR7 (IBM CR0) conditional flags */
839//zz static IRExpr* mk_ppc32g_calculate_cr7 ( void )
840//zz {
841//zz IRExpr** args =
842//zz mkIRExprVec_3( IRExpr_Get(OFFB_CC_OP, Ity_I32),
843//zz IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
844//zz IRExpr_Get(OFFB_CC_DEP2, Ity_I32) );
845//zz IRExpr* call
846//zz = mkIRExprCCall(
847//zz Ity_I32,
848//zz 0/*regparm*/,
849//zz "ppc32g_calculate_cr7", &ppc32g_calculate_cr7,
850//zz args
851//zz );
852//zz
853//zz // TODO
854//zz // 02/02/05 - leaving definedness stuff 'till get memcheck working well.
855//zz
856//zz /* Exclude OP from definedness checking. We're only
857//zz interested in DEP1 and DEP2. */
858//zz // call->Iex.CCall.cee->mcx_mask = 1;
859//zz
860//zz return call;
861//zz }
862//zz
863//zz /* Calculate XER_OV flag */
864//zz static IRExpr* mk_ppc32g_calculate_xer_ov ( UInt op, IRExpr* res,
865//zz IRExpr* argL, IRExpr* argR )
866//zz {
867//zz IRExpr** args;
868//zz IRExpr* call;
869//zz vassert(op < PPC32G_FLAG_OP_NUMBER);
870//zz vassert(typeOfIRExpr(irbb->tyenv,res) == Ity_I32);
871//zz vassert(typeOfIRExpr(irbb->tyenv,argL) == Ity_I32);
872//zz vassert(typeOfIRExpr(irbb->tyenv,argR) == Ity_I32);
873//zz
874//zz args = mkIRExprVec_4( mkU32(op), res, argL, argR );
875//zz
876//zz call
877//zz = mkIRExprCCall(
878//zz Ity_I32,
879//zz 0/*regparm*/,
880//zz "ppc32g_calculate_xer_ov", &ppc32g_calculate_xer_ov,
881//zz args
882//zz );
883//zz return binop(Iop_And32, mkU32(1), call);
884//zz }
885
886/* Calculate XER_CA flag. RES is the result of applying OP to ARGL
887 and ARGR, and OLDCA is the old carry flag. The latter may be zero
888 if it is known that OP does not need to consult it. */
889
890static IRExpr* mk_ppc32g_calculate_xer_ca ( UInt op,
891 IRExpr* res,
892 IRExpr* argL,
893 IRExpr* argR,
894 IRExpr* oldca )
cerion91ad5362005-01-27 23:02:41 +0000895{
sewardj9a036bf2005-03-14 18:19:08 +0000896 IRExpr** args;
897 IRExpr* call;
cerion38674602005-02-08 02:19:25 +0000898 vassert(op < PPC32G_FLAG_OP_NUMBER);
sewardjb51f0f42005-07-18 11:38:02 +0000899 vassert(typeOfIRExpr(irbb->tyenv,res) == Ity_I32);
900 vassert(typeOfIRExpr(irbb->tyenv,argL) == Ity_I32);
901 vassert(typeOfIRExpr(irbb->tyenv,argR) == Ity_I32);
902 vassert(typeOfIRExpr(irbb->tyenv,oldca) == Ity_I32);
cerion62bec572005-02-01 21:29:39 +0000903
sewardjb51f0f42005-07-18 11:38:02 +0000904 args = mkIRExprVec_5( mkU32(op), res, argL, argR, oldca );
cerion995bc362005-02-03 11:03:31 +0000905
sewardj9a036bf2005-03-14 18:19:08 +0000906 call
cerion91ad5362005-01-27 23:02:41 +0000907 = mkIRExprCCall(
908 Ity_I32,
909 0/*regparm*/,
910 "ppc32g_calculate_xer_ca", &ppc32g_calculate_xer_ca,
911 args
912 );
cerion7342c372005-03-03 17:36:23 +0000913 return binop(Iop_And32, mkU32(1), call);
cerion91ad5362005-01-27 23:02:41 +0000914}
915
916
sewardjb51f0f42005-07-18 11:38:02 +0000917/* Set the CR0 flags following an arithmetic operation.
918 (Condition Register CR0 Field Definition, PPC32 p60)
cerion896a1372005-01-25 12:24:25 +0000919*/
sewardj20ef5472005-07-21 14:48:31 +0000920static void set_CR0 ( IRExpr* result )
cerion896a1372005-01-25 12:24:25 +0000921{
cerion62bec572005-02-01 21:29:39 +0000922 vassert(typeOfIRExpr(irbb->tyenv,result) == Ity_I32);
sewardjb51f0f42005-07-18 11:38:02 +0000923 putCR321( 0, unop(Iop_32to8,
924 binop(Iop_CmpORD32S, result, mkU32(0))) );
925 putCR0( 0, getXER_SO() );
cerion896a1372005-01-25 12:24:25 +0000926}
cerion896a1372005-01-25 12:24:25 +0000927
sewardj20ef5472005-07-21 14:48:31 +0000928
929/* RES is the result of doing OP on ARGL and ARGR. Set %XER.OV and
930 %XER.SO accordingly. */
931
932static void set_XER_OV( UInt op, IRExpr* res,
933 IRExpr* argL, IRExpr* argR )
934{
935 IRTemp t64;
936 IRExpr* xer_ov;
937 vassert(op < PPC32G_FLAG_OP_NUMBER);
938 vassert(typeOfIRExpr(irbb->tyenv,res) == Ity_I32);
939 vassert(typeOfIRExpr(irbb->tyenv,argL) == Ity_I32);
940 vassert(typeOfIRExpr(irbb->tyenv,argR) == Ity_I32);
941
942# define INT32_MIN 0x80000000
943
944# define XOR2(_aa,_bb) \
945 binop(Iop_Xor32,(_aa),(_bb))
946
947# define XOR3(_cc,_dd,_ee) \
948 binop(Iop_Xor32,binop(Iop_Xor32,(_cc),(_dd)),(_ee))
949
950# define AND3(_ff,_gg,_hh) \
951 binop(Iop_And32,binop(Iop_And32,(_ff),(_gg)),(_hh))
952
953#define NOT(_jj) \
954 unop(Iop_Not32, (_jj))
955
956 switch (op) {
957
958 case /* 0 */ PPC32G_FLAG_OP_ADD:
959 case /* 1 */ PPC32G_FLAG_OP_ADDE:
960 /* (argL^argR^-1) & (argL^res) & (1<<31) ?1:0 */
961 // i.e. ((both_same_sign) & (sign_changed) & (sign_mask))
962 xer_ov
963 = AND3( XOR3(argL,argR,mkU32(-1)),
964 XOR2(argL,res),
965 mkU32(INT32_MIN) );
966 /* xer_ov can only be 0 or 1<<31 */
967 xer_ov
968 = binop(Iop_Shr32, xer_ov, mkU8(31) );
969 break;
970
971 case /* 2 */ PPC32G_FLAG_OP_DIVW:
972 /* (argL == INT32_MIN && argR == -1) || argR == 0 */
973 xer_ov
974 = mkOR1(
975 mkAND1(
976 binop(Iop_CmpEQ32, argL, mkU32(INT32_MIN)),
977 binop(Iop_CmpEQ32, argR, mkU32(-1))
978 ),
979 binop(Iop_CmpEQ32, argR, mkU32(0) )
980 );
981 xer_ov
982 = unop(Iop_1Uto32, xer_ov);
983 break;
984
985 case /* 3 */ PPC32G_FLAG_OP_DIVWU:
986 /* argR == 0 */
987 xer_ov
988 = unop(Iop_1Uto32, binop(Iop_CmpEQ32, argR, mkU32(0)));
989 break;
990
991 case /* 4 */ PPC32G_FLAG_OP_MULLW:
992 /* OV true if result can't be represented in 32 bits
993 i.e sHi != sign extension of sLo */
994 t64 = newTemp(Ity_I64);
sewardj6fa6bf12005-07-21 17:07:18 +0000995 assign( t64, binop(Iop_MullS32, argL, argR) );
sewardj20ef5472005-07-21 14:48:31 +0000996 xer_ov
997 = binop( Iop_CmpNE32,
998 unop(Iop_64HIto32, mkexpr(t64)),
999 binop( Iop_Sar32,
1000 unop(Iop_64to32, mkexpr(t64)),
1001 mkU8(31))
1002 );
1003 xer_ov
1004 = unop(Iop_1Uto32, xer_ov);
1005 break;
1006
1007 case /* 5 */ PPC32G_FLAG_OP_NEG:
1008 /* argL == INT32_MIN */
1009 xer_ov
1010 = unop( Iop_1Uto32,
1011 binop(Iop_CmpEQ32, argL, mkU32(INT32_MIN)) );
1012 break;
1013
1014 case /* 6 */ PPC32G_FLAG_OP_SUBF:
1015 case /* 7 */ PPC32G_FLAG_OP_SUBFC:
1016 case /* 8 */ PPC32G_FLAG_OP_SUBFE:
1017 /* ((~argL)^argR^-1) & ((~argL)^res) & (1<<31) ?1:0; */
1018 xer_ov
1019 = AND3( XOR3(NOT(argL),argR,mkU32(-1)),
1020 XOR2(NOT(argL),res),
1021 mkU32(INT32_MIN) );
1022 /* xer_ov can only be 0 or 1<<31 */
1023 xer_ov
1024 = binop(Iop_Shr32, xer_ov, mkU8(31) );
1025 break;
1026
1027 default:
1028 vex_printf("set_XER_OV: op = %d\n", op);
1029 vpanic("set_XER_OV(ppc32)");
1030 }
1031
1032 /* xer_ov MUST denote either 0 or 1, no other value allowed */
1033 stmt( IRStmt_Put( OFFB_XER_OV, unop(Iop_32to8, xer_ov) ) );
1034
1035 /* Update the summary overflow */
1036 stmt( IRStmt_Put(
1037 OFFB_XER_SO,
1038 binop(Iop_Or8, IRExpr_Get( OFFB_XER_SO, Ity_I8 ),
1039 IRExpr_Get( OFFB_XER_OV, Ity_I8 ) )
1040 ));
1041
1042# undef INT32_MIN
1043# undef AND3
1044# undef XOR3
1045# undef XOR2
1046# undef NOT
1047}
1048
cerion38674602005-02-08 02:19:25 +00001049
sewardjb51f0f42005-07-18 11:38:02 +00001050/* RES is the result of doing OP on ARGL and ARGR with the old %XER.CA
1051 value being OLDCA. Set %XER.CA accordingly. */
cerione9d361a2005-03-04 17:35:29 +00001052
sewardjb51f0f42005-07-18 11:38:02 +00001053static void set_XER_CA( UInt op,
1054 IRExpr* res,
1055 IRExpr* argL,
1056 IRExpr* argR,
1057 IRExpr* oldca )
cerion38674602005-02-08 02:19:25 +00001058{
sewardj9a036bf2005-03-14 18:19:08 +00001059 IRExpr* xer_ca;
cerionb85e8bb2005-02-16 08:54:33 +00001060 vassert(op < PPC32G_FLAG_OP_NUMBER);
sewardjb51f0f42005-07-18 11:38:02 +00001061 vassert(typeOfIRExpr(irbb->tyenv,res) == Ity_I32);
1062 vassert(typeOfIRExpr(irbb->tyenv,argL) == Ity_I32);
1063 vassert(typeOfIRExpr(irbb->tyenv,argR) == Ity_I32);
1064 vassert(typeOfIRExpr(irbb->tyenv,oldca) == Ity_I32);
cerion70e24122005-03-16 00:27:37 +00001065
sewardj20ef5472005-07-21 14:48:31 +00001066 /* Incoming oldca is assumed to hold the values 0 or 1 only. This
1067 seems reasonable given that it's always generated by
1068 get_XER_CA(), which masks it accordingly. In any case it being
1069 0 or 1 is an invariant of the ppc32 guest state representation;
1070 if it has any other value, that invariant has been violated. */
cerione9d361a2005-03-04 17:35:29 +00001071
sewardj20ef5472005-07-21 14:48:31 +00001072 switch (op) {
1073
1074 case /* 0 */ PPC32G_FLAG_OP_ADD:
1075 /* res <u argL */
1076 xer_ca
1077 = unop(Iop_1Uto32, binop(Iop_CmpLT32U, res, argL));
1078 break;
1079
1080 case /* 1 */ PPC32G_FLAG_OP_ADDE:
1081 /* res <u argL || (old_ca==1 && res==argL) */
1082 xer_ca
1083 = mkOR1(
1084 binop(Iop_CmpLT32U, res, argL),
1085 mkAND1(
1086 binop(Iop_CmpEQ32, oldca, mkU32(1)),
1087 binop(Iop_CmpEQ32, res, argL)
1088 )
1089 );
1090 xer_ca
1091 = unop(Iop_1Uto32, xer_ca);
1092 break;
1093
1094 case /* 8 */ PPC32G_FLAG_OP_SUBFE:
1095 /* res <u argR || (old_ca==1 && res==argR) */
1096 xer_ca
1097 = mkOR1(
1098 binop(Iop_CmpLT32U, res, argR),
1099 mkAND1(
1100 binop(Iop_CmpEQ32, oldca, mkU32(1)),
1101 binop(Iop_CmpEQ32, res, argR)
1102 )
1103 );
1104 xer_ca
1105 = unop(Iop_1Uto32, xer_ca);
1106 break;
1107
1108 case /* 7 */ PPC32G_FLAG_OP_SUBFC:
1109 case /* 9 */ PPC32G_FLAG_OP_SUBFI:
1110 /* res <=u argR */
1111 xer_ca
1112 = unop(Iop_1Uto32, binop(Iop_CmpLE32U, res, argR));
1113 break;
1114
1115 case /* 10 */ PPC32G_FLAG_OP_SRAW:
1116 /* The shift amount is guaranteed to be in 0 .. 63 inclusive.
1117 If it is <= 31, behave like SRAWI; else XER.CA is the sign
1118 bit of argL. */
1119 /* This term valid for shift amount < 32 only */
1120 xer_ca
1121 = binop(
1122 Iop_And32,
1123 binop(Iop_Sar32, argL, mkU8(31)),
1124 binop( Iop_And32,
1125 argL,
1126 binop( Iop_Sub32,
1127 binop(Iop_Shl32, mkU32(1), unop(Iop_32to8,argR)),
1128 mkU32(1) )
1129 )
1130 );
1131 xer_ca
1132 = IRExpr_Mux0X(
1133 /* shift amt > 31 ? */
1134 unop(Iop_1Uto8, binop(Iop_CmpLT32U, mkU32(31), argR)),
1135 /* no -- be like srawi */
1136 unop(Iop_1Uto32, binop(Iop_CmpNE32, xer_ca, mkU32(0))),
1137 /* yes -- get sign bit of argL */
1138 binop(Iop_Shr32, argL, mkU8(31))
1139 );
1140 break;
1141
1142 case /* 11 */ PPC32G_FLAG_OP_SRAWI:
1143 /* xer_ca is 1 iff src was negative and bits_shifted_out !=
1144 0. Since the shift amount is known to be in the range
1145 0 .. 31 inclusive the following seems viable:
1146 xer.ca == 1 iff the following is nonzero:
1147 (argL >>s 31) -- either all 0s or all 1s
1148 & (argL & (1<<argR)-1) -- the stuff shifted out */
1149 xer_ca
1150 = binop(
1151 Iop_And32,
1152 binop(Iop_Sar32, argL, mkU8(31)),
1153 binop( Iop_And32,
1154 argL,
1155 binop( Iop_Sub32,
1156 binop(Iop_Shl32, mkU32(1), unop(Iop_32to8,argR)),
1157 mkU32(1) )
1158 )
1159 );
1160 xer_ca
1161 = unop(Iop_1Uto32, binop(Iop_CmpNE32, xer_ca, mkU32(0)));
1162 break;
1163
1164 default:
1165 vex_printf("set_XER_CA: op = %d\n", op);
1166 vpanic("set_XER_CA(ppc32)");
1167 }
1168
1169 /* xer_ca MUST denote either 0 or 1, no other value allowed */
1170 stmt( IRStmt_Put( OFFB_XER_CA, unop(Iop_32to8, xer_ca) ) );
sewardjb51f0f42005-07-18 11:38:02 +00001171}
1172
1173static IRExpr* /* :: Ity_I32 */ get_XER_CA ( void )
1174{
1175 return binop( Iop_And32,
1176 unop( Iop_8Uto32,
1177 IRExpr_Get(OFFB_XER_CA, Ity_I8) ),
1178 mkU32(1) );
cerion38674602005-02-08 02:19:25 +00001179}
1180
cerion896a1372005-01-25 12:24:25 +00001181
1182
sewardjb51f0f42005-07-18 11:38:02 +00001183//zz /*------------------------------------------------------------*/
1184//zz /*--- Abstract register interface --- */
1185//zz /*------------------------------------------------------------*/
1186//zz /* Most registers are represented directly in the cpu_state,
1187//zz but CR is represented by a thunk */
1188//zz
1189//zz
1190//zz /* Get a masked word from the given reg */
1191//zz static IRExpr* getReg_masked ( PPC32SPR reg, UInt mask )
1192//zz {
1193//zz IRTemp val = newTemp(Ity_I32);
1194//zz vassert( reg < PPC32_SPR_MAX );
1195//zz
1196//zz switch (reg) {
1197//zz case PPC32_SPR_CIA:
1198//zz vassert(mask == 0xFFFFFFFF); // Only ever need whole reg
1199//zz assign( val, IRExpr_Get(OFFB_CIA, Ity_I32) );
1200//zz break;
1201//zz
1202//zz case PPC32_SPR_LR:
1203//zz vassert(mask == 0xFFFFFFFF); // Only ever need whole reg
1204//zz assign( val, IRExpr_Get(OFFB_LR, Ity_I32) );
1205//zz break;
1206//zz
1207//zz case PPC32_SPR_CTR:
1208//zz vassert(mask == 0xFFFFFFFF); // Only ever need whole reg
1209//zz assign( val, IRExpr_Get(OFFB_CTR, Ity_I32) );
1210//zz break;
1211//zz
1212//zz case PPC32_SPR_XER:
1213//zz // Bits 7-28 are 'Reserved'. Always return zero for these bits.
1214//zz // (They may be written to, but reading them gives zero or undefined)
1215//zz mask = mask & 0xE000007F;
1216//zz assign( val, IRExpr_Get(OFFB_XER, Ity_I32) );
1217//zz break;
1218//zz
1219//zz case PPC32_SPR_CR:
1220//zz if ((mask & 0xF0000000) == mask) { // CR7 only
1221//zz // Call helper function to calculate latest CR7 from thunk:
1222//zz assign( val, mk_ppc32g_calculate_cr7() );
1223//zz }
1224//zz else if ((mask & 0x0FFFFFFF) == mask) { // CR0to6 only
1225//zz assign( val, IRExpr_Get(OFFB_CR0to6, Ity_I32) );
1226//zz }
1227//zz else { // Both
1228//zz assign( val, binop(Iop_Or32, mk_ppc32g_calculate_cr7(),
1229//zz IRExpr_Get(OFFB_CR0to6, Ity_I32)) );
1230//zz }
1231//zz break;
1232//zz
1233//zz case PPC32_SPR_FPSCR: {
1234//zz vassert((mask & 0x3) == 0x3 || (mask & 0x3) == 0x0);
1235//zz vassert((mask & 0xF000) == 0xF000 || (mask & 0xF000) == 0x0);
1236//zz /* all masks now refer to valid fields */
1237//zz
1238//zz /* Vex-generated code expects to run with the FPSCR set as follows:
1239//zz all exceptions masked, round-to-nearest.
1240//zz This corresponds to a FPSCR value of 0x0. */
1241//zz
1242//zz /* We're only keeping track of the rounding mode,
1243//zz so if the mask isn't asking for this, just return 0x0 */
1244//zz if (mask & 0x3) {
1245//zz assign( val, IRExpr_Get(OFFB_FPROUND, Ity_I32) );
1246//zz } else {
1247//zz assign( val, mkU32(0x0) );
1248//zz }
1249//zz break;
1250//zz }
1251//zz
1252//zz case PPC32_SPR_VRSAVE:
1253//zz assign( val, IRExpr_Get(OFFB_VRSAVE, Ity_I32) );
1254//zz break;
1255//zz
1256//zz case PPC32_SPR_VSCR:
1257//zz // All other bits are 'Reserved'. Returning zero for these bits.
1258//zz mask = mask & 0x00010001;
1259//zz assign( val, IRExpr_Get(OFFB_VSCR, Ity_I32) );
1260//zz break;
1261//zz
1262//zz default:
1263//zz vpanic("getReg(ppc32)");
1264//zz }
1265//zz
1266//zz if (mask != 0xFFFFFFFF) {
1267//zz return binop(Iop_And32, mkexpr(val), mkU32(mask));
1268//zz } else {
1269//zz return mkexpr(val);
1270//zz }
1271//zz }
1272//zz
1273//zz /* Get word from the given reg */
1274//zz static IRExpr* getReg ( PPC32SPR reg )
1275//zz {
1276//zz vassert( reg < PPC32_SPR_MAX );
1277//zz return getReg_masked( reg, 0xFFFFFFFF );
1278//zz }
1279//zz
1280//zz /* Get a right-shifted nibble from given reg[field_idx]
1281//zz returns zero padded word */
1282//zz static IRExpr* getReg_field ( PPC32SPR reg, UInt field_idx )
1283//zz {
1284//zz IRExpr* fld;
1285//zz vassert( field_idx < 8 );
1286//zz vassert( reg < PPC32_SPR_MAX );
1287//zz
1288//zz fld = getReg_masked( reg, (0xF << (field_idx*4)) );
1289//zz
1290//zz if (field_idx != 0) {
1291//zz fld = binop(Iop_Shr32, fld, mkU8(toUChar(field_idx * 4)));
1292//zz }
1293//zz return fld;
1294//zz }
1295//zz
1296//zz /* Get a right-shifted bit from given reg[bit_idx]
1297//zz returns zero padded word */
1298//zz static IRExpr* getReg_bit ( PPC32SPR reg, UInt bit_idx )
1299//zz {
1300//zz IRExpr* val;
1301//zz vassert( bit_idx < 32 );
1302//zz vassert( reg < PPC32_SPR_MAX );
1303//zz
1304//zz val = getReg_masked( reg, 1<<bit_idx );
1305//zz
1306//zz if (bit_idx != 0) {
1307//zz val = binop(Iop_Shr32, val, mkU8(toUChar(bit_idx)));
1308//zz }
1309//zz return val;
1310//zz }
1311//zz
1312//zz
1313//zz
1314//zz /* Write masked src to the given reg */
1315//zz static void putReg_masked ( PPC32SPR reg, IRExpr* src, UInt mask )
1316//zz {
1317//zz vassert( reg < PPC32_SPR_MAX );
1318//zz vassert( typeOfIRExpr(irbb->tyenv,src ) == Ity_I32 );
1319//zz
1320//zz switch (reg) {
1321//zz case PPC32_SPR_CIA:
1322//zz vassert(mask == 0xFFFFFFFF); // Only ever need whole reg
1323//zz stmt( IRStmt_Put( OFFB_CIA, src ) );
1324//zz break;
1325//zz
1326//zz case PPC32_SPR_LR:
1327//zz vassert(mask == 0xFFFFFFFF); // Only ever need whole reg
1328//zz stmt( IRStmt_Put( OFFB_LR, src ) );
1329//zz break;
1330//zz
1331//zz case PPC32_SPR_CTR:
1332//zz vassert(mask == 0xFFFFFFFF); // Only ever need whole reg
1333//zz stmt( IRStmt_Put( OFFB_CTR, src ) );
1334//zz break;
1335//zz
1336//zz case PPC32_SPR_XER:
1337//zz // Bits 7-28 are 'Reserved'. Ignoring writes these bits.
1338//zz // (They may be written to, but reading them gives zero or undefined)
1339//zz stmt( IRStmt_Put( OFFB_XER,
1340//zz binop(Iop_Or32,
1341//zz binop(Iop_And32, src, mkU32(mask & 0xE000007F)),
1342//zz getReg_masked( PPC32_SPR_XER, (~mask & 0xE000007F) ))));
1343//zz break;
1344//zz
1345//zz case PPC32_SPR_CR: {
1346//zz if (mask & 0xF0000000) { // CR field 7:
1347//zz /* Set the CR7 flags thunk */
1348//zz stmt( IRStmt_Put( OFFB_CC_OP, mkU32(1)/*set imm value DEP1*/ ) );
1349//zz stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0)/*=unused*/ ) );
1350//zz stmt( IRStmt_Put( OFFB_CC_DEP1,
1351//zz binop(Iop_Or32,
1352//zz binop(Iop_And32, src, mkU32(mask & 0xF0000000)),
1353//zz getReg_masked( PPC32_SPR_CR, (~mask & 0xF0000000) ))));
1354//zz }
1355//zz if (mask & 0x0FFFFFFF) { // CR fields 0 to 6:
1356//zz stmt( IRStmt_Put( OFFB_CR0to6,
1357//zz binop(Iop_Or32,
1358//zz binop(Iop_And32, src, mkU32(mask & 0x0FFFFFFF)),
1359//zz getReg_masked( PPC32_SPR_CR, (~mask & 0x0FFFFFFF) ))));
1360//zz }
1361//zz break;
1362//zz }
1363//zz
1364//zz case PPC32_SPR_FPSCR: {
1365//zz vassert((mask & 0x3) == 0x3 || (mask & 0x3) == 0x0);
1366//zz vassert((mask & 0xF000) == 0xF000 || (mask & 0xF000) == 0x0);
1367//zz /* all masks now refer to valid fields */
1368//zz
1369//zz /* Allow writes to Rounding Mode */
1370//zz if (mask & 0x3) {
1371//zz stmt( IRStmt_Put( OFFB_FPROUND,
1372//zz binop(Iop_And32, src, mkU32(0x3)) ));
1373//zz }
1374//zz
1375//zz /*
1376//zz Give EmWarn for attempted writes to:
1377//zz - Exception Controls
1378//zz - Non-IEEE Mode
1379//zz */
1380//zz if (mask & 0xFC) { // Exception Control, Non-IEE mode
1381//zz VexEmWarn ew = EmWarn_PPC32exns;
1382//zz
1383//zz /* If any of the src::exception_control bits are actually set,
1384//zz side-exit to the next insn, reporting the warning,
1385//zz so that Valgrind's dispatcher sees the warning. */
1386//zz put_emwarn( mkU32(ew) );
1387//zz stmt(
1388//zz IRStmt_Exit(
1389//zz binop(Iop_CmpNE32, mkU32(ew), mkU32(EmWarn_NONE)),
1390//zz Ijk_EmWarn,
1391//zz IRConst_U32(guest_CIA_curr_instr + 4)
1392//zz )
1393//zz );
1394//zz }
1395//zz
1396//zz /*
1397//zz Ignore all other writes
1398//zz */
1399//zz break;
1400//zz
1401//zz case PPC32_SPR_VRSAVE:
1402//zz vassert(mask == 0xFFFFFFFF); // Only ever need whole reg
1403//zz stmt( IRStmt_Put( OFFB_VRSAVE, src ) );
1404//zz break;
1405//zz
1406//zz case PPC32_SPR_VSCR:
1407//zz //CAB: There are only 2 valid bits in VSCR - maybe split into two vars...
1408//zz
1409//zz // All other bits are 'Reserved'. Ignoring writes to these bits.
1410//zz stmt( IRStmt_Put( OFFB_VSCR,
1411//zz binop(Iop_Or32,
1412//zz binop(Iop_And32, src, mkU32(mask & 0x00010001)),
1413//zz getReg_masked( PPC32_SPR_VSCR, (~mask & 0x00010001) ))));
1414//zz break;
1415//zz }
1416//zz
1417//zz default:
1418//zz vpanic("putReg(ppc32)");
1419//zz }
1420//zz }
1421//zz
1422//zz /* Write src to the given reg */
1423//zz static void putReg ( PPC32SPR reg, IRExpr* src )
1424//zz {
1425//zz vassert( typeOfIRExpr(irbb->tyenv,src ) == Ity_I32 );
1426//zz vassert( reg < PPC32_SPR_MAX );
1427//zz putReg_masked( reg, src, 0xFFFFFFFF );
1428//zz }
cerion62bec572005-02-01 21:29:39 +00001429
sewardjb51f0f42005-07-18 11:38:02 +00001430static void putSPR ( PPC32SPR reg, IRExpr* src )
cerion76222262005-02-05 13:45:57 +00001431{
sewardjb51f0f42005-07-18 11:38:02 +00001432 vassert( typeOfIRExpr(irbb->tyenv,src ) == Ity_I32 );
cerionb85e8bb2005-02-16 08:54:33 +00001433 switch (reg) {
sewardjb51f0f42005-07-18 11:38:02 +00001434 case PPC32_SPR_CIA:
1435 stmt( IRStmt_Put( OFFB_CIA, src ) );
1436 break;
1437 case PPC32_SPR_LR:
1438 stmt( IRStmt_Put( OFFB_LR, src ) );
1439 break;
1440 case PPC32_SPR_CTR:
1441 stmt( IRStmt_Put( OFFB_CTR, src ) );
1442 break;
1443 case PPC32_SPR_VRSAVE:
1444 stmt( IRStmt_Put( OFFB_VRSAVE, src ) );
1445 break;
1446 default:
1447 vpanic("putSPR(ppc32)");
cerion3007c7f2005-02-23 23:13:29 +00001448 }
cerion76222262005-02-05 13:45:57 +00001449}
cerion38674602005-02-08 02:19:25 +00001450
sewardjb51f0f42005-07-18 11:38:02 +00001451static IRExpr* /* :: Ity_I32 */ getSPR ( PPC32SPR reg )
cerion38674602005-02-08 02:19:25 +00001452{
cerionb85e8bb2005-02-16 08:54:33 +00001453 switch (reg) {
sewardjb51f0f42005-07-18 11:38:02 +00001454 case PPC32_SPR_LR:
1455 return IRExpr_Get( OFFB_LR, Ity_I32 );
1456 case PPC32_SPR_CTR:
1457 return IRExpr_Get( OFFB_CTR, Ity_I32 );
1458 case PPC32_SPR_VRSAVE:
1459 return IRExpr_Get( OFFB_VRSAVE, Ity_I32 );
1460 default:
1461 vpanic("getSPR(ppc32)");
cerione9d361a2005-03-04 17:35:29 +00001462 }
cerion76222262005-02-05 13:45:57 +00001463}
1464
sewardjb51f0f42005-07-18 11:38:02 +00001465//zz
1466//zz /* Write least-significant nibble of src to reg[field_idx] */
1467//zz static void putReg_field ( PPC32SPR reg, IRExpr* src, UInt field_idx )
1468//zz {
1469//zz vassert( typeOfIRExpr(irbb->tyenv,src ) == Ity_I32 );
1470//zz vassert( field_idx < 8 );
1471//zz vassert( reg < PPC32_SPR_MAX );
1472//zz
1473//zz if (field_idx != 0) {
1474//zz src = binop(Iop_Shl32, src, mkU8(toUChar(field_idx * 4)));
1475//zz }
1476//zz putReg_masked( reg, src, (0xF << (field_idx*4)) );
1477//zz }
1478//zz
1479//zz /* Write least-significant bit of src to reg[bit_idx] */
1480//zz static void putReg_bit ( PPC32SPR reg, IRExpr* src, UInt bit_idx )
1481//zz {
1482//zz vassert( typeOfIRExpr(irbb->tyenv,src ) == Ity_I32 );
1483//zz vassert( bit_idx < 32 );
1484//zz vassert( reg < PPC32_SPR_MAX );
1485//zz
1486//zz if (bit_idx != 0) {
1487//zz src = binop(Iop_Shl32, src, mkU8(toUChar(bit_idx)));
1488//zz }
1489//zz putReg_masked( reg, src, (1<<bit_idx) );
1490//zz }
cerion76222262005-02-05 13:45:57 +00001491
1492
cerione9d361a2005-03-04 17:35:29 +00001493/*------------------------------------------------------------*/
cerion3d870a32005-03-18 12:23:33 +00001494/*--- Integer Instruction Translation --- */
cerione9d361a2005-03-04 17:35:29 +00001495/*------------------------------------------------------------*/
cerion896a1372005-01-25 12:24:25 +00001496
cerion91ad5362005-01-27 23:02:41 +00001497/*
1498 Integer Arithmetic Instructions
1499*/
cerion645c9302005-01-31 10:09:59 +00001500static Bool dis_int_arith ( UInt theInstr )
cerion91ad5362005-01-27 23:02:41 +00001501{
cerionb85e8bb2005-02-16 08:54:33 +00001502 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
1503 UChar Rd_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
1504 UChar Ra_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
1505
1506 /* D-Form */
1507 UInt SIMM_16 = (theInstr >> 0) & 0xFFFF; /* theInstr[0:15] */
1508
1509 /* XO-Form */
1510 UChar Rb_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
1511 UChar flag_OE = toUChar((theInstr >> 10) & 1); /* theInstr[10] */
1512 UInt opc2 = (theInstr >> 1) & 0x1FF; /* theInstr[1:9] */
1513 UChar flag_Rc = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
1514
1515 UInt EXTS_SIMM = 0;
1516
1517 IRTemp Ra = newTemp(Ity_I32);
1518 IRTemp Rb = newTemp(Ity_I32);
1519 IRTemp Rd = newTemp(Ity_I32);
1520 IRTemp res64 = newTemp(Ity_I64); // multiplies need this.
cerion70e24122005-03-16 00:27:37 +00001521
sewardjb51f0f42005-07-18 11:38:02 +00001522//zz UInt flag_op = PPC32G_FLAG_OP_NUMBER;
cerionb85e8bb2005-02-16 08:54:33 +00001523 Bool do_rc = False;
cerion91ad5362005-01-27 23:02:41 +00001524
cerionb85e8bb2005-02-16 08:54:33 +00001525 assign( Ra, getIReg(Ra_addr) );
1526 assign( Rb, getIReg(Rb_addr) ); // XO-Form: Rd, Ra, Rb
1527 EXTS_SIMM = extend_s_16to32(SIMM_16); // D-Form: Rd, Ra, EXTS(SIMM)
cerion932ad942005-01-30 10:18:50 +00001528
sewardjb51f0f42005-07-18 11:38:02 +00001529//zz assign( xer_ca, getReg_bit( PPC32_SPR_XER, SHIFT_XER_CA ) );
1530
cerionb85e8bb2005-02-16 08:54:33 +00001531 switch (opc1) {
cerionb85e8bb2005-02-16 08:54:33 +00001532 /* D-Form */
cerione9d361a2005-03-04 17:35:29 +00001533 case 0x0C: // addic (Add Immediate Carrying, PPC32 p351
cerion3007c7f2005-02-23 23:13:29 +00001534 DIP("addic r%d,r%d,0x%x\n", Rd_addr, Ra_addr, EXTS_SIMM);
cerion4561acb2005-02-21 14:07:48 +00001535 assign( Rd, binop( Iop_Add32, mkexpr(Ra), mkU32(EXTS_SIMM) ) );
sewardjb51f0f42005-07-18 11:38:02 +00001536 set_XER_CA( PPC32G_FLAG_OP_ADD,
1537 mkexpr(Rd), mkexpr(Ra), mkU32(EXTS_SIMM),
1538 mkU32(0)/*old xer.ca, which is ignored*/ );
cerion4561acb2005-02-21 14:07:48 +00001539 break;
sewardjb51f0f42005-07-18 11:38:02 +00001540
cerione9d361a2005-03-04 17:35:29 +00001541 case 0x0D: // addic. (Add Immediate Carrying and Record, PPC32 p352)
cerion3007c7f2005-02-23 23:13:29 +00001542 DIP("addic. r%d,r%d,0x%x\n", Rd_addr, Ra_addr, EXTS_SIMM);
cerion4561acb2005-02-21 14:07:48 +00001543 assign( Rd, binop( Iop_Add32, mkexpr(Ra), mkU32(EXTS_SIMM) ) );
sewardjb51f0f42005-07-18 11:38:02 +00001544 set_XER_CA( PPC32G_FLAG_OP_ADD,
1545 mkexpr(Rd), mkexpr(Ra), mkU32(EXTS_SIMM),
1546 mkU32(0)/*old xer.ca, which is ignored*/ );
cerion70e24122005-03-16 00:27:37 +00001547 do_rc = True; // Always record to CR
cerion4561acb2005-02-21 14:07:48 +00001548 flag_Rc = 1;
1549 break;
1550
cerione9d361a2005-03-04 17:35:29 +00001551 case 0x0E: // addi (Add Immediate, PPC32 p350)
cerionb85e8bb2005-02-16 08:54:33 +00001552 // li rD,val == addi rD,0,val
1553 // la disp(rA) == addi rD,rA,disp
cerionb85e8bb2005-02-16 08:54:33 +00001554 if ( Ra_addr == 0 ) {
sewardjb51f0f42005-07-18 11:38:02 +00001555 DIP("li r%d,%d\n", Rd_addr, EXTS_SIMM);
cerionb85e8bb2005-02-16 08:54:33 +00001556 assign( Rd, mkU32(EXTS_SIMM) );
1557 } else {
sewardjb51f0f42005-07-18 11:38:02 +00001558 DIP("addi r%d,r%d,0x%x\n", Rd_addr, Ra_addr, SIMM_16);
cerionb85e8bb2005-02-16 08:54:33 +00001559 assign( Rd, binop( Iop_Add32, mkexpr(Ra), mkU32(EXTS_SIMM) ) );
1560 }
1561 break;
cerion91ad5362005-01-27 23:02:41 +00001562
cerione9d361a2005-03-04 17:35:29 +00001563 case 0x0F: // addis (Add Immediate Shifted, PPC32 p353)
cerionb85e8bb2005-02-16 08:54:33 +00001564 // lis rD,val == addis rD,0,val
cerionb85e8bb2005-02-16 08:54:33 +00001565 if ( Ra_addr == 0 ) {
sewardjb51f0f42005-07-18 11:38:02 +00001566 DIP("lis r%d,%d\n", Rd_addr, SIMM_16);
cerion7c1dd1b2005-02-22 18:39:18 +00001567 assign( Rd, mkU32(SIMM_16 << 16) );
cerionb85e8bb2005-02-16 08:54:33 +00001568 } else {
sewardjb51f0f42005-07-18 11:38:02 +00001569 DIP("addis r%d,r%d,0x%x\n", Rd_addr, Ra_addr, SIMM_16);
cerion7c1dd1b2005-02-22 18:39:18 +00001570 assign( Rd, binop(Iop_Add32, mkexpr(Ra), mkU32(SIMM_16 << 16)) );
cerionb85e8bb2005-02-16 08:54:33 +00001571 }
1572 break;
cerion91ad5362005-01-27 23:02:41 +00001573
cerione9d361a2005-03-04 17:35:29 +00001574 case 0x07: // mulli (Multiply Low Immediate, PPC32 p490)
cerionb85e8bb2005-02-16 08:54:33 +00001575 DIP("mulli r%d,r%d,0x%x\n", Rd_addr, Ra_addr, SIMM_16);
1576 assign( res64, binop(Iop_MullS32, mkexpr(Ra), mkU32(EXTS_SIMM)) );
1577 assign( Rd, unop(Iop_64to32, mkexpr(res64)) );
1578 break;
cerion38674602005-02-08 02:19:25 +00001579
cerione9d361a2005-03-04 17:35:29 +00001580 case 0x08: // subfic (Subtract from Immediate Carrying, PPC32 p540)
cerionb85e8bb2005-02-16 08:54:33 +00001581 DIP("subfic r%d,r%d,0x%x\n", Rd_addr, Ra_addr, SIMM_16);
cerion01908472005-02-25 16:43:08 +00001582 // rD = exts_simm - rA
cerion9d88da62005-02-25 10:23:46 +00001583 assign( Rd, binop(Iop_Sub32, mkU32(EXTS_SIMM), mkexpr(Ra)) );
sewardjb51f0f42005-07-18 11:38:02 +00001584 set_XER_CA( PPC32G_FLAG_OP_SUBFI,
1585 mkexpr(Rd), mkexpr(Ra), mkU32(EXTS_SIMM),
1586 mkU32(0)/*old xer.ca, which is ignored*/ );
cerionb85e8bb2005-02-16 08:54:33 +00001587 break;
cerion38674602005-02-08 02:19:25 +00001588
cerionb85e8bb2005-02-16 08:54:33 +00001589 /* XO-Form */
1590 case 0x1F:
cerionb85e8bb2005-02-16 08:54:33 +00001591 do_rc = True; // All below record to CR
1592
1593 switch (opc2) {
cerione9d361a2005-03-04 17:35:29 +00001594 case 0x10A: // add (Add, PPC32 p347)
cerionb85e8bb2005-02-16 08:54:33 +00001595 DIP("add%s%s r%d,r%d,r%d\n",
1596 flag_OE ? "o" : "", flag_Rc ? "." : "",
1597 Rd_addr, Ra_addr, Rb_addr);
1598 assign( Rd, binop(Iop_Add32, mkexpr(Ra), mkexpr(Rb)) );
cerion70e24122005-03-16 00:27:37 +00001599 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001600 set_XER_OV( PPC32G_FLAG_OP_ADD,
1601 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb) );
cerion70e24122005-03-16 00:27:37 +00001602 }
cerionb85e8bb2005-02-16 08:54:33 +00001603 break;
cerion91ad5362005-01-27 23:02:41 +00001604
cerione9d361a2005-03-04 17:35:29 +00001605 case 0x00A: // addc (Add Carrying, PPC32 p348)
cerionb85e8bb2005-02-16 08:54:33 +00001606 DIP("addc%s%s r%d,r%d,r%d\n",
1607 flag_OE ? "o" : "", flag_Rc ? "." : "",
1608 Rd_addr, Ra_addr, Rb_addr);
1609 assign( Rd, binop(Iop_Add32, mkexpr(Ra), mkexpr(Rb)) );
sewardjb51f0f42005-07-18 11:38:02 +00001610 set_XER_CA( PPC32G_FLAG_OP_ADD,
1611 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb),
1612 mkU32(0)/*old xer.ca, which is ignored*/ );
cerion70e24122005-03-16 00:27:37 +00001613 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001614 set_XER_OV( PPC32G_FLAG_OP_ADD,
1615 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb) );
cerion70e24122005-03-16 00:27:37 +00001616 }
cerionb85e8bb2005-02-16 08:54:33 +00001617 break;
1618
sewardjb51f0f42005-07-18 11:38:02 +00001619 case 0x08A: { // adde (Add Extended, PPC32 p349)
1620 IRTemp old_xer_ca = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00001621 DIP("adde%s%s r%d,r%d,r%d\n",
1622 flag_OE ? "o" : "", flag_Rc ? "." : "",
1623 Rd_addr, Ra_addr, Rb_addr);
1624 // rD = rA + rB + XER[CA]
sewardjb51f0f42005-07-18 11:38:02 +00001625 assign( old_xer_ca, get_XER_CA() );
cerionb85e8bb2005-02-16 08:54:33 +00001626 assign( Rd, binop(Iop_Add32, mkexpr(Ra),
sewardjb51f0f42005-07-18 11:38:02 +00001627 binop(Iop_Add32, mkexpr(Rb), mkexpr(old_xer_ca))) );
1628 set_XER_CA( PPC32G_FLAG_OP_ADDE,
1629 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb),
1630 mkexpr(old_xer_ca) );
cerion70e24122005-03-16 00:27:37 +00001631 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001632 set_XER_OV( PPC32G_FLAG_OP_ADDE,
1633 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb) );
cerion70e24122005-03-16 00:27:37 +00001634 }
cerionb85e8bb2005-02-16 08:54:33 +00001635 break;
sewardjb51f0f42005-07-18 11:38:02 +00001636 }
1637
1638 case 0x0EA: { // addme (Add to Minus One Extended, PPC32 p354)
1639 IRTemp old_xer_ca = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00001640 if (Rb_addr != 0) {
1641 vex_printf("dis_int_arith(PPC32)(addme,Rb_addr)\n");
1642 return False;
1643 }
1644 DIP("addme%s%s r%d,r%d,r%d\n",
1645 flag_OE ? "o" : "", flag_Rc ? "." : "",
1646 Rd_addr, Ra_addr, Rb_addr);
cerion70e24122005-03-16 00:27:37 +00001647 // rD = rA + (-1) + XER[CA]
1648 // => Just another form of adde
sewardjb51f0f42005-07-18 11:38:02 +00001649 assign( old_xer_ca, get_XER_CA() );
cerionb85e8bb2005-02-16 08:54:33 +00001650 assign( Rd, binop(Iop_Add32, mkexpr(Ra),
sewardjb51f0f42005-07-18 11:38:02 +00001651 binop(Iop_Add32, mkU32(-1), mkexpr(old_xer_ca)) ));
1652 set_XER_CA( PPC32G_FLAG_OP_ADDE,
1653 mkexpr(Rd), mkexpr(Ra), mkU32(-1),
1654 mkexpr(old_xer_ca) );
cerion70e24122005-03-16 00:27:37 +00001655 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001656 set_XER_OV( PPC32G_FLAG_OP_ADDE,
1657 mkexpr(Rd), mkexpr(Ra), mkU32(-1) );
cerion70e24122005-03-16 00:27:37 +00001658 }
cerionb85e8bb2005-02-16 08:54:33 +00001659 break;
sewardjb51f0f42005-07-18 11:38:02 +00001660 }
1661
1662 case 0x0CA: { // addze (Add to Zero Extended, PPC32 p355)
1663 IRTemp old_xer_ca = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00001664 if (Rb_addr != 0) {
1665 vex_printf("dis_int_arith(PPC32)(addze,Rb_addr)\n");
1666 return False;
1667 }
1668 DIP("addze%s%s r%d,r%d,r%d\n",
1669 flag_OE ? "o" : "", flag_Rc ? "." : "",
1670 Rd_addr, Ra_addr, Rb_addr);
cerion70e24122005-03-16 00:27:37 +00001671 // rD = rA + (0) + XER[CA]
1672 // => Just another form of adde
sewardjb51f0f42005-07-18 11:38:02 +00001673 assign( old_xer_ca, get_XER_CA() );
1674 assign( Rd, binop(Iop_Add32, mkexpr(Ra), mkexpr(old_xer_ca)) );
1675 set_XER_CA( PPC32G_FLAG_OP_ADDE,
1676 mkexpr(Rd), mkexpr(Ra), mkU32(0),
1677 mkexpr(old_xer_ca) );
cerion70e24122005-03-16 00:27:37 +00001678 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001679 set_XER_OV( PPC32G_FLAG_OP_ADDE,
1680 mkexpr(Rd), mkexpr(Ra), mkU32(0) );
cerion70e24122005-03-16 00:27:37 +00001681 }
cerionb85e8bb2005-02-16 08:54:33 +00001682 break;
sewardjb51f0f42005-07-18 11:38:02 +00001683 }
cerion91ad5362005-01-27 23:02:41 +00001684
cerione9d361a2005-03-04 17:35:29 +00001685 case 0x1EB: // divw (Divide Word, PPC32 p388)
cerionb85e8bb2005-02-16 08:54:33 +00001686 DIP("divw%s%s r%d,r%d,r%d\n",
1687 flag_OE ? "o" : "", flag_Rc ? "." : "",
1688 Rd_addr, Ra_addr, Rb_addr);
1689 assign( Rd, binop(Iop_DivS32, mkexpr(Ra), mkexpr(Rb)) );
cerion70e24122005-03-16 00:27:37 +00001690 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001691 set_XER_OV( PPC32G_FLAG_OP_DIVW,
1692 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb) );
cerion70e24122005-03-16 00:27:37 +00001693 }
cerionb85e8bb2005-02-16 08:54:33 +00001694 /* Note:
1695 if (0x8000_0000 / -1) or (x / 0)
1696 => Rd=undef, if(flag_Rc) CR7=undef, if(flag_OE) XER_OV=1
1697 => But _no_ exception raised. */
1698 break;
cerion91ad5362005-01-27 23:02:41 +00001699
cerione9d361a2005-03-04 17:35:29 +00001700 case 0x1CB: // divwu (Divide Word Unsigned, PPC32 p389)
cerionb85e8bb2005-02-16 08:54:33 +00001701 DIP("divwu%s%s r%d,r%d,r%d\n",
1702 flag_OE ? "o" : "", flag_Rc ? "." : "",
1703 Rd_addr, Ra_addr, Rb_addr);
1704 assign( Rd, binop(Iop_DivU32, mkexpr(Ra), mkexpr(Rb)) );
cerion70e24122005-03-16 00:27:37 +00001705 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001706 set_XER_OV( PPC32G_FLAG_OP_DIVWU,
1707 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb) );
cerion70e24122005-03-16 00:27:37 +00001708 }
cerionb85e8bb2005-02-16 08:54:33 +00001709 /* Note: ditto comment divw, for (x / 0) */
1710 break;
cerion91ad5362005-01-27 23:02:41 +00001711
cerione9d361a2005-03-04 17:35:29 +00001712 case 0x04B: // mulhw (Multiply High Word, PPC32 p488)
cerionb85e8bb2005-02-16 08:54:33 +00001713 if (flag_OE != 0) {
1714 vex_printf("dis_int_arith(PPC32)(mulhw,flag_OE)\n");
1715 return False;
1716 }
1717 DIP("mulhw%s r%d,r%d,r%d\n", flag_Rc ? "." : "",
1718 Rd_addr, Ra_addr, Rb_addr);
1719 assign( res64, binop(Iop_MullS32, mkexpr(Ra), mkexpr(Rb)) );
1720 assign( Rd, unop(Iop_64HIto32, mkexpr(res64)) );
1721 break;
cerionc19d5e12005-02-01 15:56:25 +00001722
cerione9d361a2005-03-04 17:35:29 +00001723 case 0x00B: // mulhwu (Multiply High Word Unsigned, PPC32 p489)
cerionb85e8bb2005-02-16 08:54:33 +00001724 if (flag_OE != 0) {
1725 vex_printf("dis_int_arith(PPC32)(mulhwu,flag_OE)\n");
1726 return False;
1727 }
1728 DIP("mulhwu%s r%d,r%d,r%d\n", flag_Rc ? "." : "",
1729 Rd_addr, Ra_addr, Rb_addr);
1730 assign( res64, binop(Iop_MullU32, mkexpr(Ra), mkexpr(Rb)) );
1731 assign( Rd, unop(Iop_64HIto32, mkexpr(res64)) );
1732 break;
1733
cerione9d361a2005-03-04 17:35:29 +00001734 case 0x0EB: // mullw (Multiply Low Word, PPC32 p491)
cerionb85e8bb2005-02-16 08:54:33 +00001735 DIP("mullw%s%s r%d,r%d,r%d\n",
1736 flag_OE ? "o" : "", flag_Rc ? "." : "",
1737 Rd_addr, Ra_addr, Rb_addr);
1738 assign( res64, binop(Iop_MullU32, mkexpr(Ra), mkexpr(Rb)) );
1739 assign( Rd, unop(Iop_64to32, mkexpr(res64)) );
cerion70e24122005-03-16 00:27:37 +00001740 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001741 set_XER_OV( PPC32G_FLAG_OP_MULLW,
1742 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb) );
cerion70e24122005-03-16 00:27:37 +00001743 }
cerionb85e8bb2005-02-16 08:54:33 +00001744 break;
cerionc19d5e12005-02-01 15:56:25 +00001745
cerione9d361a2005-03-04 17:35:29 +00001746 case 0x068: // neg (Negate, PPC32 p493)
cerionb85e8bb2005-02-16 08:54:33 +00001747 if (Rb_addr != 0) {
1748 vex_printf("dis_int_arith(PPC32)(neg,Rb_addr)\n");
1749 return False;
1750 }
1751 DIP("neg%s%s r%d,r%d\n",
1752 flag_OE ? "o" : "", flag_Rc ? "." : "",
1753 Rd_addr, Ra_addr);
1754 // rD = (log not)rA + 1
1755 assign( Rd, binop(Iop_Add32,
1756 unop(Iop_Not32, mkexpr(Ra)), mkU32(1)) );
cerion70e24122005-03-16 00:27:37 +00001757 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001758 set_XER_OV( PPC32G_FLAG_OP_NEG,
1759 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb) );
cerion70e24122005-03-16 00:27:37 +00001760 }
cerionb85e8bb2005-02-16 08:54:33 +00001761 break;
cerion91ad5362005-01-27 23:02:41 +00001762
cerione9d361a2005-03-04 17:35:29 +00001763 case 0x028: // subf (Subtract From, PPC32 p537)
cerionb85e8bb2005-02-16 08:54:33 +00001764 DIP("subf%s%s r%d,r%d,r%d\n",
1765 flag_OE ? "o" : "", flag_Rc ? "." : "",
1766 Rd_addr, Ra_addr, Rb_addr);
cerion01908472005-02-25 16:43:08 +00001767 // rD = rB - rA
1768 assign( Rd, binop(Iop_Sub32, mkexpr(Rb), mkexpr(Ra)) );
cerion70e24122005-03-16 00:27:37 +00001769 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001770 set_XER_OV( PPC32G_FLAG_OP_SUBF,
1771 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb) );
cerion70e24122005-03-16 00:27:37 +00001772 }
cerionb85e8bb2005-02-16 08:54:33 +00001773 break;
cerion38674602005-02-08 02:19:25 +00001774
cerione9d361a2005-03-04 17:35:29 +00001775 case 0x008: // subfc (Subtract from Carrying, PPC32 p538)
cerionb85e8bb2005-02-16 08:54:33 +00001776 DIP("subfc%s%s r%d,r%d,r%d\n",
1777 flag_OE ? "o" : "", flag_Rc ? "." : "",
1778 Rd_addr, Ra_addr, Rb_addr);
cerion01908472005-02-25 16:43:08 +00001779 // rD = rB - rA
1780 assign( Rd, binop(Iop_Sub32, mkexpr(Rb), mkexpr(Ra)) );
sewardjb51f0f42005-07-18 11:38:02 +00001781 set_XER_CA( PPC32G_FLAG_OP_SUBFC,
1782 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb),
1783 mkU32(0)/*old xer.ca, which is ignored*/ );
cerion70e24122005-03-16 00:27:37 +00001784 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001785 set_XER_OV( PPC32G_FLAG_OP_SUBFC,
1786 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb) );
cerion70e24122005-03-16 00:27:37 +00001787 }
cerionb85e8bb2005-02-16 08:54:33 +00001788 break;
1789
sewardjb51f0f42005-07-18 11:38:02 +00001790 case 0x088: {// subfe (Subtract from Extended, PPC32 p539)
1791 IRTemp old_xer_ca = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00001792 DIP("subfe%s%s r%d,r%d,r%d\n",
1793 flag_OE ? "o" : "", flag_Rc ? "." : "",
1794 Rd_addr, Ra_addr, Rb_addr);
1795 // rD = (log not)rA + rB + XER[CA]
sewardjb51f0f42005-07-18 11:38:02 +00001796 assign( old_xer_ca, get_XER_CA() );
cerionb85e8bb2005-02-16 08:54:33 +00001797 assign( Rd, binop(Iop_Add32, unop(Iop_Not32, mkexpr(Ra)),
sewardjb51f0f42005-07-18 11:38:02 +00001798 binop(Iop_Add32, mkexpr(Rb), mkexpr(old_xer_ca))) );
1799 set_XER_CA( PPC32G_FLAG_OP_SUBFE,
1800 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb),
1801 mkexpr(old_xer_ca) );
cerion70e24122005-03-16 00:27:37 +00001802 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001803 set_XER_OV( PPC32G_FLAG_OP_SUBFE,
1804 mkexpr(Rd), mkexpr(Ra), mkexpr(Rb) );
cerion70e24122005-03-16 00:27:37 +00001805 }
cerionb85e8bb2005-02-16 08:54:33 +00001806 break;
sewardjb51f0f42005-07-18 11:38:02 +00001807 }
1808
sewardj20ef5472005-07-21 14:48:31 +00001809 case 0x0E8: { // subfme (Subtract from Minus One Extended, PPC32 p541)
1810 IRTemp old_xer_ca = newTemp(Ity_I32);
1811 if (Rb_addr != 0) {
1812 vex_printf("dis_int_arith(PPC32)(subfme,Rb_addr)\n");
1813 return False;
1814 }
1815 DIP("subfme%s%s r%d,r%d\n",
1816 flag_OE ? "o" : "", flag_Rc ? "." : "",
1817 Rd_addr, Ra_addr);
1818 // rD = (log not)rA + (-1) + XER[CA]
1819 // => Just another form of subfe
1820 assign( old_xer_ca, get_XER_CA() );
1821 assign( Rd, binop(Iop_Add32, unop(Iop_Not32, mkexpr(Ra)),
1822 binop(Iop_Add32, mkU32(-1), mkexpr(old_xer_ca))) );
1823 set_XER_CA( PPC32G_FLAG_OP_SUBFE,
1824 mkexpr(Rd), mkexpr(Ra), mkU32(-1),
1825 mkexpr(old_xer_ca) );
1826 if (flag_OE) {
1827 set_XER_OV( PPC32G_FLAG_OP_SUBFE,
1828 mkexpr(Rd), mkexpr(Ra), mkU32(-1) );
1829 }
1830 break;
1831 }
1832
sewardjb51f0f42005-07-18 11:38:02 +00001833 case 0x0C8: { // subfze (Subtract from Zero Extended, PPC32 p542)
1834 IRTemp old_xer_ca = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00001835 if (Rb_addr != 0) {
1836 vex_printf("dis_int_arith(PPC32)(subfze,Rb_addr)\n");
1837 return False;
1838 }
1839 DIP("subfze%s%s r%d,r%d\n",
1840 flag_OE ? "o" : "", flag_Rc ? "." : "",
1841 Rd_addr, Ra_addr);
cerion70e24122005-03-16 00:27:37 +00001842 // rD = (log not)rA + (0) + XER[CA]
1843 // => Just another form of subfe
sewardjb51f0f42005-07-18 11:38:02 +00001844 assign( old_xer_ca, get_XER_CA() );
1845 assign( Rd, binop(Iop_Add32,
1846 unop(Iop_Not32, mkexpr(Ra)), mkexpr(old_xer_ca)) );
1847 set_XER_CA( PPC32G_FLAG_OP_SUBFE,
1848 mkexpr(Rd), mkexpr(Ra), mkU32(0),
1849 mkexpr(old_xer_ca) );
cerion70e24122005-03-16 00:27:37 +00001850 if (flag_OE) {
sewardj20ef5472005-07-21 14:48:31 +00001851 set_XER_OV( PPC32G_FLAG_OP_SUBFE,
1852 mkexpr(Rd), mkexpr(Ra), mkU32(0) );
cerion70e24122005-03-16 00:27:37 +00001853 }
cerionb85e8bb2005-02-16 08:54:33 +00001854 break;
sewardjb51f0f42005-07-18 11:38:02 +00001855 }
cerionae694622005-01-28 17:52:47 +00001856
cerionb85e8bb2005-02-16 08:54:33 +00001857 default:
1858 vex_printf("dis_int_arith(PPC32)(opc2)\n");
1859 return False;
1860 }
1861 break;
1862 default:
1863 vex_printf("dis_int_arith(PPC32)(opc1)\n");
1864 return False;
1865 }
cerion91ad5362005-01-27 23:02:41 +00001866
cerionb85e8bb2005-02-16 08:54:33 +00001867 putIReg( Rd_addr, mkexpr(Rd) );
cerionb85e8bb2005-02-16 08:54:33 +00001868 if (do_rc && flag_Rc) {
sewardj20ef5472005-07-21 14:48:31 +00001869 set_CR0( mkexpr(Rd) );
cerionb85e8bb2005-02-16 08:54:33 +00001870 }
1871 return True;
cerion91ad5362005-01-27 23:02:41 +00001872}
1873
1874
1875
cerion3d870a32005-03-18 12:23:33 +00001876/*
1877 Integer Compare Instructions
1878*/
cerion7aa4bbc2005-01-29 09:32:07 +00001879static Bool dis_int_cmp ( UInt theInstr )
1880{
cerionb85e8bb2005-02-16 08:54:33 +00001881 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
1882 UChar crfD = toUChar((theInstr >> 23) & 0x7); /* theInstr[23:25] */
1883 UChar b9 = toUChar((theInstr >> 22) & 0x1); /* theInstr[22] */
1884 UChar flag_L = toUChar((theInstr >> 21) & 0x1); /* theInstr[21] */
1885 UChar Ra_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
1886
1887 /* D-Form */
cerionb85e8bb2005-02-16 08:54:33 +00001888 UInt UIMM_16 = (theInstr >> 0) & 0xFFFF; /* theInstr[0:15] */
1889
1890 /* X-Form */
1891 UChar Rb_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
1892 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
1893 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
1894
1895 UInt EXTS_SIMM = 0;
cerione9d361a2005-03-04 17:35:29 +00001896 IRTemp Ra = newTemp(Ity_I32);
1897 IRTemp Rb = newTemp(Ity_I32);
1898 IRTemp xer_so = newTemp(Ity_I32);
1899 IRTemp cr7 = newTemp(Ity_I32);
1900 IRTemp mux1 = newTemp(Ity_I32);
1901 IRTemp mux2 = newTemp(Ity_I32);
cerion70e24122005-03-16 00:27:37 +00001902 IRExpr* irx_cmp_lt;
1903 IRExpr* irx_cmp_eq;
cerion7aa4bbc2005-01-29 09:32:07 +00001904
cerionb85e8bb2005-02-16 08:54:33 +00001905 assign( Ra, getIReg(Ra_addr) );
1906
1907 if (flag_L==1) { // L==1 invalid for 32 bit.
1908 vex_printf("dis_int_cmp(PPC32)(flag_L)\n");
1909 return False;
1910 }
1911
1912 if (b9 != 0) {
1913 vex_printf("dis_int_cmp(PPC32)(b9)\n");
1914 return False;
1915 }
1916
1917 switch (opc1) {
sewardjb51f0f42005-07-18 11:38:02 +00001918 case 0x0B: // cmpi (Compare Immediate, PPC32 p368)
1919 EXTS_SIMM = extend_s_16to32(UIMM_16);
1920 DIP("cmp cr%d,r%d,%d\n", crfD, Ra_addr, EXTS_SIMM);
1921 putCR321( crfD, unop(Iop_32to8,
1922 binop(Iop_CmpORD32S, mkexpr(Ra),
1923 mkU32(EXTS_SIMM))) );
1924 putCR0( crfD, getXER_SO() );
1925 break;
1926
1927 case 0x0A: // cmpli (Compare Logical Immediate, PPC32 p370)
1928 DIP("cmpli cr%d,r%d,0x%x\n", crfD, Ra_addr, UIMM_16);
1929 putCR321( crfD, unop(Iop_32to8,
1930 binop(Iop_CmpORD32U, mkexpr(Ra),
1931 mkU32(UIMM_16))) );
1932 putCR0( crfD, getXER_SO() );
1933 break;
cerionb85e8bb2005-02-16 08:54:33 +00001934
1935 /* X Form */
1936 case 0x1F:
1937 if (b0 != 0) {
1938 vex_printf("dis_int_cmp(PPC32)(0x1F,b0)\n");
1939 return False;
1940 }
cerione9d361a2005-03-04 17:35:29 +00001941 assign( Rb, getIReg(Rb_addr) );
sewardjb51f0f42005-07-18 11:38:02 +00001942//zz irx_cmp_eq = binop(Iop_CmpEQ32, mkexpr(Ra), mkexpr(Rb));
cerion7aa4bbc2005-01-29 09:32:07 +00001943
cerionb85e8bb2005-02-16 08:54:33 +00001944 switch (opc2) {
sewardjb51f0f42005-07-18 11:38:02 +00001945 case 0x000: // cmp (Compare, PPC32 p367)
1946 DIP("cmp cr%d,r%d,r%d\n", crfD, Ra_addr, Rb_addr);
1947 putCR321( crfD, unop(Iop_32to8,
1948 binop(Iop_CmpORD32S, mkexpr(Ra), mkexpr(Rb))) );
1949 putCR0( crfD, getXER_SO() );
1950 break;
cerionb85e8bb2005-02-16 08:54:33 +00001951
sewardjb51f0f42005-07-18 11:38:02 +00001952 case 0x020: // cmpl (Compare Logical, PPC32 p369)
1953 DIP("cmpl cr%d,r%d,r%d\n", crfD, Ra_addr, Rb_addr);
1954 putCR321( crfD, unop(Iop_32to8,
1955 binop(Iop_CmpORD32U, mkexpr(Ra), mkexpr(Rb))) );
1956 putCR0( crfD, getXER_SO() );
1957 break;
cerion7aa4bbc2005-01-29 09:32:07 +00001958
sewardjb51f0f42005-07-18 11:38:02 +00001959 default:
1960 vex_printf("dis_int_cmp(PPC32)(opc2)\n");
1961 return False;
cerionb85e8bb2005-02-16 08:54:33 +00001962 }
1963 break;
cerion7aa4bbc2005-01-29 09:32:07 +00001964
cerionb85e8bb2005-02-16 08:54:33 +00001965 default:
1966 vex_printf("dis_int_cmp(PPC32)(opc1)\n");
1967 return False;
1968 }
1969
sewardjb51f0f42005-07-18 11:38:02 +00001970//zz irx_cmp_lt = unop(Iop_1Uto8, irx_cmp_lt);
1971//zz irx_cmp_eq = unop(Iop_1Uto8, irx_cmp_eq);
1972//zz
1973//zz // mux_shift_bit = (argL < argR) ? LT : GT (or EQ...)
1974//zz assign( mux1, IRExpr_Mux0X( irx_cmp_lt, mkU32(SHIFT_CR_GT), mkU32(SHIFT_CR_LT) ));
1975//zz
1976//zz // mux_shift_bit = (argL == argR) ? EQ : GT|LT
1977//zz assign( mux2, IRExpr_Mux0X( irx_cmp_eq, mkexpr(mux1), mkU32(SHIFT_CR_EQ) ));
1978//zz
1979//zz assign( xer_so, getReg_bit( PPC32_SPR_XER, SHIFT_XER_SO ) );
1980//zz assign( cr7, binop(Iop_Or32, mkexpr(mux2), mkexpr(xer_so)) );
1981//zz putReg_field( PPC32_SPR_CR, mkexpr(cr7), 7-crfD );
1982//zz return True;
cerionb85e8bb2005-02-16 08:54:33 +00001983 return True;
cerion7aa4bbc2005-01-29 09:32:07 +00001984}
1985
1986
cerion3d870a32005-03-18 12:23:33 +00001987/*
1988 Integer Logical Instructions
1989*/
cerion7aa4bbc2005-01-29 09:32:07 +00001990static Bool dis_int_logic ( UInt theInstr )
1991{
cerionb85e8bb2005-02-16 08:54:33 +00001992 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
1993 UChar Rs_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
1994 UChar Ra_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
1995
1996 /* D-Form */
1997 UInt UIMM_16 = (theInstr >> 0) & 0xFFFF; /* theInstr[0:15] */
1998
1999 /* X-Form */
2000 UChar Rb_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
2001 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
2002 UChar flag_Rc = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
2003
2004 Bool do_rc = False;
2005
2006 IRTemp Rs = newTemp(Ity_I32);
2007 IRTemp Ra = newTemp(Ity_I32);
2008 IRTemp Rb = newTemp(Ity_I32);
2009 IRTemp Sign = newTemp(Ity_I32);
cerione9d361a2005-03-04 17:35:29 +00002010 IRExpr* irx;
cerionb85e8bb2005-02-16 08:54:33 +00002011
ceriona31e8b52005-02-21 16:30:45 +00002012 assign( Rs, getIReg(Rs_addr) );
2013 assign( Rb, getIReg(Rb_addr) );
cerionb85e8bb2005-02-16 08:54:33 +00002014
2015 switch (opc1) {
cerione9d361a2005-03-04 17:35:29 +00002016 case 0x1C: // andi. (AND Immediate, PPC32 p358)
cerion4561acb2005-02-21 14:07:48 +00002017 DIP("andi. r%d,r%d,0x%x\n", Ra_addr, Rs_addr, UIMM_16);
cerionb85e8bb2005-02-16 08:54:33 +00002018 assign( Ra, binop(Iop_And32, mkexpr(Rs), mkU32(UIMM_16)) );
cerion70e24122005-03-16 00:27:37 +00002019 do_rc = True; // Always record to CR
cerionb85e8bb2005-02-16 08:54:33 +00002020 flag_Rc = 1;
2021 break;
2022
cerione9d361a2005-03-04 17:35:29 +00002023 case 0x1D: // andis. (AND Immediate Shifted, PPC32 p359)
cerionb85e8bb2005-02-16 08:54:33 +00002024 DIP("andis r%d,r%d,0x%x\n", Ra_addr, Rs_addr, UIMM_16);
2025 assign( Ra, binop(Iop_And32, mkexpr(Rs), mkU32(UIMM_16 << 16)) );
cerion70e24122005-03-16 00:27:37 +00002026 do_rc = True; // Always record to CR
cerionb85e8bb2005-02-16 08:54:33 +00002027 flag_Rc = 1;
2028 break;
cerion7aa4bbc2005-01-29 09:32:07 +00002029
cerione9d361a2005-03-04 17:35:29 +00002030 case 0x18: // ori (OR Immediate, PPC32 p497)
cerionb85e8bb2005-02-16 08:54:33 +00002031 DIP("ori r%d,r%d,0x%x\n", Ra_addr, Rs_addr, UIMM_16);
cerion70e24122005-03-16 00:27:37 +00002032 assign( Ra, binop(Iop_Or32, mkexpr(Rs), mkU32(UIMM_16)) );
cerionb85e8bb2005-02-16 08:54:33 +00002033 break;
cerion7aa4bbc2005-01-29 09:32:07 +00002034
cerione9d361a2005-03-04 17:35:29 +00002035 case 0x19: // oris (OR Immediate Shifted, PPC32 p498)
cerionb85e8bb2005-02-16 08:54:33 +00002036 DIP("oris r%d,r%d,0x%x\n", Ra_addr, Rs_addr, UIMM_16);
cerion70e24122005-03-16 00:27:37 +00002037 assign( Ra, binop(Iop_Or32, mkexpr(Rs), mkU32(UIMM_16 << 16)) );
cerionb85e8bb2005-02-16 08:54:33 +00002038 break;
cerionaabdfbf2005-01-29 12:56:15 +00002039
cerione9d361a2005-03-04 17:35:29 +00002040 case 0x1A: // xori (XOR Immediate, PPC32 p550)
cerionb85e8bb2005-02-16 08:54:33 +00002041 DIP("xori r%d,r%d,0x%x\n", Ra_addr, Rs_addr, UIMM_16);
cerion70e24122005-03-16 00:27:37 +00002042 assign( Ra, binop(Iop_Xor32, mkexpr(Rs), mkU32(UIMM_16)) );
cerionb85e8bb2005-02-16 08:54:33 +00002043 break;
cerion38674602005-02-08 02:19:25 +00002044
cerione9d361a2005-03-04 17:35:29 +00002045 case 0x1B: // xoris (XOR Immediate Shifted, PPC32 p551)
cerionb85e8bb2005-02-16 08:54:33 +00002046 DIP("xoris r%d,r%d,0x%x\n", Ra_addr, Rs_addr, UIMM_16);
cerion70e24122005-03-16 00:27:37 +00002047 assign( Ra, binop(Iop_Xor32, mkexpr(Rs), mkU32(UIMM_16 << 16)) );
cerionb85e8bb2005-02-16 08:54:33 +00002048 break;
cerionaabdfbf2005-01-29 12:56:15 +00002049
cerionb85e8bb2005-02-16 08:54:33 +00002050 /* X Form */
2051 case 0x1F:
cerion70e24122005-03-16 00:27:37 +00002052 do_rc = True; // All below record to CR
2053
cerionb85e8bb2005-02-16 08:54:33 +00002054 switch (opc2) {
sewardjb51f0f42005-07-18 11:38:02 +00002055 case 0x01C: // and (AND, PPC32 p356)
2056 DIP("and%s r%d,r%d,r%d\n",
2057 flag_Rc ? "." : "", Ra_addr, Rs_addr, Rb_addr);
2058 assign(Ra, binop(Iop_And32, mkexpr(Rs), mkexpr(Rb)));
2059 break;
cerionb85e8bb2005-02-16 08:54:33 +00002060
sewardjb51f0f42005-07-18 11:38:02 +00002061 case 0x03C: // andc (AND with Complement, PPC32 p357)
2062 DIP("andc%s r%d,r%d,r%d\n",
2063 flag_Rc ? "." : "", Ra_addr, Rs_addr, Rb_addr);
2064 assign(Ra, binop(Iop_And32, mkexpr(Rs),
2065 unop(Iop_Not32, mkexpr(Rb))));
2066 break;
2067
2068 case 0x01A: // cntlzw (Count Leading Zeros Word, PPC32 p371)
2069 if (Rb_addr!=0) {
2070 vex_printf("dis_int_logic(PPC32)(cntlzw,Rb_addr)\n");
2071 return False;
2072 }
2073 DIP("cntlzw%s r%d,r%d\n",
2074 flag_Rc ? "." : "", Ra_addr, Rs_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002075
sewardjb51f0f42005-07-18 11:38:02 +00002076 // Iop_Clz32 undefined for arg==0, so deal with that case:
2077 irx = binop(Iop_CmpNE32, mkexpr(Rs), mkU32(0));
2078 assign(Ra, IRExpr_Mux0X( unop(Iop_1Uto8, irx),
2079 mkU32(32),
2080 unop(Iop_Clz32, mkexpr(Rs)) ));
2081 break;
cerion7aa4bbc2005-01-29 09:32:07 +00002082
sewardj20ef5472005-07-21 14:48:31 +00002083 case 0x11C: // eqv (Equivalent, PPC32 p396)
2084 DIP("eqv%s r%d,r%d,r%d\n",
2085 flag_Rc ? "." : "", Ra_addr, Rs_addr, Rb_addr);
2086 assign( Ra, unop(Iop_Not32, binop(Iop_Xor32,
2087 mkexpr(Rs), mkexpr(Rb))) );
2088 break;
cerion7aa4bbc2005-01-29 09:32:07 +00002089
cerione9d361a2005-03-04 17:35:29 +00002090 case 0x3BA: // extsb (Extend Sign Byte, PPC32 p397
cerionb85e8bb2005-02-16 08:54:33 +00002091 if (Rb_addr!=0) {
2092 vex_printf("dis_int_logic(PPC32)(extsb,Rb_addr)\n");
2093 return False;
2094 }
2095 DIP("extsb%s r%d,r%d\n",
2096 flag_Rc ? "." : "", Ra_addr, Rs_addr);
sewardjb51f0f42005-07-18 11:38:02 +00002097 assign( Ra, unop(Iop_8Sto32, unop(Iop_32to8, mkexpr(Rs))) );
cerionb85e8bb2005-02-16 08:54:33 +00002098 break;
cerion7aa4bbc2005-01-29 09:32:07 +00002099
cerione9d361a2005-03-04 17:35:29 +00002100 case 0x39A: // extsh (Extend Sign Half Word, PPC32 p398)
cerionb85e8bb2005-02-16 08:54:33 +00002101 if (Rb_addr!=0) {
2102 vex_printf("dis_int_logic(PPC32)(extsh,Rb_addr)\n");
2103 return False;
2104 }
2105 DIP("extsh%s r%d,r%d\n",
2106 flag_Rc ? "." : "", Ra_addr, Rs_addr);
sewardjb51f0f42005-07-18 11:38:02 +00002107 assign( Ra, unop(Iop_16Sto32, unop(Iop_32to16, mkexpr(Rs))) );
cerionb85e8bb2005-02-16 08:54:33 +00002108 break;
cerion7aa4bbc2005-01-29 09:32:07 +00002109
cerione9d361a2005-03-04 17:35:29 +00002110 case 0x1DC: // nand (NAND, PPC32 p492)
cerionb85e8bb2005-02-16 08:54:33 +00002111 DIP("nand%s r%d,r%d,r%d\n",
2112 flag_Rc ? "." : "", Ra_addr, Rs_addr, Rb_addr);
2113 assign( Ra, unop(Iop_Not32,
2114 binop(Iop_And32, mkexpr(Rs), mkexpr(Rb))) );
2115 break;
2116
cerione9d361a2005-03-04 17:35:29 +00002117 case 0x07C: // nor (NOR, PPC32 p494)
cerionb85e8bb2005-02-16 08:54:33 +00002118 DIP("nor%s r%d,r%d,r%d\n",
2119 flag_Rc ? "." : "", Ra_addr, Rs_addr, Rb_addr);
2120 assign( Ra, unop(Iop_Not32,
2121 binop(Iop_Or32, mkexpr(Rs), mkexpr(Rb))) );
2122 break;
cerion7aa4bbc2005-01-29 09:32:07 +00002123
cerione9d361a2005-03-04 17:35:29 +00002124 case 0x1BC: // or (OR, PPC32 p495)
sewardjb51f0f42005-07-18 11:38:02 +00002125 if ((!flag_Rc) && Rs_addr == Rb_addr) {
2126 DIP("mr r%d,r%d\n", Ra_addr, Rs_addr);
2127 assign( Ra, mkexpr(Rs) );
2128 } else {
2129 DIP("or%s r%d,r%d,r%d\n",
2130 flag_Rc ? "." : "", Ra_addr, Rs_addr, Rb_addr);
2131 assign( Ra, binop(Iop_Or32, mkexpr(Rs), mkexpr(Rb)) );
2132 }
cerionb85e8bb2005-02-16 08:54:33 +00002133 break;
cerion7aa4bbc2005-01-29 09:32:07 +00002134
cerione9d361a2005-03-04 17:35:29 +00002135 case 0x19C: // orc (OR with Complement, PPC32 p496)
cerionb85e8bb2005-02-16 08:54:33 +00002136 DIP("orc%s r%d,r%d,r%d\n",
2137 flag_Rc ? "." : "", Ra_addr, Rs_addr, Rb_addr);
2138 assign( Ra, binop(Iop_Or32, mkexpr(Rs),
2139 unop(Iop_Not32, mkexpr(Rb))) );
2140 break;
2141
cerione9d361a2005-03-04 17:35:29 +00002142 case 0x13C: // xor (XOR, PPC32 p549)
cerionb85e8bb2005-02-16 08:54:33 +00002143 DIP("xor%s r%d,r%d,r%d\n",
2144 flag_Rc ? "." : "", Ra_addr, Rs_addr, Rb_addr);
2145 assign( Ra, binop(Iop_Xor32, mkexpr(Rs), mkexpr(Rb)) );
2146 break;
cerion7aa4bbc2005-01-29 09:32:07 +00002147
cerionb85e8bb2005-02-16 08:54:33 +00002148 default:
2149 vex_printf("dis_int_logic(PPC32)(opc2)\n");
2150 return False;
2151 }
cerionb85e8bb2005-02-16 08:54:33 +00002152 break;
2153
2154 default:
2155 vex_printf("dis_int_logic(PPC32)(opc1)\n");
2156 return False;
2157 }
cerion70e24122005-03-16 00:27:37 +00002158
2159 putIReg( Ra_addr, mkexpr(Ra) );
cerionb85e8bb2005-02-16 08:54:33 +00002160 if (do_rc && flag_Rc) {
sewardj20ef5472005-07-21 14:48:31 +00002161 set_CR0( mkexpr(Ra) );
cerionb85e8bb2005-02-16 08:54:33 +00002162 }
2163 return True;
cerion645c9302005-01-31 10:09:59 +00002164}
2165
2166
2167
cerion3d870a32005-03-18 12:23:33 +00002168/*
2169 Integer Rotate Instructions
2170*/
cerion645c9302005-01-31 10:09:59 +00002171static Bool dis_int_rot ( UInt theInstr )
2172{
cerionb85e8bb2005-02-16 08:54:33 +00002173 /* M-Form */
2174 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
2175 UChar Rs_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
2176 UChar Ra_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
2177 UChar Rb_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
2178 UChar sh_imm = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
2179 UChar MaskBegin = toUChar((theInstr >> 6) & 0x1F); /* theInstr[6:10] */
2180 UChar MaskEnd = toUChar((theInstr >> 1) & 0x1F); /* theInstr[1:5] */
2181 UChar flag_Rc = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
2182
cerion239e2e42005-02-24 16:59:17 +00002183 UInt mask = MASK(31-MaskEnd, 31-MaskBegin);
cerionb85e8bb2005-02-16 08:54:33 +00002184 IRTemp rot_amt = newTemp(Ity_I8);
2185 IRTemp Rs = newTemp(Ity_I32);
2186 IRTemp Ra = newTemp(Ity_I32);
2187 IRTemp Rb = newTemp(Ity_I32);
2188
2189 assign( Rs, getIReg(Rs_addr) );
2190 assign( Rb, getIReg(Rb_addr) );
cerione9d361a2005-03-04 17:35:29 +00002191
cerionb85e8bb2005-02-16 08:54:33 +00002192 switch (opc1) {
cerione9d361a2005-03-04 17:35:29 +00002193 case 0x14: // rlwimi (Rotate Left Word Immediate then Mask Insert, PPC32 p500)
sewardjdb36c0f2005-07-03 00:05:31 +00002194 DIP("rlwimi%s r%d,r%d,%d,%d,%d\n", flag_Rc ? "." : "",
cerionb85e8bb2005-02-16 08:54:33 +00002195 Ra_addr, Rs_addr, sh_imm, MaskBegin, MaskEnd);
2196 // Ra = (ROTL(Rs, Imm) & mask) | (Ra & ~mask);
2197 assign( Ra, binop(Iop_Or32,
2198 binop(Iop_And32, mkU32(mask),
sewardjb51f0f42005-07-18 11:38:02 +00002199 ROTL32(mkexpr(Rs), sh_imm)),
cerionb85e8bb2005-02-16 08:54:33 +00002200 binop(Iop_And32, getIReg(Ra_addr), mkU32(~mask))) );
2201 break;
cerion645c9302005-01-31 10:09:59 +00002202
cerione9d361a2005-03-04 17:35:29 +00002203 case 0x15: // rlwinm (Rotate Left Word Immediate then AND with Mask, PPC32 p501)
sewardjdb36c0f2005-07-03 00:05:31 +00002204 DIP("rlwinm%s r%d,r%d,%d,%d,%d\n", flag_Rc ? "." : "",
cerionb85e8bb2005-02-16 08:54:33 +00002205 Ra_addr, Rs_addr, sh_imm, MaskBegin, MaskEnd);
2206 // Ra = ROTL(Rs, Imm) & mask
sewardjb51f0f42005-07-18 11:38:02 +00002207 assign( Ra, binop(Iop_And32, ROTL32(mkexpr(Rs), sh_imm),
2208 mkU32(mask)) );
cerionb85e8bb2005-02-16 08:54:33 +00002209 break;
cerion45b70ff2005-01-31 17:03:25 +00002210
sewardjb51f0f42005-07-18 11:38:02 +00002211//zz case 0x17: // rlwnm (Rotate Left Word then AND with Mask, PPC32 p503
2212//zz DIP("rlwnm%s r%d,r%d,r%d,%d,%d\n", flag_Rc ? "." : "",
2213//zz Ra_addr, Rs_addr, Rb_addr, MaskBegin, MaskEnd);
2214//zz // Ra = ROTL(Rs, Rb[0-4]) & mask
2215//zz assign( rot_amt,
2216//zz unop(Iop_32to8, binop(Iop_And32, mkexpr(Rb), mkU32(0x1F))) );
2217//zz assign( Ra, binop(Iop_And32,
2218//zz ROTL32(mkexpr(Rs), mkexpr(rot_amt)), mkU32(mask)) );
2219//zz break;
cerion45b70ff2005-01-31 17:03:25 +00002220
cerionb85e8bb2005-02-16 08:54:33 +00002221 default:
2222 vex_printf("dis_int_rot(PPC32)(opc1)\n");
2223 return False;
2224 }
cerion645c9302005-01-31 10:09:59 +00002225
cerionb85e8bb2005-02-16 08:54:33 +00002226 putIReg( Ra_addr, mkexpr(Ra) );
2227 if (flag_Rc) {
sewardj20ef5472005-07-21 14:48:31 +00002228 set_CR0( mkexpr(Ra) );
cerionb85e8bb2005-02-16 08:54:33 +00002229 }
2230 return True;
cerion645c9302005-01-31 10:09:59 +00002231}
2232
2233
2234
cerion3d870a32005-03-18 12:23:33 +00002235/*
2236 Integer Load Instructions
2237*/
cerion645c9302005-01-31 10:09:59 +00002238static Bool dis_int_load ( UInt theInstr )
2239{
cerionb85e8bb2005-02-16 08:54:33 +00002240 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
2241 UChar Rd_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
2242 UChar Ra_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
2243
2244 /* D-Form */
2245 UInt d_imm = (theInstr >> 0) & 0xFFFF; /* theInstr[0:15] */
2246
2247 /* X-Form */
2248 UChar Rb_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
2249 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
2250 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
2251
2252 UInt exts_d_imm = extend_s_16to32(d_imm);
2253
2254 IRTemp Ra_or_0 = newTemp(Ity_I32);
2255 IRTemp EA_imm = newTemp(Ity_I32);
2256 IRTemp EA_reg = newTemp(Ity_I32);
2257 IRTemp Ra = newTemp(Ity_I32);
2258 IRTemp Rb = newTemp(Ity_I32);
2259
2260 assign( Ra, getIReg(Ra_addr) );
2261 assign( Rb, getIReg(Rb_addr) );
2262
cerione9d361a2005-03-04 17:35:29 +00002263 assign( Ra_or_0, ((Ra_addr == 0) ? mkU32(0) : mkexpr(Ra)) );
2264
ceriond05ee442005-02-16 18:05:16 +00002265 assign( EA_imm, binop(Iop_Add32, mkexpr(Ra_or_0), mkU32(exts_d_imm)) );
cerionb85e8bb2005-02-16 08:54:33 +00002266
2267 switch (opc1) {
cerione9d361a2005-03-04 17:35:29 +00002268 case 0x22: // lbz (Load B & Zero, PPC32 p433)
sewardjb51f0f42005-07-18 11:38:02 +00002269 DIP("lbz r%d,%d(r%d)\n", Rd_addr, exts_d_imm, Ra_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002270 putIReg( Rd_addr, unop(Iop_8Uto32,
2271 loadBE(Ity_I8, mkexpr(EA_imm))) );
2272 break;
2273
cerione9d361a2005-03-04 17:35:29 +00002274 case 0x23: // lbzu (Load B & Zero with Update, PPC32 p434)
cerionb85e8bb2005-02-16 08:54:33 +00002275 if (Ra_addr == 0 || Ra_addr == Rd_addr) {
2276 vex_printf("dis_int_load(PPC32)(lbzu,Ra_addr|Rd_addr)\n");
2277 return False;
2278 }
sewardjb51f0f42005-07-18 11:38:02 +00002279 DIP("lbzu r%d,%d(r%d)\n", Rd_addr, exts_d_imm, Ra_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002280 putIReg( Rd_addr, unop(Iop_8Uto32,
2281 loadBE(Ity_I8, mkexpr(EA_imm))) );
2282 putIReg( Ra_addr, mkexpr(EA_imm) );
2283 break;
2284
cerione9d361a2005-03-04 17:35:29 +00002285 case 0x2A: // lha (Load HW Algebraic, PPC32 p445)
sewardjb51f0f42005-07-18 11:38:02 +00002286 DIP("lha r%d,%d(r%d)\n", Rd_addr, exts_d_imm, Ra_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002287 putIReg( Rd_addr, unop(Iop_16Sto32,
2288 loadBE(Ity_I16, mkexpr(EA_imm))) );
2289 break;
cerion645c9302005-01-31 10:09:59 +00002290
sewardjb51f0f42005-07-18 11:38:02 +00002291//zz case 0x2B: // lhau (Load HW Algebraic with Update, PPC32 p446)
2292//zz if (Ra_addr == 0 || Ra_addr == Rd_addr) {
2293//zz vex_printf("dis_int_load(PPC32)(lhau,Ra_addr|Rd_addr)\n");
2294//zz return False;
2295//zz }
2296//zz DIP("lhau r%d,%d(r%d)\n", Rd_addr, (Int)d_imm, Ra_addr);
2297//zz putIReg( Rd_addr, unop(Iop_16Sto32,
2298//zz loadBE(Ity_I16, mkexpr(EA_imm))) );
2299//zz putIReg( Ra_addr, mkexpr(EA_imm) );
2300//zz break;
cerionb85e8bb2005-02-16 08:54:33 +00002301
cerione9d361a2005-03-04 17:35:29 +00002302 case 0x28: // lhz (Load HW & Zero, PPC32 p450)
sewardjb51f0f42005-07-18 11:38:02 +00002303 DIP("lhz r%d,%d(r%d)\n", Rd_addr, exts_d_imm, Ra_addr);
cerione67534c2005-02-25 20:47:36 +00002304 putIReg( Rd_addr, unop(Iop_16Uto32,
cerionb85e8bb2005-02-16 08:54:33 +00002305 loadBE(Ity_I16, mkexpr(EA_imm))) );
2306 break;
2307
sewardjb51f0f42005-07-18 11:38:02 +00002308//zz case 0x29: // lhzu (Load HW & and Zero with Update, PPC32 p451)
2309//zz if (Ra_addr == 0 || Ra_addr == Rd_addr) {
2310//zz vex_printf("dis_int_load(PPC32)(lhzu,Ra_addr|Rd_addr)\n");
2311//zz return False;
2312//zz }
2313//zz DIP("lhzu r%d,%d(r%d)\n", Rd_addr, (Int)d_imm, Ra_addr);
2314//zz putIReg( Rd_addr, unop(Iop_16Uto32,
2315//zz loadBE(Ity_I16, mkexpr(EA_imm))) );
2316//zz putIReg( Ra_addr, mkexpr(EA_imm) );
2317//zz break;
cerion645c9302005-01-31 10:09:59 +00002318
cerione9d361a2005-03-04 17:35:29 +00002319 case 0x20: // lwz (Load W & Zero, PPC32 p460)
sewardjb51f0f42005-07-18 11:38:02 +00002320 DIP("lwz r%d,%d(r%d)\n", Rd_addr, exts_d_imm, Ra_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002321 putIReg( Rd_addr, loadBE(Ity_I32, mkexpr(EA_imm)) );
2322 break;
2323
cerione9d361a2005-03-04 17:35:29 +00002324 case 0x21: // lwzu (Load W & Zero with Update, PPC32 p461))
cerionb85e8bb2005-02-16 08:54:33 +00002325 if (Ra_addr == 0 || Ra_addr == Rd_addr) {
2326 vex_printf("dis_int_load(PPC32)(lwzu,Ra_addr|Rd_addr)\n");
2327 return False;
2328 }
sewardjb51f0f42005-07-18 11:38:02 +00002329 DIP("lwzu r%d,%d(r%d)\n", Rd_addr, exts_d_imm, Ra_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002330 putIReg( Rd_addr, loadBE(Ity_I32, mkexpr(EA_imm)) );
2331 putIReg( Ra_addr, mkexpr(EA_imm) );
2332 break;
2333
2334 /* X Form */
2335 case 0x1F:
2336 if (b0 != 0) {
2337 vex_printf("dis_int_load(PPC32)(Ox1F,b0)\n");
2338 return False;
2339 }
cerion7c1dd1b2005-02-22 18:39:18 +00002340 assign( EA_reg, binop(Iop_Add32, mkexpr(Ra_or_0), mkexpr(Rb)) );
cerion645c9302005-01-31 10:09:59 +00002341
cerionb85e8bb2005-02-16 08:54:33 +00002342 switch (opc2) {
cerione9d361a2005-03-04 17:35:29 +00002343 case 0x077: // lbzux (Load B & Zero with Update Indexed, PPC32 p435)
cerionb85e8bb2005-02-16 08:54:33 +00002344 DIP("lbzux r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
2345 if (Ra_addr == 0 || Ra_addr == Rd_addr) {
2346 vex_printf("dis_int_load(PPC32)(lwzux,Ra_addr|Rd_addr)\n");
2347 return False;
2348 }
2349 putIReg( Rd_addr, unop(Iop_8Uto32,
2350 loadBE(Ity_I8, mkexpr(EA_reg))) );
2351 putIReg( Ra_addr, mkexpr(EA_reg) );
2352 break;
2353
cerione9d361a2005-03-04 17:35:29 +00002354 case 0x057: // lbzx (Load B & Zero Indexed, PPC32 p436)
cerionb85e8bb2005-02-16 08:54:33 +00002355 DIP("lbzx r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
2356 putIReg( Rd_addr, unop(Iop_8Uto32,
2357 loadBE(Ity_I8, mkexpr(EA_reg))) );
2358 break;
2359
sewardjb51f0f42005-07-18 11:38:02 +00002360//zz case 0x177: // lhaux (Load HW Algebraic with Update Indexed, PPC32 p447)
2361//zz if (Ra_addr == 0 || Ra_addr == Rd_addr) {
2362//zz vex_printf("dis_int_load(PPC32)(lhaux,Ra_addr|Rd_addr)\n");
2363//zz return False;
2364//zz }
2365//zz DIP("lhaux r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
2366//zz putIReg( Rd_addr, unop(Iop_16Sto32,
2367//zz loadBE(Ity_I16, mkexpr(EA_reg))) );
2368//zz putIReg( Ra_addr, mkexpr(EA_reg) );
2369//zz break;
cerionb85e8bb2005-02-16 08:54:33 +00002370
cerione9d361a2005-03-04 17:35:29 +00002371 case 0x157: // lhax (Load HW Algebraic Indexed, PPC32 p448)
cerionb85e8bb2005-02-16 08:54:33 +00002372 DIP("lhax r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
2373 putIReg( Rd_addr, unop(Iop_16Sto32,
2374 loadBE(Ity_I16, mkexpr(EA_reg))) );
2375 break;
2376
cerione9d361a2005-03-04 17:35:29 +00002377 case 0x137: // lhzux (Load HW & Zero with Update Indexed, PPC32 p452)
cerionb85e8bb2005-02-16 08:54:33 +00002378 if (Ra_addr == 0 || Ra_addr == Rd_addr) {
2379 vex_printf("dis_int_load(PPC32)(lhzux,Ra_addr|Rd_addr)\n");
2380 return False;
2381 }
2382 DIP("lhzux r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
cerione67534c2005-02-25 20:47:36 +00002383 putIReg( Rd_addr, unop(Iop_16Uto32,
cerionb85e8bb2005-02-16 08:54:33 +00002384 loadBE(Ity_I16, mkexpr(EA_reg))) );
2385 putIReg( Ra_addr, mkexpr(EA_reg) );
2386 break;
2387
cerione9d361a2005-03-04 17:35:29 +00002388 case 0x117: // lhzx (Load HW & Zero Indexed, PPC32 p453)
cerionb85e8bb2005-02-16 08:54:33 +00002389 DIP("lhzx r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
cerione67534c2005-02-25 20:47:36 +00002390 putIReg( Rd_addr, unop(Iop_16Uto32,
cerionb85e8bb2005-02-16 08:54:33 +00002391 loadBE(Ity_I16, mkexpr(EA_reg))) );
2392 break;
cerion44997f22005-01-31 18:45:59 +00002393
sewardjb51f0f42005-07-18 11:38:02 +00002394//zz case 0x037: // lwzux (Load W & Zero with Update Indexed, PPC32 p462)
2395//zz if (Ra_addr == 0 || Ra_addr == Rd_addr) {
2396//zz vex_printf("dis_int_load(PPC32)(lwzux,Ra_addr|Rd_addr)\n");
2397//zz return False;
2398//zz }
2399//zz DIP("lwzux r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
2400//zz putIReg( Rd_addr, loadBE(Ity_I32, mkexpr(EA_reg)) );
2401//zz putIReg( Ra_addr, mkexpr(EA_reg) );
2402//zz break;
cerionb85e8bb2005-02-16 08:54:33 +00002403
cerione9d361a2005-03-04 17:35:29 +00002404 case 0x017: // lwzx (Load W & Zero Indexed, PPC32 p463)
cerionb85e8bb2005-02-16 08:54:33 +00002405 DIP("lwzx r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
2406 putIReg( Rd_addr, loadBE(Ity_I32, mkexpr(EA_reg)) );
2407 break;
cerion44997f22005-01-31 18:45:59 +00002408
cerionb85e8bb2005-02-16 08:54:33 +00002409 default:
2410 vex_printf("dis_int_load(PPC32)(opc2)\n");
2411 return False;
2412 }
2413 break;
2414 default:
2415 vex_printf("dis_int_load(PPC32)(opc1)\n");
2416 return False;
2417 }
2418 return True;
cerion7aa4bbc2005-01-29 09:32:07 +00002419}
2420
2421
2422
cerion3d870a32005-03-18 12:23:33 +00002423/*
2424 Integer Store Instructions
2425*/
ceriond23be4e2005-01-31 07:23:07 +00002426static Bool dis_int_store ( UInt theInstr )
2427{
sewardjb51f0f42005-07-18 11:38:02 +00002428 UInt opc1 = ifieldOPC(theInstr); /* theInstr[26:31] */
2429 UInt Rs_addr = ifieldRD(theInstr); /* theInstr[21:25] */
2430 UInt Ra_addr = ifieldRA(theInstr); /* theInstr[16:20] */
cerionb85e8bb2005-02-16 08:54:33 +00002431
2432 /* D-Form */
sewardjb51f0f42005-07-18 11:38:02 +00002433 Int simm16 = ifieldSIMM16(theInstr); /* theInstr[0:15] */
cerionb85e8bb2005-02-16 08:54:33 +00002434
2435 /* X-Form */
sewardjb51f0f42005-07-18 11:38:02 +00002436 UInt Rb_addr = ifieldRB(theInstr); /* theInstr[11:15] */
2437 UInt opc2 = ifieldOPClo10(theInstr); /* theInstr[1:10] */
2438 UInt b0 = ifieldBIT0(theInstr); /* theInstr[0] */
2439
cerionb85e8bb2005-02-16 08:54:33 +00002440 IRTemp Ra = newTemp(Ity_I32);
2441 IRTemp Ra_or_0 = newTemp(Ity_I32);
2442 IRTemp Rb = newTemp(Ity_I32);
2443 IRTemp Rs = newTemp(Ity_I32);
sewardjb51f0f42005-07-18 11:38:02 +00002444// IRTemp Rs_8 = newTemp(Ity_I8);
2445//IRTemp Rs_16 = newTemp(Ity_I16);
cerionb85e8bb2005-02-16 08:54:33 +00002446 IRTemp EA_imm = newTemp(Ity_I32);
2447 IRTemp EA_reg = newTemp(Ity_I32);
2448
2449 assign( Ra, getIReg(Ra_addr) );
2450 assign( Rb, getIReg(Rb_addr) );
2451 assign( Rs, getIReg(Rs_addr) );
sewardjb51f0f42005-07-18 11:38:02 +00002452 //assign( Rs_8, unop(Iop_32to8, mkexpr(Rs)) );
2453 //assign( Rs_16, unop(Iop_32to16, mkexpr(Rs)) );
cerionb85e8bb2005-02-16 08:54:33 +00002454
2455 if (Ra_addr == 0) {
2456 assign( Ra_or_0, mkU32(0) );
2457 } else {
2458 assign( Ra_or_0, mkexpr(Ra) );
2459 }
sewardjb51f0f42005-07-18 11:38:02 +00002460 assign( EA_imm, binop(Iop_Add32, mkexpr(Ra_or_0), mkU32(simm16)) );
cerionb85e8bb2005-02-16 08:54:33 +00002461
2462 switch (opc1) {
sewardjb51f0f42005-07-18 11:38:02 +00002463 case 0x26: // stb (Store B, PPC32 p509)
2464 DIP("stb r%d,%d(r%d)\n", Rs_addr, simm16, Ra_addr);
2465 storeBE( mkexpr(EA_imm), unop(Iop_32to8, mkexpr(Rs)) );
2466 break;
2467
cerione9d361a2005-03-04 17:35:29 +00002468 case 0x27: // stbu (Store B with Update, PPC32 p510)
cerionb85e8bb2005-02-16 08:54:33 +00002469 if (Ra_addr == 0 ) {
2470 vex_printf("dis_int_store(PPC32)(stbu,Ra_addr)\n");
2471 return False;
2472 }
sewardjb51f0f42005-07-18 11:38:02 +00002473 DIP("stbu r%d,%d(r%d)\n", Rs_addr, simm16, Ra_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002474 putIReg( Ra_addr, mkexpr(EA_imm) );
sewardjb51f0f42005-07-18 11:38:02 +00002475 storeBE( mkexpr(EA_imm), unop(Iop_32to8, mkexpr(Rs)) );
cerionb85e8bb2005-02-16 08:54:33 +00002476 break;
ceriond23be4e2005-01-31 07:23:07 +00002477
cerione9d361a2005-03-04 17:35:29 +00002478 case 0x2C: // sth (Store HW, PPC32 p522)
sewardjb51f0f42005-07-18 11:38:02 +00002479 DIP("sth r%d,%d(r%d)\n", Rs_addr, simm16, Ra_addr);
2480 storeBE( mkexpr(EA_imm), unop(Iop_32to16, mkexpr(Rs)) );
cerionb85e8bb2005-02-16 08:54:33 +00002481 break;
2482
cerione9d361a2005-03-04 17:35:29 +00002483 case 0x2D: // sthu (Store HW with Update, PPC32 p524)
cerionb85e8bb2005-02-16 08:54:33 +00002484 if (Ra_addr == 0) {
2485 vex_printf("dis_int_store(PPC32)(sthu,Ra_addr)\n");
2486 return False;
2487 }
sewardjb51f0f42005-07-18 11:38:02 +00002488 DIP("sthu r%d,%d(r%d)\n", Rs_addr, simm16, Ra_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002489 putIReg( Ra_addr, mkexpr(EA_imm) );
sewardjb51f0f42005-07-18 11:38:02 +00002490 storeBE( mkexpr(EA_imm), unop(Iop_32to16, mkexpr(Rs)) );
cerionb85e8bb2005-02-16 08:54:33 +00002491 break;
ceriond23be4e2005-01-31 07:23:07 +00002492
cerione9d361a2005-03-04 17:35:29 +00002493 case 0x24: // stw (Store W, PPC32 p530)
sewardjb51f0f42005-07-18 11:38:02 +00002494 DIP("stw r%d,%d(r%d)\n", Rs_addr, simm16, Ra_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002495 storeBE( mkexpr(EA_imm), mkexpr(Rs) );
2496 break;
ceriond23be4e2005-01-31 07:23:07 +00002497
cerione9d361a2005-03-04 17:35:29 +00002498 case 0x25: // stwu (Store W with Update, PPC32 p534)
cerionb85e8bb2005-02-16 08:54:33 +00002499 if (Ra_addr == 0) {
2500 vex_printf("dis_int_store(PPC32)(stwu,Ra_addr)\n");
2501 return False;
2502 }
sewardjb51f0f42005-07-18 11:38:02 +00002503 DIP("stwu r%d,%d(r%d)\n", Rs_addr, simm16, Ra_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002504 putIReg( Ra_addr, mkexpr(EA_imm) );
cerioned623db2005-06-20 12:42:04 +00002505 storeBE( mkexpr(EA_imm), mkexpr(Rs) );
cerionb85e8bb2005-02-16 08:54:33 +00002506 break;
2507
2508 /* X Form */
2509 case 0x1F:
2510 if (b0 != 0) {
2511 vex_printf("dis_int_store(PPC32)(0x1F,b0)\n");
2512 return False;
2513 }
cerion7c1dd1b2005-02-22 18:39:18 +00002514 assign( EA_reg, binop(Iop_Add32, mkexpr(Ra_or_0), mkexpr(Rb)) );
cerion44997f22005-01-31 18:45:59 +00002515
cerionb85e8bb2005-02-16 08:54:33 +00002516 switch (opc2) {
cerione9d361a2005-03-04 17:35:29 +00002517 case 0x0F7: // stbux (Store B with Update Indexed, PPC32 p511)
cerionb85e8bb2005-02-16 08:54:33 +00002518 if (Ra_addr == 0) {
2519 vex_printf("dis_int_store(PPC32)(stbux,Ra_addr)\n");
2520 return False;
2521 }
2522 DIP("stbux r%d,r%d,r%d\n", Rs_addr, Ra_addr, Rb_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002523 putIReg( Ra_addr, mkexpr(EA_reg) );
sewardjb51f0f42005-07-18 11:38:02 +00002524 storeBE( mkexpr(EA_reg), unop(Iop_32to8, mkexpr(Rs)) );
cerionb85e8bb2005-02-16 08:54:33 +00002525 break;
2526
cerione9d361a2005-03-04 17:35:29 +00002527 case 0x0D7: // stbx (Store B Indexed, PPC32 p512)
cerionb85e8bb2005-02-16 08:54:33 +00002528 DIP("stbx r%d,r%d,r%d\n", Rs_addr, Ra_addr, Rb_addr);
sewardjb51f0f42005-07-18 11:38:02 +00002529 storeBE( mkexpr(EA_reg), unop(Iop_32to8, mkexpr(Rs)) );
cerionb85e8bb2005-02-16 08:54:33 +00002530 break;
2531
sewardjb51f0f42005-07-18 11:38:02 +00002532//zz case 0x1B7: // sthux (Store HW with Update Indexed, PPC32 p525)
2533//zz if (Ra_addr == 0) {
2534//zz vex_printf("dis_int_store(PPC32)(sthux,Ra_addr)\n");
2535//zz return False;
2536//zz }
2537//zz DIP("sthux r%d,r%d,r%d\n", Rs_addr, Ra_addr, Rb_addr);
2538//zz putIReg( Ra_addr, mkexpr(EA_reg) );
2539//zz storeBE( mkexpr(EA_reg), mkexpr(Rs_16) );
2540//zz break;
cerionb85e8bb2005-02-16 08:54:33 +00002541
cerione9d361a2005-03-04 17:35:29 +00002542 case 0x197: // sthx (Store HW Indexed, PPC32 p526)
cerionb85e8bb2005-02-16 08:54:33 +00002543 DIP("sthx r%d,r%d,r%d\n", Rs_addr, Ra_addr, Rb_addr);
sewardjb51f0f42005-07-18 11:38:02 +00002544 storeBE( mkexpr(EA_reg), unop(Iop_32to16, mkexpr(Rs)) );
cerionb85e8bb2005-02-16 08:54:33 +00002545 break;
2546
cerione9d361a2005-03-04 17:35:29 +00002547 case 0x0B7: // stwux (Store W with Update Indexed, PPC32 p535)
cerionb85e8bb2005-02-16 08:54:33 +00002548 if (Ra_addr == 0) {
2549 vex_printf("dis_int_store(PPC32)(stwux,Ra_addr)\n");
2550 return False;
2551 }
2552 DIP("stwux r%d,r%d,r%d\n", Rs_addr, Ra_addr, Rb_addr);
cerionb85e8bb2005-02-16 08:54:33 +00002553 putIReg( Ra_addr, mkexpr(EA_reg) );
cerioned623db2005-06-20 12:42:04 +00002554 storeBE( mkexpr(EA_reg), mkexpr(Rs) );
cerionb85e8bb2005-02-16 08:54:33 +00002555 break;
cerion44997f22005-01-31 18:45:59 +00002556
cerione9d361a2005-03-04 17:35:29 +00002557 case 0x097: // stwx (Store W Indexed, PPC32 p536)
cerionb85e8bb2005-02-16 08:54:33 +00002558 DIP("stwx r%d,r%d,r%d\n", Rs_addr, Ra_addr, Rb_addr);
2559 storeBE( mkexpr(EA_reg), mkexpr(Rs) );
2560 break;
2561
2562 default:
2563 vex_printf("dis_int_store(PPC32)(opc2)\n");
2564 return False;
2565 }
2566 break;
2567 default:
2568 vex_printf("dis_int_store(PPC32)(opc1)\n");
2569 return False;
2570 }
2571 return True;
ceriond23be4e2005-01-31 07:23:07 +00002572}
2573
2574
2575
sewardjb51f0f42005-07-18 11:38:02 +00002576//zz /*
2577//zz Integer Load/Store Multiple Instructions
2578//zz */
2579//zz static Bool dis_int_ldst_mult ( UInt theInstr )
2580//zz {
2581//zz /* D-Form */
2582//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
2583//zz UChar Rd_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
2584//zz UChar Rs_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
2585//zz UChar Ra_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
2586//zz UInt d_imm = (theInstr >> 0) & 0xFFFF; /* theInstr[0:15] */
2587//zz
2588//zz UInt exts_d_imm = extend_s_16to32(d_imm);
2589//zz UInt reg_idx = 0;
2590//zz UInt offset = 0;
2591//zz
2592//zz IRTemp Ra = newTemp(Ity_I32);
2593//zz IRTemp EA = newTemp(Ity_I32);
2594//zz
2595//zz IRExpr* irx_addr;
2596//zz
2597//zz if (Ra_addr == 0) {
2598//zz assign( EA, binop(Iop_Add32, mkU32(0), mkU32(exts_d_imm)) );
2599//zz } else {
2600//zz assign( Ra, getIReg(Ra_addr) );
2601//zz assign( EA, binop(Iop_Add32, mkexpr(Ra), mkU32(exts_d_imm)) );
2602//zz }
2603//zz
2604//zz switch (opc1) {
2605//zz case 0x2E: // lmw (Load Multiple Word, PPC32 p454)
2606//zz vassert(1);
2607//zz
2608//zz if (Ra_addr >= Rd_addr) {
2609//zz vex_printf("dis_int_ldst_mult(PPC32)(lmw,Ra_addr)\n");
2610//zz return False;
2611//zz }
2612//zz DIP("lmw r%d,%d(r%d)\n", Rd_addr, (Int)d_imm, Ra_addr);
2613//zz for (reg_idx = Rd_addr; reg_idx<=31; reg_idx++) {
2614//zz irx_addr = binop(Iop_Add32, mkexpr(EA), mkU32(offset));
2615//zz putIReg( reg_idx, loadBE(Ity_I32, irx_addr ) );
2616//zz offset +=4;
2617//zz }
2618//zz break;
2619//zz
2620//zz case 0x2F: // stmw (Store Multiple Word, PPC32 p527)
2621//zz vassert(1);
2622//zz
2623//zz DIP("stmw r%d,%d(r%d)\n", Rs_addr, (Int)d_imm, Ra_addr);
2624//zz for (reg_idx = Rs_addr; reg_idx<=31; reg_idx++) {
2625//zz irx_addr = binop(Iop_Add32, mkexpr(EA), mkU32(offset));
2626//zz storeBE( irx_addr, getIReg(reg_idx) );
2627//zz offset +=4;
2628//zz }
2629//zz break;
2630//zz
2631//zz default:
2632//zz vex_printf("dis_int_ldst_mult(PPC32)(opc1)\n");
2633//zz return False;
2634//zz }
2635//zz return True;
2636//zz }
2637//zz
2638//zz
2639//zz
2640//zz /*
2641//zz Integer Load/Store String Instructions
2642//zz */
2643//zz static Bool dis_int_ldst_str ( UInt theInstr )
2644//zz {
2645//zz /* X-Form */
2646//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
2647//zz UChar Rd_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
2648//zz UChar Rs_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
2649//zz UChar Ra_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
2650//zz UChar NumBytes = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
2651//zz UChar Rb_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
2652//zz UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
2653//zz UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
2654//zz
2655//zz UInt reg_idx, bit_idx, n_byte;
2656//zz UInt EA_offset = 0;
2657//zz UInt n_regs, reg_first, reg_last;
2658//zz
2659//zz IRTemp Ra = newTemp(Ity_I32);
2660//zz // IRTemp Rb = newTemp(Ity_I32);
2661//zz IRTemp EA = newTemp(Ity_I32);
2662//zz IRTemp b_EA = newTemp(Ity_I32);
2663//zz IRExpr* irx_byte;
2664//zz IRExpr* irx_shl;
2665//zz
2666//zz if (Ra_addr == 0) {
2667//zz assign( b_EA, mkU32(0) );
2668//zz } else {
2669//zz assign( Ra, getIReg(Ra_addr) );
2670//zz assign( b_EA, mkexpr(Ra) );
2671//zz }
2672//zz
2673//zz if (opc1 != 0x1F || b0 != 0) {
2674//zz vex_printf("dis_int_ldst_str(PPC32)(opc1)\n");
2675//zz return False;
2676//zz }
2677//zz
2678//zz switch (opc2) {
2679//zz case 0x255: // lswi (Load String Word Immediate, PPC32 p455)
2680//zz
2681//zz if (NumBytes == 8) {
2682//zz /* Special case hack */
2683//zz /* Rd = Mem[EA]; (Rd+1)%32 = Mem[EA+4] */
2684//zz DIP("lswi r%d,r%d,%d\n", Rd_addr, Ra_addr, NumBytes);
2685//zz putIReg( Rd_addr,
2686//zz loadBE(Ity_I32, mkexpr(b_EA)) );
2687//zz
2688//zz putIReg( (Rd_addr+1) % 32,
2689//zz loadBE(Ity_I32, binop(Iop_Add32, mkexpr(b_EA), mkU32(4))) );
2690//zz return True;
2691//zz }
2692//zz
2693//zz /* else too difficult */
2694//zz return False;
2695//zz vassert(0);
2696//zz
2697//zz n_regs = (NumBytes / 4) + (NumBytes%4 == 0 ? 0:1); // ceil(nb/4)
2698//zz reg_first = Rd_addr;
2699//zz reg_last = Rd_addr + n_regs - 1;
2700//zz
2701//zz if (reg_last < reg_first) {
2702//zz if (Ra_addr >= reg_first || Ra_addr <= reg_last) {
2703//zz vex_printf("dis_int_ldst_str(PPC32)(lswi,Ra_addr,1)\n");
2704//zz return False;
2705//zz }
2706//zz } else {
2707//zz if (Ra_addr >= reg_first && Ra_addr <= reg_last) {
2708//zz vex_printf("dis_int_ldst_str(PPC32)(lswi,Ra_addr,2)\n");
2709//zz return False;
2710//zz }
2711//zz }
2712//zz DIP("lswi r%d,r%d,%d\n", Rd_addr, Ra_addr, NumBytes);
2713//zz
2714//zz assign( EA, mkexpr(b_EA) );
2715//zz
2716//zz bit_idx = 0;
2717//zz reg_idx = Rd_addr - 1;
2718//zz n_byte = NumBytes;
2719//zz if (n_byte == 0) { n_byte = 32; }
2720//zz
2721//zz for (; n_byte>0; n_byte--) {
2722//zz if (bit_idx == 0) {
2723//zz reg_idx++;
2724//zz if (reg_idx == 32) reg_idx = 0;
2725//zz putIReg( reg_idx, mkU32(0) );
2726//zz }
2727//zz irx_byte = loadBE(Ity_I8, binop(Iop_Add32,
2728//zz mkexpr(EA),
2729//zz mkU32(EA_offset)));
2730//zz irx_shl = binop(Iop_Shl32, irx_byte,
2731//zz mkU8(toUChar(24 - bit_idx)));
2732//zz putIReg( reg_idx, binop(Iop_Or32, getIReg(reg_idx), irx_shl) );
2733//zz bit_idx += 8;
2734//zz if (bit_idx == 32) { bit_idx = 0; }
2735//zz EA_offset++;
2736//zz }
2737//zz break;
2738//zz
2739//zz case 0x215: // lswx (Load String Word Indexed, PPC32 p456)
2740//zz vassert(0);
2741//zz
2742//zz DIP("lswx r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
2743//zz return False;
2744//zz
2745//zz case 0x2D5: // stswi (Store String Word Immediate, PPC32 p528)
2746//zz
2747//zz if (NumBytes == 8) {
2748//zz /* Special case hack */
2749//zz /* Mem[EA] = Rd; Mem[EA+4] = (Rd+1)%32 */
2750//zz DIP("stswi r%d,r%d,%d\n", Rs_addr, Ra_addr, NumBytes);
2751//zz storeBE( mkexpr(b_EA),
2752//zz getIReg(Rd_addr) );
2753//zz storeBE( binop(Iop_Add32, mkexpr(b_EA), mkU32(4)),
2754//zz getIReg((Rd_addr+1) % 32) );
2755//zz return True;
2756//zz }
2757//zz
2758//zz /* else too difficult */
2759//zz return False;
2760//zz
2761//zz vassert(0);
2762//zz
2763//zz DIP("stswi r%d,r%d,%d\n", Rs_addr, Ra_addr, NumBytes);
2764//zz if (Ra_addr == 0) {
2765//zz assign( EA, mkU32(0) );
2766//zz } else {
2767//zz assign( EA, mkexpr(b_EA) );
2768//zz }
2769//zz
2770//zz n_byte = NumBytes;
2771//zz if (n_byte == 0) { n_byte = 32; }
2772//zz reg_idx = Rs_addr - 1;
2773//zz bit_idx = 0;
2774//zz
2775//zz for (; n_byte>0; n_byte--) {
2776//zz if (bit_idx == 0) {
2777//zz reg_idx++;
2778//zz if (reg_idx==32) reg_idx = 0;
2779//zz }
2780//zz irx_byte = unop(Iop_32to8,
2781//zz binop(Iop_Shr32,
2782//zz getIReg(reg_idx),
2783//zz mkU8(toUChar(24 - bit_idx))));
2784//zz storeBE( binop(Iop_Add32, mkexpr(EA), mkU32(EA_offset)),
2785//zz irx_byte );
2786//zz
2787//zz bit_idx += 8;
2788//zz if (bit_idx == 32) { bit_idx = 0; }
2789//zz EA_offset++;
2790//zz }
2791//zz break;
2792//zz
2793//zz case 0x295: // stswx (Store String Word Indexed, PPC32 p529)
2794//zz vassert(0);
2795//zz
2796//zz DIP("stswx r%d,r%d,r%d\n", Rs_addr, Ra_addr, Rb_addr);
2797//zz return False;
2798//zz #if 0
2799//zz // CAB: Might something like this work ?
2800//zz // won't produce very nice code (ir_ctr will get _rather_ long...), but hey.
2801//zz // or perhaps arrays of IRTemp...
2802//zz assign( NumBytes, AND(get(xer_bc), 0x1F) );
2803//zz IRExpr* irx_ea;
2804//zz IRExpr* irx_orig_byte;
2805//zz IRExpr* irx_tostore;
2806//zz IRExpr* ir_ctr = mkU8(0);
2807//zz Uint EA_offset = 0;
2808//zz UInt start = Rs_addr;
2809//zz UInt reg_idx;
2810//zz UInt i;
2811//zz for (i=0; i<128; i++) {
2812//zz bit_idx = (i % 4) * 8;
2813//zz reg_idx = (i / 4) + start;
2814//zz reg_idx = reg_idx % 32;
2815//zz word = getIReg(reg_idx);
2816//zz byte = get_byte(word, bit_idx);
2817//zz
2818//zz irx_ea = (EA + EA_offset);
2819//zz irx_orig_byte = loadBE(Ity_I8, irx_ea);
2820//zz irx_tostore = IRExpr_Mux0X( (ir_ctr <= NumBytes),
2821//zz irx_orig_byte,
2822//zz mkexpr(byte0) );
2823//zz storeBE( irx_ea, irx_tostore );
2824//zz
2825//zz ir_ctr = binop(Iop_And8, ir_ctr, mkU8(1));
2826//zz EA_offset++;
2827//zz }
2828//zz break;
2829//zz #endif
2830//zz
2831//zz default:
2832//zz vex_printf("dis_int_ldst_str(PPC32)(opc2)\n");
2833//zz return False;
2834//zz }
2835//zz return True;
2836//zz }
2837//zz
2838//zz
cerion094d1392005-06-20 13:45:57 +00002839
sewardjb51f0f42005-07-18 11:38:02 +00002840/* ------------------------------------------------------------------
2841 Integer Branch Instructions
2842 ------------------------------------------------------------------ */
cerion645c9302005-01-31 10:09:59 +00002843
cerion45552a92005-02-03 18:20:22 +00002844/*
2845 Branch helper function
2846 ok = BO[2] | ((CTR[0] != 0) ^ BO[1])
sewardjb51f0f42005-07-18 11:38:02 +00002847 Returns an I32 which is 0x00000000 if the ctr condition failed
2848 and 0xFFFFFFFF otherwise.
cerion45552a92005-02-03 18:20:22 +00002849*/
sewardjb51f0f42005-07-18 11:38:02 +00002850static IRExpr* /* :: Ity_I32 */ branch_ctr_ok( UInt BO )
cerion45552a92005-02-03 18:20:22 +00002851{
sewardjb51f0f42005-07-18 11:38:02 +00002852 IRTemp ok = newTemp(Ity_I32);
cerioned623db2005-06-20 12:42:04 +00002853
cerionb85e8bb2005-02-16 08:54:33 +00002854 if ((BO >> 2) & 1) {
sewardjb51f0f42005-07-18 11:38:02 +00002855 assign( ok, mkU32(0xFFFFFFFF) );
cerionb85e8bb2005-02-16 08:54:33 +00002856 } else {
cerionb85e8bb2005-02-16 08:54:33 +00002857 if ((BO >> 1) & 1) {
sewardjb51f0f42005-07-18 11:38:02 +00002858 assign( ok, unop( Iop_1Sto32,
2859 binop( Iop_CmpEQ32,
2860 getSPR( PPC32_SPR_CTR ), mkU32(0))) );
cerionb85e8bb2005-02-16 08:54:33 +00002861 } else {
sewardjb51f0f42005-07-18 11:38:02 +00002862 assign( ok, unop( Iop_1Sto32,
2863 binop( Iop_CmpNE32,
2864 getSPR( PPC32_SPR_CTR ), mkU32(0))) );
cerionb85e8bb2005-02-16 08:54:33 +00002865 }
2866 }
2867 return mkexpr(ok);
cerion45552a92005-02-03 18:20:22 +00002868}
2869
sewardjb51f0f42005-07-18 11:38:02 +00002870
cerion45552a92005-02-03 18:20:22 +00002871/*
sewardjb51f0f42005-07-18 11:38:02 +00002872 Branch helper function cond_ok = BO[4] | (CR[BI] == BO[3])
2873 Returns an I32 which is either 0 if the condition failed or
2874 some arbitrary nonzero value otherwise. */
2875
2876static IRExpr* /* :: Ity_I32 */ branch_cond_ok( UInt BO, UInt BI )
cerion45552a92005-02-03 18:20:22 +00002877{
sewardjb51f0f42005-07-18 11:38:02 +00002878 Int where;
2879 IRTemp res = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00002880 IRTemp cr_bi = newTemp(Ity_I32);
2881
sewardjb51f0f42005-07-18 11:38:02 +00002882 if ((BO >> 4) & 1) {
2883 assign( res, mkU32(1) );
cerionb85e8bb2005-02-16 08:54:33 +00002884 } else {
sewardjb51f0f42005-07-18 11:38:02 +00002885 // ok = (CR[BI] == BO[3]) Note, the following relies on
2886 // getCRbit_anywhere returning a value which
2887 // is either zero or has exactly 1 bit set.
2888 assign( cr_bi, getCRbit_anywhere( BI, &where ) );
cerione9d361a2005-03-04 17:35:29 +00002889
2890 if ((BO >> 3) & 1) {
sewardjb51f0f42005-07-18 11:38:02 +00002891 /* We can use cr_bi as-is. */
2892 assign( res, mkexpr(cr_bi) );
cerione9d361a2005-03-04 17:35:29 +00002893 } else {
sewardjb51f0f42005-07-18 11:38:02 +00002894 /* We have to invert the sense of the information held in
2895 cr_bi. For that we need to know which bit
2896 getCRbit_somewhere regards as significant. */
2897 assign( res, binop(Iop_Xor32, mkexpr(cr_bi), mkU32(1<<where)) );
cerionb85e8bb2005-02-16 08:54:33 +00002898 }
2899 }
sewardjb51f0f42005-07-18 11:38:02 +00002900 return mkexpr(res);
cerion45552a92005-02-03 18:20:22 +00002901}
2902
2903
cerion3d870a32005-03-18 12:23:33 +00002904/*
2905 Integer Branch Instructions
2906*/
sewardj9e6491a2005-07-02 19:24:10 +00002907static Bool dis_branch ( UInt theInstr, DisResult* dres )
cerion91ad5362005-01-27 23:02:41 +00002908{
cerionb85e8bb2005-02-16 08:54:33 +00002909 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
2910 UChar BO = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
2911 UChar BI = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
2912 UInt BD = (theInstr >> 2) & 0x3FFF; /* theInstr[2:15] */
2913 UChar b11to15 = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
2914 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
2915 UInt LI_24 = (theInstr >> 2) & 0xFFFFFF; /* theInstr[2:25] */
2916 UChar flag_AA = toUChar((theInstr >> 1) & 1); /* theInstr[1] */
2917 UChar flag_LK = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
2918
cerion4561acb2005-02-21 14:07:48 +00002919 Int exts_BD = (Int)extend_s_16to32(BD << 2);
cerion6b30d852005-06-24 11:25:46 +00002920 Int exts_LI = (Int)extend_s_26to32(LI_24 << 2);
cerionb85e8bb2005-02-16 08:54:33 +00002921
2922 Addr32 nia = 0;
2923
sewardjb51f0f42005-07-18 11:38:02 +00002924 // IRTemp ctr = newTemp(Ity_I32);
2925 // IRTemp lr = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00002926 IRTemp ir_nia = newTemp(Ity_I32);
2927 IRTemp do_branch = newTemp(Ity_I32);
sewardjb51f0f42005-07-18 11:38:02 +00002928 IRTemp ctr_ok = newTemp(Ity_I32);
2929 IRTemp cond_ok = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00002930
sewardjb51f0f42005-07-18 11:38:02 +00002931// assign( ctr, getSPR( PPC32_SPR_CTR ) );
cerion4561acb2005-02-21 14:07:48 +00002932
cerionb85e8bb2005-02-16 08:54:33 +00002933 /* Hack to pass through code that just wants to read the PC */
2934 if (theInstr == 0x429F0005) {
sewardjb51f0f42005-07-18 11:38:02 +00002935 DIP("bcl 0x%x, 0x%x (a.k.a mr lr,cia+4)\n", BO, BI);
2936 putSPR( PPC32_SPR_LR, mkU32(guest_CIA_curr_instr + 4) );
cerionb85e8bb2005-02-16 08:54:33 +00002937 return True;
sewardjb51f0f42005-07-18 11:38:02 +00002938 }
cerion45552a92005-02-03 18:20:22 +00002939
cerionb85e8bb2005-02-16 08:54:33 +00002940 switch (opc1) {
cerione9d361a2005-03-04 17:35:29 +00002941 case 0x12: // b (Branch, PPC32 p360)
cerion4561acb2005-02-21 14:07:48 +00002942 if (flag_AA) {
2943 nia = (UInt)exts_LI;
2944 } else {
sewardj9e6491a2005-07-02 19:24:10 +00002945 nia = (UInt)((Int)guest_CIA_curr_instr + exts_LI);
cerionb85e8bb2005-02-16 08:54:33 +00002946 }
cerione9d361a2005-03-04 17:35:29 +00002947 DIP("b%s%s 0x%x\n", flag_LK ? "l" : "", flag_AA ? "a" : "", nia);
2948
cerionb85e8bb2005-02-16 08:54:33 +00002949 if (flag_LK) {
sewardjb51f0f42005-07-18 11:38:02 +00002950 putSPR( PPC32_SPR_LR, mkU32(guest_CIA_curr_instr + 4) );
cerione9d361a2005-03-04 17:35:29 +00002951 }
cerionb85e8bb2005-02-16 08:54:33 +00002952 irbb->jumpkind = flag_LK ? Ijk_Call : Ijk_Boring;
2953 irbb->next = mkU32(nia);
cerionb85e8bb2005-02-16 08:54:33 +00002954 break;
2955
cerione9d361a2005-03-04 17:35:29 +00002956 case 0x10: // bc (Branch Conditional, PPC32 p361)
cerionb85e8bb2005-02-16 08:54:33 +00002957 DIP("bc%s%s 0x%x, 0x%x, 0x%x\n",
cerion4561acb2005-02-21 14:07:48 +00002958 flag_LK ? "l" : "", flag_AA ? "a" : "", BO, BI, exts_BD);
cerionb85e8bb2005-02-16 08:54:33 +00002959
2960 if (!(BO & 0x4)) {
sewardjb51f0f42005-07-18 11:38:02 +00002961 putSPR( PPC32_SPR_CTR,
2962 binop(Iop_Sub32, getSPR( PPC32_SPR_CTR ), mkU32(1)) );
cerionb85e8bb2005-02-16 08:54:33 +00002963 }
sewardjb51f0f42005-07-18 11:38:02 +00002964
2965 /* This is a bit subtle. ctr_ok is either all 0s or all 1s.
2966 cond_ok is either zero or nonzero, since that's the cheapest
2967 way to compute it. Anding them together gives a value which
2968 is either zero or non zero and so that's what we must test
2969 for in the IRStmt_Exit. */
2970 assign( ctr_ok, branch_ctr_ok( BO ) );
cerionb85e8bb2005-02-16 08:54:33 +00002971 assign( cond_ok, branch_cond_ok( BO, BI ) );
sewardjb51f0f42005-07-18 11:38:02 +00002972 assign( do_branch,
2973 binop(Iop_And32, mkexpr(cond_ok), mkexpr(ctr_ok)) );
2974
cerion4561acb2005-02-21 14:07:48 +00002975 if (flag_AA) {
2976 nia = (UInt)exts_BD;
2977 } else {
sewardj9e6491a2005-07-02 19:24:10 +00002978 nia = (UInt)((Int)guest_CIA_curr_instr + exts_BD);
cerionb85e8bb2005-02-16 08:54:33 +00002979 }
cerionb85e8bb2005-02-16 08:54:33 +00002980 if (flag_LK) {
sewardjb51f0f42005-07-18 11:38:02 +00002981 putSPR( PPC32_SPR_LR, mkU32(guest_CIA_curr_instr + 4) );
cerionb85e8bb2005-02-16 08:54:33 +00002982 }
2983
sewardjb51f0f42005-07-18 11:38:02 +00002984 stmt( IRStmt_Exit( binop(Iop_CmpNE32, mkexpr(do_branch), mkU32(0)),
cerionb85e8bb2005-02-16 08:54:33 +00002985 flag_LK ? Ijk_Call : Ijk_Boring,
2986 IRConst_U32(nia) ));
2987
2988 irbb->jumpkind = Ijk_Boring;
sewardj9e6491a2005-07-02 19:24:10 +00002989 irbb->next = mkU32(guest_CIA_curr_instr + 4);
cerionb85e8bb2005-02-16 08:54:33 +00002990 break;
2991
2992 case 0x13:
2993 if (b11to15!=0) {
2994 vex_printf("dis_int_branch(PPC32)(0x13,b11to15)\n");
2995 return False;
2996 }
cerion91ad5362005-01-27 23:02:41 +00002997
cerionb85e8bb2005-02-16 08:54:33 +00002998 switch (opc2) {
cerione9d361a2005-03-04 17:35:29 +00002999 case 0x210: // bcctr (Branch Cond. to Count Register, PPC32 p363)
cerionb85e8bb2005-02-16 08:54:33 +00003000 if ((BO & 0x4) == 0) { // "decrement and test CTR" option invalid
3001 vex_printf("dis_int_branch(PPC32)(bcctr,BO)\n");
3002 return False;
3003 }
ceriona31e8b52005-02-21 16:30:45 +00003004 DIP("bcctr%s 0x%x, 0x%x\n", flag_LK ? "l" : "", BO, BI);
cerionb85e8bb2005-02-16 08:54:33 +00003005
3006 assign( cond_ok, branch_cond_ok( BO, BI ) );
3007
sewardjb51f0f42005-07-18 11:38:02 +00003008 assign( ir_nia,
3009 binop(Iop_And32, mkU32(0xFFFFFFFC),
3010 getSPR( PPC32_SPR_CTR ) ));
cerionb85e8bb2005-02-16 08:54:33 +00003011
3012 if (flag_LK) {
sewardjb51f0f42005-07-18 11:38:02 +00003013 putSPR( PPC32_SPR_LR, mkU32(guest_CIA_curr_instr + 4) );
cerionb85e8bb2005-02-16 08:54:33 +00003014 }
3015
sewardjb51f0f42005-07-18 11:38:02 +00003016 stmt( IRStmt_Exit(
3017 binop(Iop_CmpEQ32, mkexpr(cond_ok), mkU32(0)),
3018 Ijk_Boring,
3019 IRConst_U32(guest_CIA_curr_instr + 4)
3020 ));
cerionb85e8bb2005-02-16 08:54:33 +00003021
3022 irbb->jumpkind = flag_LK ? Ijk_Call : Ijk_Boring;
3023 irbb->next = mkexpr(ir_nia);
3024 break;
3025
cerione9d361a2005-03-04 17:35:29 +00003026 case 0x010: // bclr (Branch Cond. to Link Register, PPC32 p365)
sewardjb51f0f42005-07-18 11:38:02 +00003027
3028 if ((BO & 0x14 /* 1z1zz */) == 0x14 && flag_LK == 0) {
3029 DIP("blr");
3030 } else {
3031 DIP("bclr%s 0x%x, 0x%x\n", flag_LK ? "l" : "", BO, BI);
3032 }
cerion91ad5362005-01-27 23:02:41 +00003033
cerionb85e8bb2005-02-16 08:54:33 +00003034 if (!(BO & 0x4)) {
sewardjb51f0f42005-07-18 11:38:02 +00003035 putSPR( PPC32_SPR_CTR,
3036 binop(Iop_Sub32, getSPR( PPC32_SPR_CTR ), mkU32(1)) );
cerionb85e8bb2005-02-16 08:54:33 +00003037 }
3038
sewardjb51f0f42005-07-18 11:38:02 +00003039 /* See comments above for 'bc' about this */
3040 assign( ctr_ok, branch_ctr_ok( BO ) );
3041 assign( cond_ok, branch_cond_ok( BO, BI ) );
3042 assign( do_branch,
3043 binop(Iop_And32, mkexpr(cond_ok), mkexpr(ctr_ok)) );
cerionb85e8bb2005-02-16 08:54:33 +00003044
3045 assign( ir_nia, binop(Iop_And32,
sewardjb51f0f42005-07-18 11:38:02 +00003046 getSPR( PPC32_SPR_LR ),
cerionb85e8bb2005-02-16 08:54:33 +00003047 mkU32(0xFFFFFFFC)) );
3048 if (flag_LK) {
sewardjb51f0f42005-07-18 11:38:02 +00003049 putSPR( PPC32_SPR_LR, mkU32(guest_CIA_curr_instr + 4) );
cerionb85e8bb2005-02-16 08:54:33 +00003050 }
sewardjb51f0f42005-07-18 11:38:02 +00003051
3052 stmt( IRStmt_Exit(
3053 binop(Iop_CmpEQ32, mkexpr(do_branch), mkU32(0)),
3054 Ijk_Boring,
3055 IRConst_U32(guest_CIA_curr_instr + 4)
3056 ));
3057
3058 irbb->jumpkind = flag_LK ? Ijk_Call : Ijk_Ret;
cerionb85e8bb2005-02-16 08:54:33 +00003059 irbb->next = mkexpr(ir_nia);
3060 break;
3061
3062 default:
3063 vex_printf("dis_int_branch(PPC32)(opc2)\n");
3064 return False;
3065 }
3066 break;
3067 default:
3068 vex_printf("dis_int_branch(PPC32)(opc1)\n");
3069 return False;
3070 }
cerion91ad5362005-01-27 23:02:41 +00003071
sewardj9e6491a2005-07-02 19:24:10 +00003072 dres->whatNext = Dis_StopHere;
cerionb85e8bb2005-02-16 08:54:33 +00003073 return True;
cerion91ad5362005-01-27 23:02:41 +00003074}
3075
3076
3077
cerion3d870a32005-03-18 12:23:33 +00003078/*
3079 Condition Register Logical Instructions
3080*/
cerion3007c7f2005-02-23 23:13:29 +00003081static Bool dis_cond_logic ( UInt theInstr )
3082{
3083 /* XL-Form */
3084 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
3085 UChar crbD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
3086 UChar crfD_addr = toUChar((theInstr >> 23) & 0x7); /* theInstr[23:25] */
3087 UChar crbA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
3088 UChar crfS_addr = toUChar((theInstr >> 18) & 0x7); /* theInstr[18:20] */
3089 UChar crbB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
3090 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
3091 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
3092
3093 IRTemp crbD = newTemp(Ity_I32);
3094 IRTemp crbA = newTemp(Ity_I32);
3095 IRTemp crbB = newTemp(Ity_I32);
cerione9d361a2005-03-04 17:35:29 +00003096 IRTemp tmp = newTemp(Ity_I32);
cerion3007c7f2005-02-23 23:13:29 +00003097
3098 if (opc1 != 19 || b0 != 0) {
3099 vex_printf("dis_cond_logic(PPC32)(opc1)\n");
3100 return False;
3101 }
3102
cerione9d361a2005-03-04 17:35:29 +00003103 if (opc2 == 0) { // mcrf (Move Cond Reg Field, PPC32 p464)
cerion3007c7f2005-02-23 23:13:29 +00003104 if (((crbD_addr & 0x3) != 0) ||
cerioned623db2005-06-20 12:42:04 +00003105 ((crbA_addr & 0x3) != 0) || (crbB_addr != 0))
cerion3007c7f2005-02-23 23:13:29 +00003106 return False;
sewardjb51f0f42005-07-18 11:38:02 +00003107 DIP("mcrf cr%d,cr%d\n", crfD_addr, crfS_addr);
3108 putCR0( crfD_addr, getCR0( crfS_addr) );
3109 putCR321( crfD_addr, getCR321(crfS_addr) );
cerion3007c7f2005-02-23 23:13:29 +00003110 } else {
sewardjb51f0f42005-07-18 11:38:02 +00003111 assign( crbA, getCRbit(crbA_addr) );
ceriona50fde52005-07-01 21:16:10 +00003112 if (crbA_addr == crbB_addr)
sewardjb51f0f42005-07-18 11:38:02 +00003113 crbB = crbA;
ceriona50fde52005-07-01 21:16:10 +00003114 else
sewardjb51f0f42005-07-18 11:38:02 +00003115 assign( crbB, getCRbit(crbB_addr) );
cerion3007c7f2005-02-23 23:13:29 +00003116
3117 switch (opc2) {
sewardjb51f0f42005-07-18 11:38:02 +00003118//zz case 0x101: // crand (Cond Reg AND, PPC32 p372)
3119//zz DIP("crand crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
3120//zz assign( crbD, binop(Iop_And32, mkexpr(crbA), mkexpr(crbB)) );
3121//zz break;
3122//zz case 0x081: // crandc (Cond Reg AND w. Complement, PPC32 p373)
3123//zz DIP("crandc crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
3124//zz assign( crbD, binop(Iop_And32, mkexpr(crbA),
3125//zz unop(Iop_Not32, mkexpr(crbB))) );
3126//zz break;
3127//zz case 0x121: // creqv (Cond Reg Equivalent, PPC32 p374)
3128//zz DIP("creqv crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
3129//zz assign( crbD, unop(Iop_Not32,
3130//zz binop(Iop_Xor32, mkexpr(crbA), mkexpr(crbB))) );
3131//zz break;
3132//zz case 0x0E1: // crnand (Cond Reg NAND, PPC32 p375)
3133//zz DIP("crnand crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
3134//zz assign( crbD, unop(Iop_Not32,
3135//zz binop(Iop_And32, mkexpr(crbA), mkexpr(crbB))) );
3136//zz break;
cerione9d361a2005-03-04 17:35:29 +00003137 case 0x021: // crnor (Cond Reg NOR, PPC32 p376)
cerion3007c7f2005-02-23 23:13:29 +00003138 DIP("crnor crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
3139 assign( crbD, unop(Iop_Not32,
3140 binop(Iop_Or32, mkexpr(crbA), mkexpr(crbB))) );
3141 break;
cerione9d361a2005-03-04 17:35:29 +00003142 case 0x1C1: // cror (Cond Reg OR, PPC32 p377)
cerion3007c7f2005-02-23 23:13:29 +00003143 DIP("cror crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
3144 assign( crbD, binop(Iop_Or32, mkexpr(crbA), mkexpr(crbB)) );
3145 break;
sewardjb51f0f42005-07-18 11:38:02 +00003146//zz case 0x1A1: // crorc (Cond Reg OR w. Complement, PPC32 p378)
3147//zz DIP("crorc crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
3148//zz assign( crbD, binop(Iop_Or32, mkexpr(crbA),
3149//zz unop(Iop_Not32, mkexpr(crbB))) );
3150//zz break;
cerione9d361a2005-03-04 17:35:29 +00003151 case 0x0C1: // crxor (Cond Reg XOR, PPC32 p379)
cerion3007c7f2005-02-23 23:13:29 +00003152 DIP("crxor crb%d,crb%d,crb%d\n", crbD_addr, crbA_addr, crbB_addr);
3153 assign( crbD, binop(Iop_Xor32, mkexpr(crbA), mkexpr(crbB)) );
3154 break;
3155
3156 default:
3157 vex_printf("dis_cond_logic(PPC32)(opc2)\n");
3158 return False;
3159 }
3160
sewardjb51f0f42005-07-18 11:38:02 +00003161 putCRbit( crbD_addr, mkexpr(crbD) );
cerion3007c7f2005-02-23 23:13:29 +00003162 }
3163 return True;
3164}
3165
3166
cerion3d870a32005-03-18 12:23:33 +00003167/*
3168 System Linkage Instructions
3169*/
sewardj9e6491a2005-07-02 19:24:10 +00003170static Bool dis_syslink ( UInt theInstr, DisResult* dres )
cerion8c3adda2005-01-31 11:54:05 +00003171{
cerionb85e8bb2005-02-16 08:54:33 +00003172 if (theInstr != 0x44000002) {
3173 vex_printf("dis_int_syslink(PPC32)(theInstr)\n");
3174 return False;
3175 }
cerione1d857b2005-02-04 18:29:05 +00003176
cerione9d361a2005-03-04 17:35:29 +00003177 // sc (System Call, PPC32 p504)
cerionb85e8bb2005-02-16 08:54:33 +00003178 DIP("sc\n");
3179
3180 /* It's important that all ArchRegs carry their up-to-date value
3181 at this point. So we declare an end-of-block here, which
3182 forces any TempRegs caching ArchRegs to be flushed. */
sewardj9e6491a2005-07-02 19:24:10 +00003183 irbb->next = mkU32( guest_CIA_curr_instr + 4 );
cerionb85e8bb2005-02-16 08:54:33 +00003184 irbb->jumpkind = Ijk_Syscall;
3185
sewardj9e6491a2005-07-02 19:24:10 +00003186 dres->whatNext = Dis_StopHere;
cerionb85e8bb2005-02-16 08:54:33 +00003187 return True;
cerion8c3adda2005-01-31 11:54:05 +00003188}
3189
cerion3d870a32005-03-18 12:23:33 +00003190
3191/*
3192 Memory Synchronization Instructions
3193*/
cerion8c3adda2005-01-31 11:54:05 +00003194static Bool dis_memsync ( UInt theInstr )
3195{
cerionb85e8bb2005-02-16 08:54:33 +00003196 /* X-Form, XL-Form */
3197 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
3198 UInt b11to25 = (theInstr >> 11) & 0x7FFF; /* theInstr[11:25] */
3199 UChar Rd_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
3200 UChar Rs_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
3201 UChar Ra_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
3202 UChar Rb_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
3203 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
3204 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
3205
3206 IRTemp EA = newTemp(Ity_I32);
3207 IRTemp Ra = newTemp(Ity_I32);
3208 IRTemp Rb = newTemp(Ity_I32);
3209 IRTemp Rs = newTemp(Ity_I32);
cerione9d361a2005-03-04 17:35:29 +00003210 IRTemp xer_so = newTemp(Ity_I32);
3211 IRTemp cr_f7 = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00003212
3213 switch (opc1) {
cerion8c3adda2005-01-31 11:54:05 +00003214 /* XL-Form */
cerione9d361a2005-03-04 17:35:29 +00003215 case 0x13: // isync (Instruction Synchronize, PPC32 p432)
cerionb85e8bb2005-02-16 08:54:33 +00003216 if (opc2 != 0x096) {
3217 vex_printf("dis_int_memsync(PPC32)(0x13,opc2)\n");
3218 return False;
3219 }
3220 if (b11to25 != 0 || b0 != 0) {
3221 vex_printf("dis_int_memsync(PPC32)(0x13,b11to25|b0)\n");
3222 return False;
3223 }
3224 DIP("isync\n");
cerionb85e8bb2005-02-16 08:54:33 +00003225 stmt( IRStmt_MFence() );
3226 break;
cerion8c3adda2005-01-31 11:54:05 +00003227
cerionb85e8bb2005-02-16 08:54:33 +00003228 /* X-Form */
3229 case 0x1F:
3230 switch (opc2) {
sewardjb51f0f42005-07-18 11:38:02 +00003231//zz case 0x356: // eieio (Enforce In-Order Execution of I/O, PPC32 p394)
3232//zz vassert(0);
3233//zz
3234//zz if (b11to25 != 0 || b0 != 0) {
3235//zz vex_printf("dis_int_memsync(PPC32)(eiei0,b11to25|b0)\n");
3236//zz return False;
3237//zz }
3238//zz DIP("eieio\n");
3239//zz return False;
cerion8c3adda2005-01-31 11:54:05 +00003240
cerione9d361a2005-03-04 17:35:29 +00003241 case 0x014: // lwarx (Load Word and Reserve Indexed, PPC32 p458)
cerionb85e8bb2005-02-16 08:54:33 +00003242 /* Note: RESERVE, RESERVE_ADDR not implemented.
3243 stwcx. is assumed to be always successful
3244 */
3245 if (b0 != 0) {
3246 vex_printf("dis_int_memsync(PPC32)(lwarx,b0)\n");
3247 return False;
3248 }
3249 DIP("lwarx r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
3250 assign( Rb, getIReg(Rb_addr) );
3251 if (Ra_addr == 0) {
3252 assign( EA, mkexpr(Rb) );
3253 } else {
3254 assign( Ra, getIReg(Ra_addr) );
ceriond7978992005-07-04 11:47:44 +00003255 assign( EA, binop(Iop_Add32, mkexpr(Ra), mkexpr(Rb)) );
cerionb85e8bb2005-02-16 08:54:33 +00003256 }
3257 putIReg( Rd_addr, loadBE(Ity_I32, mkexpr(EA)) );
3258 break;
3259
cerione9d361a2005-03-04 17:35:29 +00003260 case 0x096: // stwcx. (Store Word Conditional Indexed, PPC32 p532)
cerionb85e8bb2005-02-16 08:54:33 +00003261 /* Note: RESERVE, RESERVE_ADDR not implemented.
3262 stwcx. is assumed to be always successful
3263 */
3264 if (b0 != 1) {
3265 vex_printf("dis_int_memsync(PPC32)(stwcx.,b0)\n");
3266 return False;
3267 }
3268 DIP("stwcx. r%d,r%d,r%d\n", Rs_addr, Ra_addr, Rb_addr);
3269
3270 assign( Rb, getIReg(Rb_addr) );
3271 assign( Rs, getIReg(Rs_addr) );
3272 if (Ra_addr == 0) {
3273 assign( EA, mkexpr(Rb) );
3274 } else {
3275 assign( Ra, getIReg(Ra_addr) );
ceriond7978992005-07-04 11:47:44 +00003276 assign( EA, binop(Iop_Add32, mkexpr(Ra), mkexpr(Rb)) );
cerionb85e8bb2005-02-16 08:54:33 +00003277 }
3278 storeBE( mkexpr(EA), mkexpr(Rs) );
3279
sewardjb51f0f42005-07-18 11:38:02 +00003280 // Set CR0[LT GT EQ S0] = 0b001 || XER[SO]
3281 putCR321(0, mkU8(1<<1));
3282 putCR0(0, getXER_SO());
cerionb85e8bb2005-02-16 08:54:33 +00003283 break;
3284
cerione9d361a2005-03-04 17:35:29 +00003285 case 0x256: // sync (Synchronize, PPC32 p543)
cerionb85e8bb2005-02-16 08:54:33 +00003286 if (b11to25 != 0 || b0 != 0) {
3287 vex_printf("dis_int_memsync(PPC32)(sync,b11to25|b0)\n");
3288 return False;
3289 }
3290 DIP("sync\n");
3291 /* Insert a memory fence. It's sometimes important that these
3292 are carried through to the generated code. */
3293 stmt( IRStmt_MFence() );
3294 break;
3295
3296 default:
3297 vex_printf("dis_int_memsync(PPC32)(opc2)\n");
3298 return False;
3299 }
3300 break;
cerion8c3adda2005-01-31 11:54:05 +00003301
cerionb85e8bb2005-02-16 08:54:33 +00003302 default:
3303 vex_printf("dis_int_memsync(PPC32)(opc1)\n");
3304 return False;
3305 }
3306 return True;
cerion8c3adda2005-01-31 11:54:05 +00003307}
3308
3309
3310
cerion3d870a32005-03-18 12:23:33 +00003311/*
3312 Integer Shift Instructions
3313*/
cerion645c9302005-01-31 10:09:59 +00003314static Bool dis_int_shift ( UInt theInstr )
3315{
cerionb85e8bb2005-02-16 08:54:33 +00003316 /* X-Form */
3317 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
3318 UChar Rs_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
3319 UChar Ra_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
3320 UChar Rb_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
3321 UChar sh_imm = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
3322 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
3323 UChar flag_Rc = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
3324
cerion70e24122005-03-16 00:27:37 +00003325 UInt flag_op = PPC32G_FLAG_OP_NUMBER;
cerionb85e8bb2005-02-16 08:54:33 +00003326
3327 IRTemp sh_amt = newTemp(Ity_I8);
3328 IRTemp sign = newTemp(Ity_I32);
3329 IRTemp rb_b5 = newTemp(Ity_I32);
3330 IRTemp sext = newTemp(Ity_I32);
3331 IRTemp Rs = newTemp(Ity_I32);
3332 IRTemp Rs_sh = newTemp(Ity_I32);
cerion87d34ca2005-03-03 02:17:06 +00003333 IRTemp Rs_msk = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00003334 IRTemp Ra = newTemp(Ity_I32);
3335 IRTemp Rb = newTemp(Ity_I32);
3336 IRTemp mask = newTemp(Ity_I32);
sewardj20ef5472005-07-21 14:48:31 +00003337 IRTemp sh_amt32 = newTemp(Ity_I32);
3338 IRTemp outofrange = newTemp(Ity_I8);
cerionb85e8bb2005-02-16 08:54:33 +00003339
3340 assign( Rs, getIReg(Rs_addr) );
3341 assign( Rb, getIReg(Rb_addr) );
3342
3343 if (opc1 == 0x1F) {
3344 switch (opc2) {
cerione9d361a2005-03-04 17:35:29 +00003345 case 0x018: // slw (Shift Left Word, PPC32 p505)
cerionb85e8bb2005-02-16 08:54:33 +00003346 DIP("slw%s r%d,r%d,r%d\n", flag_Rc ? "." : "",
3347 Ra_addr, Rs_addr, Rb_addr);
3348 assign( sh_amt, binop(Iop_And8, mkU8(0x1F),
3349 unop(Iop_32to8, mkexpr(Rb))) );
cerion3a589ea2005-03-14 16:30:09 +00003350 assign( Rs_sh, binop(Iop_Shl32, mkexpr(Rs), mkexpr(sh_amt)) );
3351 assign( rb_b5, binop(Iop_And32, mkexpr(Rb), mkU32(1<<5)) );
3352 assign( Ra, IRExpr_Mux0X( unop(Iop_32to8, mkexpr(rb_b5)),
3353 mkexpr(Rs_sh), mkU32(0) ));
cerionb85e8bb2005-02-16 08:54:33 +00003354 break;
3355
cerione9d361a2005-03-04 17:35:29 +00003356 case 0x318: // sraw (Shift Right Algebraic Word, PPC32 p506)
cerionb85e8bb2005-02-16 08:54:33 +00003357 DIP("sraw%s r%d,r%d,r%d\n", flag_Rc ? "." : "",
3358 Ra_addr, Rs_addr, Rb_addr);
3359
sewardj20ef5472005-07-21 14:48:31 +00003360 /* JRS: my reading of the (poorly worded) PPC32 doc p506 is:
3361 amt = Rb & 63
3362 Ra = Sar32( Rs, amt > 31 ? 31 : amt )
3363 XER.CA = amt > 31 ? sign-of-Rs : (computation as per srawi)
3364 */
3365 assign( sh_amt32, binop(Iop_And32, mkU32(0x3F), mkexpr(Rb)) );
3366 assign( outofrange,
3367 unop( Iop_1Uto8,
3368 binop(Iop_CmpLT32U, mkU32(31), mkexpr(sh_amt32)) ));
3369 assign( Ra,
3370 binop( Iop_Sar32,
3371 mkexpr(Rs),
3372 unop( Iop_32to8,
3373 IRExpr_Mux0X( mkexpr(outofrange),
3374 mkexpr(sh_amt32),
3375 mkU32(31)) ))
3376 );
3377 set_XER_CA( PPC32G_FLAG_OP_SRAW,
3378 mkexpr(Ra), mkexpr(Rs), mkexpr(sh_amt32),
3379 get_XER_CA() );
cerionb85e8bb2005-02-16 08:54:33 +00003380 break;
3381
cerione9d361a2005-03-04 17:35:29 +00003382 case 0x338: // srawi (Shift Right Algebraic Word Immediate, PPC32 p507)
cerionb85e8bb2005-02-16 08:54:33 +00003383 DIP("srawi%s r%d,r%d,%d\n", flag_Rc ? "." : "",
3384 Ra_addr, Rs_addr, sh_imm);
sewardj20ef5472005-07-21 14:48:31 +00003385 vassert(sh_imm < 32);
cerionb85e8bb2005-02-16 08:54:33 +00003386 assign( sh_amt, mkU8(sh_imm) );
sewardj20ef5472005-07-21 14:48:31 +00003387 assign( Ra, binop(Iop_Sar32, mkexpr(Rs), mkexpr(sh_amt)) );
3388 set_XER_CA( PPC32G_FLAG_OP_SRAWI,
3389 mkexpr(Ra), mkexpr(Rs), mkU32(sh_imm),
3390 get_XER_CA() );
cerionb85e8bb2005-02-16 08:54:33 +00003391 break;
3392
cerione9d361a2005-03-04 17:35:29 +00003393 case 0x218: // srw (Shift Right Word, PPC32 p508)
cerionb85e8bb2005-02-16 08:54:33 +00003394 DIP("srw%s r%d,r%d,r%d\n", flag_Rc ? "." : "",
3395 Ra_addr, Rs_addr, Rb_addr);
3396 assign( sh_amt, binop(Iop_And8, mkU8(0x1F),
cerion3a589ea2005-03-14 16:30:09 +00003397 unop(Iop_32to8, mkexpr(Rb))) );
cerionb85e8bb2005-02-16 08:54:33 +00003398 assign( Rs_sh, binop(Iop_Shr32, mkexpr(Rs), mkexpr(sh_amt)) );
3399 assign( rb_b5, binop(Iop_And32, mkexpr(Rb), mkU32(1<<5)) );
3400 assign( Ra, IRExpr_Mux0X( unop(Iop_32to8, mkexpr(rb_b5)),
cerion2ee871e2005-03-01 09:32:01 +00003401 mkexpr(Rs_sh), mkU32(0) ));
cerionb85e8bb2005-02-16 08:54:33 +00003402 break;
3403
3404 default:
3405 vex_printf("dis_int_shift(PPC32)(opc2)\n");
3406 return False;
3407 }
3408 } else {
3409 vex_printf("dis_int_shift(PPC32)(opc1)\n");
3410 return False;
3411 }
cerion0d330c52005-02-28 16:43:16 +00003412
3413 putIReg( Ra_addr, mkexpr(Ra) );
cerionb85e8bb2005-02-16 08:54:33 +00003414
cerionb85e8bb2005-02-16 08:54:33 +00003415 if (flag_Rc) {
sewardj20ef5472005-07-21 14:48:31 +00003416 set_CR0( mkexpr(Ra) );
cerionb85e8bb2005-02-16 08:54:33 +00003417 }
3418 return True;
cerion645c9302005-01-31 10:09:59 +00003419}
3420
3421
3422
sewardjb51f0f42005-07-18 11:38:02 +00003423//zz /*
3424//zz Integer Load/Store Reverse Instructions
3425//zz */
3426//zz static Bool dis_int_ldst_rev ( UInt theInstr )
3427//zz {
3428//zz /* X-Form */
3429//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
3430//zz UChar Rd_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
3431//zz UChar Rs_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
3432//zz UChar Ra_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
3433//zz UChar Rb_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
3434//zz UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
3435//zz UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
3436//zz
3437//zz IRTemp EA = newTemp(Ity_I32);
3438//zz IRTemp Rd = newTemp(Ity_I32);
3439//zz IRTemp Rs = newTemp(Ity_I32);
3440//zz IRTemp byte0 = newTemp(Ity_I32);
3441//zz IRTemp byte1 = newTemp(Ity_I32);
3442//zz IRTemp byte2 = newTemp(Ity_I32);
3443//zz IRTemp byte3 = newTemp(Ity_I32);
3444//zz IRTemp tmp16 = newTemp(Ity_I16);
3445//zz IRTemp tmp32 = newTemp(Ity_I32);
3446//zz
3447//zz if (opc1 != 0x1F || b0 != 0) {
3448//zz vex_printf("dis_int_ldst_rev(PPC32)(opc1|b0)\n");
3449//zz return False;
3450//zz }
3451//zz
3452//zz if (Ra_addr == 0) {
3453//zz assign( EA, getIReg(Rb_addr));
3454//zz } else {
3455//zz assign( EA, binop(Iop_Add32, getIReg(Ra_addr), getIReg(Rb_addr)) );
3456//zz }
3457//zz
3458//zz switch (opc2) {
3459//zz case 0x316: // lhbrx (Load Half Word Byte-Reverse Indexed, PPC32 p449)
3460//zz vassert(0);
3461//zz
3462//zz DIP("lhbrx r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
3463//zz assign( byte0, loadBE(Ity_I8, mkexpr(EA)) );
3464//zz assign( byte1, loadBE(Ity_I8, binop(Iop_Add32, mkexpr(EA),mkU32(1))) );
3465//zz assign( Rd, binop(Iop_Or32,
3466//zz binop(Iop_Shl32, mkexpr(byte1), mkU8(8)),
3467//zz mkexpr(byte0)) );
3468//zz putIReg( Rd_addr, mkexpr(Rd));
3469//zz break;
3470//zz
3471//zz case 0x216: // lwbrx (Load Word Byte-Reverse Indexed, PPC32 p459)
3472//zz vassert(0);
3473//zz
3474//zz DIP("lwbrx r%d,r%d,r%d\n", Rd_addr, Ra_addr, Rb_addr);
3475//zz assign( byte0, loadBE(Ity_I8, mkexpr(EA)) );
3476//zz assign( byte1, loadBE(Ity_I8, binop(Iop_Add32, mkexpr(EA),mkU32(1))) );
3477//zz assign( byte2, loadBE(Ity_I8, binop(Iop_Add32, mkexpr(EA),mkU32(2))) );
3478//zz assign( byte3, loadBE(Ity_I8, binop(Iop_Add32, mkexpr(EA),mkU32(3))) );
3479//zz assign( Rd, binop(Iop_Or32,
3480//zz binop(Iop_Or32,
3481//zz binop(Iop_Shl32, mkexpr(byte3), mkU8(24)),
3482//zz binop(Iop_Shl32, mkexpr(byte2), mkU8(16))),
3483//zz binop(Iop_Or32,
3484//zz binop(Iop_Shl32, mkexpr(byte1), mkU8(8)),
3485//zz mkexpr(byte0))) );
3486//zz putIReg( Rd_addr, mkexpr(Rd));
3487//zz break;
3488//zz
3489//zz case 0x396: // sthbrx (Store Half Word Byte-Reverse Indexed, PPC32 p523)
3490//zz vassert(0);
3491//zz
3492//zz DIP("sthbrx r%d,r%d,r%d\n", Rs_addr, Ra_addr, Rb_addr);
3493//zz assign( Rs, getIReg(Rs_addr) );
3494//zz assign( byte0, binop(Iop_And32, mkexpr(Rs), mkU32(0x00FF)) );
3495//zz assign( byte1, binop(Iop_And32, mkexpr(Rs), mkU32(0xFF00)) );
3496//zz
3497//zz assign( tmp16,
3498//zz unop(Iop_32to16,
3499//zz binop(Iop_Or32,
3500//zz binop(Iop_Shl32, mkexpr(byte0), mkU8(8)),
3501//zz binop(Iop_Shr32, mkexpr(byte1), mkU8(8)))) );
3502//zz storeBE( mkexpr(EA), getIReg(tmp16) );
3503//zz break;
3504//zz
3505//zz case 0x296: // stwbrx (Store Word Byte-Reverse Indexed, PPC32 p531)
3506//zz vassert(0);
3507//zz
3508//zz DIP("stwbrx r%d,r%d,r%d\n", Rs_addr, Ra_addr, Rb_addr);
3509//zz assign( Rs, getIReg(Rs_addr) );
3510//zz assign( byte0, binop(Iop_And32, mkexpr(Rs), mkU32(0x000000FF)) );
3511//zz assign( byte1, binop(Iop_And32, mkexpr(Rs), mkU32(0x0000FF00)) );
3512//zz assign( byte2, binop(Iop_And32, mkexpr(Rs), mkU32(0x00FF0000)) );
3513//zz assign( byte3, binop(Iop_And32, mkexpr(Rs), mkU32(0xFF000000)) );
3514//zz
3515//zz assign( tmp32,
3516//zz binop(Iop_Or32,
3517//zz binop(Iop_Or32,
3518//zz binop(Iop_Shl32, mkexpr(byte0), mkU8(24)),
3519//zz binop(Iop_Shl32, mkexpr(byte1), mkU8(8))),
3520//zz binop(Iop_Or32,
3521//zz binop(Iop_Shr32, mkexpr(byte2), mkU8(8)),
3522//zz binop(Iop_Shr32, mkexpr(byte3), mkU8(24)))) );
3523//zz storeBE( mkexpr(EA), mkexpr(tmp32) );
3524//zz break;
3525//zz
3526//zz default:
3527//zz vex_printf("dis_int_ldst_rev(PPC32)(opc2)\n");
3528//zz return False;
3529//zz }
3530//zz return True;
3531//zz }
cerion645c9302005-01-31 10:09:59 +00003532
3533
3534
cerion3d870a32005-03-18 12:23:33 +00003535/*
3536 Processor Control Instructions
3537*/
cerion8c3adda2005-01-31 11:54:05 +00003538static Bool dis_proc_ctl ( UInt theInstr )
3539{
cerionb85e8bb2005-02-16 08:54:33 +00003540 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
3541
3542 /* X-Form */
3543 UChar crfD = toUChar((theInstr >> 23) & 0x7); /* theInstr[23:25] */
3544 UChar b21to22 = toUChar((theInstr >> 21) & 0x3); /* theInstr[21:22] */
3545 UChar Rd_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
3546 UInt b11to20 = (theInstr >> 11) & 0x3FF; /* theInstr[11:20] */
3547
3548 /* XFX-Form */
3549 UChar Rs_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
3550 UInt SPR = (theInstr >> 11) & 0x3FF; /* theInstr[11:20] */
3551 UInt TBR = (theInstr >> 11) & 0x3FF; /* theInstr[11:20] */
3552 UChar b20 = toUChar((theInstr >> 11) & 0x1); /* theInstr[11] */
3553 UInt CRM = (theInstr >> 12) & 0xFF; /* theInstr[12:19] */
3554 UChar b11 = toUChar((theInstr >> 11) & 0x1); /* theInstr[20] */
3555
3556 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
3557 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
3558
3559 UInt SPR_flipped = ((SPR & 0x1F) << 5) | ((SPR >> 5) & 0x1F);
cerione9d361a2005-03-04 17:35:29 +00003560
3561 IRTemp Rs = newTemp(Ity_I32);
3562 IRTemp tmp = newTemp(Ity_I32);
cerion48090c02005-02-24 11:19:51 +00003563
cerionb85e8bb2005-02-16 08:54:33 +00003564 assign( Rs, getIReg(Rs_addr) );
3565
3566 if (opc1 != 0x1F || b0 != 0) {
3567 vex_printf("dis_proc_ctl(PPC32)(opc1|b0)\n");
3568 return False;
3569 }
3570
3571 switch (opc2) {
sewardjb51f0f42005-07-18 11:38:02 +00003572//zz /* X-Form */
3573//zz case 0x200: // mcrxr (Move to Condition Register from XER, PPC32 p466)
3574//zz if (b21to22 != 0 || b11to20 != 0) {
3575//zz vex_printf("dis_proc_ctl(PPC32)(mcrxr,b21to22|b11to20)\n");
3576//zz return False;
3577//zz }
3578//zz DIP("mcrxr crf%d\n", crfD);
3579//zz
3580//zz // CR[7-crfD] = XER[28-31]
3581//zz assign( tmp, getReg_field( PPC32_SPR_XER, 7 ) );
3582//zz putReg_field( PPC32_SPR_CR, mkexpr(tmp), 7-crfD );
3583//zz
3584//zz // Clear XER[28 - 31]
3585//zz putReg_field( PPC32_SPR_XER, mkU32(0), 7 );
3586//zz break;
cerionb85e8bb2005-02-16 08:54:33 +00003587
cerione9d361a2005-03-04 17:35:29 +00003588 case 0x013: // mfcr (Move from Condition Register, PPC32 p467)
cerionb85e8bb2005-02-16 08:54:33 +00003589 if (b11to20 != 0) {
3590 vex_printf("dis_proc_ctl(PPC32)(mfcr,b11to20)\n");
3591 return False;
3592 }
sewardjb51f0f42005-07-18 11:38:02 +00003593 DIP("mfcr r%d\n", Rd_addr);
3594 putIReg( Rd_addr, getEntireCR() );
cerionb85e8bb2005-02-16 08:54:33 +00003595 break;
3596
3597 /* XFX-Form */
cerione9d361a2005-03-04 17:35:29 +00003598 case 0x153: // mfspr (Move from Special-Purpose Register, PPC32 p470)
cerionb85e8bb2005-02-16 08:54:33 +00003599
3600 switch (SPR_flipped) { // Choose a register...
sewardj20ef5472005-07-21 14:48:31 +00003601
3602 case 0x1:
3603 DIP("mfxer r%d\n", Rd_addr);
3604 /* sheesh [kebab] */
3605 putIReg(
3606 Rd_addr,
3607 binop(
3608 Iop_Or32,
3609 binop(
3610 Iop_Or32,
3611 binop( Iop_Shl32,
3612 binop( Iop_And32,
3613 unop( Iop_8Uto32,
3614 IRExpr_Get( OFFB_XER_SO, Ity_I8 )),
3615 mkU32(1)),
3616 mkU8(31)),
3617 binop( Iop_Shl32,
3618 binop( Iop_And32,
3619 unop( Iop_8Uto32,
3620 IRExpr_Get( OFFB_XER_OV, Ity_I8 )),
3621 mkU32(1)),
3622 mkU8(30))
3623 ),
3624 binop(
3625 Iop_Or32,
3626 binop( Iop_Shl32,
3627 binop( Iop_And32,
3628 unop( Iop_8Uto32,
3629 IRExpr_Get( OFFB_XER_CA, Ity_I8 )),
3630 mkU32(1)),
3631 mkU8(29)),
3632 binop( Iop_And32,
3633 unop( Iop_8Uto32,
3634 IRExpr_Get( OFFB_XER_BC, Ity_I8 )),
3635 mkU32(0xFF))
3636 )
3637 )
3638 );
3639 break;
3640
sewardjb51f0f42005-07-18 11:38:02 +00003641 case 0x8:
3642 DIP("mflr r%d\n", Rd_addr);
3643 putIReg( Rd_addr, getSPR( PPC32_SPR_LR ) );
3644 break;
3645 case 0x9:
3646 DIP("mfctr r%d\n", Rd_addr);
3647 putIReg( Rd_addr, getSPR( PPC32_SPR_CTR ) );
3648 break;
3649 case 0x100:
3650 DIP("mfvrsave r%d\n", Rd_addr);
3651 putIReg( Rd_addr, getSPR( PPC32_SPR_VRSAVE ) );
3652 break;
ceriona982c052005-06-28 17:23:09 +00003653
sewardjb51f0f42005-07-18 11:38:02 +00003654 case 0x012: case 0x013: case 0x016:
3655 case 0x019: case 0x01A: case 0x01B:
3656 case 0x110: case 0x111: case 0x112: case 0x113:
3657 // case 0x118: // 64bit only
3658 case 0x11A: case 0x11F:
3659 case 0x210: case 0x211: case 0x212: case 0x213:
3660 case 0x214: case 0x215: case 0x216: case 0x217:
3661 case 0x218: case 0x219: case 0x21A: case 0x21B:
3662 case 0x21C: case 0x21D: case 0x21E: case 0x21F:
3663 case 0x3F5:
3664 vex_printf("dis_proc_ctl(PPC32)(mfspr) - supervisor level op\n");
3665 return False;
cerion45552a92005-02-03 18:20:22 +00003666
sewardjb51f0f42005-07-18 11:38:02 +00003667 default:
3668 vex_printf("dis_proc_ctl(PPC32)(mfspr,SPR_flipped)(0x%x)\n",
3669 SPR_flipped);
3670 return False;
cerionb85e8bb2005-02-16 08:54:33 +00003671 }
3672 break;
3673
sewardjb51f0f42005-07-18 11:38:02 +00003674//zz case 0x173: // mftb (Move from Time Base, PPC32 p475)
3675//zz vassert(0);
3676//zz
3677//zz DIP("mftb r%d,0x%x\n", Rd_addr, TBR);
3678//zz return False;
cerionb85e8bb2005-02-16 08:54:33 +00003679
sewardjb51f0f42005-07-18 11:38:02 +00003680 case 0x090: // mtcrf (Move to Condition Register Fields, PPC32 p477)
cerionb85e8bb2005-02-16 08:54:33 +00003681 if (b11 != 0 || b20 != 0) {
3682 vex_printf("dis_proc_ctl(PPC32)(mtcrf,b11|b20)\n");
3683 return False;
3684 }
3685 DIP("mtcrf 0x%x,r%d\n", CRM, Rs_addr);
sewardjb51f0f42005-07-18 11:38:02 +00003686 putCRfields ( mkexpr(Rs), CRM );
cerionb85e8bb2005-02-16 08:54:33 +00003687 break;
cerione9d361a2005-03-04 17:35:29 +00003688
3689 case 0x1D3: // mtspr (Move to Special-Purpose Register, PPC32 p483)
cerionb85e8bb2005-02-16 08:54:33 +00003690
3691 switch (SPR_flipped) { // Choose a register...
sewardj20ef5472005-07-21 14:48:31 +00003692 case 0x1:
3693 DIP("mtxer r%d\n", Rs_addr);
sewardj0e88d8f2005-07-21 16:58:55 +00003694 stmt(IRStmt_Put(
sewardj20ef5472005-07-21 14:48:31 +00003695 OFFB_XER_SO,
3696 unop( Iop_32to8,
3697 binop( Iop_And32,
sewardj0e88d8f2005-07-21 16:58:55 +00003698 binop(Iop_Shr32, mkexpr(Rs), mkU8(31)),
sewardj20ef5472005-07-21 14:48:31 +00003699 mkU32(1)) )
sewardj0e88d8f2005-07-21 16:58:55 +00003700 ));
3701 stmt(IRStmt_Put(
sewardj20ef5472005-07-21 14:48:31 +00003702 OFFB_XER_OV,
3703 unop( Iop_32to8,
3704 binop( Iop_And32,
sewardj0e88d8f2005-07-21 16:58:55 +00003705 binop(Iop_Shr32, mkexpr(Rs), mkU8(30)),
sewardj20ef5472005-07-21 14:48:31 +00003706 mkU32(1)) )
sewardj0e88d8f2005-07-21 16:58:55 +00003707 ));
3708 stmt(IRStmt_Put(
sewardj20ef5472005-07-21 14:48:31 +00003709 OFFB_XER_CA,
3710 unop( Iop_32to8,
3711 binop( Iop_And32,
sewardj0e88d8f2005-07-21 16:58:55 +00003712 binop(Iop_Shr32, mkexpr(Rs), mkU8(29)),
sewardj20ef5472005-07-21 14:48:31 +00003713 mkU32(1)) )
sewardj0e88d8f2005-07-21 16:58:55 +00003714 ));
3715 stmt(IRStmt_Put(
sewardj20ef5472005-07-21 14:48:31 +00003716 OFFB_XER_BC,
3717 unop( Iop_32to8,
sewardj0e88d8f2005-07-21 16:58:55 +00003718 binop( Iop_And32, mkexpr(Rs), mkU32(0xFF)) )
3719 ));
sewardj20ef5472005-07-21 14:48:31 +00003720 break;
sewardjb51f0f42005-07-18 11:38:02 +00003721 case 0x8:
3722 DIP("mtlr r%d\n", Rs_addr);
3723 putSPR( PPC32_SPR_LR, mkexpr(Rs) );
3724 break;
3725 case 0x9:
3726 DIP("mtctr r%d\n", Rs_addr);
3727 putSPR( PPC32_SPR_CTR, mkexpr(Rs) );
3728 break;
3729 case 0x100:
3730 DIP("mtvrsave r%d\n", Rs_addr);
3731 putSPR( PPC32_SPR_VRSAVE, mkexpr(Rs) );
3732 break;
3733//zz
3734//zz case 0x012: case 0x013: case 0x016:
3735//zz case 0x019: case 0x01A: case 0x01B:
3736//zz case 0x110: case 0x111: case 0x112: case 0x113:
3737//zz // case 0x118: // 64bit only
3738//zz case 0x11A: case 0x11C: case 0x11D:
3739//zz case 0x210: case 0x211: case 0x212: case 0x213:
3740//zz case 0x214: case 0x215: case 0x216: case 0x217:
3741//zz case 0x218: case 0x219: case 0x21A: case 0x21B:
3742//zz case 0x21C: case 0x21D: case 0x21E: case 0x21F:
3743//zz case 0x3F5:
3744//zz vex_printf("dis_proc_ctl(PPC32)(mtspr) - supervisor level op\n");
3745//zz return False;
cerion8c3adda2005-01-31 11:54:05 +00003746
sewardjb51f0f42005-07-18 11:38:02 +00003747 default:
3748 vex_printf("dis_proc_ctl(PPC32)(mtspr,SPR_flipped)(%d)\n",
3749 SPR_flipped);
3750 return False;
cerionb85e8bb2005-02-16 08:54:33 +00003751 }
3752 break;
3753
3754 default:
3755 vex_printf("dis_proc_ctl(PPC32)(opc2)\n");
3756 return False;
3757 }
3758 return True;
cerion8c3adda2005-01-31 11:54:05 +00003759}
3760
3761
cerion3d870a32005-03-18 12:23:33 +00003762/*
3763 Cache Management Instructions
3764*/
sewardjd94b73a2005-06-30 12:08:48 +00003765static Bool dis_cache_manage ( UInt theInstr,
sewardj9e6491a2005-07-02 19:24:10 +00003766 DisResult* dres,
sewardjd94b73a2005-06-30 12:08:48 +00003767 VexArchInfo* guest_archinfo )
cerion8c3adda2005-01-31 11:54:05 +00003768{
cerionb85e8bb2005-02-16 08:54:33 +00003769 /* X-Form */
3770 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
3771 UChar b21to25 = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
3772 UChar Ra_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
3773 UChar Rb_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
3774 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
3775 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
sewardjb51f0f42005-07-18 11:38:02 +00003776 Int lineszB = guest_archinfo->ppc32_cache_line_szB;
cerion094d1392005-06-20 13:45:57 +00003777
cerionb85e8bb2005-02-16 08:54:33 +00003778 if (opc1 != 0x1F || b21to25 != 0 || b0 != 0) {
3779 vex_printf("dis_cache_manage(PPC32)(opc1|b21to25|b0)\n");
3780 return False;
3781 }
sewardjd94b73a2005-06-30 12:08:48 +00003782
3783 /* stay sane .. */
3784 vassert(lineszB == 32 || lineszB == 128);
cerionb85e8bb2005-02-16 08:54:33 +00003785
3786 switch (opc2) {
sewardjb51f0f42005-07-18 11:38:02 +00003787//zz case 0x2F6: // dcba (Data Cache Block Allocate, PPC32 p380)
3788//zz vassert(0); /* AWAITING TEST CASE */
3789//zz DIP("dcba r%d,r%d\n", Ra_addr, Rb_addr);
3790//zz if (0) vex_printf("vex ppc32->IR: kludged dcba\n");
3791//zz break;
sewardj20ef5472005-07-21 14:48:31 +00003792
3793 case 0x056: // dcbf (Data Cache Block Flush, PPC32 p382)
3794 DIP("dcbf r%d,r%d\n", Ra_addr, Rb_addr);
3795 /* nop as far as vex is concerned */
3796 if (0) vex_printf("vex ppc32->IR: kludged dcbf\n");
3797 break;
cerionb85e8bb2005-02-16 08:54:33 +00003798
cerione9d361a2005-03-04 17:35:29 +00003799 case 0x036: // dcbst (Data Cache Block Store, PPC32 p384)
cerionb85e8bb2005-02-16 08:54:33 +00003800 DIP("dcbst r%d,r%d\n", Ra_addr, Rb_addr);
sewardjb51f0f42005-07-18 11:38:02 +00003801 /* nop as far as vex is concerned */
cerionb85e8bb2005-02-16 08:54:33 +00003802 break;
cerion8c3adda2005-01-31 11:54:05 +00003803
cerione9d361a2005-03-04 17:35:29 +00003804 case 0x116: // dcbt (Data Cache Block Touch, PPC32 p385)
cerionb85e8bb2005-02-16 08:54:33 +00003805 DIP("dcbt r%d,r%d\n", Ra_addr, Rb_addr);
sewardjb51f0f42005-07-18 11:38:02 +00003806 /* nop as far as vex is concerned */
cerionb85e8bb2005-02-16 08:54:33 +00003807 break;
3808
cerione9d361a2005-03-04 17:35:29 +00003809 case 0x0F6: // dcbtst (Data Cache Block Touch for Store, PPC32 p386)
cerionb85e8bb2005-02-16 08:54:33 +00003810 DIP("dcbtst r%d,r%d\n", Ra_addr, Rb_addr);
sewardjb51f0f42005-07-18 11:38:02 +00003811 /* nop as far as vex is concerned */
cerionb85e8bb2005-02-16 08:54:33 +00003812 break;
3813
cerion094d1392005-06-20 13:45:57 +00003814 case 0x3F6: { // dcbz (Data Cache Block Clear to Zero, PPC32 p387)
sewardjd94b73a2005-06-30 12:08:48 +00003815 /* Clear all bytes in cache block at (rA|0) + rB. */
cerion094d1392005-06-20 13:45:57 +00003816 IRTemp EA = newTemp(Ity_I32);
3817 IRTemp addr = newTemp(Ity_I32);
3818 IRExpr* irx_addr;
cerion094d1392005-06-20 13:45:57 +00003819 UInt i;
cerionb85e8bb2005-02-16 08:54:33 +00003820 DIP("dcbz r%d,r%d\n", Ra_addr, Rb_addr);
cerion094d1392005-06-20 13:45:57 +00003821 assign( EA,
3822 binop( Iop_Add32,
3823 getIReg(Rb_addr),
3824 Ra_addr==0 ? mkU32(0) : getIReg(Ra_addr)) );
3825
3826 /* Round EA down to the start of the containing block. */
3827 assign( addr,
3828 binop( Iop_And32,
3829 mkexpr(EA),
sewardjd94b73a2005-06-30 12:08:48 +00003830 mkU32( ~(lineszB-1) )) );
cerion094d1392005-06-20 13:45:57 +00003831
sewardjd94b73a2005-06-30 12:08:48 +00003832 for (i = 0; i < lineszB / 4; i++) {
3833 irx_addr = binop( Iop_Add32, mkexpr(addr), mkU32(i*4) );
3834 storeBE( irx_addr, mkU32(0) );
cerion094d1392005-06-20 13:45:57 +00003835 }
cerionb85e8bb2005-02-16 08:54:33 +00003836 break;
cerion094d1392005-06-20 13:45:57 +00003837 }
cerion8c3adda2005-01-31 11:54:05 +00003838
sewardj7ce9d152005-03-15 16:54:13 +00003839 case 0x3D6: {
3840 // icbi (Instruction Cache Block Invalidate, PPC32 p431)
3841 /* Invalidate all translations containing code from the cache
sewardjd94b73a2005-06-30 12:08:48 +00003842 block at (rA|0) + rB. */
sewardj7ce9d152005-03-15 16:54:13 +00003843 IRTemp addr = newTemp(Ity_I32);
cerionb85e8bb2005-02-16 08:54:33 +00003844 DIP("icbi r%d,r%d\n", Ra_addr, Rb_addr);
sewardj7ce9d152005-03-15 16:54:13 +00003845
3846 assign( addr,
3847 binop( Iop_Add32,
3848 getIReg(Rb_addr),
3849 Ra_addr==0 ? mkU32(0) : getIReg(Ra_addr)) );
3850
3851 /* Round addr down to the start of the containing block. */
3852 stmt( IRStmt_Put(
3853 OFFB_TISTART,
3854 binop( Iop_And32,
3855 mkexpr(addr),
sewardjd94b73a2005-06-30 12:08:48 +00003856 mkU32( ~(lineszB-1) ))) );
sewardj7ce9d152005-03-15 16:54:13 +00003857
sewardjd94b73a2005-06-30 12:08:48 +00003858 stmt( IRStmt_Put(OFFB_TILEN, mkU32(lineszB) ) );
sewardj7ce9d152005-03-15 16:54:13 +00003859
sewardja8078f62005-03-15 18:27:40 +00003860 /* be paranoid ... */
3861 stmt( IRStmt_MFence() );
3862
sewardj7ce9d152005-03-15 16:54:13 +00003863 irbb->jumpkind = Ijk_TInval;
sewardj9e6491a2005-07-02 19:24:10 +00003864 irbb->next = mkU32(guest_CIA_curr_instr + 4);
3865 dres->whatNext = Dis_StopHere;
cerionb85e8bb2005-02-16 08:54:33 +00003866 break;
sewardj7ce9d152005-03-15 16:54:13 +00003867 }
cerion8c3adda2005-01-31 11:54:05 +00003868
cerionb85e8bb2005-02-16 08:54:33 +00003869 default:
3870 vex_printf("dis_cache_manage(PPC32)(opc2)\n");
3871 return False;
3872 }
3873 return True;
cerion8c3adda2005-01-31 11:54:05 +00003874}
3875
3876
sewardjb51f0f42005-07-18 11:38:02 +00003877//zz /*------------------------------------------------------------*/
3878//zz /*--- Floating Point Helpers ---*/
3879//zz /*------------------------------------------------------------*/
3880//zz
3881//zz /* --- Set the emulation-warning pseudo-register. --- */
3882//zz
3883//zz static void put_emwarn ( IRExpr* e /* :: Ity_I32 */ )
3884//zz {
3885//zz stmt( IRStmt_Put( OFFB_EMWARN, e ) );
3886//zz }
3887//zz
3888//zz /* --------- Synthesise a 2-bit FPU rounding mode. --------- */
3889//zz /* Produces a value in 0 .. 3, which is encoded as per the type
3890//zz IRRoundingMode. PPC32RoundingMode encoding is different to
3891//zz IRRoundingMode, so need to map it.
3892//zz */
3893//zz static IRExpr* /* :: Ity_I32 */ get_roundingmode ( void )
3894//zz {
3895//zz /*
3896//zz rounding mode | PPC | IR
3897//zz ------------------------
3898//zz to nearest | 00 | 00
3899//zz to zero | 01 | 11
3900//zz to +infinity | 10 | 10
3901//zz to -infinity | 11 | 01
3902//zz */
3903//zz IRTemp rm_PPC32 = newTemp(Ity_I32);
3904//zz assign( rm_PPC32, getReg_masked( PPC32_SPR_FPSCR, MASK_FPSCR_RN ) );
3905//zz
3906//zz // rm_IR = XOR( rm_PPC32, (rm_PPC32 << 1) & 2)
3907//zz return binop(Iop_Xor32, mkexpr(rm_PPC32),
3908//zz binop(Iop_And32, mkU32(2),
3909//zz binop(Iop_Shl32, mkexpr(rm_PPC32), mkU8(1))));
3910//zz }
3911//zz
3912//zz /* Round float to single precision
3913//zz - returns type Ity_F64 */
3914//zz static IRExpr* roundToSgl ( IRExpr* src )
3915//zz {
3916//zz return unop(Iop_F32toF64, binop(Iop_F64toF32, get_roundingmode(), src));
3917//zz }
cerion094d1392005-06-20 13:45:57 +00003918
3919
cerion3d870a32005-03-18 12:23:33 +00003920/*------------------------------------------------------------*/
3921/*--- Floating Point Instruction Translation ---*/
3922/*------------------------------------------------------------*/
3923
3924/*
3925 Floating Point Load Instructions
3926*/
3927static Bool dis_fp_load ( UInt theInstr )
3928{
3929 /* X-Form */
cerion094d1392005-06-20 13:45:57 +00003930 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
3931 UChar frD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
3932 UChar rA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
3933 UChar rB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
3934 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
3935 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
cerion3d870a32005-03-18 12:23:33 +00003936
3937 /* D-Form */
cerion094d1392005-06-20 13:45:57 +00003938 UInt d_imm = (theInstr >> 0) & 0xFFFF; /* theInstr[0:15] */
3939
sewardjdb36c0f2005-07-03 00:05:31 +00003940 Int exts_d_imm = extend_s_16to32(d_imm);
cerion094d1392005-06-20 13:45:57 +00003941
3942 IRTemp EA = newTemp(Ity_I32);
3943 IRTemp rA = newTemp(Ity_I32);
3944 IRTemp rB = newTemp(Ity_I32);
3945 IRTemp rA_or_0 = newTemp(Ity_I32);
3946
3947 assign( rA, getIReg(rA_addr) );
3948 assign( rB, getIReg(rB_addr) );
3949 assign( rA_or_0, (rA_addr == 0) ? mkU32(0) : mkexpr(rA) );
cerion3d870a32005-03-18 12:23:33 +00003950
3951 switch(opc1) {
sewardjb51f0f42005-07-18 11:38:02 +00003952//zz case 0x30: // lfs (Load Float Single, PPC32 p441)
3953//zz DIP("lfs fr%d,%d(r%d)\n", frD_addr, exts_d_imm, rA_addr);
3954//zz assign( EA, binop(Iop_Add32, mkU32(exts_d_imm), mkexpr(rA_or_0)) );
3955//zz putFReg( frD_addr, unop(Iop_F32toF64, loadBE(Ity_F32, mkexpr(EA))) );
3956//zz break;
3957//zz
3958//zz case 0x31: // lfsu (Load Float Single with Update, PPC32 p442)
3959//zz if (rA_addr == 0) {
3960//zz vex_printf("dis_fp_load(PPC32)(instr,lfsu)\n");
3961//zz return False;
3962//zz }
3963//zz DIP("lfsu fr%d,%d(r%d)\n", frD_addr, exts_d_imm, rA_addr);
3964//zz assign( EA, binop(Iop_Add32, mkU32(exts_d_imm), mkexpr(rA)) );
3965//zz putFReg( frD_addr, unop(Iop_F32toF64, loadBE(Ity_F32, mkexpr(EA))) );
3966//zz putIReg( rA_addr, mkexpr(EA) );
3967//zz break;
cerion094d1392005-06-20 13:45:57 +00003968
3969 case 0x32: // lfd (Load Float Double, PPC32 p437)
sewardjdb36c0f2005-07-03 00:05:31 +00003970 DIP("lfd fr%d,%d(r%d)\n", frD_addr, exts_d_imm, rA_addr);
cerion094d1392005-06-20 13:45:57 +00003971 assign( EA, binop(Iop_Add32, mkU32(exts_d_imm), mkexpr(rA_or_0)) );
3972 putFReg( frD_addr, loadBE(Ity_F64, mkexpr(EA)) );
3973 break;
cerion3d870a32005-03-18 12:23:33 +00003974
sewardjb51f0f42005-07-18 11:38:02 +00003975//zz case 0x33: // lfdu (Load Float Double with Update, PPC32 p438)
3976//zz if (rA_addr == 0) {
3977//zz vex_printf("dis_fp_load(PPC32)(instr,lfdu)\n");
3978//zz return False;
3979//zz }
3980//zz DIP("lfdu fr%d,%d(r%d)\n", frD_addr, exts_d_imm, rA_addr);
3981//zz assign( EA, binop(Iop_Add32, mkU32(exts_d_imm), mkexpr(rA)) );
3982//zz putFReg( frD_addr, loadBE(Ity_F64, mkexpr(EA)) );
3983//zz putIReg( rA_addr, mkexpr(EA) );
3984//zz break;
3985//zz
3986//zz case 0x1F:
3987//zz if (b0 != 0) {
3988//zz vex_printf("dis_fp_load(PPC32)(instr,b0)\n");
3989//zz return False;
3990//zz }
3991//zz
3992//zz switch(opc2) {
3993//zz case 0x217: // lfsx (Load Float Single Indexed, PPC32 p444)
3994//zz DIP("lfsx fr%d,r%d,r%d\n", frD_addr, rA_addr, rB_addr);
3995//zz assign( EA, binop(Iop_Add32, mkexpr(rB), mkexpr(rA_or_0)) );
3996//zz putFReg( frD_addr, unop(Iop_F32toF64, loadBE(Ity_F32, mkexpr(EA))) );
3997//zz break;
3998//zz
3999//zz case 0x237: // lfsux (Load Float Single with Update Indexed, PPC32 p443)
4000//zz if (rA_addr == 0) {
4001//zz vex_printf("dis_fp_load(PPC32)(instr,lfsux)\n");
4002//zz return False;
4003//zz }
4004//zz DIP("lfsux fr%d,r%d,r%d\n", frD_addr, rA_addr, rB_addr);
4005//zz assign( EA, binop(Iop_Add32, mkexpr(rB), mkexpr(rA)) );
4006//zz putFReg( frD_addr, unop(Iop_F32toF64, loadBE(Ity_F32, mkexpr(EA))) );
4007//zz putIReg( rA_addr, mkexpr(EA) );
4008//zz break;
4009//zz
4010//zz case 0x257: // lfdx (Load Float Double Indexed, PPC32 p440)
4011//zz DIP("lfdx fr%d,r%d,r%d\n", frD_addr, rA_addr, rB_addr);
4012//zz assign( EA, binop(Iop_Add32, mkexpr(rB), mkexpr(rA_or_0)) );
4013//zz putFReg( frD_addr, loadBE(Ity_F64, mkexpr(EA)) );
4014//zz break;
4015//zz
4016//zz case 0x277: // lfdux (Load Float Double with Update Indexed, PPC32 p439)
4017//zz if (rA_addr == 0) {
4018//zz vex_printf("dis_fp_load(PPC32)(instr,lfdux)\n");
4019//zz return False;
4020//zz }
4021//zz DIP("lfdux fr%d,r%d,r%d\n", frD_addr, rA_addr, rB_addr);
4022//zz assign( EA, binop(Iop_Add32, mkexpr(rB), mkexpr(rA)) );
4023//zz putFReg( frD_addr, loadBE(Ity_F64, mkexpr(EA)) );
4024//zz putIReg( rA_addr, mkexpr(EA) );
4025//zz break;
4026//zz
4027//zz default:
4028//zz vex_printf("dis_fp_load(PPC32)(opc2)\n");
4029//zz return False;
4030//zz }
4031//zz break;
cerion3d870a32005-03-18 12:23:33 +00004032
4033 default:
4034 vex_printf("dis_fp_load(PPC32)(opc1)\n");
4035 return False;
4036 }
4037 return True;
4038}
4039
4040
4041
4042/*
4043 Floating Point Store Instructions
4044*/
4045static Bool dis_fp_store ( UInt theInstr )
4046{
4047 /* X-Form */
cerion094d1392005-06-20 13:45:57 +00004048 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
4049 UChar frS_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
4050 UChar rA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
4051 UChar rB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
4052 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
4053 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
cerion3d870a32005-03-18 12:23:33 +00004054
4055 /* D-Form */
cerion094d1392005-06-20 13:45:57 +00004056 UInt d_imm = (theInstr >> 0) & 0xFFFF; /* theInstr[0:15] */
4057
sewardjdb36c0f2005-07-03 00:05:31 +00004058 Int exts_d_imm = extend_s_16to32(d_imm);
cerion094d1392005-06-20 13:45:57 +00004059
4060 IRTemp EA = newTemp(Ity_I32);
4061 IRTemp frS = newTemp(Ity_F64);
4062 IRTemp rA = newTemp(Ity_I32);
4063 IRTemp rB = newTemp(Ity_I32);
4064 IRTemp rA_or_0 = newTemp(Ity_I32);
4065
4066 assign( frS, getFReg(frS_addr) );
4067 assign( rA, getIReg(rA_addr) );
4068 assign( rB, getIReg(rB_addr) );
4069 assign( rA_or_0, (rA_addr == 0) ? mkU32(0) : mkexpr(rA) );
cerion3d870a32005-03-18 12:23:33 +00004070
4071 switch(opc1) {
sewardjb51f0f42005-07-18 11:38:02 +00004072//zz case 0x34: // stfs (Store Float Single, PPC32 p518)
4073//zz DIP("stfs fr%d,%d(r%d)\n", frS_addr, exts_d_imm, rA_addr);
4074//zz assign( EA, binop(Iop_Add32, mkU32(exts_d_imm), mkexpr(rA_or_0)) );
4075//zz storeBE( mkexpr(EA),
4076//zz binop(Iop_F64toF32, get_roundingmode(), mkexpr(frS)) );
4077//zz break;
4078//zz
4079//zz case 0x35: // stfsu (Store Float Single with Update, PPC32 p519)
4080//zz if (rA_addr == 0) {
4081//zz vex_printf("dis_fp_store(PPC32)(instr,stfsu)\n");
4082//zz return False;
4083//zz }
4084//zz DIP("stfsu fr%d,%d(r%d)\n", frS_addr, exts_d_imm, rA_addr);
4085//zz assign( EA, binop(Iop_Add32, mkU32(exts_d_imm), mkexpr(rA)) );
4086//zz storeBE( mkexpr(EA),
4087//zz binop(Iop_F64toF32, get_roundingmode(), mkexpr(frS)) );
4088//zz putIReg( rA_addr, mkexpr(EA) );
4089//zz break;
cerion3d870a32005-03-18 12:23:33 +00004090
cerion094d1392005-06-20 13:45:57 +00004091 case 0x36: // stfd (Store Float Double, PPC32 p513)
sewardjdb36c0f2005-07-03 00:05:31 +00004092 DIP("stfd fr%d,%d(r%d)\n", frS_addr, exts_d_imm, rA_addr);
cerion094d1392005-06-20 13:45:57 +00004093 assign( EA, binop(Iop_Add32, mkU32(exts_d_imm), mkexpr(rA_or_0)) );
4094 storeBE( mkexpr(EA), mkexpr(frS) );
4095 break;
cerion3d870a32005-03-18 12:23:33 +00004096
sewardjb51f0f42005-07-18 11:38:02 +00004097//zz case 0x37: // stfdu (Store Float Double with Update, PPC32 p514)
4098//zz if (rA_addr == 0) {
4099//zz vex_printf("dis_fp_store(PPC32)(instr,stfdu)\n");
4100//zz return False;
4101//zz }
4102//zz DIP("stfdu fr%d,%d(r%d)\n", frS_addr, exts_d_imm, rA_addr);
4103//zz assign( EA, binop(Iop_Add32, mkU32(exts_d_imm), mkexpr(rA)) );
4104//zz storeBE( mkexpr(EA), mkexpr(frS) );
4105//zz putIReg( rA_addr, mkexpr(EA) );
4106//zz break;
4107//zz
4108//zz case 0x1F:
4109//zz if (b0 != 0) {
4110//zz vex_printf("dis_fp_store(PPC32)(instr,b0)\n");
4111//zz return False;
4112//zz }
4113//zz
4114//zz switch(opc2) {
4115//zz case 0x297: // stfsx (Store Float Single Indexed, PPC32 p521)
4116//zz DIP("stfsx fr%d,r%d,r%d\n", frS_addr, rA_addr, rB_addr);
4117//zz assign( EA, binop(Iop_Add32, mkexpr(rB), mkexpr(rA_or_0)) );
4118//zz storeBE( mkexpr(EA),
4119//zz binop(Iop_F64toF32, get_roundingmode(), mkexpr(frS)) );
4120//zz break;
4121//zz
4122//zz case 0x2B7: // stfsux (Store Float Single with Update Indexed, PPC32 p520)
4123//zz if (rA_addr == 0) {
4124//zz vex_printf("dis_fp_store(PPC32)(instr,stfsux)\n");
4125//zz return False;
4126//zz }
4127//zz DIP("stfsux fr%d,r%d,r%d\n", frS_addr, rA_addr, rB_addr);
4128//zz assign( EA, binop(Iop_Add32, mkexpr(rB), mkexpr(rA)) );
4129//zz storeBE( mkexpr(EA),
4130//zz binop(Iop_F64toF32, get_roundingmode(), mkexpr(frS)) );
4131//zz putIReg( rA_addr, mkexpr(EA) );
4132//zz break;
4133//zz
4134//zz case 0x2D7: // stfdx (Store Float Double Indexed, PPC32 p516)
4135//zz DIP("stfdx fr%d,r%d,r%d\n", frS_addr, rA_addr, rB_addr);
4136//zz assign( EA, binop(Iop_Add32, mkexpr(rB), mkexpr(rA_or_0)) );
4137//zz storeBE( mkexpr(EA), mkexpr(frS) );
4138//zz break;
4139//zz
4140//zz case 0x2F7: // stfdux (Store Float Double with Update Indexed, PPC32 p515)
4141//zz if (rA_addr == 0) {
4142//zz vex_printf("dis_fp_store(PPC32)(instr,stfdux)\n");
4143//zz return False;
4144//zz }
4145//zz DIP("stfdux fr%d,r%d,r%d\n", frS_addr, rA_addr, rB_addr);
4146//zz assign( EA, binop(Iop_Add32, mkexpr(rB), mkexpr(rA)) );
4147//zz storeBE( mkexpr(EA), mkexpr(frS) );
4148//zz putIReg( rA_addr, mkexpr(EA) );
4149//zz break;
4150//zz
4151//zz case 0x3D7: // stfiwx (Store Float as Int, Indexed, PPC32 p517)
4152//zz DIP("stfiwx fr%d,r%d,r%d\n", frS_addr, rA_addr, rB_addr);
4153//zz assign( EA, binop(Iop_Add32, mkexpr(rB), mkexpr(rA_or_0)) );
4154//zz storeBE( mkexpr(EA),
4155//zz unop(Iop_64to32, unop(Iop_ReinterpF64asI64, mkexpr(frS))) );
4156//zz break;
4157//zz
4158//zz default:
4159//zz vex_printf("dis_fp_store(PPC32)(opc2)\n");
4160//zz return False;
4161//zz }
4162//zz break;
cerion3d870a32005-03-18 12:23:33 +00004163
4164 default:
4165 vex_printf("dis_fp_store(PPC32)(opc1)\n");
4166 return False;
4167 }
4168 return True;
4169}
4170
4171
4172
4173/*
4174 Floating Point Arith Instructions
4175*/
4176static Bool dis_fp_arith ( UInt theInstr )
4177{
4178 /* A-Form */
4179 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
4180 UChar frD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
4181 UChar frA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
4182 UChar frB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
4183 UChar frC_addr = toUChar((theInstr >> 6) & 0x1F); /* theInstr[6:10] */
4184 UChar opc2 = toUChar((theInstr >> 1) & 0x1F); /* theInstr[1:5] */
4185 UChar flag_Rc = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
cerion094d1392005-06-20 13:45:57 +00004186 // Note: flag_Rc ignored as fp exceptions not supported.
4187
4188 IRTemp frD = newTemp(Ity_F64);
4189 IRTemp frA = newTemp(Ity_F64);
4190 IRTemp frB = newTemp(Ity_F64);
4191 IRTemp frC = newTemp(Ity_F64);
4192
4193 assign( frA, getFReg(frA_addr));
4194 assign( frB, getFReg(frB_addr));
4195 assign( frC, getFReg(frC_addr));
cerion3d870a32005-03-18 12:23:33 +00004196
4197 switch (opc1) {
sewardjb51f0f42005-07-18 11:38:02 +00004198//zz case 0x3B:
4199//zz switch (opc2) {
4200//zz case 0x12: // fdivs (Floating Divide Single, PPC32 p407)
4201//zz if (frC_addr != 0) {
4202//zz vex_printf("dis_fp_arith(PPC32)(instr,fdivs)\n");
4203//zz return False;
4204//zz }
4205//zz DIP("fdivs%s fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4206//zz frD_addr, frA_addr, frB_addr);
4207//zz assign( frD, roundToSgl( binop(Iop_DivF64, mkexpr(frA), mkexpr(frB)) ));
4208//zz break;
4209//zz
4210//zz case 0x14: // fsubs (Floating Subtract Single, PPC32 p430)
4211//zz if (frC_addr != 0) {
4212//zz vex_printf("dis_fp_arith(PPC32)(instr,fsubs)\n");
4213//zz return False;
4214//zz }
4215//zz DIP("fsubs%s fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4216//zz frD_addr, frA_addr, frB_addr);
4217//zz assign( frD, roundToSgl( binop(Iop_SubF64, mkexpr(frA), mkexpr(frB)) ));
4218//zz break;
4219//zz
4220//zz case 0x15: // fadds (Floating Add Single, PPC32 p401)
4221//zz if (frC_addr != 0) {
4222//zz vex_printf("dis_fp_arith(PPC32)(instr,fadds)\n");
4223//zz return False;
4224//zz }
4225//zz DIP("fadds%s fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4226//zz frD_addr, frA_addr, frB_addr);
4227//zz assign( frD, roundToSgl( binop(Iop_AddF64, mkexpr(frA), mkexpr(frB)) ));
4228//zz break;
4229//zz
4230//zz case 0x16: // fsqrts (Floating SqRt (Single-Precision), PPC32 p428)
4231//zz if (frA_addr != 0 || frC_addr != 0) {
4232//zz vex_printf("dis_fp_arith(PPC32)(instr,fsqrts)\n");
4233//zz return False;
4234//zz }
4235//zz DIP("fsqrts%s fr%d,fr%d\n", flag_Rc ? "." : "",
4236//zz frD_addr, frB_addr);
4237//zz assign( frD, roundToSgl( unop(Iop_SqrtF64, mkexpr(frB)) ));
4238//zz break;
4239//zz
4240//zz case 0x18: // fres (Floating Reciprocal Estimate Single, PPC32 p421)
4241//zz if (frA_addr != 0 || frC_addr != 0) {
4242//zz vex_printf("dis_fp_arith(PPC32)(instr,fres)\n");
4243//zz return False;
4244//zz }
4245//zz DIP("fres%s fr%d,fr%d\n", flag_Rc ? "." : "",
4246//zz frD_addr, frB_addr);
4247//zz DIP(" => not implemented\n");
4248//zz // CAB: Can we use one of the 128 bit SIMD Iop_Recip32F ops?
4249//zz return False;
4250//zz
4251//zz case 0x19: // fmuls (Floating Multiply Single, PPC32 p414)
4252//zz if (frB_addr != 0) {
4253//zz vex_printf("dis_fp_arith(PPC32)(instr,fmuls)\n");
4254//zz return False;
4255//zz }
4256//zz DIP("fmuls%s fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4257//zz frD_addr, frA_addr, frC_addr);
4258//zz assign( frD, roundToSgl( binop(Iop_MulF64, mkexpr(frA), mkexpr(frC)) ));
4259//zz break;
4260//zz
4261//zz default:
4262//zz vex_printf("dis_fp_arith(PPC32)(3B: opc2)\n");
4263//zz return False;
4264//zz }
4265//zz break;
cerion094d1392005-06-20 13:45:57 +00004266
cerion3d870a32005-03-18 12:23:33 +00004267 case 0x3F:
4268 switch (opc2) {
sewardjb51f0f42005-07-18 11:38:02 +00004269//zz case 0x12: // fdiv (Floating Divide (Double-Precision), PPC32 p406)
4270//zz if (frC_addr != 0) {
4271//zz vex_printf("dis_fp_arith(PPC32)(instr,fdiv)\n");
4272//zz return False;
4273//zz }
4274//zz DIP("fdiv%s fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4275//zz frD_addr, frA_addr, frB_addr);
4276//zz assign( frD, binop( Iop_DivF64, mkexpr(frA), mkexpr(frB) ) );
4277//zz break;
4278//zz
4279//zz case 0x14: // fsub (Floating Subtract (Double-Precision), PPC32 p429)
4280//zz if (frC_addr != 0) {
4281//zz vex_printf("dis_fp_arith(PPC32)(instr,fsub)\n");
4282//zz return False;
4283//zz }
4284//zz DIP("fsub%s fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4285//zz frD_addr, frA_addr, frB_addr);
4286//zz assign( frD, binop( Iop_SubF64, mkexpr(frA), mkexpr(frB) ) );
4287//zz break;
cerion3d870a32005-03-18 12:23:33 +00004288
4289 case 0x15: // fadd (Floating Add (Double-Precision), PPC32 p400)
4290 if (frC_addr != 0) {
cerion094d1392005-06-20 13:45:57 +00004291 vex_printf("dis_fp_arith(PPC32)(instr,fadd)\n");
cerion3d870a32005-03-18 12:23:33 +00004292 return False;
4293 }
4294 DIP("fadd%s fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4295 frD_addr, frA_addr, frB_addr);
cerion094d1392005-06-20 13:45:57 +00004296 assign( frD, binop( Iop_AddF64, mkexpr(frA), mkexpr(frB) ) );
4297 break;
cerion3d870a32005-03-18 12:23:33 +00004298
sewardjb51f0f42005-07-18 11:38:02 +00004299//zz case 0x16: // fsqrt (Floating SqRt (Double-Precision), PPC32 p427)
4300//zz if (frA_addr != 0 || frC_addr != 0) {
4301//zz vex_printf("dis_fp_arith(PPC32)(instr,fsqrt)\n");
4302//zz return False;
4303//zz }
4304//zz DIP("fsqrt%s fr%d,fr%d\n", flag_Rc ? "." : "",
4305//zz frD_addr, frB_addr);
4306//zz assign( frD, unop( Iop_SqrtF64, mkexpr(frB) ) );
4307//zz break;
4308//zz
4309//zz case 0x17: { // fsel (Floating Select, PPC32 p426)
4310//zz IRTemp cc = newTemp(Ity_I32);
4311//zz IRTemp cc_b0 = newTemp(Ity_I32);
4312//zz
4313//zz DIP("fsel%s fr%d,fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4314//zz frD_addr, frA_addr, frC_addr, frB_addr);
4315//zz
4316//zz // cc: UN == 0x41, LT == 0x01, GT == 0x00, EQ == 0x40
4317//zz // => GT|EQ == (cc & 0x1 == 0)
4318//zz assign( cc, binop(Iop_CmpF64, mkexpr(frA), IRExpr_Const(IRConst_F64(0))) );
4319//zz assign( cc_b0, binop(Iop_And32, mkexpr(cc), mkU32(1)) );
4320//zz
4321//zz // frD = (frA >= 0.0) ? frC : frB
4322//zz // = (cc_b0 == 0) ? frC : frB
4323//zz assign( frD,
4324//zz IRExpr_Mux0X(
4325//zz unop(Iop_1Uto8,
4326//zz binop(Iop_CmpEQ32, mkexpr(cc_b0), mkU32(0))),
4327//zz mkexpr(frB),
4328//zz mkexpr(frC) ));
4329//zz break;
4330//zz }
4331//zz
4332//zz case 0x19: // fmul (Floating Multiply (Double Precision), PPC32 p413)
4333//zz if (frB_addr != 0) {
4334//zz vex_printf("dis_fp_arith(PPC32)(instr,fmul)\n");
4335//zz return False;
4336//zz }
4337//zz DIP("fmul%s fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4338//zz frD_addr, frA_addr, frC_addr);
4339//zz assign( frD, binop( Iop_MulF64, mkexpr(frA), mkexpr(frC) ) );
4340//zz break;
4341//zz
4342//zz case 0x1A: // frsqrte (Floating Reciprocal SqRt Estimate, PPC32 p424)
4343//zz if (frA_addr != 0 || frC_addr != 0) {
4344//zz vex_printf("dis_fp_arith(PPC32)(instr,frsqrte)\n");
4345//zz return False;
4346//zz }
4347//zz DIP("frsqrte%s fr%d,fr%d\n", flag_Rc ? "." : "",
4348//zz frD_addr, frB_addr);
4349//zz DIP(" => not implemented\n");
4350//zz // CAB: Iop_SqrtF64, then one of the 128 bit SIMD Iop_Recip32F ops?
4351//zz return False;
cerion3d870a32005-03-18 12:23:33 +00004352
4353 default:
4354 vex_printf("dis_fp_arith(PPC32)(3F: opc2)\n");
4355 return False;
4356 }
cerion094d1392005-06-20 13:45:57 +00004357 break;
4358
cerion3d870a32005-03-18 12:23:33 +00004359 default:
4360 vex_printf("dis_fp_arith(PPC32)(opc1)\n");
4361 return False;
4362 }
cerion094d1392005-06-20 13:45:57 +00004363
4364 putFReg( frD_addr, mkexpr(frD) );
cerion3d870a32005-03-18 12:23:33 +00004365 return True;
4366}
4367
4368
4369
sewardjb51f0f42005-07-18 11:38:02 +00004370//zz /*
4371//zz Floating Point Mult-Add Instructions
4372//zz */
4373//zz static Bool dis_fp_multadd ( UInt theInstr )
4374//zz {
4375//zz /* A-Form */
4376//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
4377//zz UChar frD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
4378//zz UChar frA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
4379//zz UChar frB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
4380//zz UChar frC_addr = toUChar((theInstr >> 6) & 0x1F); /* theInstr[6:10] */
4381//zz UChar opc2 = toUChar((theInstr >> 1) & 0x1F); /* theInstr[1:5] */
4382//zz UChar flag_Rc = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
4383//zz
4384//zz IRTemp frD = newTemp(Ity_F64);
4385//zz IRTemp frA = newTemp(Ity_F64);
4386//zz IRTemp frB = newTemp(Ity_F64);
4387//zz IRTemp frC = newTemp(Ity_F64);
4388//zz
4389//zz assign( frA, getFReg(frA_addr));
4390//zz assign( frB, getFReg(frB_addr));
4391//zz assign( frC, getFReg(frC_addr));
4392//zz
4393//zz switch (opc1) {
4394//zz case 0x3B:
4395//zz switch (opc2) {
4396//zz case 0x1C: // fmsubs (Floating Mult-Subtr Single, PPC32 p412)
4397//zz DIP("fmsubs%s fr%d,fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4398//zz frD_addr, frA_addr, frC_addr, frB_addr);
4399//zz assign( frD, roundToSgl( binop(Iop_SubF64,
4400//zz binop(Iop_MulF64, mkexpr(frA), mkexpr(frC)),
4401//zz mkexpr(frB)) ));
4402//zz break;
4403//zz
4404//zz case 0x1D: // fmadds (Floating Mult-Add Single, PPC32 p409)
4405//zz DIP("fmadds%s fr%d,fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4406//zz frD_addr, frA_addr, frC_addr, frB_addr);
4407//zz assign( frD, roundToSgl( binop(Iop_AddF64,
4408//zz binop(Iop_MulF64, mkexpr(frA), mkexpr(frC)),
4409//zz mkexpr(frB)) ));
4410//zz break;
4411//zz
4412//zz case 0x1E: // fnmsubs (Float Neg Mult-Subtr Single, PPC32 p420)
4413//zz DIP("fnmsubs%s fr%d,fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4414//zz frD_addr, frA_addr, frC_addr, frB_addr);
4415//zz assign( frD, roundToSgl(
4416//zz unop(Iop_NegF64,
4417//zz binop(Iop_SubF64,
4418//zz binop(Iop_MulF64, mkexpr(frA), mkexpr(frC)),
4419//zz mkexpr(frB))) ));
4420//zz break;
4421//zz
4422//zz case 0x1F: // fnmadds (Floating Negative Multiply-Add Single, PPC32 p418)
4423//zz DIP("fnmadds%s fr%d,fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4424//zz frD_addr, frA_addr, frC_addr, frB_addr);
4425//zz assign( frD, roundToSgl(
4426//zz unop(Iop_NegF64,
4427//zz binop(Iop_AddF64,
4428//zz binop(Iop_MulF64, mkexpr(frA), mkexpr(frC)),
4429//zz mkexpr(frB))) ));
4430//zz break;
4431//zz
4432//zz default:
4433//zz vex_printf("dis_fp_multadd(PPC32)(3B: opc2)\n");
4434//zz return False;
4435//zz }
4436//zz break;
4437//zz
4438//zz case 0x3F:
4439//zz switch (opc2) {
4440//zz case 0x1C: // fmsub (Float Mult-Subtr (Double Precision), PPC32 p411)
4441//zz DIP("fmsub%s fr%d,fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4442//zz frD_addr, frA_addr, frC_addr, frB_addr);
4443//zz assign( frD, binop( Iop_SubF64,
4444//zz binop( Iop_MulF64, mkexpr(frA), mkexpr(frC) ),
4445//zz mkexpr(frB) ));
4446//zz break;
4447//zz
4448//zz case 0x1D: // fmadd (Float Mult-Add (Double Precision), PPC32 p408)
4449//zz DIP("fmadd%s fr%d,fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4450//zz frD_addr, frA_addr, frC_addr, frB_addr);
4451//zz assign( frD, binop( Iop_AddF64,
4452//zz binop( Iop_MulF64, mkexpr(frA), mkexpr(frC) ),
4453//zz mkexpr(frB) ));
4454//zz break;
4455//zz
4456//zz case 0x1E: // fnmsub (Float Neg Mult-Subtr (Double Precision), PPC32 p419)
4457//zz DIP("fnmsub%s fr%d,fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4458//zz frD_addr, frA_addr, frC_addr, frB_addr);
4459//zz assign( frD, unop( Iop_NegF64,
4460//zz binop( Iop_SubF64,
4461//zz binop( Iop_MulF64, mkexpr(frA), mkexpr(frC) ),
4462//zz mkexpr(frB) )));
4463//zz break;
4464//zz
4465//zz case 0x1F: // fnmadd (Float Neg Mult-Add (Double Precision), PPC32 p417)
4466//zz DIP("fnmadd%s fr%d,fr%d,fr%d,fr%d\n", flag_Rc ? "." : "",
4467//zz frD_addr, frA_addr, frC_addr, frB_addr);
4468//zz assign( frD, unop( Iop_NegF64,
4469//zz binop( Iop_AddF64,
4470//zz binop( Iop_MulF64, mkexpr(frA), mkexpr(frC) ),
4471//zz mkexpr(frB) )));
4472//zz break;
4473//zz
4474//zz default:
4475//zz vex_printf("dis_fp_multadd(PPC32)(3F: opc2)\n");
4476//zz return False;
4477//zz }
4478//zz break;
4479//zz
4480//zz default:
4481//zz vex_printf("dis_fp_multadd(PPC32)(opc1)\n");
4482//zz return False;
4483//zz }
4484//zz
4485//zz putFReg( frD_addr, mkexpr(frD) );
4486//zz return True;
4487//zz }
4488//zz
4489//zz
4490//zz
4491//zz /*
4492//zz Floating Point Compare Instructions
4493//zz */
4494//zz static Bool dis_fp_cmp ( UInt theInstr )
4495//zz {
4496//zz /* X-Form */
4497//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
4498//zz UChar crfD = toUChar((theInstr >> 23) & 0x7); /* theInstr[23:25] */
4499//zz UChar b21to22 = toUChar((theInstr >> 21) & 0x3); /* theInstr[21:22] */
4500//zz UChar frA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
4501//zz UChar frB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
4502//zz UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
4503//zz UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
4504//zz
4505//zz IRTemp ccIR = newTemp(Ity_I32);
4506//zz IRTemp ccPPC32 = newTemp(Ity_I32);
4507//zz
4508//zz #if 0
4509//zz IRTemp cc_lt = newTemp(Ity_I32);
4510//zz IRTemp cc_gt = newTemp(Ity_I32);
4511//zz IRTemp cc_eq = newTemp(Ity_I32);
4512//zz IRTemp cc_un = newTemp(Ity_I32);
4513//zz #endif
4514//zz
4515//zz IRTemp frA = newTemp(Ity_F64);
4516//zz IRTemp frB = newTemp(Ity_F64);
4517//zz // IRExpr* irx;
4518//zz
4519//zz if (opc1 != 0x3F || b21to22 != 0 || b0 != 0) {
4520//zz vex_printf("dis_fp_cmp(PPC32)(instr)\n");
4521//zz return False;
4522//zz }
4523//zz
4524//zz assign( frA, getFReg(frA_addr));
4525//zz assign( frB, getFReg(frB_addr));
4526//zz
4527//zz assign( ccIR, binop(Iop_CmpF64, mkexpr(frA), mkexpr(frB)) );
4528//zz
4529//zz /* Map compare result from IR to PPC32 */
4530//zz /*
4531//zz FP cmp result | PPC | IR
4532//zz --------------------------
4533//zz UN | 0x1 | 0x45
4534//zz EQ | 0x2 | 0x40
4535//zz GT | 0x4 | 0x00
4536//zz LT | 0x8 | 0x01
4537//zz */
4538//zz
4539//zz // ccPPC32 = Shl(1, (0x2 & ~(ccIR>>5)) || (0x1 & (XOR(ccIR, ccIR>>6))))
4540//zz assign( ccPPC32,
4541//zz binop(Iop_Shl32, mkU32(1),
4542//zz unop(Iop_32to8,
4543//zz binop(Iop_Or32,
4544//zz binop(Iop_And32, mkU32(2),
4545//zz unop(Iop_Not32,
4546//zz binop(Iop_Shr32, mkexpr(ccIR), mkU8(5)))),
4547//zz binop(Iop_And32, mkU32(1),
4548//zz binop(Iop_Xor32, mkexpr(ccIR),
4549//zz binop(Iop_Shr32, mkexpr(ccIR), mkU8(6))))))) );
4550//zz
4551//zz putReg_field( PPC32_SPR_CR, mkexpr(ccPPC32), 7-crfD );
4552//zz
4553//zz // CAB: Useful to support writing cc to FPSCR->FPCC ?
4554//zz // putReg_field( PPC32_SPR_FPSCR, mkexpr(ccPPC32), 3 );
4555//zz
4556//zz // Note: Differences between fcmpu and fcmpo are only
4557//zz // in exception flag settings, which aren't supported anyway...
4558//zz opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
4559//zz switch (opc2) {
4560//zz case 0x000: // fcmpu (Floating Compare Unordered, PPC32 p403)
4561//zz DIP("fcmpu crf%d,fr%d,fr%d\n", crfD, frA_addr, frB_addr);
4562//zz break;
4563//zz
4564//zz case 0x020: // fcmpo (Floating Compare Ordered, PPC32 p402)
4565//zz DIP("fcmpo crf%d,fr%d,fr%d\n", crfD, frA_addr, frB_addr);
4566//zz break;
4567//zz
4568//zz default:
4569//zz vex_printf("dis_fp_cmp(PPC32)(opc2)\n");
4570//zz return False;
4571//zz }
4572//zz return True;
4573//zz }
4574//zz
4575//zz
4576//zz
4577//zz /*
4578//zz Floating Point Rounding/Conversion Instructions
4579//zz */
4580//zz static Bool dis_fp_round ( UInt theInstr )
4581//zz {
4582//zz /* X-Form */
4583//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
4584//zz UChar frD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
4585//zz UChar b16to20 = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
4586//zz UChar frB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
4587//zz UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
4588//zz UChar flag_Rc = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
4589//zz
4590//zz IRTemp frD = newTemp(Ity_F64);
4591//zz IRTemp frB = newTemp(Ity_F64);
4592//zz IRTemp r_tmp = newTemp(Ity_I32);
4593//zz
4594//zz if (opc1 != 0x3F || b16to20 != 0) {
4595//zz vex_printf("dis_fp_round(PPC32)(instr)\n");
4596//zz return False;
4597//zz }
4598//zz
4599//zz assign( frB, getFReg(frB_addr));
4600//zz
4601//zz opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
4602//zz switch (opc2) {
4603//zz case 0x00C: // frsp (Floating Round to Single, PPC32 p423)
4604//zz DIP("frsp%s fr%d,fr%d\n", flag_Rc ? "." : "", frD_addr, frB_addr);
4605//zz assign( frD, roundToSgl( mkexpr(frB) ));
4606//zz break;
4607//zz
4608//zz case 0x00E: // fctiw (Floating Conv to Int, PPC32 p404)
4609//zz DIP("fctiw%s fr%d,fr%d\n", flag_Rc ? "." : "", frD_addr, frB_addr);
4610//zz assign( r_tmp, binop(Iop_F64toI32, get_roundingmode(), mkexpr(frB)) );
4611//zz assign( frD, unop( Iop_ReinterpI64asF64,
4612//zz unop( Iop_32Uto64, mkexpr(r_tmp))));
4613//zz break;
4614//zz
4615//zz case 0x00F: // fctiwz (Floating Conv to Int, Round to Zero, PPC32 p405)
4616//zz DIP("fctiwz%s fr%d,fr%d\n", flag_Rc ? "." : "", frD_addr, frB_addr);
4617//zz assign( r_tmp, binop(Iop_F64toI32, mkU32(0x3), mkexpr(frB)) );
4618//zz assign( frD, unop( Iop_ReinterpI64asF64,
4619//zz unop( Iop_32Uto64, mkexpr(r_tmp))));
4620//zz break;
4621//zz
4622//zz default:
4623//zz vex_printf("dis_fp_round(PPC32)(opc2)\n");
4624//zz return False;
4625//zz }
4626//zz
4627//zz putFReg( frD_addr, mkexpr(frD) );
4628//zz return True;
4629//zz }
4630//zz
4631//zz
4632//zz
4633//zz /*
4634//zz Floating Point Move Instructions
4635//zz */
4636//zz static Bool dis_fp_move ( UInt theInstr )
4637//zz {
4638//zz /* X-Form */
4639//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
4640//zz UChar frD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
4641//zz UChar b16to20 = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
4642//zz UChar frB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
4643//zz UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
4644//zz UChar flag_Rc = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
4645//zz
4646//zz IRTemp frD = newTemp(Ity_F64);
4647//zz IRTemp frB = newTemp(Ity_F64);
4648//zz
4649//zz if (opc1 != 0x3F || b16to20 != 0) {
4650//zz vex_printf("dis_fp_move(PPC32)(instr)\n");
4651//zz return False;
4652//zz }
4653//zz
4654//zz assign( frB, getFReg(frB_addr));
4655//zz
4656//zz opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
4657//zz switch (opc2) {
4658//zz case 0x028: // fneg (Floating Negate, PPC32 p416)
4659//zz DIP("fneg%s fr%d,fr%d\n", flag_Rc ? "." : "", frD_addr, frB_addr);
4660//zz assign( frD, unop( Iop_NegF64, mkexpr(frB) ));
4661//zz break;
4662//zz
4663//zz case 0x048: // fmr (Floating Move Register, PPC32 p410)
4664//zz DIP("fmr%s fr%d,fr%d\n", flag_Rc ? "." : "", frD_addr, frB_addr);
4665//zz assign( frD, mkexpr(frB) );
4666//zz break;
4667//zz
4668//zz case 0x088: // fnabs (Floating Negative Absolute Value, PPC32 p415)
4669//zz DIP("fnabs%s fr%d,fr%d\n", flag_Rc ? "." : "", frD_addr, frB_addr);
4670//zz assign( frD, unop( Iop_NegF64, unop( Iop_AbsF64, mkexpr(frB) )));
4671//zz break;
4672//zz
4673//zz case 0x108: // fabs (Floating Absolute Value, PPC32 p399)
4674//zz DIP("fabs%s fr%d,fr%d\n", flag_Rc ? "." : "", frD_addr, frB_addr);
4675//zz assign( frD, unop( Iop_AbsF64, mkexpr(frB) ));
4676//zz break;
4677//zz
4678//zz default:
4679//zz vex_printf("dis_fp_move(PPC32)(opc2)\n");
4680//zz return False;
4681//zz }
4682//zz
4683//zz putFReg( frD_addr, mkexpr(frD) );
4684//zz return True;
4685//zz }
4686//zz
4687//zz
4688//zz
4689//zz /*
4690//zz Floating Point Status/Control Register Instructions
4691//zz */
4692//zz static Bool dis_fp_scr ( UInt theInstr )
4693//zz {
4694//zz /* X-Form */
4695//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
4696//zz /* Too many forms - see each switch case */
4697//zz UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
4698//zz UChar flag_Rc = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
4699//zz
4700//zz if (opc1 != 0x3F) {
4701//zz vex_printf("dis_fp_scr(PPC32)(instr)\n");
4702//zz return False;
4703//zz }
4704//zz
4705//zz switch (opc2) {
4706//zz case 0x026: { // mtfsb1 (Move to FPSCR Bit 1, PPC32 p479)
4707//zz // Bit crbD of the FPSCR is set.
4708//zz UChar crbD = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
4709//zz UInt b11to20 = (theInstr >> 11) & 0x3FF; /* theInstr[11:20] */
4710//zz
4711//zz if (b11to20 != 0) {
4712//zz vex_printf("dis_fp_scr(PPC32)(instr,mtfsb1)\n");
4713//zz return False;
4714//zz }
4715//zz DIP("mtfsb1%s crb%d \n", flag_Rc ? "." : "", crbD);
4716//zz putReg_bit( PPC32_SPR_FPSCR, mkU32(1), 31-crbD );
4717//zz break;
4718//zz }
4719//zz
4720//zz case 0x040: { // mcrfs (Move to Condition Register from FPSCR, PPC32 p465)
4721//zz UChar crfD = toUChar((theInstr >> 23) & 0x7); /* theInstr[23:25] */
4722//zz UChar b21to22 = toUChar((theInstr >> 21) & 0x3); /* theInstr[21:22] */
4723//zz UChar crfS = toUChar((theInstr >> 18) & 0x7); /* theInstr[18:20] */
4724//zz UChar b11to17 = toUChar((theInstr >> 11) & 0x7F); /* theInstr[11:17] */
4725//zz
4726//zz IRTemp tmp = newTemp(Ity_I32);
4727//zz
4728//zz if (b21to22 != 0 || b11to17 != 0 || flag_Rc != 0) {
4729//zz vex_printf("dis_fp_scr(PPC32)(instr,mcrfs)\n");
4730//zz return False;
4731//zz }
4732//zz DIP("mcrfs crf%d,crf%d\n", crfD, crfS);
4733//zz assign( tmp, getReg_field( PPC32_SPR_FPSCR, 7-crfS ) );
4734//zz putReg_field( PPC32_SPR_CR, mkexpr(tmp), 7-crfD );
4735//zz break;
4736//zz }
4737//zz
4738//zz case 0x046: { // mtfsb0 (Move to FPSCR Bit 0, PPC32 p478)
4739//zz // Bit crbD of the FPSCR is cleared.
4740//zz UChar crbD = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
4741//zz UInt b11to20 = (theInstr >> 11) & 0x3FF; /* theInstr[11:20] */
4742//zz
4743//zz if (b11to20 != 0) {
4744//zz vex_printf("dis_fp_scr(PPC32)(instr,mtfsb0)\n");
4745//zz return False;
4746//zz }
4747//zz DIP("mtfsb0%s crb%d\n", flag_Rc ? "." : "", crbD);
4748//zz putReg_bit( PPC32_SPR_FPSCR, mkU32(0), 31-crbD );
4749//zz break;
4750//zz }
4751//zz
4752//zz case 0x086: { // mtfsfi (Move to FPSCR Field Immediate, PPC32 p481)
4753//zz UChar crfD = toUChar((theInstr >> 23) & 0x7); /* theInstr[23:25] */
4754//zz UChar b16to22 = toUChar((theInstr >> 16) & 0x7F); /* theInstr[16:22] */
4755//zz UChar IMM = toUChar((theInstr >> 12) & 0xF); /* theInstr[11:15] */
4756//zz UChar b11 = toUChar((theInstr >> 11) & 0x1); /* theInstr[11] */
4757//zz
4758//zz if (b16to22 != 0 || b11 != 0) {
4759//zz vex_printf("dis_fp_scr(PPC32)(instr,mtfsfi)\n");
4760//zz return False;
4761//zz }
4762//zz DIP("mtfsfi%s crf%d,%d\n", flag_Rc ? "." : "", crfD, IMM);
4763//zz putReg_field( PPC32_SPR_FPSCR, mkU32(IMM), 7-crfD );
4764//zz break;
4765//zz }
4766//zz
4767//zz case 0x247: { // mffs (Move from FPSCR, PPC32 p468)
4768//zz UChar frD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
4769//zz UInt b11to20 = (theInstr >> 11) & 0x3FF; /* theInstr[11:20] */
4770//zz
4771//zz if (b11to20 != 0) {
4772//zz vex_printf("dis_fp_scr(PPC32)(instr,mffs)\n");
4773//zz return False;
4774//zz }
4775//zz DIP("mffs%s fr%d\n", flag_Rc ? "." : "", frD_addr);
4776//zz putFReg( frD_addr, unop( Iop_ReinterpI64asF64,
4777//zz unop( Iop_32Uto64, getReg( PPC32_SPR_FPSCR ) )));
4778//zz break;
4779//zz }
4780//zz
4781//zz case 0x2C7: { // mtfsf (Move to FPSCR Fields, PPC32 p480)
4782//zz UChar b25 = toUChar((theInstr >> 25) & 0x1); /* theInstr[25] */
4783//zz UChar FM = toUChar((theInstr >> 17) & 0xFF); /* theInstr[17:24] */
4784//zz UChar b16 = toUChar((theInstr >> 16) & 0x1); /* theInstr[16] */
4785//zz UChar frB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
4786//zz IRTemp frB = newTemp(Ity_F64);
4787//zz IRTemp rB_32 = newTemp(Ity_I32);
4788//zz int mask=0;
4789//zz int i=0;
4790//zz
4791//zz if (b25 != 0 || b16 != 0) {
4792//zz vex_printf("dis_fp_scr(PPC32)(instr,mtfsf)\n");
4793//zz return False;
4794//zz }
4795//zz DIP("mtfsf%s %d,fr%d\n", flag_Rc ? "." : "", FM, frB_addr);
4796//zz assign( frB, getFReg(frB_addr));
4797//zz assign( rB_32, unop( Iop_64to32,
4798//zz unop( Iop_ReinterpF64asI64, mkexpr(frB) )));
4799//zz // Build 32bit mask from FM:
4800//zz for (i=0; i<8; i++) {
4801//zz if ((FM & (1<<(7-i))) == 1) {
4802//zz mask |= 0xF << (7-i);
4803//zz }
4804//zz }
4805//zz putReg_masked( PPC32_SPR_FPSCR, mkexpr(rB_32), mask );
4806//zz break;
4807//zz }
4808//zz
4809//zz default:
4810//zz vex_printf("dis_fp_scr(PPC32)(opc2)\n");
4811//zz return False;
4812//zz }
4813//zz return True;
4814//zz }
4815//zz
4816//zz
4817//zz
4818//zz /*------------------------------------------------------------*/
4819//zz /*--- AltiVec Instruction Translation ---*/
4820//zz /*------------------------------------------------------------*/
4821//zz
4822//zz /*
4823//zz Altivec Cache Control Instructions (Data Streams)
4824//zz */
4825//zz static Bool dis_av_datastream ( UInt theInstr )
4826//zz {
4827//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
4828//zz UChar flag_T = toUChar((theInstr >> 25) & 0x1); /* theInstr[25] */
4829//zz UChar flag_A = toUChar((theInstr >> 25) & 0x1); /* theInstr[25] */
4830//zz UChar b23to24 = toUChar((theInstr >> 23) & 0x3); /* theInstr[23:24] */
4831//zz UChar STRM = toUChar((theInstr >> 21) & 0x3); /* theInstr[21:22] */
4832//zz UChar rA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
4833//zz UChar rB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
4834//zz UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
4835//zz UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
4836//zz
4837//zz if (opc1 != 0x1F || b23to24 != 0 || b0 != 0) {
4838//zz vex_printf("dis_av_datastream(PPC32)(instr)\n");
4839//zz return False;
4840//zz }
4841//zz
4842//zz switch (opc2) {
4843//zz case 0x156: // dst (Data Stream Touch, AV p115)
4844//zz DIP("dst%s r%d,r%d,%d\n", flag_T ? "t" : "", rA_addr, rB_addr, STRM);
4845//zz DIP(" => not implemented\n");
4846//zz return False;
4847//zz
4848//zz case 0x176: // dstst (Data Stream Touch for Store, AV p117)
4849//zz DIP("dstst%s r%d,r%d,%d\n", flag_T ? "t" : "", rA_addr, rB_addr, STRM);
4850//zz DIP(" => not implemented\n");
4851//zz return False;
4852//zz
4853//zz case 0x336: // dss (Data Stream Stop, AV p114)
4854//zz if (rA_addr != 0 || rB_addr != 0) {
4855//zz vex_printf("dis_av_datastream(PPC32)(opc2,dst)\n");
4856//zz return False;
4857//zz }
4858//zz if (flag_A == 0) {
4859//zz DIP("dss %d\n", STRM);
4860//zz DIP(" => not implemented\n");
4861//zz } else {
4862//zz DIP("dssall\n");
4863//zz DIP(" => not implemented\n");
4864//zz }
4865//zz return False;
4866//zz
4867//zz default:
4868//zz vex_printf("dis_av_datastream(PPC32)(opc2)\n");
4869//zz return False;
4870//zz }
4871//zz return True;
4872//zz }
4873//zz
4874//zz /*
4875//zz AltiVec Processor Control Instructions
4876//zz */
4877//zz static Bool dis_av_procctl ( UInt theInstr )
4878//zz {
4879//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
4880//zz UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
4881//zz UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
4882//zz UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
4883//zz UInt opc2 = (theInstr >> 0) & 0x7FF; /* theInstr[0:10] */
4884//zz
4885//zz if (opc1 != 0x4) {
4886//zz vex_printf("dis_av_procctl(PPC32)(instr)\n");
4887//zz return False;
4888//zz }
4889//zz
4890//zz switch (opc2) {
4891//zz case 0x604: // mfvscr (Move from VSCR, AV p129)
4892//zz if (vA_addr != 0 || vB_addr != 0) {
4893//zz vex_printf("dis_av_procctl(PPC32)(opc2,dst)\n");
4894//zz return False;
4895//zz }
4896//zz DIP("mfvscr v%d\n", vD_addr);
4897//zz DIP(" => not implemented\n");
4898//zz return False;
4899//zz
4900//zz case 0x644: // mtvscr (Move to VSCR, AV p130)
4901//zz if (vD_addr != 0 || vA_addr != 0) {
4902//zz vex_printf("dis_av_procctl(PPC32)(opc2,dst)\n");
4903//zz return False;
4904//zz }
4905//zz DIP("mtvscr v%d\n", vB_addr);
4906//zz DIP(" => not implemented\n");
4907//zz return False;
4908//zz
4909//zz default:
4910//zz vex_printf("dis_av_procctl(PPC32)(opc2)\n");
4911//zz return False;
4912//zz }
4913//zz return True;
4914//zz }
ceriona982c052005-06-28 17:23:09 +00004915
4916/*
4917 AltiVec Load Instructions
4918*/
4919static Bool dis_av_load ( UInt theInstr )
4920{
4921 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
4922 UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
4923 UChar rA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
4924 UChar rB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
4925 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
4926 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
4927
ceriona50fde52005-07-01 21:16:10 +00004928 IRTemp EA = newTemp(Ity_I32);
4929 IRTemp EA_aligned = newTemp(Ity_I32);
4930
ceriona982c052005-06-28 17:23:09 +00004931 if (opc1 != 0x1F || b0 != 0) {
4932 vex_printf("dis_av_load(PPC32)(instr)\n");
4933 return False;
4934 }
4935
ceriona50fde52005-07-01 21:16:10 +00004936 assign( EA, binop(Iop_Add32,
4937 ((rA_addr == 0) ? mkU32(0) : getIReg(rA_addr)),
4938 getIReg(rB_addr) ));
4939
ceriona982c052005-06-28 17:23:09 +00004940 switch (opc2) {
4941
sewardjb51f0f42005-07-18 11:38:02 +00004942//zz case 0x006: // lvsl (Load Vector for Shift Left, AV p123)
4943//zz DIP("lvsl v%d,r%d,r%d\n", vD_addr, rA_addr, rB_addr);
4944//zz DIP(" => not implemented\n");
4945//zz return False;
4946//zz
4947//zz case 0x026: // lvsr (Load Vector for Shift Right, AV p125)
4948//zz DIP("lvsr v%d,r%d,r%d\n", vD_addr, rA_addr, rB_addr);
4949//zz DIP(" => not implemented\n");
4950//zz return False;
4951//zz
4952//zz case 0x007: // lvebx (Load Vector Element Byte Indexed, AV p119)
4953//zz DIP("lvebx v%d,r%d,r%d\n", vD_addr, rA_addr, rB_addr);
4954//zz DIP(" => not implemented\n");
4955//zz return False;
4956//zz
4957//zz case 0x027: // lvehx (Load Vector Element Half Word Indexed, AV p121)
4958//zz DIP("lvehx v%d,r%d,r%d\n", vD_addr, rA_addr, rB_addr);
4959//zz DIP(" => not implemented\n");
4960//zz return False;
4961//zz
4962//zz case 0x047: // lvewx (Load Vector Element Word Indexed, AV p122)
4963//zz DIP("lvewx v%d,r%d,r%d\n", vD_addr, rA_addr, rB_addr);
4964//zz DIP(" => not implemented\n");
4965//zz return False;
ceriona982c052005-06-28 17:23:09 +00004966
4967 case 0x067: // lvx (Load Vector Indexed, AV p127)
4968 DIP("lvx v%d,r%d,r%d\n", vD_addr, rA_addr, rB_addr);
ceriona50fde52005-07-01 21:16:10 +00004969 assign( EA_aligned, binop( Iop_And32, mkexpr(EA), mkU32(0xFFFFFFF0) ));
4970 putVReg( vD_addr, loadBE(Ity_V128, mkexpr(EA_aligned)) );
4971 break;
ceriona982c052005-06-28 17:23:09 +00004972
sewardjb51f0f42005-07-18 11:38:02 +00004973//zz case 0x167: // lvxl (Load Vector Indexed LRU, AV p128)
4974//zz // XXX: lvxl gives explicit control over cache block replacement
4975//zz DIP("lvxl v%d,r%d,r%d\n", vD_addr, rA_addr, rB_addr);
4976//zz DIP(" => not implemented\n");
4977//zz return False;
ceriona982c052005-06-28 17:23:09 +00004978
4979 default:
4980 vex_printf("dis_av_load(PPC32)(opc2)\n");
4981 return False;
4982 }
4983 return True;
4984}
4985
4986/*
4987 AltiVec Store Instructions
4988*/
4989static Bool dis_av_store ( UInt theInstr )
4990{
4991 UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
4992 UChar vS_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
4993 UChar rA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
4994 UChar rB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
4995 UInt opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
4996 UChar b0 = toUChar((theInstr >> 0) & 1); /* theInstr[0] */
4997
4998 IRTemp rA = newTemp(Ity_I32);
4999 IRTemp rB = newTemp(Ity_I32);
5000 IRTemp vS = newTemp(Ity_V128);
5001 IRTemp EA = newTemp(Ity_I32);
5002 IRTemp EA_aligned = newTemp(Ity_I32);
5003
5004 assign( rA, getIReg(rA_addr));
5005 assign( rB, getIReg(rB_addr));
5006 assign( vS, getVReg(vS_addr));
5007
5008 if (rA_addr == 0) {
5009 assign( EA, mkexpr(rB) );
5010 } else {
5011 assign( EA, binop(Iop_Add32, mkexpr(rA), mkexpr(rB)) );
5012 }
5013
5014 if (opc1 != 0x1F || b0 != 0) {
5015 vex_printf("dis_av_store(PPC32)(instr)\n");
5016 return False;
5017 }
5018
5019 switch (opc2) {
sewardjb51f0f42005-07-18 11:38:02 +00005020//zz case 0x087: // stvebx (Store Vector Byte Indexed, AV p131)
5021//zz DIP("stvebx v%d,r%d,r%d\n", vS_addr, rA_addr, rB_addr);
5022//zz DIP(" => not implemented\n");
5023//zz return False;
5024//zz
5025//zz // eb = EA & 0xF;
5026//zz // STORE(vS[eb*8:eb*8+7], 1, EA);
5027//zz // storeBE( mkexpr(EA), mkexpr(vS) );
5028//zz
5029//zz case 0x0A7: // stvehx (Store Vector Half Word Indexed, AV p132)
5030//zz DIP("stvehx v%d,r%d,r%d\n", vS_addr, rA_addr, rB_addr);
5031//zz DIP(" => not implemented\n");
5032//zz return False;
5033//zz
5034//zz // EA_aligned = EA & 0xFFFF_FFFE
5035//zz // eb = EA_aligned & 0xF;
5036//zz // STORE(vS[eb*8:eb*8+15], 2, EA_aligned);
5037//zz
5038//zz case 0x0C7: // stvewx (Store Vector Word Indexed, AV p133)
5039//zz DIP("stvewx v%d,r%d,r%d\n", vS_addr, rA_addr, rB_addr);
5040//zz DIP(" => not implemented\n");
5041//zz return False;
5042//zz
5043//zz // EA_aligned = EA & 0xFFFF_FFFC
5044//zz // eb = EA_aligned & 0xF;
5045//zz // STORE(vS[eb*8:eb*8+31], 4, EA_aligned);
ceriona982c052005-06-28 17:23:09 +00005046
5047 case 0x0E7: // stvx (Store Vector Indexed, AV p134)
5048 DIP("stvx v%d,r%d,r%d\n", vS_addr, rA_addr, rB_addr);
5049 assign( EA_aligned, binop( Iop_And32, mkexpr(EA), mkU32(0xFFFFFFF0) ));
5050 storeBE( mkexpr(EA_aligned), mkexpr(vS) );
5051 break;
5052
sewardjb51f0f42005-07-18 11:38:02 +00005053//zz case 0x1E7: // stvxl (Store Vector Indexed LRU, AV p135)
5054//zz // XXX: stvxl can give explicit control over cache block replacement
5055//zz DIP("stvxl v%d,r%d,r%d\n", vS_addr, rA_addr, rB_addr);
5056//zz DIP(" => not implemented\n");
5057//zz return False;
5058//zz
5059//zz // EA_aligned = EA & 0xFFFF_FFF0;
5060//zz // STORE(vS, 16, EA);
ceriona982c052005-06-28 17:23:09 +00005061
5062 default:
5063 vex_printf("dis_av_store(PPC32)(opc2)\n");
5064 return False;
5065 }
5066 return True;
5067}
5068
sewardjb51f0f42005-07-18 11:38:02 +00005069//zz /*
5070//zz AltiVec Arithmetic Instructions
5071//zz */
5072//zz static Bool dis_av_arith ( UInt theInstr )
5073//zz {
5074//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
5075//zz UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
5076//zz UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5077//zz UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
5078//zz UInt opc2 = (theInstr >> 0) & 0x7FF; /* theInstr[0:10] */
5079//zz
5080//zz if (opc1 != 0x4) {
5081//zz vex_printf("dis_av_arith(PPC32)(opc1 != 0x4)\n");
5082//zz return False;
5083//zz }
5084//zz
5085//zz switch (opc2) {
5086//zz /* Add */
5087//zz case 0x180: // vaddcuw (Add Carryout Unsigned Word, AV p136)
5088//zz DIP("vaddcuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5089//zz DIP(" => not implemented\n");
5090//zz return False;
5091//zz
5092//zz case 0x000: // vaddubm (Add Unsigned Byte Modulo, AV p141)
5093//zz DIP("vaddubm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5094//zz DIP(" => not implemented\n");
5095//zz return False;
5096//zz
5097//zz case 0x040: // vadduhm (Add Unsigned Half Word Modulo, AV p143)
5098//zz DIP("vadduhm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5099//zz DIP(" => not implemented\n");
5100//zz return False;
5101//zz
5102//zz case 0x080: // vadduwm (Add Unsigned Word Modulo, AV p145)
5103//zz DIP("vadduwm v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5104//zz DIP(" => not implemented\n");
5105//zz return False;
5106//zz
5107//zz case 0x200: // vaddubs (Add Unsigned Byte Saturate, AV p142)
5108//zz DIP("vaddubs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5109//zz DIP(" => not implemented\n");
5110//zz return False;
5111//zz
5112//zz case 0x240: // vadduhs (Add Unsigned Half Word Saturate, AV p144)
5113//zz DIP("vadduhs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5114//zz DIP(" => not implemented\n");
5115//zz return False;
5116//zz
5117//zz case 0x280: // vadduws (Add Unsigned Word Saturate, AV p146)
5118//zz DIP("vadduws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5119//zz DIP(" => not implemented\n");
5120//zz return False;
5121//zz
5122//zz case 0x300: // vaddsbs (Add Signed Byte Saturate, AV p138)
5123//zz DIP("vaddsbs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5124//zz DIP(" => not implemented\n");
5125//zz return False;
5126//zz
5127//zz case 0x340: // vaddshs (Add Signed Half Word Saturate, AV p139)
5128//zz DIP("vaddshs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5129//zz DIP(" => not implemented\n");
5130//zz return False;
5131//zz
5132//zz case 0x380: // vaddsws (Add Signed Word Saturate, AV p140)
5133//zz DIP("vaddsws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5134//zz DIP(" => not implemented\n");
5135//zz return False;
5136//zz
5137//zz /* Subtract */
5138//zz case 0x580: // vsubcuw (Subtract Carryout Unsigned Word, AV p260)
5139//zz DIP("vsubcuw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5140//zz DIP(" => not implemented\n");
5141//zz return False;
5142//zz
5143//zz case 0x400: // vsububm (Subtract Unsigned Byte Modulo, AV p265)
5144//zz DIP("vsububm 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 0x440: // vsubuhm (Subtract Unsigned Half Word Modulo, AV p267)
5149//zz DIP("vsubuhm 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 0x480: // vsubuwm (Subtract Unsigned Word Modulo, AV p269)
5154//zz DIP("vsubuwm 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 0x600: // vsububs (Subtract Unsigned Byte Saturate, AV p266)
5159//zz DIP("vsububs 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 0x640: // vsubuhs (Subtract Unsigned Half Word Saturate, AV p268)
5164//zz DIP("vsubuhs 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 0x680: // vsubuws (Subtract Unsigned Word Saturate, AV p270)
5169//zz DIP("vsubuws 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 case 0x700: // vsubsbs (Subtract Signed Byte Saturate, AV p262)
5174//zz DIP("vsubsbs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5175//zz DIP(" => not implemented\n");
5176//zz return False;
5177//zz
5178//zz case 0x740: // vsubshs (Subtract Signed Half Word Saturate, AV p263)
5179//zz DIP("vsubshs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5180//zz DIP(" => not implemented\n");
5181//zz return False;
5182//zz
5183//zz case 0x780: // vsubsws (Subtract Signed Word Saturate, AV p264)
5184//zz DIP("vsubsws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5185//zz DIP(" => not implemented\n");
5186//zz return False;
5187//zz
5188//zz
5189//zz /* Maximum */
5190//zz case 0x002: // vmaxub (Maximum Unsigned Byte, AV p182)
5191//zz DIP("vmaxub 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 0x042: // vmaxuh (Maximum Unsigned Half Word, AV p183)
5196//zz DIP("vmaxuh 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 0x082: // vmaxuw (Maximum Unsigned Word, AV p184)
5201//zz DIP("vmaxuw 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 case 0x102: // vmaxsb (Maximum Signed Byte, AV p179)
5206//zz DIP("vmaxsb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5207//zz DIP(" => not implemented\n");
5208//zz return False;
5209//zz
5210//zz case 0x142: // vmaxsh (Maximum Signed Half Word, AV p180)
5211//zz DIP("vmaxsh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5212//zz DIP(" => not implemented\n");
5213//zz return False;
5214//zz
5215//zz case 0x182: // vmaxsw (Maximum Signed Word, AV p181)
5216//zz DIP("vmaxsw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5217//zz DIP(" => not implemented\n");
5218//zz return False;
5219//zz
5220//zz
5221//zz /* Minimum */
5222//zz case 0x202: // vminub (Minimum Unsigned Byte, AV p191)
5223//zz DIP("vminub 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 0x242: // vminuh (Minimum Unsigned Half Word, AV p192)
5228//zz DIP("vminuh 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 0x282: // vminuw (Minimum Unsigned Word, AV p193)
5233//zz DIP("vminuw 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 case 0x302: // vminsb (Minimum Signed Byte, AV p188)
5238//zz DIP("vminsb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5239//zz DIP(" => not implemented\n");
5240//zz return False;
5241//zz
5242//zz case 0x342: // vminsh (Minimum Signed Half Word, AV p189)
5243//zz DIP("vminsh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5244//zz DIP(" => not implemented\n");
5245//zz return False;
5246//zz
5247//zz case 0x382: // vminsw (Minimum Signed Word, AV p190)
5248//zz DIP("vminsw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5249//zz DIP(" => not implemented\n");
5250//zz return False;
5251//zz
5252//zz
5253//zz /* Average */
5254//zz case 0x402: // vavgub (Average Unsigned Byte, AV p152)
5255//zz DIP("vavgub 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 0x442: // vavguh (Average Unsigned Half Word, AV p153)
5260//zz DIP("vavguh 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 0x482: // vavguw (Average Unsigned Word, AV p154)
5265//zz DIP("vavguw 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 0x502: // vavgsb (Average Signed Byte, AV p149)
5270//zz DIP("vavgsb 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 0x542: // vavgsh (Average Signed Half Word, AV p150)
5275//zz DIP("vavgsh 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 case 0x582: // vavgsw (Average Signed Word, AV p151)
5280//zz DIP("vavgsw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5281//zz DIP(" => not implemented\n");
5282//zz return False;
5283//zz
5284//zz
5285//zz /* Multiply */
5286//zz case 0x008: // vmuloub (Multiply Odd Unsigned Byte, AV p213)
5287//zz DIP("vmuloub 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 0x048: // vmulouh (Multiply Odd Unsigned Half Word, AV p214)
5292//zz DIP("vmulouh 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 0x108: // vmulosb (Multiply Odd Signed Byte, AV p211)
5297//zz DIP("vmulosb 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 0x148: // vmulosh (Multiply Odd Signed Half Word, AV p212)
5302//zz DIP("vmulosh 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 case 0x208: // vmuleub (Multiply Even Unsigned Byte, AV p209)
5307//zz DIP("vmuleub v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5308//zz DIP(" => not implemented\n");
5309//zz return False;
5310//zz
5311//zz case 0x248: // vmuleuh (Multiply Even Unsigned Half Word, AV p210)
5312//zz DIP("vmuleuh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5313//zz DIP(" => not implemented\n");
5314//zz return False;
5315//zz
5316//zz case 0x308: // vmulesb (Multiply Even Signed Byte, AV p207)
5317//zz DIP("vmulesb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5318//zz DIP(" => not implemented\n");
5319//zz return False;
5320//zz
5321//zz case 0x348: // vmulesh (Multiply Even Signed Half Word, AV p208)
5322//zz DIP("vmulesh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5323//zz DIP(" => not implemented\n");
5324//zz return False;
5325//zz
5326//zz
5327//zz /* Sum Across Partial */
5328//zz case 0x608: // vsum4ubs (Sum Partial (1/4) UB Saturate, AV p275)
5329//zz DIP("vsum4ubs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5330//zz DIP(" => not implemented\n");
5331//zz return False;
5332//zz
5333//zz case 0x708: // vsum4sbs (Sum Partial (1/4) SB Saturate, AV p273)
5334//zz DIP("vsum4sbs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5335//zz DIP(" => not implemented\n");
5336//zz return False;
5337//zz
5338//zz case 0x648: // vsum4shs (Sum Partial (1/4) SHW Saturate, AV p274)
5339//zz DIP("vsum4shs v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5340//zz DIP(" => not implemented\n");
5341//zz return False;
5342//zz
5343//zz case 0x688: // vsum2sws (Sum Partial (1/2) SW Saturate, AV p272)
5344//zz DIP("vsum2sws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5345//zz DIP(" => not implemented\n");
5346//zz return False;
5347//zz
5348//zz case 0x788: // vsumsws (Sum SW Saturate, AV p271)
5349//zz DIP("vsumsws v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5350//zz DIP(" => not implemented\n");
5351//zz return False;
5352//zz
5353//zz default:
5354//zz vex_printf("dis_av_arith(PPC32)(opc2=0x%x)\n", opc2);
5355//zz return False;
5356//zz }
5357//zz return True;
5358//zz }
5359//zz
5360//zz /*
5361//zz AltiVec Logic Instructions
5362//zz */
5363//zz static Bool dis_av_logic ( UInt theInstr )
5364//zz {
5365//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
5366//zz UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
5367//zz UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5368//zz UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
5369//zz UInt opc2 = (theInstr >> 0) & 0x7FF; /* theInstr[0:10] */
5370//zz
5371//zz if (opc1 != 0x4) {
5372//zz vex_printf("dis_av_logic(PPC32)(opc1 != 0x4)\n");
5373//zz return False;
5374//zz }
5375//zz
5376//zz switch (opc2) {
5377//zz case 0x404: // vand (And, AV p147)
5378//zz DIP("vand v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5379//zz DIP(" => not implemented\n");
5380//zz return False;
5381//zz
5382//zz case 0x444: // vandc (And, AV p148)
5383//zz DIP("vandc v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5384//zz DIP(" => not implemented\n");
5385//zz return False;
5386//zz
5387//zz case 0x484: // vor (Or, AV p217)
5388//zz DIP("vor v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5389//zz DIP(" => not implemented\n");
5390//zz return False;
5391//zz
5392//zz case 0x4C4: // vxor (Xor, AV p282)
5393//zz DIP("vxor v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5394//zz DIP(" => not implemented\n");
5395//zz return False;
5396//zz
5397//zz case 0x504: // vnor (Nor, AV p216)
5398//zz DIP("vnor v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5399//zz DIP(" => not implemented\n");
5400//zz return False;
5401//zz
5402//zz default:
5403//zz vex_printf("dis_av_logic(PPC32)(opc2=0x%x)\n", opc2);
5404//zz return False;
5405//zz }
5406//zz return True;
5407//zz }
5408//zz
5409//zz /*
5410//zz AltiVec Compare Instructions
5411//zz */
5412//zz static Bool dis_av_cmp ( UInt theInstr )
5413//zz {
5414//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
5415//zz UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
5416//zz UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5417//zz UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
5418//zz UChar flag_Rc = toUChar((theInstr >> 10) & 0x1); /* theInstr[10] */
5419//zz UInt opc2 = (theInstr >> 0) & 0x3FF; /* theInstr[0:9] */
5420//zz
5421//zz if (opc1 != 0x4) {
5422//zz vex_printf("dis_av_cmp(PPC32)(instr)\n");
5423//zz return False;
5424//zz }
5425//zz
5426//zz switch (opc2) {
5427//zz case 0x006: // vcmpequb (Compare Equal-to Unsigned B, AV p160)
5428//zz DIP("vcmpequb%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
5429//zz DIP(" => not implemented\n");
5430//zz return False;
5431//zz
5432//zz case 0x046: // vcmpequh (Compare Equal-to Unsigned HW, AV p161)
5433//zz DIP("vcmpequh%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
5434//zz DIP(" => not implemented\n");
5435//zz return False;
5436//zz
5437//zz case 0x086: // vcmpequw (Compare Equal-to Unsigned W, AV p162)
5438//zz DIP("vcmpequw%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
5439//zz DIP(" => not implemented\n");
5440//zz return False;
5441//zz
5442//zz case 0x206: // vcmpgtub (Compare Greater-than Unsigned B, AV p168)
5443//zz DIP("vcmpgtub%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
5444//zz DIP(" => not implemented\n");
5445//zz return False;
5446//zz
5447//zz case 0x246: // vcmpgtuh (Compare Greater-than Unsigned HW, AV p169)
5448//zz DIP("vcmpgtuh%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
5449//zz DIP(" => not implemented\n");
5450//zz return False;
5451//zz
5452//zz case 0x286: // vcmpgtuw (Compare Greater-than Unsigned W, AV p170)
5453//zz DIP("vcmpgtuw%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
5454//zz DIP(" => not implemented\n");
5455//zz return False;
5456//zz
5457//zz case 0x306: // vcmpgtsb (Compare Greater-than Signed B, AV p165)
5458//zz DIP("vcmpgtsb%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
5459//zz DIP(" => not implemented\n");
5460//zz return False;
5461//zz
5462//zz case 0x346: // vcmpgtsh (Compare Greater-than Signed HW, AV p166)
5463//zz DIP("vcmpgtsh%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
5464//zz DIP(" => not implemented\n");
5465//zz return False;
5466//zz
5467//zz case 0x386: // vcmpgtsw (Compare Greater-than Signed W, AV p167)
5468//zz DIP("vcmpgtsw%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
5469//zz DIP(" => not implemented\n");
5470//zz return False;
5471//zz
5472//zz default:
5473//zz vex_printf("dis_av_cmp(PPC32)(opc2)\n");
5474//zz return False;
5475//zz }
5476//zz return True;
5477//zz }
5478//zz
5479//zz /*
5480//zz AltiVec Multiply-Sum Instructions
5481//zz */
5482//zz static Bool dis_av_multarith ( UInt theInstr )
5483//zz {
5484//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
5485//zz UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
5486//zz UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5487//zz UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
5488//zz UChar vC_addr = toUChar((theInstr >> 6) & 0x1F); /* theInstr[6:10] */
5489//zz UChar opc2 = toUChar((theInstr >> 0) & 0x3F); /* theInstr[0:5] */
5490//zz
5491//zz if (opc1 != 0x4) {
5492//zz vex_printf("dis_av_multarith(PPC32)(instr)\n");
5493//zz return False;
5494//zz }
5495//zz
5496//zz switch (opc2) {
5497//zz
5498//zz /* Multiply-Add */
5499//zz case 0x20: // vmhaddshs (Multiply High, Add Signed HW Saturate, AV p185)
5500//zz DIP("vmhaddshs v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
5501//zz DIP(" => not implemented\n");
5502//zz return False;
5503//zz
5504//zz case 0x21: // vmhraddshs (Multiply High Round, Add Signed HW Saturate, AV p186)
5505//zz DIP("vmhraddshs v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
5506//zz DIP(" => not implemented\n");
5507//zz return False;
5508//zz
5509//zz case 0x22: // vmladduhm (Multiply Low, Add Unsigned HW Modulo, AV p194)
5510//zz DIP("vmladduhm v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
5511//zz DIP(" => not implemented\n");
5512//zz return False;
5513//zz
5514//zz
5515//zz /* Multiply-Sum */
5516//zz case 0x24: // vmsumubm (Multiply Sum Unsigned B Modulo, AV p204)
5517//zz DIP("vmsumubm v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
5518//zz DIP(" => not implemented\n");
5519//zz return False;
5520//zz
5521//zz case 0x25: // vmsummbm (Multiply Sum Mixed-Sign B Modulo, AV p201)
5522//zz DIP("vmsummbm v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
5523//zz DIP(" => not implemented\n");
5524//zz return False;
5525//zz
5526//zz case 0x26: // vmsumuhm (Multiply Sum Unsigned HW Modulo, AV p205)
5527//zz DIP("vmsumuhm v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
5528//zz DIP(" => not implemented\n");
5529//zz return False;
5530//zz
5531//zz case 0x27: // vmsumuhs (Multiply Sum Unsigned HW Saturate, AV p206)
5532//zz DIP("vmsumuhs v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
5533//zz DIP(" => not implemented\n");
5534//zz return False;
5535//zz
5536//zz case 0x28: // vmsumshm (Multiply Sum Signed HW Modulo, AV p202)
5537//zz DIP("vmsumshm v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
5538//zz DIP(" => not implemented\n");
5539//zz return False;
5540//zz
5541//zz case 0x29: // vmsumshs (Multiply Sum Signed HW Saturate, AV p203)
5542//zz DIP("vmsumshs v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
5543//zz DIP(" => not implemented\n");
5544//zz return False;
5545//zz
5546//zz default:
5547//zz vex_printf("dis_av_multarith(PPC32)(opc2)\n");
5548//zz return False;
5549//zz }
5550//zz return True;
5551//zz }
5552//zz
5553//zz /*
5554//zz AltiVec Shift/Rotate Instructions
5555//zz */
5556//zz static Bool dis_av_shift ( UInt theInstr )
5557//zz {
5558//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
5559//zz UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
5560//zz UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5561//zz UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
5562//zz UInt opc2 = (theInstr >> 0) & 0x7FF; /* theInstr[0:10] */
5563//zz
5564//zz if (opc1 != 0x4){
5565//zz vex_printf("dis_av_shift(PPC32)(instr)\n");
5566//zz return False;
5567//zz }
5568//zz
5569//zz switch (opc2) {
5570//zz /* Rotate */
5571//zz case 0x004: // vrlb (Rotate Left Integer B, AV p234)
5572//zz DIP("vrlb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5573//zz DIP(" => not implemented\n");
5574//zz return False;
5575//zz
5576//zz case 0x044: // vrlh (Rotate Left Integer HW, AV p235)
5577//zz DIP("vrlh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5578//zz DIP(" => not implemented\n");
5579//zz return False;
5580//zz
5581//zz case 0x084: // vrlw (Rotate Left Integer W, AV p236)
5582//zz DIP("vrlw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5583//zz DIP(" => not implemented\n");
5584//zz return False;
5585//zz
5586//zz
5587//zz /* Shift Left */
5588//zz case 0x104: // vslb (Shift Left Integer B, AV p240)
5589//zz DIP("vslb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5590//zz DIP(" => not implemented\n");
5591//zz return False;
5592//zz
5593//zz case 0x144: // vslh (Shift Left Integer HW, AV p242)
5594//zz DIP("vslh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5595//zz DIP(" => not implemented\n");
5596//zz return False;
5597//zz
5598//zz case 0x184: // vslw (Shift Left Integer W, AV p244)
5599//zz DIP("vslw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5600//zz DIP(" => not implemented\n");
5601//zz return False;
5602//zz
5603//zz case 0x1C4: // vsl (Shift Left, AV p239)
5604//zz DIP("vsl v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5605//zz DIP(" => not implemented\n");
5606//zz return False;
5607//zz
5608//zz case 0x40C: // vslo (Shift Left by Octet, AV p243)
5609//zz DIP("vslo v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5610//zz DIP(" => not implemented\n");
5611//zz return False;
5612//zz
5613//zz /* Shift Right */
5614//zz case 0x204: // vsrb (Shift Right B, AV p256)
5615//zz DIP("vsrb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5616//zz DIP(" => not implemented\n");
5617//zz return False;
5618//zz
5619//zz case 0x244: // vsrh (Shift Right HW, AV p257)
5620//zz DIP("vsrh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5621//zz DIP(" => not implemented\n");
5622//zz return False;
5623//zz
5624//zz case 0x284: // vsrw (Shift Right W, AV p259)
5625//zz DIP("vsrw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5626//zz DIP(" => not implemented\n");
5627//zz return False;
5628//zz
5629//zz case 0x2C4: // vsr (Shift Right, AV p252)
5630//zz DIP("vsr v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5631//zz DIP(" => not implemented\n");
5632//zz return False;
5633//zz
5634//zz case 0x304: // vsrab (Shift Right Algebraic B, AV p253)
5635//zz DIP("vsrab v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5636//zz DIP(" => not implemented\n");
5637//zz return False;
5638//zz
5639//zz case 0x344: // vsrah (Shift Right Algebraic HW, AV p254)
5640//zz DIP("vsrah v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5641//zz DIP(" => not implemented\n");
5642//zz return False;
5643//zz
5644//zz case 0x384: // vsraw (Shift Right Algebraic W, AV p255)
5645//zz DIP("vsraw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5646//zz DIP(" => not implemented\n");
5647//zz return False;
5648//zz
5649//zz case 0x44C: // vsro (Shift Right by Octet, AV p258)
5650//zz DIP("vsro v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5651//zz DIP(" => not implemented\n");
5652//zz return False;
5653//zz
5654//zz default:
5655//zz vex_printf("dis_av_shift(PPC32)(opc2)\n");
5656//zz return False;
5657//zz }
5658//zz return True;
5659//zz }
5660//zz
5661//zz /*
5662//zz AltiVec Permute Instructions
5663//zz */
5664//zz static Bool dis_av_permute ( UInt theInstr )
5665//zz {
5666//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
5667//zz UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
5668//zz UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5669//zz UChar UIMM_5 = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5670//zz UChar SIMM_5 = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5671//zz UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
5672//zz UChar vC_addr = toUChar((theInstr >> 6) & 0x1F); /* theInstr[6:10] */
5673//zz UChar b10 = toUChar((theInstr >> 10) & 0x1); /* theInstr[10] */
5674//zz UChar SHB_uimm4 = toUChar((theInstr >> 6) & 0xF); /* theInstr[6:9] */
5675//zz UInt opc2 = (theInstr >> 0) & 0x3F; /* theInstr[0:5] */
5676//zz
5677//zz UChar SIMM_8 = extend_s_5to8(SIMM_5);
5678//zz
5679//zz if (opc1 != 0x4) {
5680//zz vex_printf("dis_av_permute(PPC32)(instr)\n");
5681//zz return False;
5682//zz }
5683//zz
5684//zz switch (opc2) {
5685//zz case 0x2A: // vsel (Conditional Select, AV p238)
5686//zz DIP("vsel v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
5687//zz DIP(" => not implemented\n");
5688//zz return False;
5689//zz
5690//zz case 0x2B: // vperm (Permute, AV p218)
5691//zz DIP("vperm v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr, vC_addr);
5692//zz DIP(" => not implemented\n");
5693//zz return False;
5694//zz
5695//zz case 0x2C: // vsldoi (Shift Left Double by Octet Imm, AV p241)
5696//zz if (b10 != 0) {
5697//zz vex_printf("dis_av_permute(PPC32)(vsldoi)\n");
5698//zz return False;
5699//zz }
5700//zz DIP("vsldoi v%d,v%d,v%d,%d\n", vD_addr, vA_addr, vB_addr, SHB_uimm4);
5701//zz DIP(" => not implemented\n");
5702//zz return False;
5703//zz
5704//zz default:
5705//zz break; // Fall through...
5706//zz }
5707//zz
5708//zz opc2 = (theInstr) & 0x7FF; /* theInstr[0:10] */
5709//zz switch (opc2) {
5710//zz
5711//zz /* Merge */
5712//zz case 0x00C: // vmrghb (Merge High B, AV p195)
5713//zz DIP("vmrghb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5714//zz DIP(" => not implemented\n");
5715//zz return False;
5716//zz
5717//zz case 0x04C: // vmrghh (Merge High HW, AV p196)
5718//zz DIP("vmrghh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5719//zz DIP(" => not implemented\n");
5720//zz return False;
5721//zz
5722//zz case 0x08C: // vmrghw (Merge High W, AV p197)
5723//zz DIP("vmrghw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5724//zz DIP(" => not implemented\n");
5725//zz return False;
5726//zz
5727//zz case 0x10C: // vmrglb (Merge Low B, AV p198)
5728//zz DIP("vmrglb v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5729//zz DIP(" => not implemented\n");
5730//zz return False;
5731//zz
5732//zz case 0x14C: // vmrglh (Merge Low HW, AV p199)
5733//zz DIP("vmrglh v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5734//zz DIP(" => not implemented\n");
5735//zz return False;
5736//zz
5737//zz case 0x18C: // vmrglw (Merge Low W, AV p200)
5738//zz DIP("vmrglw v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5739//zz DIP(" => not implemented\n");
5740//zz return False;
5741//zz
5742//zz /* Splat */
5743//zz case 0x20C: // vspltb (Splat Byte, AV p245)
5744//zz DIP("vspltb v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
5745//zz DIP(" => not implemented\n");
5746//zz return False;
5747//zz
5748//zz case 0x24C: // vsplth (Splat Half Word, AV p246)
5749//zz DIP("vsplth v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
5750//zz DIP(" => not implemented\n");
5751//zz return False;
5752//zz
5753//zz case 0x28C: // vspltw (Splat Word, AV p250)
5754//zz DIP("vspltw v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
5755//zz DIP(" => not implemented\n");
5756//zz return False;
5757//zz
5758//zz case 0x30C: // vspltisb (Splat Immediate Signed B, AV p247)
5759//zz DIP("vspltisb v%d,%d\n", vD_addr, (Char)SIMM_8);
5760//zz DIP(" => not implemented\n");
5761//zz return False;
5762//zz
5763//zz case 0x34C: // vspltish (Splat Immediate Signed HW, AV p248)
5764//zz DIP("vspltish v%d,%d\n", vD_addr, (Char)SIMM_8);
5765//zz DIP(" => not implemented\n");
5766//zz return False;
5767//zz
5768//zz case 0x38C: // vspltisw (Splat Immediate Signed W, AV p249)
5769//zz DIP("vspltisw v%d,%d\n", vD_addr, (Char)SIMM_8);
5770//zz DIP(" => not implemented\n");
5771//zz return False;
5772//zz
5773//zz default:
5774//zz vex_printf("dis_av_permute(PPC32)(opc2)\n");
5775//zz return False;
5776//zz }
5777//zz return True;
5778//zz }
5779//zz
5780//zz /*
5781//zz AltiVec Pack/Unpack Instructions
5782//zz */
5783//zz static Bool dis_av_pack ( UInt theInstr )
5784//zz {
5785//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
5786//zz UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
5787//zz UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5788//zz UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
5789//zz UInt opc2 = (theInstr >> 0) & 0x7FF; /* theInstr[0:10] */
5790//zz
5791//zz if (opc1 != 0x4) {
5792//zz vex_printf("dis_av_pack(PPC32)(instr)\n");
5793//zz return False;
5794//zz }
5795//zz
5796//zz switch (opc2) {
5797//zz /* Packing */
5798//zz case 0x00E: // vpkuhum (Pack Unsigned HW Unsigned Modulo, AV p224)
5799//zz DIP("vpkuhum v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5800//zz DIP(" => not implemented\n");
5801//zz return False;
5802//zz
5803//zz case 0x04E: // vpkuwum (Pack Unsigned W Unsigned Modulo, AV p226)
5804//zz DIP("vpkuwum v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5805//zz DIP(" => not implemented\n");
5806//zz return False;
5807//zz
5808//zz case 0x08E: // vpkuhus (Pack Unsigned HW Unsigned Saturate, AV p225)
5809//zz DIP("vpkuhus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5810//zz DIP(" => not implemented\n");
5811//zz return False;
5812//zz
5813//zz case 0x0CE: // vpkuwus (Pack Unsigned W Unsigned Saturate, AV p227)
5814//zz DIP("vpkuwus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5815//zz DIP(" => not implemented\n");
5816//zz return False;
5817//zz
5818//zz case 0x10E: // vpkshus (Pack Signed HW Unsigned Saturate, AV p221)
5819//zz DIP("vpkshus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5820//zz DIP(" => not implemented\n");
5821//zz return False;
5822//zz
5823//zz case 0x14E: // vpkswus (Pack Signed W Unsigned Saturate, AV p223)
5824//zz DIP("vpkswus v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5825//zz DIP(" => not implemented\n");
5826//zz return False;
5827//zz
5828//zz case 0x18E: // vpkshss (Pack Signed HW Signed Saturate, AV p220)
5829//zz DIP("vpkshss v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5830//zz DIP(" => not implemented\n");
5831//zz return False;
5832//zz
5833//zz case 0x1CE: // vpkswss (Pack Signed W Signed Saturate, AV p222)
5834//zz DIP("vpkswss v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5835//zz DIP(" => not implemented\n");
5836//zz return False;
5837//zz
5838//zz case 0x30E: // vpkpx (Pack Pixel, AV p219)
5839//zz DIP("vpkpx v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5840//zz DIP(" => not implemented\n");
5841//zz return False;
5842//zz
5843//zz default:
5844//zz break; // Fall through...
5845//zz }
5846//zz
5847//zz
5848//zz if (vA_addr != 0) {
5849//zz vex_printf("dis_av_pack(PPC32)(vA_addr)\n");
5850//zz return False;
5851//zz }
5852//zz
5853//zz switch (opc2) {
5854//zz /* Unpacking */
5855//zz case 0x20E: // vupkhsb (Unpack High Signed B, AV p277)
5856//zz DIP("vupkhsb v%d,v%d\n", vD_addr, vB_addr);
5857//zz DIP(" => not implemented\n");
5858//zz return False;
5859//zz
5860//zz case 0x24E: // vupkhsh (Unpack High Signed HW, AV p278)
5861//zz DIP("vupkhsh v%d,v%d\n", vD_addr, vB_addr);
5862//zz DIP(" => not implemented\n");
5863//zz return False;
5864//zz
5865//zz case 0x28E: // vupklsb (Unpack Low Signed B, AV p280)
5866//zz DIP("vupklsb v%d,v%d\n", vD_addr, vB_addr);
5867//zz DIP(" => not implemented\n");
5868//zz return False;
5869//zz
5870//zz case 0x2CE: // vupklsh (Unpack Low Signed HW, AV p281)
5871//zz DIP("vupklsh v%d,v%d\n", vD_addr, vB_addr);
5872//zz DIP(" => not implemented\n");
5873//zz return False;
5874//zz
5875//zz case 0x34E: // vupkhpx (Unpack High Pixel16, AV p276)
5876//zz DIP("vupkhpx v%d,v%d\n", vD_addr, vB_addr);
5877//zz DIP(" => not implemented\n");
5878//zz return False;
5879//zz
5880//zz case 0x3CE: // vupklpx (Unpack Low Pixel16, AV p279)
5881//zz DIP("vupklpx v%d,v%d\n", vD_addr, vB_addr);
5882//zz DIP(" => not implemented\n");
5883//zz return False;
5884//zz
5885//zz default:
5886//zz vex_printf("dis_av_pack(PPC32)(opc2)\n");
5887//zz return False;
5888//zz }
5889//zz return True;
5890//zz }
5891//zz
5892//zz
5893//zz /*
5894//zz AltiVec Floating Point Arithmetic Instructions
5895//zz */
5896//zz static Bool dis_av_fp_arith ( UInt theInstr )
5897//zz {
5898//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
5899//zz UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
5900//zz UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5901//zz UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
5902//zz UChar vC_addr = toUChar((theInstr >> 6) & 0x1F); /* theInstr[6:10] */
5903//zz UInt opc2=0;
5904//zz
5905//zz if (opc1 != 0x4) {
5906//zz vex_printf("dis_av_fp_arith(PPC32)(instr)\n");
5907//zz return False;
5908//zz }
5909//zz
5910//zz opc2 = (theInstr) & 0x3F; /* theInstr[0:5] */
5911//zz switch (opc2) {
5912//zz case 0x2E: // vmaddfp (Multiply Add FP, AV p177)
5913//zz DIP("vmaddfp v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vC_addr, vB_addr);
5914//zz DIP(" => not implemented\n");
5915//zz return False;
5916//zz
5917//zz case 0x2F: // vnmsubfp (Negative Multiply-Subtract FP, AV p215)
5918//zz DIP("vnmsubfp v%d,v%d,v%d,v%d\n", vD_addr, vA_addr, vC_addr, vB_addr);
5919//zz DIP(" => not implemented\n");
5920//zz return False;
5921//zz
5922//zz default:
5923//zz break; // Fall through...
5924//zz }
5925//zz
5926//zz opc2 = (theInstr) & 0x7FF; /* theInstr[0:10] */
5927//zz switch (opc2) {
5928//zz case 0x00A: // vaddfp (Add FP, AV p137)
5929//zz DIP("vaddfp v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5930//zz DIP(" => not implemented\n");
5931//zz return False;
5932//zz
5933//zz case 0x04A: // vsubfp (Subtract FP, AV p261)
5934//zz DIP("vsubfp v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5935//zz DIP(" => not implemented\n");
5936//zz return False;
5937//zz
5938//zz case 0x40A: // vmaxfp (Maximum FP, AV p178)
5939//zz DIP("vmaxfp v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5940//zz DIP(" => not implemented\n");
5941//zz return False;
5942//zz
5943//zz case 0x44A: // vminfp (Minimum FP, AV p187)
5944//zz DIP("vminfp v%d,v%d,v%d\n", vD_addr, vA_addr, vB_addr);
5945//zz DIP(" => not implemented\n");
5946//zz return False;
5947//zz
5948//zz default:
5949//zz break; // Fall through...
5950//zz }
5951//zz
5952//zz
5953//zz if (vA_addr != 0) {
5954//zz vex_printf("dis_av_fp_arith(PPC32)(vA_addr)\n");
5955//zz return False;
5956//zz }
5957//zz
5958//zz switch (opc2) {
5959//zz case 0x10A: // vrefp (Reciprocal Esimate FP, AV p228)
5960//zz DIP("vrefp v%d,v%d\n", vD_addr, vB_addr);
5961//zz DIP(" => not implemented\n");
5962//zz return False;
5963//zz
5964//zz case 0x14A: // vrsqrtefp (Reciprocal Square Root Estimate FP, AV p237)
5965//zz DIP("vrsqrtefp v%d,v%d\n", vD_addr, vB_addr);
5966//zz DIP(" => not implemented\n");
5967//zz return False;
5968//zz
5969//zz case 0x18A: // vexptefp (2 Raised to the Exp Est FP, AV p173)
5970//zz DIP("vexptefp v%d,v%d\n", vD_addr, vB_addr);
5971//zz DIP(" => not implemented\n");
5972//zz return False;
5973//zz
5974//zz case 0x1CA: // vlogefp (Log2 Estimate FP, AV p175)
5975//zz DIP("vlogefp v%d,v%d\n", vD_addr, vB_addr);
5976//zz DIP(" => not implemented\n");
5977//zz return False;
5978//zz
5979//zz default:
5980//zz vex_printf("dis_av_fp_arith(PPC32)(opc2=0x%x)\n",opc2);
5981//zz return False;
5982//zz }
5983//zz return True;
5984//zz }
5985//zz
5986//zz /*
5987//zz AltiVec Floating Point Compare Instructions
5988//zz */
5989//zz static Bool dis_av_fp_cmp ( UInt theInstr )
5990//zz {
5991//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
5992//zz UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
5993//zz UChar vA_addr = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
5994//zz UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
5995//zz UChar flag_Rc = toUChar((theInstr >> 10) & 0x1); /* theInstr[10] */
5996//zz UInt opc2 = (theInstr >> 0) & 0x3FF; /* theInstr[0:9] */
5997//zz
5998//zz if (opc1 != 0x4) {
5999//zz vex_printf("dis_av_fp_cmp(PPC32)(instr)\n");
6000//zz return False;
6001//zz }
6002//zz
6003//zz switch (opc2) {
6004//zz case 0x0C6: // vcmpeqfp (Compare Equal-to FP, AV p159)
6005//zz DIP("vcmpeqfp%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
6006//zz DIP(" => not implemented\n");
6007//zz return False;
6008//zz
6009//zz case 0x1C6: // vcmpgefp (Compare Greater-than-or-Equal-to FP, AV p163)
6010//zz DIP("vcmpgefp%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
6011//zz DIP(" => not implemented\n");
6012//zz return False;
6013//zz
6014//zz case 0x2C6: // vcmpgtfp (Compare Greater-than FP, AV p164)
6015//zz DIP("vcmpgtfp%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
6016//zz DIP(" => not implemented\n");
6017//zz return False;
6018//zz
6019//zz case 0x3C6: // vcmpbfp (Compare Bounds FP, AV p157)
6020//zz DIP("vcmpbfp%s v%d,v%d,v%d\n", (flag_Rc ? ".":""), vD_addr, vA_addr, vB_addr);
6021//zz DIP(" => not implemented\n");
6022//zz return False;
6023//zz
6024//zz default:
6025//zz vex_printf("dis_av_fp_cmp(PPC32)(opc2)\n");
6026//zz return False;
6027//zz }
6028//zz return True;
6029//zz }
6030//zz
6031//zz /*
6032//zz AltiVec Floating Point Convert/Round Instructions
6033//zz */
6034//zz static Bool dis_av_fp_convert ( UInt theInstr )
6035//zz {
6036//zz UChar opc1 = toUChar((theInstr >> 26) & 0x3F); /* theInstr[26:31] */
6037//zz UChar vD_addr = toUChar((theInstr >> 21) & 0x1F); /* theInstr[21:25] */
6038//zz UChar UIMM_5 = toUChar((theInstr >> 16) & 0x1F); /* theInstr[16:20] */
6039//zz UChar vB_addr = toUChar((theInstr >> 11) & 0x1F); /* theInstr[11:15] */
6040//zz UInt opc2 = (theInstr >> 0) & 0x7FF; /* theInstr[0:10] */
6041//zz
6042//zz if (opc1 != 0x4) {
6043//zz vex_printf("dis_av_fp_convert(PPC32)(instr)\n");
6044//zz return False;
6045//zz }
6046//zz
6047//zz switch (opc2) {
6048//zz case 0x30A: // vcfux (Convert from Unsigned Fixed-Point W, AV p156)
6049//zz DIP("vcfux v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
6050//zz DIP(" => not implemented\n");
6051//zz return False;
6052//zz
6053//zz case 0x34A: // vcfsx (Convert from Signed Fixed-Point W, AV p155)
6054//zz DIP("vcfsx v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
6055//zz DIP(" => not implemented\n");
6056//zz return False;
6057//zz
6058//zz case 0x38A: // vctuxs (Convert to Unsigned Fixed-Point W Saturate, AV p172)
6059//zz DIP("vctuxs v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
6060//zz DIP(" => not implemented\n");
6061//zz return False;
6062//zz
6063//zz case 0x3CA: // vctsxs (Convert to Signed Fixed-Point W Saturate, AV p171)
6064//zz DIP("vctsxs v%d,v%d,%d\n", vD_addr, vB_addr, UIMM_5);
6065//zz DIP(" => not implemented\n");
6066//zz return False;
6067//zz
6068//zz default:
6069//zz break; // Fall through...
6070//zz }
6071//zz
6072//zz if (UIMM_5 != 0) {
6073//zz vex_printf("dis_av_fp_convert(PPC32)(UIMM_5)\n");
6074//zz return False;
6075//zz }
6076//zz
6077//zz switch (opc2) {
6078//zz case 0x20A: // vrfin (Round to FP Integer Nearest, AV p231)
6079//zz DIP("vrfin v%d,v%d\n", vD_addr, vB_addr);
6080//zz DIP(" => not implemented\n");
6081//zz return False;
6082//zz
6083//zz case 0x24A: // vrfiz (Round to FP Integer toward zero, AV p233)
6084//zz DIP("vrfiz v%d,v%d\n", vD_addr, vB_addr);
6085//zz DIP(" => not implemented\n");
6086//zz return False;
6087//zz
6088//zz case 0x28A: // vrfip (Round to FP Integer toward +inf, AV p232)
6089//zz DIP("vrfip v%d,v%d\n", vD_addr, vB_addr);
6090//zz DIP(" => not implemented\n");
6091//zz return False;
6092//zz
6093//zz case 0x2CA: // vrfim (Round to FP Integer toward -inf, AV p230)
6094//zz DIP("vrfim v%d,v%d\n", vD_addr, vB_addr);
6095//zz DIP(" => not implemented\n");
6096//zz return False;
6097//zz
6098//zz default:
6099//zz vex_printf("dis_av_fp_convert(PPC32)(opc2)\n");
6100//zz return False;
6101//zz }
6102//zz return True;
6103//zz }
cerion3d870a32005-03-18 12:23:33 +00006104
6105
cerion91ad5362005-01-27 23:02:41 +00006106
6107
6108
6109
cerion896a1372005-01-25 12:24:25 +00006110/*------------------------------------------------------------*/
6111/*--- Disassemble a single instruction ---*/
6112/*------------------------------------------------------------*/
6113
6114/* Disassemble a single instruction into IR. The instruction
sewardj9e6491a2005-07-02 19:24:10 +00006115 is located in host memory at &guest_code[delta]. */
6116
6117static
6118DisResult disInstr_PPC32_WRK (
6119 Bool put_IP,
6120 Bool (*resteerOkFn) ( Addr64 ),
6121 Long delta64,
6122 VexArchInfo* archinfo
6123 )
cerion896a1372005-01-25 12:24:25 +00006124{
sewardj9e6491a2005-07-02 19:24:10 +00006125 UChar opc1;
6126 UInt opc2;
6127 DisResult dres;
cerion896a1372005-01-25 12:24:25 +00006128 UInt theInstr;
6129
sewardj9e6491a2005-07-02 19:24:10 +00006130 /* The running delta */
6131 Int delta = (Int)delta64;
6132
6133 /* Set result defaults. */
6134 dres.whatNext = Dis_Continue;
6135 dres.len = 0;
6136 dres.continueAt = 0;
cerion896a1372005-01-25 12:24:25 +00006137
cerion1515db92005-01-25 17:21:23 +00006138 /* At least this is simple on PPC32: insns are all 4 bytes long, and
cerion896a1372005-01-25 12:24:25 +00006139 4-aligned. So just fish the whole thing out of memory right now
6140 and have done. */
cerioncf004462005-01-31 15:24:55 +00006141 theInstr = getUIntBigendianly( (UChar*)(&guest_code[delta]) );
cerion896a1372005-01-25 12:24:25 +00006142
sewardjb51f0f42005-07-18 11:38:02 +00006143 DIP("\t0x%x: ", guest_CIA_curr_instr);
6144
6145 /* We may be asked to update the guest CIA before going further. */
6146 if (put_IP)
6147 putSPR( PPC32_SPR_CIA, mkU32(guest_CIA_curr_instr) );
cerion896a1372005-01-25 12:24:25 +00006148
cerion896a1372005-01-25 12:24:25 +00006149 /* Spot the client-request magic sequence. */
6150 // Essentially a v. unlikely sequence of noops that we can catch
6151 {
sewardj2f52de42005-07-03 01:51:29 +00006152 UChar* code = (UChar*)(&guest_code[delta]);
cerion896a1372005-01-25 12:24:25 +00006153
6154 /* Spot this:
sewardj2f52de42005-07-03 01:51:29 +00006155 0x7C03D808 tw 0,3,27 => trap word if (0) => nop
cerionb85e8bb2005-02-16 08:54:33 +00006156 0x5400E800 rlwinm 0,0,29,0,0 => r0 = rotl(r0,29)
6157 0x54001800 rlwinm 0,0,3,0,0 => r0 = rotl(r0,3)
6158 0x54006800 rlwinm 0,0,13,0,0 => r0 = rotl(r0,13)
6159 0x54009800 rlwinm 0,0,19,0,0 => r0 = rotl(r0,19)
cerion0fe6b7e2005-06-20 16:28:32 +00006160 0x60000000 nop
cerion896a1372005-01-25 12:24:25 +00006161 */
sewardj2f52de42005-07-03 01:51:29 +00006162 if (getUIntBigendianly(code+ 0) == 0x7C03D808 &&
6163 getUIntBigendianly(code+ 4) == 0x5400E800 &&
6164 getUIntBigendianly(code+ 8) == 0x54001800 &&
6165 getUIntBigendianly(code+12) == 0x54006800 &&
6166 getUIntBigendianly(code+16) == 0x54009800 &&
6167 getUIntBigendianly(code+20) == 0x60000000) {
cerion84ad6162005-06-23 15:25:57 +00006168 DIP("%%r3 = client_request ( %%r31 )\n");
sewardj9e6491a2005-07-02 19:24:10 +00006169 dres.len = 24;
cerioned623db2005-06-20 12:42:04 +00006170 delta += 24;
6171
sewardj9e6491a2005-07-02 19:24:10 +00006172 irbb->next = mkU32(guest_CIA_bbstart+delta);
cerionb85e8bb2005-02-16 08:54:33 +00006173 irbb->jumpkind = Ijk_ClientReq;
sewardj9e6491a2005-07-02 19:24:10 +00006174 dres.whatNext = Dis_StopHere;
cerion896a1372005-01-25 12:24:25 +00006175 goto decode_success;
6176 }
6177 }
6178
6179
sewardjb51f0f42005-07-18 11:38:02 +00006180 opc1 = ifieldOPC(theInstr);
6181 opc2 = ifieldOPClo10(theInstr);
cerion932ad942005-01-30 10:18:50 +00006182
cerione9d361a2005-03-04 17:35:29 +00006183#if PPC32_TOIR_DEBUG
cerion45552a92005-02-03 18:20:22 +00006184 vex_printf("\ndisInstr(ppc32): instr: 0x%x\n", theInstr);
6185 vex_printf("disInstr(ppc32): instr: ");
6186 vex_printf_binary( theInstr, 32, True );
6187 vex_printf("\n");
cerion45552a92005-02-03 18:20:22 +00006188#endif
cerione9d361a2005-03-04 17:35:29 +00006189
cerion45552a92005-02-03 18:20:22 +00006190
cerion91ad5362005-01-27 23:02:41 +00006191 // Note: all 'reserved' bits must be cleared, else invalid
6192 switch (opc1) {
cerion896a1372005-01-25 12:24:25 +00006193
cerione9d361a2005-03-04 17:35:29 +00006194 /* Integer Arithmetic Instructions */
6195 case 0x0C: case 0x0D: case 0x0E: // addic, addic., addi
6196 case 0x0F: case 0x07: case 0x08: // addis, mulli, subfic
6197 if (dis_int_arith( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006198 goto decode_failure;
cerion7aa4bbc2005-01-29 09:32:07 +00006199
cerione9d361a2005-03-04 17:35:29 +00006200 /* Integer Compare Instructions */
6201 case 0x0B: case 0x0A: // cmpi, cmpli
6202 if (dis_int_cmp( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006203 goto decode_failure;
cerion7aa4bbc2005-01-29 09:32:07 +00006204
cerione9d361a2005-03-04 17:35:29 +00006205 /* Integer Logical Instructions */
6206 case 0x1C: case 0x1D: case 0x18: // andi., andis., ori
6207 case 0x19: case 0x1A: case 0x1B: // oris, xori, xoris
6208 if (dis_int_logic( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006209 goto decode_failure;
cerion7aa4bbc2005-01-29 09:32:07 +00006210
cerione9d361a2005-03-04 17:35:29 +00006211 /* Integer Rotate Instructions */
6212 case 0x14: case 0x15: case 0x17: // rlwimi, rlwinm, rlwnm
6213 if (dis_int_rot( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006214 goto decode_failure;
cerion645c9302005-01-31 10:09:59 +00006215
cerione9d361a2005-03-04 17:35:29 +00006216 /* Integer Load Instructions */
6217 case 0x22: case 0x23: case 0x2A: // lbz, lbzu, lha
6218 case 0x2B: case 0x28: case 0x29: // lhau, lhz, lhzu
6219 case 0x20: case 0x21: // lwz, lwzu
6220 if (dis_int_load( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006221 goto decode_failure;
cerion645c9302005-01-31 10:09:59 +00006222
cerione9d361a2005-03-04 17:35:29 +00006223 /* Integer Store Instructions */
6224 case 0x26: case 0x27: case 0x2C: // stb, stbu, sth
6225 case 0x2D: case 0x24: case 0x25: // sthu, stw, stwu
6226 if (dis_int_store( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006227 goto decode_failure;
ceriond23be4e2005-01-31 07:23:07 +00006228
sewardjb51f0f42005-07-18 11:38:02 +00006229//zz /* Integer Load and Store Multiple Instructions */
6230//zz case 0x2E: case 0x2F: // lmw, stmw
6231//zz if (dis_int_ldst_mult( theInstr )) goto decode_success;
6232//zz goto decode_failure;
cerion645c9302005-01-31 10:09:59 +00006233
cerione9d361a2005-03-04 17:35:29 +00006234 /* Branch Instructions */
6235 case 0x12: case 0x10: // b, bc
sewardj9e6491a2005-07-02 19:24:10 +00006236 if (dis_branch(theInstr, &dres)) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006237 goto decode_failure;
cerion896a1372005-01-25 12:24:25 +00006238
cerione9d361a2005-03-04 17:35:29 +00006239 /* System Linkage Instructions */
cerion8c3adda2005-01-31 11:54:05 +00006240 case 0x11: // sc
sewardj9e6491a2005-07-02 19:24:10 +00006241 if (dis_syslink(theInstr, &dres)) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006242 goto decode_failure;
cerion26d07b22005-02-02 17:13:28 +00006243
sewardjb51f0f42005-07-18 11:38:02 +00006244//zz /* Trap Instructions */
6245//zz case 0x03: // twi
6246//zz DIP("trap op (twi) => not implemented\n");
6247//zz goto decode_failure;
cerion8c3adda2005-01-31 11:54:05 +00006248
cerion3d870a32005-03-18 12:23:33 +00006249 /* Floating Point Load Instructions */
cerion094d1392005-06-20 13:45:57 +00006250 case 0x30: case 0x31: case 0x32: // lfs, lfsu, lfd
6251 case 0x33: // lfdu
cerion3d870a32005-03-18 12:23:33 +00006252 if (dis_fp_load( theInstr )) goto decode_success;
cerione9d361a2005-03-04 17:35:29 +00006253 goto decode_failure;
cerion995bc362005-02-03 11:03:31 +00006254
cerion3d870a32005-03-18 12:23:33 +00006255 /* Floating Point Store Instructions */
6256 case 0x34: case 0x35: case 0x36: // stfsx, stfsux, stfdx
6257 case 0x37: // stfdux
6258 if (dis_fp_store( theInstr )) goto decode_success;
6259 goto decode_failure;
6260
sewardjb51f0f42005-07-18 11:38:02 +00006261//zz case 0x3B:
6262//zz opc2 = (theInstr >> 1) & 0x1F; /* theInstr[1:5] */
6263//zz switch (opc2) {
6264//zz /* Floating Point Arith Instructions */
6265//zz case 0x12: case 0x14: case 0x15: // fdivs, fsubs, fadds
6266//zz case 0x16: case 0x18: case 0x19: // fsqrts, fres, fmuls
6267//zz if (dis_fp_arith(theInstr)) goto decode_success;
6268//zz goto decode_failure;
6269//zz
6270//zz /* Floating Point Mult-Add Instructions */
6271//zz case 0x1C: case 0x1D: case 0x1E: // fmsubs, fmadds, fnmsubs
6272//zz case 0x1F: // fnmadds
6273//zz if (dis_fp_multadd(theInstr)) goto decode_success;
6274//zz goto decode_failure;
6275//zz
6276//zz default:
6277//zz goto decode_failure;
6278//zz }
6279//zz break;
cerion3d870a32005-03-18 12:23:33 +00006280
6281 case 0x3F:
6282 /* Instrs using opc[1:5] never overlap with instrs using opc[1:10],
6283 so we can simply fall through the first switch statement */
6284
6285 opc2 = (theInstr >> 1) & 0x1F; /* theInstr[1:5] */
6286 switch (opc2) {
sewardjb51f0f42005-07-18 11:38:02 +00006287 /* Floating Point Arith Instructions */
6288 case 0x12: case 0x14: case 0x15: // fdiv, fsub, fadd
6289 case 0x16: case 0x17: case 0x19: // fsqrt, fsel, fmul
6290 case 0x1A: // frsqrte
6291 if (dis_fp_arith(theInstr)) goto decode_success;
6292 goto decode_failure;
cerion3d870a32005-03-18 12:23:33 +00006293
sewardjb51f0f42005-07-18 11:38:02 +00006294//zz /* Floating Point Mult-Add Instructions */
6295//zz case 0x1C: case 0x1D: case 0x1E: // fmsub, fmadd, fnmsub
6296//zz case 0x1F: // fnmadd
6297//zz if (dis_fp_multadd(theInstr)) goto decode_success;
6298//zz goto decode_failure;
6299//zz
6300 default:
6301 break; // Fall through
cerion3d870a32005-03-18 12:23:33 +00006302 }
6303
sewardjb51f0f42005-07-18 11:38:02 +00006304//zz opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
6305//zz switch (opc2) {
6306//zz /* Floating Point Compare Instructions */
6307//zz case 0x000: // fcmpu
6308//zz case 0x020: // fcmpo
6309//zz if (dis_fp_cmp(theInstr)) goto decode_success;
6310//zz goto decode_failure;
6311//zz
6312//zz /* Floating Point Rounding/Conversion Instructions */
6313//zz case 0x00C: // frsp
6314//zz case 0x00E: // fctiw
6315//zz case 0x00F: // fctiwz
6316//zz if (dis_fp_round(theInstr)) goto decode_success;
6317//zz goto decode_failure;
6318//zz
6319//zz /* Floating Point Move Instructions */
6320//zz case 0x028: // fneg
6321//zz case 0x048: // fmr
6322//zz case 0x088: // fnabs
6323//zz case 0x108: // fabs
6324//zz if (dis_fp_move( theInstr )) goto decode_success;
6325//zz goto decode_failure;
6326//zz
6327//zz /* Floating Point Status/Control Register Instructions */
6328//zz case 0x026: // mtfsb1
6329//zz case 0x040: // mcrfs
6330//zz case 0x046: // mtfsb0
6331//zz case 0x086: // mtfsfi
6332//zz case 0x247: // mffs
6333//zz case 0x2C7: // mtfsf
6334//zz if (dis_fp_scr( theInstr )) goto decode_success;
6335//zz goto decode_failure;
6336//zz
6337//zz default:
6338//zz goto decode_failure;
6339//zz }
cerion3d870a32005-03-18 12:23:33 +00006340 break;
cerion91ad5362005-01-27 23:02:41 +00006341
6342 case 0x13:
cerionb85e8bb2005-02-16 08:54:33 +00006343 switch (opc2) {
cerion91ad5362005-01-27 23:02:41 +00006344
sewardjb51f0f42005-07-18 11:38:02 +00006345 /* Condition Register Logical Instructions */
6346 case 0x101: case 0x081: case 0x121: // crand, crandc, creqv
6347 case 0x0E1: case 0x021: case 0x1C1: // crnand, crnor, cror
6348 case 0x1A1: case 0x0C1: case 0x000: // crorc, crxor, mcrf
6349 if (dis_cond_logic( theInstr )) goto decode_success;
6350 goto decode_failure;
cerion26d07b22005-02-02 17:13:28 +00006351
sewardjb51f0f42005-07-18 11:38:02 +00006352 /* Branch Instructions */
6353 case 0x210: case 0x010: // bcctr, bclr
6354 if (dis_branch(theInstr, &dres)) goto decode_success;
6355 goto decode_failure;
cerion91ad5362005-01-27 23:02:41 +00006356
sewardjb51f0f42005-07-18 11:38:02 +00006357 /* Memory Synchronization Instructions */
6358 case 0x096: // isync
6359 if (dis_memsync( theInstr )) goto decode_success;
6360 goto decode_failure;
cerionb85e8bb2005-02-16 08:54:33 +00006361
sewardjb51f0f42005-07-18 11:38:02 +00006362 default:
6363 goto decode_failure;
cerionb85e8bb2005-02-16 08:54:33 +00006364 }
6365 break;
cerion91ad5362005-01-27 23:02:41 +00006366
6367
cerionb85e8bb2005-02-16 08:54:33 +00006368 case 0x1F:
cerione9d361a2005-03-04 17:35:29 +00006369
6370 /* For arith instns, bit10 is the OE flag (overflow enable) */
6371
cerionb85e8bb2005-02-16 08:54:33 +00006372 opc2 = (theInstr >> 1) & 0x1FF; /* theInstr[1:9] */
6373 switch (opc2) {
sewardjb51f0f42005-07-18 11:38:02 +00006374 /* Integer Arithmetic Instructions */
6375 case 0x10A: case 0x00A: case 0x08A: // add, addc, adde
6376 case 0x0EA: case 0x0CA: case 0x1EB: // addme, addze, divw
6377 case 0x1CB: case 0x04B: case 0x00B: // divwu, mulhw, mulhwu
6378 case 0x0EB: case 0x068: case 0x028: // mullw, neg, subf
6379 case 0x008: case 0x088: case 0x0E8: // subfc, subfe, subfme
6380 case 0x0C8: // subfze
6381 if (dis_int_arith( theInstr )) goto decode_success;
6382 goto decode_failure;
6383 default:
6384 break; // Fall through...
cerionb85e8bb2005-02-16 08:54:33 +00006385 }
cerion91ad5362005-01-27 23:02:41 +00006386
cerione9d361a2005-03-04 17:35:29 +00006387 /* All remaining opcodes use full 10 bits. */
6388
cerionb85e8bb2005-02-16 08:54:33 +00006389 opc2 = (theInstr >> 1) & 0x3FF; /* theInstr[1:10] */
6390 switch (opc2) {
cerione9d361a2005-03-04 17:35:29 +00006391 /* Integer Compare Instructions */
6392 case 0x000: case 0x020: // cmp, cmpl
6393 if (dis_int_cmp( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006394 goto decode_failure;
cerion7aa4bbc2005-01-29 09:32:07 +00006395
cerione9d361a2005-03-04 17:35:29 +00006396 /* Integer Logical Instructions */
6397 case 0x01C: case 0x03C: case 0x01A: // and, andc, cntlzw
6398 case 0x11C: case 0x3BA: case 0x39A: // eqv, extsb, extsh
6399 case 0x1DC: case 0x07C: case 0x1BC: // nand, nor, or
6400 case 0x19C: case 0x13C: // orc, xor
6401 if (dis_int_logic( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006402 goto decode_failure;
cerion932ad942005-01-30 10:18:50 +00006403
cerione9d361a2005-03-04 17:35:29 +00006404 /* Integer Shift Instructions */
6405 case 0x018: case 0x318: case 0x338: // slw, sraw, srawi
6406 case 0x218: // srw
6407 if (dis_int_shift( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006408 goto decode_failure;
cerion7aa4bbc2005-01-29 09:32:07 +00006409
cerione9d361a2005-03-04 17:35:29 +00006410 /* Integer Load Instructions */
6411 case 0x057: case 0x077: case 0x157: // lbzx, lbzux, lhax
6412 case 0x177: case 0x117: case 0x137: // lhaux, lhzx, lhzux
6413 case 0x017: case 0x037: // lwzx, lwzux
6414 if (dis_int_load( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006415 goto decode_failure;
cerion7aa4bbc2005-01-29 09:32:07 +00006416
sewardjb51f0f42005-07-18 11:38:02 +00006417 /* Integer Store Instructions */
cerione9d361a2005-03-04 17:35:29 +00006418 case 0x0F7: case 0x0D7: case 0x1B7: // stbux, stbx, sthux
6419 case 0x197: case 0x0B7: case 0x097: // sthx, stwux, stwx
6420 if (dis_int_store( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006421 goto decode_failure;
cerion91ad5362005-01-27 23:02:41 +00006422
sewardjb51f0f42005-07-18 11:38:02 +00006423//zz /* Integer Load and Store with Byte Reverse Instructions */
6424//zz case 0x316: case 0x216: case 0x396: // lhbrx, lwbrx, sthbrx
6425//zz case 0x296: // stwbrx
6426//zz if (dis_int_ldst_rev( theInstr )) goto decode_success;
6427//zz goto decode_failure;
6428//zz
6429//zz /* Integer Load and Store String Instructions */
6430//zz case 0x255: case 0x215: case 0x2D5: // lswi, lswx, stswi
6431//zz case 0x295: // stswx
6432//zz if (dis_int_ldst_str( theInstr )) goto decode_success;
6433//zz goto decode_failure;
cerion645c9302005-01-31 10:09:59 +00006434
cerione9d361a2005-03-04 17:35:29 +00006435 /* Memory Synchronization Instructions */
6436 case 0x356: case 0x014: case 0x096: // eieio, lwarx, stwcx.
6437 case 0x256: // sync
6438 if (dis_memsync( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006439 goto decode_failure;
6440
cerione9d361a2005-03-04 17:35:29 +00006441 /* Processor Control Instructions */
6442 case 0x200: case 0x013: case 0x153: // mcrxr, mfcr, mfspr
6443 case 0x173: case 0x090: case 0x1D3: // mftb, mtcrf, mtspr
6444 if (dis_proc_ctl( theInstr )) goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006445 goto decode_failure;
cerion645c9302005-01-31 10:09:59 +00006446
cerione9d361a2005-03-04 17:35:29 +00006447 /* Cache Management Instructions */
6448 case 0x2F6: case 0x056: case 0x036: // dcba, dcbf, dcbst
6449 case 0x116: case 0x0F6: case 0x3F6: // dcbt, dcbtst, dcbz
6450 case 0x3D6: // icbi
sewardj9e6491a2005-07-02 19:24:10 +00006451 if (dis_cache_manage( theInstr, &dres, archinfo ))
sewardjd94b73a2005-06-30 12:08:48 +00006452 goto decode_success;
cerionb85e8bb2005-02-16 08:54:33 +00006453 goto decode_failure;
ceriond23be4e2005-01-31 07:23:07 +00006454
sewardjb51f0f42005-07-18 11:38:02 +00006455//zz /* External Control Instructions */
6456//zz case 0x136: case 0x1B6: // eciwx, ecowx
6457//zz DIP("external control op => not implemented\n");
6458//zz goto decode_failure;
6459//zz
6460//zz /* Trap Instructions */
6461//zz case 0x004: // tw
6462//zz DIP("trap op (tw) => not implemented\n");
6463//zz goto decode_failure;
6464//zz
6465//zz /* Floating Point Load Instructions */
6466//zz case 0x217: case 0x237: case 0x257: // lfsx, lfsux, lfdx
6467//zz case 0x277: // lfdux
6468//zz if (dis_fp_load( theInstr )) goto decode_success;
6469//zz goto decode_failure;
6470//zz
6471//zz /* Floating Point Store Instructions */
6472//zz case 0x297: case 0x2B7: case 0x2D7: // stfs, stfsu, stfd
6473//zz case 0x2F7: case 0x3D7: // stfdu, stfiwx
6474//zz if (dis_fp_store( theInstr )) goto decode_success;
6475//zz goto decode_failure;
6476//zz
6477//zz
6478//zz /* AltiVec instructions */
6479//zz
6480//zz /* AV Cache Control - Data streams */
6481//zz case 0x156: case 0x176: case 0x336: // dst, dstst, dss
6482//zz if (dis_av_datastream( theInstr )) goto decode_success;
6483//zz goto decode_failure;
ceriona982c052005-06-28 17:23:09 +00006484
6485 /* AV Load */
6486 case 0x006: case 0x026: // lvsl, lvsr
6487 case 0x007: case 0x027: case 0x047: // lvebx, lvehx, lvewx
6488 case 0x067: case 0x167: // lvx, lvxl
6489 if (dis_av_load( theInstr )) goto decode_success;
6490 goto decode_failure;
6491
6492 /* AV Store */
6493 case 0x087: case 0x0A7: case 0x0C7: // stvebx, stvehx, stvewx
6494 case 0x0E7: case 0x1E7: // stvx, stvxl
6495 if (dis_av_store( theInstr )) goto decode_success;
6496 goto decode_failure;
6497
6498 default:
6499 goto decode_failure;
6500 }
6501 break;
6502
6503
sewardjb51f0f42005-07-18 11:38:02 +00006504//zz case 0x04:
6505//zz /* AltiVec instructions */
6506//zz
6507//zz opc2 = (theInstr) & 0x3F; /* theInstr[0:5] */
6508//zz switch (opc2) {
6509//zz /* AV Mult-Add, Mult-Sum */
6510//zz case 0x20: case 0x21: case 0x22: // vmhaddshs, vmhraddshs, vmladduhm
6511//zz case 0x24: case 0x25: case 0x26: // vmsumubm, vmsummbm, vmsumuhm
6512//zz case 0x27: case 0x28: case 0x29: // vmsumuhs, vmsumshm, vmsumshs
6513//zz if (dis_av_multarith( theInstr )) goto decode_success;
6514//zz goto decode_failure;
6515//zz
6516//zz /* AV Permutations */
6517//zz case 0x2A: // vsel
6518//zz case 0x2B: // vperm
6519//zz if (dis_av_permute( theInstr )) goto decode_success;
6520//zz goto decode_failure;
6521//zz
6522//zz /* AV Shift */
6523//zz case 0x2C: // vsldoi
6524//zz if (dis_av_shift( theInstr )) goto decode_success;
6525//zz goto decode_failure;
6526//zz
6527//zz /* AV Floating Point Mult-Add/Sub */
6528//zz case 0x2E: case 0x2F: // vmaddfp, vnmsubfp
6529//zz if (dis_av_fp_arith( theInstr )) goto decode_success;
6530//zz goto decode_failure;
6531//zz
6532//zz default:
6533//zz break; // Fall through...
6534//zz }
6535//zz
6536//zz opc2 = (theInstr) & 0x7FF; /* theInstr[0:10] */
6537//zz switch (opc2) {
6538//zz /* AV Arithmetic */
6539//zz case 0x180: // vaddcuw
6540//zz case 0x000: case 0x040: case 0x080: // vaddubm, vadduhm, vadduwm
6541//zz case 0x200: case 0x240: case 0x280: // vaddubs, vadduhs, vadduws
6542//zz case 0x300: case 0x340: case 0x380: // vaddsbs, vaddshs, vaddsws
6543//zz case 0x580: // vsubcuw
6544//zz case 0x400: case 0x440: case 0x480: // vsububm, vsubuhm, vsubuwm
6545//zz case 0x600: case 0x640: case 0x680: // vsububs, vsubuhs, vsubuws
6546//zz case 0x700: case 0x740: case 0x780: // vsubsbs, vsubshs, vsubsws
6547//zz case 0x402: case 0x442: case 0x482: // vavgub, vavguh, vavguw
6548//zz case 0x502: case 0x542: case 0x582: // vavgsb, vavgsh, vavgsw
6549//zz case 0x002: case 0x042: case 0x082: // vmaxub, vmaxuh, vmaxuw
6550//zz case 0x102: case 0x142: case 0x182: // vmaxsb, vmaxsh, vmaxsw
6551//zz case 0x202: case 0x242: case 0x282: // vminub, vminuh, vminuw
6552//zz case 0x302: case 0x342: case 0x382: // vminsb, vminsh, vminsw
6553//zz case 0x008: case 0x048: // vmuloub, vmulouh
6554//zz case 0x108: case 0x148: // vmulosb, vmulosh
6555//zz case 0x208: case 0x248: // vmuleub, vmuleuh
6556//zz case 0x308: case 0x348: // vmulesb, vmulesh
6557//zz case 0x608: case 0x708: case 0x648: // vsum4ubs, vsum4sbs, vsum4shs
6558//zz case 0x688: case 0x788: // vsum2sws, vsumsws
6559//zz if (dis_av_arith( theInstr )) goto decode_success;
6560//zz goto decode_failure;
6561//zz
6562//zz /* AV Rotate, Shift */
6563//zz case 0x004: case 0x044: case 0x084: // vrlb, vrlh, vrlw
6564//zz case 0x104: case 0x144: case 0x184: // vslb, vslh, vslw
6565//zz case 0x204: case 0x244: case 0x284: // vsrb, vsrh, vsrw
6566//zz case 0x304: case 0x344: case 0x384: // vsrab, vsrah, vsraw
6567//zz case 0x1C4: case 0x2C4: // vsl, vsr
6568//zz case 0x40C: case 0x44C: // vslo, vsro
6569//zz if (dis_av_shift( theInstr )) goto decode_success;
6570//zz goto decode_failure;
6571//zz
6572//zz /* AV Logic */
6573//zz case 0x404: case 0x444: case 0x484: // vand, vandc, vor
6574//zz case 0x4C4: case 0x504: // vxor, vnor
6575//zz if (dis_av_logic( theInstr )) goto decode_success;
6576//zz goto decode_failure;
6577//zz
6578//zz /* AV Processor Control */
6579//zz case 0x604: case 0x644: // mfvscr, mtvscr
6580//zz if (dis_av_procctl( theInstr )) goto decode_success;
6581//zz goto decode_failure;
6582//zz
6583//zz /* AV Floating Point Arithmetic */
6584//zz case 0x00A: case 0x04A: // vaddfp, vsubfp
6585//zz case 0x10A: case 0x14A: case 0x18A: // vrefp, vrsqrtefp, vexptefp
6586//zz case 0x1CA: // vlogefp
6587//zz case 0x40A: case 0x44A: // vmaxfp, vminfp
6588//zz if (dis_av_fp_arith( theInstr )) goto decode_success;
6589//zz goto decode_failure;
6590//zz
6591//zz /* AV Floating Point Round/Convert */
6592//zz case 0x20A: case 0x24A: case 0x28A: // vrfin, vrfiz, vrfip
6593//zz case 0x2CA: // vrfim
6594//zz case 0x30A: case 0x34A: case 0x38A: // vcfux, vcfsx, vctuxs
6595//zz case 0x3CA: // vctsxs
6596//zz if (dis_av_fp_convert( theInstr )) goto decode_success;
6597//zz goto decode_failure;
6598//zz
6599//zz /* AV Merge, Splat */
6600//zz case 0x00C: case 0x04C: case 0x08C: // vmrghb, vmrghh, vmrghw
6601//zz case 0x10C: case 0x14C: case 0x18C: // vmrglb, vmrglh, vmrglw
6602//zz case 0x20C: case 0x24C: case 0x28C: // vspltb, vsplth, vspltw
6603//zz case 0x30C: case 0x34C: case 0x38C: // vspltisb, vspltish, vspltisw
6604//zz if (dis_av_permute( theInstr )) goto decode_success;
6605//zz goto decode_failure;
6606//zz
6607//zz /* AV Pack, Unpack */
6608//zz case 0x00E: case 0x04E: case 0x08E: // vpkuhum, vpkuwum, vpkuhus
6609//zz case 0x0CE: // vpkuwus
6610//zz case 0x10E: case 0x14E: case 0x18E: // vpkshus, vpkswus, vpkshss
6611//zz case 0x1CE: // vpkswss
6612//zz case 0x20E: case 0x24E: case 0x28E: // vupkhsb, vupkhsh, vupklsb
6613//zz case 0x2CE: // vupklsh
6614//zz case 0x30E: case 0x34E: case 0x3CE: // vpkpx, vupkhpx, vupklpx
6615//zz if (dis_av_pack( theInstr )) goto decode_success;
6616//zz goto decode_failure;
6617//zz
6618//zz default:
6619//zz break; // Fall through...
6620//zz }
6621//zz
6622//zz opc2 = (theInstr) & 0x3FF; /* theInstr[0:9] (Bit 10 = Rc)*/
6623//zz switch (opc2) {
6624//zz
6625//zz /* AV Compare */
6626//zz case 0x006: case 0x046: case 0x086: // vcmpequb, vcmpequh, vcmpequw
6627//zz case 0x206: case 0x246: case 0x286: // vcmpgtub, vcmpgtuh, vcmpgtuw
6628//zz case 0x306: case 0x346: case 0x386: // vcmpgtsb, vcmpgtsh, vcmpgtsw
6629//zz if (dis_av_cmp( theInstr )) goto decode_success;
6630//zz goto decode_failure;
6631//zz
6632//zz /* AV Floating Point Compare */
6633//zz case 0x0C6: case 0x1C6: case 0x2C6: // vcmpeqfp, vcmpgefp, vcmpgtfp
6634//zz case 0x3C6: // vcmpbfp
6635//zz if (dis_av_fp_cmp( theInstr )) goto decode_success;
6636//zz goto decode_failure;
6637//zz
6638//zz default:
6639//zz goto decode_failure;
6640//zz }
6641//zz break;
cerion7aa4bbc2005-01-29 09:32:07 +00006642
cerion896a1372005-01-25 12:24:25 +00006643 default:
6644 decode_failure:
6645 /* All decode failures end up here. */
cerion1515db92005-01-25 17:21:23 +00006646 vex_printf("disInstr(ppc32): unhandled instruction: "
cerion896a1372005-01-25 12:24:25 +00006647 "0x%x\n", theInstr);
sewardjb51f0f42005-07-18 11:38:02 +00006648 vex_printf(" primary %d(0x%x), secondary %d(0x%x)\n",
6649 opc1, opc1, opc2, opc2);
cerionb85e8bb2005-02-16 08:54:33 +00006650
cerione9d361a2005-03-04 17:35:29 +00006651#if PPC32_TOIR_DEBUG
cerion995bc362005-02-03 11:03:31 +00006652 vex_printf("disInstr(ppc32): instr: ");
6653 vex_printf_binary( theInstr, 32, True );
6654 vex_printf("\n");
6655
6656 vex_printf("disInstr(ppc32): opcode1: ");
6657 vex_printf_binary( opc1, 6, False );
6658 vex_printf("\n");
6659
6660 vex_printf("disInstr(ppc32): opcode2: ");
6661 vex_printf_binary( opc2, 10, False );
cerion45552a92005-02-03 18:20:22 +00006662 vex_printf("\n\n");
6663#endif
cerion995bc362005-02-03 11:03:31 +00006664
6665
sewardj01a9e802005-02-01 20:46:00 +00006666 /* Tell the dispatcher that this insn cannot be decoded, and so has
6667 not been executed, and (is currently) the next to be executed.
6668 CIA should be up-to-date since it made so at the start of each
6669 insn, but nevertheless be paranoid and update it again right
6670 now. */
sewardjb51f0f42005-07-18 11:38:02 +00006671 putSPR( PPC32_SPR_CIA, mkU32(guest_CIA_curr_instr) );
sewardj9e6491a2005-07-02 19:24:10 +00006672 irbb->next = mkU32(guest_CIA_curr_instr);
sewardj01a9e802005-02-01 20:46:00 +00006673 irbb->jumpkind = Ijk_NoDecode;
sewardj9e6491a2005-07-02 19:24:10 +00006674 dres.whatNext = Dis_StopHere;
6675 dres.len = 0;
sewardjb51f0f42005-07-18 11:38:02 +00006676vassert(0);
sewardj9e6491a2005-07-02 19:24:10 +00006677 return dres;
cerion896a1372005-01-25 12:24:25 +00006678
6679 } /* switch (opc) for the main (primary) opcode switch. */
6680
6681 decode_success:
6682 /* All decode successes end up here. */
cerion896a1372005-01-25 12:24:25 +00006683 DIP("\n");
6684
sewardj9e6491a2005-07-02 19:24:10 +00006685 dres.len = 4;
6686 return dres;
cerion896a1372005-01-25 12:24:25 +00006687}
6688
6689#undef DIP
6690#undef DIS
6691
sewardj9e6491a2005-07-02 19:24:10 +00006692
6693/*------------------------------------------------------------*/
6694/*--- Top-level fn ---*/
6695/*------------------------------------------------------------*/
6696
6697/* Disassemble a single instruction into IR. The instruction
6698 is located in host memory at &guest_code[delta]. */
6699
6700DisResult disInstr_PPC32 ( IRBB* irbb_IN,
6701 Bool put_IP,
6702 Bool (*resteerOkFn) ( Addr64 ),
6703 UChar* guest_code_IN,
6704 Long delta,
6705 Addr64 guest_IP,
6706 VexArchInfo* archinfo,
6707 Bool host_bigendian_IN )
6708{
6709 DisResult dres;
6710
6711 /* Set globals (see top of this file) */
6712 guest_code = guest_code_IN;
6713 irbb = irbb_IN;
6714 host_is_bigendian = host_bigendian_IN;
6715 guest_CIA_curr_instr = (Addr32)guest_IP;
6716 guest_CIA_bbstart = (Addr32)toUInt(guest_IP - delta);
6717
6718 dres = disInstr_PPC32_WRK ( put_IP, resteerOkFn,
6719 delta, archinfo );
6720
6721 return dres;
6722}
6723
6724
cerion896a1372005-01-25 12:24:25 +00006725/*--------------------------------------------------------------------*/
cerion1515db92005-01-25 17:21:23 +00006726/*--- end guest-ppc32/toIR.c ---*/
cerion896a1372005-01-25 12:24:25 +00006727/*--------------------------------------------------------------------*/