]> git.proxmox.com Git - mirror_qemu.git/blame - target-ppc/translate.c
find -type f | xargs sed -i 's/[\t ]*$//g' # Yes, again. Note the star in the regex.
[mirror_qemu.git] / target-ppc / translate.c
CommitLineData
79aceca5 1/*
3fc6c082 2 * PowerPC emulation for qemu: main translation routines.
5fafdf24 3 *
76a66253 4 * Copyright (c) 2003-2007 Jocelyn Mayer
79aceca5
FB
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
c6a1c22b
FB
20#include <stdarg.h>
21#include <stdlib.h>
22#include <stdio.h>
23#include <string.h>
24#include <inttypes.h>
25
79aceca5 26#include "cpu.h"
c6a1c22b 27#include "exec-all.h"
79aceca5
FB
28#include "disas.h"
29
30//#define DO_SINGLE_STEP
9fddaa0c 31//#define PPC_DEBUG_DISAS
a496775f 32//#define DEBUG_MEMORY_ACCESSES
76a66253 33//#define DO_PPC_STATISTICS
79aceca5 34
d9bce9d9 35#if defined(USE_DIRECT_JUMP)
c53be334
FB
36#define TBPARAM(x)
37#else
38#define TBPARAM(x) (long)(x)
39#endif
40
79aceca5
FB
41enum {
42#define DEF(s, n, copy_size) INDEX_op_ ## s,
43#include "opc.h"
44#undef DEF
45 NB_OPS,
46};
47
48static uint16_t *gen_opc_ptr;
49static uint32_t *gen_opparam_ptr;
50
51#include "gen-op.h"
28b6751f 52
d9bce9d9
JM
53static inline void gen_set_T0 (target_ulong val)
54{
55#if defined(TARGET_PPC64)
56 if (val >> 32)
57 gen_op_set_T0_64(val >> 32, val);
58 else
59#endif
60 gen_op_set_T0(val);
61}
62
63static inline void gen_set_T1 (target_ulong val)
64{
65#if defined(TARGET_PPC64)
66 if (val >> 32)
67 gen_op_set_T1_64(val >> 32, val);
68 else
69#endif
70 gen_op_set_T1(val);
71}
72
73#define GEN8(func, NAME) \
9a64fbe4
FB
74static GenOpFunc *NAME ## _table [8] = { \
75NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \
76NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \
77}; \
78static inline void func(int n) \
79{ \
80 NAME ## _table[n](); \
81}
82
83#define GEN16(func, NAME) \
84static GenOpFunc *NAME ## _table [16] = { \
85NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \
86NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \
87NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \
88NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \
89}; \
90static inline void func(int n) \
91{ \
92 NAME ## _table[n](); \
28b6751f
FB
93}
94
d9bce9d9 95#define GEN32(func, NAME) \
9a64fbe4
FB
96static GenOpFunc *NAME ## _table [32] = { \
97NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \
98NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \
99NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \
100NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \
101NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \
102NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \
103NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \
104NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \
105}; \
106static inline void func(int n) \
107{ \
108 NAME ## _table[n](); \
109}
110
111/* Condition register moves */
112GEN8(gen_op_load_crf_T0, gen_op_load_crf_T0_crf);
113GEN8(gen_op_load_crf_T1, gen_op_load_crf_T1_crf);
114GEN8(gen_op_store_T0_crf, gen_op_store_T0_crf_crf);
115GEN8(gen_op_store_T1_crf, gen_op_store_T1_crf_crf);
28b6751f 116
fb0eaffc
FB
117/* Floating point condition and status register moves */
118GEN8(gen_op_load_fpscr_T0, gen_op_load_fpscr_T0_fpscr);
119GEN8(gen_op_store_T0_fpscr, gen_op_store_T0_fpscr_fpscr);
120GEN8(gen_op_clear_fpscr, gen_op_clear_fpscr_fpscr);
fb0eaffc
FB
121static inline void gen_op_store_T0_fpscri(int n, uint8_t param)
122{
76a66253
JM
123 gen_op_set_T0(param);
124 gen_op_store_T0_fpscr(n);
fb0eaffc
FB
125}
126
9a64fbe4
FB
127/* General purpose registers moves */
128GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr);
129GEN32(gen_op_load_gpr_T1, gen_op_load_gpr_T1_gpr);
130GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr);
131
132GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr);
133GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr);
76a66253 134#if 0 // unused
9a64fbe4 135GEN32(gen_op_store_T2_gpr, gen_op_store_T2_gpr_gpr);
76a66253 136#endif
28b6751f 137
fb0eaffc
FB
138/* floating point registers moves */
139GEN32(gen_op_load_fpr_FT0, gen_op_load_fpr_FT0_fpr);
140GEN32(gen_op_load_fpr_FT1, gen_op_load_fpr_FT1_fpr);
141GEN32(gen_op_load_fpr_FT2, gen_op_load_fpr_FT2_fpr);
142GEN32(gen_op_store_FT0_fpr, gen_op_store_FT0_fpr_fpr);
143GEN32(gen_op_store_FT1_fpr, gen_op_store_FT1_fpr_fpr);
76a66253 144#if 0 // unused
fb0eaffc 145GEN32(gen_op_store_FT2_fpr, gen_op_store_FT2_fpr_fpr);
76a66253 146#endif
79aceca5
FB
147
148/* internal defines */
149typedef struct DisasContext {
150 struct TranslationBlock *tb;
0fa85d43 151 target_ulong nip;
79aceca5 152 uint32_t opcode;
9a64fbe4 153 uint32_t exception;
3cc62370
FB
154 /* Routine used to access memory */
155 int mem_idx;
156 /* Translation flags */
9a64fbe4 157#if !defined(CONFIG_USER_ONLY)
79aceca5 158 int supervisor;
d9bce9d9
JM
159#endif
160#if defined(TARGET_PPC64)
161 int sf_mode;
9a64fbe4 162#endif
3cc62370 163 int fpu_enabled;
35cdaad6 164#if defined(TARGET_PPCEMB)
0487d6a8
JM
165 int spe_enabled;
166#endif
3fc6c082 167 ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */
ea4e754f 168 int singlestep_enabled;
79aceca5
FB
169} DisasContext;
170
3fc6c082 171struct opc_handler_t {
79aceca5
FB
172 /* invalid bits */
173 uint32_t inval;
9a64fbe4 174 /* instruction type */
0487d6a8 175 uint64_t type;
79aceca5
FB
176 /* handler */
177 void (*handler)(DisasContext *ctx);
76a66253
JM
178#if defined(DO_PPC_STATISTICS)
179 const unsigned char *oname;
180 uint64_t count;
181#endif
3fc6c082 182};
79aceca5 183
76a66253
JM
184static inline void gen_set_Rc0 (DisasContext *ctx)
185{
d9bce9d9
JM
186#if defined(TARGET_PPC64)
187 if (ctx->sf_mode)
188 gen_op_cmpi_64(0);
189 else
190#endif
191 gen_op_cmpi(0);
76a66253
JM
192 gen_op_set_Rc0();
193}
194
d9bce9d9
JM
195static inline void gen_update_nip (DisasContext *ctx, target_ulong nip)
196{
197#if defined(TARGET_PPC64)
198 if (ctx->sf_mode)
199 gen_op_update_nip_64(nip >> 32, nip);
200 else
201#endif
202 gen_op_update_nip(nip);
203}
204
9fddaa0c 205#define RET_EXCP(ctx, excp, error) \
79aceca5 206do { \
9fddaa0c 207 if ((ctx)->exception == EXCP_NONE) { \
d9bce9d9 208 gen_update_nip(ctx, (ctx)->nip); \
9fddaa0c
FB
209 } \
210 gen_op_raise_exception_err((excp), (error)); \
211 ctx->exception = (excp); \
79aceca5
FB
212} while (0)
213
9fddaa0c
FB
214#define RET_INVAL(ctx) \
215RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL)
216
217#define RET_PRIVOPC(ctx) \
218RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_OPC)
9a64fbe4 219
9fddaa0c
FB
220#define RET_PRIVREG(ctx) \
221RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG)
9a64fbe4 222
f24e5695 223/* Stop translation */
3fc6c082
FB
224static inline void RET_STOP (DisasContext *ctx)
225{
d9bce9d9 226 gen_update_nip(ctx, ctx->nip);
f24e5695 227 ctx->exception = EXCP_MTMSR;
3fc6c082
FB
228}
229
f24e5695 230/* No need to update nip here, as execution flow will change */
2be0071f
FB
231static inline void RET_CHG_FLOW (DisasContext *ctx)
232{
2be0071f
FB
233 ctx->exception = EXCP_MTMSR;
234}
235
79aceca5
FB
236#define GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \
237static void gen_##name (DisasContext *ctx); \
238GEN_OPCODE(name, opc1, opc2, opc3, inval, type); \
239static void gen_##name (DisasContext *ctx)
240
79aceca5
FB
241typedef struct opcode_t {
242 unsigned char opc1, opc2, opc3;
18fba28c
FB
243#if HOST_LONG_BITS == 64 /* Explicitely align to 64 bits */
244 unsigned char pad[5];
245#else
246 unsigned char pad[1];
247#endif
79aceca5 248 opc_handler_t handler;
3fc6c082 249 const unsigned char *oname;
79aceca5
FB
250} opcode_t;
251
79aceca5
FB
252/*** Instruction decoding ***/
253#define EXTRACT_HELPER(name, shift, nb) \
d9bce9d9 254static inline uint32_t name (uint32_t opcode) \
79aceca5
FB
255{ \
256 return (opcode >> (shift)) & ((1 << (nb)) - 1); \
257}
258
259#define EXTRACT_SHELPER(name, shift, nb) \
d9bce9d9 260static inline int32_t name (uint32_t opcode) \
79aceca5 261{ \
18fba28c 262 return (int16_t)((opcode >> (shift)) & ((1 << (nb)) - 1)); \
79aceca5
FB
263}
264
265/* Opcode part 1 */
266EXTRACT_HELPER(opc1, 26, 6);
267/* Opcode part 2 */
268EXTRACT_HELPER(opc2, 1, 5);
269/* Opcode part 3 */
270EXTRACT_HELPER(opc3, 6, 5);
271/* Update Cr0 flags */
272EXTRACT_HELPER(Rc, 0, 1);
273/* Destination */
274EXTRACT_HELPER(rD, 21, 5);
275/* Source */
276EXTRACT_HELPER(rS, 21, 5);
277/* First operand */
278EXTRACT_HELPER(rA, 16, 5);
279/* Second operand */
280EXTRACT_HELPER(rB, 11, 5);
281/* Third operand */
282EXTRACT_HELPER(rC, 6, 5);
283/*** Get CRn ***/
284EXTRACT_HELPER(crfD, 23, 3);
285EXTRACT_HELPER(crfS, 18, 3);
286EXTRACT_HELPER(crbD, 21, 5);
287EXTRACT_HELPER(crbA, 16, 5);
288EXTRACT_HELPER(crbB, 11, 5);
289/* SPR / TBL */
3fc6c082
FB
290EXTRACT_HELPER(_SPR, 11, 10);
291static inline uint32_t SPR (uint32_t opcode)
292{
293 uint32_t sprn = _SPR(opcode);
294
295 return ((sprn >> 5) & 0x1F) | ((sprn & 0x1F) << 5);
296}
79aceca5
FB
297/*** Get constants ***/
298EXTRACT_HELPER(IMM, 12, 8);
299/* 16 bits signed immediate value */
300EXTRACT_SHELPER(SIMM, 0, 16);
301/* 16 bits unsigned immediate value */
302EXTRACT_HELPER(UIMM, 0, 16);
303/* Bit count */
304EXTRACT_HELPER(NB, 11, 5);
305/* Shift count */
306EXTRACT_HELPER(SH, 11, 5);
307/* Mask start */
308EXTRACT_HELPER(MB, 6, 5);
309/* Mask end */
310EXTRACT_HELPER(ME, 1, 5);
fb0eaffc
FB
311/* Trap operand */
312EXTRACT_HELPER(TO, 21, 5);
79aceca5
FB
313
314EXTRACT_HELPER(CRM, 12, 8);
315EXTRACT_HELPER(FM, 17, 8);
316EXTRACT_HELPER(SR, 16, 4);
fb0eaffc
FB
317EXTRACT_HELPER(FPIMM, 20, 4);
318
79aceca5
FB
319/*** Jump target decoding ***/
320/* Displacement */
321EXTRACT_SHELPER(d, 0, 16);
322/* Immediate address */
76a66253 323static inline target_ulong LI (uint32_t opcode)
79aceca5
FB
324{
325 return (opcode >> 0) & 0x03FFFFFC;
326}
327
328static inline uint32_t BD (uint32_t opcode)
329{
330 return (opcode >> 0) & 0xFFFC;
331}
332
333EXTRACT_HELPER(BO, 21, 5);
334EXTRACT_HELPER(BI, 16, 5);
335/* Absolute/relative address */
336EXTRACT_HELPER(AA, 1, 1);
337/* Link */
338EXTRACT_HELPER(LK, 0, 1);
339
340/* Create a mask between <start> and <end> bits */
76a66253 341static inline target_ulong MASK (uint32_t start, uint32_t end)
79aceca5 342{
76a66253 343 target_ulong ret;
79aceca5 344
76a66253
JM
345#if defined(TARGET_PPC64)
346 if (likely(start == 0)) {
347 ret = (uint64_t)(-1ULL) << (63 - end);
348 } else if (likely(end == 63)) {
349 ret = (uint64_t)(-1ULL) >> start;
350 }
351#else
352 if (likely(start == 0)) {
353 ret = (uint32_t)(-1ULL) << (31 - end);
354 } else if (likely(end == 31)) {
355 ret = (uint32_t)(-1ULL) >> start;
356 }
357#endif
358 else {
359 ret = (((target_ulong)(-1ULL)) >> (start)) ^
360 (((target_ulong)(-1ULL) >> (end)) >> 1);
361 if (unlikely(start > end))
362 return ~ret;
363 }
79aceca5
FB
364
365 return ret;
366}
367
3fc6c082
FB
368#if HOST_LONG_BITS == 64
369#define OPC_ALIGN 8
370#else
371#define OPC_ALIGN 4
372#endif
1b039c09 373#if defined(__APPLE__)
d9bce9d9 374#define OPCODES_SECTION \
3fc6c082 375 __attribute__ ((section("__TEXT,__opcodes"), unused, aligned (OPC_ALIGN) ))
933dc6eb 376#else
d9bce9d9 377#define OPCODES_SECTION \
3fc6c082 378 __attribute__ ((section(".opcodes"), unused, aligned (OPC_ALIGN) ))
933dc6eb
FB
379#endif
380
76a66253 381#if defined(DO_PPC_STATISTICS)
79aceca5 382#define GEN_OPCODE(name, op1, op2, op3, invl, _typ) \
18fba28c 383OPCODES_SECTION opcode_t opc_##name = { \
79aceca5
FB
384 .opc1 = op1, \
385 .opc2 = op2, \
386 .opc3 = op3, \
18fba28c 387 .pad = { 0, }, \
79aceca5
FB
388 .handler = { \
389 .inval = invl, \
9a64fbe4 390 .type = _typ, \
79aceca5 391 .handler = &gen_##name, \
76a66253 392 .oname = stringify(name), \
79aceca5 393 }, \
3fc6c082 394 .oname = stringify(name), \
79aceca5 395}
76a66253
JM
396#else
397#define GEN_OPCODE(name, op1, op2, op3, invl, _typ) \
398OPCODES_SECTION opcode_t opc_##name = { \
399 .opc1 = op1, \
400 .opc2 = op2, \
401 .opc3 = op3, \
402 .pad = { 0, }, \
403 .handler = { \
404 .inval = invl, \
405 .type = _typ, \
406 .handler = &gen_##name, \
407 }, \
408 .oname = stringify(name), \
409}
410#endif
79aceca5
FB
411
412#define GEN_OPCODE_MARK(name) \
18fba28c 413OPCODES_SECTION opcode_t opc_##name = { \
79aceca5
FB
414 .opc1 = 0xFF, \
415 .opc2 = 0xFF, \
416 .opc3 = 0xFF, \
18fba28c 417 .pad = { 0, }, \
79aceca5
FB
418 .handler = { \
419 .inval = 0x00000000, \
9a64fbe4 420 .type = 0x00, \
79aceca5
FB
421 .handler = NULL, \
422 }, \
3fc6c082 423 .oname = stringify(name), \
79aceca5
FB
424}
425
426/* Start opcode list */
427GEN_OPCODE_MARK(start);
428
429/* Invalid instruction */
9a64fbe4
FB
430GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE)
431{
9fddaa0c 432 RET_INVAL(ctx);
9a64fbe4
FB
433}
434
79aceca5
FB
435static opc_handler_t invalid_handler = {
436 .inval = 0xFFFFFFFF,
9a64fbe4 437 .type = PPC_NONE,
79aceca5
FB
438 .handler = gen_invalid,
439};
440
441/*** Integer arithmetic ***/
d9bce9d9
JM
442#define __GEN_INT_ARITH2(name, opc1, opc2, opc3, inval, type) \
443GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \
79aceca5
FB
444{ \
445 gen_op_load_gpr_T0(rA(ctx->opcode)); \
446 gen_op_load_gpr_T1(rB(ctx->opcode)); \
447 gen_op_##name(); \
79aceca5 448 gen_op_store_T0_gpr(rD(ctx->opcode)); \
76a66253
JM
449 if (unlikely(Rc(ctx->opcode) != 0)) \
450 gen_set_Rc0(ctx); \
79aceca5
FB
451}
452
d9bce9d9
JM
453#define __GEN_INT_ARITH2_O(name, opc1, opc2, opc3, inval, type) \
454GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \
79aceca5
FB
455{ \
456 gen_op_load_gpr_T0(rA(ctx->opcode)); \
457 gen_op_load_gpr_T1(rB(ctx->opcode)); \
458 gen_op_##name(); \
79aceca5 459 gen_op_store_T0_gpr(rD(ctx->opcode)); \
76a66253
JM
460 if (unlikely(Rc(ctx->opcode) != 0)) \
461 gen_set_Rc0(ctx); \
79aceca5
FB
462}
463
d9bce9d9
JM
464#define __GEN_INT_ARITH1(name, opc1, opc2, opc3, type) \
465GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, type) \
79aceca5
FB
466{ \
467 gen_op_load_gpr_T0(rA(ctx->opcode)); \
468 gen_op_##name(); \
79aceca5 469 gen_op_store_T0_gpr(rD(ctx->opcode)); \
76a66253
JM
470 if (unlikely(Rc(ctx->opcode) != 0)) \
471 gen_set_Rc0(ctx); \
79aceca5 472}
d9bce9d9
JM
473#define __GEN_INT_ARITH1_O(name, opc1, opc2, opc3, type) \
474GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, type) \
79aceca5
FB
475{ \
476 gen_op_load_gpr_T0(rA(ctx->opcode)); \
477 gen_op_##name(); \
79aceca5 478 gen_op_store_T0_gpr(rD(ctx->opcode)); \
76a66253
JM
479 if (unlikely(Rc(ctx->opcode) != 0)) \
480 gen_set_Rc0(ctx); \
79aceca5
FB
481}
482
483/* Two operands arithmetic functions */
d9bce9d9
JM
484#define GEN_INT_ARITH2(name, opc1, opc2, opc3, type) \
485__GEN_INT_ARITH2(name, opc1, opc2, opc3, 0x00000000, type) \
486__GEN_INT_ARITH2_O(name##o, opc1, opc2, opc3 | 0x10, 0x00000000, type)
487
488/* Two operands arithmetic functions with no overflow allowed */
489#define GEN_INT_ARITHN(name, opc1, opc2, opc3, type) \
490__GEN_INT_ARITH2(name, opc1, opc2, opc3, 0x00000400, type)
491
492/* One operand arithmetic functions */
493#define GEN_INT_ARITH1(name, opc1, opc2, opc3, type) \
494__GEN_INT_ARITH1(name, opc1, opc2, opc3, type) \
495__GEN_INT_ARITH1_O(name##o, opc1, opc2, opc3 | 0x10, type)
496
497#if defined(TARGET_PPC64)
498#define __GEN_INT_ARITH2_64(name, opc1, opc2, opc3, inval, type) \
499GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \
500{ \
501 gen_op_load_gpr_T0(rA(ctx->opcode)); \
502 gen_op_load_gpr_T1(rB(ctx->opcode)); \
503 if (ctx->sf_mode) \
504 gen_op_##name##_64(); \
505 else \
506 gen_op_##name(); \
507 gen_op_store_T0_gpr(rD(ctx->opcode)); \
508 if (unlikely(Rc(ctx->opcode) != 0)) \
509 gen_set_Rc0(ctx); \
510}
511
512#define __GEN_INT_ARITH2_O_64(name, opc1, opc2, opc3, inval, type) \
513GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \
514{ \
515 gen_op_load_gpr_T0(rA(ctx->opcode)); \
516 gen_op_load_gpr_T1(rB(ctx->opcode)); \
517 if (ctx->sf_mode) \
518 gen_op_##name##_64(); \
519 else \
520 gen_op_##name(); \
521 gen_op_store_T0_gpr(rD(ctx->opcode)); \
522 if (unlikely(Rc(ctx->opcode) != 0)) \
523 gen_set_Rc0(ctx); \
524}
525
526#define __GEN_INT_ARITH1_64(name, opc1, opc2, opc3, type) \
527GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, type) \
528{ \
529 gen_op_load_gpr_T0(rA(ctx->opcode)); \
530 if (ctx->sf_mode) \
531 gen_op_##name##_64(); \
532 else \
533 gen_op_##name(); \
534 gen_op_store_T0_gpr(rD(ctx->opcode)); \
535 if (unlikely(Rc(ctx->opcode) != 0)) \
536 gen_set_Rc0(ctx); \
537}
538#define __GEN_INT_ARITH1_O_64(name, opc1, opc2, opc3, type) \
539GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, type) \
540{ \
541 gen_op_load_gpr_T0(rA(ctx->opcode)); \
542 if (ctx->sf_mode) \
543 gen_op_##name##_64(); \
544 else \
545 gen_op_##name(); \
546 gen_op_store_T0_gpr(rD(ctx->opcode)); \
547 if (unlikely(Rc(ctx->opcode) != 0)) \
548 gen_set_Rc0(ctx); \
549}
550
551/* Two operands arithmetic functions */
552#define GEN_INT_ARITH2_64(name, opc1, opc2, opc3, type) \
553__GEN_INT_ARITH2_64(name, opc1, opc2, opc3, 0x00000000, type) \
554__GEN_INT_ARITH2_O_64(name##o, opc1, opc2, opc3 | 0x10, 0x00000000, type)
79aceca5
FB
555
556/* Two operands arithmetic functions with no overflow allowed */
d9bce9d9
JM
557#define GEN_INT_ARITHN_64(name, opc1, opc2, opc3, type) \
558__GEN_INT_ARITH2_64(name, opc1, opc2, opc3, 0x00000400, type)
79aceca5
FB
559
560/* One operand arithmetic functions */
d9bce9d9
JM
561#define GEN_INT_ARITH1_64(name, opc1, opc2, opc3, type) \
562__GEN_INT_ARITH1_64(name, opc1, opc2, opc3, type) \
563__GEN_INT_ARITH1_O_64(name##o, opc1, opc2, opc3 | 0x10, type)
564#else
565#define GEN_INT_ARITH2_64 GEN_INT_ARITH2
566#define GEN_INT_ARITHN_64 GEN_INT_ARITHN
567#define GEN_INT_ARITH1_64 GEN_INT_ARITH1
568#endif
79aceca5
FB
569
570/* add add. addo addo. */
d9bce9d9
JM
571static inline void gen_op_addo (void)
572{
573 gen_op_move_T2_T0();
574 gen_op_add();
575 gen_op_check_addo();
576}
577#if defined(TARGET_PPC64)
578#define gen_op_add_64 gen_op_add
579static inline void gen_op_addo_64 (void)
580{
581 gen_op_move_T2_T0();
582 gen_op_add();
583 gen_op_check_addo_64();
584}
585#endif
586GEN_INT_ARITH2_64 (add, 0x1F, 0x0A, 0x08, PPC_INTEGER);
79aceca5 587/* addc addc. addco addco. */
d9bce9d9
JM
588static inline void gen_op_addc (void)
589{
590 gen_op_move_T2_T0();
591 gen_op_add();
592 gen_op_check_addc();
593}
594static inline void gen_op_addco (void)
595{
596 gen_op_move_T2_T0();
597 gen_op_add();
598 gen_op_check_addc();
599 gen_op_check_addo();
600}
601#if defined(TARGET_PPC64)
602static inline void gen_op_addc_64 (void)
603{
604 gen_op_move_T2_T0();
605 gen_op_add();
606 gen_op_check_addc_64();
607}
608static inline void gen_op_addco_64 (void)
609{
610 gen_op_move_T2_T0();
611 gen_op_add();
612 gen_op_check_addc_64();
613 gen_op_check_addo_64();
614}
615#endif
616GEN_INT_ARITH2_64 (addc, 0x1F, 0x0A, 0x00, PPC_INTEGER);
79aceca5 617/* adde adde. addeo addeo. */
d9bce9d9
JM
618static inline void gen_op_addeo (void)
619{
620 gen_op_move_T2_T0();
621 gen_op_adde();
622 gen_op_check_addo();
623}
624#if defined(TARGET_PPC64)
625static inline void gen_op_addeo_64 (void)
626{
627 gen_op_move_T2_T0();
628 gen_op_adde_64();
629 gen_op_check_addo_64();
630}
631#endif
632GEN_INT_ARITH2_64 (adde, 0x1F, 0x0A, 0x04, PPC_INTEGER);
79aceca5 633/* addme addme. addmeo addmeo. */
d9bce9d9
JM
634static inline void gen_op_addme (void)
635{
636 gen_op_move_T1_T0();
637 gen_op_add_me();
638}
639#if defined(TARGET_PPC64)
640static inline void gen_op_addme_64 (void)
641{
642 gen_op_move_T1_T0();
643 gen_op_add_me_64();
644}
645#endif
646GEN_INT_ARITH1_64 (addme, 0x1F, 0x0A, 0x07, PPC_INTEGER);
79aceca5 647/* addze addze. addzeo addzeo. */
d9bce9d9
JM
648static inline void gen_op_addze (void)
649{
650 gen_op_move_T2_T0();
651 gen_op_add_ze();
652 gen_op_check_addc();
653}
654static inline void gen_op_addzeo (void)
655{
656 gen_op_move_T2_T0();
657 gen_op_add_ze();
658 gen_op_check_addc();
659 gen_op_check_addo();
660}
661#if defined(TARGET_PPC64)
662static inline void gen_op_addze_64 (void)
663{
664 gen_op_move_T2_T0();
665 gen_op_add_ze();
666 gen_op_check_addc_64();
667}
668static inline void gen_op_addzeo_64 (void)
669{
670 gen_op_move_T2_T0();
671 gen_op_add_ze();
672 gen_op_check_addc_64();
673 gen_op_check_addo_64();
674}
675#endif
676GEN_INT_ARITH1_64 (addze, 0x1F, 0x0A, 0x06, PPC_INTEGER);
79aceca5 677/* divw divw. divwo divwo. */
d9bce9d9 678GEN_INT_ARITH2 (divw, 0x1F, 0x0B, 0x0F, PPC_INTEGER);
79aceca5 679/* divwu divwu. divwuo divwuo. */
d9bce9d9 680GEN_INT_ARITH2 (divwu, 0x1F, 0x0B, 0x0E, PPC_INTEGER);
79aceca5 681/* mulhw mulhw. */
d9bce9d9 682GEN_INT_ARITHN (mulhw, 0x1F, 0x0B, 0x02, PPC_INTEGER);
79aceca5 683/* mulhwu mulhwu. */
d9bce9d9 684GEN_INT_ARITHN (mulhwu, 0x1F, 0x0B, 0x00, PPC_INTEGER);
79aceca5 685/* mullw mullw. mullwo mullwo. */
d9bce9d9 686GEN_INT_ARITH2 (mullw, 0x1F, 0x0B, 0x07, PPC_INTEGER);
79aceca5 687/* neg neg. nego nego. */
d9bce9d9 688GEN_INT_ARITH1_64 (neg, 0x1F, 0x08, 0x03, PPC_INTEGER);
79aceca5 689/* subf subf. subfo subfo. */
d9bce9d9
JM
690static inline void gen_op_subfo (void)
691{
692 gen_op_move_T2_T0();
693 gen_op_subf();
694 gen_op_check_subfo();
695}
696#if defined(TARGET_PPC64)
697#define gen_op_subf_64 gen_op_subf
698static inline void gen_op_subfo_64 (void)
699{
700 gen_op_move_T2_T0();
701 gen_op_subf();
702 gen_op_check_subfo_64();
703}
704#endif
705GEN_INT_ARITH2_64 (subf, 0x1F, 0x08, 0x01, PPC_INTEGER);
79aceca5 706/* subfc subfc. subfco subfco. */
d9bce9d9
JM
707static inline void gen_op_subfc (void)
708{
709 gen_op_subf();
710 gen_op_check_subfc();
711}
712static inline void gen_op_subfco (void)
713{
714 gen_op_move_T2_T0();
715 gen_op_subf();
716 gen_op_check_subfc();
717 gen_op_check_subfo();
718}
719#if defined(TARGET_PPC64)
720static inline void gen_op_subfc_64 (void)
721{
722 gen_op_subf();
723 gen_op_check_subfc_64();
724}
725static inline void gen_op_subfco_64 (void)
726{
727 gen_op_move_T2_T0();
728 gen_op_subf();
729 gen_op_check_subfc_64();
730 gen_op_check_subfo_64();
731}
732#endif
733GEN_INT_ARITH2_64 (subfc, 0x1F, 0x08, 0x00, PPC_INTEGER);
79aceca5 734/* subfe subfe. subfeo subfeo. */
d9bce9d9
JM
735static inline void gen_op_subfeo (void)
736{
737 gen_op_move_T2_T0();
738 gen_op_subfe();
739 gen_op_check_subfo();
740}
741#if defined(TARGET_PPC64)
742#define gen_op_subfe_64 gen_op_subfe
743static inline void gen_op_subfeo_64 (void)
744{
745 gen_op_move_T2_T0();
746 gen_op_subfe_64();
747 gen_op_check_subfo_64();
748}
749#endif
750GEN_INT_ARITH2_64 (subfe, 0x1F, 0x08, 0x04, PPC_INTEGER);
79aceca5 751/* subfme subfme. subfmeo subfmeo. */
d9bce9d9 752GEN_INT_ARITH1_64 (subfme, 0x1F, 0x08, 0x07, PPC_INTEGER);
79aceca5 753/* subfze subfze. subfzeo subfzeo. */
d9bce9d9 754GEN_INT_ARITH1_64 (subfze, 0x1F, 0x08, 0x06, PPC_INTEGER);
79aceca5
FB
755/* addi */
756GEN_HANDLER(addi, 0x0E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
757{
76a66253 758 target_long simm = SIMM(ctx->opcode);
79aceca5
FB
759
760 if (rA(ctx->opcode) == 0) {
76a66253 761 /* li case */
d9bce9d9 762 gen_set_T0(simm);
79aceca5
FB
763 } else {
764 gen_op_load_gpr_T0(rA(ctx->opcode));
76a66253
JM
765 if (likely(simm != 0))
766 gen_op_addi(simm);
79aceca5
FB
767 }
768 gen_op_store_T0_gpr(rD(ctx->opcode));
79aceca5
FB
769}
770/* addic */
771GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
772{
76a66253
JM
773 target_long simm = SIMM(ctx->opcode);
774
79aceca5 775 gen_op_load_gpr_T0(rA(ctx->opcode));
d9bce9d9
JM
776 if (likely(simm != 0)) {
777 gen_op_move_T2_T0();
778 gen_op_addi(simm);
779#if defined(TARGET_PPC64)
780 if (ctx->sf_mode)
781 gen_op_check_addc_64();
782 else
783#endif
784 gen_op_check_addc();
e864cabd
JM
785 } else {
786 gen_op_clear_xer_ca();
d9bce9d9 787 }
79aceca5 788 gen_op_store_T0_gpr(rD(ctx->opcode));
79aceca5
FB
789}
790/* addic. */
791GEN_HANDLER(addic_, 0x0D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
792{
76a66253
JM
793 target_long simm = SIMM(ctx->opcode);
794
79aceca5 795 gen_op_load_gpr_T0(rA(ctx->opcode));
d9bce9d9
JM
796 if (likely(simm != 0)) {
797 gen_op_move_T2_T0();
798 gen_op_addi(simm);
799#if defined(TARGET_PPC64)
800 if (ctx->sf_mode)
801 gen_op_check_addc_64();
802 else
803#endif
804 gen_op_check_addc();
805 }
79aceca5 806 gen_op_store_T0_gpr(rD(ctx->opcode));
76a66253 807 gen_set_Rc0(ctx);
79aceca5
FB
808}
809/* addis */
810GEN_HANDLER(addis, 0x0F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
811{
76a66253 812 target_long simm = SIMM(ctx->opcode);
79aceca5
FB
813
814 if (rA(ctx->opcode) == 0) {
76a66253 815 /* lis case */
d9bce9d9 816 gen_set_T0(simm << 16);
79aceca5
FB
817 } else {
818 gen_op_load_gpr_T0(rA(ctx->opcode));
76a66253
JM
819 if (likely(simm != 0))
820 gen_op_addi(simm << 16);
79aceca5
FB
821 }
822 gen_op_store_T0_gpr(rD(ctx->opcode));
79aceca5
FB
823}
824/* mulli */
825GEN_HANDLER(mulli, 0x07, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
826{
827 gen_op_load_gpr_T0(rA(ctx->opcode));
828 gen_op_mulli(SIMM(ctx->opcode));
829 gen_op_store_T0_gpr(rD(ctx->opcode));
79aceca5
FB
830}
831/* subfic */
832GEN_HANDLER(subfic, 0x08, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
833{
834 gen_op_load_gpr_T0(rA(ctx->opcode));
d9bce9d9
JM
835#if defined(TARGET_PPC64)
836 if (ctx->sf_mode)
837 gen_op_subfic_64(SIMM(ctx->opcode));
838 else
839#endif
840 gen_op_subfic(SIMM(ctx->opcode));
79aceca5 841 gen_op_store_T0_gpr(rD(ctx->opcode));
79aceca5
FB
842}
843
d9bce9d9
JM
844#if defined(TARGET_PPC64)
845/* mulhd mulhd. */
846GEN_INT_ARITHN (mulhd, 0x1F, 0x09, 0x02, PPC_INTEGER);
847/* mulhdu mulhdu. */
848GEN_INT_ARITHN (mulhdu, 0x1F, 0x09, 0x00, PPC_INTEGER);
849/* mulld mulld. mulldo mulldo. */
850GEN_INT_ARITH2 (mulld, 0x1F, 0x09, 0x07, PPC_INTEGER);
851/* divd divd. divdo divdo. */
852GEN_INT_ARITH2 (divd, 0x1F, 0x09, 0x0F, PPC_INTEGER);
853/* divdu divdu. divduo divduo. */
854GEN_INT_ARITH2 (divdu, 0x1F, 0x09, 0x0E, PPC_INTEGER);
855#endif
856
79aceca5 857/*** Integer comparison ***/
d9bce9d9
JM
858#if defined(TARGET_PPC64)
859#define GEN_CMP(name, opc, type) \
860GEN_HANDLER(name, 0x1F, 0x00, opc, 0x00400000, type) \
861{ \
862 gen_op_load_gpr_T0(rA(ctx->opcode)); \
863 gen_op_load_gpr_T1(rB(ctx->opcode)); \
864 if (ctx->sf_mode) \
865 gen_op_##name##_64(); \
866 else \
867 gen_op_##name(); \
868 gen_op_store_T0_crf(crfD(ctx->opcode)); \
869}
870#else
871#define GEN_CMP(name, opc, type) \
872GEN_HANDLER(name, 0x1F, 0x00, opc, 0x00400000, type) \
79aceca5
FB
873{ \
874 gen_op_load_gpr_T0(rA(ctx->opcode)); \
875 gen_op_load_gpr_T1(rB(ctx->opcode)); \
876 gen_op_##name(); \
877 gen_op_store_T0_crf(crfD(ctx->opcode)); \
79aceca5 878}
d9bce9d9 879#endif
79aceca5
FB
880
881/* cmp */
d9bce9d9 882GEN_CMP(cmp, 0x00, PPC_INTEGER);
79aceca5
FB
883/* cmpi */
884GEN_HANDLER(cmpi, 0x0B, 0xFF, 0xFF, 0x00400000, PPC_INTEGER)
885{
886 gen_op_load_gpr_T0(rA(ctx->opcode));
d9bce9d9
JM
887#if defined(TARGET_PPC64)
888 if (ctx->sf_mode)
889 gen_op_cmpi_64(SIMM(ctx->opcode));
890 else
891#endif
892 gen_op_cmpi(SIMM(ctx->opcode));
79aceca5 893 gen_op_store_T0_crf(crfD(ctx->opcode));
79aceca5
FB
894}
895/* cmpl */
d9bce9d9 896GEN_CMP(cmpl, 0x01, PPC_INTEGER);
79aceca5
FB
897/* cmpli */
898GEN_HANDLER(cmpli, 0x0A, 0xFF, 0xFF, 0x00400000, PPC_INTEGER)
899{
900 gen_op_load_gpr_T0(rA(ctx->opcode));
d9bce9d9
JM
901#if defined(TARGET_PPC64)
902 if (ctx->sf_mode)
903 gen_op_cmpli_64(UIMM(ctx->opcode));
904 else
905#endif
906 gen_op_cmpli(UIMM(ctx->opcode));
79aceca5 907 gen_op_store_T0_crf(crfD(ctx->opcode));
79aceca5
FB
908}
909
d9bce9d9
JM
910/* isel (PowerPC 2.03 specification) */
911GEN_HANDLER(isel, 0x1F, 0x0F, 0x00, 0x00000001, PPC_203)
912{
913 uint32_t bi = rC(ctx->opcode);
914 uint32_t mask;
915
916 if (rA(ctx->opcode) == 0) {
917 gen_set_T0(0);
918 } else {
919 gen_op_load_gpr_T1(rA(ctx->opcode));
920 }
921 gen_op_load_gpr_T2(rB(ctx->opcode));
922 mask = 1 << (3 - (bi & 0x03));
923 gen_op_load_crf_T0(bi >> 2);
924 gen_op_test_true(mask);
925 gen_op_isel();
926 gen_op_store_T0_gpr(rD(ctx->opcode));
927}
928
79aceca5 929/*** Integer logical ***/
d9bce9d9
JM
930#define __GEN_LOGICAL2(name, opc2, opc3, type) \
931GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000000, type) \
79aceca5
FB
932{ \
933 gen_op_load_gpr_T0(rS(ctx->opcode)); \
934 gen_op_load_gpr_T1(rB(ctx->opcode)); \
935 gen_op_##name(); \
79aceca5 936 gen_op_store_T0_gpr(rA(ctx->opcode)); \
76a66253
JM
937 if (unlikely(Rc(ctx->opcode) != 0)) \
938 gen_set_Rc0(ctx); \
79aceca5 939}
d9bce9d9
JM
940#define GEN_LOGICAL2(name, opc, type) \
941__GEN_LOGICAL2(name, 0x1C, opc, type)
79aceca5 942
d9bce9d9
JM
943#define GEN_LOGICAL1(name, opc, type) \
944GEN_HANDLER(name, 0x1F, 0x1A, opc, 0x00000000, type) \
79aceca5
FB
945{ \
946 gen_op_load_gpr_T0(rS(ctx->opcode)); \
947 gen_op_##name(); \
79aceca5 948 gen_op_store_T0_gpr(rA(ctx->opcode)); \
76a66253
JM
949 if (unlikely(Rc(ctx->opcode) != 0)) \
950 gen_set_Rc0(ctx); \
79aceca5
FB
951}
952
953/* and & and. */
d9bce9d9 954GEN_LOGICAL2(and, 0x00, PPC_INTEGER);
79aceca5 955/* andc & andc. */
d9bce9d9 956GEN_LOGICAL2(andc, 0x01, PPC_INTEGER);
79aceca5
FB
957/* andi. */
958GEN_HANDLER(andi_, 0x1C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
959{
960 gen_op_load_gpr_T0(rS(ctx->opcode));
76a66253 961 gen_op_andi_T0(UIMM(ctx->opcode));
79aceca5 962 gen_op_store_T0_gpr(rA(ctx->opcode));
76a66253 963 gen_set_Rc0(ctx);
79aceca5
FB
964}
965/* andis. */
966GEN_HANDLER(andis_, 0x1D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
967{
968 gen_op_load_gpr_T0(rS(ctx->opcode));
76a66253 969 gen_op_andi_T0(UIMM(ctx->opcode) << 16);
79aceca5 970 gen_op_store_T0_gpr(rA(ctx->opcode));
76a66253 971 gen_set_Rc0(ctx);
79aceca5
FB
972}
973
974/* cntlzw */
d9bce9d9 975GEN_LOGICAL1(cntlzw, 0x00, PPC_INTEGER);
79aceca5 976/* eqv & eqv. */
d9bce9d9 977GEN_LOGICAL2(eqv, 0x08, PPC_INTEGER);
79aceca5 978/* extsb & extsb. */
d9bce9d9 979GEN_LOGICAL1(extsb, 0x1D, PPC_INTEGER);
79aceca5 980/* extsh & extsh. */
d9bce9d9 981GEN_LOGICAL1(extsh, 0x1C, PPC_INTEGER);
79aceca5 982/* nand & nand. */
d9bce9d9 983GEN_LOGICAL2(nand, 0x0E, PPC_INTEGER);
79aceca5 984/* nor & nor. */
d9bce9d9 985GEN_LOGICAL2(nor, 0x03, PPC_INTEGER);
9a64fbe4 986
79aceca5 987/* or & or. */
9a64fbe4
FB
988GEN_HANDLER(or, 0x1F, 0x1C, 0x0D, 0x00000000, PPC_INTEGER)
989{
76a66253
JM
990 int rs, ra, rb;
991
992 rs = rS(ctx->opcode);
993 ra = rA(ctx->opcode);
994 rb = rB(ctx->opcode);
995 /* Optimisation for mr. ri case */
996 if (rs != ra || rs != rb) {
997 gen_op_load_gpr_T0(rs);
998 if (rs != rb) {
999 gen_op_load_gpr_T1(rb);
1000 gen_op_or();
1001 }
1002 gen_op_store_T0_gpr(ra);
1003 if (unlikely(Rc(ctx->opcode) != 0))
1004 gen_set_Rc0(ctx);
1005 } else if (unlikely(Rc(ctx->opcode) != 0)) {
1006 gen_op_load_gpr_T0(rs);
1007 gen_set_Rc0(ctx);
9a64fbe4 1008 }
9a64fbe4
FB
1009}
1010
79aceca5 1011/* orc & orc. */
d9bce9d9 1012GEN_LOGICAL2(orc, 0x0C, PPC_INTEGER);
79aceca5 1013/* xor & xor. */
9a64fbe4
FB
1014GEN_HANDLER(xor, 0x1F, 0x1C, 0x09, 0x00000000, PPC_INTEGER)
1015{
1016 gen_op_load_gpr_T0(rS(ctx->opcode));
1017 /* Optimisation for "set to zero" case */
1018 if (rS(ctx->opcode) != rB(ctx->opcode)) {
1019 gen_op_load_gpr_T1(rB(ctx->opcode));
1020 gen_op_xor();
1021 } else {
76a66253 1022 gen_op_reset_T0();
9a64fbe4 1023 }
9a64fbe4 1024 gen_op_store_T0_gpr(rA(ctx->opcode));
76a66253
JM
1025 if (unlikely(Rc(ctx->opcode) != 0))
1026 gen_set_Rc0(ctx);
9a64fbe4 1027}
79aceca5
FB
1028/* ori */
1029GEN_HANDLER(ori, 0x18, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
1030{
76a66253 1031 target_ulong uimm = UIMM(ctx->opcode);
79aceca5 1032
9a64fbe4
FB
1033 if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
1034 /* NOP */
76a66253 1035 /* XXX: should handle special NOPs for POWER series */
9a64fbe4 1036 return;
76a66253
JM
1037 }
1038 gen_op_load_gpr_T0(rS(ctx->opcode));
1039 if (likely(uimm != 0))
79aceca5 1040 gen_op_ori(uimm);
76a66253 1041 gen_op_store_T0_gpr(rA(ctx->opcode));
79aceca5
FB
1042}
1043/* oris */
1044GEN_HANDLER(oris, 0x19, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
1045{
76a66253 1046 target_ulong uimm = UIMM(ctx->opcode);
79aceca5 1047
9a64fbe4
FB
1048 if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
1049 /* NOP */
1050 return;
76a66253
JM
1051 }
1052 gen_op_load_gpr_T0(rS(ctx->opcode));
1053 if (likely(uimm != 0))
79aceca5 1054 gen_op_ori(uimm << 16);
76a66253 1055 gen_op_store_T0_gpr(rA(ctx->opcode));
79aceca5
FB
1056}
1057/* xori */
1058GEN_HANDLER(xori, 0x1A, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
1059{
76a66253 1060 target_ulong uimm = UIMM(ctx->opcode);
9a64fbe4
FB
1061
1062 if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
1063 /* NOP */
1064 return;
1065 }
79aceca5 1066 gen_op_load_gpr_T0(rS(ctx->opcode));
76a66253
JM
1067 if (likely(uimm != 0))
1068 gen_op_xori(uimm);
79aceca5 1069 gen_op_store_T0_gpr(rA(ctx->opcode));
79aceca5
FB
1070}
1071
1072/* xoris */
1073GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
1074{
76a66253 1075 target_ulong uimm = UIMM(ctx->opcode);
9a64fbe4
FB
1076
1077 if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
1078 /* NOP */
1079 return;
1080 }
79aceca5 1081 gen_op_load_gpr_T0(rS(ctx->opcode));
76a66253
JM
1082 if (likely(uimm != 0))
1083 gen_op_xori(uimm << 16);
79aceca5 1084 gen_op_store_T0_gpr(rA(ctx->opcode));
79aceca5
FB
1085}
1086
d9bce9d9
JM
1087/* popcntb : PowerPC 2.03 specification */
1088GEN_HANDLER(popcntb, 0x1F, 0x03, 0x03, 0x0000F801, PPC_203)
1089{
1090 gen_op_load_gpr_T0(rS(ctx->opcode));
1091#if defined(TARGET_PPC64)
1092 if (ctx->sf_mode)
1093 gen_op_popcntb_64();
1094 else
1095#endif
1096 gen_op_popcntb();
1097 gen_op_store_T0_gpr(rA(ctx->opcode));
1098}
1099
1100#if defined(TARGET_PPC64)
1101/* extsw & extsw. */
1102GEN_LOGICAL1(extsw, 0x1E, PPC_64B);
1103/* cntlzd */
1104GEN_LOGICAL1(cntlzd, 0x01, PPC_64B);
1105#endif
1106
79aceca5
FB
1107/*** Integer rotate ***/
1108/* rlwimi & rlwimi. */
1109GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
1110{
76a66253
JM
1111 target_ulong mask;
1112 uint32_t mb, me, sh;
79aceca5
FB
1113
1114 mb = MB(ctx->opcode);
1115 me = ME(ctx->opcode);
76a66253 1116 sh = SH(ctx->opcode);
76a66253
JM
1117 if (likely(sh == 0)) {
1118 if (likely(mb == 0 && me == 31)) {
1119 gen_op_load_gpr_T0(rS(ctx->opcode));
1120 goto do_store;
1121 } else if (likely(mb == 31 && me == 0)) {
1122 gen_op_load_gpr_T0(rA(ctx->opcode));
1123 goto do_store;
1124 }
1125 gen_op_load_gpr_T0(rS(ctx->opcode));
1126 gen_op_load_gpr_T1(rA(ctx->opcode));
1127 goto do_mask;
1128 }
79aceca5 1129 gen_op_load_gpr_T0(rS(ctx->opcode));
fb0eaffc 1130 gen_op_load_gpr_T1(rA(ctx->opcode));
76a66253
JM
1131 gen_op_rotli32_T0(SH(ctx->opcode));
1132 do_mask:
1133#if defined(TARGET_PPC64)
1134 mb += 32;
1135 me += 32;
1136#endif
1137 mask = MASK(mb, me);
1138 gen_op_andi_T0(mask);
1139 gen_op_andi_T1(~mask);
1140 gen_op_or();
1141 do_store:
79aceca5 1142 gen_op_store_T0_gpr(rA(ctx->opcode));
76a66253
JM
1143 if (unlikely(Rc(ctx->opcode) != 0))
1144 gen_set_Rc0(ctx);
79aceca5
FB
1145}
1146/* rlwinm & rlwinm. */
1147GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
1148{
1149 uint32_t mb, me, sh;
3b46e624 1150
79aceca5
FB
1151 sh = SH(ctx->opcode);
1152 mb = MB(ctx->opcode);
1153 me = ME(ctx->opcode);
1154 gen_op_load_gpr_T0(rS(ctx->opcode));
76a66253
JM
1155 if (likely(sh == 0)) {
1156 goto do_mask;
1157 }
1158 if (likely(mb == 0)) {
1159 if (likely(me == 31)) {
1160 gen_op_rotli32_T0(sh);
1161 goto do_store;
1162 } else if (likely(me == (31 - sh))) {
1163 gen_op_sli_T0(sh);
1164 goto do_store;
79aceca5 1165 }
76a66253
JM
1166 } else if (likely(me == 31)) {
1167 if (likely(sh == (32 - mb))) {
1168 gen_op_srli_T0(mb);
1169 goto do_store;
79aceca5
FB
1170 }
1171 }
76a66253
JM
1172 gen_op_rotli32_T0(sh);
1173 do_mask:
1174#if defined(TARGET_PPC64)
1175 mb += 32;
1176 me += 32;
1177#endif
1178 gen_op_andi_T0(MASK(mb, me));
1179 do_store:
79aceca5 1180 gen_op_store_T0_gpr(rA(ctx->opcode));
76a66253
JM
1181 if (unlikely(Rc(ctx->opcode) != 0))
1182 gen_set_Rc0(ctx);
79aceca5
FB
1183}
1184/* rlwnm & rlwnm. */
1185GEN_HANDLER(rlwnm, 0x17, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
1186{
1187 uint32_t mb, me;
1188
1189 mb = MB(ctx->opcode);
1190 me = ME(ctx->opcode);
1191 gen_op_load_gpr_T0(rS(ctx->opcode));
1192 gen_op_load_gpr_T1(rB(ctx->opcode));
76a66253
JM
1193 gen_op_rotl32_T0_T1();
1194 if (unlikely(mb != 0 || me != 31)) {
1195#if defined(TARGET_PPC64)
1196 mb += 32;
1197 me += 32;
1198#endif
1199 gen_op_andi_T0(MASK(mb, me));
79aceca5 1200 }
79aceca5 1201 gen_op_store_T0_gpr(rA(ctx->opcode));
76a66253
JM
1202 if (unlikely(Rc(ctx->opcode) != 0))
1203 gen_set_Rc0(ctx);
79aceca5
FB
1204}
1205
d9bce9d9
JM
1206#if defined(TARGET_PPC64)
1207#define GEN_PPC64_R2(name, opc1, opc2) \
1208GEN_HANDLER(name##0, opc1, opc2, 0xFF, 0x00000000, PPC_64B) \
1209{ \
1210 gen_##name(ctx, 0); \
1211} \
1212GEN_HANDLER(name##1, opc1, opc2 | 0x10, 0xFF, 0x00000000, PPC_64B) \
1213{ \
1214 gen_##name(ctx, 1); \
1215}
1216#define GEN_PPC64_R4(name, opc1, opc2) \
1217GEN_HANDLER(name##0, opc1, opc2, 0xFF, 0x00000000, PPC_64B) \
1218{ \
1219 gen_##name(ctx, 0, 0); \
1220} \
1221GEN_HANDLER(name##1, opc1, opc2 | 0x01, 0xFF, 0x00000000, PPC_64B) \
1222{ \
1223 gen_##name(ctx, 0, 1); \
1224} \
1225GEN_HANDLER(name##2, opc1, opc2 | 0x10, 0xFF, 0x00000000, PPC_64B) \
1226{ \
1227 gen_##name(ctx, 1, 0); \
1228} \
1229GEN_HANDLER(name##3, opc1, opc2 | 0x11, 0xFF, 0x00000000, PPC_64B) \
1230{ \
1231 gen_##name(ctx, 1, 1); \
1232}
51789c41
JM
1233
1234static inline void gen_rldinm (DisasContext *ctx, uint32_t mb, uint32_t me,
1235 uint32_t sh)
1236{
1237 gen_op_load_gpr_T0(rS(ctx->opcode));
1238 if (likely(sh == 0)) {
1239 goto do_mask;
1240 }
1241 if (likely(mb == 0)) {
1242 if (likely(me == 63)) {
1243 gen_op_rotli32_T0(sh);
1244 goto do_store;
1245 } else if (likely(me == (63 - sh))) {
1246 gen_op_sli_T0(sh);
1247 goto do_store;
1248 }
1249 } else if (likely(me == 63)) {
1250 if (likely(sh == (64 - mb))) {
1251 gen_op_srli_T0(mb);
1252 goto do_store;
1253 }
1254 }
1255 gen_op_rotli64_T0(sh);
1256 do_mask:
1257 gen_op_andi_T0(MASK(mb, me));
1258 do_store:
1259 gen_op_store_T0_gpr(rA(ctx->opcode));
1260 if (unlikely(Rc(ctx->opcode) != 0))
1261 gen_set_Rc0(ctx);
1262}
d9bce9d9
JM
1263/* rldicl - rldicl. */
1264static inline void gen_rldicl (DisasContext *ctx, int mbn, int shn)
1265{
51789c41 1266 uint32_t sh, mb;
d9bce9d9 1267
9d53c753
JM
1268 sh = SH(ctx->opcode) | (shn << 5);
1269 mb = MB(ctx->opcode) | (mbn << 5);
51789c41 1270 gen_rldinm(ctx, mb, 63, sh);
d9bce9d9 1271}
51789c41 1272GEN_PPC64_R4(rldicl, 0x1E, 0x00);
d9bce9d9
JM
1273/* rldicr - rldicr. */
1274static inline void gen_rldicr (DisasContext *ctx, int men, int shn)
1275{
51789c41 1276 uint32_t sh, me;
d9bce9d9 1277
9d53c753
JM
1278 sh = SH(ctx->opcode) | (shn << 5);
1279 me = MB(ctx->opcode) | (men << 5);
51789c41 1280 gen_rldinm(ctx, 0, me, sh);
d9bce9d9 1281}
51789c41 1282GEN_PPC64_R4(rldicr, 0x1E, 0x02);
d9bce9d9
JM
1283/* rldic - rldic. */
1284static inline void gen_rldic (DisasContext *ctx, int mbn, int shn)
1285{
51789c41 1286 uint32_t sh, mb;
d9bce9d9 1287
9d53c753
JM
1288 sh = SH(ctx->opcode) | (shn << 5);
1289 mb = MB(ctx->opcode) | (mbn << 5);
51789c41
JM
1290 gen_rldinm(ctx, mb, 63 - sh, sh);
1291}
1292GEN_PPC64_R4(rldic, 0x1E, 0x04);
1293
1294static inline void gen_rldnm (DisasContext *ctx, uint32_t mb, uint32_t me)
1295{
1296 gen_op_load_gpr_T0(rS(ctx->opcode));
1297 gen_op_load_gpr_T1(rB(ctx->opcode));
1298 gen_op_rotl64_T0_T1();
1299 if (unlikely(mb != 0 || me != 63)) {
1300 gen_op_andi_T0(MASK(mb, me));
1301 }
1302 gen_op_store_T0_gpr(rA(ctx->opcode));
1303 if (unlikely(Rc(ctx->opcode) != 0))
1304 gen_set_Rc0(ctx);
d9bce9d9 1305}
51789c41 1306
d9bce9d9
JM
1307/* rldcl - rldcl. */
1308static inline void gen_rldcl (DisasContext *ctx, int mbn)
1309{
51789c41 1310 uint32_t mb;
d9bce9d9 1311
9d53c753 1312 mb = MB(ctx->opcode) | (mbn << 5);
51789c41 1313 gen_rldnm(ctx, mb, 63);
d9bce9d9
JM
1314}
1315GEN_PPC64_R2(rldcl, 0x1E, 0x08)
1316/* rldcr - rldcr. */
1317static inline void gen_rldcr (DisasContext *ctx, int men)
1318{
51789c41 1319 uint32_t me;
d9bce9d9 1320
9d53c753 1321 me = MB(ctx->opcode) | (men << 5);
51789c41 1322 gen_rldnm(ctx, 0, me);
d9bce9d9
JM
1323}
1324GEN_PPC64_R2(rldcr, 0x1E, 0x09)
1325/* rldimi - rldimi. */
1326static inline void gen_rldimi (DisasContext *ctx, int mbn, int shn)
1327{
51789c41
JM
1328 uint64_t mask;
1329 uint32_t sh, mb;
d9bce9d9 1330
9d53c753
JM
1331 sh = SH(ctx->opcode) | (shn << 5);
1332 mb = MB(ctx->opcode) | (mbn << 5);
51789c41
JM
1333 if (likely(sh == 0)) {
1334 if (likely(mb == 0)) {
1335 gen_op_load_gpr_T0(rS(ctx->opcode));
1336 goto do_store;
1337 } else if (likely(mb == 63)) {
1338 gen_op_load_gpr_T0(rA(ctx->opcode));
1339 goto do_store;
1340 }
1341 gen_op_load_gpr_T0(rS(ctx->opcode));
1342 gen_op_load_gpr_T1(rA(ctx->opcode));
1343 goto do_mask;
1344 }
1345 gen_op_load_gpr_T0(rS(ctx->opcode));
1346 gen_op_load_gpr_T1(rA(ctx->opcode));
1347 gen_op_rotli64_T0(SH(ctx->opcode));
1348 do_mask:
1349 mask = MASK(mb, 63 - sh);
1350 gen_op_andi_T0(mask);
1351 gen_op_andi_T1(~mask);
1352 gen_op_or();
1353 do_store:
1354 gen_op_store_T0_gpr(rA(ctx->opcode));
1355 if (unlikely(Rc(ctx->opcode) != 0))
1356 gen_set_Rc0(ctx);
d9bce9d9
JM
1357}
1358GEN_PPC64_R4(rldimi, 0x1E, 0x06)
1359#endif
1360
79aceca5
FB
1361/*** Integer shift ***/
1362/* slw & slw. */
d9bce9d9 1363__GEN_LOGICAL2(slw, 0x18, 0x00, PPC_INTEGER);
79aceca5 1364/* sraw & sraw. */
d9bce9d9 1365__GEN_LOGICAL2(sraw, 0x18, 0x18, PPC_INTEGER);
79aceca5
FB
1366/* srawi & srawi. */
1367GEN_HANDLER(srawi, 0x1F, 0x18, 0x19, 0x00000000, PPC_INTEGER)
1368{
d9bce9d9 1369 int mb, me;
79aceca5 1370 gen_op_load_gpr_T0(rS(ctx->opcode));
d9bce9d9
JM
1371 if (SH(ctx->opcode) != 0) {
1372 gen_op_move_T1_T0();
1373 mb = 32 - SH(ctx->opcode);
1374 me = 31;
1375#if defined(TARGET_PPC64)
1376 mb += 32;
1377 me += 32;
1378#endif
1379 gen_op_srawi(SH(ctx->opcode), MASK(mb, me));
1380 }
79aceca5 1381 gen_op_store_T0_gpr(rA(ctx->opcode));
76a66253
JM
1382 if (unlikely(Rc(ctx->opcode) != 0))
1383 gen_set_Rc0(ctx);
79aceca5
FB
1384}
1385/* srw & srw. */
d9bce9d9
JM
1386__GEN_LOGICAL2(srw, 0x18, 0x10, PPC_INTEGER);
1387
1388#if defined(TARGET_PPC64)
1389/* sld & sld. */
1390__GEN_LOGICAL2(sld, 0x1B, 0x00, PPC_64B);
1391/* srad & srad. */
1392__GEN_LOGICAL2(srad, 0x1A, 0x18, PPC_64B);
1393/* sradi & sradi. */
1394static inline void gen_sradi (DisasContext *ctx, int n)
1395{
1396 uint64_t mask;
1397 int sh, mb, me;
1398
1399 gen_op_load_gpr_T0(rS(ctx->opcode));
1400 sh = SH(ctx->opcode) + (n << 5);
1401 if (sh != 0) {
1402 gen_op_move_T1_T0();
1403 mb = 64 - SH(ctx->opcode);
1404 me = 63;
1405 mask = MASK(mb, me);
1406 gen_op_sradi(sh, mask >> 32, mask);
1407 }
1408 gen_op_store_T0_gpr(rA(ctx->opcode));
1409 if (unlikely(Rc(ctx->opcode) != 0))
1410 gen_set_Rc0(ctx);
1411}
1412GEN_HANDLER(sradi0, 0x1F, 0x1A, 0x19, 0x00000000, PPC_64B)
1413{
1414 gen_sradi(ctx, 0);
1415}
1416GEN_HANDLER(sradi1, 0x1F, 0x1B, 0x19, 0x00000000, PPC_64B)
1417{
1418 gen_sradi(ctx, 1);
1419}
1420/* srd & srd. */
1421__GEN_LOGICAL2(srd, 0x1B, 0x10, PPC_64B);
1422#endif
79aceca5
FB
1423
1424/*** Floating-Point arithmetic ***/
4ecc3190 1425#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat) \
9a64fbe4
FB
1426GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, PPC_FLOAT) \
1427{ \
76a66253 1428 if (unlikely(!ctx->fpu_enabled)) { \
3cc62370
FB
1429 RET_EXCP(ctx, EXCP_NO_FP, 0); \
1430 return; \
1431 } \
9a64fbe4
FB
1432 gen_op_reset_scrfx(); \
1433 gen_op_load_fpr_FT0(rA(ctx->opcode)); \
1434 gen_op_load_fpr_FT1(rC(ctx->opcode)); \
1435 gen_op_load_fpr_FT2(rB(ctx->opcode)); \
4ecc3190
FB
1436 gen_op_f##op(); \
1437 if (isfloat) { \
1438 gen_op_frsp(); \
1439 } \
9a64fbe4 1440 gen_op_store_FT0_fpr(rD(ctx->opcode)); \
76a66253 1441 if (unlikely(Rc(ctx->opcode) != 0)) \
9a64fbe4
FB
1442 gen_op_set_Rc1(); \
1443}
1444
1445#define GEN_FLOAT_ACB(name, op2) \
4ecc3190
FB
1446_GEN_FLOAT_ACB(name, name, 0x3F, op2, 0); \
1447_GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1);
9a64fbe4 1448
4ecc3190 1449#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat) \
9a64fbe4
FB
1450GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \
1451{ \
76a66253 1452 if (unlikely(!ctx->fpu_enabled)) { \
3cc62370
FB
1453 RET_EXCP(ctx, EXCP_NO_FP, 0); \
1454 return; \
1455 } \
9a64fbe4
FB
1456 gen_op_reset_scrfx(); \
1457 gen_op_load_fpr_FT0(rA(ctx->opcode)); \
1458 gen_op_load_fpr_FT1(rB(ctx->opcode)); \
4ecc3190
FB
1459 gen_op_f##op(); \
1460 if (isfloat) { \
1461 gen_op_frsp(); \
1462 } \
9a64fbe4 1463 gen_op_store_FT0_fpr(rD(ctx->opcode)); \
76a66253 1464 if (unlikely(Rc(ctx->opcode) != 0)) \
9a64fbe4
FB
1465 gen_op_set_Rc1(); \
1466}
1467#define GEN_FLOAT_AB(name, op2, inval) \
4ecc3190
FB
1468_GEN_FLOAT_AB(name, name, 0x3F, op2, inval, 0); \
1469_GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1);
9a64fbe4 1470
4ecc3190 1471#define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat) \
9a64fbe4
FB
1472GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \
1473{ \
76a66253 1474 if (unlikely(!ctx->fpu_enabled)) { \
3cc62370
FB
1475 RET_EXCP(ctx, EXCP_NO_FP, 0); \
1476 return; \
1477 } \
9a64fbe4
FB
1478 gen_op_reset_scrfx(); \
1479 gen_op_load_fpr_FT0(rA(ctx->opcode)); \
1480 gen_op_load_fpr_FT1(rC(ctx->opcode)); \
4ecc3190
FB
1481 gen_op_f##op(); \
1482 if (isfloat) { \
1483 gen_op_frsp(); \
1484 } \
9a64fbe4 1485 gen_op_store_FT0_fpr(rD(ctx->opcode)); \
76a66253 1486 if (unlikely(Rc(ctx->opcode) != 0)) \
9a64fbe4
FB
1487 gen_op_set_Rc1(); \
1488}
1489#define GEN_FLOAT_AC(name, op2, inval) \
4ecc3190
FB
1490_GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0); \
1491_GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1);
9a64fbe4
FB
1492
1493#define GEN_FLOAT_B(name, op2, op3) \
1494GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, PPC_FLOAT) \
1495{ \
76a66253 1496 if (unlikely(!ctx->fpu_enabled)) { \
3cc62370
FB
1497 RET_EXCP(ctx, EXCP_NO_FP, 0); \
1498 return; \
1499 } \
9a64fbe4
FB
1500 gen_op_reset_scrfx(); \
1501 gen_op_load_fpr_FT0(rB(ctx->opcode)); \
1502 gen_op_f##name(); \
1503 gen_op_store_FT0_fpr(rD(ctx->opcode)); \
76a66253 1504 if (unlikely(Rc(ctx->opcode) != 0)) \
9a64fbe4 1505 gen_op_set_Rc1(); \
79aceca5
FB
1506}
1507
4ecc3190
FB
1508#define GEN_FLOAT_BS(name, op1, op2) \
1509GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, PPC_FLOAT) \
9a64fbe4 1510{ \
76a66253 1511 if (unlikely(!ctx->fpu_enabled)) { \
3cc62370
FB
1512 RET_EXCP(ctx, EXCP_NO_FP, 0); \
1513 return; \
1514 } \
9a64fbe4
FB
1515 gen_op_reset_scrfx(); \
1516 gen_op_load_fpr_FT0(rB(ctx->opcode)); \
1517 gen_op_f##name(); \
1518 gen_op_store_FT0_fpr(rD(ctx->opcode)); \
76a66253 1519 if (unlikely(Rc(ctx->opcode) != 0)) \
9a64fbe4 1520 gen_op_set_Rc1(); \
79aceca5
FB
1521}
1522
9a64fbe4
FB
1523/* fadd - fadds */
1524GEN_FLOAT_AB(add, 0x15, 0x000007C0);
4ecc3190 1525/* fdiv - fdivs */
9a64fbe4 1526GEN_FLOAT_AB(div, 0x12, 0x000007C0);
4ecc3190 1527/* fmul - fmuls */
9a64fbe4 1528GEN_FLOAT_AC(mul, 0x19, 0x0000F800);
79aceca5 1529
76a66253 1530/* fres */ /* XXX: not in 601 */
4ecc3190 1531GEN_FLOAT_BS(res, 0x3B, 0x18);
79aceca5 1532
76a66253 1533/* frsqrte */ /* XXX: not in 601 */
4ecc3190 1534GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A);
79aceca5 1535
76a66253 1536/* fsel */ /* XXX: not in 601 */
4ecc3190
FB
1537_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0);
1538/* fsub - fsubs */
9a64fbe4 1539GEN_FLOAT_AB(sub, 0x14, 0x000007C0);
79aceca5
FB
1540/* Optional: */
1541/* fsqrt */
c7d344af
FB
1542GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT)
1543{
76a66253 1544 if (unlikely(!ctx->fpu_enabled)) {
c7d344af
FB
1545 RET_EXCP(ctx, EXCP_NO_FP, 0);
1546 return;
1547 }
1548 gen_op_reset_scrfx();
1549 gen_op_load_fpr_FT0(rB(ctx->opcode));
1550 gen_op_fsqrt();
1551 gen_op_store_FT0_fpr(rD(ctx->opcode));
76a66253 1552 if (unlikely(Rc(ctx->opcode) != 0))
c7d344af
FB
1553 gen_op_set_Rc1();
1554}
79aceca5 1555
9a64fbe4 1556GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT)
79aceca5 1557{
76a66253 1558 if (unlikely(!ctx->fpu_enabled)) {
3cc62370
FB
1559 RET_EXCP(ctx, EXCP_NO_FP, 0);
1560 return;
1561 }
9a64fbe4
FB
1562 gen_op_reset_scrfx();
1563 gen_op_load_fpr_FT0(rB(ctx->opcode));
4ecc3190
FB
1564 gen_op_fsqrt();
1565 gen_op_frsp();
9a64fbe4 1566 gen_op_store_FT0_fpr(rD(ctx->opcode));
76a66253 1567 if (unlikely(Rc(ctx->opcode) != 0))
9a64fbe4 1568 gen_op_set_Rc1();
79aceca5
FB
1569}
1570
1571/*** Floating-Point multiply-and-add ***/
4ecc3190 1572/* fmadd - fmadds */
9a64fbe4 1573GEN_FLOAT_ACB(madd, 0x1D);
4ecc3190 1574/* fmsub - fmsubs */
9a64fbe4 1575GEN_FLOAT_ACB(msub, 0x1C);
4ecc3190 1576/* fnmadd - fnmadds */
9a64fbe4 1577GEN_FLOAT_ACB(nmadd, 0x1F);
4ecc3190 1578/* fnmsub - fnmsubs */
9a64fbe4 1579GEN_FLOAT_ACB(nmsub, 0x1E);
79aceca5
FB
1580
1581/*** Floating-Point round & convert ***/
1582/* fctiw */
9a64fbe4 1583GEN_FLOAT_B(ctiw, 0x0E, 0x00);
79aceca5 1584/* fctiwz */
9a64fbe4 1585GEN_FLOAT_B(ctiwz, 0x0F, 0x00);
79aceca5 1586/* frsp */
9a64fbe4 1587GEN_FLOAT_B(rsp, 0x0C, 0x00);
426613db
JM
1588#if defined(TARGET_PPC64)
1589/* fcfid */
1590GEN_FLOAT_B(cfid, 0x0E, 0x1A);
1591/* fctid */
1592GEN_FLOAT_B(ctid, 0x0E, 0x19);
1593/* fctidz */
1594GEN_FLOAT_B(ctidz, 0x0F, 0x19);
1595#endif
79aceca5
FB
1596
1597/*** Floating-Point compare ***/
1598/* fcmpo */
76a66253 1599GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT)
79aceca5 1600{
76a66253 1601 if (unlikely(!ctx->fpu_enabled)) {
3cc62370
FB
1602 RET_EXCP(ctx, EXCP_NO_FP, 0);
1603 return;
1604 }
9a64fbe4
FB
1605 gen_op_reset_scrfx();
1606 gen_op_load_fpr_FT0(rA(ctx->opcode));
1607 gen_op_load_fpr_FT1(rB(ctx->opcode));
1608 gen_op_fcmpo();
1609 gen_op_store_T0_crf(crfD(ctx->opcode));
79aceca5
FB
1610}
1611
1612/* fcmpu */
76a66253 1613GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT)
79aceca5 1614{
76a66253 1615 if (unlikely(!ctx->fpu_enabled)) {
3cc62370
FB
1616 RET_EXCP(ctx, EXCP_NO_FP, 0);
1617 return;
1618 }
9a64fbe4
FB
1619 gen_op_reset_scrfx();
1620 gen_op_load_fpr_FT0(rA(ctx->opcode));
1621 gen_op_load_fpr_FT1(rB(ctx->opcode));
1622 gen_op_fcmpu();
1623 gen_op_store_T0_crf(crfD(ctx->opcode));
79aceca5
FB
1624}
1625
9a64fbe4
FB
1626/*** Floating-point move ***/
1627/* fabs */
1628GEN_FLOAT_B(abs, 0x08, 0x08);
1629
1630/* fmr - fmr. */
1631GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT)
1632{
76a66253 1633 if (unlikely(!ctx->fpu_enabled)) {
3cc62370
FB
1634 RET_EXCP(ctx, EXCP_NO_FP, 0);
1635 return;
1636 }
9a64fbe4
FB
1637 gen_op_reset_scrfx();
1638 gen_op_load_fpr_FT0(rB(ctx->opcode));
1639 gen_op_store_FT0_fpr(rD(ctx->opcode));
76a66253 1640 if (unlikely(Rc(ctx->opcode) != 0))
9a64fbe4
FB
1641 gen_op_set_Rc1();
1642}
1643
1644/* fnabs */
1645GEN_FLOAT_B(nabs, 0x08, 0x04);
1646/* fneg */
1647GEN_FLOAT_B(neg, 0x08, 0x01);
1648
79aceca5
FB
1649/*** Floating-Point status & ctrl register ***/
1650/* mcrfs */
1651GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT)
1652{
76a66253 1653 if (unlikely(!ctx->fpu_enabled)) {
3cc62370
FB
1654 RET_EXCP(ctx, EXCP_NO_FP, 0);
1655 return;
1656 }
fb0eaffc
FB
1657 gen_op_load_fpscr_T0(crfS(ctx->opcode));
1658 gen_op_store_T0_crf(crfD(ctx->opcode));
1659 gen_op_clear_fpscr(crfS(ctx->opcode));
79aceca5
FB
1660}
1661
1662/* mffs */
1663GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT)
1664{
76a66253 1665 if (unlikely(!ctx->fpu_enabled)) {
3cc62370
FB
1666 RET_EXCP(ctx, EXCP_NO_FP, 0);
1667 return;
1668 }
28b6751f 1669 gen_op_load_fpscr();
fb0eaffc 1670 gen_op_store_FT0_fpr(rD(ctx->opcode));
76a66253 1671 if (unlikely(Rc(ctx->opcode) != 0))
fb0eaffc 1672 gen_op_set_Rc1();
79aceca5
FB
1673}
1674
1675/* mtfsb0 */
1676GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT)
1677{
fb0eaffc 1678 uint8_t crb;
3b46e624 1679
76a66253 1680 if (unlikely(!ctx->fpu_enabled)) {
3cc62370
FB
1681 RET_EXCP(ctx, EXCP_NO_FP, 0);
1682 return;
1683 }
fb0eaffc
FB
1684 crb = crbD(ctx->opcode) >> 2;
1685 gen_op_load_fpscr_T0(crb);
76a66253 1686 gen_op_andi_T0(~(1 << (crbD(ctx->opcode) & 0x03)));
fb0eaffc 1687 gen_op_store_T0_fpscr(crb);
76a66253 1688 if (unlikely(Rc(ctx->opcode) != 0))
fb0eaffc 1689 gen_op_set_Rc1();
79aceca5
FB
1690}
1691
1692/* mtfsb1 */
1693GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT)
1694{
fb0eaffc 1695 uint8_t crb;
3b46e624 1696
76a66253 1697 if (unlikely(!ctx->fpu_enabled)) {
3cc62370
FB
1698 RET_EXCP(ctx, EXCP_NO_FP, 0);
1699 return;
1700 }
fb0eaffc
FB
1701 crb = crbD(ctx->opcode) >> 2;
1702 gen_op_load_fpscr_T0(crb);
1703 gen_op_ori(1 << (crbD(ctx->opcode) & 0x03));
1704 gen_op_store_T0_fpscr(crb);
76a66253 1705 if (unlikely(Rc(ctx->opcode) != 0))
fb0eaffc 1706 gen_op_set_Rc1();
79aceca5
FB
1707}
1708
1709/* mtfsf */
1710GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x02010000, PPC_FLOAT)
1711{
76a66253 1712 if (unlikely(!ctx->fpu_enabled)) {
3cc62370
FB
1713 RET_EXCP(ctx, EXCP_NO_FP, 0);
1714 return;
1715 }
fb0eaffc 1716 gen_op_load_fpr_FT0(rB(ctx->opcode));
28b6751f 1717 gen_op_store_fpscr(FM(ctx->opcode));
76a66253 1718 if (unlikely(Rc(ctx->opcode) != 0))
fb0eaffc 1719 gen_op_set_Rc1();
79aceca5
FB
1720}
1721
1722/* mtfsfi */
1723GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT)
1724{
76a66253 1725 if (unlikely(!ctx->fpu_enabled)) {
3cc62370
FB
1726 RET_EXCP(ctx, EXCP_NO_FP, 0);
1727 return;
1728 }
fb0eaffc 1729 gen_op_store_T0_fpscri(crbD(ctx->opcode) >> 2, FPIMM(ctx->opcode));
76a66253 1730 if (unlikely(Rc(ctx->opcode) != 0))
fb0eaffc 1731 gen_op_set_Rc1();
79aceca5
FB
1732}
1733
76a66253
JM
1734/*** Addressing modes ***/
1735/* Register indirect with immediate index : EA = (rA|0) + SIMM */
9d53c753 1736static inline void gen_addr_imm_index (DisasContext *ctx, int maskl)
76a66253
JM
1737{
1738 target_long simm = SIMM(ctx->opcode);
1739
9d53c753
JM
1740 if (maskl)
1741 simm &= ~0x03;
76a66253 1742 if (rA(ctx->opcode) == 0) {
d9bce9d9 1743 gen_set_T0(simm);
76a66253
JM
1744 } else {
1745 gen_op_load_gpr_T0(rA(ctx->opcode));
1746 if (likely(simm != 0))
1747 gen_op_addi(simm);
1748 }
a496775f
JM
1749#ifdef DEBUG_MEMORY_ACCESSES
1750 gen_op_print_mem_EA();
1751#endif
76a66253
JM
1752}
1753
1754static inline void gen_addr_reg_index (DisasContext *ctx)
1755{
1756 if (rA(ctx->opcode) == 0) {
1757 gen_op_load_gpr_T0(rB(ctx->opcode));
1758 } else {
1759 gen_op_load_gpr_T0(rA(ctx->opcode));
1760 gen_op_load_gpr_T1(rB(ctx->opcode));
1761 gen_op_add();
1762 }
a496775f
JM
1763#ifdef DEBUG_MEMORY_ACCESSES
1764 gen_op_print_mem_EA();
1765#endif
76a66253
JM
1766}
1767
1768static inline void gen_addr_register (DisasContext *ctx)
1769{
1770 if (rA(ctx->opcode) == 0) {
1771 gen_op_reset_T0();
1772 } else {
1773 gen_op_load_gpr_T0(rA(ctx->opcode));
1774 }
a496775f
JM
1775#ifdef DEBUG_MEMORY_ACCESSES
1776 gen_op_print_mem_EA();
1777#endif
76a66253
JM
1778}
1779
79aceca5 1780/*** Integer load ***/
111bfab3 1781#define op_ldst(name) (*gen_op_##name[ctx->mem_idx])()
9a64fbe4 1782#if defined(CONFIG_USER_ONLY)
d9bce9d9 1783#if defined(TARGET_PPC64)
111bfab3
FB
1784#define OP_LD_TABLE(width) \
1785static GenOpFunc *gen_op_l##width[] = { \
1786 &gen_op_l##width##_raw, \
1787 &gen_op_l##width##_le_raw, \
d9bce9d9
JM
1788 &gen_op_l##width##_64_raw, \
1789 &gen_op_l##width##_le_64_raw, \
111bfab3
FB
1790};
1791#define OP_ST_TABLE(width) \
1792static GenOpFunc *gen_op_st##width[] = { \
1793 &gen_op_st##width##_raw, \
1794 &gen_op_st##width##_le_raw, \
d9bce9d9
JM
1795 &gen_op_st##width##_64_raw, \
1796 &gen_op_st##width##_le_64_raw, \
111bfab3
FB
1797};
1798/* Byte access routine are endian safe */
d9bce9d9
JM
1799#define gen_op_stb_le_64_raw gen_op_stb_64_raw
1800#define gen_op_lbz_le_64_raw gen_op_lbz_64_raw
1801#else
1802#define OP_LD_TABLE(width) \
1803static GenOpFunc *gen_op_l##width[] = { \
1804 &gen_op_l##width##_raw, \
1805 &gen_op_l##width##_le_raw, \
1806};
1807#define OP_ST_TABLE(width) \
1808static GenOpFunc *gen_op_st##width[] = { \
1809 &gen_op_st##width##_raw, \
1810 &gen_op_st##width##_le_raw, \
1811};
1812#endif
1813/* Byte access routine are endian safe */
111bfab3
FB
1814#define gen_op_stb_le_raw gen_op_stb_raw
1815#define gen_op_lbz_le_raw gen_op_lbz_raw
9a64fbe4 1816#else
d9bce9d9 1817#if defined(TARGET_PPC64)
9a64fbe4
FB
1818#define OP_LD_TABLE(width) \
1819static GenOpFunc *gen_op_l##width[] = { \
1820 &gen_op_l##width##_user, \
111bfab3 1821 &gen_op_l##width##_le_user, \
9a64fbe4 1822 &gen_op_l##width##_kernel, \
111bfab3 1823 &gen_op_l##width##_le_kernel, \
d9bce9d9
JM
1824 &gen_op_l##width##_64_user, \
1825 &gen_op_l##width##_le_64_user, \
1826 &gen_op_l##width##_64_kernel, \
1827 &gen_op_l##width##_le_64_kernel, \
111bfab3 1828};
9a64fbe4
FB
1829#define OP_ST_TABLE(width) \
1830static GenOpFunc *gen_op_st##width[] = { \
1831 &gen_op_st##width##_user, \
111bfab3 1832 &gen_op_st##width##_le_user, \
9a64fbe4 1833 &gen_op_st##width##_kernel, \
111bfab3 1834 &gen_op_st##width##_le_kernel, \
d9bce9d9
JM
1835 &gen_op_st##width##_64_user, \
1836 &gen_op_st##width##_le_64_user, \
1837 &gen_op_st##width##_64_kernel, \
1838 &gen_op_st##width##_le_64_kernel, \
111bfab3
FB
1839};
1840/* Byte access routine are endian safe */
d9bce9d9
JM
1841#define gen_op_stb_le_64_user gen_op_stb_64_user
1842#define gen_op_lbz_le_64_user gen_op_lbz_64_user
1843#define gen_op_stb_le_64_kernel gen_op_stb_64_kernel
1844#define gen_op_lbz_le_64_kernel gen_op_lbz_64_kernel
1845#else
1846#define OP_LD_TABLE(width) \
1847static GenOpFunc *gen_op_l##width[] = { \
1848 &gen_op_l##width##_user, \
1849 &gen_op_l##width##_le_user, \
1850 &gen_op_l##width##_kernel, \
1851 &gen_op_l##width##_le_kernel, \
1852};
1853#define OP_ST_TABLE(width) \
1854static GenOpFunc *gen_op_st##width[] = { \
1855 &gen_op_st##width##_user, \
1856 &gen_op_st##width##_le_user, \
1857 &gen_op_st##width##_kernel, \
1858 &gen_op_st##width##_le_kernel, \
1859};
1860#endif
1861/* Byte access routine are endian safe */
111bfab3
FB
1862#define gen_op_stb_le_user gen_op_stb_user
1863#define gen_op_lbz_le_user gen_op_lbz_user
1864#define gen_op_stb_le_kernel gen_op_stb_kernel
1865#define gen_op_lbz_le_kernel gen_op_lbz_kernel
9a64fbe4
FB
1866#endif
1867
d9bce9d9
JM
1868#define GEN_LD(width, opc, type) \
1869GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, type) \
79aceca5 1870{ \
9d53c753 1871 gen_addr_imm_index(ctx, 0); \
9a64fbe4 1872 op_ldst(l##width); \
79aceca5 1873 gen_op_store_T1_gpr(rD(ctx->opcode)); \
79aceca5
FB
1874}
1875
d9bce9d9
JM
1876#define GEN_LDU(width, opc, type) \
1877GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, type) \
79aceca5 1878{ \
76a66253
JM
1879 if (unlikely(rA(ctx->opcode) == 0 || \
1880 rA(ctx->opcode) == rD(ctx->opcode))) { \
9fddaa0c
FB
1881 RET_INVAL(ctx); \
1882 return; \
9a64fbe4 1883 } \
9d53c753
JM
1884 if (type == PPC_64B) \
1885 gen_addr_imm_index(ctx, 1); \
1886 else \
1887 gen_addr_imm_index(ctx, 0); \
9a64fbe4 1888 op_ldst(l##width); \
79aceca5
FB
1889 gen_op_store_T1_gpr(rD(ctx->opcode)); \
1890 gen_op_store_T0_gpr(rA(ctx->opcode)); \
79aceca5
FB
1891}
1892
d9bce9d9
JM
1893#define GEN_LDUX(width, opc2, opc3, type) \
1894GEN_HANDLER(l##width##ux, 0x1F, opc2, opc3, 0x00000001, type) \
79aceca5 1895{ \
76a66253
JM
1896 if (unlikely(rA(ctx->opcode) == 0 || \
1897 rA(ctx->opcode) == rD(ctx->opcode))) { \
9fddaa0c
FB
1898 RET_INVAL(ctx); \
1899 return; \
9a64fbe4 1900 } \
76a66253 1901 gen_addr_reg_index(ctx); \
9a64fbe4 1902 op_ldst(l##width); \
79aceca5
FB
1903 gen_op_store_T1_gpr(rD(ctx->opcode)); \
1904 gen_op_store_T0_gpr(rA(ctx->opcode)); \
79aceca5
FB
1905}
1906
d9bce9d9
JM
1907#define GEN_LDX(width, opc2, opc3, type) \
1908GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, type) \
79aceca5 1909{ \
76a66253 1910 gen_addr_reg_index(ctx); \
9a64fbe4 1911 op_ldst(l##width); \
79aceca5 1912 gen_op_store_T1_gpr(rD(ctx->opcode)); \
79aceca5
FB
1913}
1914
d9bce9d9 1915#define GEN_LDS(width, op, type) \
9a64fbe4 1916OP_LD_TABLE(width); \
d9bce9d9
JM
1917GEN_LD(width, op | 0x20, type); \
1918GEN_LDU(width, op | 0x21, type); \
1919GEN_LDUX(width, 0x17, op | 0x01, type); \
1920GEN_LDX(width, 0x17, op | 0x00, type)
79aceca5
FB
1921
1922/* lbz lbzu lbzux lbzx */
d9bce9d9 1923GEN_LDS(bz, 0x02, PPC_INTEGER);
79aceca5 1924/* lha lhau lhaux lhax */
d9bce9d9 1925GEN_LDS(ha, 0x0A, PPC_INTEGER);
79aceca5 1926/* lhz lhzu lhzux lhzx */
d9bce9d9 1927GEN_LDS(hz, 0x08, PPC_INTEGER);
79aceca5 1928/* lwz lwzu lwzux lwzx */
d9bce9d9
JM
1929GEN_LDS(wz, 0x00, PPC_INTEGER);
1930#if defined(TARGET_PPC64)
1931OP_LD_TABLE(wa);
1932OP_LD_TABLE(d);
1933/* lwaux */
1934GEN_LDUX(wa, 0x15, 0x0B, PPC_64B);
1935/* lwax */
1936GEN_LDX(wa, 0x15, 0x0A, PPC_64B);
1937/* ldux */
1938GEN_LDUX(d, 0x15, 0x01, PPC_64B);
1939/* ldx */
1940GEN_LDX(d, 0x15, 0x00, PPC_64B);
1941GEN_HANDLER(ld, 0x3A, 0xFF, 0xFF, 0x00000000, PPC_64B)
1942{
1943 if (Rc(ctx->opcode)) {
1944 if (unlikely(rA(ctx->opcode) == 0 ||
1945 rA(ctx->opcode) == rD(ctx->opcode))) {
1946 RET_INVAL(ctx);
1947 return;
1948 }
1949 }
9d53c753 1950 gen_addr_imm_index(ctx, 1);
d9bce9d9
JM
1951 if (ctx->opcode & 0x02) {
1952 /* lwa (lwau is undefined) */
1953 op_ldst(lwa);
1954 } else {
1955 /* ld - ldu */
1956 op_ldst(ld);
1957 }
1958 gen_op_store_T1_gpr(rD(ctx->opcode));
1959 if (Rc(ctx->opcode))
1960 gen_op_store_T0_gpr(rA(ctx->opcode));
1961}
1962#endif
79aceca5
FB
1963
1964/*** Integer store ***/
d9bce9d9
JM
1965#define GEN_ST(width, opc, type) \
1966GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, type) \
79aceca5 1967{ \
9d53c753 1968 gen_addr_imm_index(ctx, 0); \
9a64fbe4
FB
1969 gen_op_load_gpr_T1(rS(ctx->opcode)); \
1970 op_ldst(st##width); \
79aceca5
FB
1971}
1972
d9bce9d9
JM
1973#define GEN_STU(width, opc, type) \
1974GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, type) \
79aceca5 1975{ \
76a66253 1976 if (unlikely(rA(ctx->opcode) == 0)) { \
9fddaa0c
FB
1977 RET_INVAL(ctx); \
1978 return; \
9a64fbe4 1979 } \
9d53c753
JM
1980 if (type == PPC_64B) \
1981 gen_addr_imm_index(ctx, 1); \
1982 else \
1983 gen_addr_imm_index(ctx, 0); \
79aceca5 1984 gen_op_load_gpr_T1(rS(ctx->opcode)); \
9a64fbe4 1985 op_ldst(st##width); \
79aceca5 1986 gen_op_store_T0_gpr(rA(ctx->opcode)); \
79aceca5
FB
1987}
1988
d9bce9d9
JM
1989#define GEN_STUX(width, opc2, opc3, type) \
1990GEN_HANDLER(st##width##ux, 0x1F, opc2, opc3, 0x00000001, type) \
79aceca5 1991{ \
76a66253 1992 if (unlikely(rA(ctx->opcode) == 0)) { \
9fddaa0c
FB
1993 RET_INVAL(ctx); \
1994 return; \
9a64fbe4 1995 } \
76a66253 1996 gen_addr_reg_index(ctx); \
9a64fbe4
FB
1997 gen_op_load_gpr_T1(rS(ctx->opcode)); \
1998 op_ldst(st##width); \
79aceca5 1999 gen_op_store_T0_gpr(rA(ctx->opcode)); \
79aceca5
FB
2000}
2001
d9bce9d9
JM
2002#define GEN_STX(width, opc2, opc3, type) \
2003GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, type) \
79aceca5 2004{ \
76a66253 2005 gen_addr_reg_index(ctx); \
9a64fbe4
FB
2006 gen_op_load_gpr_T1(rS(ctx->opcode)); \
2007 op_ldst(st##width); \
79aceca5
FB
2008}
2009
d9bce9d9 2010#define GEN_STS(width, op, type) \
9a64fbe4 2011OP_ST_TABLE(width); \
d9bce9d9
JM
2012GEN_ST(width, op | 0x20, type); \
2013GEN_STU(width, op | 0x21, type); \
2014GEN_STUX(width, 0x17, op | 0x01, type); \
2015GEN_STX(width, 0x17, op | 0x00, type)
79aceca5
FB
2016
2017/* stb stbu stbux stbx */
d9bce9d9 2018GEN_STS(b, 0x06, PPC_INTEGER);
79aceca5 2019/* sth sthu sthux sthx */
d9bce9d9 2020GEN_STS(h, 0x0C, PPC_INTEGER);
79aceca5 2021/* stw stwu stwux stwx */
d9bce9d9
JM
2022GEN_STS(w, 0x04, PPC_INTEGER);
2023#if defined(TARGET_PPC64)
2024OP_ST_TABLE(d);
426613db
JM
2025GEN_STUX(d, 0x15, 0x05, PPC_64B);
2026GEN_STX(d, 0x15, 0x04, PPC_64B);
d9bce9d9
JM
2027GEN_HANDLER(std, 0x3E, 0xFF, 0xFF, 0x00000002, PPC_64B)
2028{
2029 if (Rc(ctx->opcode)) {
2030 if (unlikely(rA(ctx->opcode) == 0)) {
2031 RET_INVAL(ctx);
2032 return;
2033 }
2034 }
9d53c753 2035 gen_addr_imm_index(ctx, 1);
d9bce9d9
JM
2036 gen_op_load_gpr_T1(rS(ctx->opcode));
2037 op_ldst(std);
2038 if (Rc(ctx->opcode))
2039 gen_op_store_T0_gpr(rA(ctx->opcode));
2040}
2041#endif
79aceca5
FB
2042/*** Integer load and store with byte reverse ***/
2043/* lhbrx */
9a64fbe4 2044OP_LD_TABLE(hbr);
d9bce9d9 2045GEN_LDX(hbr, 0x16, 0x18, PPC_INTEGER);
79aceca5 2046/* lwbrx */
9a64fbe4 2047OP_LD_TABLE(wbr);
d9bce9d9 2048GEN_LDX(wbr, 0x16, 0x10, PPC_INTEGER);
79aceca5 2049/* sthbrx */
9a64fbe4 2050OP_ST_TABLE(hbr);
d9bce9d9 2051GEN_STX(hbr, 0x16, 0x1C, PPC_INTEGER);
79aceca5 2052/* stwbrx */
9a64fbe4 2053OP_ST_TABLE(wbr);
d9bce9d9 2054GEN_STX(wbr, 0x16, 0x14, PPC_INTEGER);
79aceca5
FB
2055
2056/*** Integer load and store multiple ***/
111bfab3 2057#define op_ldstm(name, reg) (*gen_op_##name[ctx->mem_idx])(reg)
d9bce9d9
JM
2058#if defined(TARGET_PPC64)
2059#if defined(CONFIG_USER_ONLY)
2060static GenOpFunc1 *gen_op_lmw[] = {
2061 &gen_op_lmw_raw,
2062 &gen_op_lmw_le_raw,
2063 &gen_op_lmw_64_raw,
2064 &gen_op_lmw_le_64_raw,
2065};
2066static GenOpFunc1 *gen_op_stmw[] = {
2067 &gen_op_stmw_64_raw,
2068 &gen_op_stmw_le_64_raw,
2069};
2070#else
2071static GenOpFunc1 *gen_op_lmw[] = {
2072 &gen_op_lmw_user,
2073 &gen_op_lmw_le_user,
2074 &gen_op_lmw_kernel,
2075 &gen_op_lmw_le_kernel,
2076 &gen_op_lmw_64_user,
2077 &gen_op_lmw_le_64_user,
2078 &gen_op_lmw_64_kernel,
2079 &gen_op_lmw_le_64_kernel,
2080};
2081static GenOpFunc1 *gen_op_stmw[] = {
2082 &gen_op_stmw_user,
2083 &gen_op_stmw_le_user,
2084 &gen_op_stmw_kernel,
2085 &gen_op_stmw_le_kernel,
2086 &gen_op_stmw_64_user,
2087 &gen_op_stmw_le_64_user,
2088 &gen_op_stmw_64_kernel,
2089 &gen_op_stmw_le_64_kernel,
2090};
2091#endif
2092#else
9a64fbe4 2093#if defined(CONFIG_USER_ONLY)
111bfab3
FB
2094static GenOpFunc1 *gen_op_lmw[] = {
2095 &gen_op_lmw_raw,
2096 &gen_op_lmw_le_raw,
2097};
2098static GenOpFunc1 *gen_op_stmw[] = {
2099 &gen_op_stmw_raw,
2100 &gen_op_stmw_le_raw,
2101};
9a64fbe4 2102#else
9a64fbe4
FB
2103static GenOpFunc1 *gen_op_lmw[] = {
2104 &gen_op_lmw_user,
111bfab3 2105 &gen_op_lmw_le_user,
9a64fbe4 2106 &gen_op_lmw_kernel,
111bfab3 2107 &gen_op_lmw_le_kernel,
9a64fbe4
FB
2108};
2109static GenOpFunc1 *gen_op_stmw[] = {
2110 &gen_op_stmw_user,
111bfab3 2111 &gen_op_stmw_le_user,
9a64fbe4 2112 &gen_op_stmw_kernel,
111bfab3 2113 &gen_op_stmw_le_kernel,
9a64fbe4
FB
2114};
2115#endif
d9bce9d9 2116#endif
9a64fbe4 2117
79aceca5
FB
2118/* lmw */
2119GEN_HANDLER(lmw, 0x2E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
2120{
76a66253 2121 /* NIP cannot be restored if the memory exception comes from an helper */
d9bce9d9 2122 gen_update_nip(ctx, ctx->nip - 4);
9d53c753 2123 gen_addr_imm_index(ctx, 0);
9a64fbe4 2124 op_ldstm(lmw, rD(ctx->opcode));
79aceca5
FB
2125}
2126
2127/* stmw */
2128GEN_HANDLER(stmw, 0x2F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
2129{
76a66253 2130 /* NIP cannot be restored if the memory exception comes from an helper */
d9bce9d9 2131 gen_update_nip(ctx, ctx->nip - 4);
9d53c753 2132 gen_addr_imm_index(ctx, 0);
9a64fbe4 2133 op_ldstm(stmw, rS(ctx->opcode));
79aceca5
FB
2134}
2135
2136/*** Integer load and store strings ***/
9a64fbe4
FB
2137#define op_ldsts(name, start) (*gen_op_##name[ctx->mem_idx])(start)
2138#define op_ldstsx(name, rd, ra, rb) (*gen_op_##name[ctx->mem_idx])(rd, ra, rb)
d9bce9d9
JM
2139#if defined(TARGET_PPC64)
2140#if defined(CONFIG_USER_ONLY)
2141static GenOpFunc1 *gen_op_lswi[] = {
2142 &gen_op_lswi_raw,
2143 &gen_op_lswi_le_raw,
2144 &gen_op_lswi_64_raw,
2145 &gen_op_lswi_le_64_raw,
2146};
2147static GenOpFunc3 *gen_op_lswx[] = {
2148 &gen_op_lswx_raw,
2149 &gen_op_lswx_le_raw,
2150 &gen_op_lswx_64_raw,
2151 &gen_op_lswx_le_64_raw,
2152};
2153static GenOpFunc1 *gen_op_stsw[] = {
2154 &gen_op_stsw_raw,
2155 &gen_op_stsw_le_raw,
2156 &gen_op_stsw_64_raw,
2157 &gen_op_stsw_le_64_raw,
2158};
2159#else
2160static GenOpFunc1 *gen_op_lswi[] = {
2161 &gen_op_lswi_user,
2162 &gen_op_lswi_le_user,
2163 &gen_op_lswi_kernel,
2164 &gen_op_lswi_le_kernel,
2165 &gen_op_lswi_64_user,
2166 &gen_op_lswi_le_64_user,
2167 &gen_op_lswi_64_kernel,
2168 &gen_op_lswi_le_64_kernel,
2169};
2170static GenOpFunc3 *gen_op_lswx[] = {
2171 &gen_op_lswx_user,
2172 &gen_op_lswx_le_user,
2173 &gen_op_lswx_kernel,
2174 &gen_op_lswx_le_kernel,
2175 &gen_op_lswx_64_user,
2176 &gen_op_lswx_le_64_user,
2177 &gen_op_lswx_64_kernel,
2178 &gen_op_lswx_le_64_kernel,
2179};
2180static GenOpFunc1 *gen_op_stsw[] = {
2181 &gen_op_stsw_user,
2182 &gen_op_stsw_le_user,
2183 &gen_op_stsw_kernel,
2184 &gen_op_stsw_le_kernel,
2185 &gen_op_stsw_64_user,
2186 &gen_op_stsw_le_64_user,
2187 &gen_op_stsw_64_kernel,
2188 &gen_op_stsw_le_64_kernel,
2189};
2190#endif
2191#else
111bfab3
FB
2192#if defined(CONFIG_USER_ONLY)
2193static GenOpFunc1 *gen_op_lswi[] = {
2194 &gen_op_lswi_raw,
2195 &gen_op_lswi_le_raw,
2196};
2197static GenOpFunc3 *gen_op_lswx[] = {
2198 &gen_op_lswx_raw,
2199 &gen_op_lswx_le_raw,
2200};
2201static GenOpFunc1 *gen_op_stsw[] = {
2202 &gen_op_stsw_raw,
2203 &gen_op_stsw_le_raw,
2204};
2205#else
9a64fbe4
FB
2206static GenOpFunc1 *gen_op_lswi[] = {
2207 &gen_op_lswi_user,
111bfab3 2208 &gen_op_lswi_le_user,
9a64fbe4 2209 &gen_op_lswi_kernel,
111bfab3 2210 &gen_op_lswi_le_kernel,
9a64fbe4
FB
2211};
2212static GenOpFunc3 *gen_op_lswx[] = {
2213 &gen_op_lswx_user,
111bfab3 2214 &gen_op_lswx_le_user,
9a64fbe4 2215 &gen_op_lswx_kernel,
111bfab3 2216 &gen_op_lswx_le_kernel,
9a64fbe4
FB
2217};
2218static GenOpFunc1 *gen_op_stsw[] = {
2219 &gen_op_stsw_user,
111bfab3 2220 &gen_op_stsw_le_user,
9a64fbe4 2221 &gen_op_stsw_kernel,
111bfab3 2222 &gen_op_stsw_le_kernel,
9a64fbe4
FB
2223};
2224#endif
d9bce9d9 2225#endif
9a64fbe4 2226
79aceca5 2227/* lswi */
3fc6c082 2228/* PowerPC32 specification says we must generate an exception if
9a64fbe4
FB
2229 * rA is in the range of registers to be loaded.
2230 * In an other hand, IBM says this is valid, but rA won't be loaded.
2231 * For now, I'll follow the spec...
2232 */
79aceca5
FB
2233GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_INTEGER)
2234{
2235 int nb = NB(ctx->opcode);
2236 int start = rD(ctx->opcode);
9a64fbe4 2237 int ra = rA(ctx->opcode);
79aceca5
FB
2238 int nr;
2239
2240 if (nb == 0)
2241 nb = 32;
2242 nr = nb / 4;
76a66253
JM
2243 if (unlikely(((start + nr) > 32 &&
2244 start <= ra && (start + nr - 32) > ra) ||
2245 ((start + nr) <= 32 && start <= ra && (start + nr) > ra))) {
9fddaa0c
FB
2246 RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX);
2247 return;
297d8e62 2248 }
8dd4983c 2249 /* NIP cannot be restored if the memory exception comes from an helper */
d9bce9d9 2250 gen_update_nip(ctx, ctx->nip - 4);
76a66253
JM
2251 gen_addr_register(ctx);
2252 gen_op_set_T1(nb);
9a64fbe4 2253 op_ldsts(lswi, start);
79aceca5
FB
2254}
2255
2256/* lswx */
2257GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001, PPC_INTEGER)
2258{
9a64fbe4
FB
2259 int ra = rA(ctx->opcode);
2260 int rb = rB(ctx->opcode);
2261
76a66253 2262 /* NIP cannot be restored if the memory exception comes from an helper */
d9bce9d9 2263 gen_update_nip(ctx, ctx->nip - 4);
76a66253 2264 gen_addr_reg_index(ctx);
9a64fbe4 2265 if (ra == 0) {
9a64fbe4 2266 ra = rb;
79aceca5 2267 }
9a64fbe4
FB
2268 gen_op_load_xer_bc();
2269 op_ldstsx(lswx, rD(ctx->opcode), ra, rb);
79aceca5
FB
2270}
2271
2272/* stswi */
2273GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_INTEGER)
2274{
4b3686fa
FB
2275 int nb = NB(ctx->opcode);
2276
76a66253 2277 /* NIP cannot be restored if the memory exception comes from an helper */
d9bce9d9 2278 gen_update_nip(ctx, ctx->nip - 4);
76a66253 2279 gen_addr_register(ctx);
4b3686fa
FB
2280 if (nb == 0)
2281 nb = 32;
2282 gen_op_set_T1(nb);
9a64fbe4 2283 op_ldsts(stsw, rS(ctx->opcode));
79aceca5
FB
2284}
2285
2286/* stswx */
2287GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_INTEGER)
2288{
8dd4983c 2289 /* NIP cannot be restored if the memory exception comes from an helper */
5fafdf24 2290 gen_update_nip(ctx, ctx->nip - 4);
76a66253
JM
2291 gen_addr_reg_index(ctx);
2292 gen_op_load_xer_bc();
9a64fbe4 2293 op_ldsts(stsw, rS(ctx->opcode));
79aceca5
FB
2294}
2295
2296/*** Memory synchronisation ***/
2297/* eieio */
76a66253 2298GEN_HANDLER(eieio, 0x1F, 0x16, 0x1A, 0x03FF0801, PPC_MEM_EIEIO)
79aceca5 2299{
79aceca5
FB
2300}
2301
2302/* isync */
76a66253 2303GEN_HANDLER(isync, 0x13, 0x16, 0x04, 0x03FF0801, PPC_MEM)
79aceca5 2304{
79aceca5
FB
2305}
2306
111bfab3
FB
2307#define op_lwarx() (*gen_op_lwarx[ctx->mem_idx])()
2308#define op_stwcx() (*gen_op_stwcx[ctx->mem_idx])()
d9bce9d9 2309#if defined(TARGET_PPC64)
9a64fbe4 2310#if defined(CONFIG_USER_ONLY)
111bfab3
FB
2311static GenOpFunc *gen_op_lwarx[] = {
2312 &gen_op_lwarx_raw,
2313 &gen_op_lwarx_le_raw,
d9bce9d9
JM
2314 &gen_op_lwarx_64_raw,
2315 &gen_op_lwarx_le_64_raw,
111bfab3
FB
2316};
2317static GenOpFunc *gen_op_stwcx[] = {
2318 &gen_op_stwcx_raw,
2319 &gen_op_stwcx_le_raw,
d9bce9d9
JM
2320 &gen_op_stwcx_64_raw,
2321 &gen_op_stwcx_le_64_raw,
111bfab3 2322};
9a64fbe4 2323#else
985a19d6
FB
2324static GenOpFunc *gen_op_lwarx[] = {
2325 &gen_op_lwarx_user,
111bfab3 2326 &gen_op_lwarx_le_user,
985a19d6 2327 &gen_op_lwarx_kernel,
111bfab3 2328 &gen_op_lwarx_le_kernel,
d9bce9d9
JM
2329 &gen_op_lwarx_64_user,
2330 &gen_op_lwarx_le_64_user,
2331 &gen_op_lwarx_64_kernel,
2332 &gen_op_lwarx_le_64_kernel,
985a19d6 2333};
9a64fbe4
FB
2334static GenOpFunc *gen_op_stwcx[] = {
2335 &gen_op_stwcx_user,
111bfab3 2336 &gen_op_stwcx_le_user,
9a64fbe4 2337 &gen_op_stwcx_kernel,
111bfab3 2338 &gen_op_stwcx_le_kernel,
d9bce9d9
JM
2339 &gen_op_stwcx_64_user,
2340 &gen_op_stwcx_le_64_user,
2341 &gen_op_stwcx_64_kernel,
2342 &gen_op_stwcx_le_64_kernel,
9a64fbe4
FB
2343};
2344#endif
d9bce9d9
JM
2345#else
2346#if defined(CONFIG_USER_ONLY)
2347static GenOpFunc *gen_op_lwarx[] = {
2348 &gen_op_lwarx_raw,
2349 &gen_op_lwarx_le_raw,
2350};
2351static GenOpFunc *gen_op_stwcx[] = {
2352 &gen_op_stwcx_raw,
2353 &gen_op_stwcx_le_raw,
2354};
2355#else
2356static GenOpFunc *gen_op_lwarx[] = {
2357 &gen_op_lwarx_user,
2358 &gen_op_lwarx_le_user,
2359 &gen_op_lwarx_kernel,
2360 &gen_op_lwarx_le_kernel,
2361};
2362static GenOpFunc *gen_op_stwcx[] = {
2363 &gen_op_stwcx_user,
2364 &gen_op_stwcx_le_user,
2365 &gen_op_stwcx_kernel,
2366 &gen_op_stwcx_le_kernel,
2367};
2368#endif
2369#endif
9a64fbe4 2370
111bfab3 2371/* lwarx */
76a66253 2372GEN_HANDLER(lwarx, 0x1F, 0x14, 0x00, 0x00000001, PPC_RES)
79aceca5 2373{
76a66253 2374 gen_addr_reg_index(ctx);
985a19d6 2375 op_lwarx();
79aceca5 2376 gen_op_store_T1_gpr(rD(ctx->opcode));
79aceca5
FB
2377}
2378
2379/* stwcx. */
9a64fbe4 2380GEN_HANDLER(stwcx_, 0x1F, 0x16, 0x04, 0x00000000, PPC_RES)
79aceca5 2381{
76a66253 2382 gen_addr_reg_index(ctx);
9a64fbe4
FB
2383 gen_op_load_gpr_T1(rS(ctx->opcode));
2384 op_stwcx();
79aceca5
FB
2385}
2386
426613db
JM
2387#if defined(TARGET_PPC64)
2388#define op_ldarx() (*gen_op_ldarx[ctx->mem_idx])()
2389#define op_stdcx() (*gen_op_stdcx[ctx->mem_idx])()
2390#if defined(CONFIG_USER_ONLY)
2391static GenOpFunc *gen_op_ldarx[] = {
2392 &gen_op_ldarx_raw,
2393 &gen_op_ldarx_le_raw,
2394 &gen_op_ldarx_64_raw,
2395 &gen_op_ldarx_le_64_raw,
2396};
2397static GenOpFunc *gen_op_stdcx[] = {
2398 &gen_op_stdcx_raw,
2399 &gen_op_stdcx_le_raw,
2400 &gen_op_stdcx_64_raw,
2401 &gen_op_stdcx_le_64_raw,
2402};
2403#else
2404static GenOpFunc *gen_op_ldarx[] = {
2405 &gen_op_ldarx_user,
2406 &gen_op_ldarx_le_user,
2407 &gen_op_ldarx_kernel,
2408 &gen_op_ldarx_le_kernel,
2409 &gen_op_ldarx_64_user,
2410 &gen_op_ldarx_le_64_user,
2411 &gen_op_ldarx_64_kernel,
2412 &gen_op_ldarx_le_64_kernel,
2413};
2414static GenOpFunc *gen_op_stdcx[] = {
2415 &gen_op_stdcx_user,
2416 &gen_op_stdcx_le_user,
2417 &gen_op_stdcx_kernel,
2418 &gen_op_stdcx_le_kernel,
2419 &gen_op_stdcx_64_user,
2420 &gen_op_stdcx_le_64_user,
2421 &gen_op_stdcx_64_kernel,
2422 &gen_op_stdcx_le_64_kernel,
2423};
2424#endif
2425
2426/* ldarx */
2427GEN_HANDLER(ldarx, 0x1F, 0x14, 0x02, 0x00000001, PPC_RES)
2428{
2429 gen_addr_reg_index(ctx);
2430 op_ldarx();
2431 gen_op_store_T1_gpr(rD(ctx->opcode));
2432}
2433
2434/* stdcx. */
2435GEN_HANDLER(stdcx_, 0x1F, 0x16, 0x06, 0x00000000, PPC_RES)
2436{
2437 gen_addr_reg_index(ctx);
2438 gen_op_load_gpr_T1(rS(ctx->opcode));
2439 op_stdcx();
2440}
2441#endif /* defined(TARGET_PPC64) */
2442
79aceca5 2443/* sync */
76a66253 2444GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_MEM_SYNC)
79aceca5 2445{
79aceca5
FB
2446}
2447
2448/*** Floating-point load ***/
9a64fbe4 2449#define GEN_LDF(width, opc) \
c7d344af 2450GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
79aceca5 2451{ \
76a66253 2452 if (unlikely(!ctx->fpu_enabled)) { \
4ecc3190
FB
2453 RET_EXCP(ctx, EXCP_NO_FP, 0); \
2454 return; \
2455 } \
9d53c753 2456 gen_addr_imm_index(ctx, 0); \
9a64fbe4 2457 op_ldst(l##width); \
76a66253 2458 gen_op_store_FT0_fpr(rD(ctx->opcode)); \
79aceca5
FB
2459}
2460
9a64fbe4 2461#define GEN_LDUF(width, opc) \
c7d344af 2462GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
79aceca5 2463{ \
76a66253 2464 if (unlikely(!ctx->fpu_enabled)) { \
4ecc3190
FB
2465 RET_EXCP(ctx, EXCP_NO_FP, 0); \
2466 return; \
2467 } \
76a66253 2468 if (unlikely(rA(ctx->opcode) == 0)) { \
9fddaa0c
FB
2469 RET_INVAL(ctx); \
2470 return; \
9a64fbe4 2471 } \
9d53c753 2472 gen_addr_imm_index(ctx, 0); \
9a64fbe4 2473 op_ldst(l##width); \
76a66253 2474 gen_op_store_FT0_fpr(rD(ctx->opcode)); \
79aceca5 2475 gen_op_store_T0_gpr(rA(ctx->opcode)); \
79aceca5
FB
2476}
2477
9a64fbe4 2478#define GEN_LDUXF(width, opc) \
c7d344af 2479GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \
79aceca5 2480{ \
76a66253 2481 if (unlikely(!ctx->fpu_enabled)) { \
4ecc3190
FB
2482 RET_EXCP(ctx, EXCP_NO_FP, 0); \
2483 return; \
2484 } \
76a66253 2485 if (unlikely(rA(ctx->opcode) == 0)) { \
9fddaa0c
FB
2486 RET_INVAL(ctx); \
2487 return; \
9a64fbe4 2488 } \
76a66253 2489 gen_addr_reg_index(ctx); \
9a64fbe4 2490 op_ldst(l##width); \
76a66253 2491 gen_op_store_FT0_fpr(rD(ctx->opcode)); \
79aceca5 2492 gen_op_store_T0_gpr(rA(ctx->opcode)); \
79aceca5
FB
2493}
2494
9a64fbe4 2495#define GEN_LDXF(width, opc2, opc3) \
c7d344af 2496GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_FLOAT) \
79aceca5 2497{ \
76a66253 2498 if (unlikely(!ctx->fpu_enabled)) { \
4ecc3190
FB
2499 RET_EXCP(ctx, EXCP_NO_FP, 0); \
2500 return; \
2501 } \
76a66253 2502 gen_addr_reg_index(ctx); \
9a64fbe4 2503 op_ldst(l##width); \
76a66253 2504 gen_op_store_FT0_fpr(rD(ctx->opcode)); \
79aceca5
FB
2505}
2506
9a64fbe4
FB
2507#define GEN_LDFS(width, op) \
2508OP_LD_TABLE(width); \
2509GEN_LDF(width, op | 0x20); \
2510GEN_LDUF(width, op | 0x21); \
2511GEN_LDUXF(width, op | 0x01); \
2512GEN_LDXF(width, 0x17, op | 0x00)
79aceca5
FB
2513
2514/* lfd lfdu lfdux lfdx */
9a64fbe4 2515GEN_LDFS(fd, 0x12);
79aceca5 2516/* lfs lfsu lfsux lfsx */
9a64fbe4 2517GEN_LDFS(fs, 0x10);
79aceca5
FB
2518
2519/*** Floating-point store ***/
2520#define GEN_STF(width, opc) \
c7d344af 2521GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
79aceca5 2522{ \
76a66253 2523 if (unlikely(!ctx->fpu_enabled)) { \
4ecc3190
FB
2524 RET_EXCP(ctx, EXCP_NO_FP, 0); \
2525 return; \
2526 } \
9d53c753 2527 gen_addr_imm_index(ctx, 0); \
76a66253 2528 gen_op_load_fpr_FT0(rS(ctx->opcode)); \
9a64fbe4 2529 op_ldst(st##width); \
79aceca5
FB
2530}
2531
9a64fbe4 2532#define GEN_STUF(width, opc) \
c7d344af 2533GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
79aceca5 2534{ \
76a66253 2535 if (unlikely(!ctx->fpu_enabled)) { \
4ecc3190
FB
2536 RET_EXCP(ctx, EXCP_NO_FP, 0); \
2537 return; \
2538 } \
76a66253 2539 if (unlikely(rA(ctx->opcode) == 0)) { \
9fddaa0c
FB
2540 RET_INVAL(ctx); \
2541 return; \
9a64fbe4 2542 } \
9d53c753 2543 gen_addr_imm_index(ctx, 0); \
76a66253 2544 gen_op_load_fpr_FT0(rS(ctx->opcode)); \
9a64fbe4 2545 op_ldst(st##width); \
79aceca5 2546 gen_op_store_T0_gpr(rA(ctx->opcode)); \
79aceca5
FB
2547}
2548
9a64fbe4 2549#define GEN_STUXF(width, opc) \
c7d344af 2550GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \
79aceca5 2551{ \
76a66253 2552 if (unlikely(!ctx->fpu_enabled)) { \
4ecc3190
FB
2553 RET_EXCP(ctx, EXCP_NO_FP, 0); \
2554 return; \
2555 } \
76a66253 2556 if (unlikely(rA(ctx->opcode) == 0)) { \
9fddaa0c
FB
2557 RET_INVAL(ctx); \
2558 return; \
9a64fbe4 2559 } \
76a66253
JM
2560 gen_addr_reg_index(ctx); \
2561 gen_op_load_fpr_FT0(rS(ctx->opcode)); \
9a64fbe4 2562 op_ldst(st##width); \
79aceca5 2563 gen_op_store_T0_gpr(rA(ctx->opcode)); \
79aceca5
FB
2564}
2565
9a64fbe4 2566#define GEN_STXF(width, opc2, opc3) \
c7d344af 2567GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_FLOAT) \
79aceca5 2568{ \
76a66253 2569 if (unlikely(!ctx->fpu_enabled)) { \
4ecc3190
FB
2570 RET_EXCP(ctx, EXCP_NO_FP, 0); \
2571 return; \
2572 } \
76a66253
JM
2573 gen_addr_reg_index(ctx); \
2574 gen_op_load_fpr_FT0(rS(ctx->opcode)); \
9a64fbe4 2575 op_ldst(st##width); \
79aceca5
FB
2576}
2577
9a64fbe4
FB
2578#define GEN_STFS(width, op) \
2579OP_ST_TABLE(width); \
2580GEN_STF(width, op | 0x20); \
2581GEN_STUF(width, op | 0x21); \
2582GEN_STUXF(width, op | 0x01); \
2583GEN_STXF(width, 0x17, op | 0x00)
79aceca5
FB
2584
2585/* stfd stfdu stfdux stfdx */
9a64fbe4 2586GEN_STFS(fd, 0x16);
79aceca5 2587/* stfs stfsu stfsux stfsx */
9a64fbe4 2588GEN_STFS(fs, 0x14);
79aceca5
FB
2589
2590/* Optional: */
2591/* stfiwx */
2592GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT)
2593{
76a66253 2594 if (unlikely(!ctx->fpu_enabled)) {
3cc62370
FB
2595 RET_EXCP(ctx, EXCP_NO_FP, 0);
2596 return;
2597 }
76a66253
JM
2598 gen_addr_reg_index(ctx);
2599 /* XXX: TODO: memcpy low order 32 bits of FRP(rs) into memory */
9fddaa0c 2600 RET_INVAL(ctx);
79aceca5
FB
2601}
2602
2603/*** Branch ***/
79aceca5 2604
c1942362
FB
2605static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
2606{
2607 TranslationBlock *tb;
2608 tb = ctx->tb;
2609 if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
2610 if (n == 0)
2611 gen_op_goto_tb0(TBPARAM(tb));
2612 else
2613 gen_op_goto_tb1(TBPARAM(tb));
d9bce9d9
JM
2614 gen_set_T1(dest);
2615#if defined(TARGET_PPC64)
2616 if (ctx->sf_mode)
2617 gen_op_b_T1_64();
2618 else
2619#endif
2620 gen_op_b_T1();
c1942362 2621 gen_op_set_T0((long)tb + n);
ea4e754f
FB
2622 if (ctx->singlestep_enabled)
2623 gen_op_debug();
c1942362
FB
2624 gen_op_exit_tb();
2625 } else {
d9bce9d9
JM
2626 gen_set_T1(dest);
2627#if defined(TARGET_PPC64)
2628 if (ctx->sf_mode)
2629 gen_op_b_T1_64();
2630 else
2631#endif
2632 gen_op_b_T1();
76a66253 2633 gen_op_reset_T0();
ea4e754f
FB
2634 if (ctx->singlestep_enabled)
2635 gen_op_debug();
c1942362
FB
2636 gen_op_exit_tb();
2637 }
c53be334
FB
2638}
2639
79aceca5
FB
2640/* b ba bl bla */
2641GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
2642{
76a66253 2643 target_ulong li, target;
38a64f9d
FB
2644
2645 /* sign extend LI */
76a66253 2646#if defined(TARGET_PPC64)
d9bce9d9
JM
2647 if (ctx->sf_mode)
2648 li = ((int64_t)LI(ctx->opcode) << 38) >> 38;
2649 else
76a66253 2650#endif
d9bce9d9 2651 li = ((int32_t)LI(ctx->opcode) << 6) >> 6;
76a66253 2652 if (likely(AA(ctx->opcode) == 0))
046d6672 2653 target = ctx->nip + li - 4;
79aceca5 2654 else
9a64fbe4 2655 target = li;
9a64fbe4 2656 if (LK(ctx->opcode)) {
d9bce9d9
JM
2657#if defined(TARGET_PPC64)
2658 if (ctx->sf_mode)
2659 gen_op_setlr_64(ctx->nip >> 32, ctx->nip);
2660 else
2661#endif
2662 gen_op_setlr(ctx->nip);
9a64fbe4 2663 }
c1942362 2664 gen_goto_tb(ctx, 0, target);
9a64fbe4 2665 ctx->exception = EXCP_BRANCH;
79aceca5
FB
2666}
2667
e98a6e40
FB
2668#define BCOND_IM 0
2669#define BCOND_LR 1
2670#define BCOND_CTR 2
2671
d9bce9d9
JM
2672static inline void gen_bcond(DisasContext *ctx, int type)
2673{
76a66253
JM
2674 target_ulong target = 0;
2675 target_ulong li;
d9bce9d9
JM
2676 uint32_t bo = BO(ctx->opcode);
2677 uint32_t bi = BI(ctx->opcode);
2678 uint32_t mask;
e98a6e40 2679
e98a6e40 2680 if ((bo & 0x4) == 0)
d9bce9d9 2681 gen_op_dec_ctr();
e98a6e40
FB
2682 switch(type) {
2683 case BCOND_IM:
76a66253
JM
2684 li = (target_long)((int16_t)(BD(ctx->opcode)));
2685 if (likely(AA(ctx->opcode) == 0)) {
046d6672 2686 target = ctx->nip + li - 4;
e98a6e40
FB
2687 } else {
2688 target = li;
2689 }
2690 break;
2691 case BCOND_CTR:
2692 gen_op_movl_T1_ctr();
2693 break;
2694 default:
2695 case BCOND_LR:
2696 gen_op_movl_T1_lr();
2697 break;
2698 }
d9bce9d9
JM
2699 if (LK(ctx->opcode)) {
2700#if defined(TARGET_PPC64)
2701 if (ctx->sf_mode)
2702 gen_op_setlr_64(ctx->nip >> 32, ctx->nip);
2703 else
2704#endif
2705 gen_op_setlr(ctx->nip);
e98a6e40
FB
2706 }
2707 if (bo & 0x10) {
d9bce9d9
JM
2708 /* No CR condition */
2709 switch (bo & 0x6) {
2710 case 0:
2711#if defined(TARGET_PPC64)
2712 if (ctx->sf_mode)
2713 gen_op_test_ctr_64();
2714 else
2715#endif
2716 gen_op_test_ctr();
2717 break;
2718 case 2:
2719#if defined(TARGET_PPC64)
2720 if (ctx->sf_mode)
2721 gen_op_test_ctrz_64();
2722 else
2723#endif
2724 gen_op_test_ctrz();
e98a6e40 2725 break;
e98a6e40 2726 default:
d9bce9d9
JM
2727 case 4:
2728 case 6:
e98a6e40 2729 if (type == BCOND_IM) {
c1942362 2730 gen_goto_tb(ctx, 0, target);
e98a6e40 2731 } else {
d9bce9d9
JM
2732#if defined(TARGET_PPC64)
2733 if (ctx->sf_mode)
2734 gen_op_b_T1_64();
2735 else
2736#endif
2737 gen_op_b_T1();
76a66253 2738 gen_op_reset_T0();
e98a6e40
FB
2739 }
2740 goto no_test;
2741 }
d9bce9d9
JM
2742 } else {
2743 mask = 1 << (3 - (bi & 0x03));
2744 gen_op_load_crf_T0(bi >> 2);
2745 if (bo & 0x8) {
2746 switch (bo & 0x6) {
2747 case 0:
2748#if defined(TARGET_PPC64)
2749 if (ctx->sf_mode)
2750 gen_op_test_ctr_true_64(mask);
2751 else
2752#endif
2753 gen_op_test_ctr_true(mask);
2754 break;
2755 case 2:
2756#if defined(TARGET_PPC64)
2757 if (ctx->sf_mode)
2758 gen_op_test_ctrz_true_64(mask);
2759 else
2760#endif
2761 gen_op_test_ctrz_true(mask);
2762 break;
2763 default:
2764 case 4:
2765 case 6:
e98a6e40 2766 gen_op_test_true(mask);
d9bce9d9
JM
2767 break;
2768 }
2769 } else {
2770 switch (bo & 0x6) {
2771 case 0:
2772#if defined(TARGET_PPC64)
2773 if (ctx->sf_mode)
2774 gen_op_test_ctr_false_64(mask);
2775 else
2776#endif
2777 gen_op_test_ctr_false(mask);
3b46e624 2778 break;
d9bce9d9
JM
2779 case 2:
2780#if defined(TARGET_PPC64)
2781 if (ctx->sf_mode)
2782 gen_op_test_ctrz_false_64(mask);
2783 else
2784#endif
2785 gen_op_test_ctrz_false(mask);
2786 break;
e98a6e40 2787 default:
d9bce9d9
JM
2788 case 4:
2789 case 6:
e98a6e40 2790 gen_op_test_false(mask);
d9bce9d9
JM
2791 break;
2792 }
2793 }
2794 }
e98a6e40 2795 if (type == BCOND_IM) {
c53be334
FB
2796 int l1 = gen_new_label();
2797 gen_op_jz_T0(l1);
c1942362 2798 gen_goto_tb(ctx, 0, target);
c53be334 2799 gen_set_label(l1);
c1942362 2800 gen_goto_tb(ctx, 1, ctx->nip);
e98a6e40 2801 } else {
d9bce9d9
JM
2802#if defined(TARGET_PPC64)
2803 if (ctx->sf_mode)
2804 gen_op_btest_T1_64(ctx->nip >> 32, ctx->nip);
2805 else
2806#endif
2807 gen_op_btest_T1(ctx->nip);
76a66253 2808 gen_op_reset_T0();
e98a6e40 2809 no_test:
08e46e54
JM
2810 if (ctx->singlestep_enabled)
2811 gen_op_debug();
2812 gen_op_exit_tb();
2813 }
d9bce9d9 2814 ctx->exception = EXCP_BRANCH;
e98a6e40
FB
2815}
2816
2817GEN_HANDLER(bc, 0x10, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
3b46e624 2818{
e98a6e40
FB
2819 gen_bcond(ctx, BCOND_IM);
2820}
2821
2822GEN_HANDLER(bcctr, 0x13, 0x10, 0x10, 0x00000000, PPC_FLOW)
3b46e624 2823{
e98a6e40
FB
2824 gen_bcond(ctx, BCOND_CTR);
2825}
2826
2827GEN_HANDLER(bclr, 0x13, 0x10, 0x00, 0x00000000, PPC_FLOW)
3b46e624 2828{
e98a6e40
FB
2829 gen_bcond(ctx, BCOND_LR);
2830}
79aceca5
FB
2831
2832/*** Condition register logical ***/
2833#define GEN_CRLOGIC(op, opc) \
2834GEN_HANDLER(cr##op, 0x13, 0x01, opc, 0x00000001, PPC_INTEGER) \
2835{ \
2836 gen_op_load_crf_T0(crbA(ctx->opcode) >> 2); \
2837 gen_op_getbit_T0(3 - (crbA(ctx->opcode) & 0x03)); \
2838 gen_op_load_crf_T1(crbB(ctx->opcode) >> 2); \
2839 gen_op_getbit_T1(3 - (crbB(ctx->opcode) & 0x03)); \
2840 gen_op_##op(); \
2841 gen_op_load_crf_T1(crbD(ctx->opcode) >> 2); \
2842 gen_op_setcrfbit(~(1 << (3 - (crbD(ctx->opcode) & 0x03))), \
2843 3 - (crbD(ctx->opcode) & 0x03)); \
2844 gen_op_store_T1_crf(crbD(ctx->opcode) >> 2); \
79aceca5
FB
2845}
2846
2847/* crand */
76a66253 2848GEN_CRLOGIC(and, 0x08);
79aceca5 2849/* crandc */
76a66253 2850GEN_CRLOGIC(andc, 0x04);
79aceca5 2851/* creqv */
76a66253 2852GEN_CRLOGIC(eqv, 0x09);
79aceca5 2853/* crnand */
76a66253 2854GEN_CRLOGIC(nand, 0x07);
79aceca5 2855/* crnor */
76a66253 2856GEN_CRLOGIC(nor, 0x01);
79aceca5 2857/* cror */
76a66253 2858GEN_CRLOGIC(or, 0x0E);
79aceca5 2859/* crorc */
76a66253 2860GEN_CRLOGIC(orc, 0x0D);
79aceca5 2861/* crxor */
76a66253 2862GEN_CRLOGIC(xor, 0x06);
79aceca5
FB
2863/* mcrf */
2864GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER)
2865{
2866 gen_op_load_crf_T0(crfS(ctx->opcode));
2867 gen_op_store_T0_crf(crfD(ctx->opcode));
79aceca5
FB
2868}
2869
2870/*** System linkage ***/
2871/* rfi (supervisor only) */
76a66253 2872GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW)
79aceca5 2873{
9a64fbe4 2874#if defined(CONFIG_USER_ONLY)
9fddaa0c 2875 RET_PRIVOPC(ctx);
9a64fbe4
FB
2876#else
2877 /* Restore CPU state */
76a66253 2878 if (unlikely(!ctx->supervisor)) {
9fddaa0c
FB
2879 RET_PRIVOPC(ctx);
2880 return;
9a64fbe4 2881 }
a42bd6cc 2882 gen_op_rfi();
2be0071f 2883 RET_CHG_FLOW(ctx);
9a64fbe4 2884#endif
79aceca5
FB
2885}
2886
426613db
JM
2887#if defined(TARGET_PPC64)
2888GEN_HANDLER(rfid, 0x13, 0x12, 0x00, 0x03FF8001, PPC_FLOW)
2889{
2890#if defined(CONFIG_USER_ONLY)
2891 RET_PRIVOPC(ctx);
2892#else
2893 /* Restore CPU state */
2894 if (unlikely(!ctx->supervisor)) {
2895 RET_PRIVOPC(ctx);
2896 return;
2897 }
a42bd6cc 2898 gen_op_rfid();
426613db
JM
2899 RET_CHG_FLOW(ctx);
2900#endif
2901}
2902#endif
2903
79aceca5
FB
2904/* sc */
2905GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFFFFD, PPC_FLOW)
2906{
9a64fbe4 2907#if defined(CONFIG_USER_ONLY)
9fddaa0c 2908 RET_EXCP(ctx, EXCP_SYSCALL_USER, 0);
9a64fbe4 2909#else
9fddaa0c 2910 RET_EXCP(ctx, EXCP_SYSCALL, 0);
9a64fbe4 2911#endif
79aceca5
FB
2912}
2913
2914/*** Trap ***/
2915/* tw */
76a66253 2916GEN_HANDLER(tw, 0x1F, 0x04, 0x00, 0x00000001, PPC_FLOW)
79aceca5 2917{
9a64fbe4
FB
2918 gen_op_load_gpr_T0(rA(ctx->opcode));
2919 gen_op_load_gpr_T1(rB(ctx->opcode));
a0ae05aa 2920 /* Update the nip since this might generate a trap exception */
d9bce9d9 2921 gen_update_nip(ctx, ctx->nip);
9a64fbe4 2922 gen_op_tw(TO(ctx->opcode));
79aceca5
FB
2923}
2924
2925/* twi */
2926GEN_HANDLER(twi, 0x03, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
2927{
9a64fbe4 2928 gen_op_load_gpr_T0(rA(ctx->opcode));
d9bce9d9
JM
2929 gen_set_T1(SIMM(ctx->opcode));
2930 /* Update the nip since this might generate a trap exception */
2931 gen_update_nip(ctx, ctx->nip);
76a66253 2932 gen_op_tw(TO(ctx->opcode));
79aceca5
FB
2933}
2934
d9bce9d9
JM
2935#if defined(TARGET_PPC64)
2936/* td */
2937GEN_HANDLER(td, 0x1F, 0x04, 0x02, 0x00000001, PPC_64B)
2938{
2939 gen_op_load_gpr_T0(rA(ctx->opcode));
2940 gen_op_load_gpr_T1(rB(ctx->opcode));
2941 /* Update the nip since this might generate a trap exception */
2942 gen_update_nip(ctx, ctx->nip);
2943 gen_op_td(TO(ctx->opcode));
2944}
2945
2946/* tdi */
2947GEN_HANDLER(tdi, 0x02, 0xFF, 0xFF, 0x00000000, PPC_64B)
2948{
2949 gen_op_load_gpr_T0(rA(ctx->opcode));
2950 gen_set_T1(SIMM(ctx->opcode));
2951 /* Update the nip since this might generate a trap exception */
2952 gen_update_nip(ctx, ctx->nip);
2953 gen_op_td(TO(ctx->opcode));
2954}
2955#endif
2956
79aceca5 2957/*** Processor control ***/
79aceca5
FB
2958/* mcrxr */
2959GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC)
2960{
2961 gen_op_load_xer_cr();
2962 gen_op_store_T0_crf(crfD(ctx->opcode));
e864cabd
JM
2963 gen_op_clear_xer_ov();
2964 gen_op_clear_xer_ca();
79aceca5
FB
2965}
2966
2967/* mfcr */
76a66253 2968GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x00000801, PPC_MISC)
79aceca5 2969{
76a66253 2970 uint32_t crm, crn;
3b46e624 2971
76a66253
JM
2972 if (likely(ctx->opcode & 0x00100000)) {
2973 crm = CRM(ctx->opcode);
2974 if (likely((crm ^ (crm - 1)) == 0)) {
2975 crn = ffs(crm);
2976 gen_op_load_cro(7 - crn);
2977 }
d9bce9d9
JM
2978 } else {
2979 gen_op_load_cr();
2980 }
79aceca5 2981 gen_op_store_T0_gpr(rD(ctx->opcode));
79aceca5
FB
2982}
2983
2984/* mfmsr */
2985GEN_HANDLER(mfmsr, 0x1F, 0x13, 0x02, 0x001FF801, PPC_MISC)
2986{
9a64fbe4 2987#if defined(CONFIG_USER_ONLY)
9fddaa0c 2988 RET_PRIVREG(ctx);
9a64fbe4 2989#else
76a66253 2990 if (unlikely(!ctx->supervisor)) {
9fddaa0c
FB
2991 RET_PRIVREG(ctx);
2992 return;
9a64fbe4 2993 }
79aceca5
FB
2994 gen_op_load_msr();
2995 gen_op_store_T0_gpr(rD(ctx->opcode));
9a64fbe4 2996#endif
79aceca5
FB
2997}
2998
3fc6c082
FB
2999#if 0
3000#define SPR_NOACCESS ((void *)(-1))
3001#else
3002static void spr_noaccess (void *opaque, int sprn)
3003{
3004 sprn = ((sprn >> 5) & 0x1F) | ((sprn & 0x1F) << 5);
3005 printf("ERROR: try to access SPR %d !\n", sprn);
3006}
3007#define SPR_NOACCESS (&spr_noaccess)
3008#endif
3009
79aceca5 3010/* mfspr */
3fc6c082 3011static inline void gen_op_mfspr (DisasContext *ctx)
79aceca5 3012{
3fc6c082 3013 void (*read_cb)(void *opaque, int sprn);
79aceca5
FB
3014 uint32_t sprn = SPR(ctx->opcode);
3015
3fc6c082
FB
3016#if !defined(CONFIG_USER_ONLY)
3017 if (ctx->supervisor)
3018 read_cb = ctx->spr_cb[sprn].oea_read;
3019 else
9a64fbe4 3020#endif
3fc6c082 3021 read_cb = ctx->spr_cb[sprn].uea_read;
76a66253
JM
3022 if (likely(read_cb != NULL)) {
3023 if (likely(read_cb != SPR_NOACCESS)) {
3fc6c082
FB
3024 (*read_cb)(ctx, sprn);
3025 gen_op_store_T0_gpr(rD(ctx->opcode));
3026 } else {
3027 /* Privilege exception */
4a057712 3028 if (loglevel != 0) {
7f75ffd3 3029 fprintf(logfile, "Trying to read privileged spr %d %03x\n",
f24e5695
FB
3030 sprn, sprn);
3031 }
7f75ffd3 3032 printf("Trying to read privileged spr %d %03x\n", sprn, sprn);
76a66253 3033 RET_PRIVREG(ctx);
79aceca5 3034 }
3fc6c082
FB
3035 } else {
3036 /* Not defined */
4a057712 3037 if (loglevel != 0) {
f24e5695
FB
3038 fprintf(logfile, "Trying to read invalid spr %d %03x\n",
3039 sprn, sprn);
3040 }
3fc6c082
FB
3041 printf("Trying to read invalid spr %d %03x\n", sprn, sprn);
3042 RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
79aceca5 3043 }
79aceca5
FB
3044}
3045
3fc6c082 3046GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC)
79aceca5 3047{
3fc6c082 3048 gen_op_mfspr(ctx);
76a66253 3049}
3fc6c082
FB
3050
3051/* mftb */
3052GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_TB)
3053{
3054 gen_op_mfspr(ctx);
79aceca5
FB
3055}
3056
3057/* mtcrf */
8dd4983c 3058GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00000801, PPC_MISC)
79aceca5 3059{
76a66253 3060 uint32_t crm, crn;
3b46e624 3061
79aceca5 3062 gen_op_load_gpr_T0(rS(ctx->opcode));
76a66253
JM
3063 crm = CRM(ctx->opcode);
3064 if (likely((ctx->opcode & 0x00100000) || (crm ^ (crm - 1)) == 0)) {
3065 crn = ffs(crm);
3066 gen_op_srli_T0(crn * 4);
3067 gen_op_andi_T0(0xF);
3068 gen_op_store_cro(7 - crn);
3069 } else {
3070 gen_op_store_cr(crm);
3071 }
79aceca5
FB
3072}
3073
3074/* mtmsr */
426613db
JM
3075#if defined(TARGET_PPC64)
3076GEN_HANDLER(mtmsrd, 0x1F, 0x12, 0x05, 0x001FF801, PPC_MISC)
3077{
3078#if defined(CONFIG_USER_ONLY)
3079 RET_PRIVREG(ctx);
3080#else
3081 if (unlikely(!ctx->supervisor)) {
3082 RET_PRIVREG(ctx);
3083 return;
3084 }
3085 gen_update_nip(ctx, ctx->nip);
3086 gen_op_load_gpr_T0(rS(ctx->opcode));
3087 gen_op_store_msr();
3088 /* Must stop the translation as machine state (may have) changed */
3089 RET_CHG_FLOW(ctx);
3090#endif
3091}
3092#endif
3093
79aceca5
FB
3094GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC)
3095{
9a64fbe4 3096#if defined(CONFIG_USER_ONLY)
9fddaa0c 3097 RET_PRIVREG(ctx);
9a64fbe4 3098#else
76a66253 3099 if (unlikely(!ctx->supervisor)) {
9fddaa0c
FB
3100 RET_PRIVREG(ctx);
3101 return;
9a64fbe4 3102 }
d9bce9d9 3103 gen_update_nip(ctx, ctx->nip);
79aceca5 3104 gen_op_load_gpr_T0(rS(ctx->opcode));
d9bce9d9
JM
3105#if defined(TARGET_PPC64)
3106 if (!ctx->sf_mode)
3107 gen_op_store_msr_32();
3108 else
3109#endif
3110 gen_op_store_msr();
79aceca5 3111 /* Must stop the translation as machine state (may have) changed */
e80e1cc4 3112 RET_CHG_FLOW(ctx);
9a64fbe4 3113#endif
79aceca5
FB
3114}
3115
3116/* mtspr */
3117GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC)
3118{
3fc6c082 3119 void (*write_cb)(void *opaque, int sprn);
79aceca5
FB
3120 uint32_t sprn = SPR(ctx->opcode);
3121
3fc6c082
FB
3122#if !defined(CONFIG_USER_ONLY)
3123 if (ctx->supervisor)
3124 write_cb = ctx->spr_cb[sprn].oea_write;
3125 else
9a64fbe4 3126#endif
3fc6c082 3127 write_cb = ctx->spr_cb[sprn].uea_write;
76a66253
JM
3128 if (likely(write_cb != NULL)) {
3129 if (likely(write_cb != SPR_NOACCESS)) {
3fc6c082
FB
3130 gen_op_load_gpr_T0(rS(ctx->opcode));
3131 (*write_cb)(ctx, sprn);
3132 } else {
3133 /* Privilege exception */
4a057712 3134 if (loglevel != 0) {
7f75ffd3 3135 fprintf(logfile, "Trying to write privileged spr %d %03x\n",
f24e5695
FB
3136 sprn, sprn);
3137 }
7f75ffd3 3138 printf("Trying to write privileged spr %d %03x\n", sprn, sprn);
76a66253
JM
3139 RET_PRIVREG(ctx);
3140 }
3fc6c082
FB
3141 } else {
3142 /* Not defined */
4a057712 3143 if (loglevel != 0) {
f24e5695
FB
3144 fprintf(logfile, "Trying to write invalid spr %d %03x\n",
3145 sprn, sprn);
3146 }
3fc6c082
FB
3147 printf("Trying to write invalid spr %d %03x\n", sprn, sprn);
3148 RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
79aceca5 3149 }
79aceca5
FB
3150}
3151
3152/*** Cache management ***/
3153/* For now, all those will be implemented as nop:
3154 * this is valid, regarding the PowerPC specs...
9a64fbe4 3155 * We just have to flush tb while invalidating instruction cache lines...
79aceca5
FB
3156 */
3157/* dcbf */
9a64fbe4 3158GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03E00001, PPC_CACHE)
79aceca5 3159{
76a66253 3160 gen_addr_reg_index(ctx);
a541f297 3161 op_ldst(lbz);
79aceca5
FB
3162}
3163
3164/* dcbi (Supervisor only) */
9a64fbe4 3165GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE)
79aceca5 3166{
a541f297 3167#if defined(CONFIG_USER_ONLY)
9fddaa0c 3168 RET_PRIVOPC(ctx);
a541f297 3169#else
76a66253 3170 if (unlikely(!ctx->supervisor)) {
9fddaa0c
FB
3171 RET_PRIVOPC(ctx);
3172 return;
9a64fbe4 3173 }
76a66253
JM
3174 gen_addr_reg_index(ctx);
3175 /* XXX: specification says this should be treated as a store by the MMU */
3176 //op_ldst(lbz);
a541f297
FB
3177 op_ldst(stb);
3178#endif
79aceca5
FB
3179}
3180
3181/* dcdst */
9a64fbe4 3182GEN_HANDLER(dcbst, 0x1F, 0x16, 0x01, 0x03E00001, PPC_CACHE)
79aceca5 3183{
76a66253
JM
3184 /* XXX: specification say this is treated as a load by the MMU */
3185 gen_addr_reg_index(ctx);
a541f297 3186 op_ldst(lbz);
79aceca5
FB
3187}
3188
3189/* dcbt */
9a64fbe4 3190GEN_HANDLER(dcbt, 0x1F, 0x16, 0x08, 0x03E00001, PPC_CACHE)
79aceca5 3191{
76a66253
JM
3192 /* XXX: specification say this is treated as a load by the MMU
3193 * but does not generate any exception
3194 */
79aceca5
FB
3195}
3196
3197/* dcbtst */
9a64fbe4 3198GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x03E00001, PPC_CACHE)
79aceca5 3199{
76a66253
JM
3200 /* XXX: specification say this is treated as a load by the MMU
3201 * but does not generate any exception
3202 */
79aceca5
FB
3203}
3204
3205/* dcbz */
76a66253 3206#define op_dcbz() (*gen_op_dcbz[ctx->mem_idx])()
d9bce9d9
JM
3207#if defined(TARGET_PPC64)
3208#if defined(CONFIG_USER_ONLY)
3209static GenOpFunc *gen_op_dcbz[] = {
3210 &gen_op_dcbz_raw,
3211 &gen_op_dcbz_raw,
3212 &gen_op_dcbz_64_raw,
3213 &gen_op_dcbz_64_raw,
3214};
3215#else
3216static GenOpFunc *gen_op_dcbz[] = {
3217 &gen_op_dcbz_user,
3218 &gen_op_dcbz_user,
3219 &gen_op_dcbz_kernel,
3220 &gen_op_dcbz_kernel,
3221 &gen_op_dcbz_64_user,
3222 &gen_op_dcbz_64_user,
3223 &gen_op_dcbz_64_kernel,
3224 &gen_op_dcbz_64_kernel,
3225};
3226#endif
3227#else
9a64fbe4 3228#if defined(CONFIG_USER_ONLY)
76a66253
JM
3229static GenOpFunc *gen_op_dcbz[] = {
3230 &gen_op_dcbz_raw,
3231 &gen_op_dcbz_raw,
3232};
9a64fbe4 3233#else
9a64fbe4
FB
3234static GenOpFunc *gen_op_dcbz[] = {
3235 &gen_op_dcbz_user,
2d5262f9
FB
3236 &gen_op_dcbz_user,
3237 &gen_op_dcbz_kernel,
9a64fbe4
FB
3238 &gen_op_dcbz_kernel,
3239};
3240#endif
d9bce9d9 3241#endif
9a64fbe4
FB
3242
3243GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE)
79aceca5 3244{
76a66253 3245 gen_addr_reg_index(ctx);
9a64fbe4 3246 op_dcbz();
4b3686fa 3247 gen_op_check_reservation();
79aceca5
FB
3248}
3249
3250/* icbi */
36f69651
JM
3251#define op_icbi() (*gen_op_icbi[ctx->mem_idx])()
3252#if defined(TARGET_PPC64)
3253#if defined(CONFIG_USER_ONLY)
3254static GenOpFunc *gen_op_icbi[] = {
3255 &gen_op_icbi_raw,
3256 &gen_op_icbi_raw,
3257 &gen_op_icbi_64_raw,
3258 &gen_op_icbi_64_raw,
3259};
3260#else
3261static GenOpFunc *gen_op_icbi[] = {
3262 &gen_op_icbi_user,
3263 &gen_op_icbi_user,
3264 &gen_op_icbi_kernel,
3265 &gen_op_icbi_kernel,
3266 &gen_op_icbi_64_user,
3267 &gen_op_icbi_64_user,
3268 &gen_op_icbi_64_kernel,
3269 &gen_op_icbi_64_kernel,
3270};
3271#endif
3272#else
3273#if defined(CONFIG_USER_ONLY)
3274static GenOpFunc *gen_op_icbi[] = {
3275 &gen_op_icbi_raw,
3276 &gen_op_icbi_raw,
3277};
3278#else
3279static GenOpFunc *gen_op_icbi[] = {
3280 &gen_op_icbi_user,
3281 &gen_op_icbi_user,
3282 &gen_op_icbi_kernel,
3283 &gen_op_icbi_kernel,
3284};
3285#endif
3286#endif
9a64fbe4 3287GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_CACHE)
79aceca5 3288{
76a66253 3289 /* NIP cannot be restored if the memory exception comes from an helper */
d9bce9d9 3290 gen_update_nip(ctx, ctx->nip - 4);
76a66253 3291 gen_addr_reg_index(ctx);
36f69651 3292 op_icbi();
76a66253 3293 RET_STOP(ctx);
79aceca5
FB
3294}
3295
3296/* Optional: */
3297/* dcba */
c7d344af 3298GEN_HANDLER(dcba, 0x1F, 0x16, 0x17, 0x03E00001, PPC_CACHE_OPT)
79aceca5 3299{
79aceca5
FB
3300}
3301
3302/*** Segment register manipulation ***/
3303/* Supervisor only: */
3304/* mfsr */
3305GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT)
3306{
9a64fbe4 3307#if defined(CONFIG_USER_ONLY)
9fddaa0c 3308 RET_PRIVREG(ctx);
9a64fbe4 3309#else
76a66253 3310 if (unlikely(!ctx->supervisor)) {
9fddaa0c
FB
3311 RET_PRIVREG(ctx);
3312 return;
9a64fbe4 3313 }
76a66253
JM
3314 gen_op_set_T1(SR(ctx->opcode));
3315 gen_op_load_sr();
9a64fbe4
FB
3316 gen_op_store_T0_gpr(rD(ctx->opcode));
3317#endif
79aceca5
FB
3318}
3319
3320/* mfsrin */
9a64fbe4 3321GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT)
79aceca5 3322{
9a64fbe4 3323#if defined(CONFIG_USER_ONLY)
9fddaa0c 3324 RET_PRIVREG(ctx);
9a64fbe4 3325#else
76a66253 3326 if (unlikely(!ctx->supervisor)) {
9fddaa0c
FB
3327 RET_PRIVREG(ctx);
3328 return;
9a64fbe4
FB
3329 }
3330 gen_op_load_gpr_T1(rB(ctx->opcode));
76a66253
JM
3331 gen_op_srli_T1(28);
3332 gen_op_load_sr();
9a64fbe4
FB
3333 gen_op_store_T0_gpr(rD(ctx->opcode));
3334#endif
79aceca5
FB
3335}
3336
3337/* mtsr */
e63c59cb 3338GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT)
79aceca5 3339{
9a64fbe4 3340#if defined(CONFIG_USER_ONLY)
9fddaa0c 3341 RET_PRIVREG(ctx);
9a64fbe4 3342#else
76a66253 3343 if (unlikely(!ctx->supervisor)) {
9fddaa0c
FB
3344 RET_PRIVREG(ctx);
3345 return;
9a64fbe4
FB
3346 }
3347 gen_op_load_gpr_T0(rS(ctx->opcode));
76a66253
JM
3348 gen_op_set_T1(SR(ctx->opcode));
3349 gen_op_store_sr();
f24e5695 3350 RET_STOP(ctx);
9a64fbe4 3351#endif
79aceca5
FB
3352}
3353
3354/* mtsrin */
9a64fbe4 3355GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT)
79aceca5 3356{
9a64fbe4 3357#if defined(CONFIG_USER_ONLY)
9fddaa0c 3358 RET_PRIVREG(ctx);
9a64fbe4 3359#else
76a66253 3360 if (unlikely(!ctx->supervisor)) {
9fddaa0c
FB
3361 RET_PRIVREG(ctx);
3362 return;
9a64fbe4
FB
3363 }
3364 gen_op_load_gpr_T0(rS(ctx->opcode));
3365 gen_op_load_gpr_T1(rB(ctx->opcode));
76a66253
JM
3366 gen_op_srli_T1(28);
3367 gen_op_store_sr();
f24e5695 3368 RET_STOP(ctx);
9a64fbe4 3369#endif
79aceca5
FB
3370}
3371
3372/*** Lookaside buffer management ***/
3373/* Optional & supervisor only: */
3374/* tlbia */
3fc6c082 3375GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA)
79aceca5 3376{
9a64fbe4 3377#if defined(CONFIG_USER_ONLY)
9fddaa0c 3378 RET_PRIVOPC(ctx);
9a64fbe4 3379#else
76a66253 3380 if (unlikely(!ctx->supervisor)) {
4a057712 3381 if (loglevel != 0)
9fddaa0c
FB
3382 fprintf(logfile, "%s: ! supervisor\n", __func__);
3383 RET_PRIVOPC(ctx);
3384 return;
9a64fbe4
FB
3385 }
3386 gen_op_tlbia();
f24e5695 3387 RET_STOP(ctx);
9a64fbe4 3388#endif
79aceca5
FB
3389}
3390
3391/* tlbie */
76a66253 3392GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM_TLBIE)
79aceca5 3393{
9a64fbe4 3394#if defined(CONFIG_USER_ONLY)
9fddaa0c 3395 RET_PRIVOPC(ctx);
9a64fbe4 3396#else
76a66253 3397 if (unlikely(!ctx->supervisor)) {
9fddaa0c
FB
3398 RET_PRIVOPC(ctx);
3399 return;
9a64fbe4
FB
3400 }
3401 gen_op_load_gpr_T0(rB(ctx->opcode));
d9bce9d9
JM
3402#if defined(TARGET_PPC64)
3403 if (ctx->sf_mode)
3404 gen_op_tlbie_64();
3405 else
3406#endif
3407 gen_op_tlbie();
f24e5695 3408 RET_STOP(ctx);
9a64fbe4 3409#endif
79aceca5
FB
3410}
3411
3412/* tlbsync */
76a66253 3413GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM_TLBSYNC)
79aceca5 3414{
9a64fbe4 3415#if defined(CONFIG_USER_ONLY)
9fddaa0c 3416 RET_PRIVOPC(ctx);
9a64fbe4 3417#else
76a66253 3418 if (unlikely(!ctx->supervisor)) {
9fddaa0c
FB
3419 RET_PRIVOPC(ctx);
3420 return;
9a64fbe4
FB
3421 }
3422 /* This has no effect: it should ensure that all previous
3423 * tlbie have completed
3424 */
f24e5695 3425 RET_STOP(ctx);
9a64fbe4 3426#endif
79aceca5
FB
3427}
3428
426613db
JM
3429#if defined(TARGET_PPC64)
3430/* slbia */
3431GEN_HANDLER(slbia, 0x1F, 0x12, 0x0F, 0x03FFFC01, PPC_SLBI)
3432{
3433#if defined(CONFIG_USER_ONLY)
3434 RET_PRIVOPC(ctx);
3435#else
3436 if (unlikely(!ctx->supervisor)) {
4a057712 3437 if (loglevel != 0)
426613db
JM
3438 fprintf(logfile, "%s: ! supervisor\n", __func__);
3439 RET_PRIVOPC(ctx);
3440 return;
3441 }
3442 gen_op_slbia();
3443 RET_STOP(ctx);
3444#endif
3445}
3446
3447/* slbie */
3448GEN_HANDLER(slbie, 0x1F, 0x12, 0x0D, 0x03FF0001, PPC_SLBI)
3449{
3450#if defined(CONFIG_USER_ONLY)
3451 RET_PRIVOPC(ctx);
3452#else
3453 if (unlikely(!ctx->supervisor)) {
3454 RET_PRIVOPC(ctx);
3455 return;
3456 }
3457 gen_op_load_gpr_T0(rB(ctx->opcode));
3458 gen_op_slbie();
3459 RET_STOP(ctx);
3460#endif
3461}
3462#endif
3463
79aceca5
FB
3464/*** External control ***/
3465/* Optional: */
9a64fbe4
FB
3466#define op_eciwx() (*gen_op_eciwx[ctx->mem_idx])()
3467#define op_ecowx() (*gen_op_ecowx[ctx->mem_idx])()
d9bce9d9 3468#if defined(TARGET_PPC64)
111bfab3
FB
3469#if defined(CONFIG_USER_ONLY)
3470static GenOpFunc *gen_op_eciwx[] = {
3471 &gen_op_eciwx_raw,
3472 &gen_op_eciwx_le_raw,
d9bce9d9
JM
3473 &gen_op_eciwx_64_raw,
3474 &gen_op_eciwx_le_64_raw,
111bfab3
FB
3475};
3476static GenOpFunc *gen_op_ecowx[] = {
3477 &gen_op_ecowx_raw,
3478 &gen_op_ecowx_le_raw,
d9bce9d9
JM
3479 &gen_op_ecowx_64_raw,
3480 &gen_op_ecowx_le_64_raw,
111bfab3
FB
3481};
3482#else
9a64fbe4
FB
3483static GenOpFunc *gen_op_eciwx[] = {
3484 &gen_op_eciwx_user,
111bfab3 3485 &gen_op_eciwx_le_user,
9a64fbe4 3486 &gen_op_eciwx_kernel,
111bfab3 3487 &gen_op_eciwx_le_kernel,
d9bce9d9
JM
3488 &gen_op_eciwx_64_user,
3489 &gen_op_eciwx_le_64_user,
3490 &gen_op_eciwx_64_kernel,
3491 &gen_op_eciwx_le_64_kernel,
9a64fbe4
FB
3492};
3493static GenOpFunc *gen_op_ecowx[] = {
3494 &gen_op_ecowx_user,
111bfab3 3495 &gen_op_ecowx_le_user,
9a64fbe4 3496 &gen_op_ecowx_kernel,
111bfab3 3497 &gen_op_ecowx_le_kernel,
d9bce9d9
JM
3498 &gen_op_ecowx_64_user,
3499 &gen_op_ecowx_le_64_user,
3500 &gen_op_ecowx_64_kernel,
3501 &gen_op_ecowx_le_64_kernel,
9a64fbe4
FB
3502};
3503#endif
d9bce9d9
JM
3504#else
3505#if defined(CONFIG_USER_ONLY)
3506static GenOpFunc *gen_op_eciwx[] = {
3507 &gen_op_eciwx_raw,
3508 &gen_op_eciwx_le_raw,
3509};
3510static GenOpFunc *gen_op_ecowx[] = {
3511 &gen_op_ecowx_raw,
3512 &gen_op_ecowx_le_raw,
3513};
3514#else
3515static GenOpFunc *gen_op_eciwx[] = {
3516 &gen_op_eciwx_user,
3517 &gen_op_eciwx_le_user,
3518 &gen_op_eciwx_kernel,
3519 &gen_op_eciwx_le_kernel,
3520};
3521static GenOpFunc *gen_op_ecowx[] = {
3522 &gen_op_ecowx_user,
3523 &gen_op_ecowx_le_user,
3524 &gen_op_ecowx_kernel,
3525 &gen_op_ecowx_le_kernel,
3526};
3527#endif
3528#endif
9a64fbe4 3529
111bfab3 3530/* eciwx */
79aceca5
FB
3531GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN)
3532{
9a64fbe4 3533 /* Should check EAR[E] & alignment ! */
76a66253
JM
3534 gen_addr_reg_index(ctx);
3535 op_eciwx();
3536 gen_op_store_T0_gpr(rD(ctx->opcode));
3537}
3538
3539/* ecowx */
3540GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN)
3541{
3542 /* Should check EAR[E] & alignment ! */
3543 gen_addr_reg_index(ctx);
3544 gen_op_load_gpr_T1(rS(ctx->opcode));
3545 op_ecowx();
3546}
3547
3548/* PowerPC 601 specific instructions */
3549/* abs - abs. */
3550GEN_HANDLER(abs, 0x1F, 0x08, 0x0B, 0x0000F800, PPC_POWER_BR)
3551{
3552 gen_op_load_gpr_T0(rA(ctx->opcode));
3553 gen_op_POWER_abs();
3554 gen_op_store_T0_gpr(rD(ctx->opcode));
3555 if (unlikely(Rc(ctx->opcode) != 0))
3556 gen_set_Rc0(ctx);
3557}
3558
3559/* abso - abso. */
3560GEN_HANDLER(abso, 0x1F, 0x08, 0x1B, 0x0000F800, PPC_POWER_BR)
3561{
3562 gen_op_load_gpr_T0(rA(ctx->opcode));
3563 gen_op_POWER_abso();
3564 gen_op_store_T0_gpr(rD(ctx->opcode));
3565 if (unlikely(Rc(ctx->opcode) != 0))
3566 gen_set_Rc0(ctx);
3567}
3568
3569/* clcs */
3570GEN_HANDLER(clcs, 0x1F, 0x10, 0x13, 0x0000F800, PPC_POWER_BR) /* 601 ? */
3571{
3572 gen_op_load_gpr_T0(rA(ctx->opcode));
3573 gen_op_POWER_clcs();
3574 gen_op_store_T0_gpr(rD(ctx->opcode));
3575}
3576
3577/* div - div. */
3578GEN_HANDLER(div, 0x1F, 0x0B, 0x0A, 0x00000000, PPC_POWER_BR)
3579{
3580 gen_op_load_gpr_T0(rA(ctx->opcode));
3581 gen_op_load_gpr_T1(rB(ctx->opcode));
3582 gen_op_POWER_div();
3583 gen_op_store_T0_gpr(rD(ctx->opcode));
3584 if (unlikely(Rc(ctx->opcode) != 0))
3585 gen_set_Rc0(ctx);
3586}
3587
3588/* divo - divo. */
3589GEN_HANDLER(divo, 0x1F, 0x0B, 0x1A, 0x00000000, PPC_POWER_BR)
3590{
3591 gen_op_load_gpr_T0(rA(ctx->opcode));
3592 gen_op_load_gpr_T1(rB(ctx->opcode));
3593 gen_op_POWER_divo();
3594 gen_op_store_T0_gpr(rD(ctx->opcode));
3595 if (unlikely(Rc(ctx->opcode) != 0))
3596 gen_set_Rc0(ctx);
3597}
3598
3599/* divs - divs. */
3600GEN_HANDLER(divs, 0x1F, 0x0B, 0x0B, 0x00000000, PPC_POWER_BR)
3601{
3602 gen_op_load_gpr_T0(rA(ctx->opcode));
3603 gen_op_load_gpr_T1(rB(ctx->opcode));
3604 gen_op_POWER_divs();
3605 gen_op_store_T0_gpr(rD(ctx->opcode));
3606 if (unlikely(Rc(ctx->opcode) != 0))
3607 gen_set_Rc0(ctx);
3608}
3609
3610/* divso - divso. */
3611GEN_HANDLER(divso, 0x1F, 0x0B, 0x1B, 0x00000000, PPC_POWER_BR)
3612{
3613 gen_op_load_gpr_T0(rA(ctx->opcode));
3614 gen_op_load_gpr_T1(rB(ctx->opcode));
3615 gen_op_POWER_divso();
3616 gen_op_store_T0_gpr(rD(ctx->opcode));
3617 if (unlikely(Rc(ctx->opcode) != 0))
3618 gen_set_Rc0(ctx);
3619}
3620
3621/* doz - doz. */
3622GEN_HANDLER(doz, 0x1F, 0x08, 0x08, 0x00000000, PPC_POWER_BR)
3623{
3624 gen_op_load_gpr_T0(rA(ctx->opcode));
3625 gen_op_load_gpr_T1(rB(ctx->opcode));
3626 gen_op_POWER_doz();
3627 gen_op_store_T0_gpr(rD(ctx->opcode));
3628 if (unlikely(Rc(ctx->opcode) != 0))
3629 gen_set_Rc0(ctx);
3630}
3631
3632/* dozo - dozo. */
3633GEN_HANDLER(dozo, 0x1F, 0x08, 0x18, 0x00000000, PPC_POWER_BR)
3634{
3635 gen_op_load_gpr_T0(rA(ctx->opcode));
3636 gen_op_load_gpr_T1(rB(ctx->opcode));
3637 gen_op_POWER_dozo();
3638 gen_op_store_T0_gpr(rD(ctx->opcode));
3639 if (unlikely(Rc(ctx->opcode) != 0))
3640 gen_set_Rc0(ctx);
3641}
3642
3643/* dozi */
3644GEN_HANDLER(dozi, 0x09, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR)
3645{
3646 gen_op_load_gpr_T0(rA(ctx->opcode));
3647 gen_op_set_T1(SIMM(ctx->opcode));
3648 gen_op_POWER_doz();
3649 gen_op_store_T0_gpr(rD(ctx->opcode));
3650}
3651
3652/* As lscbx load from memory byte after byte, it's always endian safe */
3653#define op_POWER_lscbx(start, ra, rb) \
3654(*gen_op_POWER_lscbx[ctx->mem_idx])(start, ra, rb)
3655#if defined(CONFIG_USER_ONLY)
3656static GenOpFunc3 *gen_op_POWER_lscbx[] = {
3657 &gen_op_POWER_lscbx_raw,
3658 &gen_op_POWER_lscbx_raw,
3659};
3660#else
3661static GenOpFunc3 *gen_op_POWER_lscbx[] = {
3662 &gen_op_POWER_lscbx_user,
3663 &gen_op_POWER_lscbx_user,
3664 &gen_op_POWER_lscbx_kernel,
3665 &gen_op_POWER_lscbx_kernel,
3666};
3667#endif
3668
3669/* lscbx - lscbx. */
3670GEN_HANDLER(lscbx, 0x1F, 0x15, 0x08, 0x00000000, PPC_POWER_BR)
3671{
3672 int ra = rA(ctx->opcode);
3673 int rb = rB(ctx->opcode);
3674
3675 gen_addr_reg_index(ctx);
3676 if (ra == 0) {
3677 ra = rb;
3678 }
3679 /* NIP cannot be restored if the memory exception comes from an helper */
d9bce9d9 3680 gen_update_nip(ctx, ctx->nip - 4);
76a66253
JM
3681 gen_op_load_xer_bc();
3682 gen_op_load_xer_cmp();
3683 op_POWER_lscbx(rD(ctx->opcode), ra, rb);
3684 gen_op_store_xer_bc();
3685 if (unlikely(Rc(ctx->opcode) != 0))
3686 gen_set_Rc0(ctx);
3687}
3688
3689/* maskg - maskg. */
3690GEN_HANDLER(maskg, 0x1F, 0x1D, 0x00, 0x00000000, PPC_POWER_BR)
3691{
3692 gen_op_load_gpr_T0(rS(ctx->opcode));
3693 gen_op_load_gpr_T1(rB(ctx->opcode));
3694 gen_op_POWER_maskg();
3695 gen_op_store_T0_gpr(rA(ctx->opcode));
3696 if (unlikely(Rc(ctx->opcode) != 0))
3697 gen_set_Rc0(ctx);
3698}
3699
3700/* maskir - maskir. */
3701GEN_HANDLER(maskir, 0x1F, 0x1D, 0x10, 0x00000000, PPC_POWER_BR)
3702{
3703 gen_op_load_gpr_T0(rA(ctx->opcode));
3704 gen_op_load_gpr_T1(rS(ctx->opcode));
3705 gen_op_load_gpr_T2(rB(ctx->opcode));
3706 gen_op_POWER_maskir();
3707 gen_op_store_T0_gpr(rA(ctx->opcode));
3708 if (unlikely(Rc(ctx->opcode) != 0))
3709 gen_set_Rc0(ctx);
3710}
3711
3712/* mul - mul. */
3713GEN_HANDLER(mul, 0x1F, 0x0B, 0x03, 0x00000000, PPC_POWER_BR)
3714{
3715 gen_op_load_gpr_T0(rA(ctx->opcode));
3716 gen_op_load_gpr_T1(rB(ctx->opcode));
3717 gen_op_POWER_mul();
3718 gen_op_store_T0_gpr(rD(ctx->opcode));
3719 if (unlikely(Rc(ctx->opcode) != 0))
3720 gen_set_Rc0(ctx);
3721}
3722
3723/* mulo - mulo. */
3724GEN_HANDLER(mulo, 0x1F, 0x0B, 0x13, 0x00000000, PPC_POWER_BR)
3725{
3726 gen_op_load_gpr_T0(rA(ctx->opcode));
3727 gen_op_load_gpr_T1(rB(ctx->opcode));
3728 gen_op_POWER_mulo();
3729 gen_op_store_T0_gpr(rD(ctx->opcode));
3730 if (unlikely(Rc(ctx->opcode) != 0))
3731 gen_set_Rc0(ctx);
3732}
3733
3734/* nabs - nabs. */
3735GEN_HANDLER(nabs, 0x1F, 0x08, 0x0F, 0x00000000, PPC_POWER_BR)
3736{
3737 gen_op_load_gpr_T0(rA(ctx->opcode));
3738 gen_op_POWER_nabs();
3739 gen_op_store_T0_gpr(rD(ctx->opcode));
3740 if (unlikely(Rc(ctx->opcode) != 0))
3741 gen_set_Rc0(ctx);
3742}
3743
3744/* nabso - nabso. */
3745GEN_HANDLER(nabso, 0x1F, 0x08, 0x1F, 0x00000000, PPC_POWER_BR)
3746{
3747 gen_op_load_gpr_T0(rA(ctx->opcode));
3748 gen_op_POWER_nabso();
3749 gen_op_store_T0_gpr(rD(ctx->opcode));
3750 if (unlikely(Rc(ctx->opcode) != 0))
3751 gen_set_Rc0(ctx);
3752}
3753
3754/* rlmi - rlmi. */
3755GEN_HANDLER(rlmi, 0x16, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR)
3756{
3757 uint32_t mb, me;
3758
3759 mb = MB(ctx->opcode);
3760 me = ME(ctx->opcode);
3761 gen_op_load_gpr_T0(rS(ctx->opcode));
3762 gen_op_load_gpr_T1(rA(ctx->opcode));
3763 gen_op_load_gpr_T2(rB(ctx->opcode));
3764 gen_op_POWER_rlmi(MASK(mb, me), ~MASK(mb, me));
3765 gen_op_store_T0_gpr(rA(ctx->opcode));
3766 if (unlikely(Rc(ctx->opcode) != 0))
3767 gen_set_Rc0(ctx);
3768}
3769
3770/* rrib - rrib. */
3771GEN_HANDLER(rrib, 0x1F, 0x19, 0x10, 0x00000000, PPC_POWER_BR)
3772{
3773 gen_op_load_gpr_T0(rS(ctx->opcode));
3774 gen_op_load_gpr_T1(rA(ctx->opcode));
3775 gen_op_load_gpr_T2(rB(ctx->opcode));
3776 gen_op_POWER_rrib();
3777 gen_op_store_T0_gpr(rA(ctx->opcode));
3778 if (unlikely(Rc(ctx->opcode) != 0))
3779 gen_set_Rc0(ctx);
3780}
3781
3782/* sle - sle. */
3783GEN_HANDLER(sle, 0x1F, 0x19, 0x04, 0x00000000, PPC_POWER_BR)
3784{
3785 gen_op_load_gpr_T0(rS(ctx->opcode));
3786 gen_op_load_gpr_T1(rB(ctx->opcode));
3787 gen_op_POWER_sle();
3788 gen_op_store_T0_gpr(rA(ctx->opcode));
3789 if (unlikely(Rc(ctx->opcode) != 0))
3790 gen_set_Rc0(ctx);
3791}
3792
3793/* sleq - sleq. */
3794GEN_HANDLER(sleq, 0x1F, 0x19, 0x06, 0x00000000, PPC_POWER_BR)
3795{
3796 gen_op_load_gpr_T0(rS(ctx->opcode));
3797 gen_op_load_gpr_T1(rB(ctx->opcode));
3798 gen_op_POWER_sleq();
3799 gen_op_store_T0_gpr(rA(ctx->opcode));
3800 if (unlikely(Rc(ctx->opcode) != 0))
3801 gen_set_Rc0(ctx);
3802}
3803
3804/* sliq - sliq. */
3805GEN_HANDLER(sliq, 0x1F, 0x18, 0x05, 0x00000000, PPC_POWER_BR)
3806{
3807 gen_op_load_gpr_T0(rS(ctx->opcode));
3808 gen_op_set_T1(SH(ctx->opcode));
3809 gen_op_POWER_sle();
3810 gen_op_store_T0_gpr(rA(ctx->opcode));
3811 if (unlikely(Rc(ctx->opcode) != 0))
3812 gen_set_Rc0(ctx);
3813}
3814
3815/* slliq - slliq. */
3816GEN_HANDLER(slliq, 0x1F, 0x18, 0x07, 0x00000000, PPC_POWER_BR)
3817{
3818 gen_op_load_gpr_T0(rS(ctx->opcode));
3819 gen_op_set_T1(SH(ctx->opcode));
3820 gen_op_POWER_sleq();
3821 gen_op_store_T0_gpr(rA(ctx->opcode));
3822 if (unlikely(Rc(ctx->opcode) != 0))
3823 gen_set_Rc0(ctx);
3824}
3825
3826/* sllq - sllq. */
3827GEN_HANDLER(sllq, 0x1F, 0x18, 0x06, 0x00000000, PPC_POWER_BR)
3828{
3829 gen_op_load_gpr_T0(rS(ctx->opcode));
3830 gen_op_load_gpr_T1(rB(ctx->opcode));
3831 gen_op_POWER_sllq();
3832 gen_op_store_T0_gpr(rA(ctx->opcode));
3833 if (unlikely(Rc(ctx->opcode) != 0))
3834 gen_set_Rc0(ctx);
3835}
3836
3837/* slq - slq. */
3838GEN_HANDLER(slq, 0x1F, 0x18, 0x04, 0x00000000, PPC_POWER_BR)
3839{
3840 gen_op_load_gpr_T0(rS(ctx->opcode));
3841 gen_op_load_gpr_T1(rB(ctx->opcode));
3842 gen_op_POWER_slq();
3843 gen_op_store_T0_gpr(rA(ctx->opcode));
3844 if (unlikely(Rc(ctx->opcode) != 0))
3845 gen_set_Rc0(ctx);
3846}
3847
d9bce9d9 3848/* sraiq - sraiq. */
76a66253
JM
3849GEN_HANDLER(sraiq, 0x1F, 0x18, 0x1D, 0x00000000, PPC_POWER_BR)
3850{
3851 gen_op_load_gpr_T0(rS(ctx->opcode));
3852 gen_op_set_T1(SH(ctx->opcode));
3853 gen_op_POWER_sraq();
3854 gen_op_store_T0_gpr(rA(ctx->opcode));
3855 if (unlikely(Rc(ctx->opcode) != 0))
3856 gen_set_Rc0(ctx);
3857}
3858
3859/* sraq - sraq. */
3860GEN_HANDLER(sraq, 0x1F, 0x18, 0x1C, 0x00000000, PPC_POWER_BR)
3861{
3862 gen_op_load_gpr_T0(rS(ctx->opcode));
3863 gen_op_load_gpr_T1(rB(ctx->opcode));
3864 gen_op_POWER_sraq();
3865 gen_op_store_T0_gpr(rA(ctx->opcode));
3866 if (unlikely(Rc(ctx->opcode) != 0))
3867 gen_set_Rc0(ctx);
3868}
3869
3870/* sre - sre. */
3871GEN_HANDLER(sre, 0x1F, 0x19, 0x14, 0x00000000, PPC_POWER_BR)
3872{
3873 gen_op_load_gpr_T0(rS(ctx->opcode));
3874 gen_op_load_gpr_T1(rB(ctx->opcode));
3875 gen_op_POWER_sre();
3876 gen_op_store_T0_gpr(rA(ctx->opcode));
3877 if (unlikely(Rc(ctx->opcode) != 0))
3878 gen_set_Rc0(ctx);
3879}
3880
3881/* srea - srea. */
3882GEN_HANDLER(srea, 0x1F, 0x19, 0x1C, 0x00000000, PPC_POWER_BR)
3883{
3884 gen_op_load_gpr_T0(rS(ctx->opcode));
3885 gen_op_load_gpr_T1(rB(ctx->opcode));
3886 gen_op_POWER_srea();
3887 gen_op_store_T0_gpr(rA(ctx->opcode));
3888 if (unlikely(Rc(ctx->opcode) != 0))
3889 gen_set_Rc0(ctx);
3890}
3891
3892/* sreq */
3893GEN_HANDLER(sreq, 0x1F, 0x19, 0x16, 0x00000000, PPC_POWER_BR)
3894{
3895 gen_op_load_gpr_T0(rS(ctx->opcode));
3896 gen_op_load_gpr_T1(rB(ctx->opcode));
3897 gen_op_POWER_sreq();
3898 gen_op_store_T0_gpr(rA(ctx->opcode));
3899 if (unlikely(Rc(ctx->opcode) != 0))
3900 gen_set_Rc0(ctx);
3901}
3902
3903/* sriq */
3904GEN_HANDLER(sriq, 0x1F, 0x18, 0x15, 0x00000000, PPC_POWER_BR)
3905{
3906 gen_op_load_gpr_T0(rS(ctx->opcode));
3907 gen_op_set_T1(SH(ctx->opcode));
3908 gen_op_POWER_srq();
3909 gen_op_store_T0_gpr(rA(ctx->opcode));
3910 if (unlikely(Rc(ctx->opcode) != 0))
3911 gen_set_Rc0(ctx);
3912}
3913
3914/* srliq */
3915GEN_HANDLER(srliq, 0x1F, 0x18, 0x17, 0x00000000, PPC_POWER_BR)
3916{
3917 gen_op_load_gpr_T0(rS(ctx->opcode));
3918 gen_op_load_gpr_T1(rB(ctx->opcode));
3919 gen_op_set_T1(SH(ctx->opcode));
3920 gen_op_POWER_srlq();
3921 gen_op_store_T0_gpr(rA(ctx->opcode));
3922 if (unlikely(Rc(ctx->opcode) != 0))
3923 gen_set_Rc0(ctx);
3924}
3925
3926/* srlq */
3927GEN_HANDLER(srlq, 0x1F, 0x18, 0x16, 0x00000000, PPC_POWER_BR)
3928{
3929 gen_op_load_gpr_T0(rS(ctx->opcode));
3930 gen_op_load_gpr_T1(rB(ctx->opcode));
3931 gen_op_POWER_srlq();
3932 gen_op_store_T0_gpr(rA(ctx->opcode));
3933 if (unlikely(Rc(ctx->opcode) != 0))
3934 gen_set_Rc0(ctx);
3935}
3936
3937/* srq */
3938GEN_HANDLER(srq, 0x1F, 0x18, 0x14, 0x00000000, PPC_POWER_BR)
3939{
3940 gen_op_load_gpr_T0(rS(ctx->opcode));
3941 gen_op_load_gpr_T1(rB(ctx->opcode));
3942 gen_op_POWER_srq();
3943 gen_op_store_T0_gpr(rA(ctx->opcode));
3944 if (unlikely(Rc(ctx->opcode) != 0))
3945 gen_set_Rc0(ctx);
3946}
3947
3948/* PowerPC 602 specific instructions */
3949/* dsa */
3950GEN_HANDLER(dsa, 0x1F, 0x14, 0x13, 0x03FFF801, PPC_602_SPEC)
3951{
3952 /* XXX: TODO */
3953 RET_INVAL(ctx);
3954}
3955
3956/* esa */
3957GEN_HANDLER(esa, 0x1F, 0x14, 0x12, 0x03FFF801, PPC_602_SPEC)
3958{
3959 /* XXX: TODO */
3960 RET_INVAL(ctx);
3961}
3962
3963/* mfrom */
3964GEN_HANDLER(mfrom, 0x1F, 0x09, 0x08, 0x03E0F801, PPC_602_SPEC)
3965{
3966#if defined(CONFIG_USER_ONLY)
3967 RET_PRIVOPC(ctx);
3968#else
3969 if (unlikely(!ctx->supervisor)) {
3970 RET_PRIVOPC(ctx);
3971 return;
3972 }
3973 gen_op_load_gpr_T0(rA(ctx->opcode));
3974 gen_op_602_mfrom();
3975 gen_op_store_T0_gpr(rD(ctx->opcode));
3976#endif
3977}
3978
3979/* 602 - 603 - G2 TLB management */
3980/* tlbld */
3981GEN_HANDLER(tlbld, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB)
3982{
3983#if defined(CONFIG_USER_ONLY)
3984 RET_PRIVOPC(ctx);
3985#else
3986 if (unlikely(!ctx->supervisor)) {
3987 RET_PRIVOPC(ctx);
3988 return;
3989 }
3990 gen_op_load_gpr_T0(rB(ctx->opcode));
3991 gen_op_6xx_tlbld();
3992 RET_STOP(ctx);
3993#endif
3994}
3995
3996/* tlbli */
3997GEN_HANDLER(tlbli, 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB)
3998{
3999#if defined(CONFIG_USER_ONLY)
4000 RET_PRIVOPC(ctx);
4001#else
4002 if (unlikely(!ctx->supervisor)) {
4003 RET_PRIVOPC(ctx);
4004 return;
4005 }
4006 gen_op_load_gpr_T0(rB(ctx->opcode));
4007 gen_op_6xx_tlbli();
4008 RET_STOP(ctx);
4009#endif
4010}
4011
4012/* POWER instructions not in PowerPC 601 */
4013/* clf */
4014GEN_HANDLER(clf, 0x1F, 0x16, 0x03, 0x03E00000, PPC_POWER)
4015{
4016 /* Cache line flush: implemented as no-op */
4017}
4018
4019/* cli */
4020GEN_HANDLER(cli, 0x1F, 0x16, 0x0F, 0x03E00000, PPC_POWER)
4021{
7f75ffd3 4022 /* Cache line invalidate: privileged and treated as no-op */
76a66253
JM
4023#if defined(CONFIG_USER_ONLY)
4024 RET_PRIVOPC(ctx);
4025#else
4026 if (unlikely(!ctx->supervisor)) {
4027 RET_PRIVOPC(ctx);
4028 return;
4029 }
4030#endif
4031}
4032
4033/* dclst */
4034GEN_HANDLER(dclst, 0x1F, 0x16, 0x13, 0x03E00000, PPC_POWER)
4035{
4036 /* Data cache line store: treated as no-op */
4037}
4038
4039GEN_HANDLER(mfsri, 0x1F, 0x13, 0x13, 0x00000001, PPC_POWER)
4040{
4041#if defined(CONFIG_USER_ONLY)
4042 RET_PRIVOPC(ctx);
4043#else
4044 if (unlikely(!ctx->supervisor)) {
4045 RET_PRIVOPC(ctx);
4046 return;
4047 }
4048 int ra = rA(ctx->opcode);
4049 int rd = rD(ctx->opcode);
4050
4051 gen_addr_reg_index(ctx);
4052 gen_op_POWER_mfsri();
4053 gen_op_store_T0_gpr(rd);
4054 if (ra != 0 && ra != rd)
4055 gen_op_store_T1_gpr(ra);
4056#endif
4057}
4058
4059GEN_HANDLER(rac, 0x1F, 0x12, 0x19, 0x00000001, PPC_POWER)
4060{
4061#if defined(CONFIG_USER_ONLY)
4062 RET_PRIVOPC(ctx);
4063#else
4064 if (unlikely(!ctx->supervisor)) {
4065 RET_PRIVOPC(ctx);
4066 return;
4067 }
4068 gen_addr_reg_index(ctx);
4069 gen_op_POWER_rac();
4070 gen_op_store_T0_gpr(rD(ctx->opcode));
4071#endif
4072}
4073
4074GEN_HANDLER(rfsvc, 0x13, 0x12, 0x02, 0x03FFF0001, PPC_POWER)
4075{
4076#if defined(CONFIG_USER_ONLY)
4077 RET_PRIVOPC(ctx);
4078#else
4079 if (unlikely(!ctx->supervisor)) {
4080 RET_PRIVOPC(ctx);
4081 return;
4082 }
4083 gen_op_POWER_rfsvc();
4084 RET_CHG_FLOW(ctx);
4085#endif
4086}
4087
4088/* svc is not implemented for now */
4089
4090/* POWER2 specific instructions */
4091/* Quad manipulation (load/store two floats at a time) */
4092#define op_POWER2_lfq() (*gen_op_POWER2_lfq[ctx->mem_idx])()
4093#define op_POWER2_stfq() (*gen_op_POWER2_stfq[ctx->mem_idx])()
4094#if defined(CONFIG_USER_ONLY)
4095static GenOpFunc *gen_op_POWER2_lfq[] = {
4096 &gen_op_POWER2_lfq_le_raw,
4097 &gen_op_POWER2_lfq_raw,
4098};
4099static GenOpFunc *gen_op_POWER2_stfq[] = {
4100 &gen_op_POWER2_stfq_le_raw,
4101 &gen_op_POWER2_stfq_raw,
4102};
4103#else
4104static GenOpFunc *gen_op_POWER2_lfq[] = {
4105 &gen_op_POWER2_lfq_le_user,
4106 &gen_op_POWER2_lfq_user,
4107 &gen_op_POWER2_lfq_le_kernel,
4108 &gen_op_POWER2_lfq_kernel,
4109};
4110static GenOpFunc *gen_op_POWER2_stfq[] = {
4111 &gen_op_POWER2_stfq_le_user,
4112 &gen_op_POWER2_stfq_user,
4113 &gen_op_POWER2_stfq_le_kernel,
4114 &gen_op_POWER2_stfq_kernel,
4115};
4116#endif
4117
4118/* lfq */
4119GEN_HANDLER(lfq, 0x38, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
4120{
4121 /* NIP cannot be restored if the memory exception comes from an helper */
d9bce9d9 4122 gen_update_nip(ctx, ctx->nip - 4);
9d53c753 4123 gen_addr_imm_index(ctx, 0);
76a66253
JM
4124 op_POWER2_lfq();
4125 gen_op_store_FT0_fpr(rD(ctx->opcode));
4126 gen_op_store_FT1_fpr(rD(ctx->opcode) + 1);
4127}
4128
4129/* lfqu */
4130GEN_HANDLER(lfqu, 0x39, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
4131{
4132 int ra = rA(ctx->opcode);
4133
4134 /* NIP cannot be restored if the memory exception comes from an helper */
d9bce9d9 4135 gen_update_nip(ctx, ctx->nip - 4);
9d53c753 4136 gen_addr_imm_index(ctx, 0);
76a66253
JM
4137 op_POWER2_lfq();
4138 gen_op_store_FT0_fpr(rD(ctx->opcode));
4139 gen_op_store_FT1_fpr(rD(ctx->opcode) + 1);
4140 if (ra != 0)
4141 gen_op_store_T0_gpr(ra);
4142}
4143
4144/* lfqux */
4145GEN_HANDLER(lfqux, 0x1F, 0x17, 0x19, 0x00000001, PPC_POWER2)
4146{
4147 int ra = rA(ctx->opcode);
4148
4149 /* NIP cannot be restored if the memory exception comes from an helper */
d9bce9d9 4150 gen_update_nip(ctx, ctx->nip - 4);
76a66253
JM
4151 gen_addr_reg_index(ctx);
4152 op_POWER2_lfq();
4153 gen_op_store_FT0_fpr(rD(ctx->opcode));
4154 gen_op_store_FT1_fpr(rD(ctx->opcode) + 1);
4155 if (ra != 0)
4156 gen_op_store_T0_gpr(ra);
4157}
4158
4159/* lfqx */
4160GEN_HANDLER(lfqx, 0x1F, 0x17, 0x18, 0x00000001, PPC_POWER2)
4161{
4162 /* NIP cannot be restored if the memory exception comes from an helper */
d9bce9d9 4163 gen_update_nip(ctx, ctx->nip - 4);
76a66253
JM
4164 gen_addr_reg_index(ctx);
4165 op_POWER2_lfq();
4166 gen_op_store_FT0_fpr(rD(ctx->opcode));
4167 gen_op_store_FT1_fpr(rD(ctx->opcode) + 1);
4168}
4169
4170/* stfq */
4171GEN_HANDLER(stfq, 0x3C, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
4172{
4173 /* NIP cannot be restored if the memory exception comes from an helper */
d9bce9d9 4174 gen_update_nip(ctx, ctx->nip - 4);
9d53c753 4175 gen_addr_imm_index(ctx, 0);
76a66253
JM
4176 gen_op_load_fpr_FT0(rS(ctx->opcode));
4177 gen_op_load_fpr_FT1(rS(ctx->opcode) + 1);
4178 op_POWER2_stfq();
4179}
4180
4181/* stfqu */
4182GEN_HANDLER(stfqu, 0x3D, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
4183{
4184 int ra = rA(ctx->opcode);
4185
4186 /* NIP cannot be restored if the memory exception comes from an helper */
d9bce9d9 4187 gen_update_nip(ctx, ctx->nip - 4);
9d53c753 4188 gen_addr_imm_index(ctx, 0);
76a66253
JM
4189 gen_op_load_fpr_FT0(rS(ctx->opcode));
4190 gen_op_load_fpr_FT1(rS(ctx->opcode) + 1);
4191 op_POWER2_stfq();
4192 if (ra != 0)
4193 gen_op_store_T0_gpr(ra);
4194}
4195
4196/* stfqux */
4197GEN_HANDLER(stfqux, 0x1F, 0x17, 0x1D, 0x00000001, PPC_POWER2)
4198{
4199 int ra = rA(ctx->opcode);
4200
4201 /* NIP cannot be restored if the memory exception comes from an helper */
d9bce9d9 4202 gen_update_nip(ctx, ctx->nip - 4);
76a66253
JM
4203 gen_addr_reg_index(ctx);
4204 gen_op_load_fpr_FT0(rS(ctx->opcode));
4205 gen_op_load_fpr_FT1(rS(ctx->opcode) + 1);
4206 op_POWER2_stfq();
4207 if (ra != 0)
4208 gen_op_store_T0_gpr(ra);
4209}
4210
4211/* stfqx */
4212GEN_HANDLER(stfqx, 0x1F, 0x17, 0x1C, 0x00000001, PPC_POWER2)
4213{
4214 /* NIP cannot be restored if the memory exception comes from an helper */
d9bce9d9 4215 gen_update_nip(ctx, ctx->nip - 4);
76a66253
JM
4216 gen_addr_reg_index(ctx);
4217 gen_op_load_fpr_FT0(rS(ctx->opcode));
4218 gen_op_load_fpr_FT1(rS(ctx->opcode) + 1);
4219 op_POWER2_stfq();
4220}
4221
4222/* BookE specific instructions */
4223GEN_HANDLER(mfapidi, 0x1F, 0x13, 0x08, 0x0000F801, PPC_BOOKE)
4224{
4225 /* XXX: TODO */
4226 RET_INVAL(ctx);
4227}
4228
4229GEN_HANDLER(tlbiva, 0x1F, 0x12, 0x18, 0x03FFF801, PPC_BOOKE)
4230{
4231#if defined(CONFIG_USER_ONLY)
4232 RET_PRIVOPC(ctx);
4233#else
4234 if (unlikely(!ctx->supervisor)) {
4235 RET_PRIVOPC(ctx);
4236 return;
4237 }
4238 gen_addr_reg_index(ctx);
4239 /* Use the same micro-ops as for tlbie */
d9bce9d9
JM
4240#if defined(TARGET_PPC64)
4241 if (ctx->sf_mode)
4242 gen_op_tlbie_64();
4243 else
4244#endif
4245 gen_op_tlbie();
76a66253
JM
4246 RET_STOP(ctx);
4247#endif
4248}
4249
4250/* All 405 MAC instructions are translated here */
4251static inline void gen_405_mulladd_insn (DisasContext *ctx, int opc2, int opc3,
4252 int ra, int rb, int rt, int Rc)
4253{
4254 gen_op_load_gpr_T0(ra);
4255 gen_op_load_gpr_T1(rb);
4256 switch (opc3 & 0x0D) {
4257 case 0x05:
4258 /* macchw - macchw. - macchwo - macchwo. */
4259 /* macchws - macchws. - macchwso - macchwso. */
4260 /* nmacchw - nmacchw. - nmacchwo - nmacchwo. */
4261 /* nmacchws - nmacchws. - nmacchwso - nmacchwso. */
4262 /* mulchw - mulchw. */
4263 gen_op_405_mulchw();
4264 break;
4265 case 0x04:
4266 /* macchwu - macchwu. - macchwuo - macchwuo. */
4267 /* macchwsu - macchwsu. - macchwsuo - macchwsuo. */
4268 /* mulchwu - mulchwu. */
4269 gen_op_405_mulchwu();
4270 break;
4271 case 0x01:
4272 /* machhw - machhw. - machhwo - machhwo. */
4273 /* machhws - machhws. - machhwso - machhwso. */
4274 /* nmachhw - nmachhw. - nmachhwo - nmachhwo. */
4275 /* nmachhws - nmachhws. - nmachhwso - nmachhwso. */
4276 /* mulhhw - mulhhw. */
4277 gen_op_405_mulhhw();
4278 break;
4279 case 0x00:
4280 /* machhwu - machhwu. - machhwuo - machhwuo. */
4281 /* machhwsu - machhwsu. - machhwsuo - machhwsuo. */
4282 /* mulhhwu - mulhhwu. */
4283 gen_op_405_mulhhwu();
4284 break;
4285 case 0x0D:
4286 /* maclhw - maclhw. - maclhwo - maclhwo. */
4287 /* maclhws - maclhws. - maclhwso - maclhwso. */
4288 /* nmaclhw - nmaclhw. - nmaclhwo - nmaclhwo. */
4289 /* nmaclhws - nmaclhws. - nmaclhwso - nmaclhwso. */
4290 /* mullhw - mullhw. */
4291 gen_op_405_mullhw();
4292 break;
4293 case 0x0C:
4294 /* maclhwu - maclhwu. - maclhwuo - maclhwuo. */
4295 /* maclhwsu - maclhwsu. - maclhwsuo - maclhwsuo. */
4296 /* mullhwu - mullhwu. */
4297 gen_op_405_mullhwu();
4298 break;
4299 }
4300 if (opc2 & 0x02) {
4301 /* nmultiply-and-accumulate (0x0E) */
4302 gen_op_neg();
4303 }
4304 if (opc2 & 0x04) {
4305 /* (n)multiply-and-accumulate (0x0C - 0x0E) */
4306 gen_op_load_gpr_T2(rt);
4307 gen_op_move_T1_T0();
4308 gen_op_405_add_T0_T2();
4309 }
4310 if (opc3 & 0x10) {
4311 /* Check overflow */
4312 if (opc3 & 0x01)
4313 gen_op_405_check_ov();
4314 else
4315 gen_op_405_check_ovu();
4316 }
4317 if (opc3 & 0x02) {
4318 /* Saturate */
4319 if (opc3 & 0x01)
4320 gen_op_405_check_sat();
4321 else
4322 gen_op_405_check_satu();
4323 }
4324 gen_op_store_T0_gpr(rt);
4325 if (unlikely(Rc) != 0) {
4326 /* Update Rc0 */
4327 gen_set_Rc0(ctx);
4328 }
4329}
4330
4331#define GEN_MAC_HANDLER(name, opc2, opc3) \
4332GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_405_MAC) \
4333{ \
4334 gen_405_mulladd_insn(ctx, opc2, opc3, rA(ctx->opcode), rB(ctx->opcode), \
4335 rD(ctx->opcode), Rc(ctx->opcode)); \
4336}
4337
4338/* macchw - macchw. */
4339GEN_MAC_HANDLER(macchw, 0x0C, 0x05);
4340/* macchwo - macchwo. */
4341GEN_MAC_HANDLER(macchwo, 0x0C, 0x15);
4342/* macchws - macchws. */
4343GEN_MAC_HANDLER(macchws, 0x0C, 0x07);
4344/* macchwso - macchwso. */
4345GEN_MAC_HANDLER(macchwso, 0x0C, 0x17);
4346/* macchwsu - macchwsu. */
4347GEN_MAC_HANDLER(macchwsu, 0x0C, 0x06);
4348/* macchwsuo - macchwsuo. */
4349GEN_MAC_HANDLER(macchwsuo, 0x0C, 0x16);
4350/* macchwu - macchwu. */
4351GEN_MAC_HANDLER(macchwu, 0x0C, 0x04);
4352/* macchwuo - macchwuo. */
4353GEN_MAC_HANDLER(macchwuo, 0x0C, 0x14);
4354/* machhw - machhw. */
4355GEN_MAC_HANDLER(machhw, 0x0C, 0x01);
4356/* machhwo - machhwo. */
4357GEN_MAC_HANDLER(machhwo, 0x0C, 0x11);
4358/* machhws - machhws. */
4359GEN_MAC_HANDLER(machhws, 0x0C, 0x03);
4360/* machhwso - machhwso. */
4361GEN_MAC_HANDLER(machhwso, 0x0C, 0x13);
4362/* machhwsu - machhwsu. */
4363GEN_MAC_HANDLER(machhwsu, 0x0C, 0x02);
4364/* machhwsuo - machhwsuo. */
4365GEN_MAC_HANDLER(machhwsuo, 0x0C, 0x12);
4366/* machhwu - machhwu. */
4367GEN_MAC_HANDLER(machhwu, 0x0C, 0x00);
4368/* machhwuo - machhwuo. */
4369GEN_MAC_HANDLER(machhwuo, 0x0C, 0x10);
4370/* maclhw - maclhw. */
4371GEN_MAC_HANDLER(maclhw, 0x0C, 0x0D);
4372/* maclhwo - maclhwo. */
4373GEN_MAC_HANDLER(maclhwo, 0x0C, 0x1D);
4374/* maclhws - maclhws. */
4375GEN_MAC_HANDLER(maclhws, 0x0C, 0x0F);
4376/* maclhwso - maclhwso. */
4377GEN_MAC_HANDLER(maclhwso, 0x0C, 0x1F);
4378/* maclhwu - maclhwu. */
4379GEN_MAC_HANDLER(maclhwu, 0x0C, 0x0C);
4380/* maclhwuo - maclhwuo. */
4381GEN_MAC_HANDLER(maclhwuo, 0x0C, 0x1C);
4382/* maclhwsu - maclhwsu. */
4383GEN_MAC_HANDLER(maclhwsu, 0x0C, 0x0E);
4384/* maclhwsuo - maclhwsuo. */
4385GEN_MAC_HANDLER(maclhwsuo, 0x0C, 0x1E);
4386/* nmacchw - nmacchw. */
4387GEN_MAC_HANDLER(nmacchw, 0x0E, 0x05);
4388/* nmacchwo - nmacchwo. */
4389GEN_MAC_HANDLER(nmacchwo, 0x0E, 0x15);
4390/* nmacchws - nmacchws. */
4391GEN_MAC_HANDLER(nmacchws, 0x0E, 0x07);
4392/* nmacchwso - nmacchwso. */
4393GEN_MAC_HANDLER(nmacchwso, 0x0E, 0x17);
4394/* nmachhw - nmachhw. */
4395GEN_MAC_HANDLER(nmachhw, 0x0E, 0x01);
4396/* nmachhwo - nmachhwo. */
4397GEN_MAC_HANDLER(nmachhwo, 0x0E, 0x11);
4398/* nmachhws - nmachhws. */
4399GEN_MAC_HANDLER(nmachhws, 0x0E, 0x03);
4400/* nmachhwso - nmachhwso. */
4401GEN_MAC_HANDLER(nmachhwso, 0x0E, 0x13);
4402/* nmaclhw - nmaclhw. */
4403GEN_MAC_HANDLER(nmaclhw, 0x0E, 0x0D);
4404/* nmaclhwo - nmaclhwo. */
4405GEN_MAC_HANDLER(nmaclhwo, 0x0E, 0x1D);
4406/* nmaclhws - nmaclhws. */
4407GEN_MAC_HANDLER(nmaclhws, 0x0E, 0x0F);
4408/* nmaclhwso - nmaclhwso. */
4409GEN_MAC_HANDLER(nmaclhwso, 0x0E, 0x1F);
4410
4411/* mulchw - mulchw. */
4412GEN_MAC_HANDLER(mulchw, 0x08, 0x05);
4413/* mulchwu - mulchwu. */
4414GEN_MAC_HANDLER(mulchwu, 0x08, 0x04);
4415/* mulhhw - mulhhw. */
4416GEN_MAC_HANDLER(mulhhw, 0x08, 0x01);
4417/* mulhhwu - mulhhwu. */
4418GEN_MAC_HANDLER(mulhhwu, 0x08, 0x00);
4419/* mullhw - mullhw. */
4420GEN_MAC_HANDLER(mullhw, 0x08, 0x0D);
4421/* mullhwu - mullhwu. */
4422GEN_MAC_HANDLER(mullhwu, 0x08, 0x0C);
4423
4424/* mfdcr */
4425GEN_HANDLER(mfdcr, 0x1F, 0x03, 0x0A, 0x00000001, PPC_EMB_COMMON)
4426{
4427#if defined(CONFIG_USER_ONLY)
4428 RET_PRIVREG(ctx);
4429#else
4430 uint32_t dcrn = SPR(ctx->opcode);
4431
4432 if (unlikely(!ctx->supervisor)) {
4433 RET_PRIVREG(ctx);
4434 return;
4435 }
a42bd6cc
JM
4436 gen_op_set_T0(dcrn);
4437 gen_op_load_dcr();
76a66253
JM
4438 gen_op_store_T0_gpr(rD(ctx->opcode));
4439#endif
4440}
4441
4442/* mtdcr */
4443GEN_HANDLER(mtdcr, 0x1F, 0x03, 0x0E, 0x00000001, PPC_EMB_COMMON)
4444{
4445#if defined(CONFIG_USER_ONLY)
4446 RET_PRIVREG(ctx);
4447#else
4448 uint32_t dcrn = SPR(ctx->opcode);
4449
4450 if (unlikely(!ctx->supervisor)) {
4451 RET_PRIVREG(ctx);
4452 return;
4453 }
a42bd6cc
JM
4454 gen_op_set_T0(dcrn);
4455 gen_op_load_gpr_T1(rS(ctx->opcode));
4456 gen_op_store_dcr();
4457#endif
4458}
4459
4460/* mfdcrx */
4461GEN_HANDLER(mfdcrx, 0x1F, 0x03, 0x08, 0x00000001, PPC_BOOKE)
4462{
4463#if defined(CONFIG_USER_ONLY)
4464 RET_PRIVREG(ctx);
4465#else
4466 if (unlikely(!ctx->supervisor)) {
4467 RET_PRIVREG(ctx);
4468 return;
4469 }
4470 gen_op_load_gpr_T0(rA(ctx->opcode));
4471 gen_op_load_dcr();
4472 gen_op_store_T0_gpr(rD(ctx->opcode));
4473#endif
4474}
4475
4476/* mtdcrx */
4477GEN_HANDLER(mtdcrx, 0x1F, 0x03, 0x0C, 0x00000001, PPC_BOOKE)
4478{
4479#if defined(CONFIG_USER_ONLY)
4480 RET_PRIVREG(ctx);
4481#else
4482 if (unlikely(!ctx->supervisor)) {
4483 RET_PRIVREG(ctx);
4484 return;
4485 }
4486 gen_op_load_gpr_T0(rA(ctx->opcode));
4487 gen_op_load_gpr_T1(rS(ctx->opcode));
4488 gen_op_store_dcr();
76a66253
JM
4489#endif
4490}
4491
4492/* dccci */
4493GEN_HANDLER(dccci, 0x1F, 0x06, 0x0E, 0x03E00001, PPC_4xx_COMMON)
4494{
4495#if defined(CONFIG_USER_ONLY)
4496 RET_PRIVOPC(ctx);
4497#else
4498 if (unlikely(!ctx->supervisor)) {
4499 RET_PRIVOPC(ctx);
4500 return;
4501 }
4502 /* interpreted as no-op */
4503#endif
4504}
4505
4506/* dcread */
4507GEN_HANDLER(dcread, 0x1F, 0x06, 0x0F, 0x00000001, PPC_4xx_COMMON)
4508{
4509#if defined(CONFIG_USER_ONLY)
4510 RET_PRIVOPC(ctx);
4511#else
4512 if (unlikely(!ctx->supervisor)) {
4513 RET_PRIVOPC(ctx);
4514 return;
4515 }
4516 gen_addr_reg_index(ctx);
4517 op_ldst(lwz);
4518 gen_op_store_T0_gpr(rD(ctx->opcode));
4519#endif
4520}
4521
4522/* icbt */
4523GEN_HANDLER(icbt_40x, 0x1F, 0x06, 0x08, 0x03E00001, PPC_40x_SPEC)
4524{
4525 /* interpreted as no-op */
4526 /* XXX: specification say this is treated as a load by the MMU
4527 * but does not generate any exception
4528 */
4529}
4530
4531/* iccci */
4532GEN_HANDLER(iccci, 0x1F, 0x06, 0x1E, 0x00000001, PPC_4xx_COMMON)
4533{
4534#if defined(CONFIG_USER_ONLY)
4535 RET_PRIVOPC(ctx);
4536#else
4537 if (unlikely(!ctx->supervisor)) {
4538 RET_PRIVOPC(ctx);
4539 return;
4540 }
4541 /* interpreted as no-op */
4542#endif
4543}
4544
4545/* icread */
4546GEN_HANDLER(icread, 0x1F, 0x06, 0x1F, 0x03E00001, PPC_4xx_COMMON)
4547{
4548#if defined(CONFIG_USER_ONLY)
4549 RET_PRIVOPC(ctx);
4550#else
4551 if (unlikely(!ctx->supervisor)) {
4552 RET_PRIVOPC(ctx);
4553 return;
4554 }
4555 /* interpreted as no-op */
4556#endif
4557}
4558
4559/* rfci (supervisor only) */
a42bd6cc
JM
4560GEN_HANDLER(rfci_40x, 0x13, 0x13, 0x01, 0x03FF8001, PPC_40x_EXCP)
4561{
4562#if defined(CONFIG_USER_ONLY)
4563 RET_PRIVOPC(ctx);
4564#else
4565 if (unlikely(!ctx->supervisor)) {
4566 RET_PRIVOPC(ctx);
4567 return;
4568 }
4569 /* Restore CPU state */
4570 gen_op_40x_rfci();
4571 RET_CHG_FLOW(ctx);
4572#endif
4573}
4574
4575GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE)
4576{
4577#if defined(CONFIG_USER_ONLY)
4578 RET_PRIVOPC(ctx);
4579#else
4580 if (unlikely(!ctx->supervisor)) {
4581 RET_PRIVOPC(ctx);
4582 return;
4583 }
4584 /* Restore CPU state */
4585 gen_op_rfci();
4586 RET_CHG_FLOW(ctx);
4587#endif
4588}
4589
4590/* BookE specific */
4591GEN_HANDLER(rfdi, 0x13, 0x07, 0x01, 0x03FF8001, PPC_BOOKE)
76a66253
JM
4592{
4593#if defined(CONFIG_USER_ONLY)
4594 RET_PRIVOPC(ctx);
4595#else
4596 if (unlikely(!ctx->supervisor)) {
4597 RET_PRIVOPC(ctx);
4598 return;
4599 }
4600 /* Restore CPU state */
a42bd6cc 4601 gen_op_rfdi();
76a66253
JM
4602 RET_CHG_FLOW(ctx);
4603#endif
4604}
4605
a42bd6cc
JM
4606GEN_HANDLER(rfmci, 0x13, 0x06, 0x01, 0x03FF8001, PPC_BOOKE)
4607{
4608#if defined(CONFIG_USER_ONLY)
4609 RET_PRIVOPC(ctx);
4610#else
4611 if (unlikely(!ctx->supervisor)) {
4612 RET_PRIVOPC(ctx);
4613 return;
4614 }
4615 /* Restore CPU state */
4616 gen_op_rfmci();
4617 RET_CHG_FLOW(ctx);
4618#endif
4619}
d9bce9d9 4620/* TLB management - PowerPC 405 implementation */
76a66253 4621/* tlbre */
a42bd6cc 4622GEN_HANDLER(tlbre, 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_SPEC)
76a66253
JM
4623{
4624#if defined(CONFIG_USER_ONLY)
4625 RET_PRIVOPC(ctx);
4626#else
4627 if (unlikely(!ctx->supervisor)) {
4628 RET_PRIVOPC(ctx);
4629 return;
4630 }
4631 switch (rB(ctx->opcode)) {
4632 case 0:
9a64fbe4 4633 gen_op_load_gpr_T0(rA(ctx->opcode));
76a66253
JM
4634 gen_op_4xx_tlbre_hi();
4635 gen_op_store_T0_gpr(rD(ctx->opcode));
4636 break;
4637 case 1:
4638 gen_op_load_gpr_T0(rA(ctx->opcode));
4639 gen_op_4xx_tlbre_lo();
4640 gen_op_store_T0_gpr(rD(ctx->opcode));
4641 break;
4642 default:
4643 RET_INVAL(ctx);
4644 break;
9a64fbe4 4645 }
76a66253
JM
4646#endif
4647}
4648
d9bce9d9 4649/* tlbsx - tlbsx. */
a42bd6cc 4650GEN_HANDLER(tlbsx, 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_SPEC)
76a66253
JM
4651{
4652#if defined(CONFIG_USER_ONLY)
4653 RET_PRIVOPC(ctx);
4654#else
4655 if (unlikely(!ctx->supervisor)) {
4656 RET_PRIVOPC(ctx);
4657 return;
4658 }
4659 gen_addr_reg_index(ctx);
4660 if (Rc(ctx->opcode))
4661 gen_op_4xx_tlbsx_();
4662 else
4663 gen_op_4xx_tlbsx();
9a64fbe4 4664 gen_op_store_T0_gpr(rD(ctx->opcode));
76a66253 4665#endif
79aceca5
FB
4666}
4667
76a66253 4668/* tlbwe */
d9bce9d9 4669GEN_HANDLER(tlbwe, 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_SPEC)
79aceca5 4670{
76a66253
JM
4671#if defined(CONFIG_USER_ONLY)
4672 RET_PRIVOPC(ctx);
4673#else
4674 if (unlikely(!ctx->supervisor)) {
4675 RET_PRIVOPC(ctx);
4676 return;
4677 }
4678 switch (rB(ctx->opcode)) {
4679 case 0:
9a64fbe4 4680 gen_op_load_gpr_T0(rA(ctx->opcode));
76a66253
JM
4681 gen_op_load_gpr_T1(rS(ctx->opcode));
4682 gen_op_4xx_tlbwe_hi();
4683 break;
4684 case 1:
4685 gen_op_load_gpr_T0(rA(ctx->opcode));
4686 gen_op_load_gpr_T1(rS(ctx->opcode));
4687 gen_op_4xx_tlbwe_lo();
4688 break;
4689 default:
4690 RET_INVAL(ctx);
4691 break;
9a64fbe4 4692 }
76a66253
JM
4693#endif
4694}
4695
4696/* wrtee */
4697GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_EMB_COMMON)
4698{
4699#if defined(CONFIG_USER_ONLY)
4700 RET_PRIVOPC(ctx);
4701#else
4702 if (unlikely(!ctx->supervisor)) {
4703 RET_PRIVOPC(ctx);
4704 return;
4705 }
4706 gen_op_load_gpr_T0(rD(ctx->opcode));
a42bd6cc 4707 gen_op_wrte();
76a66253
JM
4708 RET_EXCP(ctx, EXCP_MTMSR, 0);
4709#endif
4710}
4711
4712/* wrteei */
4713GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000EFC01, PPC_EMB_COMMON)
4714{
4715#if defined(CONFIG_USER_ONLY)
4716 RET_PRIVOPC(ctx);
4717#else
4718 if (unlikely(!ctx->supervisor)) {
4719 RET_PRIVOPC(ctx);
4720 return;
4721 }
4722 gen_op_set_T0(ctx->opcode & 0x00010000);
a42bd6cc 4723 gen_op_wrte();
76a66253
JM
4724 RET_EXCP(ctx, EXCP_MTMSR, 0);
4725#endif
4726}
4727
08e46e54 4728/* PowerPC 440 specific instructions */
76a66253
JM
4729/* dlmzb */
4730GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC)
4731{
4732 gen_op_load_gpr_T0(rS(ctx->opcode));
4733 gen_op_load_gpr_T1(rB(ctx->opcode));
4734 gen_op_440_dlmzb();
4735 gen_op_store_T0_gpr(rA(ctx->opcode));
4736 gen_op_store_xer_bc();
4737 if (Rc(ctx->opcode)) {
4738 gen_op_440_dlmzb_update_Rc();
4739 gen_op_store_T0_crf(0);
4740 }
4741}
4742
4743/* mbar replaces eieio on 440 */
4744GEN_HANDLER(mbar, 0x1F, 0x16, 0x13, 0x001FF801, PPC_BOOKE)
4745{
4746 /* interpreted as no-op */
4747}
4748
4749/* msync replaces sync on 440 */
4750GEN_HANDLER(msync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_BOOKE)
4751{
4752 /* interpreted as no-op */
4753}
4754
4755/* icbt */
4756GEN_HANDLER(icbt_440, 0x1F, 0x16, 0x00, 0x03E00001, PPC_BOOKE)
4757{
4758 /* interpreted as no-op */
4759 /* XXX: specification say this is treated as a load by the MMU
4760 * but does not generate any exception
4761 */
79aceca5
FB
4762}
4763
35cdaad6 4764#if defined(TARGET_PPCEMB)
0487d6a8
JM
4765/*** SPE extension ***/
4766
4767/* Register moves */
4768GEN32(gen_op_load_gpr64_T0, gen_op_load_gpr64_T0_gpr);
4769GEN32(gen_op_load_gpr64_T1, gen_op_load_gpr64_T1_gpr);
4770#if 0 // unused
4771GEN32(gen_op_load_gpr64_T2, gen_op_load_gpr64_T2_gpr);
4772#endif
4773
4774GEN32(gen_op_store_T0_gpr64, gen_op_store_T0_gpr64_gpr);
4775GEN32(gen_op_store_T1_gpr64, gen_op_store_T1_gpr64_gpr);
4776#if 0 // unused
4777GEN32(gen_op_store_T2_gpr64, gen_op_store_T2_gpr64_gpr);
4778#endif
4779
4780#define GEN_SPE(name0, name1, opc2, opc3, inval, type) \
4781GEN_HANDLER(name0##_##name1, 0x04, opc2, opc3, inval, type) \
4782{ \
4783 if (Rc(ctx->opcode)) \
4784 gen_##name1(ctx); \
4785 else \
4786 gen_##name0(ctx); \
4787}
4788
4789/* Handler for undefined SPE opcodes */
4790static inline void gen_speundef (DisasContext *ctx)
4791{
4792 RET_INVAL(ctx);
4793}
4794
4795/* SPE load and stores */
4796static inline void gen_addr_spe_imm_index (DisasContext *ctx, int sh)
4797{
4798 target_long simm = rB(ctx->opcode);
4799
4800 if (rA(ctx->opcode) == 0) {
4801 gen_set_T0(simm << sh);
4802 } else {
4803 gen_op_load_gpr_T0(rA(ctx->opcode));
4804 if (likely(simm != 0))
4805 gen_op_addi(simm << sh);
4806 }
4807}
4808
4809#define op_spe_ldst(name) (*gen_op_##name[ctx->mem_idx])()
4810#if defined(CONFIG_USER_ONLY)
4811#if defined(TARGET_PPC64)
4812#define OP_SPE_LD_TABLE(name) \
4813static GenOpFunc *gen_op_spe_l##name[] = { \
4814 &gen_op_spe_l##name##_raw, \
4815 &gen_op_spe_l##name##_le_raw, \
4816 &gen_op_spe_l##name##_64_raw, \
4817 &gen_op_spe_l##name##_le_64_raw, \
4818};
4819#define OP_SPE_ST_TABLE(name) \
4820static GenOpFunc *gen_op_spe_st##name[] = { \
4821 &gen_op_spe_st##name##_raw, \
4822 &gen_op_spe_st##name##_le_raw, \
4823 &gen_op_spe_st##name##_64_raw, \
4824 &gen_op_spe_st##name##_le_64_raw, \
4825};
4826#else /* defined(TARGET_PPC64) */
4827#define OP_SPE_LD_TABLE(name) \
4828static GenOpFunc *gen_op_spe_l##name[] = { \
4829 &gen_op_spe_l##name##_raw, \
4830 &gen_op_spe_l##name##_le_raw, \
4831};
4832#define OP_SPE_ST_TABLE(name) \
4833static GenOpFunc *gen_op_spe_st##name[] = { \
4834 &gen_op_spe_st##name##_raw, \
4835 &gen_op_spe_st##name##_le_raw, \
4836};
4837#endif /* defined(TARGET_PPC64) */
4838#else /* defined(CONFIG_USER_ONLY) */
4839#if defined(TARGET_PPC64)
4840#define OP_SPE_LD_TABLE(name) \
4841static GenOpFunc *gen_op_spe_l##name[] = { \
4842 &gen_op_spe_l##name##_user, \
4843 &gen_op_spe_l##name##_le_user, \
4844 &gen_op_spe_l##name##_kernel, \
4845 &gen_op_spe_l##name##_le_kernel, \
4846 &gen_op_spe_l##name##_64_user, \
4847 &gen_op_spe_l##name##_le_64_user, \
4848 &gen_op_spe_l##name##_64_kernel, \
4849 &gen_op_spe_l##name##_le_64_kernel, \
4850};
4851#define OP_SPE_ST_TABLE(name) \
4852static GenOpFunc *gen_op_spe_st##name[] = { \
4853 &gen_op_spe_st##name##_user, \
4854 &gen_op_spe_st##name##_le_user, \
4855 &gen_op_spe_st##name##_kernel, \
4856 &gen_op_spe_st##name##_le_kernel, \
4857 &gen_op_spe_st##name##_64_user, \
4858 &gen_op_spe_st##name##_le_64_user, \
4859 &gen_op_spe_st##name##_64_kernel, \
4860 &gen_op_spe_st##name##_le_64_kernel, \
4861};
4862#else /* defined(TARGET_PPC64) */
4863#define OP_SPE_LD_TABLE(name) \
4864static GenOpFunc *gen_op_spe_l##name[] = { \
4865 &gen_op_spe_l##name##_user, \
4866 &gen_op_spe_l##name##_le_user, \
4867 &gen_op_spe_l##name##_kernel, \
4868 &gen_op_spe_l##name##_le_kernel, \
4869};
4870#define OP_SPE_ST_TABLE(name) \
4871static GenOpFunc *gen_op_spe_st##name[] = { \
4872 &gen_op_spe_st##name##_user, \
4873 &gen_op_spe_st##name##_le_user, \
4874 &gen_op_spe_st##name##_kernel, \
4875 &gen_op_spe_st##name##_le_kernel, \
4876};
4877#endif /* defined(TARGET_PPC64) */
4878#endif /* defined(CONFIG_USER_ONLY) */
4879
4880#define GEN_SPE_LD(name, sh) \
4881static inline void gen_evl##name (DisasContext *ctx) \
4882{ \
4883 if (unlikely(!ctx->spe_enabled)) { \
4884 RET_EXCP(ctx, EXCP_NO_SPE, 0); \
4885 return; \
4886 } \
4887 gen_addr_spe_imm_index(ctx, sh); \
4888 op_spe_ldst(spe_l##name); \
4889 gen_op_store_T1_gpr64(rD(ctx->opcode)); \
4890}
4891
4892#define GEN_SPE_LDX(name) \
4893static inline void gen_evl##name##x (DisasContext *ctx) \
4894{ \
4895 if (unlikely(!ctx->spe_enabled)) { \
4896 RET_EXCP(ctx, EXCP_NO_SPE, 0); \
4897 return; \
4898 } \
4899 gen_addr_reg_index(ctx); \
4900 op_spe_ldst(spe_l##name); \
4901 gen_op_store_T1_gpr64(rD(ctx->opcode)); \
4902}
4903
4904#define GEN_SPEOP_LD(name, sh) \
4905OP_SPE_LD_TABLE(name); \
4906GEN_SPE_LD(name, sh); \
4907GEN_SPE_LDX(name)
4908
4909#define GEN_SPE_ST(name, sh) \
4910static inline void gen_evst##name (DisasContext *ctx) \
4911{ \
4912 if (unlikely(!ctx->spe_enabled)) { \
4913 RET_EXCP(ctx, EXCP_NO_SPE, 0); \
4914 return; \
4915 } \
4916 gen_addr_spe_imm_index(ctx, sh); \
4917 gen_op_load_gpr64_T1(rS(ctx->opcode)); \
4918 op_spe_ldst(spe_st##name); \
4919}
4920
4921#define GEN_SPE_STX(name) \
4922static inline void gen_evst##name##x (DisasContext *ctx) \
4923{ \
4924 if (unlikely(!ctx->spe_enabled)) { \
4925 RET_EXCP(ctx, EXCP_NO_SPE, 0); \
4926 return; \
4927 } \
4928 gen_addr_reg_index(ctx); \
4929 gen_op_load_gpr64_T1(rS(ctx->opcode)); \
4930 op_spe_ldst(spe_st##name); \
4931}
4932
4933#define GEN_SPEOP_ST(name, sh) \
4934OP_SPE_ST_TABLE(name); \
4935GEN_SPE_ST(name, sh); \
4936GEN_SPE_STX(name)
4937
4938#define GEN_SPEOP_LDST(name, sh) \
4939GEN_SPEOP_LD(name, sh); \
4940GEN_SPEOP_ST(name, sh)
4941
4942/* SPE arithmetic and logic */
4943#define GEN_SPEOP_ARITH2(name) \
4944static inline void gen_##name (DisasContext *ctx) \
4945{ \
4946 if (unlikely(!ctx->spe_enabled)) { \
4947 RET_EXCP(ctx, EXCP_NO_SPE, 0); \
4948 return; \
4949 } \
4950 gen_op_load_gpr64_T0(rA(ctx->opcode)); \
4951 gen_op_load_gpr64_T1(rB(ctx->opcode)); \
4952 gen_op_##name(); \
4953 gen_op_store_T0_gpr64(rD(ctx->opcode)); \
4954}
4955
4956#define GEN_SPEOP_ARITH1(name) \
4957static inline void gen_##name (DisasContext *ctx) \
4958{ \
4959 if (unlikely(!ctx->spe_enabled)) { \
4960 RET_EXCP(ctx, EXCP_NO_SPE, 0); \
4961 return; \
4962 } \
4963 gen_op_load_gpr64_T0(rA(ctx->opcode)); \
4964 gen_op_##name(); \
4965 gen_op_store_T0_gpr64(rD(ctx->opcode)); \
4966}
4967
4968#define GEN_SPEOP_COMP(name) \
4969static inline void gen_##name (DisasContext *ctx) \
4970{ \
4971 if (unlikely(!ctx->spe_enabled)) { \
4972 RET_EXCP(ctx, EXCP_NO_SPE, 0); \
4973 return; \
4974 } \
4975 gen_op_load_gpr64_T0(rA(ctx->opcode)); \
4976 gen_op_load_gpr64_T1(rB(ctx->opcode)); \
4977 gen_op_##name(); \
4978 gen_op_store_T0_crf(crfD(ctx->opcode)); \
4979}
4980
4981/* Logical */
4982GEN_SPEOP_ARITH2(evand);
4983GEN_SPEOP_ARITH2(evandc);
4984GEN_SPEOP_ARITH2(evxor);
4985GEN_SPEOP_ARITH2(evor);
4986GEN_SPEOP_ARITH2(evnor);
4987GEN_SPEOP_ARITH2(eveqv);
4988GEN_SPEOP_ARITH2(evorc);
4989GEN_SPEOP_ARITH2(evnand);
4990GEN_SPEOP_ARITH2(evsrwu);
4991GEN_SPEOP_ARITH2(evsrws);
4992GEN_SPEOP_ARITH2(evslw);
4993GEN_SPEOP_ARITH2(evrlw);
4994GEN_SPEOP_ARITH2(evmergehi);
4995GEN_SPEOP_ARITH2(evmergelo);
4996GEN_SPEOP_ARITH2(evmergehilo);
4997GEN_SPEOP_ARITH2(evmergelohi);
4998
4999/* Arithmetic */
5000GEN_SPEOP_ARITH2(evaddw);
5001GEN_SPEOP_ARITH2(evsubfw);
5002GEN_SPEOP_ARITH1(evabs);
5003GEN_SPEOP_ARITH1(evneg);
5004GEN_SPEOP_ARITH1(evextsb);
5005GEN_SPEOP_ARITH1(evextsh);
5006GEN_SPEOP_ARITH1(evrndw);
5007GEN_SPEOP_ARITH1(evcntlzw);
5008GEN_SPEOP_ARITH1(evcntlsw);
5009static inline void gen_brinc (DisasContext *ctx)
5010{
5011 /* Note: brinc is usable even if SPE is disabled */
5012 gen_op_load_gpr64_T0(rA(ctx->opcode));
5013 gen_op_load_gpr64_T1(rB(ctx->opcode));
5014 gen_op_brinc();
5015 gen_op_store_T0_gpr64(rD(ctx->opcode));
5016}
5017
5018#define GEN_SPEOP_ARITH_IMM2(name) \
5019static inline void gen_##name##i (DisasContext *ctx) \
5020{ \
5021 if (unlikely(!ctx->spe_enabled)) { \
5022 RET_EXCP(ctx, EXCP_NO_SPE, 0); \
5023 return; \
5024 } \
5025 gen_op_load_gpr64_T0(rB(ctx->opcode)); \
5026 gen_op_splatwi_T1_64(rA(ctx->opcode)); \
5027 gen_op_##name(); \
5028 gen_op_store_T0_gpr64(rD(ctx->opcode)); \
5029}
5030
5031#define GEN_SPEOP_LOGIC_IMM2(name) \
5032static inline void gen_##name##i (DisasContext *ctx) \
5033{ \
5034 if (unlikely(!ctx->spe_enabled)) { \
5035 RET_EXCP(ctx, EXCP_NO_SPE, 0); \
5036 return; \
5037 } \
5038 gen_op_load_gpr64_T0(rA(ctx->opcode)); \
5039 gen_op_splatwi_T1_64(rB(ctx->opcode)); \
5040 gen_op_##name(); \
5041 gen_op_store_T0_gpr64(rD(ctx->opcode)); \
5042}
5043
5044GEN_SPEOP_ARITH_IMM2(evaddw);
5045#define gen_evaddiw gen_evaddwi
5046GEN_SPEOP_ARITH_IMM2(evsubfw);
5047#define gen_evsubifw gen_evsubfwi
5048GEN_SPEOP_LOGIC_IMM2(evslw);
5049GEN_SPEOP_LOGIC_IMM2(evsrwu);
5050#define gen_evsrwis gen_evsrwsi
5051GEN_SPEOP_LOGIC_IMM2(evsrws);
5052#define gen_evsrwiu gen_evsrwui
5053GEN_SPEOP_LOGIC_IMM2(evrlw);
5054
5055static inline void gen_evsplati (DisasContext *ctx)
5056{
5057 int32_t imm = (int32_t)(rA(ctx->opcode) << 27) >> 27;
5058
5059 gen_op_splatwi_T0_64(imm);
5060 gen_op_store_T0_gpr64(rD(ctx->opcode));
5061}
5062
5063static inline void gen_evsplatfi (DisasContext *ctx)
5064{
5065 uint32_t imm = rA(ctx->opcode) << 27;
5066
5067 gen_op_splatwi_T0_64(imm);
5068 gen_op_store_T0_gpr64(rD(ctx->opcode));
5069}
5070
5071/* Comparison */
5072GEN_SPEOP_COMP(evcmpgtu);
5073GEN_SPEOP_COMP(evcmpgts);
5074GEN_SPEOP_COMP(evcmpltu);
5075GEN_SPEOP_COMP(evcmplts);
5076GEN_SPEOP_COMP(evcmpeq);
5077
5078GEN_SPE(evaddw, speundef, 0x00, 0x08, 0x00000000, PPC_SPE); ////
5079GEN_SPE(evaddiw, speundef, 0x01, 0x08, 0x00000000, PPC_SPE);
5080GEN_SPE(evsubfw, speundef, 0x02, 0x08, 0x00000000, PPC_SPE); ////
5081GEN_SPE(evsubifw, speundef, 0x03, 0x08, 0x00000000, PPC_SPE);
5082GEN_SPE(evabs, evneg, 0x04, 0x08, 0x0000F800, PPC_SPE); ////
5083GEN_SPE(evextsb, evextsh, 0x05, 0x08, 0x0000F800, PPC_SPE); ////
5084GEN_SPE(evrndw, evcntlzw, 0x06, 0x08, 0x0000F800, PPC_SPE); ////
5085GEN_SPE(evcntlsw, brinc, 0x07, 0x08, 0x00000000, PPC_SPE); //
5086GEN_SPE(speundef, evand, 0x08, 0x08, 0x00000000, PPC_SPE); ////
5087GEN_SPE(evandc, speundef, 0x09, 0x08, 0x00000000, PPC_SPE); ////
5088GEN_SPE(evxor, evor, 0x0B, 0x08, 0x00000000, PPC_SPE); ////
5089GEN_SPE(evnor, eveqv, 0x0C, 0x08, 0x00000000, PPC_SPE); ////
5090GEN_SPE(speundef, evorc, 0x0D, 0x08, 0x00000000, PPC_SPE); ////
5091GEN_SPE(evnand, speundef, 0x0F, 0x08, 0x00000000, PPC_SPE); ////
5092GEN_SPE(evsrwu, evsrws, 0x10, 0x08, 0x00000000, PPC_SPE); ////
5093GEN_SPE(evsrwiu, evsrwis, 0x11, 0x08, 0x00000000, PPC_SPE);
5094GEN_SPE(evslw, speundef, 0x12, 0x08, 0x00000000, PPC_SPE); ////
5095GEN_SPE(evslwi, speundef, 0x13, 0x08, 0x00000000, PPC_SPE);
5096GEN_SPE(evrlw, evsplati, 0x14, 0x08, 0x00000000, PPC_SPE); //
5097GEN_SPE(evrlwi, evsplatfi, 0x15, 0x08, 0x00000000, PPC_SPE);
5098GEN_SPE(evmergehi, evmergelo, 0x16, 0x08, 0x00000000, PPC_SPE); ////
5099GEN_SPE(evmergehilo, evmergelohi, 0x17, 0x08, 0x00000000, PPC_SPE); ////
5100GEN_SPE(evcmpgtu, evcmpgts, 0x18, 0x08, 0x00600000, PPC_SPE); ////
5101GEN_SPE(evcmpltu, evcmplts, 0x19, 0x08, 0x00600000, PPC_SPE); ////
5102GEN_SPE(evcmpeq, speundef, 0x1A, 0x08, 0x00600000, PPC_SPE); ////
5103
5104static inline void gen_evsel (DisasContext *ctx)
5105{
5106 if (unlikely(!ctx->spe_enabled)) {
5107 RET_EXCP(ctx, EXCP_NO_SPE, 0);
5108 return;
5109 }
5110 gen_op_load_crf_T0(ctx->opcode & 0x7);
5111 gen_op_load_gpr64_T0(rA(ctx->opcode));
5112 gen_op_load_gpr64_T1(rB(ctx->opcode));
5113 gen_op_evsel();
5114 gen_op_store_T0_gpr64(rD(ctx->opcode));
5115}
5116
5117GEN_HANDLER(evsel0, 0x04, 0x1c, 0x09, 0x00000000, PPC_SPE)
5118{
5119 gen_evsel(ctx);
5120}
5121GEN_HANDLER(evsel1, 0x04, 0x1d, 0x09, 0x00000000, PPC_SPE)
5122{
5123 gen_evsel(ctx);
5124}
5125GEN_HANDLER(evsel2, 0x04, 0x1e, 0x09, 0x00000000, PPC_SPE)
5126{
5127 gen_evsel(ctx);
5128}
5129GEN_HANDLER(evsel3, 0x04, 0x1f, 0x09, 0x00000000, PPC_SPE)
5130{
5131 gen_evsel(ctx);
5132}
5133
5134/* Load and stores */
5135#if defined(TARGET_PPC64)
5136/* In that case, we already have 64 bits load & stores
5137 * so, spe_ldd is equivalent to ld and spe_std is equivalent to std
5138 */
5139#if defined(CONFIG_USER_ONLY)
5140#define gen_op_spe_ldd_raw gen_op_ld_raw
5141#define gen_op_spe_ldd_64_raw gen_op_ld_64_raw
5142#define gen_op_spe_ldd_le_raw gen_op_ld_le_raw
5143#define gen_op_spe_ldd_le_64_raw gen_op_ld_le_64_raw
5144#define gen_op_spe_stdd_raw gen_op_ld_raw
5145#define gen_op_spe_stdd_64_raw gen_op_std_64_raw
5146#define gen_op_spe_stdd_le_raw gen_op_std_le_raw
5147#define gen_op_spe_stdd_le_64_raw gen_op_std_le_64_raw
5148#else /* defined(CONFIG_USER_ONLY) */
5149#define gen_op_spe_ldd_kernel gen_op_ld_kernel
5150#define gen_op_spe_ldd_64_kernel gen_op_ld_64_kernel
5151#define gen_op_spe_ldd_le_kernel gen_op_ld_kernel
5152#define gen_op_spe_ldd_le_64_kernel gen_op_ld_64_kernel
5153#define gen_op_spe_ldd_user gen_op_ld_user
5154#define gen_op_spe_ldd_64_user gen_op_ld_64_user
5155#define gen_op_spe_ldd_le_user gen_op_ld_le_user
5156#define gen_op_spe_ldd_le_64_user gen_op_ld_le_64_user
5157#define gen_op_spe_stdd_kernel gen_op_std_kernel
5158#define gen_op_spe_stdd_64_kernel gen_op_std_64_kernel
5159#define gen_op_spe_stdd_le_kernel gen_op_std_kernel
5160#define gen_op_spe_stdd_le_64_kernel gen_op_std_64_kernel
5161#define gen_op_spe_stdd_user gen_op_std_user
5162#define gen_op_spe_stdd_64_user gen_op_std_64_user
5163#define gen_op_spe_stdd_le_user gen_op_std_le_user
5164#define gen_op_spe_stdd_le_64_user gen_op_std_le_64_user
5165#endif /* defined(CONFIG_USER_ONLY) */
5166#endif /* defined(TARGET_PPC64) */
5167GEN_SPEOP_LDST(dd, 3);
5168GEN_SPEOP_LDST(dw, 3);
5169GEN_SPEOP_LDST(dh, 3);
5170GEN_SPEOP_LDST(whe, 2);
5171GEN_SPEOP_LD(whou, 2);
5172GEN_SPEOP_LD(whos, 2);
5173GEN_SPEOP_ST(who, 2);
5174
5175#if defined(TARGET_PPC64)
5176/* In that case, spe_stwwo is equivalent to stw */
5177#if defined(CONFIG_USER_ONLY)
5178#define gen_op_spe_stwwo_raw gen_op_stw_raw
5179#define gen_op_spe_stwwo_le_raw gen_op_stw_le_raw
5180#define gen_op_spe_stwwo_64_raw gen_op_stw_64_raw
5181#define gen_op_spe_stwwo_le_64_raw gen_op_stw_le_64_raw
5182#else
5183#define gen_op_spe_stwwo_user gen_op_stw_user
5184#define gen_op_spe_stwwo_le_user gen_op_stw_le_user
5185#define gen_op_spe_stwwo_64_user gen_op_stw_64_user
5186#define gen_op_spe_stwwo_le_64_user gen_op_stw_le_64_user
5187#define gen_op_spe_stwwo_kernel gen_op_stw_kernel
5188#define gen_op_spe_stwwo_le_kernel gen_op_stw_le_kernel
5189#define gen_op_spe_stwwo_64_kernel gen_op_stw_64_kernel
5190#define gen_op_spe_stwwo_le_64_kernel gen_op_stw_le_64_kernel
5191#endif
5192#endif
5193#define _GEN_OP_SPE_STWWE(suffix) \
5194static inline void gen_op_spe_stwwe_##suffix (void) \
5195{ \
5196 gen_op_srli32_T1_64(); \
5197 gen_op_spe_stwwo_##suffix(); \
5198}
5199#define _GEN_OP_SPE_STWWE_LE(suffix) \
5200static inline void gen_op_spe_stwwe_le_##suffix (void) \
5201{ \
5202 gen_op_srli32_T1_64(); \
5203 gen_op_spe_stwwo_le_##suffix(); \
5204}
5205#if defined(TARGET_PPC64)
5206#define GEN_OP_SPE_STWWE(suffix) \
5207_GEN_OP_SPE_STWWE(suffix); \
5208_GEN_OP_SPE_STWWE_LE(suffix); \
5209static inline void gen_op_spe_stwwe_64_##suffix (void) \
5210{ \
5211 gen_op_srli32_T1_64(); \
5212 gen_op_spe_stwwo_64_##suffix(); \
5213} \
5214static inline void gen_op_spe_stwwe_le_64_##suffix (void) \
5215{ \
5216 gen_op_srli32_T1_64(); \
5217 gen_op_spe_stwwo_le_64_##suffix(); \
5218}
5219#else
5220#define GEN_OP_SPE_STWWE(suffix) \
5221_GEN_OP_SPE_STWWE(suffix); \
5222_GEN_OP_SPE_STWWE_LE(suffix)
5223#endif
5224#if defined(CONFIG_USER_ONLY)
5225GEN_OP_SPE_STWWE(raw);
5226#else /* defined(CONFIG_USER_ONLY) */
5227GEN_OP_SPE_STWWE(kernel);
5228GEN_OP_SPE_STWWE(user);
5229#endif /* defined(CONFIG_USER_ONLY) */
5230GEN_SPEOP_ST(wwe, 2);
5231GEN_SPEOP_ST(wwo, 2);
5232
5233#define GEN_SPE_LDSPLAT(name, op, suffix) \
5234static inline void gen_op_spe_l##name##_##suffix (void) \
5235{ \
5236 gen_op_##op##_##suffix(); \
5237 gen_op_splatw_T1_64(); \
5238}
5239
5240#define GEN_OP_SPE_LHE(suffix) \
5241static inline void gen_op_spe_lhe_##suffix (void) \
5242{ \
5243 gen_op_spe_lh_##suffix(); \
5244 gen_op_sli16_T1_64(); \
5245}
5246
5247#define GEN_OP_SPE_LHX(suffix) \
5248static inline void gen_op_spe_lhx_##suffix (void) \
5249{ \
5250 gen_op_spe_lh_##suffix(); \
5251 gen_op_extsh_T1_64(); \
5252}
5253
5254#if defined(CONFIG_USER_ONLY)
5255GEN_OP_SPE_LHE(raw);
5256GEN_SPE_LDSPLAT(hhesplat, spe_lhe, raw);
5257GEN_OP_SPE_LHE(le_raw);
5258GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_raw);
5259GEN_SPE_LDSPLAT(hhousplat, spe_lh, raw);
5260GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_raw);
5261GEN_OP_SPE_LHX(raw);
5262GEN_SPE_LDSPLAT(hhossplat, spe_lhx, raw);
5263GEN_OP_SPE_LHX(le_raw);
5264GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_raw);
5265#if defined(TARGET_PPC64)
5266GEN_OP_SPE_LHE(64_raw);
5267GEN_SPE_LDSPLAT(hhesplat, spe_lhe, 64_raw);
5268GEN_OP_SPE_LHE(le_64_raw);
5269GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_64_raw);
5270GEN_SPE_LDSPLAT(hhousplat, spe_lh, 64_raw);
5271GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_64_raw);
5272GEN_OP_SPE_LHX(64_raw);
5273GEN_SPE_LDSPLAT(hhossplat, spe_lhx, 64_raw);
5274GEN_OP_SPE_LHX(le_64_raw);
5275GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_raw);
5276#endif
5277#else
5278GEN_OP_SPE_LHE(kernel);
5279GEN_OP_SPE_LHE(user);
5280GEN_SPE_LDSPLAT(hhesplat, spe_lhe, kernel);
5281GEN_SPE_LDSPLAT(hhesplat, spe_lhe, user);
5282GEN_OP_SPE_LHE(le_kernel);
5283GEN_OP_SPE_LHE(le_user);
5284GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_kernel);
5285GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_user);
5286GEN_SPE_LDSPLAT(hhousplat, spe_lh, kernel);
5287GEN_SPE_LDSPLAT(hhousplat, spe_lh, user);
5288GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_kernel);
5289GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_user);
5290GEN_OP_SPE_LHX(kernel);
5291GEN_OP_SPE_LHX(user);
5292GEN_SPE_LDSPLAT(hhossplat, spe_lhx, kernel);
5293GEN_SPE_LDSPLAT(hhossplat, spe_lhx, user);
5294GEN_OP_SPE_LHX(le_kernel);
5295GEN_OP_SPE_LHX(le_user);
5296GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_kernel);
5297GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_user);
5298#if defined(TARGET_PPC64)
5299GEN_OP_SPE_LHE(64_kernel);
5300GEN_OP_SPE_LHE(64_user);
5301GEN_SPE_LDSPLAT(hhesplat, spe_lhe, 64_kernel);
5302GEN_SPE_LDSPLAT(hhesplat, spe_lhe, 64_user);
5303GEN_OP_SPE_LHE(le_64_kernel);
5304GEN_OP_SPE_LHE(le_64_user);
5305GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_64_kernel);
5306GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_64_user);
5307GEN_SPE_LDSPLAT(hhousplat, spe_lh, 64_kernel);
5308GEN_SPE_LDSPLAT(hhousplat, spe_lh, 64_user);
5309GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_64_kernel);
5310GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_64_user);
5311GEN_OP_SPE_LHX(64_kernel);
5312GEN_OP_SPE_LHX(64_user);
5313GEN_SPE_LDSPLAT(hhossplat, spe_lhx, 64_kernel);
5314GEN_SPE_LDSPLAT(hhossplat, spe_lhx, 64_user);
5315GEN_OP_SPE_LHX(le_64_kernel);
5316GEN_OP_SPE_LHX(le_64_user);
5317GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_kernel);
5318GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_user);
5319#endif
5320#endif
5321GEN_SPEOP_LD(hhesplat, 1);
5322GEN_SPEOP_LD(hhousplat, 1);
5323GEN_SPEOP_LD(hhossplat, 1);
5324GEN_SPEOP_LD(wwsplat, 2);
5325GEN_SPEOP_LD(whsplat, 2);
5326
5327GEN_SPE(evlddx, evldd, 0x00, 0x0C, 0x00000000, PPC_SPE); //
5328GEN_SPE(evldwx, evldw, 0x01, 0x0C, 0x00000000, PPC_SPE); //
5329GEN_SPE(evldhx, evldh, 0x02, 0x0C, 0x00000000, PPC_SPE); //
5330GEN_SPE(evlhhesplatx, evlhhesplat, 0x04, 0x0C, 0x00000000, PPC_SPE); //
5331GEN_SPE(evlhhousplatx, evlhhousplat, 0x06, 0x0C, 0x00000000, PPC_SPE); //
5332GEN_SPE(evlhhossplatx, evlhhossplat, 0x07, 0x0C, 0x00000000, PPC_SPE); //
5333GEN_SPE(evlwhex, evlwhe, 0x08, 0x0C, 0x00000000, PPC_SPE); //
5334GEN_SPE(evlwhoux, evlwhou, 0x0A, 0x0C, 0x00000000, PPC_SPE); //
5335GEN_SPE(evlwhosx, evlwhos, 0x0B, 0x0C, 0x00000000, PPC_SPE); //
5336GEN_SPE(evlwwsplatx, evlwwsplat, 0x0C, 0x0C, 0x00000000, PPC_SPE); //
5337GEN_SPE(evlwhsplatx, evlwhsplat, 0x0E, 0x0C, 0x00000000, PPC_SPE); //
5338GEN_SPE(evstddx, evstdd, 0x10, 0x0C, 0x00000000, PPC_SPE); //
5339GEN_SPE(evstdwx, evstdw, 0x11, 0x0C, 0x00000000, PPC_SPE); //
5340GEN_SPE(evstdhx, evstdh, 0x12, 0x0C, 0x00000000, PPC_SPE); //
5341GEN_SPE(evstwhex, evstwhe, 0x18, 0x0C, 0x00000000, PPC_SPE); //
5342GEN_SPE(evstwhox, evstwho, 0x1A, 0x0C, 0x00000000, PPC_SPE); //
5343GEN_SPE(evstwwex, evstwwe, 0x1C, 0x0C, 0x00000000, PPC_SPE); //
5344GEN_SPE(evstwwox, evstwwo, 0x1E, 0x0C, 0x00000000, PPC_SPE); //
5345
5346/* Multiply and add - TODO */
5347#if 0
5348GEN_SPE(speundef, evmhessf, 0x01, 0x10, 0x00000000, PPC_SPE);
5349GEN_SPE(speundef, evmhossf, 0x03, 0x10, 0x00000000, PPC_SPE);
5350GEN_SPE(evmheumi, evmhesmi, 0x04, 0x10, 0x00000000, PPC_SPE);
5351GEN_SPE(speundef, evmhesmf, 0x05, 0x10, 0x00000000, PPC_SPE);
5352GEN_SPE(evmhoumi, evmhosmi, 0x06, 0x10, 0x00000000, PPC_SPE);
5353GEN_SPE(speundef, evmhosmf, 0x07, 0x10, 0x00000000, PPC_SPE);
5354GEN_SPE(speundef, evmhessfa, 0x11, 0x10, 0x00000000, PPC_SPE);
5355GEN_SPE(speundef, evmhossfa, 0x13, 0x10, 0x00000000, PPC_SPE);
5356GEN_SPE(evmheumia, evmhesmia, 0x14, 0x10, 0x00000000, PPC_SPE);
5357GEN_SPE(speundef, evmhesmfa, 0x15, 0x10, 0x00000000, PPC_SPE);
5358GEN_SPE(evmhoumia, evmhosmia, 0x16, 0x10, 0x00000000, PPC_SPE);
5359GEN_SPE(speundef, evmhosmfa, 0x17, 0x10, 0x00000000, PPC_SPE);
5360
5361GEN_SPE(speundef, evmwhssf, 0x03, 0x11, 0x00000000, PPC_SPE);
5362GEN_SPE(evmwlumi, speundef, 0x04, 0x11, 0x00000000, PPC_SPE);
5363GEN_SPE(evmwhumi, evmwhsmi, 0x06, 0x11, 0x00000000, PPC_SPE);
5364GEN_SPE(speundef, evmwhsmf, 0x07, 0x11, 0x00000000, PPC_SPE);
5365GEN_SPE(speundef, evmwssf, 0x09, 0x11, 0x00000000, PPC_SPE);
5366GEN_SPE(evmwumi, evmwsmi, 0x0C, 0x11, 0x00000000, PPC_SPE);
5367GEN_SPE(speundef, evmwsmf, 0x0D, 0x11, 0x00000000, PPC_SPE);
5368GEN_SPE(speundef, evmwhssfa, 0x13, 0x11, 0x00000000, PPC_SPE);
5369GEN_SPE(evmwlumia, speundef, 0x14, 0x11, 0x00000000, PPC_SPE);
5370GEN_SPE(evmwhumia, evmwhsmia, 0x16, 0x11, 0x00000000, PPC_SPE);
5371GEN_SPE(speundef, evmwhsmfa, 0x17, 0x11, 0x00000000, PPC_SPE);
5372GEN_SPE(speundef, evmwssfa, 0x19, 0x11, 0x00000000, PPC_SPE);
5373GEN_SPE(evmwumia, evmwsmia, 0x1C, 0x11, 0x00000000, PPC_SPE);
5374GEN_SPE(speundef, evmwsmfa, 0x1D, 0x11, 0x00000000, PPC_SPE);
5375
5376GEN_SPE(evadduiaaw, evaddsiaaw, 0x00, 0x13, 0x0000F800, PPC_SPE);
5377GEN_SPE(evsubfusiaaw, evsubfssiaaw, 0x01, 0x13, 0x0000F800, PPC_SPE);
5378GEN_SPE(evaddumiaaw, evaddsmiaaw, 0x04, 0x13, 0x0000F800, PPC_SPE);
5379GEN_SPE(evsubfumiaaw, evsubfsmiaaw, 0x05, 0x13, 0x0000F800, PPC_SPE);
5380GEN_SPE(evdivws, evdivwu, 0x06, 0x13, 0x00000000, PPC_SPE);
5381GEN_SPE(evmra, speundef, 0x07, 0x13, 0x0000F800, PPC_SPE);
5382
5383GEN_SPE(evmheusiaaw, evmhessiaaw, 0x00, 0x14, 0x00000000, PPC_SPE);
5384GEN_SPE(speundef, evmhessfaaw, 0x01, 0x14, 0x00000000, PPC_SPE);
5385GEN_SPE(evmhousiaaw, evmhossiaaw, 0x02, 0x14, 0x00000000, PPC_SPE);
5386GEN_SPE(speundef, evmhossfaaw, 0x03, 0x14, 0x00000000, PPC_SPE);
5387GEN_SPE(evmheumiaaw, evmhesmiaaw, 0x04, 0x14, 0x00000000, PPC_SPE);
5388GEN_SPE(speundef, evmhesmfaaw, 0x05, 0x14, 0x00000000, PPC_SPE);
5389GEN_SPE(evmhoumiaaw, evmhosmiaaw, 0x06, 0x14, 0x00000000, PPC_SPE);
5390GEN_SPE(speundef, evmhosmfaaw, 0x07, 0x14, 0x00000000, PPC_SPE);
5391GEN_SPE(evmhegumiaa, evmhegsmiaa, 0x14, 0x14, 0x00000000, PPC_SPE);
5392GEN_SPE(speundef, evmhegsmfaa, 0x15, 0x14, 0x00000000, PPC_SPE);
5393GEN_SPE(evmhogumiaa, evmhogsmiaa, 0x16, 0x14, 0x00000000, PPC_SPE);
5394GEN_SPE(speundef, evmhogsmfaa, 0x17, 0x14, 0x00000000, PPC_SPE);
5395
5396GEN_SPE(evmwlusiaaw, evmwlssiaaw, 0x00, 0x15, 0x00000000, PPC_SPE);
5397GEN_SPE(evmwlumiaaw, evmwlsmiaaw, 0x04, 0x15, 0x00000000, PPC_SPE);
5398GEN_SPE(speundef, evmwssfaa, 0x09, 0x15, 0x00000000, PPC_SPE);
5399GEN_SPE(evmwumiaa, evmwsmiaa, 0x0C, 0x15, 0x00000000, PPC_SPE);
5400GEN_SPE(speundef, evmwsmfaa, 0x0D, 0x15, 0x00000000, PPC_SPE);
5401
5402GEN_SPE(evmheusianw, evmhessianw, 0x00, 0x16, 0x00000000, PPC_SPE);
5403GEN_SPE(speundef, evmhessfanw, 0x01, 0x16, 0x00000000, PPC_SPE);
5404GEN_SPE(evmhousianw, evmhossianw, 0x02, 0x16, 0x00000000, PPC_SPE);
5405GEN_SPE(speundef, evmhossfanw, 0x03, 0x16, 0x00000000, PPC_SPE);
5406GEN_SPE(evmheumianw, evmhesmianw, 0x04, 0x16, 0x00000000, PPC_SPE);
5407GEN_SPE(speundef, evmhesmfanw, 0x05, 0x16, 0x00000000, PPC_SPE);
5408GEN_SPE(evmhoumianw, evmhosmianw, 0x06, 0x16, 0x00000000, PPC_SPE);
5409GEN_SPE(speundef, evmhosmfanw, 0x07, 0x16, 0x00000000, PPC_SPE);
5410GEN_SPE(evmhegumian, evmhegsmian, 0x14, 0x16, 0x00000000, PPC_SPE);
5411GEN_SPE(speundef, evmhegsmfan, 0x15, 0x16, 0x00000000, PPC_SPE);
5412GEN_SPE(evmhigumian, evmhigsmian, 0x16, 0x16, 0x00000000, PPC_SPE);
5413GEN_SPE(speundef, evmhogsmfan, 0x17, 0x16, 0x00000000, PPC_SPE);
5414
5415GEN_SPE(evmwlusianw, evmwlssianw, 0x00, 0x17, 0x00000000, PPC_SPE);
5416GEN_SPE(evmwlumianw, evmwlsmianw, 0x04, 0x17, 0x00000000, PPC_SPE);
5417GEN_SPE(speundef, evmwssfan, 0x09, 0x17, 0x00000000, PPC_SPE);
5418GEN_SPE(evmwumian, evmwsmian, 0x0C, 0x17, 0x00000000, PPC_SPE);
5419GEN_SPE(speundef, evmwsmfan, 0x0D, 0x17, 0x00000000, PPC_SPE);
5420#endif
5421
5422/*** SPE floating-point extension ***/
5423#define GEN_SPEFPUOP_CONV(name) \
5424static inline void gen_##name (DisasContext *ctx) \
5425{ \
5426 gen_op_load_gpr64_T0(rB(ctx->opcode)); \
5427 gen_op_##name(); \
5428 gen_op_store_T0_gpr64(rD(ctx->opcode)); \
5429}
5430
5431/* Single precision floating-point vectors operations */
5432/* Arithmetic */
5433GEN_SPEOP_ARITH2(evfsadd);
5434GEN_SPEOP_ARITH2(evfssub);
5435GEN_SPEOP_ARITH2(evfsmul);
5436GEN_SPEOP_ARITH2(evfsdiv);
5437GEN_SPEOP_ARITH1(evfsabs);
5438GEN_SPEOP_ARITH1(evfsnabs);
5439GEN_SPEOP_ARITH1(evfsneg);
5440/* Conversion */
5441GEN_SPEFPUOP_CONV(evfscfui);
5442GEN_SPEFPUOP_CONV(evfscfsi);
5443GEN_SPEFPUOP_CONV(evfscfuf);
5444GEN_SPEFPUOP_CONV(evfscfsf);
5445GEN_SPEFPUOP_CONV(evfsctui);
5446GEN_SPEFPUOP_CONV(evfsctsi);
5447GEN_SPEFPUOP_CONV(evfsctuf);
5448GEN_SPEFPUOP_CONV(evfsctsf);
5449GEN_SPEFPUOP_CONV(evfsctuiz);
5450GEN_SPEFPUOP_CONV(evfsctsiz);
5451/* Comparison */
5452GEN_SPEOP_COMP(evfscmpgt);
5453GEN_SPEOP_COMP(evfscmplt);
5454GEN_SPEOP_COMP(evfscmpeq);
5455GEN_SPEOP_COMP(evfststgt);
5456GEN_SPEOP_COMP(evfststlt);
5457GEN_SPEOP_COMP(evfststeq);
5458
5459/* Opcodes definitions */
5460GEN_SPE(evfsadd, evfssub, 0x00, 0x0A, 0x00000000, PPC_SPEFPU); //
5461GEN_SPE(evfsabs, evfsnabs, 0x02, 0x0A, 0x0000F800, PPC_SPEFPU); //
5462GEN_SPE(evfsneg, speundef, 0x03, 0x0A, 0x0000F800, PPC_SPEFPU); //
5463GEN_SPE(evfsmul, evfsdiv, 0x04, 0x0A, 0x00000000, PPC_SPEFPU); //
5464GEN_SPE(evfscmpgt, evfscmplt, 0x06, 0x0A, 0x00600000, PPC_SPEFPU); //
5465GEN_SPE(evfscmpeq, speundef, 0x07, 0x0A, 0x00600000, PPC_SPEFPU); //
5466GEN_SPE(evfscfui, evfscfsi, 0x08, 0x0A, 0x00180000, PPC_SPEFPU); //
5467GEN_SPE(evfscfuf, evfscfsf, 0x09, 0x0A, 0x00180000, PPC_SPEFPU); //
5468GEN_SPE(evfsctui, evfsctsi, 0x0A, 0x0A, 0x00180000, PPC_SPEFPU); //
5469GEN_SPE(evfsctuf, evfsctsf, 0x0B, 0x0A, 0x00180000, PPC_SPEFPU); //
5470GEN_SPE(evfsctuiz, speundef, 0x0C, 0x0A, 0x00180000, PPC_SPEFPU); //
5471GEN_SPE(evfsctsiz, speundef, 0x0D, 0x0A, 0x00180000, PPC_SPEFPU); //
5472GEN_SPE(evfststgt, evfststlt, 0x0E, 0x0A, 0x00600000, PPC_SPEFPU); //
5473GEN_SPE(evfststeq, speundef, 0x0F, 0x0A, 0x00600000, PPC_SPEFPU); //
5474
5475/* Single precision floating-point operations */
5476/* Arithmetic */
5477GEN_SPEOP_ARITH2(efsadd);
5478GEN_SPEOP_ARITH2(efssub);
5479GEN_SPEOP_ARITH2(efsmul);
5480GEN_SPEOP_ARITH2(efsdiv);
5481GEN_SPEOP_ARITH1(efsabs);
5482GEN_SPEOP_ARITH1(efsnabs);
5483GEN_SPEOP_ARITH1(efsneg);
5484/* Conversion */
5485GEN_SPEFPUOP_CONV(efscfui);
5486GEN_SPEFPUOP_CONV(efscfsi);
5487GEN_SPEFPUOP_CONV(efscfuf);
5488GEN_SPEFPUOP_CONV(efscfsf);
5489GEN_SPEFPUOP_CONV(efsctui);
5490GEN_SPEFPUOP_CONV(efsctsi);
5491GEN_SPEFPUOP_CONV(efsctuf);
5492GEN_SPEFPUOP_CONV(efsctsf);
5493GEN_SPEFPUOP_CONV(efsctuiz);
5494GEN_SPEFPUOP_CONV(efsctsiz);
5495GEN_SPEFPUOP_CONV(efscfd);
5496/* Comparison */
5497GEN_SPEOP_COMP(efscmpgt);
5498GEN_SPEOP_COMP(efscmplt);
5499GEN_SPEOP_COMP(efscmpeq);
5500GEN_SPEOP_COMP(efststgt);
5501GEN_SPEOP_COMP(efststlt);
5502GEN_SPEOP_COMP(efststeq);
5503
5504/* Opcodes definitions */
5505GEN_SPE(efsadd, efssub, 0x00, 0x0A, 0x00000000, PPC_SPEFPU); //
5506GEN_SPE(efsabs, efsnabs, 0x02, 0x0B, 0x0000F800, PPC_SPEFPU); //
5507GEN_SPE(efsneg, speundef, 0x03, 0x0B, 0x0000F800, PPC_SPEFPU); //
5508GEN_SPE(efsmul, efsdiv, 0x04, 0x0B, 0x00000000, PPC_SPEFPU); //
5509GEN_SPE(efscmpgt, efscmplt, 0x06, 0x0B, 0x00600000, PPC_SPEFPU); //
5510GEN_SPE(efscmpeq, efscfd, 0x07, 0x0B, 0x00600000, PPC_SPEFPU); //
5511GEN_SPE(efscfui, efscfsi, 0x08, 0x0B, 0x00180000, PPC_SPEFPU); //
5512GEN_SPE(efscfuf, efscfsf, 0x09, 0x0B, 0x00180000, PPC_SPEFPU); //
5513GEN_SPE(efsctui, efsctsi, 0x0A, 0x0B, 0x00180000, PPC_SPEFPU); //
5514GEN_SPE(efsctuf, efsctsf, 0x0B, 0x0B, 0x00180000, PPC_SPEFPU); //
5515GEN_SPE(efsctuiz, efsctsiz, 0x0C, 0x0B, 0x00180000, PPC_SPEFPU); //
5516GEN_SPE(efststgt, efststlt, 0x0E, 0x0B, 0x00600000, PPC_SPEFPU); //
5517GEN_SPE(efststeq, speundef, 0x0F, 0x0B, 0x00600000, PPC_SPEFPU); //
5518
5519/* Double precision floating-point operations */
5520/* Arithmetic */
5521GEN_SPEOP_ARITH2(efdadd);
5522GEN_SPEOP_ARITH2(efdsub);
5523GEN_SPEOP_ARITH2(efdmul);
5524GEN_SPEOP_ARITH2(efddiv);
5525GEN_SPEOP_ARITH1(efdabs);
5526GEN_SPEOP_ARITH1(efdnabs);
5527GEN_SPEOP_ARITH1(efdneg);
5528/* Conversion */
5529
5530GEN_SPEFPUOP_CONV(efdcfui);
5531GEN_SPEFPUOP_CONV(efdcfsi);
5532GEN_SPEFPUOP_CONV(efdcfuf);
5533GEN_SPEFPUOP_CONV(efdcfsf);
5534GEN_SPEFPUOP_CONV(efdctui);
5535GEN_SPEFPUOP_CONV(efdctsi);
5536GEN_SPEFPUOP_CONV(efdctuf);
5537GEN_SPEFPUOP_CONV(efdctsf);
5538GEN_SPEFPUOP_CONV(efdctuiz);
5539GEN_SPEFPUOP_CONV(efdctsiz);
5540GEN_SPEFPUOP_CONV(efdcfs);
5541GEN_SPEFPUOP_CONV(efdcfuid);
5542GEN_SPEFPUOP_CONV(efdcfsid);
5543GEN_SPEFPUOP_CONV(efdctuidz);
5544GEN_SPEFPUOP_CONV(efdctsidz);
5545/* Comparison */
5546GEN_SPEOP_COMP(efdcmpgt);
5547GEN_SPEOP_COMP(efdcmplt);
5548GEN_SPEOP_COMP(efdcmpeq);
5549GEN_SPEOP_COMP(efdtstgt);
5550GEN_SPEOP_COMP(efdtstlt);
5551GEN_SPEOP_COMP(efdtsteq);
5552
5553/* Opcodes definitions */
5554GEN_SPE(efdadd, efdsub, 0x10, 0x0B, 0x00000000, PPC_SPEFPU); //
5555GEN_SPE(efdcfuid, efdcfsid, 0x11, 0x0B, 0x00180000, PPC_SPEFPU); //
5556GEN_SPE(efdabs, efdnabs, 0x12, 0x0B, 0x0000F800, PPC_SPEFPU); //
5557GEN_SPE(efdneg, speundef, 0x13, 0x0B, 0x0000F800, PPC_SPEFPU); //
5558GEN_SPE(efdmul, efddiv, 0x14, 0x0B, 0x00000000, PPC_SPEFPU); //
5559GEN_SPE(efdctuidz, efdctsidz, 0x15, 0x0B, 0x00180000, PPC_SPEFPU); //
5560GEN_SPE(efdcmpgt, efdcmplt, 0x16, 0x0B, 0x00600000, PPC_SPEFPU); //
5561GEN_SPE(efdcmpeq, efdcfs, 0x17, 0x0B, 0x00600000, PPC_SPEFPU); //
5562GEN_SPE(efdcfui, efdcfsi, 0x18, 0x0B, 0x00180000, PPC_SPEFPU); //
5563GEN_SPE(efdcfuf, efdcfsf, 0x19, 0x0B, 0x00180000, PPC_SPEFPU); //
5564GEN_SPE(efdctui, efdctsi, 0x1A, 0x0B, 0x00180000, PPC_SPEFPU); //
5565GEN_SPE(efdctuf, efdctsf, 0x1B, 0x0B, 0x00180000, PPC_SPEFPU); //
5566GEN_SPE(efdctuiz, speundef, 0x1C, 0x0B, 0x00180000, PPC_SPEFPU); //
5567GEN_SPE(efdctsiz, speundef, 0x1D, 0x0B, 0x00180000, PPC_SPEFPU); //
5568GEN_SPE(efdtstgt, efdtstlt, 0x1E, 0x0B, 0x00600000, PPC_SPEFPU); //
5569GEN_SPE(efdtsteq, speundef, 0x1F, 0x0B, 0x00600000, PPC_SPEFPU); //
5570#endif
5571
79aceca5
FB
5572/* End opcode list */
5573GEN_OPCODE_MARK(end);
5574
3fc6c082 5575#include "translate_init.c"
79aceca5 5576
9a64fbe4 5577/*****************************************************************************/
3fc6c082 5578/* Misc PowerPC helpers */
76a66253
JM
5579static inline uint32_t load_xer (CPUState *env)
5580{
5581 return (xer_so << XER_SO) |
5582 (xer_ov << XER_OV) |
5583 (xer_ca << XER_CA) |
5584 (xer_bc << XER_BC) |
5585 (xer_cmp << XER_CMP);
5586}
5587
5fafdf24 5588void cpu_dump_state(CPUState *env, FILE *f,
7fe48483
FB
5589 int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
5590 int flags)
79aceca5 5591{
3fc6c082
FB
5592#if defined(TARGET_PPC64) || 1
5593#define FILL ""
3fc6c082
FB
5594#define RGPL 4
5595#define RFPL 4
5596#else
5597#define FILL " "
3fc6c082
FB
5598#define RGPL 8
5599#define RFPL 4
5600#endif
5601
79aceca5
FB
5602 int i;
5603
1b9eb036 5604 cpu_fprintf(f, "NIP " ADDRX " LR " ADDRX " CTR " ADDRX "\n",
3fc6c082 5605 env->nip, env->lr, env->ctr);
d9bce9d9
JM
5606 cpu_fprintf(f, "MSR " REGX FILL " XER %08x "
5607#if !defined(NO_TIMER_DUMP)
5608 "TB %08x %08x "
76a66253
JM
5609#if !defined(CONFIG_USER_ONLY)
5610 "DECR %08x"
d9bce9d9 5611#endif
76a66253
JM
5612#endif
5613 "\n",
d9bce9d9
JM
5614 do_load_msr(env), load_xer(env)
5615#if !defined(NO_TIMER_DUMP)
5616 , cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env)
76a66253
JM
5617#if !defined(CONFIG_USER_ONLY)
5618 , cpu_ppc_load_decr(env)
d9bce9d9 5619#endif
76a66253
JM
5620#endif
5621 );
5622 for (i = 0; i < 32; i++) {
3fc6c082
FB
5623 if ((i & (RGPL - 1)) == 0)
5624 cpu_fprintf(f, "GPR%02d", i);
5625 cpu_fprintf(f, " " REGX, env->gpr[i]);
5626 if ((i & (RGPL - 1)) == (RGPL - 1))
7fe48483 5627 cpu_fprintf(f, "\n");
76a66253 5628 }
3fc6c082 5629 cpu_fprintf(f, "CR ");
76a66253 5630 for (i = 0; i < 8; i++)
7fe48483
FB
5631 cpu_fprintf(f, "%01x", env->crf[i]);
5632 cpu_fprintf(f, " [");
76a66253
JM
5633 for (i = 0; i < 8; i++) {
5634 char a = '-';
5635 if (env->crf[i] & 0x08)
5636 a = 'L';
5637 else if (env->crf[i] & 0x04)
5638 a = 'G';
5639 else if (env->crf[i] & 0x02)
5640 a = 'E';
7fe48483 5641 cpu_fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' ');
76a66253 5642 }
3fc6c082
FB
5643 cpu_fprintf(f, " ] " FILL "RES " REGX "\n", env->reserve);
5644 for (i = 0; i < 32; i++) {
5645 if ((i & (RFPL - 1)) == 0)
5646 cpu_fprintf(f, "FPR%02d", i);
26a76461 5647 cpu_fprintf(f, " %016" PRIx64, *((uint64_t *)&env->fpr[i]));
3fc6c082 5648 if ((i & (RFPL - 1)) == (RFPL - 1))
7fe48483 5649 cpu_fprintf(f, "\n");
79aceca5 5650 }
3fc6c082
FB
5651 cpu_fprintf(f, "SRR0 " REGX " SRR1 " REGX " " FILL FILL FILL
5652 "SDR1 " REGX "\n",
5653 env->spr[SPR_SRR0], env->spr[SPR_SRR1], env->sdr1);
79aceca5 5654
3fc6c082
FB
5655#undef RGPL
5656#undef RFPL
5657#undef FILL
79aceca5
FB
5658}
5659
76a66253
JM
5660void cpu_dump_statistics (CPUState *env, FILE*f,
5661 int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
5662 int flags)
5663{
5664#if defined(DO_PPC_STATISTICS)
5665 opc_handler_t **t1, **t2, **t3, *handler;
5666 int op1, op2, op3;
5667
5668 t1 = env->opcodes;
5669 for (op1 = 0; op1 < 64; op1++) {
5670 handler = t1[op1];
5671 if (is_indirect_opcode(handler)) {
5672 t2 = ind_table(handler);
5673 for (op2 = 0; op2 < 32; op2++) {
5674 handler = t2[op2];
5675 if (is_indirect_opcode(handler)) {
5676 t3 = ind_table(handler);
5677 for (op3 = 0; op3 < 32; op3++) {
5678 handler = t3[op3];
5679 if (handler->count == 0)
5680 continue;
5681 cpu_fprintf(f, "%02x %02x %02x (%02x %04d) %16s: "
5682 "%016llx %lld\n",
5683 op1, op2, op3, op1, (op3 << 5) | op2,
5684 handler->oname,
5685 handler->count, handler->count);
5686 }
5687 } else {
5688 if (handler->count == 0)
5689 continue;
5690 cpu_fprintf(f, "%02x %02x (%02x %04d) %16s: "
5691 "%016llx %lld\n",
5692 op1, op2, op1, op2, handler->oname,
5693 handler->count, handler->count);
5694 }
5695 }
5696 } else {
5697 if (handler->count == 0)
5698 continue;
5699 cpu_fprintf(f, "%02x (%02x ) %16s: %016llx %lld\n",
5700 op1, op1, handler->oname,
5701 handler->count, handler->count);
5702 }
5703 }
5704#endif
5705}
5706
9a64fbe4 5707/*****************************************************************************/
0487d6a8
JM
5708static inline int gen_intermediate_code_internal (CPUState *env,
5709 TranslationBlock *tb,
5710 int search_pc)
79aceca5 5711{
9fddaa0c 5712 DisasContext ctx, *ctxp = &ctx;
79aceca5 5713 opc_handler_t **table, *handler;
0fa85d43 5714 target_ulong pc_start;
79aceca5
FB
5715 uint16_t *gen_opc_end;
5716 int j, lj = -1;
79aceca5
FB
5717
5718 pc_start = tb->pc;
5719 gen_opc_ptr = gen_opc_buf;
5720 gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
5721 gen_opparam_ptr = gen_opparam_buf;
c53be334 5722 nb_gen_labels = 0;
046d6672 5723 ctx.nip = pc_start;
79aceca5 5724 ctx.tb = tb;
9a64fbe4 5725 ctx.exception = EXCP_NONE;
3fc6c082 5726 ctx.spr_cb = env->spr_cb;
9a64fbe4 5727#if defined(CONFIG_USER_ONLY)
111bfab3 5728 ctx.mem_idx = msr_le;
d9bce9d9
JM
5729#if defined(TARGET_PPC64)
5730 ctx.mem_idx |= msr_sf << 1;
5731#endif
9a64fbe4
FB
5732#else
5733 ctx.supervisor = 1 - msr_pr;
111bfab3 5734 ctx.mem_idx = ((1 - msr_pr) << 1) | msr_le;
d9bce9d9
JM
5735#if defined(TARGET_PPC64)
5736 ctx.mem_idx |= msr_sf << 2;
5737#endif
5738#endif
5739#if defined(TARGET_PPC64)
5740 ctx.sf_mode = msr_sf;
9a64fbe4 5741#endif
3cc62370 5742 ctx.fpu_enabled = msr_fp;
35cdaad6 5743#if defined(TARGET_PPCEMB)
0487d6a8
JM
5744 ctx.spe_enabled = msr_spe;
5745#endif
ea4e754f 5746 ctx.singlestep_enabled = env->singlestep_enabled;
3fc6c082 5747#if defined (DO_SINGLE_STEP) && 0
9a64fbe4
FB
5748 /* Single step trace mode */
5749 msr_se = 1;
5750#endif
5751 /* Set env in case of segfault during code fetch */
5752 while (ctx.exception == EXCP_NONE && gen_opc_ptr < gen_opc_end) {
76a66253
JM
5753 if (unlikely(env->nb_breakpoints > 0)) {
5754 for (j = 0; j < env->nb_breakpoints; j++) {
ea4e754f 5755 if (env->breakpoints[j] == ctx.nip) {
5fafdf24 5756 gen_update_nip(&ctx, ctx.nip);
ea4e754f
FB
5757 gen_op_debug();
5758 break;
5759 }
5760 }
5761 }
76a66253 5762 if (unlikely(search_pc)) {
79aceca5
FB
5763 j = gen_opc_ptr - gen_opc_buf;
5764 if (lj < j) {
5765 lj++;
5766 while (lj < j)
5767 gen_opc_instr_start[lj++] = 0;
046d6672 5768 gen_opc_pc[lj] = ctx.nip;
79aceca5
FB
5769 gen_opc_instr_start[lj] = 1;
5770 }
5771 }
9fddaa0c
FB
5772#if defined PPC_DEBUG_DISAS
5773 if (loglevel & CPU_LOG_TB_IN_ASM) {
79aceca5 5774 fprintf(logfile, "----------------\n");
1b9eb036 5775 fprintf(logfile, "nip=" ADDRX " super=%d ir=%d\n",
9a64fbe4
FB
5776 ctx.nip, 1 - msr_pr, msr_ir);
5777 }
5778#endif
0fa85d43 5779 ctx.opcode = ldl_code(ctx.nip);
111bfab3
FB
5780 if (msr_le) {
5781 ctx.opcode = ((ctx.opcode & 0xFF000000) >> 24) |
5782 ((ctx.opcode & 0x00FF0000) >> 8) |
5783 ((ctx.opcode & 0x0000FF00) << 8) |
5784 ((ctx.opcode & 0x000000FF) << 24);
5785 }
9fddaa0c
FB
5786#if defined PPC_DEBUG_DISAS
5787 if (loglevel & CPU_LOG_TB_IN_ASM) {
111bfab3 5788 fprintf(logfile, "translate opcode %08x (%02x %02x %02x) (%s)\n",
9a64fbe4 5789 ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode),
111bfab3 5790 opc3(ctx.opcode), msr_le ? "little" : "big");
79aceca5
FB
5791 }
5792#endif
046d6672 5793 ctx.nip += 4;
3fc6c082 5794 table = env->opcodes;
79aceca5
FB
5795 handler = table[opc1(ctx.opcode)];
5796 if (is_indirect_opcode(handler)) {
5797 table = ind_table(handler);
5798 handler = table[opc2(ctx.opcode)];
5799 if (is_indirect_opcode(handler)) {
5800 table = ind_table(handler);
5801 handler = table[opc3(ctx.opcode)];
5802 }
5803 }
5804 /* Is opcode *REALLY* valid ? */
76a66253 5805 if (unlikely(handler->handler == &gen_invalid)) {
4a057712 5806 if (loglevel != 0) {
76a66253 5807 fprintf(logfile, "invalid/unsupported opcode: "
1b9eb036 5808 "%02x - %02x - %02x (%08x) 0x" ADDRX " %d\n",
76a66253 5809 opc1(ctx.opcode), opc2(ctx.opcode),
4b3686fa
FB
5810 opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir);
5811 } else {
5812 printf("invalid/unsupported opcode: "
1b9eb036 5813 "%02x - %02x - %02x (%08x) 0x" ADDRX " %d\n",
4b3686fa
FB
5814 opc1(ctx.opcode), opc2(ctx.opcode),
5815 opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir);
5816 }
76a66253
JM
5817 } else {
5818 if (unlikely((ctx.opcode & handler->inval) != 0)) {
4a057712 5819 if (loglevel != 0) {
79aceca5 5820 fprintf(logfile, "invalid bits: %08x for opcode: "
1b9eb036 5821 "%02x -%02x - %02x (%08x) 0x" ADDRX "\n",
79aceca5
FB
5822 ctx.opcode & handler->inval, opc1(ctx.opcode),
5823 opc2(ctx.opcode), opc3(ctx.opcode),
046d6672 5824 ctx.opcode, ctx.nip - 4);
9a64fbe4
FB
5825 } else {
5826 printf("invalid bits: %08x for opcode: "
1b9eb036 5827 "%02x -%02x - %02x (%08x) 0x" ADDRX "\n",
76a66253
JM
5828 ctx.opcode & handler->inval, opc1(ctx.opcode),
5829 opc2(ctx.opcode), opc3(ctx.opcode),
046d6672 5830 ctx.opcode, ctx.nip - 4);
76a66253 5831 }
4b3686fa
FB
5832 RET_INVAL(ctxp);
5833 break;
79aceca5 5834 }
79aceca5 5835 }
4b3686fa 5836 (*(handler->handler))(&ctx);
76a66253
JM
5837#if defined(DO_PPC_STATISTICS)
5838 handler->count++;
5839#endif
9a64fbe4 5840 /* Check trace mode exceptions */
08e46e54 5841#if 0 // XXX: buggy on embedded PowerPC
76a66253
JM
5842 if (unlikely((msr_be && ctx.exception == EXCP_BRANCH) ||
5843 /* Check in single step trace mode
5844 * we need to stop except if:
5845 * - rfi, trap or syscall
5846 * - first instruction of an exception handler
5847 */
5848 (msr_se && (ctx.nip < 0x100 ||
5849 ctx.nip > 0xF00 ||
5850 (ctx.nip & 0xFC) != 0x04) &&
5851 ctx.exception != EXCP_SYSCALL &&
5852 ctx.exception != EXCP_SYSCALL_USER &&
5853 ctx.exception != EXCP_TRAP))) {
9fddaa0c 5854 RET_EXCP(ctxp, EXCP_TRACE, 0);
9a64fbe4 5855 }
08e46e54 5856#endif
ea4e754f
FB
5857 /* if we reach a page boundary or are single stepping, stop
5858 * generation
5859 */
76a66253
JM
5860 if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) ||
5861 (env->singlestep_enabled))) {
8dd4983c 5862 break;
76a66253 5863 }
3fc6c082
FB
5864#if defined (DO_SINGLE_STEP)
5865 break;
5866#endif
5867 }
9fddaa0c 5868 if (ctx.exception == EXCP_NONE) {
c1942362 5869 gen_goto_tb(&ctx, 0, ctx.nip);
9fddaa0c 5870 } else if (ctx.exception != EXCP_BRANCH) {
76a66253
JM
5871 gen_op_reset_T0();
5872 /* Generate the return instruction */
5873 gen_op_exit_tb();
9a64fbe4 5874 }
79aceca5 5875 *gen_opc_ptr = INDEX_op_end;
76a66253 5876 if (unlikely(search_pc)) {
9a64fbe4
FB
5877 j = gen_opc_ptr - gen_opc_buf;
5878 lj++;
5879 while (lj <= j)
5880 gen_opc_instr_start[lj++] = 0;
9a64fbe4 5881 } else {
046d6672 5882 tb->size = ctx.nip - pc_start;
9a64fbe4 5883 }
d9bce9d9 5884#if defined(DEBUG_DISAS)
9fddaa0c 5885 if (loglevel & CPU_LOG_TB_CPU) {
9a64fbe4 5886 fprintf(logfile, "---------------- excp: %04x\n", ctx.exception);
7fe48483 5887 cpu_dump_state(env, logfile, fprintf, 0);
9fddaa0c
FB
5888 }
5889 if (loglevel & CPU_LOG_TB_IN_ASM) {
76a66253
JM
5890 int flags;
5891 flags = msr_le;
0fa85d43 5892 fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
76a66253 5893 target_disas(logfile, pc_start, ctx.nip - pc_start, flags);
79aceca5 5894 fprintf(logfile, "\n");
9fddaa0c
FB
5895 }
5896 if (loglevel & CPU_LOG_TB_OP) {
79aceca5
FB
5897 fprintf(logfile, "OP:\n");
5898 dump_ops(gen_opc_buf, gen_opparam_buf);
5899 fprintf(logfile, "\n");
5900 }
5901#endif
79aceca5
FB
5902 return 0;
5903}
5904
9a64fbe4 5905int gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
79aceca5
FB
5906{
5907 return gen_intermediate_code_internal(env, tb, 0);
5908}
5909
9a64fbe4 5910int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
79aceca5
FB
5911{
5912 return gen_intermediate_code_internal(env, tb, 1);
5913}