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