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