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