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