]> git.proxmox.com Git - qemu.git/blame - target-ppc/translate.c
ARM register index+writeback fix (Lauro Ramos Venancio).
[qemu.git] / target-ppc / translate.c
CommitLineData
79aceca5 1/*
3fc6c082 2 * PowerPC emulation for qemu: main translation routines.
79aceca5 3 *
76a66253 4 * Copyright (c) 2003-2007 Jocelyn Mayer
79aceca5
FB
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
c6a1c22b
FB
20#include <stdarg.h>
21#include <stdlib.h>
22#include <stdio.h>
23#include <string.h>
24#include <inttypes.h>
25
79aceca5 26#include "cpu.h"
c6a1c22b 27#include "exec-all.h"
79aceca5
FB
28#include "disas.h"
29
30//#define DO_SINGLE_STEP
9fddaa0c 31//#define PPC_DEBUG_DISAS
76a66253 32//#define DO_PPC_STATISTICS
79aceca5 33
c53be334
FB
34#ifdef USE_DIRECT_JUMP
35#define TBPARAM(x)
36#else
37#define TBPARAM(x) (long)(x)
38#endif
39
79aceca5
FB
40enum {
41#define DEF(s, n, copy_size) INDEX_op_ ## s,
42#include "opc.h"
43#undef DEF
44 NB_OPS,
45};
46
47static uint16_t *gen_opc_ptr;
48static uint32_t *gen_opparam_ptr;
49
50#include "gen-op.h"
28b6751f 51
28b6751f 52#define GEN8(func, NAME) \
9a64fbe4
FB
53static GenOpFunc *NAME ## _table [8] = { \
54NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \
55NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \
56}; \
57static inline void func(int n) \
58{ \
59 NAME ## _table[n](); \
60}
61
62#define GEN16(func, NAME) \
63static GenOpFunc *NAME ## _table [16] = { \
64NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \
65NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \
66NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \
67NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \
68}; \
69static inline void func(int n) \
70{ \
71 NAME ## _table[n](); \
28b6751f
FB
72}
73
74#define GEN32(func, NAME) \
9a64fbe4
FB
75static GenOpFunc *NAME ## _table [32] = { \
76NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \
77NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \
78NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \
79NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \
80NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \
81NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \
82NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \
83NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \
84}; \
85static inline void func(int n) \
86{ \
87 NAME ## _table[n](); \
88}
89
90/* Condition register moves */
91GEN8(gen_op_load_crf_T0, gen_op_load_crf_T0_crf);
92GEN8(gen_op_load_crf_T1, gen_op_load_crf_T1_crf);
93GEN8(gen_op_store_T0_crf, gen_op_store_T0_crf_crf);
94GEN8(gen_op_store_T1_crf, gen_op_store_T1_crf_crf);
28b6751f 95
fb0eaffc
FB
96/* Floating point condition and status register moves */
97GEN8(gen_op_load_fpscr_T0, gen_op_load_fpscr_T0_fpscr);
98GEN8(gen_op_store_T0_fpscr, gen_op_store_T0_fpscr_fpscr);
99GEN8(gen_op_clear_fpscr, gen_op_clear_fpscr_fpscr);
fb0eaffc
FB
100static inline void gen_op_store_T0_fpscri(int n, uint8_t param)
101{
76a66253
JM
102 gen_op_set_T0(param);
103 gen_op_store_T0_fpscr(n);
fb0eaffc
FB
104}
105
9a64fbe4
FB
106/* General purpose registers moves */
107GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr);
108GEN32(gen_op_load_gpr_T1, gen_op_load_gpr_T1_gpr);
109GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr);
110
111GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr);
112GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr);
76a66253 113#if 0 // unused
9a64fbe4 114GEN32(gen_op_store_T2_gpr, gen_op_store_T2_gpr_gpr);
76a66253 115#endif
28b6751f 116
fb0eaffc
FB
117/* floating point registers moves */
118GEN32(gen_op_load_fpr_FT0, gen_op_load_fpr_FT0_fpr);
119GEN32(gen_op_load_fpr_FT1, gen_op_load_fpr_FT1_fpr);
120GEN32(gen_op_load_fpr_FT2, gen_op_load_fpr_FT2_fpr);
121GEN32(gen_op_store_FT0_fpr, gen_op_store_FT0_fpr_fpr);
122GEN32(gen_op_store_FT1_fpr, gen_op_store_FT1_fpr_fpr);
76a66253 123#if 0 // unused
fb0eaffc 124GEN32(gen_op_store_FT2_fpr, gen_op_store_FT2_fpr_fpr);
76a66253 125#endif
79aceca5
FB
126
127/* internal defines */
128typedef struct DisasContext {
129 struct TranslationBlock *tb;
0fa85d43 130 target_ulong nip;
79aceca5 131 uint32_t opcode;
9a64fbe4 132 uint32_t exception;
3cc62370
FB
133 /* Routine used to access memory */
134 int mem_idx;
135 /* Translation flags */
9a64fbe4 136#if !defined(CONFIG_USER_ONLY)
79aceca5 137 int supervisor;
9a64fbe4 138#endif
3cc62370 139 int fpu_enabled;
3fc6c082 140 ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */
ea4e754f 141 int singlestep_enabled;
79aceca5
FB
142} DisasContext;
143
3fc6c082 144struct opc_handler_t {
79aceca5
FB
145 /* invalid bits */
146 uint32_t inval;
9a64fbe4
FB
147 /* instruction type */
148 uint32_t type;
79aceca5
FB
149 /* handler */
150 void (*handler)(DisasContext *ctx);
76a66253
JM
151#if defined(DO_PPC_STATISTICS)
152 const unsigned char *oname;
153 uint64_t count;
154#endif
3fc6c082 155};
79aceca5 156
76a66253
JM
157static inline void gen_set_Rc0 (DisasContext *ctx)
158{
159 gen_op_cmpi(0);
160 gen_op_set_Rc0();
161}
162
9fddaa0c 163#define RET_EXCP(ctx, excp, error) \
79aceca5 164do { \
9fddaa0c
FB
165 if ((ctx)->exception == EXCP_NONE) { \
166 gen_op_update_nip((ctx)->nip); \
167 } \
168 gen_op_raise_exception_err((excp), (error)); \
169 ctx->exception = (excp); \
79aceca5
FB
170} while (0)
171
9fddaa0c
FB
172#define RET_INVAL(ctx) \
173RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL)
174
175#define RET_PRIVOPC(ctx) \
176RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_OPC)
9a64fbe4 177
9fddaa0c
FB
178#define RET_PRIVREG(ctx) \
179RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG)
9a64fbe4 180
f24e5695 181/* Stop translation */
3fc6c082
FB
182static inline void RET_STOP (DisasContext *ctx)
183{
f24e5695
FB
184 gen_op_update_nip((ctx)->nip);
185 ctx->exception = EXCP_MTMSR;
3fc6c082
FB
186}
187
f24e5695 188/* No need to update nip here, as execution flow will change */
2be0071f
FB
189static inline void RET_CHG_FLOW (DisasContext *ctx)
190{
2be0071f
FB
191 ctx->exception = EXCP_MTMSR;
192}
193
79aceca5
FB
194#define GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \
195static void gen_##name (DisasContext *ctx); \
196GEN_OPCODE(name, opc1, opc2, opc3, inval, type); \
197static void gen_##name (DisasContext *ctx)
198
79aceca5
FB
199typedef struct opcode_t {
200 unsigned char opc1, opc2, opc3;
18fba28c
FB
201#if HOST_LONG_BITS == 64 /* Explicitely align to 64 bits */
202 unsigned char pad[5];
203#else
204 unsigned char pad[1];
205#endif
79aceca5 206 opc_handler_t handler;
3fc6c082 207 const unsigned char *oname;
79aceca5
FB
208} opcode_t;
209
79aceca5
FB
210/*** Instruction decoding ***/
211#define EXTRACT_HELPER(name, shift, nb) \
76a66253 212static inline target_ulong name (uint32_t opcode) \
79aceca5
FB
213{ \
214 return (opcode >> (shift)) & ((1 << (nb)) - 1); \
215}
216
217#define EXTRACT_SHELPER(name, shift, nb) \
76a66253 218static inline target_long name (uint32_t opcode) \
79aceca5 219{ \
18fba28c 220 return (int16_t)((opcode >> (shift)) & ((1 << (nb)) - 1)); \
79aceca5
FB
221}
222
223/* Opcode part 1 */
224EXTRACT_HELPER(opc1, 26, 6);
225/* Opcode part 2 */
226EXTRACT_HELPER(opc2, 1, 5);
227/* Opcode part 3 */
228EXTRACT_HELPER(opc3, 6, 5);
229/* Update Cr0 flags */
230EXTRACT_HELPER(Rc, 0, 1);
231/* Destination */
232EXTRACT_HELPER(rD, 21, 5);
233/* Source */
234EXTRACT_HELPER(rS, 21, 5);
235/* First operand */
236EXTRACT_HELPER(rA, 16, 5);
237/* Second operand */
238EXTRACT_HELPER(rB, 11, 5);
239/* Third operand */
240EXTRACT_HELPER(rC, 6, 5);
241/*** Get CRn ***/
242EXTRACT_HELPER(crfD, 23, 3);
243EXTRACT_HELPER(crfS, 18, 3);
244EXTRACT_HELPER(crbD, 21, 5);
245EXTRACT_HELPER(crbA, 16, 5);
246EXTRACT_HELPER(crbB, 11, 5);
247/* SPR / TBL */
3fc6c082
FB
248EXTRACT_HELPER(_SPR, 11, 10);
249static inline uint32_t SPR (uint32_t opcode)
250{
251 uint32_t sprn = _SPR(opcode);
252
253 return ((sprn >> 5) & 0x1F) | ((sprn & 0x1F) << 5);
254}
79aceca5
FB
255/*** Get constants ***/
256EXTRACT_HELPER(IMM, 12, 8);
257/* 16 bits signed immediate value */
258EXTRACT_SHELPER(SIMM, 0, 16);
259/* 16 bits unsigned immediate value */
260EXTRACT_HELPER(UIMM, 0, 16);
261/* Bit count */
262EXTRACT_HELPER(NB, 11, 5);
263/* Shift count */
264EXTRACT_HELPER(SH, 11, 5);
265/* Mask start */
266EXTRACT_HELPER(MB, 6, 5);
267/* Mask end */
268EXTRACT_HELPER(ME, 1, 5);
fb0eaffc
FB
269/* Trap operand */
270EXTRACT_HELPER(TO, 21, 5);
79aceca5
FB
271
272EXTRACT_HELPER(CRM, 12, 8);
273EXTRACT_HELPER(FM, 17, 8);
274EXTRACT_HELPER(SR, 16, 4);
fb0eaffc
FB
275EXTRACT_HELPER(FPIMM, 20, 4);
276
79aceca5
FB
277/*** Jump target decoding ***/
278/* Displacement */
279EXTRACT_SHELPER(d, 0, 16);
280/* Immediate address */
76a66253 281static inline target_ulong LI (uint32_t opcode)
79aceca5
FB
282{
283 return (opcode >> 0) & 0x03FFFFFC;
284}
285
286static inline uint32_t BD (uint32_t opcode)
287{
288 return (opcode >> 0) & 0xFFFC;
289}
290
291EXTRACT_HELPER(BO, 21, 5);
292EXTRACT_HELPER(BI, 16, 5);
293/* Absolute/relative address */
294EXTRACT_HELPER(AA, 1, 1);
295/* Link */
296EXTRACT_HELPER(LK, 0, 1);
297
298/* Create a mask between <start> and <end> bits */
76a66253 299static inline target_ulong MASK (uint32_t start, uint32_t end)
79aceca5 300{
76a66253 301 target_ulong ret;
79aceca5 302
76a66253
JM
303#if defined(TARGET_PPC64)
304 if (likely(start == 0)) {
305 ret = (uint64_t)(-1ULL) << (63 - end);
306 } else if (likely(end == 63)) {
307 ret = (uint64_t)(-1ULL) >> start;
308 }
309#else
310 if (likely(start == 0)) {
311 ret = (uint32_t)(-1ULL) << (31 - end);
312 } else if (likely(end == 31)) {
313 ret = (uint32_t)(-1ULL) >> start;
314 }
315#endif
316 else {
317 ret = (((target_ulong)(-1ULL)) >> (start)) ^
318 (((target_ulong)(-1ULL) >> (end)) >> 1);
319 if (unlikely(start > end))
320 return ~ret;
321 }
79aceca5
FB
322
323 return ret;
324}
325
3fc6c082
FB
326#if HOST_LONG_BITS == 64
327#define OPC_ALIGN 8
328#else
329#define OPC_ALIGN 4
330#endif
1b039c09 331#if defined(__APPLE__)
933dc6eb 332#define OPCODES_SECTION \
3fc6c082 333 __attribute__ ((section("__TEXT,__opcodes"), unused, aligned (OPC_ALIGN) ))
933dc6eb 334#else
1b039c09 335#define OPCODES_SECTION \
3fc6c082 336 __attribute__ ((section(".opcodes"), unused, aligned (OPC_ALIGN) ))
933dc6eb
FB
337#endif
338
76a66253 339#if defined(DO_PPC_STATISTICS)
79aceca5 340#define GEN_OPCODE(name, op1, op2, op3, invl, _typ) \
18fba28c 341OPCODES_SECTION opcode_t opc_##name = { \
79aceca5
FB
342 .opc1 = op1, \
343 .opc2 = op2, \
344 .opc3 = op3, \
18fba28c 345 .pad = { 0, }, \
79aceca5
FB
346 .handler = { \
347 .inval = invl, \
9a64fbe4 348 .type = _typ, \
79aceca5 349 .handler = &gen_##name, \
76a66253 350 .oname = stringify(name), \
79aceca5 351 }, \
3fc6c082 352 .oname = stringify(name), \
79aceca5 353}
76a66253
JM
354#else
355#define GEN_OPCODE(name, op1, op2, op3, invl, _typ) \
356OPCODES_SECTION opcode_t opc_##name = { \
357 .opc1 = op1, \
358 .opc2 = op2, \
359 .opc3 = op3, \
360 .pad = { 0, }, \
361 .handler = { \
362 .inval = invl, \
363 .type = _typ, \
364 .handler = &gen_##name, \
365 }, \
366 .oname = stringify(name), \
367}
368#endif
79aceca5
FB
369
370#define GEN_OPCODE_MARK(name) \
18fba28c 371OPCODES_SECTION opcode_t opc_##name = { \
79aceca5
FB
372 .opc1 = 0xFF, \
373 .opc2 = 0xFF, \
374 .opc3 = 0xFF, \
18fba28c 375 .pad = { 0, }, \
79aceca5
FB
376 .handler = { \
377 .inval = 0x00000000, \
9a64fbe4 378 .type = 0x00, \
79aceca5
FB
379 .handler = NULL, \
380 }, \
3fc6c082 381 .oname = stringify(name), \
79aceca5
FB
382}
383
384/* Start opcode list */
385GEN_OPCODE_MARK(start);
386
387/* Invalid instruction */
9a64fbe4
FB
388GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE)
389{
9fddaa0c 390 RET_INVAL(ctx);
9a64fbe4
FB
391}
392
79aceca5
FB
393static opc_handler_t invalid_handler = {
394 .inval = 0xFFFFFFFF,
9a64fbe4 395 .type = PPC_NONE,
79aceca5
FB
396 .handler = gen_invalid,
397};
398
399/*** Integer arithmetic ***/
400#define __GEN_INT_ARITH2(name, opc1, opc2, opc3, inval) \
401GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER) \
402{ \
403 gen_op_load_gpr_T0(rA(ctx->opcode)); \
404 gen_op_load_gpr_T1(rB(ctx->opcode)); \
405 gen_op_##name(); \
79aceca5 406 gen_op_store_T0_gpr(rD(ctx->opcode)); \
76a66253
JM
407 if (unlikely(Rc(ctx->opcode) != 0)) \
408 gen_set_Rc0(ctx); \
79aceca5
FB
409}
410
411#define __GEN_INT_ARITH2_O(name, opc1, opc2, opc3, inval) \
412GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER) \
413{ \
414 gen_op_load_gpr_T0(rA(ctx->opcode)); \
415 gen_op_load_gpr_T1(rB(ctx->opcode)); \
416 gen_op_##name(); \
79aceca5 417 gen_op_store_T0_gpr(rD(ctx->opcode)); \
76a66253
JM
418 if (unlikely(Rc(ctx->opcode) != 0)) \
419 gen_set_Rc0(ctx); \
79aceca5
FB
420}
421
422#define __GEN_INT_ARITH1(name, opc1, opc2, opc3) \
423GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER) \
424{ \
425 gen_op_load_gpr_T0(rA(ctx->opcode)); \
426 gen_op_##name(); \
79aceca5 427 gen_op_store_T0_gpr(rD(ctx->opcode)); \
76a66253
JM
428 if (unlikely(Rc(ctx->opcode) != 0)) \
429 gen_set_Rc0(ctx); \
79aceca5
FB
430}
431#define __GEN_INT_ARITH1_O(name, opc1, opc2, opc3) \
432GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER) \
433{ \
434 gen_op_load_gpr_T0(rA(ctx->opcode)); \
435 gen_op_##name(); \
79aceca5 436 gen_op_store_T0_gpr(rD(ctx->opcode)); \
76a66253
JM
437 if (unlikely(Rc(ctx->opcode) != 0)) \
438 gen_set_Rc0(ctx); \
79aceca5
FB
439}
440
441/* Two operands arithmetic functions */
442#define GEN_INT_ARITH2(name, opc1, opc2, opc3) \
443__GEN_INT_ARITH2(name, opc1, opc2, opc3, 0x00000000) \
444__GEN_INT_ARITH2_O(name##o, opc1, opc2, opc3 | 0x10, 0x00000000)
445
446/* Two operands arithmetic functions with no overflow allowed */
447#define GEN_INT_ARITHN(name, opc1, opc2, opc3) \
448__GEN_INT_ARITH2(name, opc1, opc2, opc3, 0x00000400)
449
450/* One operand arithmetic functions */
451#define GEN_INT_ARITH1(name, opc1, opc2, opc3) \
452__GEN_INT_ARITH1(name, opc1, opc2, opc3) \
453__GEN_INT_ARITH1_O(name##o, opc1, opc2, opc3 | 0x10)
454
455/* add add. addo addo. */
456GEN_INT_ARITH2 (add, 0x1F, 0x0A, 0x08);
457/* addc addc. addco addco. */
458GEN_INT_ARITH2 (addc, 0x1F, 0x0A, 0x00);
459/* adde adde. addeo addeo. */
460GEN_INT_ARITH2 (adde, 0x1F, 0x0A, 0x04);
461/* addme addme. addmeo addmeo. */
462GEN_INT_ARITH1 (addme, 0x1F, 0x0A, 0x07);
463/* addze addze. addzeo addzeo. */
464GEN_INT_ARITH1 (addze, 0x1F, 0x0A, 0x06);
465/* divw divw. divwo divwo. */
466GEN_INT_ARITH2 (divw, 0x1F, 0x0B, 0x0F);
467/* divwu divwu. divwuo divwuo. */
468GEN_INT_ARITH2 (divwu, 0x1F, 0x0B, 0x0E);
469/* mulhw mulhw. */
470GEN_INT_ARITHN (mulhw, 0x1F, 0x0B, 0x02);
471/* mulhwu mulhwu. */
472GEN_INT_ARITHN (mulhwu, 0x1F, 0x0B, 0x00);
473/* mullw mullw. mullwo mullwo. */
474GEN_INT_ARITH2 (mullw, 0x1F, 0x0B, 0x07);
475/* neg neg. nego nego. */
476GEN_INT_ARITH1 (neg, 0x1F, 0x08, 0x03);
477/* subf subf. subfo subfo. */
478GEN_INT_ARITH2 (subf, 0x1F, 0x08, 0x01);
479/* subfc subfc. subfco subfco. */
480GEN_INT_ARITH2 (subfc, 0x1F, 0x08, 0x00);
481/* subfe subfe. subfeo subfeo. */
482GEN_INT_ARITH2 (subfe, 0x1F, 0x08, 0x04);
483/* subfme subfme. subfmeo subfmeo. */
484GEN_INT_ARITH1 (subfme, 0x1F, 0x08, 0x07);
485/* subfze subfze. subfzeo subfzeo. */
486GEN_INT_ARITH1 (subfze, 0x1F, 0x08, 0x06);
487/* addi */
488GEN_HANDLER(addi, 0x0E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
489{
76a66253 490 target_long simm = SIMM(ctx->opcode);
79aceca5
FB
491
492 if (rA(ctx->opcode) == 0) {
76a66253 493 /* li case */
79aceca5
FB
494 gen_op_set_T0(simm);
495 } else {
496 gen_op_load_gpr_T0(rA(ctx->opcode));
76a66253
JM
497 if (likely(simm != 0))
498 gen_op_addi(simm);
79aceca5
FB
499 }
500 gen_op_store_T0_gpr(rD(ctx->opcode));
79aceca5
FB
501}
502/* addic */
503GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
504{
76a66253
JM
505 target_long simm = SIMM(ctx->opcode);
506
79aceca5 507 gen_op_load_gpr_T0(rA(ctx->opcode));
76a66253
JM
508 if (likely(simm != 0))
509 gen_op_addic(SIMM(ctx->opcode));
79aceca5 510 gen_op_store_T0_gpr(rD(ctx->opcode));
79aceca5
FB
511}
512/* addic. */
513GEN_HANDLER(addic_, 0x0D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
514{
76a66253
JM
515 target_long simm = SIMM(ctx->opcode);
516
79aceca5 517 gen_op_load_gpr_T0(rA(ctx->opcode));
76a66253
JM
518 if (likely(simm != 0))
519 gen_op_addic(SIMM(ctx->opcode));
79aceca5 520 gen_op_store_T0_gpr(rD(ctx->opcode));
76a66253 521 gen_set_Rc0(ctx);
79aceca5
FB
522}
523/* addis */
524GEN_HANDLER(addis, 0x0F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
525{
76a66253 526 target_long simm = SIMM(ctx->opcode);
79aceca5
FB
527
528 if (rA(ctx->opcode) == 0) {
76a66253 529 /* lis case */
79aceca5
FB
530 gen_op_set_T0(simm << 16);
531 } else {
532 gen_op_load_gpr_T0(rA(ctx->opcode));
76a66253
JM
533 if (likely(simm != 0))
534 gen_op_addi(simm << 16);
79aceca5
FB
535 }
536 gen_op_store_T0_gpr(rD(ctx->opcode));
79aceca5
FB
537}
538/* mulli */
539GEN_HANDLER(mulli, 0x07, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
540{
541 gen_op_load_gpr_T0(rA(ctx->opcode));
542 gen_op_mulli(SIMM(ctx->opcode));
543 gen_op_store_T0_gpr(rD(ctx->opcode));
79aceca5
FB
544}
545/* subfic */
546GEN_HANDLER(subfic, 0x08, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
547{
548 gen_op_load_gpr_T0(rA(ctx->opcode));
549 gen_op_subfic(SIMM(ctx->opcode));
550 gen_op_store_T0_gpr(rD(ctx->opcode));
79aceca5
FB
551}
552
553/*** Integer comparison ***/
554#define GEN_CMP(name, opc) \
555GEN_HANDLER(name, 0x1F, 0x00, opc, 0x00400000, PPC_INTEGER) \
556{ \
557 gen_op_load_gpr_T0(rA(ctx->opcode)); \
558 gen_op_load_gpr_T1(rB(ctx->opcode)); \
559 gen_op_##name(); \
560 gen_op_store_T0_crf(crfD(ctx->opcode)); \
79aceca5
FB
561}
562
563/* cmp */
564GEN_CMP(cmp, 0x00);
565/* cmpi */
566GEN_HANDLER(cmpi, 0x0B, 0xFF, 0xFF, 0x00400000, PPC_INTEGER)
567{
568 gen_op_load_gpr_T0(rA(ctx->opcode));
569 gen_op_cmpi(SIMM(ctx->opcode));
570 gen_op_store_T0_crf(crfD(ctx->opcode));
79aceca5
FB
571}
572/* cmpl */
573GEN_CMP(cmpl, 0x01);
574/* cmpli */
575GEN_HANDLER(cmpli, 0x0A, 0xFF, 0xFF, 0x00400000, PPC_INTEGER)
576{
577 gen_op_load_gpr_T0(rA(ctx->opcode));
578 gen_op_cmpli(UIMM(ctx->opcode));
579 gen_op_store_T0_crf(crfD(ctx->opcode));
79aceca5
FB
580}
581
582/*** Integer logical ***/
583#define __GEN_LOGICAL2(name, opc2, opc3) \
584GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000000, PPC_INTEGER) \
585{ \
586 gen_op_load_gpr_T0(rS(ctx->opcode)); \
587 gen_op_load_gpr_T1(rB(ctx->opcode)); \
588 gen_op_##name(); \
79aceca5 589 gen_op_store_T0_gpr(rA(ctx->opcode)); \
76a66253
JM
590 if (unlikely(Rc(ctx->opcode) != 0)) \
591 gen_set_Rc0(ctx); \
79aceca5
FB
592}
593#define GEN_LOGICAL2(name, opc) \
594__GEN_LOGICAL2(name, 0x1C, opc)
595
596#define GEN_LOGICAL1(name, opc) \
597GEN_HANDLER(name, 0x1F, 0x1A, opc, 0x00000000, PPC_INTEGER) \
598{ \
599 gen_op_load_gpr_T0(rS(ctx->opcode)); \
600 gen_op_##name(); \
79aceca5 601 gen_op_store_T0_gpr(rA(ctx->opcode)); \
76a66253
JM
602 if (unlikely(Rc(ctx->opcode) != 0)) \
603 gen_set_Rc0(ctx); \
79aceca5
FB
604}
605
606/* and & and. */
607GEN_LOGICAL2(and, 0x00);
608/* andc & andc. */
609GEN_LOGICAL2(andc, 0x01);
610/* andi. */
611GEN_HANDLER(andi_, 0x1C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
612{
613 gen_op_load_gpr_T0(rS(ctx->opcode));
76a66253 614 gen_op_andi_T0(UIMM(ctx->opcode));
79aceca5 615 gen_op_store_T0_gpr(rA(ctx->opcode));
76a66253 616 gen_set_Rc0(ctx);
79aceca5
FB
617}
618/* andis. */
619GEN_HANDLER(andis_, 0x1D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
620{
621 gen_op_load_gpr_T0(rS(ctx->opcode));
76a66253 622 gen_op_andi_T0(UIMM(ctx->opcode) << 16);
79aceca5 623 gen_op_store_T0_gpr(rA(ctx->opcode));
76a66253 624 gen_set_Rc0(ctx);
79aceca5
FB
625}
626
627/* cntlzw */
628GEN_LOGICAL1(cntlzw, 0x00);
629/* eqv & eqv. */
630GEN_LOGICAL2(eqv, 0x08);
631/* extsb & extsb. */
632GEN_LOGICAL1(extsb, 0x1D);
633/* extsh & extsh. */
634GEN_LOGICAL1(extsh, 0x1C);
635/* nand & nand. */
636GEN_LOGICAL2(nand, 0x0E);
637/* nor & nor. */
638GEN_LOGICAL2(nor, 0x03);
9a64fbe4 639
79aceca5 640/* or & or. */
9a64fbe4
FB
641GEN_HANDLER(or, 0x1F, 0x1C, 0x0D, 0x00000000, PPC_INTEGER)
642{
76a66253
JM
643 int rs, ra, rb;
644
645 rs = rS(ctx->opcode);
646 ra = rA(ctx->opcode);
647 rb = rB(ctx->opcode);
648 /* Optimisation for mr. ri case */
649 if (rs != ra || rs != rb) {
650 gen_op_load_gpr_T0(rs);
651 if (rs != rb) {
652 gen_op_load_gpr_T1(rb);
653 gen_op_or();
654 }
655 gen_op_store_T0_gpr(ra);
656 if (unlikely(Rc(ctx->opcode) != 0))
657 gen_set_Rc0(ctx);
658 } else if (unlikely(Rc(ctx->opcode) != 0)) {
659 gen_op_load_gpr_T0(rs);
660 gen_set_Rc0(ctx);
9a64fbe4 661 }
9a64fbe4
FB
662}
663
79aceca5
FB
664/* orc & orc. */
665GEN_LOGICAL2(orc, 0x0C);
666/* xor & xor. */
9a64fbe4
FB
667GEN_HANDLER(xor, 0x1F, 0x1C, 0x09, 0x00000000, PPC_INTEGER)
668{
669 gen_op_load_gpr_T0(rS(ctx->opcode));
670 /* Optimisation for "set to zero" case */
671 if (rS(ctx->opcode) != rB(ctx->opcode)) {
672 gen_op_load_gpr_T1(rB(ctx->opcode));
673 gen_op_xor();
674 } else {
76a66253 675 gen_op_reset_T0();
9a64fbe4 676 }
9a64fbe4 677 gen_op_store_T0_gpr(rA(ctx->opcode));
76a66253
JM
678 if (unlikely(Rc(ctx->opcode) != 0))
679 gen_set_Rc0(ctx);
9a64fbe4 680}
79aceca5
FB
681/* ori */
682GEN_HANDLER(ori, 0x18, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
683{
76a66253 684 target_ulong uimm = UIMM(ctx->opcode);
79aceca5 685
9a64fbe4
FB
686 if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
687 /* NOP */
76a66253 688 /* XXX: should handle special NOPs for POWER series */
9a64fbe4 689 return;
76a66253
JM
690 }
691 gen_op_load_gpr_T0(rS(ctx->opcode));
692 if (likely(uimm != 0))
79aceca5 693 gen_op_ori(uimm);
76a66253 694 gen_op_store_T0_gpr(rA(ctx->opcode));
79aceca5
FB
695}
696/* oris */
697GEN_HANDLER(oris, 0x19, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
698{
76a66253 699 target_ulong uimm = UIMM(ctx->opcode);
79aceca5 700
9a64fbe4
FB
701 if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
702 /* NOP */
703 return;
76a66253
JM
704 }
705 gen_op_load_gpr_T0(rS(ctx->opcode));
706 if (likely(uimm != 0))
79aceca5 707 gen_op_ori(uimm << 16);
76a66253 708 gen_op_store_T0_gpr(rA(ctx->opcode));
79aceca5
FB
709}
710/* xori */
711GEN_HANDLER(xori, 0x1A, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
712{
76a66253 713 target_ulong uimm = UIMM(ctx->opcode);
9a64fbe4
FB
714
715 if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
716 /* NOP */
717 return;
718 }
79aceca5 719 gen_op_load_gpr_T0(rS(ctx->opcode));
76a66253
JM
720 if (likely(uimm != 0))
721 gen_op_xori(uimm);
79aceca5 722 gen_op_store_T0_gpr(rA(ctx->opcode));
79aceca5
FB
723}
724
725/* xoris */
726GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
727{
76a66253 728 target_ulong uimm = UIMM(ctx->opcode);
9a64fbe4
FB
729
730 if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
731 /* NOP */
732 return;
733 }
79aceca5 734 gen_op_load_gpr_T0(rS(ctx->opcode));
76a66253
JM
735 if (likely(uimm != 0))
736 gen_op_xori(uimm << 16);
79aceca5 737 gen_op_store_T0_gpr(rA(ctx->opcode));
79aceca5
FB
738}
739
740/*** Integer rotate ***/
741/* rlwimi & rlwimi. */
742GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
743{
76a66253
JM
744 target_ulong mask;
745 uint32_t mb, me, sh;
746 int n;
79aceca5
FB
747
748 mb = MB(ctx->opcode);
749 me = ME(ctx->opcode);
76a66253
JM
750 sh = SH(ctx->opcode);
751 n = me + 1 - mb;
752 if (likely(sh == 0)) {
753 if (likely(mb == 0 && me == 31)) {
754 gen_op_load_gpr_T0(rS(ctx->opcode));
755 goto do_store;
756 } else if (likely(mb == 31 && me == 0)) {
757 gen_op_load_gpr_T0(rA(ctx->opcode));
758 goto do_store;
759 }
760 gen_op_load_gpr_T0(rS(ctx->opcode));
761 gen_op_load_gpr_T1(rA(ctx->opcode));
762 goto do_mask;
763 }
79aceca5 764 gen_op_load_gpr_T0(rS(ctx->opcode));
fb0eaffc 765 gen_op_load_gpr_T1(rA(ctx->opcode));
76a66253
JM
766 gen_op_rotli32_T0(SH(ctx->opcode));
767 do_mask:
768#if defined(TARGET_PPC64)
769 mb += 32;
770 me += 32;
771#endif
772 mask = MASK(mb, me);
773 gen_op_andi_T0(mask);
774 gen_op_andi_T1(~mask);
775 gen_op_or();
776 do_store:
79aceca5 777 gen_op_store_T0_gpr(rA(ctx->opcode));
76a66253
JM
778 if (unlikely(Rc(ctx->opcode) != 0))
779 gen_set_Rc0(ctx);
79aceca5
FB
780}
781/* rlwinm & rlwinm. */
782GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
783{
784 uint32_t mb, me, sh;
785
786 sh = SH(ctx->opcode);
787 mb = MB(ctx->opcode);
788 me = ME(ctx->opcode);
789 gen_op_load_gpr_T0(rS(ctx->opcode));
76a66253
JM
790 if (likely(sh == 0)) {
791 goto do_mask;
792 }
793 if (likely(mb == 0)) {
794 if (likely(me == 31)) {
795 gen_op_rotli32_T0(sh);
796 goto do_store;
797 } else if (likely(me == (31 - sh))) {
798 gen_op_sli_T0(sh);
799 goto do_store;
79aceca5 800 }
76a66253
JM
801 } else if (likely(me == 31)) {
802 if (likely(sh == (32 - mb))) {
803 gen_op_srli_T0(mb);
804 goto do_store;
79aceca5
FB
805 }
806 }
76a66253
JM
807 gen_op_rotli32_T0(sh);
808 do_mask:
809#if defined(TARGET_PPC64)
810 mb += 32;
811 me += 32;
812#endif
813 gen_op_andi_T0(MASK(mb, me));
814 do_store:
79aceca5 815 gen_op_store_T0_gpr(rA(ctx->opcode));
76a66253
JM
816 if (unlikely(Rc(ctx->opcode) != 0))
817 gen_set_Rc0(ctx);
79aceca5
FB
818}
819/* rlwnm & rlwnm. */
820GEN_HANDLER(rlwnm, 0x17, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
821{
822 uint32_t mb, me;
823
824 mb = MB(ctx->opcode);
825 me = ME(ctx->opcode);
826 gen_op_load_gpr_T0(rS(ctx->opcode));
827 gen_op_load_gpr_T1(rB(ctx->opcode));
76a66253
JM
828 gen_op_rotl32_T0_T1();
829 if (unlikely(mb != 0 || me != 31)) {
830#if defined(TARGET_PPC64)
831 mb += 32;
832 me += 32;
833#endif
834 gen_op_andi_T0(MASK(mb, me));
79aceca5 835 }
79aceca5 836 gen_op_store_T0_gpr(rA(ctx->opcode));
76a66253
JM
837 if (unlikely(Rc(ctx->opcode) != 0))
838 gen_set_Rc0(ctx);
79aceca5
FB
839}
840
841/*** Integer shift ***/
842/* slw & slw. */
843__GEN_LOGICAL2(slw, 0x18, 0x00);
844/* sraw & sraw. */
845__GEN_LOGICAL2(sraw, 0x18, 0x18);
846/* srawi & srawi. */
847GEN_HANDLER(srawi, 0x1F, 0x18, 0x19, 0x00000000, PPC_INTEGER)
848{
849 gen_op_load_gpr_T0(rS(ctx->opcode));
4ecc3190 850 if (SH(ctx->opcode) != 0)
76a66253 851 gen_op_srawi(SH(ctx->opcode), MASK(32 - SH(ctx->opcode), 31));
79aceca5 852 gen_op_store_T0_gpr(rA(ctx->opcode));
76a66253
JM
853 if (unlikely(Rc(ctx->opcode) != 0))
854 gen_set_Rc0(ctx);
79aceca5
FB
855}
856/* srw & srw. */
857__GEN_LOGICAL2(srw, 0x18, 0x10);
858
859/*** Floating-Point arithmetic ***/
4ecc3190 860#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat) \
9a64fbe4
FB
861GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, PPC_FLOAT) \
862{ \
76a66253 863 if (unlikely(!ctx->fpu_enabled)) { \
3cc62370
FB
864 RET_EXCP(ctx, EXCP_NO_FP, 0); \
865 return; \
866 } \
9a64fbe4
FB
867 gen_op_reset_scrfx(); \
868 gen_op_load_fpr_FT0(rA(ctx->opcode)); \
869 gen_op_load_fpr_FT1(rC(ctx->opcode)); \
870 gen_op_load_fpr_FT2(rB(ctx->opcode)); \
4ecc3190
FB
871 gen_op_f##op(); \
872 if (isfloat) { \
873 gen_op_frsp(); \
874 } \
9a64fbe4 875 gen_op_store_FT0_fpr(rD(ctx->opcode)); \
76a66253 876 if (unlikely(Rc(ctx->opcode) != 0)) \
9a64fbe4
FB
877 gen_op_set_Rc1(); \
878}
879
880#define GEN_FLOAT_ACB(name, op2) \
4ecc3190
FB
881_GEN_FLOAT_ACB(name, name, 0x3F, op2, 0); \
882_GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1);
9a64fbe4 883
4ecc3190 884#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat) \
9a64fbe4
FB
885GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \
886{ \
76a66253 887 if (unlikely(!ctx->fpu_enabled)) { \
3cc62370
FB
888 RET_EXCP(ctx, EXCP_NO_FP, 0); \
889 return; \
890 } \
9a64fbe4
FB
891 gen_op_reset_scrfx(); \
892 gen_op_load_fpr_FT0(rA(ctx->opcode)); \
893 gen_op_load_fpr_FT1(rB(ctx->opcode)); \
4ecc3190
FB
894 gen_op_f##op(); \
895 if (isfloat) { \
896 gen_op_frsp(); \
897 } \
9a64fbe4 898 gen_op_store_FT0_fpr(rD(ctx->opcode)); \
76a66253 899 if (unlikely(Rc(ctx->opcode) != 0)) \
9a64fbe4
FB
900 gen_op_set_Rc1(); \
901}
902#define GEN_FLOAT_AB(name, op2, inval) \
4ecc3190
FB
903_GEN_FLOAT_AB(name, name, 0x3F, op2, inval, 0); \
904_GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1);
9a64fbe4 905
4ecc3190 906#define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat) \
9a64fbe4
FB
907GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \
908{ \
76a66253 909 if (unlikely(!ctx->fpu_enabled)) { \
3cc62370
FB
910 RET_EXCP(ctx, EXCP_NO_FP, 0); \
911 return; \
912 } \
9a64fbe4
FB
913 gen_op_reset_scrfx(); \
914 gen_op_load_fpr_FT0(rA(ctx->opcode)); \
915 gen_op_load_fpr_FT1(rC(ctx->opcode)); \
4ecc3190
FB
916 gen_op_f##op(); \
917 if (isfloat) { \
918 gen_op_frsp(); \
919 } \
9a64fbe4 920 gen_op_store_FT0_fpr(rD(ctx->opcode)); \
76a66253 921 if (unlikely(Rc(ctx->opcode) != 0)) \
9a64fbe4
FB
922 gen_op_set_Rc1(); \
923}
924#define GEN_FLOAT_AC(name, op2, inval) \
4ecc3190
FB
925_GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0); \
926_GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1);
9a64fbe4
FB
927
928#define GEN_FLOAT_B(name, op2, op3) \
929GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, PPC_FLOAT) \
930{ \
76a66253 931 if (unlikely(!ctx->fpu_enabled)) { \
3cc62370
FB
932 RET_EXCP(ctx, EXCP_NO_FP, 0); \
933 return; \
934 } \
9a64fbe4
FB
935 gen_op_reset_scrfx(); \
936 gen_op_load_fpr_FT0(rB(ctx->opcode)); \
937 gen_op_f##name(); \
938 gen_op_store_FT0_fpr(rD(ctx->opcode)); \
76a66253 939 if (unlikely(Rc(ctx->opcode) != 0)) \
9a64fbe4 940 gen_op_set_Rc1(); \
79aceca5
FB
941}
942
4ecc3190
FB
943#define GEN_FLOAT_BS(name, op1, op2) \
944GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, PPC_FLOAT) \
9a64fbe4 945{ \
76a66253 946 if (unlikely(!ctx->fpu_enabled)) { \
3cc62370
FB
947 RET_EXCP(ctx, EXCP_NO_FP, 0); \
948 return; \
949 } \
9a64fbe4
FB
950 gen_op_reset_scrfx(); \
951 gen_op_load_fpr_FT0(rB(ctx->opcode)); \
952 gen_op_f##name(); \
953 gen_op_store_FT0_fpr(rD(ctx->opcode)); \
76a66253 954 if (unlikely(Rc(ctx->opcode) != 0)) \
9a64fbe4 955 gen_op_set_Rc1(); \
79aceca5
FB
956}
957
9a64fbe4
FB
958/* fadd - fadds */
959GEN_FLOAT_AB(add, 0x15, 0x000007C0);
4ecc3190 960/* fdiv - fdivs */
9a64fbe4 961GEN_FLOAT_AB(div, 0x12, 0x000007C0);
4ecc3190 962/* fmul - fmuls */
9a64fbe4 963GEN_FLOAT_AC(mul, 0x19, 0x0000F800);
79aceca5 964
76a66253 965/* fres */ /* XXX: not in 601 */
4ecc3190 966GEN_FLOAT_BS(res, 0x3B, 0x18);
79aceca5 967
76a66253 968/* frsqrte */ /* XXX: not in 601 */
4ecc3190 969GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A);
79aceca5 970
76a66253 971/* fsel */ /* XXX: not in 601 */
4ecc3190
FB
972_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0);
973/* fsub - fsubs */
9a64fbe4 974GEN_FLOAT_AB(sub, 0x14, 0x000007C0);
79aceca5
FB
975/* Optional: */
976/* fsqrt */
c7d344af
FB
977GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT)
978{
76a66253 979 if (unlikely(!ctx->fpu_enabled)) {
c7d344af
FB
980 RET_EXCP(ctx, EXCP_NO_FP, 0);
981 return;
982 }
983 gen_op_reset_scrfx();
984 gen_op_load_fpr_FT0(rB(ctx->opcode));
985 gen_op_fsqrt();
986 gen_op_store_FT0_fpr(rD(ctx->opcode));
76a66253 987 if (unlikely(Rc(ctx->opcode) != 0))
c7d344af
FB
988 gen_op_set_Rc1();
989}
79aceca5 990
9a64fbe4 991GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT)
79aceca5 992{
76a66253 993 if (unlikely(!ctx->fpu_enabled)) {
3cc62370
FB
994 RET_EXCP(ctx, EXCP_NO_FP, 0);
995 return;
996 }
9a64fbe4
FB
997 gen_op_reset_scrfx();
998 gen_op_load_fpr_FT0(rB(ctx->opcode));
4ecc3190
FB
999 gen_op_fsqrt();
1000 gen_op_frsp();
9a64fbe4 1001 gen_op_store_FT0_fpr(rD(ctx->opcode));
76a66253 1002 if (unlikely(Rc(ctx->opcode) != 0))
9a64fbe4 1003 gen_op_set_Rc1();
79aceca5
FB
1004}
1005
1006/*** Floating-Point multiply-and-add ***/
4ecc3190 1007/* fmadd - fmadds */
9a64fbe4 1008GEN_FLOAT_ACB(madd, 0x1D);
4ecc3190 1009/* fmsub - fmsubs */
9a64fbe4 1010GEN_FLOAT_ACB(msub, 0x1C);
4ecc3190 1011/* fnmadd - fnmadds */
9a64fbe4 1012GEN_FLOAT_ACB(nmadd, 0x1F);
4ecc3190 1013/* fnmsub - fnmsubs */
9a64fbe4 1014GEN_FLOAT_ACB(nmsub, 0x1E);
79aceca5
FB
1015
1016/*** Floating-Point round & convert ***/
1017/* fctiw */
9a64fbe4 1018GEN_FLOAT_B(ctiw, 0x0E, 0x00);
79aceca5 1019/* fctiwz */
9a64fbe4 1020GEN_FLOAT_B(ctiwz, 0x0F, 0x00);
79aceca5 1021/* frsp */
9a64fbe4 1022GEN_FLOAT_B(rsp, 0x0C, 0x00);
79aceca5
FB
1023
1024/*** Floating-Point compare ***/
1025/* fcmpo */
76a66253 1026GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT)
79aceca5 1027{
76a66253 1028 if (unlikely(!ctx->fpu_enabled)) {
3cc62370
FB
1029 RET_EXCP(ctx, EXCP_NO_FP, 0);
1030 return;
1031 }
9a64fbe4
FB
1032 gen_op_reset_scrfx();
1033 gen_op_load_fpr_FT0(rA(ctx->opcode));
1034 gen_op_load_fpr_FT1(rB(ctx->opcode));
1035 gen_op_fcmpo();
1036 gen_op_store_T0_crf(crfD(ctx->opcode));
79aceca5
FB
1037}
1038
1039/* fcmpu */
76a66253 1040GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT)
79aceca5 1041{
76a66253 1042 if (unlikely(!ctx->fpu_enabled)) {
3cc62370
FB
1043 RET_EXCP(ctx, EXCP_NO_FP, 0);
1044 return;
1045 }
9a64fbe4
FB
1046 gen_op_reset_scrfx();
1047 gen_op_load_fpr_FT0(rA(ctx->opcode));
1048 gen_op_load_fpr_FT1(rB(ctx->opcode));
1049 gen_op_fcmpu();
1050 gen_op_store_T0_crf(crfD(ctx->opcode));
79aceca5
FB
1051}
1052
9a64fbe4
FB
1053/*** Floating-point move ***/
1054/* fabs */
1055GEN_FLOAT_B(abs, 0x08, 0x08);
1056
1057/* fmr - fmr. */
1058GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT)
1059{
76a66253 1060 if (unlikely(!ctx->fpu_enabled)) {
3cc62370
FB
1061 RET_EXCP(ctx, EXCP_NO_FP, 0);
1062 return;
1063 }
9a64fbe4
FB
1064 gen_op_reset_scrfx();
1065 gen_op_load_fpr_FT0(rB(ctx->opcode));
1066 gen_op_store_FT0_fpr(rD(ctx->opcode));
76a66253 1067 if (unlikely(Rc(ctx->opcode) != 0))
9a64fbe4
FB
1068 gen_op_set_Rc1();
1069}
1070
1071/* fnabs */
1072GEN_FLOAT_B(nabs, 0x08, 0x04);
1073/* fneg */
1074GEN_FLOAT_B(neg, 0x08, 0x01);
1075
79aceca5
FB
1076/*** Floating-Point status & ctrl register ***/
1077/* mcrfs */
1078GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT)
1079{
76a66253 1080 if (unlikely(!ctx->fpu_enabled)) {
3cc62370
FB
1081 RET_EXCP(ctx, EXCP_NO_FP, 0);
1082 return;
1083 }
fb0eaffc
FB
1084 gen_op_load_fpscr_T0(crfS(ctx->opcode));
1085 gen_op_store_T0_crf(crfD(ctx->opcode));
1086 gen_op_clear_fpscr(crfS(ctx->opcode));
79aceca5
FB
1087}
1088
1089/* mffs */
1090GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT)
1091{
76a66253 1092 if (unlikely(!ctx->fpu_enabled)) {
3cc62370
FB
1093 RET_EXCP(ctx, EXCP_NO_FP, 0);
1094 return;
1095 }
28b6751f 1096 gen_op_load_fpscr();
fb0eaffc 1097 gen_op_store_FT0_fpr(rD(ctx->opcode));
76a66253 1098 if (unlikely(Rc(ctx->opcode) != 0))
fb0eaffc 1099 gen_op_set_Rc1();
79aceca5
FB
1100}
1101
1102/* mtfsb0 */
1103GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT)
1104{
fb0eaffc
FB
1105 uint8_t crb;
1106
76a66253 1107 if (unlikely(!ctx->fpu_enabled)) {
3cc62370
FB
1108 RET_EXCP(ctx, EXCP_NO_FP, 0);
1109 return;
1110 }
fb0eaffc
FB
1111 crb = crbD(ctx->opcode) >> 2;
1112 gen_op_load_fpscr_T0(crb);
76a66253 1113 gen_op_andi_T0(~(1 << (crbD(ctx->opcode) & 0x03)));
fb0eaffc 1114 gen_op_store_T0_fpscr(crb);
76a66253 1115 if (unlikely(Rc(ctx->opcode) != 0))
fb0eaffc 1116 gen_op_set_Rc1();
79aceca5
FB
1117}
1118
1119/* mtfsb1 */
1120GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT)
1121{
fb0eaffc
FB
1122 uint8_t crb;
1123
76a66253 1124 if (unlikely(!ctx->fpu_enabled)) {
3cc62370
FB
1125 RET_EXCP(ctx, EXCP_NO_FP, 0);
1126 return;
1127 }
fb0eaffc
FB
1128 crb = crbD(ctx->opcode) >> 2;
1129 gen_op_load_fpscr_T0(crb);
1130 gen_op_ori(1 << (crbD(ctx->opcode) & 0x03));
1131 gen_op_store_T0_fpscr(crb);
76a66253 1132 if (unlikely(Rc(ctx->opcode) != 0))
fb0eaffc 1133 gen_op_set_Rc1();
79aceca5
FB
1134}
1135
1136/* mtfsf */
1137GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x02010000, PPC_FLOAT)
1138{
76a66253 1139 if (unlikely(!ctx->fpu_enabled)) {
3cc62370
FB
1140 RET_EXCP(ctx, EXCP_NO_FP, 0);
1141 return;
1142 }
fb0eaffc 1143 gen_op_load_fpr_FT0(rB(ctx->opcode));
28b6751f 1144 gen_op_store_fpscr(FM(ctx->opcode));
76a66253 1145 if (unlikely(Rc(ctx->opcode) != 0))
fb0eaffc 1146 gen_op_set_Rc1();
79aceca5
FB
1147}
1148
1149/* mtfsfi */
1150GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT)
1151{
76a66253 1152 if (unlikely(!ctx->fpu_enabled)) {
3cc62370
FB
1153 RET_EXCP(ctx, EXCP_NO_FP, 0);
1154 return;
1155 }
fb0eaffc 1156 gen_op_store_T0_fpscri(crbD(ctx->opcode) >> 2, FPIMM(ctx->opcode));
76a66253 1157 if (unlikely(Rc(ctx->opcode) != 0))
fb0eaffc 1158 gen_op_set_Rc1();
79aceca5
FB
1159}
1160
76a66253
JM
1161/*** Addressing modes ***/
1162/* Register indirect with immediate index : EA = (rA|0) + SIMM */
1163static inline void gen_addr_imm_index (DisasContext *ctx)
1164{
1165 target_long simm = SIMM(ctx->opcode);
1166
1167 if (rA(ctx->opcode) == 0) {
1168 gen_op_set_T0(simm);
1169 } else {
1170 gen_op_load_gpr_T0(rA(ctx->opcode));
1171 if (likely(simm != 0))
1172 gen_op_addi(simm);
1173 }
1174}
1175
1176static inline void gen_addr_reg_index (DisasContext *ctx)
1177{
1178 if (rA(ctx->opcode) == 0) {
1179 gen_op_load_gpr_T0(rB(ctx->opcode));
1180 } else {
1181 gen_op_load_gpr_T0(rA(ctx->opcode));
1182 gen_op_load_gpr_T1(rB(ctx->opcode));
1183 gen_op_add();
1184 }
1185}
1186
1187static inline void gen_addr_register (DisasContext *ctx)
1188{
1189 if (rA(ctx->opcode) == 0) {
1190 gen_op_reset_T0();
1191 } else {
1192 gen_op_load_gpr_T0(rA(ctx->opcode));
1193 }
1194}
1195
79aceca5 1196/*** Integer load ***/
111bfab3 1197#define op_ldst(name) (*gen_op_##name[ctx->mem_idx])()
9a64fbe4 1198#if defined(CONFIG_USER_ONLY)
111bfab3
FB
1199#define OP_LD_TABLE(width) \
1200static GenOpFunc *gen_op_l##width[] = { \
1201 &gen_op_l##width##_raw, \
1202 &gen_op_l##width##_le_raw, \
1203};
1204#define OP_ST_TABLE(width) \
1205static GenOpFunc *gen_op_st##width[] = { \
1206 &gen_op_st##width##_raw, \
1207 &gen_op_st##width##_le_raw, \
1208};
1209/* Byte access routine are endian safe */
1210#define gen_op_stb_le_raw gen_op_stb_raw
1211#define gen_op_lbz_le_raw gen_op_lbz_raw
9a64fbe4 1212#else
9a64fbe4
FB
1213#define OP_LD_TABLE(width) \
1214static GenOpFunc *gen_op_l##width[] = { \
1215 &gen_op_l##width##_user, \
111bfab3 1216 &gen_op_l##width##_le_user, \
9a64fbe4 1217 &gen_op_l##width##_kernel, \
111bfab3
FB
1218 &gen_op_l##width##_le_kernel, \
1219};
9a64fbe4
FB
1220#define OP_ST_TABLE(width) \
1221static GenOpFunc *gen_op_st##width[] = { \
1222 &gen_op_st##width##_user, \
111bfab3 1223 &gen_op_st##width##_le_user, \
9a64fbe4 1224 &gen_op_st##width##_kernel, \
111bfab3
FB
1225 &gen_op_st##width##_le_kernel, \
1226};
1227/* Byte access routine are endian safe */
1228#define gen_op_stb_le_user gen_op_stb_user
1229#define gen_op_lbz_le_user gen_op_lbz_user
1230#define gen_op_stb_le_kernel gen_op_stb_kernel
1231#define gen_op_lbz_le_kernel gen_op_lbz_kernel
9a64fbe4
FB
1232#endif
1233
1234#define GEN_LD(width, opc) \
79aceca5
FB
1235GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
1236{ \
76a66253 1237 gen_addr_imm_index(ctx); \
9a64fbe4 1238 op_ldst(l##width); \
79aceca5 1239 gen_op_store_T1_gpr(rD(ctx->opcode)); \
79aceca5
FB
1240}
1241
9a64fbe4 1242#define GEN_LDU(width, opc) \
79aceca5
FB
1243GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
1244{ \
76a66253
JM
1245 if (unlikely(rA(ctx->opcode) == 0 || \
1246 rA(ctx->opcode) == rD(ctx->opcode))) { \
9fddaa0c
FB
1247 RET_INVAL(ctx); \
1248 return; \
9a64fbe4 1249 } \
76a66253 1250 gen_addr_imm_index(ctx); \
9a64fbe4 1251 op_ldst(l##width); \
79aceca5
FB
1252 gen_op_store_T1_gpr(rD(ctx->opcode)); \
1253 gen_op_store_T0_gpr(rA(ctx->opcode)); \
79aceca5
FB
1254}
1255
9a64fbe4 1256#define GEN_LDUX(width, opc) \
79aceca5
FB
1257GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \
1258{ \
76a66253
JM
1259 if (unlikely(rA(ctx->opcode) == 0 || \
1260 rA(ctx->opcode) == rD(ctx->opcode))) { \
9fddaa0c
FB
1261 RET_INVAL(ctx); \
1262 return; \
9a64fbe4 1263 } \
76a66253 1264 gen_addr_reg_index(ctx); \
9a64fbe4 1265 op_ldst(l##width); \
79aceca5
FB
1266 gen_op_store_T1_gpr(rD(ctx->opcode)); \
1267 gen_op_store_T0_gpr(rA(ctx->opcode)); \
79aceca5
FB
1268}
1269
9a64fbe4 1270#define GEN_LDX(width, opc2, opc3) \
79aceca5
FB
1271GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \
1272{ \
76a66253 1273 gen_addr_reg_index(ctx); \
9a64fbe4 1274 op_ldst(l##width); \
79aceca5 1275 gen_op_store_T1_gpr(rD(ctx->opcode)); \
79aceca5
FB
1276}
1277
9a64fbe4
FB
1278#define GEN_LDS(width, op) \
1279OP_LD_TABLE(width); \
1280GEN_LD(width, op | 0x20); \
1281GEN_LDU(width, op | 0x21); \
1282GEN_LDUX(width, op | 0x01); \
1283GEN_LDX(width, 0x17, op | 0x00)
79aceca5
FB
1284
1285/* lbz lbzu lbzux lbzx */
9a64fbe4 1286GEN_LDS(bz, 0x02);
79aceca5 1287/* lha lhau lhaux lhax */
9a64fbe4 1288GEN_LDS(ha, 0x0A);
79aceca5 1289/* lhz lhzu lhzux lhzx */
9a64fbe4 1290GEN_LDS(hz, 0x08);
79aceca5 1291/* lwz lwzu lwzux lwzx */
9a64fbe4 1292GEN_LDS(wz, 0x00);
79aceca5
FB
1293
1294/*** Integer store ***/
9a64fbe4 1295#define GEN_ST(width, opc) \
79aceca5
FB
1296GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
1297{ \
76a66253 1298 gen_addr_imm_index(ctx); \
9a64fbe4
FB
1299 gen_op_load_gpr_T1(rS(ctx->opcode)); \
1300 op_ldst(st##width); \
79aceca5
FB
1301}
1302
9a64fbe4 1303#define GEN_STU(width, opc) \
79aceca5
FB
1304GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
1305{ \
76a66253 1306 if (unlikely(rA(ctx->opcode) == 0)) { \
9fddaa0c
FB
1307 RET_INVAL(ctx); \
1308 return; \
9a64fbe4 1309 } \
76a66253 1310 gen_addr_imm_index(ctx); \
79aceca5 1311 gen_op_load_gpr_T1(rS(ctx->opcode)); \
9a64fbe4 1312 op_ldst(st##width); \
79aceca5 1313 gen_op_store_T0_gpr(rA(ctx->opcode)); \
79aceca5
FB
1314}
1315
9a64fbe4 1316#define GEN_STUX(width, opc) \
79aceca5
FB
1317GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \
1318{ \
76a66253 1319 if (unlikely(rA(ctx->opcode) == 0)) { \
9fddaa0c
FB
1320 RET_INVAL(ctx); \
1321 return; \
9a64fbe4 1322 } \
76a66253 1323 gen_addr_reg_index(ctx); \
9a64fbe4
FB
1324 gen_op_load_gpr_T1(rS(ctx->opcode)); \
1325 op_ldst(st##width); \
79aceca5 1326 gen_op_store_T0_gpr(rA(ctx->opcode)); \
79aceca5
FB
1327}
1328
9a64fbe4 1329#define GEN_STX(width, opc2, opc3) \
79aceca5
FB
1330GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \
1331{ \
76a66253 1332 gen_addr_reg_index(ctx); \
9a64fbe4
FB
1333 gen_op_load_gpr_T1(rS(ctx->opcode)); \
1334 op_ldst(st##width); \
79aceca5
FB
1335}
1336
9a64fbe4
FB
1337#define GEN_STS(width, op) \
1338OP_ST_TABLE(width); \
1339GEN_ST(width, op | 0x20); \
1340GEN_STU(width, op | 0x21); \
1341GEN_STUX(width, op | 0x01); \
1342GEN_STX(width, 0x17, op | 0x00)
79aceca5
FB
1343
1344/* stb stbu stbux stbx */
9a64fbe4 1345GEN_STS(b, 0x06);
79aceca5 1346/* sth sthu sthux sthx */
9a64fbe4 1347GEN_STS(h, 0x0C);
79aceca5 1348/* stw stwu stwux stwx */
9a64fbe4 1349GEN_STS(w, 0x04);
79aceca5
FB
1350
1351/*** Integer load and store with byte reverse ***/
1352/* lhbrx */
9a64fbe4
FB
1353OP_LD_TABLE(hbr);
1354GEN_LDX(hbr, 0x16, 0x18);
79aceca5 1355/* lwbrx */
9a64fbe4
FB
1356OP_LD_TABLE(wbr);
1357GEN_LDX(wbr, 0x16, 0x10);
79aceca5 1358/* sthbrx */
9a64fbe4
FB
1359OP_ST_TABLE(hbr);
1360GEN_STX(hbr, 0x16, 0x1C);
79aceca5 1361/* stwbrx */
9a64fbe4
FB
1362OP_ST_TABLE(wbr);
1363GEN_STX(wbr, 0x16, 0x14);
79aceca5
FB
1364
1365/*** Integer load and store multiple ***/
111bfab3 1366#define op_ldstm(name, reg) (*gen_op_##name[ctx->mem_idx])(reg)
9a64fbe4 1367#if defined(CONFIG_USER_ONLY)
111bfab3
FB
1368static GenOpFunc1 *gen_op_lmw[] = {
1369 &gen_op_lmw_raw,
1370 &gen_op_lmw_le_raw,
1371};
1372static GenOpFunc1 *gen_op_stmw[] = {
1373 &gen_op_stmw_raw,
1374 &gen_op_stmw_le_raw,
1375};
9a64fbe4 1376#else
9a64fbe4
FB
1377static GenOpFunc1 *gen_op_lmw[] = {
1378 &gen_op_lmw_user,
111bfab3 1379 &gen_op_lmw_le_user,
9a64fbe4 1380 &gen_op_lmw_kernel,
111bfab3 1381 &gen_op_lmw_le_kernel,
9a64fbe4
FB
1382};
1383static GenOpFunc1 *gen_op_stmw[] = {
1384 &gen_op_stmw_user,
111bfab3 1385 &gen_op_stmw_le_user,
9a64fbe4 1386 &gen_op_stmw_kernel,
111bfab3 1387 &gen_op_stmw_le_kernel,
9a64fbe4
FB
1388};
1389#endif
1390
79aceca5
FB
1391/* lmw */
1392GEN_HANDLER(lmw, 0x2E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
1393{
76a66253
JM
1394 /* NIP cannot be restored if the memory exception comes from an helper */
1395 gen_op_update_nip(ctx->nip - 4);
1396 gen_addr_imm_index(ctx);
9a64fbe4 1397 op_ldstm(lmw, rD(ctx->opcode));
79aceca5
FB
1398}
1399
1400/* stmw */
1401GEN_HANDLER(stmw, 0x2F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
1402{
76a66253
JM
1403 /* NIP cannot be restored if the memory exception comes from an helper */
1404 gen_op_update_nip(ctx->nip - 4);
1405 gen_addr_imm_index(ctx);
9a64fbe4 1406 op_ldstm(stmw, rS(ctx->opcode));
79aceca5
FB
1407}
1408
1409/*** Integer load and store strings ***/
9a64fbe4
FB
1410#define op_ldsts(name, start) (*gen_op_##name[ctx->mem_idx])(start)
1411#define op_ldstsx(name, rd, ra, rb) (*gen_op_##name[ctx->mem_idx])(rd, ra, rb)
111bfab3
FB
1412#if defined(CONFIG_USER_ONLY)
1413static GenOpFunc1 *gen_op_lswi[] = {
1414 &gen_op_lswi_raw,
1415 &gen_op_lswi_le_raw,
1416};
1417static GenOpFunc3 *gen_op_lswx[] = {
1418 &gen_op_lswx_raw,
1419 &gen_op_lswx_le_raw,
1420};
1421static GenOpFunc1 *gen_op_stsw[] = {
1422 &gen_op_stsw_raw,
1423 &gen_op_stsw_le_raw,
1424};
1425#else
9a64fbe4
FB
1426static GenOpFunc1 *gen_op_lswi[] = {
1427 &gen_op_lswi_user,
111bfab3 1428 &gen_op_lswi_le_user,
9a64fbe4 1429 &gen_op_lswi_kernel,
111bfab3 1430 &gen_op_lswi_le_kernel,
9a64fbe4
FB
1431};
1432static GenOpFunc3 *gen_op_lswx[] = {
1433 &gen_op_lswx_user,
111bfab3 1434 &gen_op_lswx_le_user,
9a64fbe4 1435 &gen_op_lswx_kernel,
111bfab3 1436 &gen_op_lswx_le_kernel,
9a64fbe4
FB
1437};
1438static GenOpFunc1 *gen_op_stsw[] = {
1439 &gen_op_stsw_user,
111bfab3 1440 &gen_op_stsw_le_user,
9a64fbe4 1441 &gen_op_stsw_kernel,
111bfab3 1442 &gen_op_stsw_le_kernel,
9a64fbe4
FB
1443};
1444#endif
1445
79aceca5 1446/* lswi */
3fc6c082 1447/* PowerPC32 specification says we must generate an exception if
9a64fbe4
FB
1448 * rA is in the range of registers to be loaded.
1449 * In an other hand, IBM says this is valid, but rA won't be loaded.
1450 * For now, I'll follow the spec...
1451 */
79aceca5
FB
1452GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_INTEGER)
1453{
1454 int nb = NB(ctx->opcode);
1455 int start = rD(ctx->opcode);
9a64fbe4 1456 int ra = rA(ctx->opcode);
79aceca5
FB
1457 int nr;
1458
1459 if (nb == 0)
1460 nb = 32;
1461 nr = nb / 4;
76a66253
JM
1462 if (unlikely(((start + nr) > 32 &&
1463 start <= ra && (start + nr - 32) > ra) ||
1464 ((start + nr) <= 32 && start <= ra && (start + nr) > ra))) {
9fddaa0c
FB
1465 RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX);
1466 return;
297d8e62 1467 }
8dd4983c 1468 /* NIP cannot be restored if the memory exception comes from an helper */
76a66253
JM
1469 gen_op_update_nip(ctx->nip - 4);
1470 gen_addr_register(ctx);
1471 gen_op_set_T1(nb);
9a64fbe4 1472 op_ldsts(lswi, start);
79aceca5
FB
1473}
1474
1475/* lswx */
1476GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001, PPC_INTEGER)
1477{
9a64fbe4
FB
1478 int ra = rA(ctx->opcode);
1479 int rb = rB(ctx->opcode);
1480
76a66253
JM
1481 /* NIP cannot be restored if the memory exception comes from an helper */
1482 gen_op_update_nip(ctx->nip - 4);
1483 gen_addr_reg_index(ctx);
9a64fbe4 1484 if (ra == 0) {
9a64fbe4 1485 ra = rb;
79aceca5 1486 }
9a64fbe4
FB
1487 gen_op_load_xer_bc();
1488 op_ldstsx(lswx, rD(ctx->opcode), ra, rb);
79aceca5
FB
1489}
1490
1491/* stswi */
1492GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_INTEGER)
1493{
4b3686fa
FB
1494 int nb = NB(ctx->opcode);
1495
76a66253
JM
1496 /* NIP cannot be restored if the memory exception comes from an helper */
1497 gen_op_update_nip(ctx->nip - 4);
1498 gen_addr_register(ctx);
4b3686fa
FB
1499 if (nb == 0)
1500 nb = 32;
1501 gen_op_set_T1(nb);
9a64fbe4 1502 op_ldsts(stsw, rS(ctx->opcode));
79aceca5
FB
1503}
1504
1505/* stswx */
1506GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_INTEGER)
1507{
8dd4983c 1508 /* NIP cannot be restored if the memory exception comes from an helper */
76a66253
JM
1509 gen_op_update_nip(ctx->nip - 4);
1510 gen_addr_reg_index(ctx);
1511 gen_op_load_xer_bc();
9a64fbe4 1512 op_ldsts(stsw, rS(ctx->opcode));
79aceca5
FB
1513}
1514
1515/*** Memory synchronisation ***/
1516/* eieio */
76a66253 1517GEN_HANDLER(eieio, 0x1F, 0x16, 0x1A, 0x03FF0801, PPC_MEM_EIEIO)
79aceca5 1518{
79aceca5
FB
1519}
1520
1521/* isync */
76a66253 1522GEN_HANDLER(isync, 0x13, 0x16, 0x04, 0x03FF0801, PPC_MEM)
79aceca5 1523{
79aceca5
FB
1524}
1525
111bfab3
FB
1526#define op_lwarx() (*gen_op_lwarx[ctx->mem_idx])()
1527#define op_stwcx() (*gen_op_stwcx[ctx->mem_idx])()
9a64fbe4 1528#if defined(CONFIG_USER_ONLY)
111bfab3
FB
1529static GenOpFunc *gen_op_lwarx[] = {
1530 &gen_op_lwarx_raw,
1531 &gen_op_lwarx_le_raw,
1532};
1533static GenOpFunc *gen_op_stwcx[] = {
1534 &gen_op_stwcx_raw,
1535 &gen_op_stwcx_le_raw,
1536};
9a64fbe4 1537#else
985a19d6
FB
1538static GenOpFunc *gen_op_lwarx[] = {
1539 &gen_op_lwarx_user,
111bfab3 1540 &gen_op_lwarx_le_user,
985a19d6 1541 &gen_op_lwarx_kernel,
111bfab3 1542 &gen_op_lwarx_le_kernel,
985a19d6 1543};
9a64fbe4
FB
1544static GenOpFunc *gen_op_stwcx[] = {
1545 &gen_op_stwcx_user,
111bfab3 1546 &gen_op_stwcx_le_user,
9a64fbe4 1547 &gen_op_stwcx_kernel,
111bfab3 1548 &gen_op_stwcx_le_kernel,
9a64fbe4
FB
1549};
1550#endif
1551
111bfab3 1552/* lwarx */
76a66253 1553GEN_HANDLER(lwarx, 0x1F, 0x14, 0x00, 0x00000001, PPC_RES)
79aceca5 1554{
76a66253 1555 gen_addr_reg_index(ctx);
985a19d6 1556 op_lwarx();
79aceca5 1557 gen_op_store_T1_gpr(rD(ctx->opcode));
79aceca5
FB
1558}
1559
1560/* stwcx. */
9a64fbe4 1561GEN_HANDLER(stwcx_, 0x1F, 0x16, 0x04, 0x00000000, PPC_RES)
79aceca5 1562{
76a66253 1563 gen_addr_reg_index(ctx);
9a64fbe4
FB
1564 gen_op_load_gpr_T1(rS(ctx->opcode));
1565 op_stwcx();
79aceca5
FB
1566}
1567
1568/* sync */
76a66253 1569GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_MEM_SYNC)
79aceca5 1570{
79aceca5
FB
1571}
1572
1573/*** Floating-point load ***/
9a64fbe4 1574#define GEN_LDF(width, opc) \
c7d344af 1575GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
79aceca5 1576{ \
76a66253 1577 if (unlikely(!ctx->fpu_enabled)) { \
4ecc3190
FB
1578 RET_EXCP(ctx, EXCP_NO_FP, 0); \
1579 return; \
1580 } \
76a66253 1581 gen_addr_imm_index(ctx); \
9a64fbe4 1582 op_ldst(l##width); \
76a66253 1583 gen_op_store_FT0_fpr(rD(ctx->opcode)); \
79aceca5
FB
1584}
1585
9a64fbe4 1586#define GEN_LDUF(width, opc) \
c7d344af 1587GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
79aceca5 1588{ \
76a66253 1589 if (unlikely(!ctx->fpu_enabled)) { \
4ecc3190
FB
1590 RET_EXCP(ctx, EXCP_NO_FP, 0); \
1591 return; \
1592 } \
76a66253 1593 if (unlikely(rA(ctx->opcode) == 0)) { \
9fddaa0c
FB
1594 RET_INVAL(ctx); \
1595 return; \
9a64fbe4 1596 } \
76a66253 1597 gen_addr_imm_index(ctx); \
9a64fbe4 1598 op_ldst(l##width); \
76a66253 1599 gen_op_store_FT0_fpr(rD(ctx->opcode)); \
79aceca5 1600 gen_op_store_T0_gpr(rA(ctx->opcode)); \
79aceca5
FB
1601}
1602
9a64fbe4 1603#define GEN_LDUXF(width, opc) \
c7d344af 1604GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \
79aceca5 1605{ \
76a66253 1606 if (unlikely(!ctx->fpu_enabled)) { \
4ecc3190
FB
1607 RET_EXCP(ctx, EXCP_NO_FP, 0); \
1608 return; \
1609 } \
76a66253 1610 if (unlikely(rA(ctx->opcode) == 0)) { \
9fddaa0c
FB
1611 RET_INVAL(ctx); \
1612 return; \
9a64fbe4 1613 } \
76a66253 1614 gen_addr_reg_index(ctx); \
9a64fbe4 1615 op_ldst(l##width); \
76a66253 1616 gen_op_store_FT0_fpr(rD(ctx->opcode)); \
79aceca5 1617 gen_op_store_T0_gpr(rA(ctx->opcode)); \
79aceca5
FB
1618}
1619
9a64fbe4 1620#define GEN_LDXF(width, opc2, opc3) \
c7d344af 1621GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_FLOAT) \
79aceca5 1622{ \
76a66253 1623 if (unlikely(!ctx->fpu_enabled)) { \
4ecc3190
FB
1624 RET_EXCP(ctx, EXCP_NO_FP, 0); \
1625 return; \
1626 } \
76a66253 1627 gen_addr_reg_index(ctx); \
9a64fbe4 1628 op_ldst(l##width); \
76a66253 1629 gen_op_store_FT0_fpr(rD(ctx->opcode)); \
79aceca5
FB
1630}
1631
9a64fbe4
FB
1632#define GEN_LDFS(width, op) \
1633OP_LD_TABLE(width); \
1634GEN_LDF(width, op | 0x20); \
1635GEN_LDUF(width, op | 0x21); \
1636GEN_LDUXF(width, op | 0x01); \
1637GEN_LDXF(width, 0x17, op | 0x00)
79aceca5
FB
1638
1639/* lfd lfdu lfdux lfdx */
9a64fbe4 1640GEN_LDFS(fd, 0x12);
79aceca5 1641/* lfs lfsu lfsux lfsx */
9a64fbe4 1642GEN_LDFS(fs, 0x10);
79aceca5
FB
1643
1644/*** Floating-point store ***/
1645#define GEN_STF(width, opc) \
c7d344af 1646GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
79aceca5 1647{ \
76a66253 1648 if (unlikely(!ctx->fpu_enabled)) { \
4ecc3190
FB
1649 RET_EXCP(ctx, EXCP_NO_FP, 0); \
1650 return; \
1651 } \
76a66253
JM
1652 gen_addr_imm_index(ctx); \
1653 gen_op_load_fpr_FT0(rS(ctx->opcode)); \
9a64fbe4 1654 op_ldst(st##width); \
79aceca5
FB
1655}
1656
9a64fbe4 1657#define GEN_STUF(width, opc) \
c7d344af 1658GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
79aceca5 1659{ \
76a66253 1660 if (unlikely(!ctx->fpu_enabled)) { \
4ecc3190
FB
1661 RET_EXCP(ctx, EXCP_NO_FP, 0); \
1662 return; \
1663 } \
76a66253 1664 if (unlikely(rA(ctx->opcode) == 0)) { \
9fddaa0c
FB
1665 RET_INVAL(ctx); \
1666 return; \
9a64fbe4 1667 } \
76a66253
JM
1668 gen_addr_imm_index(ctx); \
1669 gen_op_load_fpr_FT0(rS(ctx->opcode)); \
9a64fbe4 1670 op_ldst(st##width); \
79aceca5 1671 gen_op_store_T0_gpr(rA(ctx->opcode)); \
79aceca5
FB
1672}
1673
9a64fbe4 1674#define GEN_STUXF(width, opc) \
c7d344af 1675GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \
79aceca5 1676{ \
76a66253 1677 if (unlikely(!ctx->fpu_enabled)) { \
4ecc3190
FB
1678 RET_EXCP(ctx, EXCP_NO_FP, 0); \
1679 return; \
1680 } \
76a66253 1681 if (unlikely(rA(ctx->opcode) == 0)) { \
9fddaa0c
FB
1682 RET_INVAL(ctx); \
1683 return; \
9a64fbe4 1684 } \
76a66253
JM
1685 gen_addr_reg_index(ctx); \
1686 gen_op_load_fpr_FT0(rS(ctx->opcode)); \
9a64fbe4 1687 op_ldst(st##width); \
79aceca5 1688 gen_op_store_T0_gpr(rA(ctx->opcode)); \
79aceca5
FB
1689}
1690
9a64fbe4 1691#define GEN_STXF(width, opc2, opc3) \
c7d344af 1692GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_FLOAT) \
79aceca5 1693{ \
76a66253 1694 if (unlikely(!ctx->fpu_enabled)) { \
4ecc3190
FB
1695 RET_EXCP(ctx, EXCP_NO_FP, 0); \
1696 return; \
1697 } \
76a66253
JM
1698 gen_addr_reg_index(ctx); \
1699 gen_op_load_fpr_FT0(rS(ctx->opcode)); \
9a64fbe4 1700 op_ldst(st##width); \
79aceca5
FB
1701}
1702
9a64fbe4
FB
1703#define GEN_STFS(width, op) \
1704OP_ST_TABLE(width); \
1705GEN_STF(width, op | 0x20); \
1706GEN_STUF(width, op | 0x21); \
1707GEN_STUXF(width, op | 0x01); \
1708GEN_STXF(width, 0x17, op | 0x00)
79aceca5
FB
1709
1710/* stfd stfdu stfdux stfdx */
9a64fbe4 1711GEN_STFS(fd, 0x16);
79aceca5 1712/* stfs stfsu stfsux stfsx */
9a64fbe4 1713GEN_STFS(fs, 0x14);
79aceca5
FB
1714
1715/* Optional: */
1716/* stfiwx */
1717GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT)
1718{
76a66253 1719 if (unlikely(!ctx->fpu_enabled)) {
3cc62370
FB
1720 RET_EXCP(ctx, EXCP_NO_FP, 0);
1721 return;
1722 }
76a66253
JM
1723 gen_addr_reg_index(ctx);
1724 /* XXX: TODO: memcpy low order 32 bits of FRP(rs) into memory */
9fddaa0c 1725 RET_INVAL(ctx);
79aceca5
FB
1726}
1727
1728/*** Branch ***/
79aceca5 1729
c1942362
FB
1730static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
1731{
1732 TranslationBlock *tb;
1733 tb = ctx->tb;
1734 if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
1735 if (n == 0)
1736 gen_op_goto_tb0(TBPARAM(tb));
1737 else
1738 gen_op_goto_tb1(TBPARAM(tb));
1739 gen_op_set_T1(dest);
1740 gen_op_b_T1();
1741 gen_op_set_T0((long)tb + n);
ea4e754f
FB
1742 if (ctx->singlestep_enabled)
1743 gen_op_debug();
c1942362
FB
1744 gen_op_exit_tb();
1745 } else {
1746 gen_op_set_T1(dest);
1747 gen_op_b_T1();
76a66253 1748 gen_op_reset_T0();
ea4e754f
FB
1749 if (ctx->singlestep_enabled)
1750 gen_op_debug();
c1942362
FB
1751 gen_op_exit_tb();
1752 }
c53be334
FB
1753}
1754
79aceca5
FB
1755/* b ba bl bla */
1756GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
1757{
76a66253 1758 target_ulong li, target;
38a64f9d
FB
1759
1760 /* sign extend LI */
76a66253
JM
1761#if defined(TARGET_PPC64)
1762 li = ((target_long)LI(ctx->opcode) << 38) >> 38;
1763#else
1764 li = ((target_long)LI(ctx->opcode) << 6) >> 6;
1765#endif
1766 if (likely(AA(ctx->opcode) == 0))
046d6672 1767 target = ctx->nip + li - 4;
79aceca5 1768 else
9a64fbe4 1769 target = li;
9a64fbe4 1770 if (LK(ctx->opcode)) {
046d6672 1771 gen_op_setlr(ctx->nip);
9a64fbe4 1772 }
c1942362 1773 gen_goto_tb(ctx, 0, target);
9a64fbe4 1774 ctx->exception = EXCP_BRANCH;
79aceca5
FB
1775}
1776
e98a6e40
FB
1777#define BCOND_IM 0
1778#define BCOND_LR 1
1779#define BCOND_CTR 2
1780
1781static inline void gen_bcond(DisasContext *ctx, int type)
1782{
76a66253
JM
1783 target_ulong target = 0;
1784 target_ulong li;
e98a6e40
FB
1785 uint32_t bo = BO(ctx->opcode);
1786 uint32_t bi = BI(ctx->opcode);
1787 uint32_t mask;
e98a6e40 1788
e98a6e40
FB
1789 if ((bo & 0x4) == 0)
1790 gen_op_dec_ctr();
1791 switch(type) {
1792 case BCOND_IM:
76a66253
JM
1793 li = (target_long)((int16_t)(BD(ctx->opcode)));
1794 if (likely(AA(ctx->opcode) == 0)) {
046d6672 1795 target = ctx->nip + li - 4;
e98a6e40
FB
1796 } else {
1797 target = li;
1798 }
1799 break;
1800 case BCOND_CTR:
1801 gen_op_movl_T1_ctr();
1802 break;
1803 default:
1804 case BCOND_LR:
1805 gen_op_movl_T1_lr();
1806 break;
1807 }
1808 if (LK(ctx->opcode)) {
046d6672 1809 gen_op_setlr(ctx->nip);
e98a6e40
FB
1810 }
1811 if (bo & 0x10) {
1812 /* No CR condition */
1813 switch (bo & 0x6) {
1814 case 0:
1815 gen_op_test_ctr();
1816 break;
1817 case 2:
1818 gen_op_test_ctrz();
1819 break;
1820 default:
1821 case 4:
1822 case 6:
1823 if (type == BCOND_IM) {
c1942362 1824 gen_goto_tb(ctx, 0, target);
e98a6e40
FB
1825 } else {
1826 gen_op_b_T1();
76a66253 1827 gen_op_reset_T0();
e98a6e40
FB
1828 }
1829 goto no_test;
1830 }
1831 } else {
1832 mask = 1 << (3 - (bi & 0x03));
1833 gen_op_load_crf_T0(bi >> 2);
1834 if (bo & 0x8) {
1835 switch (bo & 0x6) {
1836 case 0:
1837 gen_op_test_ctr_true(mask);
1838 break;
1839 case 2:
1840 gen_op_test_ctrz_true(mask);
1841 break;
1842 default:
1843 case 4:
1844 case 6:
1845 gen_op_test_true(mask);
1846 break;
1847 }
1848 } else {
1849 switch (bo & 0x6) {
1850 case 0:
1851 gen_op_test_ctr_false(mask);
1852 break;
1853 case 2:
1854 gen_op_test_ctrz_false(mask);
1855 break;
1856 default:
1857 case 4:
1858 case 6:
1859 gen_op_test_false(mask);
1860 break;
1861 }
1862 }
1863 }
1864 if (type == BCOND_IM) {
c53be334
FB
1865 int l1 = gen_new_label();
1866 gen_op_jz_T0(l1);
c1942362 1867 gen_goto_tb(ctx, 0, target);
c53be334 1868 gen_set_label(l1);
c1942362 1869 gen_goto_tb(ctx, 1, ctx->nip);
e98a6e40 1870 } else {
046d6672 1871 gen_op_btest_T1(ctx->nip);
76a66253 1872 gen_op_reset_T0();
e98a6e40
FB
1873 }
1874 no_test:
76a66253
JM
1875 if (ctx->singlestep_enabled)
1876 gen_op_debug();
1877 gen_op_exit_tb();
e98a6e40
FB
1878 ctx->exception = EXCP_BRANCH;
1879}
1880
1881GEN_HANDLER(bc, 0x10, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
1882{
1883 gen_bcond(ctx, BCOND_IM);
1884}
1885
1886GEN_HANDLER(bcctr, 0x13, 0x10, 0x10, 0x00000000, PPC_FLOW)
1887{
1888 gen_bcond(ctx, BCOND_CTR);
1889}
1890
1891GEN_HANDLER(bclr, 0x13, 0x10, 0x00, 0x00000000, PPC_FLOW)
1892{
1893 gen_bcond(ctx, BCOND_LR);
1894}
79aceca5
FB
1895
1896/*** Condition register logical ***/
1897#define GEN_CRLOGIC(op, opc) \
1898GEN_HANDLER(cr##op, 0x13, 0x01, opc, 0x00000001, PPC_INTEGER) \
1899{ \
1900 gen_op_load_crf_T0(crbA(ctx->opcode) >> 2); \
1901 gen_op_getbit_T0(3 - (crbA(ctx->opcode) & 0x03)); \
1902 gen_op_load_crf_T1(crbB(ctx->opcode) >> 2); \
1903 gen_op_getbit_T1(3 - (crbB(ctx->opcode) & 0x03)); \
1904 gen_op_##op(); \
1905 gen_op_load_crf_T1(crbD(ctx->opcode) >> 2); \
1906 gen_op_setcrfbit(~(1 << (3 - (crbD(ctx->opcode) & 0x03))), \
1907 3 - (crbD(ctx->opcode) & 0x03)); \
1908 gen_op_store_T1_crf(crbD(ctx->opcode) >> 2); \
79aceca5
FB
1909}
1910
1911/* crand */
76a66253 1912GEN_CRLOGIC(and, 0x08);
79aceca5 1913/* crandc */
76a66253 1914GEN_CRLOGIC(andc, 0x04);
79aceca5 1915/* creqv */
76a66253 1916GEN_CRLOGIC(eqv, 0x09);
79aceca5 1917/* crnand */
76a66253 1918GEN_CRLOGIC(nand, 0x07);
79aceca5 1919/* crnor */
76a66253 1920GEN_CRLOGIC(nor, 0x01);
79aceca5 1921/* cror */
76a66253 1922GEN_CRLOGIC(or, 0x0E);
79aceca5 1923/* crorc */
76a66253 1924GEN_CRLOGIC(orc, 0x0D);
79aceca5 1925/* crxor */
76a66253 1926GEN_CRLOGIC(xor, 0x06);
79aceca5
FB
1927/* mcrf */
1928GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER)
1929{
1930 gen_op_load_crf_T0(crfS(ctx->opcode));
1931 gen_op_store_T0_crf(crfD(ctx->opcode));
79aceca5
FB
1932}
1933
1934/*** System linkage ***/
1935/* rfi (supervisor only) */
76a66253 1936GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW)
79aceca5 1937{
9a64fbe4 1938#if defined(CONFIG_USER_ONLY)
9fddaa0c 1939 RET_PRIVOPC(ctx);
9a64fbe4
FB
1940#else
1941 /* Restore CPU state */
76a66253 1942 if (unlikely(!ctx->supervisor)) {
9fddaa0c
FB
1943 RET_PRIVOPC(ctx);
1944 return;
9a64fbe4
FB
1945 }
1946 gen_op_rfi();
2be0071f 1947 RET_CHG_FLOW(ctx);
9a64fbe4 1948#endif
79aceca5
FB
1949}
1950
1951/* sc */
1952GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFFFFD, PPC_FLOW)
1953{
9a64fbe4 1954#if defined(CONFIG_USER_ONLY)
9fddaa0c 1955 RET_EXCP(ctx, EXCP_SYSCALL_USER, 0);
9a64fbe4 1956#else
9fddaa0c 1957 RET_EXCP(ctx, EXCP_SYSCALL, 0);
9a64fbe4 1958#endif
79aceca5
FB
1959}
1960
1961/*** Trap ***/
1962/* tw */
76a66253 1963GEN_HANDLER(tw, 0x1F, 0x04, 0x00, 0x00000001, PPC_FLOW)
79aceca5 1964{
9a64fbe4
FB
1965 gen_op_load_gpr_T0(rA(ctx->opcode));
1966 gen_op_load_gpr_T1(rB(ctx->opcode));
a0ae05aa
TS
1967 /* Update the nip since this might generate a trap exception */
1968 gen_op_update_nip(ctx->nip);
9a64fbe4 1969 gen_op_tw(TO(ctx->opcode));
79aceca5
FB
1970}
1971
1972/* twi */
1973GEN_HANDLER(twi, 0x03, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
1974{
9a64fbe4 1975 gen_op_load_gpr_T0(rA(ctx->opcode));
76a66253
JM
1976 gen_op_set_T1(SIMM(ctx->opcode));
1977 gen_op_tw(TO(ctx->opcode));
79aceca5
FB
1978}
1979
1980/*** Processor control ***/
79aceca5
FB
1981/* mcrxr */
1982GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC)
1983{
1984 gen_op_load_xer_cr();
1985 gen_op_store_T0_crf(crfD(ctx->opcode));
1986 gen_op_clear_xer_cr();
79aceca5
FB
1987}
1988
1989/* mfcr */
76a66253 1990GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x00000801, PPC_MISC)
79aceca5 1991{
76a66253
JM
1992#if 0 // XXX: to be tested
1993 uint32_t crm, crn;
1994
1995 if (likely(ctx->opcode & 0x00100000)) {
1996 crm = CRM(ctx->opcode);
1997 if (likely((crm ^ (crm - 1)) == 0)) {
1998 crn = ffs(crm);
1999 gen_op_load_cro(7 - crn);
2000 }
2001 } else
2002#endif
2003 {
2004 gen_op_load_cr();
2005 }
79aceca5 2006 gen_op_store_T0_gpr(rD(ctx->opcode));
79aceca5
FB
2007}
2008
2009/* mfmsr */
2010GEN_HANDLER(mfmsr, 0x1F, 0x13, 0x02, 0x001FF801, PPC_MISC)
2011{
9a64fbe4 2012#if defined(CONFIG_USER_ONLY)
9fddaa0c 2013 RET_PRIVREG(ctx);
9a64fbe4 2014#else
76a66253 2015 if (unlikely(!ctx->supervisor)) {
9fddaa0c
FB
2016 RET_PRIVREG(ctx);
2017 return;
9a64fbe4 2018 }
79aceca5
FB
2019 gen_op_load_msr();
2020 gen_op_store_T0_gpr(rD(ctx->opcode));
9a64fbe4 2021#endif
79aceca5
FB
2022}
2023
3fc6c082
FB
2024#if 0
2025#define SPR_NOACCESS ((void *)(-1))
2026#else
2027static void spr_noaccess (void *opaque, int sprn)
2028{
2029 sprn = ((sprn >> 5) & 0x1F) | ((sprn & 0x1F) << 5);
2030 printf("ERROR: try to access SPR %d !\n", sprn);
2031}
2032#define SPR_NOACCESS (&spr_noaccess)
2033#endif
2034
79aceca5 2035/* mfspr */
3fc6c082 2036static inline void gen_op_mfspr (DisasContext *ctx)
79aceca5 2037{
3fc6c082 2038 void (*read_cb)(void *opaque, int sprn);
79aceca5
FB
2039 uint32_t sprn = SPR(ctx->opcode);
2040
3fc6c082
FB
2041#if !defined(CONFIG_USER_ONLY)
2042 if (ctx->supervisor)
2043 read_cb = ctx->spr_cb[sprn].oea_read;
2044 else
9a64fbe4 2045#endif
3fc6c082 2046 read_cb = ctx->spr_cb[sprn].uea_read;
76a66253
JM
2047 if (likely(read_cb != NULL)) {
2048 if (likely(read_cb != SPR_NOACCESS)) {
3fc6c082
FB
2049 (*read_cb)(ctx, sprn);
2050 gen_op_store_T0_gpr(rD(ctx->opcode));
2051 } else {
2052 /* Privilege exception */
f24e5695
FB
2053 if (loglevel) {
2054 fprintf(logfile, "Trying to read priviledged spr %d %03x\n",
2055 sprn, sprn);
2056 }
3fc6c082 2057 printf("Trying to read priviledged spr %d %03x\n", sprn, sprn);
76a66253 2058 RET_PRIVREG(ctx);
79aceca5 2059 }
3fc6c082
FB
2060 } else {
2061 /* Not defined */
f24e5695
FB
2062 if (loglevel) {
2063 fprintf(logfile, "Trying to read invalid spr %d %03x\n",
2064 sprn, sprn);
2065 }
3fc6c082
FB
2066 printf("Trying to read invalid spr %d %03x\n", sprn, sprn);
2067 RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
79aceca5 2068 }
79aceca5
FB
2069}
2070
3fc6c082 2071GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC)
79aceca5 2072{
3fc6c082 2073 gen_op_mfspr(ctx);
76a66253 2074}
3fc6c082
FB
2075
2076/* mftb */
2077GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_TB)
2078{
2079 gen_op_mfspr(ctx);
79aceca5
FB
2080}
2081
2082/* mtcrf */
8dd4983c 2083GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00000801, PPC_MISC)
79aceca5 2084{
76a66253
JM
2085 uint32_t crm, crn;
2086
79aceca5 2087 gen_op_load_gpr_T0(rS(ctx->opcode));
76a66253
JM
2088 crm = CRM(ctx->opcode);
2089 if (likely((ctx->opcode & 0x00100000) || (crm ^ (crm - 1)) == 0)) {
2090 crn = ffs(crm);
2091 gen_op_srli_T0(crn * 4);
2092 gen_op_andi_T0(0xF);
2093 gen_op_store_cro(7 - crn);
2094 } else {
2095 gen_op_store_cr(crm);
2096 }
79aceca5
FB
2097}
2098
2099/* mtmsr */
2100GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC)
2101{
9a64fbe4 2102#if defined(CONFIG_USER_ONLY)
9fddaa0c 2103 RET_PRIVREG(ctx);
9a64fbe4 2104#else
76a66253 2105 if (unlikely(!ctx->supervisor)) {
9fddaa0c
FB
2106 RET_PRIVREG(ctx);
2107 return;
9a64fbe4 2108 }
e80e1cc4 2109 gen_op_update_nip((ctx)->nip);
79aceca5
FB
2110 gen_op_load_gpr_T0(rS(ctx->opcode));
2111 gen_op_store_msr();
2112 /* Must stop the translation as machine state (may have) changed */
e80e1cc4 2113 RET_CHG_FLOW(ctx);
9a64fbe4 2114#endif
79aceca5
FB
2115}
2116
2117/* mtspr */
2118GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC)
2119{
3fc6c082 2120 void (*write_cb)(void *opaque, int sprn);
79aceca5
FB
2121 uint32_t sprn = SPR(ctx->opcode);
2122
3fc6c082
FB
2123#if !defined(CONFIG_USER_ONLY)
2124 if (ctx->supervisor)
2125 write_cb = ctx->spr_cb[sprn].oea_write;
2126 else
9a64fbe4 2127#endif
3fc6c082 2128 write_cb = ctx->spr_cb[sprn].uea_write;
76a66253
JM
2129 if (likely(write_cb != NULL)) {
2130 if (likely(write_cb != SPR_NOACCESS)) {
3fc6c082
FB
2131 gen_op_load_gpr_T0(rS(ctx->opcode));
2132 (*write_cb)(ctx, sprn);
2133 } else {
2134 /* Privilege exception */
f24e5695
FB
2135 if (loglevel) {
2136 fprintf(logfile, "Trying to write priviledged spr %d %03x\n",
2137 sprn, sprn);
2138 }
3fc6c082 2139 printf("Trying to write priviledged spr %d %03x\n", sprn, sprn);
76a66253
JM
2140 RET_PRIVREG(ctx);
2141 }
3fc6c082
FB
2142 } else {
2143 /* Not defined */
f24e5695
FB
2144 if (loglevel) {
2145 fprintf(logfile, "Trying to write invalid spr %d %03x\n",
2146 sprn, sprn);
2147 }
3fc6c082
FB
2148 printf("Trying to write invalid spr %d %03x\n", sprn, sprn);
2149 RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
79aceca5 2150 }
79aceca5
FB
2151}
2152
2153/*** Cache management ***/
2154/* For now, all those will be implemented as nop:
2155 * this is valid, regarding the PowerPC specs...
9a64fbe4 2156 * We just have to flush tb while invalidating instruction cache lines...
79aceca5
FB
2157 */
2158/* dcbf */
9a64fbe4 2159GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03E00001, PPC_CACHE)
79aceca5 2160{
76a66253 2161 gen_addr_reg_index(ctx);
a541f297 2162 op_ldst(lbz);
79aceca5
FB
2163}
2164
2165/* dcbi (Supervisor only) */
9a64fbe4 2166GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE)
79aceca5 2167{
a541f297 2168#if defined(CONFIG_USER_ONLY)
9fddaa0c 2169 RET_PRIVOPC(ctx);
a541f297 2170#else
76a66253 2171 if (unlikely(!ctx->supervisor)) {
9fddaa0c
FB
2172 RET_PRIVOPC(ctx);
2173 return;
9a64fbe4 2174 }
76a66253
JM
2175 gen_addr_reg_index(ctx);
2176 /* XXX: specification says this should be treated as a store by the MMU */
2177 //op_ldst(lbz);
a541f297
FB
2178 op_ldst(stb);
2179#endif
79aceca5
FB
2180}
2181
2182/* dcdst */
9a64fbe4 2183GEN_HANDLER(dcbst, 0x1F, 0x16, 0x01, 0x03E00001, PPC_CACHE)
79aceca5 2184{
76a66253
JM
2185 /* XXX: specification say this is treated as a load by the MMU */
2186 gen_addr_reg_index(ctx);
a541f297 2187 op_ldst(lbz);
79aceca5
FB
2188}
2189
2190/* dcbt */
9a64fbe4 2191GEN_HANDLER(dcbt, 0x1F, 0x16, 0x08, 0x03E00001, PPC_CACHE)
79aceca5 2192{
76a66253
JM
2193 /* XXX: specification say this is treated as a load by the MMU
2194 * but does not generate any exception
2195 */
79aceca5
FB
2196}
2197
2198/* dcbtst */
9a64fbe4 2199GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x03E00001, PPC_CACHE)
79aceca5 2200{
76a66253
JM
2201 /* XXX: specification say this is treated as a load by the MMU
2202 * but does not generate any exception
2203 */
79aceca5
FB
2204}
2205
2206/* dcbz */
76a66253 2207#define op_dcbz() (*gen_op_dcbz[ctx->mem_idx])()
9a64fbe4 2208#if defined(CONFIG_USER_ONLY)
76a66253
JM
2209static GenOpFunc *gen_op_dcbz[] = {
2210 &gen_op_dcbz_raw,
2211 &gen_op_dcbz_raw,
2212};
9a64fbe4 2213#else
9a64fbe4
FB
2214static GenOpFunc *gen_op_dcbz[] = {
2215 &gen_op_dcbz_user,
2d5262f9
FB
2216 &gen_op_dcbz_user,
2217 &gen_op_dcbz_kernel,
9a64fbe4
FB
2218 &gen_op_dcbz_kernel,
2219};
2220#endif
2221
2222GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE)
79aceca5 2223{
76a66253 2224 gen_addr_reg_index(ctx);
9a64fbe4 2225 op_dcbz();
4b3686fa 2226 gen_op_check_reservation();
79aceca5
FB
2227}
2228
2229/* icbi */
9a64fbe4 2230GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_CACHE)
79aceca5 2231{
76a66253
JM
2232 /* NIP cannot be restored if the memory exception comes from an helper */
2233 gen_op_update_nip(ctx->nip - 4);
2234 gen_addr_reg_index(ctx);
9a64fbe4 2235 gen_op_icbi();
76a66253 2236 RET_STOP(ctx);
79aceca5
FB
2237}
2238
2239/* Optional: */
2240/* dcba */
c7d344af 2241GEN_HANDLER(dcba, 0x1F, 0x16, 0x17, 0x03E00001, PPC_CACHE_OPT)
79aceca5 2242{
79aceca5
FB
2243}
2244
2245/*** Segment register manipulation ***/
2246/* Supervisor only: */
2247/* mfsr */
2248GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT)
2249{
9a64fbe4 2250#if defined(CONFIG_USER_ONLY)
9fddaa0c 2251 RET_PRIVREG(ctx);
9a64fbe4 2252#else
76a66253 2253 if (unlikely(!ctx->supervisor)) {
9fddaa0c
FB
2254 RET_PRIVREG(ctx);
2255 return;
9a64fbe4 2256 }
76a66253
JM
2257 gen_op_set_T1(SR(ctx->opcode));
2258 gen_op_load_sr();
9a64fbe4
FB
2259 gen_op_store_T0_gpr(rD(ctx->opcode));
2260#endif
79aceca5
FB
2261}
2262
2263/* mfsrin */
9a64fbe4 2264GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT)
79aceca5 2265{
9a64fbe4 2266#if defined(CONFIG_USER_ONLY)
9fddaa0c 2267 RET_PRIVREG(ctx);
9a64fbe4 2268#else
76a66253 2269 if (unlikely(!ctx->supervisor)) {
9fddaa0c
FB
2270 RET_PRIVREG(ctx);
2271 return;
9a64fbe4
FB
2272 }
2273 gen_op_load_gpr_T1(rB(ctx->opcode));
76a66253
JM
2274 gen_op_srli_T1(28);
2275 gen_op_load_sr();
9a64fbe4
FB
2276 gen_op_store_T0_gpr(rD(ctx->opcode));
2277#endif
79aceca5
FB
2278}
2279
2280/* mtsr */
e63c59cb 2281GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT)
79aceca5 2282{
9a64fbe4 2283#if defined(CONFIG_USER_ONLY)
9fddaa0c 2284 RET_PRIVREG(ctx);
9a64fbe4 2285#else
76a66253 2286 if (unlikely(!ctx->supervisor)) {
9fddaa0c
FB
2287 RET_PRIVREG(ctx);
2288 return;
9a64fbe4
FB
2289 }
2290 gen_op_load_gpr_T0(rS(ctx->opcode));
76a66253
JM
2291 gen_op_set_T1(SR(ctx->opcode));
2292 gen_op_store_sr();
f24e5695 2293 RET_STOP(ctx);
9a64fbe4 2294#endif
79aceca5
FB
2295}
2296
2297/* mtsrin */
9a64fbe4 2298GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT)
79aceca5 2299{
9a64fbe4 2300#if defined(CONFIG_USER_ONLY)
9fddaa0c 2301 RET_PRIVREG(ctx);
9a64fbe4 2302#else
76a66253 2303 if (unlikely(!ctx->supervisor)) {
9fddaa0c
FB
2304 RET_PRIVREG(ctx);
2305 return;
9a64fbe4
FB
2306 }
2307 gen_op_load_gpr_T0(rS(ctx->opcode));
2308 gen_op_load_gpr_T1(rB(ctx->opcode));
76a66253
JM
2309 gen_op_srli_T1(28);
2310 gen_op_store_sr();
f24e5695 2311 RET_STOP(ctx);
9a64fbe4 2312#endif
79aceca5
FB
2313}
2314
2315/*** Lookaside buffer management ***/
2316/* Optional & supervisor only: */
2317/* tlbia */
3fc6c082 2318GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA)
79aceca5 2319{
9a64fbe4 2320#if defined(CONFIG_USER_ONLY)
9fddaa0c 2321 RET_PRIVOPC(ctx);
9a64fbe4 2322#else
76a66253 2323 if (unlikely(!ctx->supervisor)) {
9fddaa0c
FB
2324 if (loglevel)
2325 fprintf(logfile, "%s: ! supervisor\n", __func__);
2326 RET_PRIVOPC(ctx);
2327 return;
9a64fbe4
FB
2328 }
2329 gen_op_tlbia();
f24e5695 2330 RET_STOP(ctx);
9a64fbe4 2331#endif
79aceca5
FB
2332}
2333
2334/* tlbie */
76a66253 2335GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM_TLBIE)
79aceca5 2336{
9a64fbe4 2337#if defined(CONFIG_USER_ONLY)
9fddaa0c 2338 RET_PRIVOPC(ctx);
9a64fbe4 2339#else
76a66253 2340 if (unlikely(!ctx->supervisor)) {
9fddaa0c
FB
2341 RET_PRIVOPC(ctx);
2342 return;
9a64fbe4
FB
2343 }
2344 gen_op_load_gpr_T0(rB(ctx->opcode));
2345 gen_op_tlbie();
f24e5695 2346 RET_STOP(ctx);
9a64fbe4 2347#endif
79aceca5
FB
2348}
2349
2350/* tlbsync */
76a66253 2351GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM_TLBSYNC)
79aceca5 2352{
9a64fbe4 2353#if defined(CONFIG_USER_ONLY)
9fddaa0c 2354 RET_PRIVOPC(ctx);
9a64fbe4 2355#else
76a66253 2356 if (unlikely(!ctx->supervisor)) {
9fddaa0c
FB
2357 RET_PRIVOPC(ctx);
2358 return;
9a64fbe4
FB
2359 }
2360 /* This has no effect: it should ensure that all previous
2361 * tlbie have completed
2362 */
f24e5695 2363 RET_STOP(ctx);
9a64fbe4 2364#endif
79aceca5
FB
2365}
2366
2367/*** External control ***/
2368/* Optional: */
9a64fbe4
FB
2369#define op_eciwx() (*gen_op_eciwx[ctx->mem_idx])()
2370#define op_ecowx() (*gen_op_ecowx[ctx->mem_idx])()
111bfab3
FB
2371#if defined(CONFIG_USER_ONLY)
2372static GenOpFunc *gen_op_eciwx[] = {
2373 &gen_op_eciwx_raw,
2374 &gen_op_eciwx_le_raw,
2375};
2376static GenOpFunc *gen_op_ecowx[] = {
2377 &gen_op_ecowx_raw,
2378 &gen_op_ecowx_le_raw,
2379};
2380#else
9a64fbe4
FB
2381static GenOpFunc *gen_op_eciwx[] = {
2382 &gen_op_eciwx_user,
111bfab3 2383 &gen_op_eciwx_le_user,
9a64fbe4 2384 &gen_op_eciwx_kernel,
111bfab3 2385 &gen_op_eciwx_le_kernel,
9a64fbe4
FB
2386};
2387static GenOpFunc *gen_op_ecowx[] = {
2388 &gen_op_ecowx_user,
111bfab3 2389 &gen_op_ecowx_le_user,
9a64fbe4 2390 &gen_op_ecowx_kernel,
111bfab3 2391 &gen_op_ecowx_le_kernel,
9a64fbe4
FB
2392};
2393#endif
2394
111bfab3 2395/* eciwx */
79aceca5
FB
2396GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN)
2397{
9a64fbe4 2398 /* Should check EAR[E] & alignment ! */
76a66253
JM
2399 gen_addr_reg_index(ctx);
2400 op_eciwx();
2401 gen_op_store_T0_gpr(rD(ctx->opcode));
2402}
2403
2404/* ecowx */
2405GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN)
2406{
2407 /* Should check EAR[E] & alignment ! */
2408 gen_addr_reg_index(ctx);
2409 gen_op_load_gpr_T1(rS(ctx->opcode));
2410 op_ecowx();
2411}
2412
2413/* PowerPC 601 specific instructions */
2414/* abs - abs. */
2415GEN_HANDLER(abs, 0x1F, 0x08, 0x0B, 0x0000F800, PPC_POWER_BR)
2416{
2417 gen_op_load_gpr_T0(rA(ctx->opcode));
2418 gen_op_POWER_abs();
2419 gen_op_store_T0_gpr(rD(ctx->opcode));
2420 if (unlikely(Rc(ctx->opcode) != 0))
2421 gen_set_Rc0(ctx);
2422}
2423
2424/* abso - abso. */
2425GEN_HANDLER(abso, 0x1F, 0x08, 0x1B, 0x0000F800, PPC_POWER_BR)
2426{
2427 gen_op_load_gpr_T0(rA(ctx->opcode));
2428 gen_op_POWER_abso();
2429 gen_op_store_T0_gpr(rD(ctx->opcode));
2430 if (unlikely(Rc(ctx->opcode) != 0))
2431 gen_set_Rc0(ctx);
2432}
2433
2434/* clcs */
2435GEN_HANDLER(clcs, 0x1F, 0x10, 0x13, 0x0000F800, PPC_POWER_BR) /* 601 ? */
2436{
2437 gen_op_load_gpr_T0(rA(ctx->opcode));
2438 gen_op_POWER_clcs();
2439 gen_op_store_T0_gpr(rD(ctx->opcode));
2440}
2441
2442/* div - div. */
2443GEN_HANDLER(div, 0x1F, 0x0B, 0x0A, 0x00000000, PPC_POWER_BR)
2444{
2445 gen_op_load_gpr_T0(rA(ctx->opcode));
2446 gen_op_load_gpr_T1(rB(ctx->opcode));
2447 gen_op_POWER_div();
2448 gen_op_store_T0_gpr(rD(ctx->opcode));
2449 if (unlikely(Rc(ctx->opcode) != 0))
2450 gen_set_Rc0(ctx);
2451}
2452
2453/* divo - divo. */
2454GEN_HANDLER(divo, 0x1F, 0x0B, 0x1A, 0x00000000, PPC_POWER_BR)
2455{
2456 gen_op_load_gpr_T0(rA(ctx->opcode));
2457 gen_op_load_gpr_T1(rB(ctx->opcode));
2458 gen_op_POWER_divo();
2459 gen_op_store_T0_gpr(rD(ctx->opcode));
2460 if (unlikely(Rc(ctx->opcode) != 0))
2461 gen_set_Rc0(ctx);
2462}
2463
2464/* divs - divs. */
2465GEN_HANDLER(divs, 0x1F, 0x0B, 0x0B, 0x00000000, PPC_POWER_BR)
2466{
2467 gen_op_load_gpr_T0(rA(ctx->opcode));
2468 gen_op_load_gpr_T1(rB(ctx->opcode));
2469 gen_op_POWER_divs();
2470 gen_op_store_T0_gpr(rD(ctx->opcode));
2471 if (unlikely(Rc(ctx->opcode) != 0))
2472 gen_set_Rc0(ctx);
2473}
2474
2475/* divso - divso. */
2476GEN_HANDLER(divso, 0x1F, 0x0B, 0x1B, 0x00000000, PPC_POWER_BR)
2477{
2478 gen_op_load_gpr_T0(rA(ctx->opcode));
2479 gen_op_load_gpr_T1(rB(ctx->opcode));
2480 gen_op_POWER_divso();
2481 gen_op_store_T0_gpr(rD(ctx->opcode));
2482 if (unlikely(Rc(ctx->opcode) != 0))
2483 gen_set_Rc0(ctx);
2484}
2485
2486/* doz - doz. */
2487GEN_HANDLER(doz, 0x1F, 0x08, 0x08, 0x00000000, PPC_POWER_BR)
2488{
2489 gen_op_load_gpr_T0(rA(ctx->opcode));
2490 gen_op_load_gpr_T1(rB(ctx->opcode));
2491 gen_op_POWER_doz();
2492 gen_op_store_T0_gpr(rD(ctx->opcode));
2493 if (unlikely(Rc(ctx->opcode) != 0))
2494 gen_set_Rc0(ctx);
2495}
2496
2497/* dozo - dozo. */
2498GEN_HANDLER(dozo, 0x1F, 0x08, 0x18, 0x00000000, PPC_POWER_BR)
2499{
2500 gen_op_load_gpr_T0(rA(ctx->opcode));
2501 gen_op_load_gpr_T1(rB(ctx->opcode));
2502 gen_op_POWER_dozo();
2503 gen_op_store_T0_gpr(rD(ctx->opcode));
2504 if (unlikely(Rc(ctx->opcode) != 0))
2505 gen_set_Rc0(ctx);
2506}
2507
2508/* dozi */
2509GEN_HANDLER(dozi, 0x09, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR)
2510{
2511 gen_op_load_gpr_T0(rA(ctx->opcode));
2512 gen_op_set_T1(SIMM(ctx->opcode));
2513 gen_op_POWER_doz();
2514 gen_op_store_T0_gpr(rD(ctx->opcode));
2515}
2516
2517/* As lscbx load from memory byte after byte, it's always endian safe */
2518#define op_POWER_lscbx(start, ra, rb) \
2519(*gen_op_POWER_lscbx[ctx->mem_idx])(start, ra, rb)
2520#if defined(CONFIG_USER_ONLY)
2521static GenOpFunc3 *gen_op_POWER_lscbx[] = {
2522 &gen_op_POWER_lscbx_raw,
2523 &gen_op_POWER_lscbx_raw,
2524};
2525#else
2526static GenOpFunc3 *gen_op_POWER_lscbx[] = {
2527 &gen_op_POWER_lscbx_user,
2528 &gen_op_POWER_lscbx_user,
2529 &gen_op_POWER_lscbx_kernel,
2530 &gen_op_POWER_lscbx_kernel,
2531};
2532#endif
2533
2534/* lscbx - lscbx. */
2535GEN_HANDLER(lscbx, 0x1F, 0x15, 0x08, 0x00000000, PPC_POWER_BR)
2536{
2537 int ra = rA(ctx->opcode);
2538 int rb = rB(ctx->opcode);
2539
2540 gen_addr_reg_index(ctx);
2541 if (ra == 0) {
2542 ra = rb;
2543 }
2544 /* NIP cannot be restored if the memory exception comes from an helper */
2545 gen_op_update_nip(ctx->nip - 4);
2546 gen_op_load_xer_bc();
2547 gen_op_load_xer_cmp();
2548 op_POWER_lscbx(rD(ctx->opcode), ra, rb);
2549 gen_op_store_xer_bc();
2550 if (unlikely(Rc(ctx->opcode) != 0))
2551 gen_set_Rc0(ctx);
2552}
2553
2554/* maskg - maskg. */
2555GEN_HANDLER(maskg, 0x1F, 0x1D, 0x00, 0x00000000, PPC_POWER_BR)
2556{
2557 gen_op_load_gpr_T0(rS(ctx->opcode));
2558 gen_op_load_gpr_T1(rB(ctx->opcode));
2559 gen_op_POWER_maskg();
2560 gen_op_store_T0_gpr(rA(ctx->opcode));
2561 if (unlikely(Rc(ctx->opcode) != 0))
2562 gen_set_Rc0(ctx);
2563}
2564
2565/* maskir - maskir. */
2566GEN_HANDLER(maskir, 0x1F, 0x1D, 0x10, 0x00000000, PPC_POWER_BR)
2567{
2568 gen_op_load_gpr_T0(rA(ctx->opcode));
2569 gen_op_load_gpr_T1(rS(ctx->opcode));
2570 gen_op_load_gpr_T2(rB(ctx->opcode));
2571 gen_op_POWER_maskir();
2572 gen_op_store_T0_gpr(rA(ctx->opcode));
2573 if (unlikely(Rc(ctx->opcode) != 0))
2574 gen_set_Rc0(ctx);
2575}
2576
2577/* mul - mul. */
2578GEN_HANDLER(mul, 0x1F, 0x0B, 0x03, 0x00000000, PPC_POWER_BR)
2579{
2580 gen_op_load_gpr_T0(rA(ctx->opcode));
2581 gen_op_load_gpr_T1(rB(ctx->opcode));
2582 gen_op_POWER_mul();
2583 gen_op_store_T0_gpr(rD(ctx->opcode));
2584 if (unlikely(Rc(ctx->opcode) != 0))
2585 gen_set_Rc0(ctx);
2586}
2587
2588/* mulo - mulo. */
2589GEN_HANDLER(mulo, 0x1F, 0x0B, 0x13, 0x00000000, PPC_POWER_BR)
2590{
2591 gen_op_load_gpr_T0(rA(ctx->opcode));
2592 gen_op_load_gpr_T1(rB(ctx->opcode));
2593 gen_op_POWER_mulo();
2594 gen_op_store_T0_gpr(rD(ctx->opcode));
2595 if (unlikely(Rc(ctx->opcode) != 0))
2596 gen_set_Rc0(ctx);
2597}
2598
2599/* nabs - nabs. */
2600GEN_HANDLER(nabs, 0x1F, 0x08, 0x0F, 0x00000000, PPC_POWER_BR)
2601{
2602 gen_op_load_gpr_T0(rA(ctx->opcode));
2603 gen_op_POWER_nabs();
2604 gen_op_store_T0_gpr(rD(ctx->opcode));
2605 if (unlikely(Rc(ctx->opcode) != 0))
2606 gen_set_Rc0(ctx);
2607}
2608
2609/* nabso - nabso. */
2610GEN_HANDLER(nabso, 0x1F, 0x08, 0x1F, 0x00000000, PPC_POWER_BR)
2611{
2612 gen_op_load_gpr_T0(rA(ctx->opcode));
2613 gen_op_POWER_nabso();
2614 gen_op_store_T0_gpr(rD(ctx->opcode));
2615 if (unlikely(Rc(ctx->opcode) != 0))
2616 gen_set_Rc0(ctx);
2617}
2618
2619/* rlmi - rlmi. */
2620GEN_HANDLER(rlmi, 0x16, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR)
2621{
2622 uint32_t mb, me;
2623
2624 mb = MB(ctx->opcode);
2625 me = ME(ctx->opcode);
2626 gen_op_load_gpr_T0(rS(ctx->opcode));
2627 gen_op_load_gpr_T1(rA(ctx->opcode));
2628 gen_op_load_gpr_T2(rB(ctx->opcode));
2629 gen_op_POWER_rlmi(MASK(mb, me), ~MASK(mb, me));
2630 gen_op_store_T0_gpr(rA(ctx->opcode));
2631 if (unlikely(Rc(ctx->opcode) != 0))
2632 gen_set_Rc0(ctx);
2633}
2634
2635/* rrib - rrib. */
2636GEN_HANDLER(rrib, 0x1F, 0x19, 0x10, 0x00000000, PPC_POWER_BR)
2637{
2638 gen_op_load_gpr_T0(rS(ctx->opcode));
2639 gen_op_load_gpr_T1(rA(ctx->opcode));
2640 gen_op_load_gpr_T2(rB(ctx->opcode));
2641 gen_op_POWER_rrib();
2642 gen_op_store_T0_gpr(rA(ctx->opcode));
2643 if (unlikely(Rc(ctx->opcode) != 0))
2644 gen_set_Rc0(ctx);
2645}
2646
2647/* sle - sle. */
2648GEN_HANDLER(sle, 0x1F, 0x19, 0x04, 0x00000000, PPC_POWER_BR)
2649{
2650 gen_op_load_gpr_T0(rS(ctx->opcode));
2651 gen_op_load_gpr_T1(rB(ctx->opcode));
2652 gen_op_POWER_sle();
2653 gen_op_store_T0_gpr(rA(ctx->opcode));
2654 if (unlikely(Rc(ctx->opcode) != 0))
2655 gen_set_Rc0(ctx);
2656}
2657
2658/* sleq - sleq. */
2659GEN_HANDLER(sleq, 0x1F, 0x19, 0x06, 0x00000000, PPC_POWER_BR)
2660{
2661 gen_op_load_gpr_T0(rS(ctx->opcode));
2662 gen_op_load_gpr_T1(rB(ctx->opcode));
2663 gen_op_POWER_sleq();
2664 gen_op_store_T0_gpr(rA(ctx->opcode));
2665 if (unlikely(Rc(ctx->opcode) != 0))
2666 gen_set_Rc0(ctx);
2667}
2668
2669/* sliq - sliq. */
2670GEN_HANDLER(sliq, 0x1F, 0x18, 0x05, 0x00000000, PPC_POWER_BR)
2671{
2672 gen_op_load_gpr_T0(rS(ctx->opcode));
2673 gen_op_set_T1(SH(ctx->opcode));
2674 gen_op_POWER_sle();
2675 gen_op_store_T0_gpr(rA(ctx->opcode));
2676 if (unlikely(Rc(ctx->opcode) != 0))
2677 gen_set_Rc0(ctx);
2678}
2679
2680/* slliq - slliq. */
2681GEN_HANDLER(slliq, 0x1F, 0x18, 0x07, 0x00000000, PPC_POWER_BR)
2682{
2683 gen_op_load_gpr_T0(rS(ctx->opcode));
2684 gen_op_set_T1(SH(ctx->opcode));
2685 gen_op_POWER_sleq();
2686 gen_op_store_T0_gpr(rA(ctx->opcode));
2687 if (unlikely(Rc(ctx->opcode) != 0))
2688 gen_set_Rc0(ctx);
2689}
2690
2691/* sllq - sllq. */
2692GEN_HANDLER(sllq, 0x1F, 0x18, 0x06, 0x00000000, PPC_POWER_BR)
2693{
2694 gen_op_load_gpr_T0(rS(ctx->opcode));
2695 gen_op_load_gpr_T1(rB(ctx->opcode));
2696 gen_op_POWER_sllq();
2697 gen_op_store_T0_gpr(rA(ctx->opcode));
2698 if (unlikely(Rc(ctx->opcode) != 0))
2699 gen_set_Rc0(ctx);
2700}
2701
2702/* slq - slq. */
2703GEN_HANDLER(slq, 0x1F, 0x18, 0x04, 0x00000000, PPC_POWER_BR)
2704{
2705 gen_op_load_gpr_T0(rS(ctx->opcode));
2706 gen_op_load_gpr_T1(rB(ctx->opcode));
2707 gen_op_POWER_slq();
2708 gen_op_store_T0_gpr(rA(ctx->opcode));
2709 if (unlikely(Rc(ctx->opcode) != 0))
2710 gen_set_Rc0(ctx);
2711}
2712
2713/* sraiq -sraiq. */
2714GEN_HANDLER(sraiq, 0x1F, 0x18, 0x1D, 0x00000000, PPC_POWER_BR)
2715{
2716 gen_op_load_gpr_T0(rS(ctx->opcode));
2717 gen_op_set_T1(SH(ctx->opcode));
2718 gen_op_POWER_sraq();
2719 gen_op_store_T0_gpr(rA(ctx->opcode));
2720 if (unlikely(Rc(ctx->opcode) != 0))
2721 gen_set_Rc0(ctx);
2722}
2723
2724/* sraq - sraq. */
2725GEN_HANDLER(sraq, 0x1F, 0x18, 0x1C, 0x00000000, PPC_POWER_BR)
2726{
2727 gen_op_load_gpr_T0(rS(ctx->opcode));
2728 gen_op_load_gpr_T1(rB(ctx->opcode));
2729 gen_op_POWER_sraq();
2730 gen_op_store_T0_gpr(rA(ctx->opcode));
2731 if (unlikely(Rc(ctx->opcode) != 0))
2732 gen_set_Rc0(ctx);
2733}
2734
2735/* sre - sre. */
2736GEN_HANDLER(sre, 0x1F, 0x19, 0x14, 0x00000000, PPC_POWER_BR)
2737{
2738 gen_op_load_gpr_T0(rS(ctx->opcode));
2739 gen_op_load_gpr_T1(rB(ctx->opcode));
2740 gen_op_POWER_sre();
2741 gen_op_store_T0_gpr(rA(ctx->opcode));
2742 if (unlikely(Rc(ctx->opcode) != 0))
2743 gen_set_Rc0(ctx);
2744}
2745
2746/* srea - srea. */
2747GEN_HANDLER(srea, 0x1F, 0x19, 0x1C, 0x00000000, PPC_POWER_BR)
2748{
2749 gen_op_load_gpr_T0(rS(ctx->opcode));
2750 gen_op_load_gpr_T1(rB(ctx->opcode));
2751 gen_op_POWER_srea();
2752 gen_op_store_T0_gpr(rA(ctx->opcode));
2753 if (unlikely(Rc(ctx->opcode) != 0))
2754 gen_set_Rc0(ctx);
2755}
2756
2757/* sreq */
2758GEN_HANDLER(sreq, 0x1F, 0x19, 0x16, 0x00000000, PPC_POWER_BR)
2759{
2760 gen_op_load_gpr_T0(rS(ctx->opcode));
2761 gen_op_load_gpr_T1(rB(ctx->opcode));
2762 gen_op_POWER_sreq();
2763 gen_op_store_T0_gpr(rA(ctx->opcode));
2764 if (unlikely(Rc(ctx->opcode) != 0))
2765 gen_set_Rc0(ctx);
2766}
2767
2768/* sriq */
2769GEN_HANDLER(sriq, 0x1F, 0x18, 0x15, 0x00000000, PPC_POWER_BR)
2770{
2771 gen_op_load_gpr_T0(rS(ctx->opcode));
2772 gen_op_set_T1(SH(ctx->opcode));
2773 gen_op_POWER_srq();
2774 gen_op_store_T0_gpr(rA(ctx->opcode));
2775 if (unlikely(Rc(ctx->opcode) != 0))
2776 gen_set_Rc0(ctx);
2777}
2778
2779/* srliq */
2780GEN_HANDLER(srliq, 0x1F, 0x18, 0x17, 0x00000000, PPC_POWER_BR)
2781{
2782 gen_op_load_gpr_T0(rS(ctx->opcode));
2783 gen_op_load_gpr_T1(rB(ctx->opcode));
2784 gen_op_set_T1(SH(ctx->opcode));
2785 gen_op_POWER_srlq();
2786 gen_op_store_T0_gpr(rA(ctx->opcode));
2787 if (unlikely(Rc(ctx->opcode) != 0))
2788 gen_set_Rc0(ctx);
2789}
2790
2791/* srlq */
2792GEN_HANDLER(srlq, 0x1F, 0x18, 0x16, 0x00000000, PPC_POWER_BR)
2793{
2794 gen_op_load_gpr_T0(rS(ctx->opcode));
2795 gen_op_load_gpr_T1(rB(ctx->opcode));
2796 gen_op_POWER_srlq();
2797 gen_op_store_T0_gpr(rA(ctx->opcode));
2798 if (unlikely(Rc(ctx->opcode) != 0))
2799 gen_set_Rc0(ctx);
2800}
2801
2802/* srq */
2803GEN_HANDLER(srq, 0x1F, 0x18, 0x14, 0x00000000, PPC_POWER_BR)
2804{
2805 gen_op_load_gpr_T0(rS(ctx->opcode));
2806 gen_op_load_gpr_T1(rB(ctx->opcode));
2807 gen_op_POWER_srq();
2808 gen_op_store_T0_gpr(rA(ctx->opcode));
2809 if (unlikely(Rc(ctx->opcode) != 0))
2810 gen_set_Rc0(ctx);
2811}
2812
2813/* PowerPC 602 specific instructions */
2814/* dsa */
2815GEN_HANDLER(dsa, 0x1F, 0x14, 0x13, 0x03FFF801, PPC_602_SPEC)
2816{
2817 /* XXX: TODO */
2818 RET_INVAL(ctx);
2819}
2820
2821/* esa */
2822GEN_HANDLER(esa, 0x1F, 0x14, 0x12, 0x03FFF801, PPC_602_SPEC)
2823{
2824 /* XXX: TODO */
2825 RET_INVAL(ctx);
2826}
2827
2828/* mfrom */
2829GEN_HANDLER(mfrom, 0x1F, 0x09, 0x08, 0x03E0F801, PPC_602_SPEC)
2830{
2831#if defined(CONFIG_USER_ONLY)
2832 RET_PRIVOPC(ctx);
2833#else
2834 if (unlikely(!ctx->supervisor)) {
2835 RET_PRIVOPC(ctx);
2836 return;
2837 }
2838 gen_op_load_gpr_T0(rA(ctx->opcode));
2839 gen_op_602_mfrom();
2840 gen_op_store_T0_gpr(rD(ctx->opcode));
2841#endif
2842}
2843
2844/* 602 - 603 - G2 TLB management */
2845/* tlbld */
2846GEN_HANDLER(tlbld, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB)
2847{
2848#if defined(CONFIG_USER_ONLY)
2849 RET_PRIVOPC(ctx);
2850#else
2851 if (unlikely(!ctx->supervisor)) {
2852 RET_PRIVOPC(ctx);
2853 return;
2854 }
2855 gen_op_load_gpr_T0(rB(ctx->opcode));
2856 gen_op_6xx_tlbld();
2857 RET_STOP(ctx);
2858#endif
2859}
2860
2861/* tlbli */
2862GEN_HANDLER(tlbli, 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB)
2863{
2864#if defined(CONFIG_USER_ONLY)
2865 RET_PRIVOPC(ctx);
2866#else
2867 if (unlikely(!ctx->supervisor)) {
2868 RET_PRIVOPC(ctx);
2869 return;
2870 }
2871 gen_op_load_gpr_T0(rB(ctx->opcode));
2872 gen_op_6xx_tlbli();
2873 RET_STOP(ctx);
2874#endif
2875}
2876
2877/* POWER instructions not in PowerPC 601 */
2878/* clf */
2879GEN_HANDLER(clf, 0x1F, 0x16, 0x03, 0x03E00000, PPC_POWER)
2880{
2881 /* Cache line flush: implemented as no-op */
2882}
2883
2884/* cli */
2885GEN_HANDLER(cli, 0x1F, 0x16, 0x0F, 0x03E00000, PPC_POWER)
2886{
2887 /* Cache line invalidate: priviledged and treated as no-op */
2888#if defined(CONFIG_USER_ONLY)
2889 RET_PRIVOPC(ctx);
2890#else
2891 if (unlikely(!ctx->supervisor)) {
2892 RET_PRIVOPC(ctx);
2893 return;
2894 }
2895#endif
2896}
2897
2898/* dclst */
2899GEN_HANDLER(dclst, 0x1F, 0x16, 0x13, 0x03E00000, PPC_POWER)
2900{
2901 /* Data cache line store: treated as no-op */
2902}
2903
2904GEN_HANDLER(mfsri, 0x1F, 0x13, 0x13, 0x00000001, PPC_POWER)
2905{
2906#if defined(CONFIG_USER_ONLY)
2907 RET_PRIVOPC(ctx);
2908#else
2909 if (unlikely(!ctx->supervisor)) {
2910 RET_PRIVOPC(ctx);
2911 return;
2912 }
2913 int ra = rA(ctx->opcode);
2914 int rd = rD(ctx->opcode);
2915
2916 gen_addr_reg_index(ctx);
2917 gen_op_POWER_mfsri();
2918 gen_op_store_T0_gpr(rd);
2919 if (ra != 0 && ra != rd)
2920 gen_op_store_T1_gpr(ra);
2921#endif
2922}
2923
2924GEN_HANDLER(rac, 0x1F, 0x12, 0x19, 0x00000001, PPC_POWER)
2925{
2926#if defined(CONFIG_USER_ONLY)
2927 RET_PRIVOPC(ctx);
2928#else
2929 if (unlikely(!ctx->supervisor)) {
2930 RET_PRIVOPC(ctx);
2931 return;
2932 }
2933 gen_addr_reg_index(ctx);
2934 gen_op_POWER_rac();
2935 gen_op_store_T0_gpr(rD(ctx->opcode));
2936#endif
2937}
2938
2939GEN_HANDLER(rfsvc, 0x13, 0x12, 0x02, 0x03FFF0001, PPC_POWER)
2940{
2941#if defined(CONFIG_USER_ONLY)
2942 RET_PRIVOPC(ctx);
2943#else
2944 if (unlikely(!ctx->supervisor)) {
2945 RET_PRIVOPC(ctx);
2946 return;
2947 }
2948 gen_op_POWER_rfsvc();
2949 RET_CHG_FLOW(ctx);
2950#endif
2951}
2952
2953/* svc is not implemented for now */
2954
2955/* POWER2 specific instructions */
2956/* Quad manipulation (load/store two floats at a time) */
2957#define op_POWER2_lfq() (*gen_op_POWER2_lfq[ctx->mem_idx])()
2958#define op_POWER2_stfq() (*gen_op_POWER2_stfq[ctx->mem_idx])()
2959#if defined(CONFIG_USER_ONLY)
2960static GenOpFunc *gen_op_POWER2_lfq[] = {
2961 &gen_op_POWER2_lfq_le_raw,
2962 &gen_op_POWER2_lfq_raw,
2963};
2964static GenOpFunc *gen_op_POWER2_stfq[] = {
2965 &gen_op_POWER2_stfq_le_raw,
2966 &gen_op_POWER2_stfq_raw,
2967};
2968#else
2969static GenOpFunc *gen_op_POWER2_lfq[] = {
2970 &gen_op_POWER2_lfq_le_user,
2971 &gen_op_POWER2_lfq_user,
2972 &gen_op_POWER2_lfq_le_kernel,
2973 &gen_op_POWER2_lfq_kernel,
2974};
2975static GenOpFunc *gen_op_POWER2_stfq[] = {
2976 &gen_op_POWER2_stfq_le_user,
2977 &gen_op_POWER2_stfq_user,
2978 &gen_op_POWER2_stfq_le_kernel,
2979 &gen_op_POWER2_stfq_kernel,
2980};
2981#endif
2982
2983/* lfq */
2984GEN_HANDLER(lfq, 0x38, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
2985{
2986 /* NIP cannot be restored if the memory exception comes from an helper */
2987 gen_op_update_nip(ctx->nip - 4);
2988 gen_addr_imm_index(ctx);
2989 op_POWER2_lfq();
2990 gen_op_store_FT0_fpr(rD(ctx->opcode));
2991 gen_op_store_FT1_fpr(rD(ctx->opcode) + 1);
2992}
2993
2994/* lfqu */
2995GEN_HANDLER(lfqu, 0x39, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
2996{
2997 int ra = rA(ctx->opcode);
2998
2999 /* NIP cannot be restored if the memory exception comes from an helper */
3000 gen_op_update_nip(ctx->nip - 4);
3001 gen_addr_imm_index(ctx);
3002 op_POWER2_lfq();
3003 gen_op_store_FT0_fpr(rD(ctx->opcode));
3004 gen_op_store_FT1_fpr(rD(ctx->opcode) + 1);
3005 if (ra != 0)
3006 gen_op_store_T0_gpr(ra);
3007}
3008
3009/* lfqux */
3010GEN_HANDLER(lfqux, 0x1F, 0x17, 0x19, 0x00000001, PPC_POWER2)
3011{
3012 int ra = rA(ctx->opcode);
3013
3014 /* NIP cannot be restored if the memory exception comes from an helper */
3015 gen_op_update_nip(ctx->nip - 4);
3016 gen_addr_reg_index(ctx);
3017 op_POWER2_lfq();
3018 gen_op_store_FT0_fpr(rD(ctx->opcode));
3019 gen_op_store_FT1_fpr(rD(ctx->opcode) + 1);
3020 if (ra != 0)
3021 gen_op_store_T0_gpr(ra);
3022}
3023
3024/* lfqx */
3025GEN_HANDLER(lfqx, 0x1F, 0x17, 0x18, 0x00000001, PPC_POWER2)
3026{
3027 /* NIP cannot be restored if the memory exception comes from an helper */
3028 gen_op_update_nip(ctx->nip - 4);
3029 gen_addr_reg_index(ctx);
3030 op_POWER2_lfq();
3031 gen_op_store_FT0_fpr(rD(ctx->opcode));
3032 gen_op_store_FT1_fpr(rD(ctx->opcode) + 1);
3033}
3034
3035/* stfq */
3036GEN_HANDLER(stfq, 0x3C, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
3037{
3038 /* NIP cannot be restored if the memory exception comes from an helper */
3039 gen_op_update_nip(ctx->nip - 4);
3040 gen_addr_imm_index(ctx);
3041 gen_op_load_fpr_FT0(rS(ctx->opcode));
3042 gen_op_load_fpr_FT1(rS(ctx->opcode) + 1);
3043 op_POWER2_stfq();
3044}
3045
3046/* stfqu */
3047GEN_HANDLER(stfqu, 0x3D, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
3048{
3049 int ra = rA(ctx->opcode);
3050
3051 /* NIP cannot be restored if the memory exception comes from an helper */
3052 gen_op_update_nip(ctx->nip - 4);
3053 gen_addr_imm_index(ctx);
3054 gen_op_load_fpr_FT0(rS(ctx->opcode));
3055 gen_op_load_fpr_FT1(rS(ctx->opcode) + 1);
3056 op_POWER2_stfq();
3057 if (ra != 0)
3058 gen_op_store_T0_gpr(ra);
3059}
3060
3061/* stfqux */
3062GEN_HANDLER(stfqux, 0x1F, 0x17, 0x1D, 0x00000001, PPC_POWER2)
3063{
3064 int ra = rA(ctx->opcode);
3065
3066 /* NIP cannot be restored if the memory exception comes from an helper */
3067 gen_op_update_nip(ctx->nip - 4);
3068 gen_addr_reg_index(ctx);
3069 gen_op_load_fpr_FT0(rS(ctx->opcode));
3070 gen_op_load_fpr_FT1(rS(ctx->opcode) + 1);
3071 op_POWER2_stfq();
3072 if (ra != 0)
3073 gen_op_store_T0_gpr(ra);
3074}
3075
3076/* stfqx */
3077GEN_HANDLER(stfqx, 0x1F, 0x17, 0x1C, 0x00000001, PPC_POWER2)
3078{
3079 /* NIP cannot be restored if the memory exception comes from an helper */
3080 gen_op_update_nip(ctx->nip - 4);
3081 gen_addr_reg_index(ctx);
3082 gen_op_load_fpr_FT0(rS(ctx->opcode));
3083 gen_op_load_fpr_FT1(rS(ctx->opcode) + 1);
3084 op_POWER2_stfq();
3085}
3086
3087/* BookE specific instructions */
3088GEN_HANDLER(mfapidi, 0x1F, 0x13, 0x08, 0x0000F801, PPC_BOOKE)
3089{
3090 /* XXX: TODO */
3091 RET_INVAL(ctx);
3092}
3093
3094GEN_HANDLER(tlbiva, 0x1F, 0x12, 0x18, 0x03FFF801, PPC_BOOKE)
3095{
3096#if defined(CONFIG_USER_ONLY)
3097 RET_PRIVOPC(ctx);
3098#else
3099 if (unlikely(!ctx->supervisor)) {
3100 RET_PRIVOPC(ctx);
3101 return;
3102 }
3103 gen_addr_reg_index(ctx);
3104 /* Use the same micro-ops as for tlbie */
3105 gen_op_tlbie();
3106 RET_STOP(ctx);
3107#endif
3108}
3109
3110/* All 405 MAC instructions are translated here */
3111static inline void gen_405_mulladd_insn (DisasContext *ctx, int opc2, int opc3,
3112 int ra, int rb, int rt, int Rc)
3113{
3114 gen_op_load_gpr_T0(ra);
3115 gen_op_load_gpr_T1(rb);
3116 switch (opc3 & 0x0D) {
3117 case 0x05:
3118 /* macchw - macchw. - macchwo - macchwo. */
3119 /* macchws - macchws. - macchwso - macchwso. */
3120 /* nmacchw - nmacchw. - nmacchwo - nmacchwo. */
3121 /* nmacchws - nmacchws. - nmacchwso - nmacchwso. */
3122 /* mulchw - mulchw. */
3123 gen_op_405_mulchw();
3124 break;
3125 case 0x04:
3126 /* macchwu - macchwu. - macchwuo - macchwuo. */
3127 /* macchwsu - macchwsu. - macchwsuo - macchwsuo. */
3128 /* mulchwu - mulchwu. */
3129 gen_op_405_mulchwu();
3130 break;
3131 case 0x01:
3132 /* machhw - machhw. - machhwo - machhwo. */
3133 /* machhws - machhws. - machhwso - machhwso. */
3134 /* nmachhw - nmachhw. - nmachhwo - nmachhwo. */
3135 /* nmachhws - nmachhws. - nmachhwso - nmachhwso. */
3136 /* mulhhw - mulhhw. */
3137 gen_op_405_mulhhw();
3138 break;
3139 case 0x00:
3140 /* machhwu - machhwu. - machhwuo - machhwuo. */
3141 /* machhwsu - machhwsu. - machhwsuo - machhwsuo. */
3142 /* mulhhwu - mulhhwu. */
3143 gen_op_405_mulhhwu();
3144 break;
3145 case 0x0D:
3146 /* maclhw - maclhw. - maclhwo - maclhwo. */
3147 /* maclhws - maclhws. - maclhwso - maclhwso. */
3148 /* nmaclhw - nmaclhw. - nmaclhwo - nmaclhwo. */
3149 /* nmaclhws - nmaclhws. - nmaclhwso - nmaclhwso. */
3150 /* mullhw - mullhw. */
3151 gen_op_405_mullhw();
3152 break;
3153 case 0x0C:
3154 /* maclhwu - maclhwu. - maclhwuo - maclhwuo. */
3155 /* maclhwsu - maclhwsu. - maclhwsuo - maclhwsuo. */
3156 /* mullhwu - mullhwu. */
3157 gen_op_405_mullhwu();
3158 break;
3159 }
3160 if (opc2 & 0x02) {
3161 /* nmultiply-and-accumulate (0x0E) */
3162 gen_op_neg();
3163 }
3164 if (opc2 & 0x04) {
3165 /* (n)multiply-and-accumulate (0x0C - 0x0E) */
3166 gen_op_load_gpr_T2(rt);
3167 gen_op_move_T1_T0();
3168 gen_op_405_add_T0_T2();
3169 }
3170 if (opc3 & 0x10) {
3171 /* Check overflow */
3172 if (opc3 & 0x01)
3173 gen_op_405_check_ov();
3174 else
3175 gen_op_405_check_ovu();
3176 }
3177 if (opc3 & 0x02) {
3178 /* Saturate */
3179 if (opc3 & 0x01)
3180 gen_op_405_check_sat();
3181 else
3182 gen_op_405_check_satu();
3183 }
3184 gen_op_store_T0_gpr(rt);
3185 if (unlikely(Rc) != 0) {
3186 /* Update Rc0 */
3187 gen_set_Rc0(ctx);
3188 }
3189}
3190
3191#define GEN_MAC_HANDLER(name, opc2, opc3) \
3192GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_405_MAC) \
3193{ \
3194 gen_405_mulladd_insn(ctx, opc2, opc3, rA(ctx->opcode), rB(ctx->opcode), \
3195 rD(ctx->opcode), Rc(ctx->opcode)); \
3196}
3197
3198/* macchw - macchw. */
3199GEN_MAC_HANDLER(macchw, 0x0C, 0x05);
3200/* macchwo - macchwo. */
3201GEN_MAC_HANDLER(macchwo, 0x0C, 0x15);
3202/* macchws - macchws. */
3203GEN_MAC_HANDLER(macchws, 0x0C, 0x07);
3204/* macchwso - macchwso. */
3205GEN_MAC_HANDLER(macchwso, 0x0C, 0x17);
3206/* macchwsu - macchwsu. */
3207GEN_MAC_HANDLER(macchwsu, 0x0C, 0x06);
3208/* macchwsuo - macchwsuo. */
3209GEN_MAC_HANDLER(macchwsuo, 0x0C, 0x16);
3210/* macchwu - macchwu. */
3211GEN_MAC_HANDLER(macchwu, 0x0C, 0x04);
3212/* macchwuo - macchwuo. */
3213GEN_MAC_HANDLER(macchwuo, 0x0C, 0x14);
3214/* machhw - machhw. */
3215GEN_MAC_HANDLER(machhw, 0x0C, 0x01);
3216/* machhwo - machhwo. */
3217GEN_MAC_HANDLER(machhwo, 0x0C, 0x11);
3218/* machhws - machhws. */
3219GEN_MAC_HANDLER(machhws, 0x0C, 0x03);
3220/* machhwso - machhwso. */
3221GEN_MAC_HANDLER(machhwso, 0x0C, 0x13);
3222/* machhwsu - machhwsu. */
3223GEN_MAC_HANDLER(machhwsu, 0x0C, 0x02);
3224/* machhwsuo - machhwsuo. */
3225GEN_MAC_HANDLER(machhwsuo, 0x0C, 0x12);
3226/* machhwu - machhwu. */
3227GEN_MAC_HANDLER(machhwu, 0x0C, 0x00);
3228/* machhwuo - machhwuo. */
3229GEN_MAC_HANDLER(machhwuo, 0x0C, 0x10);
3230/* maclhw - maclhw. */
3231GEN_MAC_HANDLER(maclhw, 0x0C, 0x0D);
3232/* maclhwo - maclhwo. */
3233GEN_MAC_HANDLER(maclhwo, 0x0C, 0x1D);
3234/* maclhws - maclhws. */
3235GEN_MAC_HANDLER(maclhws, 0x0C, 0x0F);
3236/* maclhwso - maclhwso. */
3237GEN_MAC_HANDLER(maclhwso, 0x0C, 0x1F);
3238/* maclhwu - maclhwu. */
3239GEN_MAC_HANDLER(maclhwu, 0x0C, 0x0C);
3240/* maclhwuo - maclhwuo. */
3241GEN_MAC_HANDLER(maclhwuo, 0x0C, 0x1C);
3242/* maclhwsu - maclhwsu. */
3243GEN_MAC_HANDLER(maclhwsu, 0x0C, 0x0E);
3244/* maclhwsuo - maclhwsuo. */
3245GEN_MAC_HANDLER(maclhwsuo, 0x0C, 0x1E);
3246/* nmacchw - nmacchw. */
3247GEN_MAC_HANDLER(nmacchw, 0x0E, 0x05);
3248/* nmacchwo - nmacchwo. */
3249GEN_MAC_HANDLER(nmacchwo, 0x0E, 0x15);
3250/* nmacchws - nmacchws. */
3251GEN_MAC_HANDLER(nmacchws, 0x0E, 0x07);
3252/* nmacchwso - nmacchwso. */
3253GEN_MAC_HANDLER(nmacchwso, 0x0E, 0x17);
3254/* nmachhw - nmachhw. */
3255GEN_MAC_HANDLER(nmachhw, 0x0E, 0x01);
3256/* nmachhwo - nmachhwo. */
3257GEN_MAC_HANDLER(nmachhwo, 0x0E, 0x11);
3258/* nmachhws - nmachhws. */
3259GEN_MAC_HANDLER(nmachhws, 0x0E, 0x03);
3260/* nmachhwso - nmachhwso. */
3261GEN_MAC_HANDLER(nmachhwso, 0x0E, 0x13);
3262/* nmaclhw - nmaclhw. */
3263GEN_MAC_HANDLER(nmaclhw, 0x0E, 0x0D);
3264/* nmaclhwo - nmaclhwo. */
3265GEN_MAC_HANDLER(nmaclhwo, 0x0E, 0x1D);
3266/* nmaclhws - nmaclhws. */
3267GEN_MAC_HANDLER(nmaclhws, 0x0E, 0x0F);
3268/* nmaclhwso - nmaclhwso. */
3269GEN_MAC_HANDLER(nmaclhwso, 0x0E, 0x1F);
3270
3271/* mulchw - mulchw. */
3272GEN_MAC_HANDLER(mulchw, 0x08, 0x05);
3273/* mulchwu - mulchwu. */
3274GEN_MAC_HANDLER(mulchwu, 0x08, 0x04);
3275/* mulhhw - mulhhw. */
3276GEN_MAC_HANDLER(mulhhw, 0x08, 0x01);
3277/* mulhhwu - mulhhwu. */
3278GEN_MAC_HANDLER(mulhhwu, 0x08, 0x00);
3279/* mullhw - mullhw. */
3280GEN_MAC_HANDLER(mullhw, 0x08, 0x0D);
3281/* mullhwu - mullhwu. */
3282GEN_MAC_HANDLER(mullhwu, 0x08, 0x0C);
3283
3284/* mfdcr */
3285GEN_HANDLER(mfdcr, 0x1F, 0x03, 0x0A, 0x00000001, PPC_EMB_COMMON)
3286{
3287#if defined(CONFIG_USER_ONLY)
3288 RET_PRIVREG(ctx);
3289#else
3290 uint32_t dcrn = SPR(ctx->opcode);
3291
3292 if (unlikely(!ctx->supervisor)) {
3293 RET_PRIVREG(ctx);
3294 return;
3295 }
3296 gen_op_4xx_load_dcr(dcrn);
3297 gen_op_store_T0_gpr(rD(ctx->opcode));
3298#endif
3299}
3300
3301/* mtdcr */
3302GEN_HANDLER(mtdcr, 0x1F, 0x03, 0x0E, 0x00000001, PPC_EMB_COMMON)
3303{
3304#if defined(CONFIG_USER_ONLY)
3305 RET_PRIVREG(ctx);
3306#else
3307 uint32_t dcrn = SPR(ctx->opcode);
3308
3309 if (unlikely(!ctx->supervisor)) {
3310 RET_PRIVREG(ctx);
3311 return;
3312 }
3313 gen_op_load_gpr_T0(rS(ctx->opcode));
3314 gen_op_4xx_store_dcr(dcrn);
3315#endif
3316}
3317
3318/* dccci */
3319GEN_HANDLER(dccci, 0x1F, 0x06, 0x0E, 0x03E00001, PPC_4xx_COMMON)
3320{
3321#if defined(CONFIG_USER_ONLY)
3322 RET_PRIVOPC(ctx);
3323#else
3324 if (unlikely(!ctx->supervisor)) {
3325 RET_PRIVOPC(ctx);
3326 return;
3327 }
3328 /* interpreted as no-op */
3329#endif
3330}
3331
3332/* dcread */
3333GEN_HANDLER(dcread, 0x1F, 0x06, 0x0F, 0x00000001, PPC_4xx_COMMON)
3334{
3335#if defined(CONFIG_USER_ONLY)
3336 RET_PRIVOPC(ctx);
3337#else
3338 if (unlikely(!ctx->supervisor)) {
3339 RET_PRIVOPC(ctx);
3340 return;
3341 }
3342 gen_addr_reg_index(ctx);
3343 op_ldst(lwz);
3344 gen_op_store_T0_gpr(rD(ctx->opcode));
3345#endif
3346}
3347
3348/* icbt */
3349GEN_HANDLER(icbt_40x, 0x1F, 0x06, 0x08, 0x03E00001, PPC_40x_SPEC)
3350{
3351 /* interpreted as no-op */
3352 /* XXX: specification say this is treated as a load by the MMU
3353 * but does not generate any exception
3354 */
3355}
3356
3357/* iccci */
3358GEN_HANDLER(iccci, 0x1F, 0x06, 0x1E, 0x00000001, PPC_4xx_COMMON)
3359{
3360#if defined(CONFIG_USER_ONLY)
3361 RET_PRIVOPC(ctx);
3362#else
3363 if (unlikely(!ctx->supervisor)) {
3364 RET_PRIVOPC(ctx);
3365 return;
3366 }
3367 /* interpreted as no-op */
3368#endif
3369}
3370
3371/* icread */
3372GEN_HANDLER(icread, 0x1F, 0x06, 0x1F, 0x03E00001, PPC_4xx_COMMON)
3373{
3374#if defined(CONFIG_USER_ONLY)
3375 RET_PRIVOPC(ctx);
3376#else
3377 if (unlikely(!ctx->supervisor)) {
3378 RET_PRIVOPC(ctx);
3379 return;
3380 }
3381 /* interpreted as no-op */
3382#endif
3383}
3384
3385/* rfci (supervisor only) */
3386GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_EMB_COMMON)
3387{
3388#if defined(CONFIG_USER_ONLY)
3389 RET_PRIVOPC(ctx);
3390#else
3391 if (unlikely(!ctx->supervisor)) {
3392 RET_PRIVOPC(ctx);
3393 return;
3394 }
3395 /* Restore CPU state */
3396 gen_op_4xx_rfci();
3397 RET_CHG_FLOW(ctx);
3398#endif
3399}
3400
3401/* tlbre */
3402GEN_HANDLER(tlbre, 0x1F, 0x12, 0x1D, 0x00000001, PPC_EMB_COMMON)
3403{
3404#if defined(CONFIG_USER_ONLY)
3405 RET_PRIVOPC(ctx);
3406#else
3407 if (unlikely(!ctx->supervisor)) {
3408 RET_PRIVOPC(ctx);
3409 return;
3410 }
3411 switch (rB(ctx->opcode)) {
3412 case 0:
9a64fbe4 3413 gen_op_load_gpr_T0(rA(ctx->opcode));
76a66253
JM
3414 gen_op_4xx_tlbre_hi();
3415 gen_op_store_T0_gpr(rD(ctx->opcode));
3416 break;
3417 case 1:
3418 gen_op_load_gpr_T0(rA(ctx->opcode));
3419 gen_op_4xx_tlbre_lo();
3420 gen_op_store_T0_gpr(rD(ctx->opcode));
3421 break;
3422 default:
3423 RET_INVAL(ctx);
3424 break;
9a64fbe4 3425 }
76a66253
JM
3426#endif
3427}
3428
3429/* tlbsx - tlbsx. */ /* Named tlbs in BookE */
3430GEN_HANDLER(tlbsx, 0x1F, 0x12, 0x1C, 0x00000000, PPC_EMB_COMMON)
3431{
3432#if defined(CONFIG_USER_ONLY)
3433 RET_PRIVOPC(ctx);
3434#else
3435 if (unlikely(!ctx->supervisor)) {
3436 RET_PRIVOPC(ctx);
3437 return;
3438 }
3439 gen_addr_reg_index(ctx);
3440 if (Rc(ctx->opcode))
3441 gen_op_4xx_tlbsx_();
3442 else
3443 gen_op_4xx_tlbsx();
9a64fbe4 3444 gen_op_store_T0_gpr(rD(ctx->opcode));
76a66253 3445#endif
79aceca5
FB
3446}
3447
76a66253
JM
3448/* tlbwe */
3449GEN_HANDLER(tlbwe, 0x1F, 0x12, 0x1E, 0x00000001, PPC_EMB_COMMON)
79aceca5 3450{
76a66253
JM
3451#if defined(CONFIG_USER_ONLY)
3452 RET_PRIVOPC(ctx);
3453#else
3454 if (unlikely(!ctx->supervisor)) {
3455 RET_PRIVOPC(ctx);
3456 return;
3457 }
3458 switch (rB(ctx->opcode)) {
3459 case 0:
9a64fbe4 3460 gen_op_load_gpr_T0(rA(ctx->opcode));
76a66253
JM
3461 gen_op_load_gpr_T1(rS(ctx->opcode));
3462 gen_op_4xx_tlbwe_hi();
3463 break;
3464 case 1:
3465 gen_op_load_gpr_T0(rA(ctx->opcode));
3466 gen_op_load_gpr_T1(rS(ctx->opcode));
3467 gen_op_4xx_tlbwe_lo();
3468 break;
3469 default:
3470 RET_INVAL(ctx);
3471 break;
9a64fbe4 3472 }
76a66253
JM
3473#endif
3474}
3475
3476/* wrtee */
3477GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_EMB_COMMON)
3478{
3479#if defined(CONFIG_USER_ONLY)
3480 RET_PRIVOPC(ctx);
3481#else
3482 if (unlikely(!ctx->supervisor)) {
3483 RET_PRIVOPC(ctx);
3484 return;
3485 }
3486 gen_op_load_gpr_T0(rD(ctx->opcode));
3487 gen_op_4xx_wrte();
3488 RET_EXCP(ctx, EXCP_MTMSR, 0);
3489#endif
3490}
3491
3492/* wrteei */
3493GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000EFC01, PPC_EMB_COMMON)
3494{
3495#if defined(CONFIG_USER_ONLY)
3496 RET_PRIVOPC(ctx);
3497#else
3498 if (unlikely(!ctx->supervisor)) {
3499 RET_PRIVOPC(ctx);
3500 return;
3501 }
3502 gen_op_set_T0(ctx->opcode & 0x00010000);
3503 gen_op_4xx_wrte();
3504 RET_EXCP(ctx, EXCP_MTMSR, 0);
3505#endif
3506}
3507
3508/* PPC 440 specific instructions */
3509/* dlmzb */
3510GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC)
3511{
3512 gen_op_load_gpr_T0(rS(ctx->opcode));
3513 gen_op_load_gpr_T1(rB(ctx->opcode));
3514 gen_op_440_dlmzb();
3515 gen_op_store_T0_gpr(rA(ctx->opcode));
3516 gen_op_store_xer_bc();
3517 if (Rc(ctx->opcode)) {
3518 gen_op_440_dlmzb_update_Rc();
3519 gen_op_store_T0_crf(0);
3520 }
3521}
3522
3523/* mbar replaces eieio on 440 */
3524GEN_HANDLER(mbar, 0x1F, 0x16, 0x13, 0x001FF801, PPC_BOOKE)
3525{
3526 /* interpreted as no-op */
3527}
3528
3529/* msync replaces sync on 440 */
3530GEN_HANDLER(msync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_BOOKE)
3531{
3532 /* interpreted as no-op */
3533}
3534
3535/* icbt */
3536GEN_HANDLER(icbt_440, 0x1F, 0x16, 0x00, 0x03E00001, PPC_BOOKE)
3537{
3538 /* interpreted as no-op */
3539 /* XXX: specification say this is treated as a load by the MMU
3540 * but does not generate any exception
3541 */
79aceca5
FB
3542}
3543
3544/* End opcode list */
3545GEN_OPCODE_MARK(end);
3546
3fc6c082 3547#include "translate_init.c"
79aceca5 3548
9a64fbe4 3549/*****************************************************************************/
3fc6c082 3550/* Misc PowerPC helpers */
76a66253
JM
3551static inline uint32_t load_xer (CPUState *env)
3552{
3553 return (xer_so << XER_SO) |
3554 (xer_ov << XER_OV) |
3555 (xer_ca << XER_CA) |
3556 (xer_bc << XER_BC) |
3557 (xer_cmp << XER_CMP);
3558}
3559
7fe48483
FB
3560void cpu_dump_state(CPUState *env, FILE *f,
3561 int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
3562 int flags)
79aceca5 3563{
3fc6c082
FB
3564#if defined(TARGET_PPC64) || 1
3565#define FILL ""
3fc6c082
FB
3566#define RGPL 4
3567#define RFPL 4
3568#else
3569#define FILL " "
3fc6c082
FB
3570#define RGPL 8
3571#define RFPL 4
3572#endif
3573
79aceca5
FB
3574 int i;
3575
3fc6c082
FB
3576 cpu_fprintf(f, "NIP " REGX " LR " REGX " CTR " REGX "\n",
3577 env->nip, env->lr, env->ctr);
76a66253
JM
3578 cpu_fprintf(f, "MSR " REGX FILL " XER %08x TB %08x %08x "
3579#if !defined(CONFIG_USER_ONLY)
3580 "DECR %08x"
3581#endif
3582 "\n",
3583 do_load_msr(env), load_xer(env), cpu_ppc_load_tbu(env),
3584 cpu_ppc_load_tbl(env)
3585#if !defined(CONFIG_USER_ONLY)
3586 , cpu_ppc_load_decr(env)
3587#endif
3588 );
3589 for (i = 0; i < 32; i++) {
3fc6c082
FB
3590 if ((i & (RGPL - 1)) == 0)
3591 cpu_fprintf(f, "GPR%02d", i);
3592 cpu_fprintf(f, " " REGX, env->gpr[i]);
3593 if ((i & (RGPL - 1)) == (RGPL - 1))
7fe48483 3594 cpu_fprintf(f, "\n");
76a66253 3595 }
3fc6c082 3596 cpu_fprintf(f, "CR ");
76a66253 3597 for (i = 0; i < 8; i++)
7fe48483
FB
3598 cpu_fprintf(f, "%01x", env->crf[i]);
3599 cpu_fprintf(f, " [");
76a66253
JM
3600 for (i = 0; i < 8; i++) {
3601 char a = '-';
3602 if (env->crf[i] & 0x08)
3603 a = 'L';
3604 else if (env->crf[i] & 0x04)
3605 a = 'G';
3606 else if (env->crf[i] & 0x02)
3607 a = 'E';
7fe48483 3608 cpu_fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' ');
76a66253 3609 }
3fc6c082
FB
3610 cpu_fprintf(f, " ] " FILL "RES " REGX "\n", env->reserve);
3611 for (i = 0; i < 32; i++) {
3612 if ((i & (RFPL - 1)) == 0)
3613 cpu_fprintf(f, "FPR%02d", i);
26a76461 3614 cpu_fprintf(f, " %016" PRIx64, *((uint64_t *)&env->fpr[i]));
3fc6c082 3615 if ((i & (RFPL - 1)) == (RFPL - 1))
7fe48483 3616 cpu_fprintf(f, "\n");
79aceca5 3617 }
3fc6c082
FB
3618 cpu_fprintf(f, "SRR0 " REGX " SRR1 " REGX " " FILL FILL FILL
3619 "SDR1 " REGX "\n",
3620 env->spr[SPR_SRR0], env->spr[SPR_SRR1], env->sdr1);
79aceca5 3621
3fc6c082
FB
3622#undef REGX
3623#undef RGPL
3624#undef RFPL
3625#undef FILL
79aceca5
FB
3626}
3627
76a66253
JM
3628void cpu_dump_statistics (CPUState *env, FILE*f,
3629 int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
3630 int flags)
3631{
3632#if defined(DO_PPC_STATISTICS)
3633 opc_handler_t **t1, **t2, **t3, *handler;
3634 int op1, op2, op3;
3635
3636 t1 = env->opcodes;
3637 for (op1 = 0; op1 < 64; op1++) {
3638 handler = t1[op1];
3639 if (is_indirect_opcode(handler)) {
3640 t2 = ind_table(handler);
3641 for (op2 = 0; op2 < 32; op2++) {
3642 handler = t2[op2];
3643 if (is_indirect_opcode(handler)) {
3644 t3 = ind_table(handler);
3645 for (op3 = 0; op3 < 32; op3++) {
3646 handler = t3[op3];
3647 if (handler->count == 0)
3648 continue;
3649 cpu_fprintf(f, "%02x %02x %02x (%02x %04d) %16s: "
3650 "%016llx %lld\n",
3651 op1, op2, op3, op1, (op3 << 5) | op2,
3652 handler->oname,
3653 handler->count, handler->count);
3654 }
3655 } else {
3656 if (handler->count == 0)
3657 continue;
3658 cpu_fprintf(f, "%02x %02x (%02x %04d) %16s: "
3659 "%016llx %lld\n",
3660 op1, op2, op1, op2, handler->oname,
3661 handler->count, handler->count);
3662 }
3663 }
3664 } else {
3665 if (handler->count == 0)
3666 continue;
3667 cpu_fprintf(f, "%02x (%02x ) %16s: %016llx %lld\n",
3668 op1, op1, handler->oname,
3669 handler->count, handler->count);
3670 }
3671 }
3672#endif
3673}
3674
9a64fbe4 3675/*****************************************************************************/
79aceca5
FB
3676int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
3677 int search_pc)
3678{
9fddaa0c 3679 DisasContext ctx, *ctxp = &ctx;
79aceca5 3680 opc_handler_t **table, *handler;
0fa85d43 3681 target_ulong pc_start;
79aceca5
FB
3682 uint16_t *gen_opc_end;
3683 int j, lj = -1;
79aceca5
FB
3684
3685 pc_start = tb->pc;
3686 gen_opc_ptr = gen_opc_buf;
3687 gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
3688 gen_opparam_ptr = gen_opparam_buf;
c53be334 3689 nb_gen_labels = 0;
046d6672 3690 ctx.nip = pc_start;
79aceca5 3691 ctx.tb = tb;
9a64fbe4 3692 ctx.exception = EXCP_NONE;
3fc6c082 3693 ctx.spr_cb = env->spr_cb;
9a64fbe4 3694#if defined(CONFIG_USER_ONLY)
111bfab3 3695 ctx.mem_idx = msr_le;
9a64fbe4
FB
3696#else
3697 ctx.supervisor = 1 - msr_pr;
111bfab3 3698 ctx.mem_idx = ((1 - msr_pr) << 1) | msr_le;
9a64fbe4 3699#endif
3cc62370 3700 ctx.fpu_enabled = msr_fp;
ea4e754f 3701 ctx.singlestep_enabled = env->singlestep_enabled;
3fc6c082 3702#if defined (DO_SINGLE_STEP) && 0
9a64fbe4
FB
3703 /* Single step trace mode */
3704 msr_se = 1;
3705#endif
3706 /* Set env in case of segfault during code fetch */
3707 while (ctx.exception == EXCP_NONE && gen_opc_ptr < gen_opc_end) {
76a66253
JM
3708 if (unlikely(env->nb_breakpoints > 0)) {
3709 for (j = 0; j < env->nb_breakpoints; j++) {
ea4e754f
FB
3710 if (env->breakpoints[j] == ctx.nip) {
3711 gen_op_update_nip(ctx.nip);
3712 gen_op_debug();
3713 break;
3714 }
3715 }
3716 }
76a66253 3717 if (unlikely(search_pc)) {
79aceca5
FB
3718 j = gen_opc_ptr - gen_opc_buf;
3719 if (lj < j) {
3720 lj++;
3721 while (lj < j)
3722 gen_opc_instr_start[lj++] = 0;
046d6672 3723 gen_opc_pc[lj] = ctx.nip;
79aceca5
FB
3724 gen_opc_instr_start[lj] = 1;
3725 }
3726 }
9fddaa0c
FB
3727#if defined PPC_DEBUG_DISAS
3728 if (loglevel & CPU_LOG_TB_IN_ASM) {
79aceca5 3729 fprintf(logfile, "----------------\n");
046d6672 3730 fprintf(logfile, "nip=%08x super=%d ir=%d\n",
9a64fbe4
FB
3731 ctx.nip, 1 - msr_pr, msr_ir);
3732 }
3733#endif
0fa85d43 3734 ctx.opcode = ldl_code(ctx.nip);
111bfab3
FB
3735 if (msr_le) {
3736 ctx.opcode = ((ctx.opcode & 0xFF000000) >> 24) |
3737 ((ctx.opcode & 0x00FF0000) >> 8) |
3738 ((ctx.opcode & 0x0000FF00) << 8) |
3739 ((ctx.opcode & 0x000000FF) << 24);
3740 }
9fddaa0c
FB
3741#if defined PPC_DEBUG_DISAS
3742 if (loglevel & CPU_LOG_TB_IN_ASM) {
111bfab3 3743 fprintf(logfile, "translate opcode %08x (%02x %02x %02x) (%s)\n",
9a64fbe4 3744 ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode),
111bfab3 3745 opc3(ctx.opcode), msr_le ? "little" : "big");
79aceca5
FB
3746 }
3747#endif
046d6672 3748 ctx.nip += 4;
3fc6c082 3749 table = env->opcodes;
79aceca5
FB
3750 handler = table[opc1(ctx.opcode)];
3751 if (is_indirect_opcode(handler)) {
3752 table = ind_table(handler);
3753 handler = table[opc2(ctx.opcode)];
3754 if (is_indirect_opcode(handler)) {
3755 table = ind_table(handler);
3756 handler = table[opc3(ctx.opcode)];
3757 }
3758 }
3759 /* Is opcode *REALLY* valid ? */
76a66253 3760 if (unlikely(handler->handler == &gen_invalid)) {
4b3686fa 3761 if (loglevel > 0) {
76a66253 3762 fprintf(logfile, "invalid/unsupported opcode: "
4b3686fa 3763 "%02x - %02x - %02x (%08x) 0x%08x %d\n",
76a66253 3764 opc1(ctx.opcode), opc2(ctx.opcode),
4b3686fa
FB
3765 opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir);
3766 } else {
3767 printf("invalid/unsupported opcode: "
3768 "%02x - %02x - %02x (%08x) 0x%08x %d\n",
3769 opc1(ctx.opcode), opc2(ctx.opcode),
3770 opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir);
3771 }
76a66253
JM
3772 } else {
3773 if (unlikely((ctx.opcode & handler->inval) != 0)) {
4b3686fa 3774 if (loglevel > 0) {
79aceca5 3775 fprintf(logfile, "invalid bits: %08x for opcode: "
046d6672 3776 "%02x -%02x - %02x (0x%08x) (0x%08x)\n",
79aceca5
FB
3777 ctx.opcode & handler->inval, opc1(ctx.opcode),
3778 opc2(ctx.opcode), opc3(ctx.opcode),
046d6672 3779 ctx.opcode, ctx.nip - 4);
9a64fbe4
FB
3780 } else {
3781 printf("invalid bits: %08x for opcode: "
046d6672 3782 "%02x -%02x - %02x (0x%08x) (0x%08x)\n",
76a66253
JM
3783 ctx.opcode & handler->inval, opc1(ctx.opcode),
3784 opc2(ctx.opcode), opc3(ctx.opcode),
046d6672 3785 ctx.opcode, ctx.nip - 4);
76a66253 3786 }
4b3686fa
FB
3787 RET_INVAL(ctxp);
3788 break;
79aceca5 3789 }
79aceca5 3790 }
4b3686fa 3791 (*(handler->handler))(&ctx);
76a66253
JM
3792#if defined(DO_PPC_STATISTICS)
3793 handler->count++;
3794#endif
9a64fbe4 3795 /* Check trace mode exceptions */
76a66253
JM
3796 if (unlikely((msr_be && ctx.exception == EXCP_BRANCH) ||
3797 /* Check in single step trace mode
3798 * we need to stop except if:
3799 * - rfi, trap or syscall
3800 * - first instruction of an exception handler
3801 */
3802 (msr_se && (ctx.nip < 0x100 ||
3803 ctx.nip > 0xF00 ||
3804 (ctx.nip & 0xFC) != 0x04) &&
3805 ctx.exception != EXCP_SYSCALL &&
3806 ctx.exception != EXCP_SYSCALL_USER &&
3807 ctx.exception != EXCP_TRAP))) {
9fddaa0c 3808 RET_EXCP(ctxp, EXCP_TRACE, 0);
9a64fbe4 3809 }
ea4e754f
FB
3810 /* if we reach a page boundary or are single stepping, stop
3811 * generation
3812 */
76a66253
JM
3813 if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) ||
3814 (env->singlestep_enabled))) {
8dd4983c 3815 break;
76a66253 3816 }
3fc6c082
FB
3817#if defined (DO_SINGLE_STEP)
3818 break;
3819#endif
3820 }
9fddaa0c 3821 if (ctx.exception == EXCP_NONE) {
c1942362 3822 gen_goto_tb(&ctx, 0, ctx.nip);
9fddaa0c 3823 } else if (ctx.exception != EXCP_BRANCH) {
76a66253
JM
3824 gen_op_reset_T0();
3825 /* Generate the return instruction */
3826 gen_op_exit_tb();
9a64fbe4 3827 }
79aceca5 3828 *gen_opc_ptr = INDEX_op_end;
76a66253 3829 if (unlikely(search_pc)) {
9a64fbe4
FB
3830 j = gen_opc_ptr - gen_opc_buf;
3831 lj++;
3832 while (lj <= j)
3833 gen_opc_instr_start[lj++] = 0;
79aceca5 3834 tb->size = 0;
9a64fbe4 3835 } else {
046d6672 3836 tb->size = ctx.nip - pc_start;
9a64fbe4 3837 }
79aceca5 3838#ifdef DEBUG_DISAS
9fddaa0c 3839 if (loglevel & CPU_LOG_TB_CPU) {
9a64fbe4 3840 fprintf(logfile, "---------------- excp: %04x\n", ctx.exception);
7fe48483 3841 cpu_dump_state(env, logfile, fprintf, 0);
9fddaa0c
FB
3842 }
3843 if (loglevel & CPU_LOG_TB_IN_ASM) {
76a66253
JM
3844 int flags;
3845 flags = msr_le;
0fa85d43 3846 fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
76a66253 3847 target_disas(logfile, pc_start, ctx.nip - pc_start, flags);
79aceca5 3848 fprintf(logfile, "\n");
9fddaa0c
FB
3849 }
3850 if (loglevel & CPU_LOG_TB_OP) {
79aceca5
FB
3851 fprintf(logfile, "OP:\n");
3852 dump_ops(gen_opc_buf, gen_opparam_buf);
3853 fprintf(logfile, "\n");
3854 }
3855#endif
79aceca5
FB
3856 return 0;
3857}
3858
9a64fbe4 3859int gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
79aceca5
FB
3860{
3861 return gen_intermediate_code_internal(env, tb, 0);
3862}
3863
9a64fbe4 3864int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
79aceca5
FB
3865{
3866 return gen_intermediate_code_internal(env, tb, 1);
3867}