]> git.proxmox.com Git - qemu.git/blame - target-ppc/translate.c
comment
[qemu.git] / target-ppc / translate.c
CommitLineData
79aceca5
FB
1/*
2 * PPC emulation for qemu: main translation routines.
3 *
4 * Copyright (c) 2003 Jocelyn Mayer
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
79aceca5
FB
32
33enum {
34#define DEF(s, n, copy_size) INDEX_op_ ## s,
35#include "opc.h"
36#undef DEF
37 NB_OPS,
38};
39
40static uint16_t *gen_opc_ptr;
41static uint32_t *gen_opparam_ptr;
42
43#include "gen-op.h"
28b6751f 44
28b6751f 45#define GEN8(func, NAME) \
9a64fbe4
FB
46static GenOpFunc *NAME ## _table [8] = { \
47NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \
48NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \
49}; \
50static inline void func(int n) \
51{ \
52 NAME ## _table[n](); \
53}
54
55#define GEN16(func, NAME) \
56static GenOpFunc *NAME ## _table [16] = { \
57NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \
58NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \
59NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \
60NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \
61}; \
62static inline void func(int n) \
63{ \
64 NAME ## _table[n](); \
28b6751f
FB
65}
66
67#define GEN32(func, NAME) \
9a64fbe4
FB
68static GenOpFunc *NAME ## _table [32] = { \
69NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \
70NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \
71NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \
72NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \
73NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \
74NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \
75NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \
76NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \
77}; \
78static inline void func(int n) \
79{ \
80 NAME ## _table[n](); \
81}
82
83/* Condition register moves */
84GEN8(gen_op_load_crf_T0, gen_op_load_crf_T0_crf);
85GEN8(gen_op_load_crf_T1, gen_op_load_crf_T1_crf);
86GEN8(gen_op_store_T0_crf, gen_op_store_T0_crf_crf);
87GEN8(gen_op_store_T1_crf, gen_op_store_T1_crf_crf);
28b6751f 88
fb0eaffc
FB
89/* Floating point condition and status register moves */
90GEN8(gen_op_load_fpscr_T0, gen_op_load_fpscr_T0_fpscr);
91GEN8(gen_op_store_T0_fpscr, gen_op_store_T0_fpscr_fpscr);
92GEN8(gen_op_clear_fpscr, gen_op_clear_fpscr_fpscr);
93static GenOpFunc1 *gen_op_store_T0_fpscri_fpscr_table[8] = {
94 &gen_op_store_T0_fpscri_fpscr0,
95 &gen_op_store_T0_fpscri_fpscr1,
96 &gen_op_store_T0_fpscri_fpscr2,
97 &gen_op_store_T0_fpscri_fpscr3,
98 &gen_op_store_T0_fpscri_fpscr4,
99 &gen_op_store_T0_fpscri_fpscr5,
100 &gen_op_store_T0_fpscri_fpscr6,
101 &gen_op_store_T0_fpscri_fpscr7,
102};
103static inline void gen_op_store_T0_fpscri(int n, uint8_t param)
104{
105 (*gen_op_store_T0_fpscri_fpscr_table[n])(param);
106}
107
9a64fbe4
FB
108/* Segment register moves */
109GEN16(gen_op_load_sr, gen_op_load_sr);
110GEN16(gen_op_store_sr, gen_op_store_sr);
28b6751f 111
9a64fbe4
FB
112/* General purpose registers moves */
113GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr);
114GEN32(gen_op_load_gpr_T1, gen_op_load_gpr_T1_gpr);
115GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr);
116
117GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr);
118GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr);
119GEN32(gen_op_store_T2_gpr, gen_op_store_T2_gpr_gpr);
28b6751f 120
fb0eaffc
FB
121/* floating point registers moves */
122GEN32(gen_op_load_fpr_FT0, gen_op_load_fpr_FT0_fpr);
123GEN32(gen_op_load_fpr_FT1, gen_op_load_fpr_FT1_fpr);
124GEN32(gen_op_load_fpr_FT2, gen_op_load_fpr_FT2_fpr);
125GEN32(gen_op_store_FT0_fpr, gen_op_store_FT0_fpr_fpr);
126GEN32(gen_op_store_FT1_fpr, gen_op_store_FT1_fpr_fpr);
127GEN32(gen_op_store_FT2_fpr, gen_op_store_FT2_fpr_fpr);
79aceca5
FB
128
129static uint8_t spr_access[1024 / 2];
130
131/* internal defines */
132typedef struct DisasContext {
133 struct TranslationBlock *tb;
046d6672 134 uint32_t nip;
79aceca5 135 uint32_t opcode;
9a64fbe4 136 uint32_t exception;
9a64fbe4
FB
137 /* Execution mode */
138#if !defined(CONFIG_USER_ONLY)
79aceca5 139 int supervisor;
9a64fbe4
FB
140#endif
141 /* Routine used to access memory */
142 int mem_idx;
79aceca5
FB
143} DisasContext;
144
145typedef struct opc_handler_t {
146 /* invalid bits */
147 uint32_t inval;
9a64fbe4
FB
148 /* instruction type */
149 uint32_t type;
79aceca5
FB
150 /* handler */
151 void (*handler)(DisasContext *ctx);
152} opc_handler_t;
153
9fddaa0c 154#define RET_EXCP(ctx, excp, error) \
79aceca5 155do { \
9fddaa0c
FB
156 if ((ctx)->exception == EXCP_NONE) { \
157 gen_op_update_nip((ctx)->nip); \
158 } \
159 gen_op_raise_exception_err((excp), (error)); \
160 ctx->exception = (excp); \
79aceca5
FB
161} while (0)
162
9fddaa0c
FB
163#define RET_INVAL(ctx) \
164RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL)
165
166#define RET_PRIVOPC(ctx) \
167RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_OPC)
9a64fbe4 168
9fddaa0c
FB
169#define RET_PRIVREG(ctx) \
170RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG)
9a64fbe4 171
9fddaa0c
FB
172#define RET_MTMSR(ctx) \
173RET_EXCP((ctx), EXCP_MTMSR, 0)
79aceca5
FB
174
175#define GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \
176static void gen_##name (DisasContext *ctx); \
177GEN_OPCODE(name, opc1, opc2, opc3, inval, type); \
178static void gen_##name (DisasContext *ctx)
179
79aceca5
FB
180typedef struct opcode_t {
181 unsigned char opc1, opc2, opc3;
79aceca5
FB
182 opc_handler_t handler;
183} opcode_t;
184
79aceca5
FB
185/*** Instruction decoding ***/
186#define EXTRACT_HELPER(name, shift, nb) \
187static inline uint32_t name (uint32_t opcode) \
188{ \
189 return (opcode >> (shift)) & ((1 << (nb)) - 1); \
190}
191
192#define EXTRACT_SHELPER(name, shift, nb) \
193static inline int32_t name (uint32_t opcode) \
194{ \
195 return s_ext16((opcode >> (shift)) & ((1 << (nb)) - 1)); \
196}
197
198/* Opcode part 1 */
199EXTRACT_HELPER(opc1, 26, 6);
200/* Opcode part 2 */
201EXTRACT_HELPER(opc2, 1, 5);
202/* Opcode part 3 */
203EXTRACT_HELPER(opc3, 6, 5);
204/* Update Cr0 flags */
205EXTRACT_HELPER(Rc, 0, 1);
206/* Destination */
207EXTRACT_HELPER(rD, 21, 5);
208/* Source */
209EXTRACT_HELPER(rS, 21, 5);
210/* First operand */
211EXTRACT_HELPER(rA, 16, 5);
212/* Second operand */
213EXTRACT_HELPER(rB, 11, 5);
214/* Third operand */
215EXTRACT_HELPER(rC, 6, 5);
216/*** Get CRn ***/
217EXTRACT_HELPER(crfD, 23, 3);
218EXTRACT_HELPER(crfS, 18, 3);
219EXTRACT_HELPER(crbD, 21, 5);
220EXTRACT_HELPER(crbA, 16, 5);
221EXTRACT_HELPER(crbB, 11, 5);
222/* SPR / TBL */
223EXTRACT_HELPER(SPR, 11, 10);
224/*** Get constants ***/
225EXTRACT_HELPER(IMM, 12, 8);
226/* 16 bits signed immediate value */
227EXTRACT_SHELPER(SIMM, 0, 16);
228/* 16 bits unsigned immediate value */
229EXTRACT_HELPER(UIMM, 0, 16);
230/* Bit count */
231EXTRACT_HELPER(NB, 11, 5);
232/* Shift count */
233EXTRACT_HELPER(SH, 11, 5);
234/* Mask start */
235EXTRACT_HELPER(MB, 6, 5);
236/* Mask end */
237EXTRACT_HELPER(ME, 1, 5);
fb0eaffc
FB
238/* Trap operand */
239EXTRACT_HELPER(TO, 21, 5);
79aceca5
FB
240
241EXTRACT_HELPER(CRM, 12, 8);
242EXTRACT_HELPER(FM, 17, 8);
243EXTRACT_HELPER(SR, 16, 4);
fb0eaffc
FB
244EXTRACT_HELPER(FPIMM, 20, 4);
245
79aceca5
FB
246/*** Jump target decoding ***/
247/* Displacement */
248EXTRACT_SHELPER(d, 0, 16);
249/* Immediate address */
250static inline uint32_t LI (uint32_t opcode)
251{
252 return (opcode >> 0) & 0x03FFFFFC;
253}
254
255static inline uint32_t BD (uint32_t opcode)
256{
257 return (opcode >> 0) & 0xFFFC;
258}
259
260EXTRACT_HELPER(BO, 21, 5);
261EXTRACT_HELPER(BI, 16, 5);
262/* Absolute/relative address */
263EXTRACT_HELPER(AA, 1, 1);
264/* Link */
265EXTRACT_HELPER(LK, 0, 1);
266
267/* Create a mask between <start> and <end> bits */
268static inline uint32_t MASK (uint32_t start, uint32_t end)
269{
270 uint32_t ret;
271
272 ret = (((uint32_t)(-1)) >> (start)) ^ (((uint32_t)(-1) >> (end)) >> 1);
273 if (start > end)
274 return ~ret;
275
276 return ret;
277}
278
279#define GEN_OPCODE(name, op1, op2, op3, invl, _typ) \
1ef59d0a 280__attribute__ ((section(".opcodes"), unused, aligned (8) )) \
79aceca5
FB
281static opcode_t opc_##name = { \
282 .opc1 = op1, \
283 .opc2 = op2, \
284 .opc3 = op3, \
79aceca5
FB
285 .handler = { \
286 .inval = invl, \
9a64fbe4 287 .type = _typ, \
79aceca5
FB
288 .handler = &gen_##name, \
289 }, \
290}
291
292#define GEN_OPCODE_MARK(name) \
1ef59d0a 293__attribute__ ((section(".opcodes"), unused, aligned (8) )) \
79aceca5
FB
294static opcode_t opc_##name = { \
295 .opc1 = 0xFF, \
296 .opc2 = 0xFF, \
297 .opc3 = 0xFF, \
79aceca5
FB
298 .handler = { \
299 .inval = 0x00000000, \
9a64fbe4 300 .type = 0x00, \
79aceca5
FB
301 .handler = NULL, \
302 }, \
303}
304
305/* Start opcode list */
306GEN_OPCODE_MARK(start);
307
308/* Invalid instruction */
9a64fbe4
FB
309GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE)
310{
9fddaa0c 311 RET_INVAL(ctx);
9a64fbe4
FB
312}
313
314/* Special opcode to stop emulation */
315GEN_HANDLER(stop, 0x06, 0x00, 0xFF, 0x03FFFFC1, PPC_COMMON)
79aceca5 316{
9fddaa0c 317 RET_EXCP(ctx, EXCP_HLT, 0);
9a64fbe4
FB
318}
319
320/* Special opcode to call open-firmware */
321GEN_HANDLER(of_enter, 0x06, 0x01, 0xFF, 0x03FFFFC1, PPC_COMMON)
322{
9fddaa0c 323 RET_EXCP(ctx, EXCP_OFCALL, 0);
9a64fbe4
FB
324}
325
326/* Special opcode to call RTAS */
327GEN_HANDLER(rtas_enter, 0x06, 0x02, 0xFF, 0x03FFFFC1, PPC_COMMON)
328{
329 printf("RTAS entry point !\n");
9fddaa0c 330 RET_EXCP(ctx, EXCP_RTASCALL, 0);
79aceca5
FB
331}
332
333static opc_handler_t invalid_handler = {
334 .inval = 0xFFFFFFFF,
9a64fbe4 335 .type = PPC_NONE,
79aceca5
FB
336 .handler = gen_invalid,
337};
338
339/*** Integer arithmetic ***/
340#define __GEN_INT_ARITH2(name, opc1, opc2, opc3, inval) \
341GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER) \
342{ \
343 gen_op_load_gpr_T0(rA(ctx->opcode)); \
344 gen_op_load_gpr_T1(rB(ctx->opcode)); \
345 gen_op_##name(); \
346 if (Rc(ctx->opcode) != 0) \
347 gen_op_set_Rc0(); \
348 gen_op_store_T0_gpr(rD(ctx->opcode)); \
79aceca5
FB
349}
350
351#define __GEN_INT_ARITH2_O(name, opc1, opc2, opc3, inval) \
352GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER) \
353{ \
354 gen_op_load_gpr_T0(rA(ctx->opcode)); \
355 gen_op_load_gpr_T1(rB(ctx->opcode)); \
356 gen_op_##name(); \
357 if (Rc(ctx->opcode) != 0) \
358 gen_op_set_Rc0_ov(); \
359 gen_op_store_T0_gpr(rD(ctx->opcode)); \
79aceca5
FB
360}
361
362#define __GEN_INT_ARITH1(name, opc1, opc2, opc3) \
363GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER) \
364{ \
365 gen_op_load_gpr_T0(rA(ctx->opcode)); \
366 gen_op_##name(); \
367 if (Rc(ctx->opcode) != 0) \
368 gen_op_set_Rc0(); \
369 gen_op_store_T0_gpr(rD(ctx->opcode)); \
79aceca5
FB
370}
371#define __GEN_INT_ARITH1_O(name, opc1, opc2, opc3) \
372GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER) \
373{ \
374 gen_op_load_gpr_T0(rA(ctx->opcode)); \
375 gen_op_##name(); \
376 if (Rc(ctx->opcode) != 0) \
377 gen_op_set_Rc0_ov(); \
378 gen_op_store_T0_gpr(rD(ctx->opcode)); \
79aceca5
FB
379}
380
381/* Two operands arithmetic functions */
382#define GEN_INT_ARITH2(name, opc1, opc2, opc3) \
383__GEN_INT_ARITH2(name, opc1, opc2, opc3, 0x00000000) \
384__GEN_INT_ARITH2_O(name##o, opc1, opc2, opc3 | 0x10, 0x00000000)
385
386/* Two operands arithmetic functions with no overflow allowed */
387#define GEN_INT_ARITHN(name, opc1, opc2, opc3) \
388__GEN_INT_ARITH2(name, opc1, opc2, opc3, 0x00000400)
389
390/* One operand arithmetic functions */
391#define GEN_INT_ARITH1(name, opc1, opc2, opc3) \
392__GEN_INT_ARITH1(name, opc1, opc2, opc3) \
393__GEN_INT_ARITH1_O(name##o, opc1, opc2, opc3 | 0x10)
394
395/* add add. addo addo. */
396GEN_INT_ARITH2 (add, 0x1F, 0x0A, 0x08);
397/* addc addc. addco addco. */
398GEN_INT_ARITH2 (addc, 0x1F, 0x0A, 0x00);
399/* adde adde. addeo addeo. */
400GEN_INT_ARITH2 (adde, 0x1F, 0x0A, 0x04);
401/* addme addme. addmeo addmeo. */
402GEN_INT_ARITH1 (addme, 0x1F, 0x0A, 0x07);
403/* addze addze. addzeo addzeo. */
404GEN_INT_ARITH1 (addze, 0x1F, 0x0A, 0x06);
405/* divw divw. divwo divwo. */
406GEN_INT_ARITH2 (divw, 0x1F, 0x0B, 0x0F);
407/* divwu divwu. divwuo divwuo. */
408GEN_INT_ARITH2 (divwu, 0x1F, 0x0B, 0x0E);
409/* mulhw mulhw. */
410GEN_INT_ARITHN (mulhw, 0x1F, 0x0B, 0x02);
411/* mulhwu mulhwu. */
412GEN_INT_ARITHN (mulhwu, 0x1F, 0x0B, 0x00);
413/* mullw mullw. mullwo mullwo. */
414GEN_INT_ARITH2 (mullw, 0x1F, 0x0B, 0x07);
415/* neg neg. nego nego. */
416GEN_INT_ARITH1 (neg, 0x1F, 0x08, 0x03);
417/* subf subf. subfo subfo. */
418GEN_INT_ARITH2 (subf, 0x1F, 0x08, 0x01);
419/* subfc subfc. subfco subfco. */
420GEN_INT_ARITH2 (subfc, 0x1F, 0x08, 0x00);
421/* subfe subfe. subfeo subfeo. */
422GEN_INT_ARITH2 (subfe, 0x1F, 0x08, 0x04);
423/* subfme subfme. subfmeo subfmeo. */
424GEN_INT_ARITH1 (subfme, 0x1F, 0x08, 0x07);
425/* subfze subfze. subfzeo subfzeo. */
426GEN_INT_ARITH1 (subfze, 0x1F, 0x08, 0x06);
427/* addi */
428GEN_HANDLER(addi, 0x0E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
429{
430 int32_t simm = SIMM(ctx->opcode);
431
432 if (rA(ctx->opcode) == 0) {
433 gen_op_set_T0(simm);
434 } else {
435 gen_op_load_gpr_T0(rA(ctx->opcode));
436 gen_op_addi(simm);
437 }
438 gen_op_store_T0_gpr(rD(ctx->opcode));
79aceca5
FB
439}
440/* addic */
441GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
442{
443 gen_op_load_gpr_T0(rA(ctx->opcode));
444 gen_op_addic(SIMM(ctx->opcode));
445 gen_op_store_T0_gpr(rD(ctx->opcode));
79aceca5
FB
446}
447/* addic. */
448GEN_HANDLER(addic_, 0x0D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
449{
450 gen_op_load_gpr_T0(rA(ctx->opcode));
451 gen_op_addic(SIMM(ctx->opcode));
452 gen_op_set_Rc0();
453 gen_op_store_T0_gpr(rD(ctx->opcode));
79aceca5
FB
454}
455/* addis */
456GEN_HANDLER(addis, 0x0F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
457{
458 int32_t simm = SIMM(ctx->opcode);
459
460 if (rA(ctx->opcode) == 0) {
461 gen_op_set_T0(simm << 16);
462 } else {
463 gen_op_load_gpr_T0(rA(ctx->opcode));
464 gen_op_addi(simm << 16);
465 }
466 gen_op_store_T0_gpr(rD(ctx->opcode));
79aceca5
FB
467}
468/* mulli */
469GEN_HANDLER(mulli, 0x07, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
470{
471 gen_op_load_gpr_T0(rA(ctx->opcode));
472 gen_op_mulli(SIMM(ctx->opcode));
473 gen_op_store_T0_gpr(rD(ctx->opcode));
79aceca5
FB
474}
475/* subfic */
476GEN_HANDLER(subfic, 0x08, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
477{
478 gen_op_load_gpr_T0(rA(ctx->opcode));
479 gen_op_subfic(SIMM(ctx->opcode));
480 gen_op_store_T0_gpr(rD(ctx->opcode));
79aceca5
FB
481}
482
483/*** Integer comparison ***/
484#define GEN_CMP(name, opc) \
485GEN_HANDLER(name, 0x1F, 0x00, opc, 0x00400000, PPC_INTEGER) \
486{ \
487 gen_op_load_gpr_T0(rA(ctx->opcode)); \
488 gen_op_load_gpr_T1(rB(ctx->opcode)); \
489 gen_op_##name(); \
490 gen_op_store_T0_crf(crfD(ctx->opcode)); \
79aceca5
FB
491}
492
493/* cmp */
494GEN_CMP(cmp, 0x00);
495/* cmpi */
496GEN_HANDLER(cmpi, 0x0B, 0xFF, 0xFF, 0x00400000, PPC_INTEGER)
497{
498 gen_op_load_gpr_T0(rA(ctx->opcode));
499 gen_op_cmpi(SIMM(ctx->opcode));
500 gen_op_store_T0_crf(crfD(ctx->opcode));
79aceca5
FB
501}
502/* cmpl */
503GEN_CMP(cmpl, 0x01);
504/* cmpli */
505GEN_HANDLER(cmpli, 0x0A, 0xFF, 0xFF, 0x00400000, PPC_INTEGER)
506{
507 gen_op_load_gpr_T0(rA(ctx->opcode));
508 gen_op_cmpli(UIMM(ctx->opcode));
509 gen_op_store_T0_crf(crfD(ctx->opcode));
79aceca5
FB
510}
511
512/*** Integer logical ***/
513#define __GEN_LOGICAL2(name, opc2, opc3) \
514GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000000, PPC_INTEGER) \
515{ \
516 gen_op_load_gpr_T0(rS(ctx->opcode)); \
517 gen_op_load_gpr_T1(rB(ctx->opcode)); \
518 gen_op_##name(); \
519 if (Rc(ctx->opcode) != 0) \
520 gen_op_set_Rc0(); \
521 gen_op_store_T0_gpr(rA(ctx->opcode)); \
79aceca5
FB
522}
523#define GEN_LOGICAL2(name, opc) \
524__GEN_LOGICAL2(name, 0x1C, opc)
525
526#define GEN_LOGICAL1(name, opc) \
527GEN_HANDLER(name, 0x1F, 0x1A, opc, 0x00000000, PPC_INTEGER) \
528{ \
529 gen_op_load_gpr_T0(rS(ctx->opcode)); \
530 gen_op_##name(); \
531 if (Rc(ctx->opcode) != 0) \
532 gen_op_set_Rc0(); \
533 gen_op_store_T0_gpr(rA(ctx->opcode)); \
79aceca5
FB
534}
535
536/* and & and. */
537GEN_LOGICAL2(and, 0x00);
538/* andc & andc. */
539GEN_LOGICAL2(andc, 0x01);
540/* andi. */
541GEN_HANDLER(andi_, 0x1C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
542{
543 gen_op_load_gpr_T0(rS(ctx->opcode));
544 gen_op_andi_(UIMM(ctx->opcode));
545 gen_op_set_Rc0();
546 gen_op_store_T0_gpr(rA(ctx->opcode));
79aceca5
FB
547}
548/* andis. */
549GEN_HANDLER(andis_, 0x1D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
550{
551 gen_op_load_gpr_T0(rS(ctx->opcode));
552 gen_op_andi_(UIMM(ctx->opcode) << 16);
553 gen_op_set_Rc0();
554 gen_op_store_T0_gpr(rA(ctx->opcode));
79aceca5
FB
555}
556
557/* cntlzw */
558GEN_LOGICAL1(cntlzw, 0x00);
559/* eqv & eqv. */
560GEN_LOGICAL2(eqv, 0x08);
561/* extsb & extsb. */
562GEN_LOGICAL1(extsb, 0x1D);
563/* extsh & extsh. */
564GEN_LOGICAL1(extsh, 0x1C);
565/* nand & nand. */
566GEN_LOGICAL2(nand, 0x0E);
567/* nor & nor. */
568GEN_LOGICAL2(nor, 0x03);
9a64fbe4 569
79aceca5 570/* or & or. */
9a64fbe4
FB
571GEN_HANDLER(or, 0x1F, 0x1C, 0x0D, 0x00000000, PPC_INTEGER)
572{
573 gen_op_load_gpr_T0(rS(ctx->opcode));
574 /* Optimisation for mr case */
575 if (rS(ctx->opcode) != rB(ctx->opcode)) {
576 gen_op_load_gpr_T1(rB(ctx->opcode));
577 gen_op_or();
578 }
579 if (Rc(ctx->opcode) != 0)
580 gen_op_set_Rc0();
581 gen_op_store_T0_gpr(rA(ctx->opcode));
582}
583
79aceca5
FB
584/* orc & orc. */
585GEN_LOGICAL2(orc, 0x0C);
586/* xor & xor. */
9a64fbe4
FB
587GEN_HANDLER(xor, 0x1F, 0x1C, 0x09, 0x00000000, PPC_INTEGER)
588{
589 gen_op_load_gpr_T0(rS(ctx->opcode));
590 /* Optimisation for "set to zero" case */
591 if (rS(ctx->opcode) != rB(ctx->opcode)) {
592 gen_op_load_gpr_T1(rB(ctx->opcode));
593 gen_op_xor();
594 } else {
595 gen_op_set_T0(0);
596 }
597 if (Rc(ctx->opcode) != 0)
598 gen_op_set_Rc0();
599 gen_op_store_T0_gpr(rA(ctx->opcode));
600}
79aceca5
FB
601/* ori */
602GEN_HANDLER(ori, 0x18, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
603{
604 uint32_t uimm = UIMM(ctx->opcode);
605
9a64fbe4
FB
606 if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
607 /* NOP */
608 return;
79aceca5 609 }
79aceca5 610 gen_op_load_gpr_T0(rS(ctx->opcode));
9a64fbe4 611 if (uimm != 0)
79aceca5
FB
612 gen_op_ori(uimm);
613 gen_op_store_T0_gpr(rA(ctx->opcode));
79aceca5
FB
614}
615/* oris */
616GEN_HANDLER(oris, 0x19, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
617{
618 uint32_t uimm = UIMM(ctx->opcode);
619
9a64fbe4
FB
620 if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
621 /* NOP */
622 return;
79aceca5 623 }
79aceca5 624 gen_op_load_gpr_T0(rS(ctx->opcode));
9a64fbe4 625 if (uimm != 0)
79aceca5
FB
626 gen_op_ori(uimm << 16);
627 gen_op_store_T0_gpr(rA(ctx->opcode));
79aceca5
FB
628}
629/* xori */
630GEN_HANDLER(xori, 0x1A, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
631{
9a64fbe4
FB
632 uint32_t uimm = UIMM(ctx->opcode);
633
634 if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
635 /* NOP */
636 return;
637 }
79aceca5 638 gen_op_load_gpr_T0(rS(ctx->opcode));
9a64fbe4 639 if (uimm != 0)
4b3686fa 640 gen_op_xori(uimm);
79aceca5 641 gen_op_store_T0_gpr(rA(ctx->opcode));
79aceca5
FB
642}
643
644/* xoris */
645GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
646{
9a64fbe4
FB
647 uint32_t uimm = UIMM(ctx->opcode);
648
649 if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
650 /* NOP */
651 return;
652 }
79aceca5 653 gen_op_load_gpr_T0(rS(ctx->opcode));
9a64fbe4 654 if (uimm != 0)
4b3686fa 655 gen_op_xori(uimm << 16);
79aceca5 656 gen_op_store_T0_gpr(rA(ctx->opcode));
79aceca5
FB
657}
658
659/*** Integer rotate ***/
660/* rlwimi & rlwimi. */
661GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
662{
663 uint32_t mb, me;
664
665 mb = MB(ctx->opcode);
666 me = ME(ctx->opcode);
667 gen_op_load_gpr_T0(rS(ctx->opcode));
fb0eaffc 668 gen_op_load_gpr_T1(rA(ctx->opcode));
79aceca5
FB
669 gen_op_rlwimi(SH(ctx->opcode), MASK(mb, me), ~MASK(mb, me));
670 if (Rc(ctx->opcode) != 0)
671 gen_op_set_Rc0();
672 gen_op_store_T0_gpr(rA(ctx->opcode));
79aceca5
FB
673}
674/* rlwinm & rlwinm. */
675GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
676{
677 uint32_t mb, me, sh;
678
679 sh = SH(ctx->opcode);
680 mb = MB(ctx->opcode);
681 me = ME(ctx->opcode);
682 gen_op_load_gpr_T0(rS(ctx->opcode));
4b3686fa
FB
683#if 1 // TRY
684 if (sh == 0) {
685 gen_op_andi_(MASK(mb, me));
686 goto store;
687 }
688#endif
79aceca5
FB
689 if (mb == 0) {
690 if (me == 31) {
691 gen_op_rotlwi(sh);
692 goto store;
4b3686fa 693#if 0
79aceca5
FB
694 } else if (me == (31 - sh)) {
695 gen_op_slwi(sh);
696 goto store;
4b3686fa 697#endif
79aceca5
FB
698 }
699 } else if (me == 31) {
4b3686fa 700#if 0
79aceca5
FB
701 if (sh == (32 - mb)) {
702 gen_op_srwi(mb);
703 goto store;
79aceca5 704 }
4b3686fa 705#endif
79aceca5
FB
706 }
707 gen_op_rlwinm(sh, MASK(mb, me));
708store:
709 if (Rc(ctx->opcode) != 0)
710 gen_op_set_Rc0();
711 gen_op_store_T0_gpr(rA(ctx->opcode));
79aceca5
FB
712}
713/* rlwnm & rlwnm. */
714GEN_HANDLER(rlwnm, 0x17, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
715{
716 uint32_t mb, me;
717
718 mb = MB(ctx->opcode);
719 me = ME(ctx->opcode);
720 gen_op_load_gpr_T0(rS(ctx->opcode));
721 gen_op_load_gpr_T1(rB(ctx->opcode));
722 if (mb == 0 && me == 31) {
723 gen_op_rotl();
724 } else
725 {
726 gen_op_rlwnm(MASK(mb, me));
727 }
728 if (Rc(ctx->opcode) != 0)
729 gen_op_set_Rc0();
730 gen_op_store_T0_gpr(rA(ctx->opcode));
79aceca5
FB
731}
732
733/*** Integer shift ***/
734/* slw & slw. */
735__GEN_LOGICAL2(slw, 0x18, 0x00);
736/* sraw & sraw. */
737__GEN_LOGICAL2(sraw, 0x18, 0x18);
738/* srawi & srawi. */
739GEN_HANDLER(srawi, 0x1F, 0x18, 0x19, 0x00000000, PPC_INTEGER)
740{
741 gen_op_load_gpr_T0(rS(ctx->opcode));
742 gen_op_srawi(SH(ctx->opcode), MASK(32 - SH(ctx->opcode), 31));
743 if (Rc(ctx->opcode) != 0)
744 gen_op_set_Rc0();
745 gen_op_store_T0_gpr(rA(ctx->opcode));
79aceca5
FB
746}
747/* srw & srw. */
748__GEN_LOGICAL2(srw, 0x18, 0x10);
749
750/*** Floating-Point arithmetic ***/
9a64fbe4
FB
751#define _GEN_FLOAT_ACB(name, op1, op2) \
752GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, PPC_FLOAT) \
753{ \
754 gen_op_reset_scrfx(); \
755 gen_op_load_fpr_FT0(rA(ctx->opcode)); \
756 gen_op_load_fpr_FT1(rC(ctx->opcode)); \
757 gen_op_load_fpr_FT2(rB(ctx->opcode)); \
758 gen_op_f##name(); \
759 gen_op_store_FT0_fpr(rD(ctx->opcode)); \
760 if (Rc(ctx->opcode)) \
761 gen_op_set_Rc1(); \
762}
763
764#define GEN_FLOAT_ACB(name, op2) \
765_GEN_FLOAT_ACB(name, 0x3F, op2); \
766_GEN_FLOAT_ACB(name##s, 0x3B, op2);
767
768#define _GEN_FLOAT_AB(name, op1, op2, inval) \
769GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \
770{ \
771 gen_op_reset_scrfx(); \
772 gen_op_load_fpr_FT0(rA(ctx->opcode)); \
773 gen_op_load_fpr_FT1(rB(ctx->opcode)); \
774 gen_op_f##name(); \
775 gen_op_store_FT0_fpr(rD(ctx->opcode)); \
776 if (Rc(ctx->opcode)) \
777 gen_op_set_Rc1(); \
778}
779#define GEN_FLOAT_AB(name, op2, inval) \
780_GEN_FLOAT_AB(name, 0x3F, op2, inval); \
781_GEN_FLOAT_AB(name##s, 0x3B, op2, inval);
782
783#define _GEN_FLOAT_AC(name, op1, op2, inval) \
784GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \
785{ \
786 gen_op_reset_scrfx(); \
787 gen_op_load_fpr_FT0(rA(ctx->opcode)); \
788 gen_op_load_fpr_FT1(rC(ctx->opcode)); \
789 gen_op_f##name(); \
790 gen_op_store_FT0_fpr(rD(ctx->opcode)); \
791 if (Rc(ctx->opcode)) \
792 gen_op_set_Rc1(); \
793}
794#define GEN_FLOAT_AC(name, op2, inval) \
795_GEN_FLOAT_AC(name, 0x3F, op2, inval); \
796_GEN_FLOAT_AC(name##s, 0x3B, op2, inval);
797
798#define GEN_FLOAT_B(name, op2, op3) \
799GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, PPC_FLOAT) \
800{ \
801 gen_op_reset_scrfx(); \
802 gen_op_load_fpr_FT0(rB(ctx->opcode)); \
803 gen_op_f##name(); \
804 gen_op_store_FT0_fpr(rD(ctx->opcode)); \
805 if (Rc(ctx->opcode)) \
806 gen_op_set_Rc1(); \
79aceca5
FB
807}
808
9a64fbe4
FB
809#define GEN_FLOAT_BS(name, op2) \
810GEN_HANDLER(f##name, 0x3F, op2, 0xFF, 0x001F07C0, PPC_FLOAT) \
811{ \
812 gen_op_reset_scrfx(); \
813 gen_op_load_fpr_FT0(rB(ctx->opcode)); \
814 gen_op_f##name(); \
815 gen_op_store_FT0_fpr(rD(ctx->opcode)); \
816 if (Rc(ctx->opcode)) \
817 gen_op_set_Rc1(); \
79aceca5
FB
818}
819
9a64fbe4
FB
820/* fadd - fadds */
821GEN_FLOAT_AB(add, 0x15, 0x000007C0);
79aceca5 822/* fdiv */
9a64fbe4 823GEN_FLOAT_AB(div, 0x12, 0x000007C0);
79aceca5 824/* fmul */
9a64fbe4 825GEN_FLOAT_AC(mul, 0x19, 0x0000F800);
79aceca5
FB
826
827/* fres */
9a64fbe4 828GEN_FLOAT_BS(res, 0x18);
79aceca5
FB
829
830/* frsqrte */
9a64fbe4 831GEN_FLOAT_BS(rsqrte, 0x1A);
79aceca5
FB
832
833/* fsel */
9a64fbe4 834_GEN_FLOAT_ACB(sel, 0x3F, 0x17);
79aceca5 835/* fsub */
9a64fbe4 836GEN_FLOAT_AB(sub, 0x14, 0x000007C0);
79aceca5
FB
837/* Optional: */
838/* fsqrt */
9a64fbe4 839GEN_FLOAT_BS(sqrt, 0x16);
79aceca5 840
9a64fbe4 841GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT)
79aceca5 842{
9a64fbe4
FB
843 gen_op_reset_scrfx();
844 gen_op_load_fpr_FT0(rB(ctx->opcode));
845 gen_op_fsqrts();
846 gen_op_store_FT0_fpr(rD(ctx->opcode));
847 if (Rc(ctx->opcode))
848 gen_op_set_Rc1();
79aceca5
FB
849}
850
851/*** Floating-Point multiply-and-add ***/
852/* fmadd */
9a64fbe4 853GEN_FLOAT_ACB(madd, 0x1D);
79aceca5 854/* fmsub */
9a64fbe4 855GEN_FLOAT_ACB(msub, 0x1C);
79aceca5 856/* fnmadd */
9a64fbe4 857GEN_FLOAT_ACB(nmadd, 0x1F);
79aceca5 858/* fnmsub */
9a64fbe4 859GEN_FLOAT_ACB(nmsub, 0x1E);
79aceca5
FB
860
861/*** Floating-Point round & convert ***/
862/* fctiw */
9a64fbe4 863GEN_FLOAT_B(ctiw, 0x0E, 0x00);
79aceca5 864/* fctiwz */
9a64fbe4 865GEN_FLOAT_B(ctiwz, 0x0F, 0x00);
79aceca5 866/* frsp */
9a64fbe4 867GEN_FLOAT_B(rsp, 0x0C, 0x00);
79aceca5
FB
868
869/*** Floating-Point compare ***/
870/* fcmpo */
871GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT)
872{
9a64fbe4
FB
873 gen_op_reset_scrfx();
874 gen_op_load_fpr_FT0(rA(ctx->opcode));
875 gen_op_load_fpr_FT1(rB(ctx->opcode));
876 gen_op_fcmpo();
877 gen_op_store_T0_crf(crfD(ctx->opcode));
79aceca5
FB
878}
879
880/* fcmpu */
881GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT)
882{
9a64fbe4
FB
883 gen_op_reset_scrfx();
884 gen_op_load_fpr_FT0(rA(ctx->opcode));
885 gen_op_load_fpr_FT1(rB(ctx->opcode));
886 gen_op_fcmpu();
887 gen_op_store_T0_crf(crfD(ctx->opcode));
79aceca5
FB
888}
889
9a64fbe4
FB
890/*** Floating-point move ***/
891/* fabs */
892GEN_FLOAT_B(abs, 0x08, 0x08);
893
894/* fmr - fmr. */
895GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT)
896{
897 gen_op_reset_scrfx();
898 gen_op_load_fpr_FT0(rB(ctx->opcode));
899 gen_op_store_FT0_fpr(rD(ctx->opcode));
900 if (Rc(ctx->opcode))
901 gen_op_set_Rc1();
902}
903
904/* fnabs */
905GEN_FLOAT_B(nabs, 0x08, 0x04);
906/* fneg */
907GEN_FLOAT_B(neg, 0x08, 0x01);
908
79aceca5
FB
909/*** Floating-Point status & ctrl register ***/
910/* mcrfs */
911GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT)
912{
fb0eaffc
FB
913 gen_op_load_fpscr_T0(crfS(ctx->opcode));
914 gen_op_store_T0_crf(crfD(ctx->opcode));
915 gen_op_clear_fpscr(crfS(ctx->opcode));
79aceca5
FB
916}
917
918/* mffs */
919GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT)
920{
28b6751f 921 gen_op_load_fpscr();
fb0eaffc
FB
922 gen_op_store_FT0_fpr(rD(ctx->opcode));
923 if (Rc(ctx->opcode))
924 gen_op_set_Rc1();
79aceca5
FB
925}
926
927/* mtfsb0 */
928GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT)
929{
fb0eaffc
FB
930 uint8_t crb;
931
932 crb = crbD(ctx->opcode) >> 2;
933 gen_op_load_fpscr_T0(crb);
934 gen_op_andi_(~(1 << (crbD(ctx->opcode) & 0x03)));
935 gen_op_store_T0_fpscr(crb);
936 if (Rc(ctx->opcode))
937 gen_op_set_Rc1();
79aceca5
FB
938}
939
940/* mtfsb1 */
941GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT)
942{
fb0eaffc
FB
943 uint8_t crb;
944
945 crb = crbD(ctx->opcode) >> 2;
946 gen_op_load_fpscr_T0(crb);
947 gen_op_ori(1 << (crbD(ctx->opcode) & 0x03));
948 gen_op_store_T0_fpscr(crb);
949 if (Rc(ctx->opcode))
950 gen_op_set_Rc1();
79aceca5
FB
951}
952
953/* mtfsf */
954GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x02010000, PPC_FLOAT)
955{
fb0eaffc 956 gen_op_load_fpr_FT0(rB(ctx->opcode));
28b6751f 957 gen_op_store_fpscr(FM(ctx->opcode));
fb0eaffc
FB
958 if (Rc(ctx->opcode))
959 gen_op_set_Rc1();
79aceca5
FB
960}
961
962/* mtfsfi */
963GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT)
964{
fb0eaffc
FB
965 gen_op_store_T0_fpscri(crbD(ctx->opcode) >> 2, FPIMM(ctx->opcode));
966 if (Rc(ctx->opcode))
967 gen_op_set_Rc1();
79aceca5
FB
968}
969
970/*** Integer load ***/
9a64fbe4
FB
971#if defined(CONFIG_USER_ONLY)
972#define op_ldst(name) gen_op_##name##_raw()
973#define OP_LD_TABLE(width)
974#define OP_ST_TABLE(width)
975#else
976#define op_ldst(name) (*gen_op_##name[ctx->mem_idx])()
977#define OP_LD_TABLE(width) \
978static GenOpFunc *gen_op_l##width[] = { \
979 &gen_op_l##width##_user, \
980 &gen_op_l##width##_kernel, \
981}
982#define OP_ST_TABLE(width) \
983static GenOpFunc *gen_op_st##width[] = { \
984 &gen_op_st##width##_user, \
985 &gen_op_st##width##_kernel, \
986}
987#endif
988
989#define GEN_LD(width, opc) \
79aceca5
FB
990GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
991{ \
992 uint32_t simm = SIMM(ctx->opcode); \
993 if (rA(ctx->opcode) == 0) { \
9a64fbe4 994 gen_op_set_T0(simm); \
79aceca5
FB
995 } else { \
996 gen_op_load_gpr_T0(rA(ctx->opcode)); \
9a64fbe4
FB
997 if (simm != 0) \
998 gen_op_addi(simm); \
79aceca5 999 } \
9a64fbe4 1000 op_ldst(l##width); \
79aceca5 1001 gen_op_store_T1_gpr(rD(ctx->opcode)); \
79aceca5
FB
1002}
1003
9a64fbe4 1004#define GEN_LDU(width, opc) \
79aceca5
FB
1005GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
1006{ \
9a64fbe4 1007 uint32_t simm = SIMM(ctx->opcode); \
79aceca5 1008 if (rA(ctx->opcode) == 0 || \
9a64fbe4 1009 rA(ctx->opcode) == rD(ctx->opcode)) { \
9fddaa0c
FB
1010 RET_INVAL(ctx); \
1011 return; \
9a64fbe4 1012 } \
79aceca5 1013 gen_op_load_gpr_T0(rA(ctx->opcode)); \
9a64fbe4
FB
1014 if (simm != 0) \
1015 gen_op_addi(simm); \
1016 op_ldst(l##width); \
79aceca5
FB
1017 gen_op_store_T1_gpr(rD(ctx->opcode)); \
1018 gen_op_store_T0_gpr(rA(ctx->opcode)); \
79aceca5
FB
1019}
1020
9a64fbe4 1021#define GEN_LDUX(width, opc) \
79aceca5
FB
1022GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \
1023{ \
1024 if (rA(ctx->opcode) == 0 || \
9a64fbe4 1025 rA(ctx->opcode) == rD(ctx->opcode)) { \
9fddaa0c
FB
1026 RET_INVAL(ctx); \
1027 return; \
9a64fbe4 1028 } \
79aceca5
FB
1029 gen_op_load_gpr_T0(rA(ctx->opcode)); \
1030 gen_op_load_gpr_T1(rB(ctx->opcode)); \
9a64fbe4
FB
1031 gen_op_add(); \
1032 op_ldst(l##width); \
79aceca5
FB
1033 gen_op_store_T1_gpr(rD(ctx->opcode)); \
1034 gen_op_store_T0_gpr(rA(ctx->opcode)); \
79aceca5
FB
1035}
1036
9a64fbe4 1037#define GEN_LDX(width, opc2, opc3) \
79aceca5
FB
1038GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \
1039{ \
1040 if (rA(ctx->opcode) == 0) { \
1041 gen_op_load_gpr_T0(rB(ctx->opcode)); \
79aceca5
FB
1042 } else { \
1043 gen_op_load_gpr_T0(rA(ctx->opcode)); \
1044 gen_op_load_gpr_T1(rB(ctx->opcode)); \
9a64fbe4 1045 gen_op_add(); \
79aceca5 1046 } \
9a64fbe4 1047 op_ldst(l##width); \
79aceca5 1048 gen_op_store_T1_gpr(rD(ctx->opcode)); \
79aceca5
FB
1049}
1050
9a64fbe4
FB
1051#define GEN_LDS(width, op) \
1052OP_LD_TABLE(width); \
1053GEN_LD(width, op | 0x20); \
1054GEN_LDU(width, op | 0x21); \
1055GEN_LDUX(width, op | 0x01); \
1056GEN_LDX(width, 0x17, op | 0x00)
79aceca5
FB
1057
1058/* lbz lbzu lbzux lbzx */
9a64fbe4 1059GEN_LDS(bz, 0x02);
79aceca5 1060/* lha lhau lhaux lhax */
9a64fbe4 1061GEN_LDS(ha, 0x0A);
79aceca5 1062/* lhz lhzu lhzux lhzx */
9a64fbe4 1063GEN_LDS(hz, 0x08);
79aceca5 1064/* lwz lwzu lwzux lwzx */
9a64fbe4 1065GEN_LDS(wz, 0x00);
79aceca5
FB
1066
1067/*** Integer store ***/
9a64fbe4 1068#define GEN_ST(width, opc) \
79aceca5
FB
1069GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
1070{ \
1071 uint32_t simm = SIMM(ctx->opcode); \
1072 if (rA(ctx->opcode) == 0) { \
9a64fbe4 1073 gen_op_set_T0(simm); \
79aceca5
FB
1074 } else { \
1075 gen_op_load_gpr_T0(rA(ctx->opcode)); \
9a64fbe4
FB
1076 if (simm != 0) \
1077 gen_op_addi(simm); \
79aceca5 1078 } \
9a64fbe4
FB
1079 gen_op_load_gpr_T1(rS(ctx->opcode)); \
1080 op_ldst(st##width); \
79aceca5
FB
1081}
1082
9a64fbe4 1083#define GEN_STU(width, opc) \
79aceca5
FB
1084GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
1085{ \
9a64fbe4
FB
1086 uint32_t simm = SIMM(ctx->opcode); \
1087 if (rA(ctx->opcode) == 0) { \
9fddaa0c
FB
1088 RET_INVAL(ctx); \
1089 return; \
9a64fbe4 1090 } \
79aceca5 1091 gen_op_load_gpr_T0(rA(ctx->opcode)); \
9a64fbe4
FB
1092 if (simm != 0) \
1093 gen_op_addi(simm); \
79aceca5 1094 gen_op_load_gpr_T1(rS(ctx->opcode)); \
9a64fbe4 1095 op_ldst(st##width); \
79aceca5 1096 gen_op_store_T0_gpr(rA(ctx->opcode)); \
79aceca5
FB
1097}
1098
9a64fbe4 1099#define GEN_STUX(width, opc) \
79aceca5
FB
1100GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \
1101{ \
9a64fbe4 1102 if (rA(ctx->opcode) == 0) { \
9fddaa0c
FB
1103 RET_INVAL(ctx); \
1104 return; \
9a64fbe4 1105 } \
79aceca5
FB
1106 gen_op_load_gpr_T0(rA(ctx->opcode)); \
1107 gen_op_load_gpr_T1(rB(ctx->opcode)); \
9a64fbe4
FB
1108 gen_op_add(); \
1109 gen_op_load_gpr_T1(rS(ctx->opcode)); \
1110 op_ldst(st##width); \
79aceca5 1111 gen_op_store_T0_gpr(rA(ctx->opcode)); \
79aceca5
FB
1112}
1113
9a64fbe4 1114#define GEN_STX(width, opc2, opc3) \
79aceca5
FB
1115GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \
1116{ \
1117 if (rA(ctx->opcode) == 0) { \
1118 gen_op_load_gpr_T0(rB(ctx->opcode)); \
79aceca5
FB
1119 } else { \
1120 gen_op_load_gpr_T0(rA(ctx->opcode)); \
1121 gen_op_load_gpr_T1(rB(ctx->opcode)); \
9a64fbe4 1122 gen_op_add(); \
79aceca5 1123 } \
9a64fbe4
FB
1124 gen_op_load_gpr_T1(rS(ctx->opcode)); \
1125 op_ldst(st##width); \
79aceca5
FB
1126}
1127
9a64fbe4
FB
1128#define GEN_STS(width, op) \
1129OP_ST_TABLE(width); \
1130GEN_ST(width, op | 0x20); \
1131GEN_STU(width, op | 0x21); \
1132GEN_STUX(width, op | 0x01); \
1133GEN_STX(width, 0x17, op | 0x00)
79aceca5
FB
1134
1135/* stb stbu stbux stbx */
9a64fbe4 1136GEN_STS(b, 0x06);
79aceca5 1137/* sth sthu sthux sthx */
9a64fbe4 1138GEN_STS(h, 0x0C);
79aceca5 1139/* stw stwu stwux stwx */
9a64fbe4 1140GEN_STS(w, 0x04);
79aceca5
FB
1141
1142/*** Integer load and store with byte reverse ***/
1143/* lhbrx */
9a64fbe4
FB
1144OP_LD_TABLE(hbr);
1145GEN_LDX(hbr, 0x16, 0x18);
79aceca5 1146/* lwbrx */
9a64fbe4
FB
1147OP_LD_TABLE(wbr);
1148GEN_LDX(wbr, 0x16, 0x10);
79aceca5 1149/* sthbrx */
9a64fbe4
FB
1150OP_ST_TABLE(hbr);
1151GEN_STX(hbr, 0x16, 0x1C);
79aceca5 1152/* stwbrx */
9a64fbe4
FB
1153OP_ST_TABLE(wbr);
1154GEN_STX(wbr, 0x16, 0x14);
79aceca5
FB
1155
1156/*** Integer load and store multiple ***/
9a64fbe4
FB
1157#if defined(CONFIG_USER_ONLY)
1158#define op_ldstm(name, reg) gen_op_##name##_raw(reg)
1159#else
1160#define op_ldstm(name, reg) (*gen_op_##name[ctx->mem_idx])(reg)
1161static GenOpFunc1 *gen_op_lmw[] = {
1162 &gen_op_lmw_user,
1163 &gen_op_lmw_kernel,
1164};
1165static GenOpFunc1 *gen_op_stmw[] = {
1166 &gen_op_stmw_user,
1167 &gen_op_stmw_kernel,
1168};
1169#endif
1170
79aceca5
FB
1171/* lmw */
1172GEN_HANDLER(lmw, 0x2E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
1173{
9a64fbe4
FB
1174 int simm = SIMM(ctx->opcode);
1175
79aceca5 1176 if (rA(ctx->opcode) == 0) {
9a64fbe4 1177 gen_op_set_T0(simm);
79aceca5
FB
1178 } else {
1179 gen_op_load_gpr_T0(rA(ctx->opcode));
9a64fbe4
FB
1180 if (simm != 0)
1181 gen_op_addi(simm);
79aceca5 1182 }
9a64fbe4 1183 op_ldstm(lmw, rD(ctx->opcode));
79aceca5
FB
1184}
1185
1186/* stmw */
1187GEN_HANDLER(stmw, 0x2F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
1188{
9a64fbe4
FB
1189 int simm = SIMM(ctx->opcode);
1190
79aceca5 1191 if (rA(ctx->opcode) == 0) {
9a64fbe4 1192 gen_op_set_T0(simm);
79aceca5
FB
1193 } else {
1194 gen_op_load_gpr_T0(rA(ctx->opcode));
9a64fbe4
FB
1195 if (simm != 0)
1196 gen_op_addi(simm);
79aceca5 1197 }
9a64fbe4 1198 op_ldstm(stmw, rS(ctx->opcode));
79aceca5
FB
1199}
1200
1201/*** Integer load and store strings ***/
9a64fbe4
FB
1202#if defined(CONFIG_USER_ONLY)
1203#define op_ldsts(name, start) gen_op_##name##_raw(start)
1204#define op_ldstsx(name, rd, ra, rb) gen_op_##name##_raw(rd, ra, rb)
1205#else
1206#define op_ldsts(name, start) (*gen_op_##name[ctx->mem_idx])(start)
1207#define op_ldstsx(name, rd, ra, rb) (*gen_op_##name[ctx->mem_idx])(rd, ra, rb)
1208static GenOpFunc1 *gen_op_lswi[] = {
1209 &gen_op_lswi_user,
1210 &gen_op_lswi_kernel,
1211};
1212static GenOpFunc3 *gen_op_lswx[] = {
1213 &gen_op_lswx_user,
1214 &gen_op_lswx_kernel,
1215};
1216static GenOpFunc1 *gen_op_stsw[] = {
1217 &gen_op_stsw_user,
1218 &gen_op_stsw_kernel,
1219};
1220#endif
1221
79aceca5 1222/* lswi */
9a64fbe4
FB
1223/* PPC32 specification says we must generate an exception if
1224 * rA is in the range of registers to be loaded.
1225 * In an other hand, IBM says this is valid, but rA won't be loaded.
1226 * For now, I'll follow the spec...
1227 */
79aceca5
FB
1228GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_INTEGER)
1229{
1230 int nb = NB(ctx->opcode);
1231 int start = rD(ctx->opcode);
9a64fbe4 1232 int ra = rA(ctx->opcode);
79aceca5
FB
1233 int nr;
1234
1235 if (nb == 0)
1236 nb = 32;
1237 nr = nb / 4;
297d8e62
FB
1238 if (((start + nr) > 32 && start <= ra && (start + nr - 32) > ra) ||
1239 ((start + nr) <= 32 && start <= ra && (start + nr) > ra)) {
9fddaa0c
FB
1240 RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX);
1241 return;
297d8e62 1242 }
9a64fbe4 1243 if (ra == 0) {
79aceca5
FB
1244 gen_op_set_T0(0);
1245 } else {
9a64fbe4 1246 gen_op_load_gpr_T0(ra);
79aceca5 1247 }
9a64fbe4
FB
1248 gen_op_set_T1(nb);
1249 op_ldsts(lswi, start);
79aceca5
FB
1250}
1251
1252/* lswx */
1253GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001, PPC_INTEGER)
1254{
9a64fbe4
FB
1255 int ra = rA(ctx->opcode);
1256 int rb = rB(ctx->opcode);
1257
1258 if (ra == 0) {
1259 gen_op_load_gpr_T0(rb);
1260 ra = rb;
79aceca5 1261 } else {
9a64fbe4
FB
1262 gen_op_load_gpr_T0(ra);
1263 gen_op_load_gpr_T1(rb);
1264 gen_op_add();
79aceca5 1265 }
9a64fbe4
FB
1266 gen_op_load_xer_bc();
1267 op_ldstsx(lswx, rD(ctx->opcode), ra, rb);
79aceca5
FB
1268}
1269
1270/* stswi */
1271GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_INTEGER)
1272{
4b3686fa
FB
1273 int nb = NB(ctx->opcode);
1274
79aceca5
FB
1275 if (rA(ctx->opcode) == 0) {
1276 gen_op_set_T0(0);
1277 } else {
1278 gen_op_load_gpr_T0(rA(ctx->opcode));
1279 }
4b3686fa
FB
1280 if (nb == 0)
1281 nb = 32;
1282 gen_op_set_T1(nb);
9a64fbe4 1283 op_ldsts(stsw, rS(ctx->opcode));
79aceca5
FB
1284}
1285
1286/* stswx */
1287GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_INTEGER)
1288{
9a64fbe4
FB
1289 int ra = rA(ctx->opcode);
1290
1291 if (ra == 0) {
1292 gen_op_load_gpr_T0(rB(ctx->opcode));
1293 ra = rB(ctx->opcode);
79aceca5 1294 } else {
9a64fbe4
FB
1295 gen_op_load_gpr_T0(ra);
1296 gen_op_load_gpr_T1(rB(ctx->opcode));
1297 gen_op_add();
79aceca5 1298 }
9a64fbe4
FB
1299 gen_op_load_xer_bc();
1300 op_ldsts(stsw, rS(ctx->opcode));
79aceca5
FB
1301}
1302
1303/*** Memory synchronisation ***/
1304/* eieio */
1305GEN_HANDLER(eieio, 0x1F, 0x16, 0x1A, 0x03FF0801, PPC_MEM)
1306{
79aceca5
FB
1307}
1308
1309/* isync */
1310GEN_HANDLER(isync, 0x13, 0x16, 0xFF, 0x03FF0801, PPC_MEM)
1311{
79aceca5
FB
1312}
1313
1314/* lwarx */
9a64fbe4 1315#if defined(CONFIG_USER_ONLY)
985a19d6 1316#define op_lwarx() gen_op_lwarx_raw()
9a64fbe4
FB
1317#define op_stwcx() gen_op_stwcx_raw()
1318#else
985a19d6
FB
1319#define op_lwarx() (*gen_op_lwarx[ctx->mem_idx])()
1320static GenOpFunc *gen_op_lwarx[] = {
1321 &gen_op_lwarx_user,
1322 &gen_op_lwarx_kernel,
1323};
9a64fbe4
FB
1324#define op_stwcx() (*gen_op_stwcx[ctx->mem_idx])()
1325static GenOpFunc *gen_op_stwcx[] = {
1326 &gen_op_stwcx_user,
1327 &gen_op_stwcx_kernel,
1328};
1329#endif
1330
1331GEN_HANDLER(lwarx, 0x1F, 0x14, 0xFF, 0x00000001, PPC_RES)
79aceca5 1332{
79aceca5
FB
1333 if (rA(ctx->opcode) == 0) {
1334 gen_op_load_gpr_T0(rB(ctx->opcode));
79aceca5
FB
1335 } else {
1336 gen_op_load_gpr_T0(rA(ctx->opcode));
1337 gen_op_load_gpr_T1(rB(ctx->opcode));
9a64fbe4 1338 gen_op_add();
79aceca5 1339 }
985a19d6 1340 op_lwarx();
79aceca5 1341 gen_op_store_T1_gpr(rD(ctx->opcode));
79aceca5
FB
1342}
1343
1344/* stwcx. */
9a64fbe4 1345GEN_HANDLER(stwcx_, 0x1F, 0x16, 0x04, 0x00000000, PPC_RES)
79aceca5 1346{
79aceca5
FB
1347 if (rA(ctx->opcode) == 0) {
1348 gen_op_load_gpr_T0(rB(ctx->opcode));
79aceca5
FB
1349 } else {
1350 gen_op_load_gpr_T0(rA(ctx->opcode));
1351 gen_op_load_gpr_T1(rB(ctx->opcode));
9a64fbe4 1352 gen_op_add();
79aceca5 1353 }
9a64fbe4
FB
1354 gen_op_load_gpr_T1(rS(ctx->opcode));
1355 op_stwcx();
79aceca5
FB
1356}
1357
1358/* sync */
1359GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_MEM)
1360{
79aceca5
FB
1361}
1362
1363/*** Floating-point load ***/
9a64fbe4
FB
1364#define GEN_LDF(width, opc) \
1365GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
79aceca5
FB
1366{ \
1367 uint32_t simm = SIMM(ctx->opcode); \
1368 if (rA(ctx->opcode) == 0) { \
9a64fbe4 1369 gen_op_set_T0(simm); \
79aceca5
FB
1370 } else { \
1371 gen_op_load_gpr_T0(rA(ctx->opcode)); \
9a64fbe4
FB
1372 if (simm != 0) \
1373 gen_op_addi(simm); \
79aceca5 1374 } \
9a64fbe4
FB
1375 op_ldst(l##width); \
1376 gen_op_store_FT1_fpr(rD(ctx->opcode)); \
79aceca5
FB
1377}
1378
9a64fbe4
FB
1379#define GEN_LDUF(width, opc) \
1380GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
79aceca5 1381{ \
9a64fbe4 1382 uint32_t simm = SIMM(ctx->opcode); \
79aceca5 1383 if (rA(ctx->opcode) == 0 || \
9a64fbe4 1384 rA(ctx->opcode) == rD(ctx->opcode)) { \
9fddaa0c
FB
1385 RET_INVAL(ctx); \
1386 return; \
9a64fbe4 1387 } \
79aceca5 1388 gen_op_load_gpr_T0(rA(ctx->opcode)); \
9a64fbe4
FB
1389 if (simm != 0) \
1390 gen_op_addi(simm); \
1391 op_ldst(l##width); \
1392 gen_op_store_FT1_fpr(rD(ctx->opcode)); \
79aceca5 1393 gen_op_store_T0_gpr(rA(ctx->opcode)); \
79aceca5
FB
1394}
1395
9a64fbe4
FB
1396#define GEN_LDUXF(width, opc) \
1397GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \
79aceca5
FB
1398{ \
1399 if (rA(ctx->opcode) == 0 || \
9a64fbe4 1400 rA(ctx->opcode) == rD(ctx->opcode)) { \
9fddaa0c
FB
1401 RET_INVAL(ctx); \
1402 return; \
9a64fbe4 1403 } \
79aceca5
FB
1404 gen_op_load_gpr_T0(rA(ctx->opcode)); \
1405 gen_op_load_gpr_T1(rB(ctx->opcode)); \
9a64fbe4
FB
1406 gen_op_add(); \
1407 op_ldst(l##width); \
1408 gen_op_store_FT1_fpr(rD(ctx->opcode)); \
79aceca5 1409 gen_op_store_T0_gpr(rA(ctx->opcode)); \
79aceca5
FB
1410}
1411
9a64fbe4
FB
1412#define GEN_LDXF(width, opc2, opc3) \
1413GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \
79aceca5
FB
1414{ \
1415 if (rA(ctx->opcode) == 0) { \
1416 gen_op_load_gpr_T0(rB(ctx->opcode)); \
79aceca5
FB
1417 } else { \
1418 gen_op_load_gpr_T0(rA(ctx->opcode)); \
1419 gen_op_load_gpr_T1(rB(ctx->opcode)); \
9a64fbe4 1420 gen_op_add(); \
79aceca5 1421 } \
9a64fbe4
FB
1422 op_ldst(l##width); \
1423 gen_op_store_FT1_fpr(rD(ctx->opcode)); \
79aceca5
FB
1424}
1425
9a64fbe4
FB
1426#define GEN_LDFS(width, op) \
1427OP_LD_TABLE(width); \
1428GEN_LDF(width, op | 0x20); \
1429GEN_LDUF(width, op | 0x21); \
1430GEN_LDUXF(width, op | 0x01); \
1431GEN_LDXF(width, 0x17, op | 0x00)
79aceca5
FB
1432
1433/* lfd lfdu lfdux lfdx */
9a64fbe4 1434GEN_LDFS(fd, 0x12);
79aceca5 1435/* lfs lfsu lfsux lfsx */
9a64fbe4 1436GEN_LDFS(fs, 0x10);
79aceca5
FB
1437
1438/*** Floating-point store ***/
1439#define GEN_STF(width, opc) \
9a64fbe4 1440GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
79aceca5
FB
1441{ \
1442 uint32_t simm = SIMM(ctx->opcode); \
1443 if (rA(ctx->opcode) == 0) { \
9a64fbe4 1444 gen_op_set_T0(simm); \
79aceca5
FB
1445 } else { \
1446 gen_op_load_gpr_T0(rA(ctx->opcode)); \
9a64fbe4
FB
1447 if (simm != 0) \
1448 gen_op_addi(simm); \
79aceca5 1449 } \
9a64fbe4
FB
1450 gen_op_load_fpr_FT1(rS(ctx->opcode)); \
1451 op_ldst(st##width); \
79aceca5
FB
1452}
1453
9a64fbe4
FB
1454#define GEN_STUF(width, opc) \
1455GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
79aceca5 1456{ \
9a64fbe4
FB
1457 uint32_t simm = SIMM(ctx->opcode); \
1458 if (rA(ctx->opcode) == 0) { \
9fddaa0c
FB
1459 RET_INVAL(ctx); \
1460 return; \
9a64fbe4 1461 } \
79aceca5 1462 gen_op_load_gpr_T0(rA(ctx->opcode)); \
9a64fbe4
FB
1463 if (simm != 0) \
1464 gen_op_addi(simm); \
1465 gen_op_load_fpr_FT1(rS(ctx->opcode)); \
1466 op_ldst(st##width); \
79aceca5 1467 gen_op_store_T0_gpr(rA(ctx->opcode)); \
79aceca5
FB
1468}
1469
9a64fbe4
FB
1470#define GEN_STUXF(width, opc) \
1471GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \
79aceca5 1472{ \
9a64fbe4 1473 if (rA(ctx->opcode) == 0) { \
9fddaa0c
FB
1474 RET_INVAL(ctx); \
1475 return; \
9a64fbe4 1476 } \
79aceca5
FB
1477 gen_op_load_gpr_T0(rA(ctx->opcode)); \
1478 gen_op_load_gpr_T1(rB(ctx->opcode)); \
9a64fbe4
FB
1479 gen_op_add(); \
1480 gen_op_load_fpr_FT1(rS(ctx->opcode)); \
1481 op_ldst(st##width); \
79aceca5 1482 gen_op_store_T0_gpr(rA(ctx->opcode)); \
79aceca5
FB
1483}
1484
9a64fbe4
FB
1485#define GEN_STXF(width, opc2, opc3) \
1486GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \
79aceca5
FB
1487{ \
1488 if (rA(ctx->opcode) == 0) { \
1489 gen_op_load_gpr_T0(rB(ctx->opcode)); \
79aceca5
FB
1490 } else { \
1491 gen_op_load_gpr_T0(rA(ctx->opcode)); \
1492 gen_op_load_gpr_T1(rB(ctx->opcode)); \
9a64fbe4 1493 gen_op_add(); \
79aceca5 1494 } \
9a64fbe4
FB
1495 gen_op_load_fpr_FT1(rS(ctx->opcode)); \
1496 op_ldst(st##width); \
79aceca5
FB
1497}
1498
9a64fbe4
FB
1499#define GEN_STFS(width, op) \
1500OP_ST_TABLE(width); \
1501GEN_STF(width, op | 0x20); \
1502GEN_STUF(width, op | 0x21); \
1503GEN_STUXF(width, op | 0x01); \
1504GEN_STXF(width, 0x17, op | 0x00)
79aceca5
FB
1505
1506/* stfd stfdu stfdux stfdx */
9a64fbe4 1507GEN_STFS(fd, 0x16);
79aceca5 1508/* stfs stfsu stfsux stfsx */
9a64fbe4 1509GEN_STFS(fs, 0x14);
79aceca5
FB
1510
1511/* Optional: */
1512/* stfiwx */
1513GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT)
1514{
9fddaa0c 1515 RET_INVAL(ctx);
79aceca5
FB
1516}
1517
1518/*** Branch ***/
79aceca5
FB
1519
1520/* b ba bl bla */
1521GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
1522{
38a64f9d
FB
1523 uint32_t li, target;
1524
1525 /* sign extend LI */
1526 li = ((int32_t)LI(ctx->opcode) << 6) >> 6;
79aceca5
FB
1527
1528 if (AA(ctx->opcode) == 0)
046d6672 1529 target = ctx->nip + li - 4;
79aceca5 1530 else
9a64fbe4 1531 target = li;
9a64fbe4 1532 if (LK(ctx->opcode)) {
046d6672 1533 gen_op_setlr(ctx->nip);
9a64fbe4 1534 }
e98a6e40 1535 gen_op_b((long)ctx->tb, target);
9a64fbe4 1536 ctx->exception = EXCP_BRANCH;
79aceca5
FB
1537}
1538
e98a6e40
FB
1539#define BCOND_IM 0
1540#define BCOND_LR 1
1541#define BCOND_CTR 2
1542
1543static inline void gen_bcond(DisasContext *ctx, int type)
1544{
1545 uint32_t target = 0;
1546 uint32_t bo = BO(ctx->opcode);
1547 uint32_t bi = BI(ctx->opcode);
1548 uint32_t mask;
1549 uint32_t li;
1550
e98a6e40
FB
1551 if ((bo & 0x4) == 0)
1552 gen_op_dec_ctr();
1553 switch(type) {
1554 case BCOND_IM:
1555 li = s_ext16(BD(ctx->opcode));
1556 if (AA(ctx->opcode) == 0) {
046d6672 1557 target = ctx->nip + li - 4;
e98a6e40
FB
1558 } else {
1559 target = li;
1560 }
1561 break;
1562 case BCOND_CTR:
1563 gen_op_movl_T1_ctr();
1564 break;
1565 default:
1566 case BCOND_LR:
1567 gen_op_movl_T1_lr();
1568 break;
1569 }
1570 if (LK(ctx->opcode)) {
046d6672 1571 gen_op_setlr(ctx->nip);
e98a6e40
FB
1572 }
1573 if (bo & 0x10) {
1574 /* No CR condition */
1575 switch (bo & 0x6) {
1576 case 0:
1577 gen_op_test_ctr();
1578 break;
1579 case 2:
1580 gen_op_test_ctrz();
1581 break;
1582 default:
1583 case 4:
1584 case 6:
1585 if (type == BCOND_IM) {
1586 gen_op_b((long)ctx->tb, target);
1587 } else {
1588 gen_op_b_T1();
e98a6e40
FB
1589 }
1590 goto no_test;
1591 }
1592 } else {
1593 mask = 1 << (3 - (bi & 0x03));
1594 gen_op_load_crf_T0(bi >> 2);
1595 if (bo & 0x8) {
1596 switch (bo & 0x6) {
1597 case 0:
1598 gen_op_test_ctr_true(mask);
1599 break;
1600 case 2:
1601 gen_op_test_ctrz_true(mask);
1602 break;
1603 default:
1604 case 4:
1605 case 6:
1606 gen_op_test_true(mask);
1607 break;
1608 }
1609 } else {
1610 switch (bo & 0x6) {
1611 case 0:
1612 gen_op_test_ctr_false(mask);
1613 break;
1614 case 2:
1615 gen_op_test_ctrz_false(mask);
1616 break;
1617 default:
1618 case 4:
1619 case 6:
1620 gen_op_test_false(mask);
1621 break;
1622 }
1623 }
1624 }
1625 if (type == BCOND_IM) {
046d6672 1626 gen_op_btest((long)ctx->tb, target, ctx->nip);
e98a6e40 1627 } else {
046d6672 1628 gen_op_btest_T1(ctx->nip);
e98a6e40
FB
1629 }
1630 no_test:
1631 ctx->exception = EXCP_BRANCH;
1632}
1633
1634GEN_HANDLER(bc, 0x10, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
1635{
1636 gen_bcond(ctx, BCOND_IM);
1637}
1638
1639GEN_HANDLER(bcctr, 0x13, 0x10, 0x10, 0x00000000, PPC_FLOW)
1640{
1641 gen_bcond(ctx, BCOND_CTR);
1642}
1643
1644GEN_HANDLER(bclr, 0x13, 0x10, 0x00, 0x00000000, PPC_FLOW)
1645{
1646 gen_bcond(ctx, BCOND_LR);
1647}
79aceca5
FB
1648
1649/*** Condition register logical ***/
1650#define GEN_CRLOGIC(op, opc) \
1651GEN_HANDLER(cr##op, 0x13, 0x01, opc, 0x00000001, PPC_INTEGER) \
1652{ \
1653 gen_op_load_crf_T0(crbA(ctx->opcode) >> 2); \
1654 gen_op_getbit_T0(3 - (crbA(ctx->opcode) & 0x03)); \
1655 gen_op_load_crf_T1(crbB(ctx->opcode) >> 2); \
1656 gen_op_getbit_T1(3 - (crbB(ctx->opcode) & 0x03)); \
1657 gen_op_##op(); \
1658 gen_op_load_crf_T1(crbD(ctx->opcode) >> 2); \
1659 gen_op_setcrfbit(~(1 << (3 - (crbD(ctx->opcode) & 0x03))), \
1660 3 - (crbD(ctx->opcode) & 0x03)); \
1661 gen_op_store_T1_crf(crbD(ctx->opcode) >> 2); \
79aceca5
FB
1662}
1663
1664/* crand */
1665GEN_CRLOGIC(and, 0x08)
1666/* crandc */
1667GEN_CRLOGIC(andc, 0x04)
1668/* creqv */
1669GEN_CRLOGIC(eqv, 0x09)
1670/* crnand */
1671GEN_CRLOGIC(nand, 0x07)
1672/* crnor */
1673GEN_CRLOGIC(nor, 0x01)
1674/* cror */
1675GEN_CRLOGIC(or, 0x0E)
1676/* crorc */
1677GEN_CRLOGIC(orc, 0x0D)
1678/* crxor */
1679GEN_CRLOGIC(xor, 0x06)
1680/* mcrf */
1681GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER)
1682{
1683 gen_op_load_crf_T0(crfS(ctx->opcode));
1684 gen_op_store_T0_crf(crfD(ctx->opcode));
79aceca5
FB
1685}
1686
1687/*** System linkage ***/
1688/* rfi (supervisor only) */
1689GEN_HANDLER(rfi, 0x13, 0x12, 0xFF, 0x03FF8001, PPC_FLOW)
1690{
9a64fbe4 1691#if defined(CONFIG_USER_ONLY)
9fddaa0c 1692 RET_PRIVOPC(ctx);
9a64fbe4
FB
1693#else
1694 /* Restore CPU state */
1695 if (!ctx->supervisor) {
9fddaa0c
FB
1696 RET_PRIVOPC(ctx);
1697 return;
9a64fbe4
FB
1698 }
1699 gen_op_rfi();
9fddaa0c 1700 RET_EXCP(ctx, EXCP_RFI, 0);
9a64fbe4 1701#endif
79aceca5
FB
1702}
1703
1704/* sc */
1705GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFFFFD, PPC_FLOW)
1706{
9a64fbe4 1707#if defined(CONFIG_USER_ONLY)
9fddaa0c 1708 RET_EXCP(ctx, EXCP_SYSCALL_USER, 0);
9a64fbe4 1709#else
9fddaa0c 1710 RET_EXCP(ctx, EXCP_SYSCALL, 0);
9a64fbe4 1711#endif
79aceca5
FB
1712}
1713
1714/*** Trap ***/
1715/* tw */
1716GEN_HANDLER(tw, 0x1F, 0x04, 0xFF, 0x00000001, PPC_FLOW)
1717{
9a64fbe4
FB
1718 gen_op_load_gpr_T0(rA(ctx->opcode));
1719 gen_op_load_gpr_T1(rB(ctx->opcode));
1720 gen_op_tw(TO(ctx->opcode));
79aceca5
FB
1721}
1722
1723/* twi */
1724GEN_HANDLER(twi, 0x03, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
1725{
9a64fbe4
FB
1726 gen_op_load_gpr_T0(rA(ctx->opcode));
1727#if 0
1728 printf("%s: param=0x%04x T0=0x%04x\n", __func__,
1729 SIMM(ctx->opcode), TO(ctx->opcode));
1730#endif
1731 gen_op_twi(SIMM(ctx->opcode), TO(ctx->opcode));
79aceca5
FB
1732}
1733
1734/*** Processor control ***/
1735static inline int check_spr_access (int spr, int rw, int supervisor)
1736{
1737 uint32_t rights = spr_access[spr >> 1] >> (4 * (spr & 1));
1738
9a64fbe4
FB
1739#if 0
1740 if (spr != LR && spr != CTR) {
1741 if (loglevel > 0) {
1742 fprintf(logfile, "%s reg=%d s=%d rw=%d r=0x%02x 0x%02x\n", __func__,
1743 SPR_ENCODE(spr), supervisor, rw, rights,
1744 (rights >> ((2 * supervisor) + rw)) & 1);
1745 } else {
1746 printf("%s reg=%d s=%d rw=%d r=0x%02x 0x%02x\n", __func__,
1747 SPR_ENCODE(spr), supervisor, rw, rights,
1748 (rights >> ((2 * supervisor) + rw)) & 1);
1749 }
1750 }
1751#endif
1752 if (rights == 0)
1753 return -1;
79aceca5
FB
1754 rights = rights >> (2 * supervisor);
1755 rights = rights >> rw;
1756
1757 return rights & 1;
1758}
1759
1760/* mcrxr */
1761GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC)
1762{
1763 gen_op_load_xer_cr();
1764 gen_op_store_T0_crf(crfD(ctx->opcode));
1765 gen_op_clear_xer_cr();
79aceca5
FB
1766}
1767
1768/* mfcr */
1769GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x001FF801, PPC_MISC)
1770{
1771 gen_op_load_cr();
1772 gen_op_store_T0_gpr(rD(ctx->opcode));
79aceca5
FB
1773}
1774
1775/* mfmsr */
1776GEN_HANDLER(mfmsr, 0x1F, 0x13, 0x02, 0x001FF801, PPC_MISC)
1777{
9a64fbe4 1778#if defined(CONFIG_USER_ONLY)
9fddaa0c 1779 RET_PRIVREG(ctx);
9a64fbe4
FB
1780#else
1781 if (!ctx->supervisor) {
9fddaa0c
FB
1782 RET_PRIVREG(ctx);
1783 return;
9a64fbe4 1784 }
79aceca5
FB
1785 gen_op_load_msr();
1786 gen_op_store_T0_gpr(rD(ctx->opcode));
9a64fbe4 1787#endif
79aceca5
FB
1788}
1789
1790/* mfspr */
1791GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC)
1792{
1793 uint32_t sprn = SPR(ctx->opcode);
1794
9a64fbe4
FB
1795#if defined(CONFIG_USER_ONLY)
1796 switch (check_spr_access(sprn, 0, 0))
1797#else
1798 switch (check_spr_access(sprn, 0, ctx->supervisor))
1799#endif
1800 {
1801 case -1:
9fddaa0c
FB
1802 RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
1803 return;
9a64fbe4 1804 case 0:
9fddaa0c
FB
1805 RET_PRIVREG(ctx);
1806 return;
9a64fbe4
FB
1807 default:
1808 break;
79aceca5 1809 }
9a64fbe4
FB
1810 switch (sprn) {
1811 case XER:
79aceca5
FB
1812 gen_op_load_xer();
1813 break;
9a64fbe4
FB
1814 case LR:
1815 gen_op_load_lr();
1816 break;
1817 case CTR:
1818 gen_op_load_ctr();
1819 break;
1820 case IBAT0U:
1821 gen_op_load_ibat(0, 0);
1822 break;
1823 case IBAT1U:
1824 gen_op_load_ibat(0, 1);
1825 break;
1826 case IBAT2U:
1827 gen_op_load_ibat(0, 2);
1828 break;
1829 case IBAT3U:
1830 gen_op_load_ibat(0, 3);
1831 break;
1832 case IBAT4U:
1833 gen_op_load_ibat(0, 4);
1834 break;
1835 case IBAT5U:
1836 gen_op_load_ibat(0, 5);
1837 break;
1838 case IBAT6U:
1839 gen_op_load_ibat(0, 6);
1840 break;
1841 case IBAT7U:
1842 gen_op_load_ibat(0, 7);
1843 break;
1844 case IBAT0L:
1845 gen_op_load_ibat(1, 0);
1846 break;
1847 case IBAT1L:
1848 gen_op_load_ibat(1, 1);
1849 break;
1850 case IBAT2L:
1851 gen_op_load_ibat(1, 2);
1852 break;
1853 case IBAT3L:
1854 gen_op_load_ibat(1, 3);
1855 break;
1856 case IBAT4L:
1857 gen_op_load_ibat(1, 4);
1858 break;
1859 case IBAT5L:
1860 gen_op_load_ibat(1, 5);
1861 break;
1862 case IBAT6L:
1863 gen_op_load_ibat(1, 6);
1864 break;
1865 case IBAT7L:
1866 gen_op_load_ibat(1, 7);
1867 break;
1868 case DBAT0U:
1869 gen_op_load_dbat(0, 0);
1870 break;
1871 case DBAT1U:
1872 gen_op_load_dbat(0, 1);
1873 break;
1874 case DBAT2U:
1875 gen_op_load_dbat(0, 2);
1876 break;
1877 case DBAT3U:
1878 gen_op_load_dbat(0, 3);
1879 break;
1880 case DBAT4U:
1881 gen_op_load_dbat(0, 4);
1882 break;
1883 case DBAT5U:
1884 gen_op_load_dbat(0, 5);
1885 break;
1886 case DBAT6U:
1887 gen_op_load_dbat(0, 6);
1888 break;
1889 case DBAT7U:
1890 gen_op_load_dbat(0, 7);
1891 break;
1892 case DBAT0L:
1893 gen_op_load_dbat(1, 0);
1894 break;
1895 case DBAT1L:
1896 gen_op_load_dbat(1, 1);
1897 break;
1898 case DBAT2L:
1899 gen_op_load_dbat(1, 2);
1900 break;
1901 case DBAT3L:
1902 gen_op_load_dbat(1, 3);
1903 break;
1904 case DBAT4L:
1905 gen_op_load_dbat(1, 4);
1906 break;
1907 case DBAT5L:
1908 gen_op_load_dbat(1, 5);
1909 break;
1910 case DBAT6L:
1911 gen_op_load_dbat(1, 6);
1912 break;
1913 case DBAT7L:
1914 gen_op_load_dbat(1, 7);
1915 break;
1916 case SDR1:
1917 gen_op_load_sdr1();
1918 break;
1919 case V_TBL:
9fddaa0c 1920 gen_op_load_tbl();
79aceca5 1921 break;
9a64fbe4 1922 case V_TBU:
9fddaa0c 1923 gen_op_load_tbu();
9a64fbe4
FB
1924 break;
1925 case DECR:
9fddaa0c 1926 gen_op_load_decr();
79aceca5
FB
1927 break;
1928 default:
1929 gen_op_load_spr(sprn);
1930 break;
1931 }
9a64fbe4 1932 gen_op_store_T0_gpr(rD(ctx->opcode));
79aceca5
FB
1933}
1934
1935/* mftb */
1936GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_MISC)
1937{
1938 uint32_t sprn = SPR(ctx->opcode);
1939
79aceca5 1940 /* We need to update the time base before reading it */
9a64fbe4
FB
1941 switch (sprn) {
1942 case V_TBL:
9fddaa0c 1943 gen_op_load_tbl();
79aceca5 1944 break;
9a64fbe4 1945 case V_TBU:
9fddaa0c 1946 gen_op_load_tbu();
79aceca5
FB
1947 break;
1948 default:
9fddaa0c
FB
1949 RET_INVAL(ctx);
1950 return;
79aceca5 1951 }
9a64fbe4 1952 gen_op_store_T0_gpr(rD(ctx->opcode));
79aceca5
FB
1953}
1954
1955/* mtcrf */
1956GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00100801, PPC_MISC)
1957{
1958 gen_op_load_gpr_T0(rS(ctx->opcode));
1959 gen_op_store_cr(CRM(ctx->opcode));
79aceca5
FB
1960}
1961
1962/* mtmsr */
1963GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC)
1964{
9a64fbe4 1965#if defined(CONFIG_USER_ONLY)
9fddaa0c 1966 RET_PRIVREG(ctx);
9a64fbe4
FB
1967#else
1968 if (!ctx->supervisor) {
9fddaa0c
FB
1969 RET_PRIVREG(ctx);
1970 return;
9a64fbe4 1971 }
79aceca5
FB
1972 gen_op_load_gpr_T0(rS(ctx->opcode));
1973 gen_op_store_msr();
1974 /* Must stop the translation as machine state (may have) changed */
9fddaa0c 1975 RET_MTMSR(ctx);
9a64fbe4 1976#endif
79aceca5
FB
1977}
1978
1979/* mtspr */
1980GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC)
1981{
1982 uint32_t sprn = SPR(ctx->opcode);
1983
9a64fbe4
FB
1984#if 0
1985 if (loglevel > 0) {
1986 fprintf(logfile, "MTSPR %d src=%d (%d)\n", SPR_ENCODE(sprn),
1987 rS(ctx->opcode), sprn);
1988 }
1989#endif
1990#if defined(CONFIG_USER_ONLY)
1991 switch (check_spr_access(sprn, 1, 0))
1992#else
1993 switch (check_spr_access(sprn, 1, ctx->supervisor))
1994#endif
1995 {
1996 case -1:
9fddaa0c 1997 RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
9a64fbe4
FB
1998 break;
1999 case 0:
9fddaa0c 2000 RET_PRIVREG(ctx);
9a64fbe4
FB
2001 break;
2002 default:
2003 break;
2004 }
79aceca5 2005 gen_op_load_gpr_T0(rS(ctx->opcode));
9a64fbe4
FB
2006 switch (sprn) {
2007 case XER:
79aceca5 2008 gen_op_store_xer();
9a64fbe4
FB
2009 break;
2010 case LR:
9a64fbe4
FB
2011 gen_op_store_lr();
2012 break;
2013 case CTR:
2014 gen_op_store_ctr();
2015 break;
2016 case IBAT0U:
2017 gen_op_store_ibat(0, 0);
4b3686fa 2018 RET_MTMSR(ctx);
9a64fbe4
FB
2019 break;
2020 case IBAT1U:
2021 gen_op_store_ibat(0, 1);
4b3686fa 2022 RET_MTMSR(ctx);
9a64fbe4
FB
2023 break;
2024 case IBAT2U:
2025 gen_op_store_ibat(0, 2);
4b3686fa 2026 RET_MTMSR(ctx);
9a64fbe4
FB
2027 break;
2028 case IBAT3U:
2029 gen_op_store_ibat(0, 3);
4b3686fa 2030 RET_MTMSR(ctx);
9a64fbe4
FB
2031 break;
2032 case IBAT4U:
2033 gen_op_store_ibat(0, 4);
4b3686fa 2034 RET_MTMSR(ctx);
9a64fbe4
FB
2035 break;
2036 case IBAT5U:
2037 gen_op_store_ibat(0, 5);
4b3686fa 2038 RET_MTMSR(ctx);
9a64fbe4
FB
2039 break;
2040 case IBAT6U:
2041 gen_op_store_ibat(0, 6);
4b3686fa 2042 RET_MTMSR(ctx);
9a64fbe4
FB
2043 break;
2044 case IBAT7U:
2045 gen_op_store_ibat(0, 7);
4b3686fa 2046 RET_MTMSR(ctx);
9a64fbe4
FB
2047 break;
2048 case IBAT0L:
2049 gen_op_store_ibat(1, 0);
4b3686fa 2050 RET_MTMSR(ctx);
9a64fbe4
FB
2051 break;
2052 case IBAT1L:
2053 gen_op_store_ibat(1, 1);
4b3686fa 2054 RET_MTMSR(ctx);
9a64fbe4
FB
2055 break;
2056 case IBAT2L:
2057 gen_op_store_ibat(1, 2);
4b3686fa 2058 RET_MTMSR(ctx);
9a64fbe4
FB
2059 break;
2060 case IBAT3L:
2061 gen_op_store_ibat(1, 3);
4b3686fa 2062 RET_MTMSR(ctx);
9a64fbe4
FB
2063 break;
2064 case IBAT4L:
2065 gen_op_store_ibat(1, 4);
4b3686fa 2066 RET_MTMSR(ctx);
9a64fbe4
FB
2067 break;
2068 case IBAT5L:
2069 gen_op_store_ibat(1, 5);
4b3686fa 2070 RET_MTMSR(ctx);
9a64fbe4
FB
2071 break;
2072 case IBAT6L:
2073 gen_op_store_ibat(1, 6);
4b3686fa 2074 RET_MTMSR(ctx);
9a64fbe4
FB
2075 break;
2076 case IBAT7L:
2077 gen_op_store_ibat(1, 7);
4b3686fa 2078 RET_MTMSR(ctx);
9a64fbe4
FB
2079 break;
2080 case DBAT0U:
2081 gen_op_store_dbat(0, 0);
4b3686fa 2082 RET_MTMSR(ctx);
9a64fbe4
FB
2083 break;
2084 case DBAT1U:
2085 gen_op_store_dbat(0, 1);
4b3686fa 2086 RET_MTMSR(ctx);
9a64fbe4
FB
2087 break;
2088 case DBAT2U:
2089 gen_op_store_dbat(0, 2);
4b3686fa 2090 RET_MTMSR(ctx);
9a64fbe4
FB
2091 break;
2092 case DBAT3U:
2093 gen_op_store_dbat(0, 3);
4b3686fa 2094 RET_MTMSR(ctx);
9a64fbe4
FB
2095 break;
2096 case DBAT4U:
2097 gen_op_store_dbat(0, 4);
4b3686fa 2098 RET_MTMSR(ctx);
9a64fbe4
FB
2099 break;
2100 case DBAT5U:
2101 gen_op_store_dbat(0, 5);
4b3686fa 2102 RET_MTMSR(ctx);
9a64fbe4
FB
2103 break;
2104 case DBAT6U:
2105 gen_op_store_dbat(0, 6);
4b3686fa 2106 RET_MTMSR(ctx);
9a64fbe4
FB
2107 break;
2108 case DBAT7U:
2109 gen_op_store_dbat(0, 7);
4b3686fa 2110 RET_MTMSR(ctx);
9a64fbe4
FB
2111 break;
2112 case DBAT0L:
2113 gen_op_store_dbat(1, 0);
4b3686fa 2114 RET_MTMSR(ctx);
9a64fbe4
FB
2115 break;
2116 case DBAT1L:
2117 gen_op_store_dbat(1, 1);
4b3686fa 2118 RET_MTMSR(ctx);
9a64fbe4
FB
2119 break;
2120 case DBAT2L:
2121 gen_op_store_dbat(1, 2);
4b3686fa 2122 RET_MTMSR(ctx);
9a64fbe4
FB
2123 break;
2124 case DBAT3L:
2125 gen_op_store_dbat(1, 3);
4b3686fa 2126 RET_MTMSR(ctx);
9a64fbe4
FB
2127 break;
2128 case DBAT4L:
2129 gen_op_store_dbat(1, 4);
4b3686fa 2130 RET_MTMSR(ctx);
9a64fbe4
FB
2131 break;
2132 case DBAT5L:
2133 gen_op_store_dbat(1, 5);
4b3686fa 2134 RET_MTMSR(ctx);
9a64fbe4
FB
2135 break;
2136 case DBAT6L:
2137 gen_op_store_dbat(1, 6);
4b3686fa 2138 RET_MTMSR(ctx);
9a64fbe4
FB
2139 break;
2140 case DBAT7L:
2141 gen_op_store_dbat(1, 7);
4b3686fa 2142 RET_MTMSR(ctx);
9a64fbe4
FB
2143 break;
2144 case SDR1:
2145 gen_op_store_sdr1();
4b3686fa 2146 RET_MTMSR(ctx);
9a64fbe4
FB
2147 break;
2148 case O_TBL:
9fddaa0c 2149 gen_op_store_tbl();
9a64fbe4
FB
2150 break;
2151 case O_TBU:
9fddaa0c 2152 gen_op_store_tbu();
9a64fbe4
FB
2153 break;
2154 case DECR:
2155 gen_op_store_decr();
9a64fbe4 2156 break;
4b3686fa
FB
2157#if 0
2158 case HID0:
2159 gen_op_store_hid0();
2160 break;
2161#endif
9a64fbe4 2162 default:
79aceca5 2163 gen_op_store_spr(sprn);
9a64fbe4 2164 break;
79aceca5 2165 }
79aceca5
FB
2166}
2167
2168/*** Cache management ***/
2169/* For now, all those will be implemented as nop:
2170 * this is valid, regarding the PowerPC specs...
9a64fbe4 2171 * We just have to flush tb while invalidating instruction cache lines...
79aceca5
FB
2172 */
2173/* dcbf */
9a64fbe4 2174GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03E00001, PPC_CACHE)
79aceca5 2175{
a541f297
FB
2176 if (rA(ctx->opcode) == 0) {
2177 gen_op_load_gpr_T0(rB(ctx->opcode));
2178 } else {
2179 gen_op_load_gpr_T0(rA(ctx->opcode));
2180 gen_op_load_gpr_T1(rB(ctx->opcode));
2181 gen_op_add();
2182 }
2183 op_ldst(lbz);
79aceca5
FB
2184}
2185
2186/* dcbi (Supervisor only) */
9a64fbe4 2187GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE)
79aceca5 2188{
a541f297 2189#if defined(CONFIG_USER_ONLY)
9fddaa0c 2190 RET_PRIVOPC(ctx);
a541f297
FB
2191#else
2192 if (!ctx->supervisor) {
9fddaa0c
FB
2193 RET_PRIVOPC(ctx);
2194 return;
9a64fbe4 2195 }
a541f297
FB
2196 if (rA(ctx->opcode) == 0) {
2197 gen_op_load_gpr_T0(rB(ctx->opcode));
2198 } else {
2199 gen_op_load_gpr_T0(rA(ctx->opcode));
2200 gen_op_load_gpr_T1(rB(ctx->opcode));
2201 gen_op_add();
2202 }
2203 op_ldst(lbz);
2204 op_ldst(stb);
2205#endif
79aceca5
FB
2206}
2207
2208/* dcdst */
9a64fbe4 2209GEN_HANDLER(dcbst, 0x1F, 0x16, 0x01, 0x03E00001, PPC_CACHE)
79aceca5 2210{
a541f297
FB
2211 if (rA(ctx->opcode) == 0) {
2212 gen_op_load_gpr_T0(rB(ctx->opcode));
2213 } else {
2214 gen_op_load_gpr_T0(rA(ctx->opcode));
2215 gen_op_load_gpr_T1(rB(ctx->opcode));
2216 gen_op_add();
2217 }
2218 op_ldst(lbz);
79aceca5
FB
2219}
2220
2221/* dcbt */
9a64fbe4 2222GEN_HANDLER(dcbt, 0x1F, 0x16, 0x08, 0x03E00001, PPC_CACHE)
79aceca5 2223{
79aceca5
FB
2224}
2225
2226/* dcbtst */
9a64fbe4 2227GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x03E00001, PPC_CACHE)
79aceca5 2228{
79aceca5
FB
2229}
2230
2231/* dcbz */
9a64fbe4
FB
2232#if defined(CONFIG_USER_ONLY)
2233#define op_dcbz() gen_op_dcbz_raw()
2234#else
2235#define op_dcbz() (*gen_op_dcbz[ctx->mem_idx])()
2236static GenOpFunc *gen_op_dcbz[] = {
2237 &gen_op_dcbz_user,
2238 &gen_op_dcbz_kernel,
2239};
2240#endif
2241
2242GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE)
79aceca5 2243{
fb0eaffc
FB
2244 if (rA(ctx->opcode) == 0) {
2245 gen_op_load_gpr_T0(rB(ctx->opcode));
fb0eaffc
FB
2246 } else {
2247 gen_op_load_gpr_T0(rA(ctx->opcode));
2248 gen_op_load_gpr_T1(rB(ctx->opcode));
9a64fbe4 2249 gen_op_add();
fb0eaffc 2250 }
9a64fbe4 2251 op_dcbz();
4b3686fa 2252 gen_op_check_reservation();
79aceca5
FB
2253}
2254
2255/* icbi */
9a64fbe4 2256GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_CACHE)
79aceca5 2257{
fb0eaffc
FB
2258 if (rA(ctx->opcode) == 0) {
2259 gen_op_load_gpr_T0(rB(ctx->opcode));
fb0eaffc
FB
2260 } else {
2261 gen_op_load_gpr_T0(rA(ctx->opcode));
2262 gen_op_load_gpr_T1(rB(ctx->opcode));
9a64fbe4 2263 gen_op_add();
fb0eaffc 2264 }
9a64fbe4 2265 gen_op_icbi();
79aceca5
FB
2266}
2267
2268/* Optional: */
2269/* dcba */
9a64fbe4 2270GEN_HANDLER(dcba, 0x1F, 0x16, 0x07, 0x03E00001, PPC_CACHE_OPT)
79aceca5 2271{
79aceca5
FB
2272}
2273
2274/*** Segment register manipulation ***/
2275/* Supervisor only: */
2276/* mfsr */
2277GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT)
2278{
9a64fbe4 2279#if defined(CONFIG_USER_ONLY)
9fddaa0c 2280 RET_PRIVREG(ctx);
9a64fbe4
FB
2281#else
2282 if (!ctx->supervisor) {
9fddaa0c
FB
2283 RET_PRIVREG(ctx);
2284 return;
9a64fbe4
FB
2285 }
2286 gen_op_load_sr(SR(ctx->opcode));
2287 gen_op_store_T0_gpr(rD(ctx->opcode));
2288#endif
79aceca5
FB
2289}
2290
2291/* mfsrin */
9a64fbe4 2292GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT)
79aceca5 2293{
9a64fbe4 2294#if defined(CONFIG_USER_ONLY)
9fddaa0c 2295 RET_PRIVREG(ctx);
9a64fbe4
FB
2296#else
2297 if (!ctx->supervisor) {
9fddaa0c
FB
2298 RET_PRIVREG(ctx);
2299 return;
9a64fbe4
FB
2300 }
2301 gen_op_load_gpr_T1(rB(ctx->opcode));
2302 gen_op_load_srin();
2303 gen_op_store_T0_gpr(rD(ctx->opcode));
2304#endif
79aceca5
FB
2305}
2306
2307/* mtsr */
e63c59cb 2308GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT)
79aceca5 2309{
9a64fbe4 2310#if defined(CONFIG_USER_ONLY)
9fddaa0c 2311 RET_PRIVREG(ctx);
9a64fbe4
FB
2312#else
2313 if (!ctx->supervisor) {
9fddaa0c
FB
2314 RET_PRIVREG(ctx);
2315 return;
9a64fbe4
FB
2316 }
2317 gen_op_load_gpr_T0(rS(ctx->opcode));
2318 gen_op_store_sr(SR(ctx->opcode));
9a64fbe4 2319#endif
79aceca5
FB
2320}
2321
2322/* mtsrin */
9a64fbe4 2323GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT)
79aceca5 2324{
9a64fbe4 2325#if defined(CONFIG_USER_ONLY)
9fddaa0c 2326 RET_PRIVREG(ctx);
9a64fbe4
FB
2327#else
2328 if (!ctx->supervisor) {
9fddaa0c
FB
2329 RET_PRIVREG(ctx);
2330 return;
9a64fbe4
FB
2331 }
2332 gen_op_load_gpr_T0(rS(ctx->opcode));
2333 gen_op_load_gpr_T1(rB(ctx->opcode));
2334 gen_op_store_srin();
9a64fbe4 2335#endif
79aceca5
FB
2336}
2337
2338/*** Lookaside buffer management ***/
2339/* Optional & supervisor only: */
2340/* tlbia */
9a64fbe4 2341GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_OPT)
79aceca5 2342{
9a64fbe4 2343#if defined(CONFIG_USER_ONLY)
9fddaa0c 2344 RET_PRIVOPC(ctx);
9a64fbe4
FB
2345#else
2346 if (!ctx->supervisor) {
9fddaa0c
FB
2347 if (loglevel)
2348 fprintf(logfile, "%s: ! supervisor\n", __func__);
2349 RET_PRIVOPC(ctx);
2350 return;
9a64fbe4
FB
2351 }
2352 gen_op_tlbia();
4b3686fa 2353 RET_MTMSR(ctx);
9a64fbe4 2354#endif
79aceca5
FB
2355}
2356
2357/* tlbie */
9a64fbe4 2358GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM)
79aceca5 2359{
9a64fbe4 2360#if defined(CONFIG_USER_ONLY)
9fddaa0c 2361 RET_PRIVOPC(ctx);
9a64fbe4
FB
2362#else
2363 if (!ctx->supervisor) {
9fddaa0c
FB
2364 RET_PRIVOPC(ctx);
2365 return;
9a64fbe4
FB
2366 }
2367 gen_op_load_gpr_T0(rB(ctx->opcode));
2368 gen_op_tlbie();
4b3686fa 2369 RET_MTMSR(ctx);
9a64fbe4 2370#endif
79aceca5
FB
2371}
2372
2373/* tlbsync */
e63c59cb 2374GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM)
79aceca5 2375{
9a64fbe4 2376#if defined(CONFIG_USER_ONLY)
9fddaa0c 2377 RET_PRIVOPC(ctx);
9a64fbe4
FB
2378#else
2379 if (!ctx->supervisor) {
9fddaa0c
FB
2380 RET_PRIVOPC(ctx);
2381 return;
9a64fbe4
FB
2382 }
2383 /* This has no effect: it should ensure that all previous
2384 * tlbie have completed
2385 */
4b3686fa 2386 RET_MTMSR(ctx);
9a64fbe4 2387#endif
79aceca5
FB
2388}
2389
2390/*** External control ***/
2391/* Optional: */
2392/* eciwx */
9a64fbe4
FB
2393#if defined(CONFIG_USER_ONLY)
2394#define op_eciwx() gen_op_eciwx_raw()
2395#define op_ecowx() gen_op_ecowx_raw()
2396#else
2397#define op_eciwx() (*gen_op_eciwx[ctx->mem_idx])()
2398#define op_ecowx() (*gen_op_ecowx[ctx->mem_idx])()
2399static GenOpFunc *gen_op_eciwx[] = {
2400 &gen_op_eciwx_user,
2401 &gen_op_eciwx_kernel,
2402};
2403static GenOpFunc *gen_op_ecowx[] = {
2404 &gen_op_ecowx_user,
2405 &gen_op_ecowx_kernel,
2406};
2407#endif
2408
79aceca5
FB
2409GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN)
2410{
9a64fbe4
FB
2411 /* Should check EAR[E] & alignment ! */
2412 if (rA(ctx->opcode) == 0) {
2413 gen_op_load_gpr_T0(rB(ctx->opcode));
2414 } else {
2415 gen_op_load_gpr_T0(rA(ctx->opcode));
2416 gen_op_load_gpr_T1(rB(ctx->opcode));
2417 gen_op_add();
2418 }
2419 op_eciwx();
2420 gen_op_store_T0_gpr(rD(ctx->opcode));
79aceca5
FB
2421}
2422
2423/* ecowx */
2424GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN)
2425{
9a64fbe4
FB
2426 /* Should check EAR[E] & alignment ! */
2427 if (rA(ctx->opcode) == 0) {
2428 gen_op_load_gpr_T0(rB(ctx->opcode));
2429 } else {
2430 gen_op_load_gpr_T0(rA(ctx->opcode));
2431 gen_op_load_gpr_T1(rB(ctx->opcode));
2432 gen_op_add();
2433 }
2434 gen_op_load_gpr_T2(rS(ctx->opcode));
2435 op_ecowx();
79aceca5
FB
2436}
2437
2438/* End opcode list */
2439GEN_OPCODE_MARK(end);
2440
2441/*****************************************************************************/
9a64fbe4 2442#include <stdlib.h>
79aceca5 2443#include <string.h>
9a64fbe4
FB
2444
2445int fflush (FILE *stream);
79aceca5
FB
2446
2447/* Main ppc opcodes table:
2448 * at init, all opcodes are invalids
2449 */
2450static opc_handler_t *ppc_opcodes[0x40];
2451
2452/* Opcode types */
2453enum {
2454 PPC_DIRECT = 0, /* Opcode routine */
2455 PPC_INDIRECT = 1, /* Indirect opcode table */
2456};
2457
2458static inline int is_indirect_opcode (void *handler)
2459{
2460 return ((unsigned long)handler & 0x03) == PPC_INDIRECT;
2461}
2462
2463static inline opc_handler_t **ind_table(void *handler)
2464{
2465 return (opc_handler_t **)((unsigned long)handler & ~3);
2466}
2467
9a64fbe4 2468/* Instruction table creation */
79aceca5
FB
2469/* Opcodes tables creation */
2470static void fill_new_table (opc_handler_t **table, int len)
2471{
2472 int i;
2473
2474 for (i = 0; i < len; i++)
2475 table[i] = &invalid_handler;
2476}
2477
2478static int create_new_table (opc_handler_t **table, unsigned char idx)
2479{
2480 opc_handler_t **tmp;
2481
2482 tmp = malloc(0x20 * sizeof(opc_handler_t));
2483 if (tmp == NULL)
2484 return -1;
2485 fill_new_table(tmp, 0x20);
2486 table[idx] = (opc_handler_t *)((unsigned long)tmp | PPC_INDIRECT);
2487
2488 return 0;
2489}
2490
2491static int insert_in_table (opc_handler_t **table, unsigned char idx,
2492 opc_handler_t *handler)
2493{
2494 if (table[idx] != &invalid_handler)
2495 return -1;
2496 table[idx] = handler;
2497
2498 return 0;
2499}
2500
9a64fbe4
FB
2501static int register_direct_insn (opc_handler_t **ppc_opcodes,
2502 unsigned char idx, opc_handler_t *handler)
79aceca5
FB
2503{
2504 if (insert_in_table(ppc_opcodes, idx, handler) < 0) {
9a64fbe4 2505 printf("*** ERROR: opcode %02x already assigned in main "
79aceca5
FB
2506 "opcode table\n", idx);
2507 return -1;
2508 }
2509
2510 return 0;
2511}
2512
2513static int register_ind_in_table (opc_handler_t **table,
2514 unsigned char idx1, unsigned char idx2,
2515 opc_handler_t *handler)
2516{
2517 if (table[idx1] == &invalid_handler) {
2518 if (create_new_table(table, idx1) < 0) {
9a64fbe4 2519 printf("*** ERROR: unable to create indirect table "
79aceca5
FB
2520 "idx=%02x\n", idx1);
2521 return -1;
2522 }
2523 } else {
2524 if (!is_indirect_opcode(table[idx1])) {
9a64fbe4 2525 printf("*** ERROR: idx %02x already assigned to a direct "
79aceca5
FB
2526 "opcode\n", idx1);
2527 return -1;
2528 }
2529 }
2530 if (handler != NULL &&
2531 insert_in_table(ind_table(table[idx1]), idx2, handler) < 0) {
9a64fbe4 2532 printf("*** ERROR: opcode %02x already assigned in "
79aceca5
FB
2533 "opcode table %02x\n", idx2, idx1);
2534 return -1;
2535 }
2536
2537 return 0;
2538}
2539
9a64fbe4
FB
2540static int register_ind_insn (opc_handler_t **ppc_opcodes,
2541 unsigned char idx1, unsigned char idx2,
79aceca5
FB
2542 opc_handler_t *handler)
2543{
2544 int ret;
2545
2546 ret = register_ind_in_table(ppc_opcodes, idx1, idx2, handler);
2547
2548 return ret;
2549}
2550
9a64fbe4
FB
2551static int register_dblind_insn (opc_handler_t **ppc_opcodes,
2552 unsigned char idx1, unsigned char idx2,
79aceca5
FB
2553 unsigned char idx3, opc_handler_t *handler)
2554{
2555 if (register_ind_in_table(ppc_opcodes, idx1, idx2, NULL) < 0) {
9a64fbe4 2556 printf("*** ERROR: unable to join indirect table idx "
79aceca5
FB
2557 "[%02x-%02x]\n", idx1, idx2);
2558 return -1;
2559 }
2560 if (register_ind_in_table(ind_table(ppc_opcodes[idx1]), idx2, idx3,
2561 handler) < 0) {
9a64fbe4 2562 printf("*** ERROR: unable to insert opcode "
79aceca5
FB
2563 "[%02x-%02x-%02x]\n", idx1, idx2, idx3);
2564 return -1;
2565 }
2566
2567 return 0;
2568}
2569
9a64fbe4 2570static int register_insn (opc_handler_t **ppc_opcodes, opcode_t *insn)
79aceca5
FB
2571{
2572 if (insn->opc2 != 0xFF) {
2573 if (insn->opc3 != 0xFF) {
9a64fbe4
FB
2574 if (register_dblind_insn(ppc_opcodes, insn->opc1, insn->opc2,
2575 insn->opc3, &insn->handler) < 0)
79aceca5
FB
2576 return -1;
2577 } else {
9a64fbe4
FB
2578 if (register_ind_insn(ppc_opcodes, insn->opc1,
2579 insn->opc2, &insn->handler) < 0)
79aceca5
FB
2580 return -1;
2581 }
2582 } else {
9a64fbe4 2583 if (register_direct_insn(ppc_opcodes, insn->opc1, &insn->handler) < 0)
79aceca5
FB
2584 return -1;
2585 }
2586
2587 return 0;
2588}
2589
2590static int test_opcode_table (opc_handler_t **table, int len)
2591{
2592 int i, count, tmp;
2593
2594 for (i = 0, count = 0; i < len; i++) {
2595 /* Consistency fixup */
2596 if (table[i] == NULL)
2597 table[i] = &invalid_handler;
2598 if (table[i] != &invalid_handler) {
2599 if (is_indirect_opcode(table[i])) {
2600 tmp = test_opcode_table(ind_table(table[i]), 0x20);
2601 if (tmp == 0) {
2602 free(table[i]);
2603 table[i] = &invalid_handler;
2604 } else {
2605 count++;
2606 }
2607 } else {
2608 count++;
2609 }
2610 }
2611 }
2612
2613 return count;
2614}
2615
9a64fbe4 2616static void fix_opcode_tables (opc_handler_t **ppc_opcodes)
79aceca5
FB
2617{
2618 if (test_opcode_table(ppc_opcodes, 0x40) == 0)
9a64fbe4 2619 printf("*** WARNING: no opcode defined !\n");
79aceca5
FB
2620}
2621
9a64fbe4 2622#define SPR_RIGHTS(rw, priv) (1 << ((2 * (priv)) + (rw)))
79aceca5
FB
2623#define SPR_UR SPR_RIGHTS(0, 0)
2624#define SPR_UW SPR_RIGHTS(1, 0)
2625#define SPR_SR SPR_RIGHTS(0, 1)
2626#define SPR_SW SPR_RIGHTS(1, 1)
2627
2628#define spr_set_rights(spr, rights) \
2629do { \
2630 spr_access[(spr) >> 1] |= ((rights) << (4 * ((spr) & 1))); \
2631} while (0)
2632
9a64fbe4 2633static void init_spr_rights (uint32_t pvr)
79aceca5
FB
2634{
2635 /* XER (SPR 1) */
9a64fbe4 2636 spr_set_rights(XER, SPR_UR | SPR_UW | SPR_SR | SPR_SW);
79aceca5 2637 /* LR (SPR 8) */
9a64fbe4 2638 spr_set_rights(LR, SPR_UR | SPR_UW | SPR_SR | SPR_SW);
79aceca5 2639 /* CTR (SPR 9) */
9a64fbe4 2640 spr_set_rights(CTR, SPR_UR | SPR_UW | SPR_SR | SPR_SW);
79aceca5 2641 /* TBL (SPR 268) */
9a64fbe4 2642 spr_set_rights(V_TBL, SPR_UR | SPR_SR);
79aceca5 2643 /* TBU (SPR 269) */
9a64fbe4 2644 spr_set_rights(V_TBU, SPR_UR | SPR_SR);
79aceca5 2645 /* DSISR (SPR 18) */
9a64fbe4 2646 spr_set_rights(DSISR, SPR_SR | SPR_SW);
79aceca5 2647 /* DAR (SPR 19) */
9a64fbe4 2648 spr_set_rights(DAR, SPR_SR | SPR_SW);
79aceca5 2649 /* DEC (SPR 22) */
9a64fbe4 2650 spr_set_rights(DECR, SPR_SR | SPR_SW);
79aceca5 2651 /* SDR1 (SPR 25) */
9a64fbe4
FB
2652 spr_set_rights(SDR1, SPR_SR | SPR_SW);
2653 /* SRR0 (SPR 26) */
2654 spr_set_rights(SRR0, SPR_SR | SPR_SW);
2655 /* SRR1 (SPR 27) */
2656 spr_set_rights(SRR1, SPR_SR | SPR_SW);
79aceca5 2657 /* SPRG0 (SPR 272) */
9a64fbe4 2658 spr_set_rights(SPRG0, SPR_SR | SPR_SW);
79aceca5 2659 /* SPRG1 (SPR 273) */
9a64fbe4 2660 spr_set_rights(SPRG1, SPR_SR | SPR_SW);
79aceca5 2661 /* SPRG2 (SPR 274) */
9a64fbe4 2662 spr_set_rights(SPRG2, SPR_SR | SPR_SW);
79aceca5 2663 /* SPRG3 (SPR 275) */
9a64fbe4 2664 spr_set_rights(SPRG3, SPR_SR | SPR_SW);
79aceca5 2665 /* ASR (SPR 280) */
9a64fbe4 2666 spr_set_rights(ASR, SPR_SR | SPR_SW);
79aceca5 2667 /* EAR (SPR 282) */
9a64fbe4
FB
2668 spr_set_rights(EAR, SPR_SR | SPR_SW);
2669 /* TBL (SPR 284) */
2670 spr_set_rights(O_TBL, SPR_SW);
2671 /* TBU (SPR 285) */
2672 spr_set_rights(O_TBU, SPR_SW);
2673 /* PVR (SPR 287) */
2674 spr_set_rights(PVR, SPR_SR);
79aceca5 2675 /* IBAT0U (SPR 528) */
9a64fbe4 2676 spr_set_rights(IBAT0U, SPR_SR | SPR_SW);
79aceca5 2677 /* IBAT0L (SPR 529) */
9a64fbe4 2678 spr_set_rights(IBAT0L, SPR_SR | SPR_SW);
79aceca5 2679 /* IBAT1U (SPR 530) */
9a64fbe4 2680 spr_set_rights(IBAT1U, SPR_SR | SPR_SW);
79aceca5 2681 /* IBAT1L (SPR 531) */
9a64fbe4 2682 spr_set_rights(IBAT1L, SPR_SR | SPR_SW);
79aceca5 2683 /* IBAT2U (SPR 532) */
9a64fbe4 2684 spr_set_rights(IBAT2U, SPR_SR | SPR_SW);
79aceca5 2685 /* IBAT2L (SPR 533) */
9a64fbe4 2686 spr_set_rights(IBAT2L, SPR_SR | SPR_SW);
79aceca5 2687 /* IBAT3U (SPR 534) */
9a64fbe4 2688 spr_set_rights(IBAT3U, SPR_SR | SPR_SW);
79aceca5 2689 /* IBAT3L (SPR 535) */
9a64fbe4 2690 spr_set_rights(IBAT3L, SPR_SR | SPR_SW);
79aceca5 2691 /* DBAT0U (SPR 536) */
9a64fbe4 2692 spr_set_rights(DBAT0U, SPR_SR | SPR_SW);
79aceca5 2693 /* DBAT0L (SPR 537) */
9a64fbe4 2694 spr_set_rights(DBAT0L, SPR_SR | SPR_SW);
79aceca5 2695 /* DBAT1U (SPR 538) */
9a64fbe4 2696 spr_set_rights(DBAT1U, SPR_SR | SPR_SW);
79aceca5 2697 /* DBAT1L (SPR 539) */
9a64fbe4 2698 spr_set_rights(DBAT1L, SPR_SR | SPR_SW);
79aceca5 2699 /* DBAT2U (SPR 540) */
9a64fbe4 2700 spr_set_rights(DBAT2U, SPR_SR | SPR_SW);
79aceca5 2701 /* DBAT2L (SPR 541) */
9a64fbe4 2702 spr_set_rights(DBAT2L, SPR_SR | SPR_SW);
79aceca5 2703 /* DBAT3U (SPR 542) */
9a64fbe4 2704 spr_set_rights(DBAT3U, SPR_SR | SPR_SW);
79aceca5 2705 /* DBAT3L (SPR 543) */
9a64fbe4 2706 spr_set_rights(DBAT3L, SPR_SR | SPR_SW);
79aceca5 2707 /* FPECR (SPR 1022) */
9a64fbe4 2708 spr_set_rights(FPECR, SPR_SR | SPR_SW);
4b3686fa
FB
2709 /* Special registers for PPC 604 */
2710 if ((pvr & 0xFFFF0000) == 0x00040000) {
2711 /* IABR */
2712 spr_set_rights(IABR , SPR_SR | SPR_SW);
2713 /* DABR (SPR 1013) */
2714 spr_set_rights(DABR, SPR_SR | SPR_SW);
2715 /* HID0 */
2716 spr_set_rights(HID0, SPR_SR | SPR_SW);
2717 /* PIR */
9a64fbe4 2718 spr_set_rights(PIR, SPR_SR | SPR_SW);
4b3686fa
FB
2719 /* PMC1 */
2720 spr_set_rights(PMC1, SPR_SR | SPR_SW);
2721 /* PMC2 */
2722 spr_set_rights(PMC2, SPR_SR | SPR_SW);
2723 /* MMCR0 */
2724 spr_set_rights(MMCR0, SPR_SR | SPR_SW);
2725 /* SIA */
2726 spr_set_rights(SIA, SPR_SR | SPR_SW);
2727 /* SDA */
2728 spr_set_rights(SDA, SPR_SR | SPR_SW);
2729 }
9a64fbe4
FB
2730 /* Special registers for MPC740/745/750/755 (aka G3) & IBM 750 */
2731 if ((pvr & 0xFFFF0000) == 0x00080000 ||
2732 (pvr & 0xFFFF0000) == 0x70000000) {
2733 /* HID0 */
4b3686fa 2734 spr_set_rights(HID0, SPR_SR | SPR_SW);
9a64fbe4 2735 /* HID1 */
4b3686fa 2736 spr_set_rights(HID1, SPR_SR | SPR_SW);
9a64fbe4 2737 /* IABR */
4b3686fa 2738 spr_set_rights(IABR, SPR_SR | SPR_SW);
9a64fbe4 2739 /* ICTC */
4b3686fa 2740 spr_set_rights(ICTC, SPR_SR | SPR_SW);
9a64fbe4 2741 /* L2CR */
4b3686fa 2742 spr_set_rights(L2CR, SPR_SR | SPR_SW);
9a64fbe4 2743 /* MMCR0 */
4b3686fa 2744 spr_set_rights(MMCR0, SPR_SR | SPR_SW);
9a64fbe4 2745 /* MMCR1 */
4b3686fa 2746 spr_set_rights(MMCR1, SPR_SR | SPR_SW);
9a64fbe4 2747 /* PMC1 */
4b3686fa 2748 spr_set_rights(PMC1, SPR_SR | SPR_SW);
9a64fbe4 2749 /* PMC2 */
4b3686fa 2750 spr_set_rights(PMC2, SPR_SR | SPR_SW);
9a64fbe4 2751 /* PMC3 */
4b3686fa 2752 spr_set_rights(PMC3, SPR_SR | SPR_SW);
9a64fbe4 2753 /* PMC4 */
4b3686fa 2754 spr_set_rights(PMC4, SPR_SR | SPR_SW);
9a64fbe4 2755 /* SIA */
4b3686fa
FB
2756 spr_set_rights(SIA, SPR_SR | SPR_SW);
2757 /* SDA */
2758 spr_set_rights(SDA, SPR_SR | SPR_SW);
9a64fbe4 2759 /* THRM1 */
4b3686fa 2760 spr_set_rights(THRM1, SPR_SR | SPR_SW);
9a64fbe4 2761 /* THRM2 */
4b3686fa 2762 spr_set_rights(THRM2, SPR_SR | SPR_SW);
9a64fbe4 2763 /* THRM3 */
4b3686fa 2764 spr_set_rights(THRM3, SPR_SR | SPR_SW);
9a64fbe4 2765 /* UMMCR0 */
4b3686fa 2766 spr_set_rights(UMMCR0, SPR_UR | SPR_UW);
9a64fbe4 2767 /* UMMCR1 */
4b3686fa 2768 spr_set_rights(UMMCR1, SPR_UR | SPR_UW);
9a64fbe4 2769 /* UPMC1 */
4b3686fa 2770 spr_set_rights(UPMC1, SPR_UR | SPR_UW);
9a64fbe4 2771 /* UPMC2 */
4b3686fa 2772 spr_set_rights(UPMC2, SPR_UR | SPR_UW);
9a64fbe4 2773 /* UPMC3 */
4b3686fa 2774 spr_set_rights(UPMC3, SPR_UR | SPR_UW);
9a64fbe4 2775 /* UPMC4 */
4b3686fa 2776 spr_set_rights(UPMC4, SPR_UR | SPR_UW);
9a64fbe4 2777 /* USIA */
4b3686fa 2778 spr_set_rights(USIA, SPR_UR | SPR_UW);
9a64fbe4
FB
2779 }
2780 /* MPC755 has special registers */
2781 if (pvr == 0x00083100) {
2782 /* SPRG4 */
2783 spr_set_rights(SPRG4, SPR_SR | SPR_SW);
2784 /* SPRG5 */
2785 spr_set_rights(SPRG5, SPR_SR | SPR_SW);
2786 /* SPRG6 */
2787 spr_set_rights(SPRG6, SPR_SR | SPR_SW);
2788 /* SPRG7 */
2789 spr_set_rights(SPRG7, SPR_SR | SPR_SW);
2790 /* IBAT4U */
2791 spr_set_rights(IBAT4U, SPR_SR | SPR_SW);
2792 /* IBAT4L */
2793 spr_set_rights(IBAT4L, SPR_SR | SPR_SW);
2794 /* IBAT5U */
2795 spr_set_rights(IBAT5U, SPR_SR | SPR_SW);
2796 /* IBAT5L */
2797 spr_set_rights(IBAT5L, SPR_SR | SPR_SW);
2798 /* IBAT6U */
2799 spr_set_rights(IBAT6U, SPR_SR | SPR_SW);
2800 /* IBAT6L */
2801 spr_set_rights(IBAT6L, SPR_SR | SPR_SW);
2802 /* IBAT7U */
2803 spr_set_rights(IBAT7U, SPR_SR | SPR_SW);
2804 /* IBAT7L */
2805 spr_set_rights(IBAT7L, SPR_SR | SPR_SW);
2806 /* DBAT4U */
2807 spr_set_rights(DBAT4U, SPR_SR | SPR_SW);
2808 /* DBAT4L */
2809 spr_set_rights(DBAT4L, SPR_SR | SPR_SW);
2810 /* DBAT5U */
2811 spr_set_rights(DBAT5U, SPR_SR | SPR_SW);
2812 /* DBAT5L */
2813 spr_set_rights(DBAT5L, SPR_SR | SPR_SW);
2814 /* DBAT6U */
2815 spr_set_rights(DBAT6U, SPR_SR | SPR_SW);
2816 /* DBAT6L */
2817 spr_set_rights(DBAT6L, SPR_SR | SPR_SW);
2818 /* DBAT7U */
2819 spr_set_rights(DBAT7U, SPR_SR | SPR_SW);
2820 /* DBAT7L */
2821 spr_set_rights(DBAT7L, SPR_SR | SPR_SW);
2822 /* DMISS */
4b3686fa 2823 spr_set_rights(DMISS, SPR_SR | SPR_SW);
9a64fbe4 2824 /* DCMP */
4b3686fa 2825 spr_set_rights(DCMP, SPR_SR | SPR_SW);
9a64fbe4 2826 /* DHASH1 */
4b3686fa 2827 spr_set_rights(DHASH1, SPR_SR | SPR_SW);
9a64fbe4 2828 /* DHASH2 */
4b3686fa 2829 spr_set_rights(DHASH2, SPR_SR | SPR_SW);
9a64fbe4 2830 /* IMISS */
4b3686fa 2831 spr_set_rights(IMISS, SPR_SR | SPR_SW);
9a64fbe4 2832 /* ICMP */
4b3686fa 2833 spr_set_rights(ICMP, SPR_SR | SPR_SW);
9a64fbe4 2834 /* RPA */
4b3686fa 2835 spr_set_rights(RPA, SPR_SR | SPR_SW);
9a64fbe4 2836 /* HID2 */
4b3686fa 2837 spr_set_rights(HID2, SPR_SR | SPR_SW);
9a64fbe4 2838 /* L2PM */
4b3686fa 2839 spr_set_rights(L2PM, SPR_SR | SPR_SW);
9a64fbe4 2840 }
79aceca5
FB
2841}
2842
9a64fbe4
FB
2843/*****************************************************************************/
2844/* PPC "main stream" common instructions (no optional ones) */
79aceca5
FB
2845
2846typedef struct ppc_proc_t {
2847 int flags;
2848 void *specific;
2849} ppc_proc_t;
2850
2851typedef struct ppc_def_t {
2852 unsigned long pvr;
2853 unsigned long pvr_mask;
2854 ppc_proc_t *proc;
2855} ppc_def_t;
2856
2857static ppc_proc_t ppc_proc_common = {
2858 .flags = PPC_COMMON,
2859 .specific = NULL,
2860};
2861
9a64fbe4
FB
2862static ppc_proc_t ppc_proc_G3 = {
2863 .flags = PPC_750,
2864 .specific = NULL,
2865};
2866
79aceca5
FB
2867static ppc_def_t ppc_defs[] =
2868{
9a64fbe4
FB
2869 /* MPC740/745/750/755 (G3) */
2870 {
2871 .pvr = 0x00080000,
2872 .pvr_mask = 0xFFFF0000,
2873 .proc = &ppc_proc_G3,
2874 },
2875 /* IBM 750FX (G3 embedded) */
2876 {
2877 .pvr = 0x70000000,
2878 .pvr_mask = 0xFFFF0000,
2879 .proc = &ppc_proc_G3,
2880 },
2881 /* Fallback (generic PPC) */
79aceca5
FB
2882 {
2883 .pvr = 0x00000000,
2884 .pvr_mask = 0x00000000,
2885 .proc = &ppc_proc_common,
2886 },
2887};
2888
9a64fbe4 2889static int create_ppc_proc (opc_handler_t **ppc_opcodes, unsigned long pvr)
79aceca5
FB
2890{
2891 opcode_t *opc;
2892 int i, flags;
2893
2894 fill_new_table(ppc_opcodes, 0x40);
2895 for (i = 0; ; i++) {
2896 if ((ppc_defs[i].pvr & ppc_defs[i].pvr_mask) ==
2897 (pvr & ppc_defs[i].pvr_mask)) {
2898 flags = ppc_defs[i].proc->flags;
2899 break;
2900 }
2901 }
2902
2903 for (opc = &opc_start + 1; opc != &opc_end; opc++) {
9a64fbe4
FB
2904 if ((opc->handler.type & flags) != 0)
2905 if (register_insn(ppc_opcodes, opc) < 0) {
2906 printf("*** ERROR initializing PPC instruction "
79aceca5
FB
2907 "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2,
2908 opc->opc3);
2909 return -1;
2910 }
2911 }
9a64fbe4 2912 fix_opcode_tables(ppc_opcodes);
79aceca5
FB
2913
2914 return 0;
2915}
2916
9a64fbe4 2917
79aceca5 2918/*****************************************************************************/
9a64fbe4 2919/* Misc PPC helpers */
79aceca5
FB
2920
2921void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags)
2922{
2923 int i;
2924
9a64fbe4
FB
2925 fprintf(f, "nip=0x%08x LR=0x%08x CTR=0x%08x XER=0x%08x "
2926 "MSR=0x%08x\n", env->nip, env->lr, env->ctr,
a541f297 2927 _load_xer(env), _load_msr(env));
79aceca5
FB
2928 for (i = 0; i < 32; i++) {
2929 if ((i & 7) == 0)
9a64fbe4
FB
2930 fprintf(f, "GPR%02d:", i);
2931 fprintf(f, " %08x", env->gpr[i]);
79aceca5 2932 if ((i & 7) == 7)
9a64fbe4 2933 fprintf(f, "\n");
79aceca5 2934 }
9a64fbe4 2935 fprintf(f, "CR: 0x");
79aceca5 2936 for (i = 0; i < 8; i++)
9a64fbe4
FB
2937 fprintf(f, "%01x", env->crf[i]);
2938 fprintf(f, " [");
79aceca5
FB
2939 for (i = 0; i < 8; i++) {
2940 char a = '-';
79aceca5
FB
2941 if (env->crf[i] & 0x08)
2942 a = 'L';
2943 else if (env->crf[i] & 0x04)
2944 a = 'G';
2945 else if (env->crf[i] & 0x02)
2946 a = 'E';
9a64fbe4 2947 fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' ');
79aceca5 2948 }
9a64fbe4 2949 fprintf(f, " ] ");
9fddaa0c
FB
2950 fprintf(f, "TB: 0x%08x %08x\n", cpu_ppc_load_tbu(env),
2951 cpu_ppc_load_tbl(env));
79aceca5
FB
2952 for (i = 0; i < 16; i++) {
2953 if ((i & 3) == 0)
9a64fbe4
FB
2954 fprintf(f, "FPR%02d:", i);
2955 fprintf(f, " %016llx", *((uint64_t *)&env->fpr[i]));
79aceca5 2956 if ((i & 3) == 3)
9a64fbe4 2957 fprintf(f, "\n");
79aceca5 2958 }
9fddaa0c
FB
2959 fprintf(f, "SRR0 0x%08x SRR1 0x%08x DECR=0x%08x\n",
2960 env->spr[SRR0], env->spr[SRR1], cpu_ppc_load_decr(env));
9a64fbe4
FB
2961 fprintf(f, "reservation 0x%08x\n", env->reserve);
2962 fflush(f);
79aceca5
FB
2963}
2964
9a64fbe4
FB
2965#if !defined(CONFIG_USER_ONLY) && defined (USE_OPENFIRMWARE)
2966int setup_machine (CPUPPCState *env, uint32_t mid);
2967#endif
2968
79aceca5
FB
2969CPUPPCState *cpu_ppc_init(void)
2970{
2971 CPUPPCState *env;
2972
2973 cpu_exec_init();
2974
4b3686fa 2975 env = qemu_mallocz(sizeof(CPUPPCState));
79aceca5
FB
2976 if (!env)
2977 return NULL;
9a64fbe4
FB
2978#if !defined(CONFIG_USER_ONLY) && defined (USE_OPEN_FIRMWARE)
2979 setup_machine(env, 0);
2980#else
2981// env->spr[PVR] = 0; /* Basic PPC */
2982 env->spr[PVR] = 0x00080100; /* G3 CPU */
2983// env->spr[PVR] = 0x00083100; /* MPC755 (G3 embedded) */
2984// env->spr[PVR] = 0x00070100; /* IBM 750FX */
2985#endif
ad081323 2986 tlb_flush(env, 1);
9a64fbe4
FB
2987#if defined (DO_SINGLE_STEP)
2988 /* Single step trace mode */
2989 msr_se = 1;
2990#endif
4b3686fa
FB
2991 msr_fp = 1; /* Allow floating point exceptions */
2992 msr_me = 1; /* Allow machine check exceptions */
9a64fbe4
FB
2993#if defined(CONFIG_USER_ONLY)
2994 msr_pr = 1;
4b3686fa
FB
2995 cpu_ppc_register(env, 0x00080000);
2996#else
2997 env->nip = 0xFFFFFFFC;
9a64fbe4 2998#endif
a541f297 2999 env->access_type = ACCESS_INT;
7496f526 3000 cpu_single_env = env;
79aceca5
FB
3001 return env;
3002}
3003
4b3686fa
FB
3004int cpu_ppc_register (CPUPPCState *env, uint32_t pvr)
3005{
3006 env->spr[PVR] = pvr;
3007 if (create_ppc_proc(ppc_opcodes, env->spr[PVR]) < 0)
3008 return -1;
3009 init_spr_rights(env->spr[PVR]);
3010
3011 return 0;
3012}
3013
79aceca5
FB
3014void cpu_ppc_close(CPUPPCState *env)
3015{
3016 /* Should also remove all opcode tables... */
3017 free(env);
3018}
3019
9a64fbe4 3020/*****************************************************************************/
9a64fbe4
FB
3021int print_insn_powerpc (FILE *out, unsigned long insn, unsigned memaddr,
3022 int dialect);
3023
79aceca5
FB
3024int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
3025 int search_pc)
3026{
9fddaa0c 3027 DisasContext ctx, *ctxp = &ctx;
79aceca5
FB
3028 opc_handler_t **table, *handler;
3029 uint32_t pc_start;
3030 uint16_t *gen_opc_end;
3031 int j, lj = -1;
79aceca5
FB
3032
3033 pc_start = tb->pc;
3034 gen_opc_ptr = gen_opc_buf;
3035 gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
3036 gen_opparam_ptr = gen_opparam_buf;
046d6672 3037 ctx.nip = pc_start;
79aceca5 3038 ctx.tb = tb;
9a64fbe4
FB
3039 ctx.exception = EXCP_NONE;
3040#if defined(CONFIG_USER_ONLY)
3041 ctx.mem_idx = 0;
3042#else
3043 ctx.supervisor = 1 - msr_pr;
3044 ctx.mem_idx = (1 - msr_pr);
3045#endif
3046#if defined (DO_SINGLE_STEP)
3047 /* Single step trace mode */
3048 msr_se = 1;
3049#endif
a541f297 3050 env->access_type = ACCESS_CODE;
9a64fbe4
FB
3051 /* Set env in case of segfault during code fetch */
3052 while (ctx.exception == EXCP_NONE && gen_opc_ptr < gen_opc_end) {
79aceca5
FB
3053 if (search_pc) {
3054 if (loglevel > 0)
3055 fprintf(logfile, "Search PC...\n");
3056 j = gen_opc_ptr - gen_opc_buf;
3057 if (lj < j) {
3058 lj++;
3059 while (lj < j)
3060 gen_opc_instr_start[lj++] = 0;
046d6672 3061 gen_opc_pc[lj] = ctx.nip;
79aceca5
FB
3062 gen_opc_instr_start[lj] = 1;
3063 }
3064 }
9fddaa0c
FB
3065#if defined PPC_DEBUG_DISAS
3066 if (loglevel & CPU_LOG_TB_IN_ASM) {
79aceca5 3067 fprintf(logfile, "----------------\n");
046d6672 3068 fprintf(logfile, "nip=%08x super=%d ir=%d\n",
9a64fbe4
FB
3069 ctx.nip, 1 - msr_pr, msr_ir);
3070 }
3071#endif
046d6672 3072 ctx.opcode = ldl_code((void *)ctx.nip);
9fddaa0c
FB
3073#if defined PPC_DEBUG_DISAS
3074 if (loglevel & CPU_LOG_TB_IN_ASM) {
9a64fbe4
FB
3075 fprintf(logfile, "translate opcode %08x (%02x %02x %02x)\n",
3076 ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode),
3077 opc3(ctx.opcode));
79aceca5
FB
3078 }
3079#endif
046d6672 3080 ctx.nip += 4;
79aceca5
FB
3081 table = ppc_opcodes;
3082 handler = table[opc1(ctx.opcode)];
3083 if (is_indirect_opcode(handler)) {
3084 table = ind_table(handler);
3085 handler = table[opc2(ctx.opcode)];
3086 if (is_indirect_opcode(handler)) {
3087 table = ind_table(handler);
3088 handler = table[opc3(ctx.opcode)];
3089 }
3090 }
3091 /* Is opcode *REALLY* valid ? */
79aceca5 3092 if (handler->handler == &gen_invalid) {
4b3686fa 3093 if (loglevel > 0) {
79aceca5 3094 fprintf(logfile, "invalid/unsupported opcode: "
4b3686fa 3095 "%02x - %02x - %02x (%08x) 0x%08x %d\n",
9a64fbe4 3096 opc1(ctx.opcode), opc2(ctx.opcode),
4b3686fa
FB
3097 opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir);
3098 } else {
3099 printf("invalid/unsupported opcode: "
3100 "%02x - %02x - %02x (%08x) 0x%08x %d\n",
3101 opc1(ctx.opcode), opc2(ctx.opcode),
3102 opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir);
3103 }
79aceca5 3104 } else {
4b3686fa
FB
3105 if ((ctx.opcode & handler->inval) != 0) {
3106 if (loglevel > 0) {
79aceca5 3107 fprintf(logfile, "invalid bits: %08x for opcode: "
046d6672 3108 "%02x -%02x - %02x (0x%08x) (0x%08x)\n",
79aceca5
FB
3109 ctx.opcode & handler->inval, opc1(ctx.opcode),
3110 opc2(ctx.opcode), opc3(ctx.opcode),
046d6672 3111 ctx.opcode, ctx.nip - 4);
9a64fbe4
FB
3112 } else {
3113 printf("invalid bits: %08x for opcode: "
046d6672 3114 "%02x -%02x - %02x (0x%08x) (0x%08x)\n",
9a64fbe4
FB
3115 ctx.opcode & handler->inval, opc1(ctx.opcode),
3116 opc2(ctx.opcode), opc3(ctx.opcode),
046d6672 3117 ctx.opcode, ctx.nip - 4);
9a64fbe4 3118 }
4b3686fa
FB
3119 RET_INVAL(ctxp);
3120 break;
79aceca5 3121 }
79aceca5 3122 }
4b3686fa 3123 (*(handler->handler))(&ctx);
9a64fbe4
FB
3124 /* Check trace mode exceptions */
3125 if ((msr_be && ctx.exception == EXCP_BRANCH) ||
3126 /* Check in single step trace mode
3127 * we need to stop except if:
3128 * - rfi, trap or syscall
3129 * - first instruction of an exception handler
3130 */
046d6672
FB
3131 (msr_se && (ctx.nip < 0x100 ||
3132 ctx.nip > 0xF00 ||
3133 (ctx.nip & 0xFC) != 0x04) &&
9a64fbe4
FB
3134 ctx.exception != EXCP_SYSCALL && ctx.exception != EXCP_RFI &&
3135 ctx.exception != EXCP_TRAP)) {
9fddaa0c 3136 RET_EXCP(ctxp, EXCP_TRACE, 0);
9a64fbe4 3137 }
a541f297 3138 /* if we reach a page boundary, stop generation */
046d6672 3139 if ((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) {
9fddaa0c 3140 RET_EXCP(ctxp, EXCP_BRANCH, 0);
79aceca5 3141 }
9a64fbe4 3142 }
9fddaa0c
FB
3143 if (ctx.exception == EXCP_NONE) {
3144 gen_op_b((unsigned long)ctx.tb, ctx.nip);
3145 } else if (ctx.exception != EXCP_BRANCH) {
3146 gen_op_set_T0(0);
9a64fbe4
FB
3147 }
3148#if 1
79aceca5
FB
3149 /* TO BE FIXED: T0 hasn't got a proper value, which makes tb_add_jump
3150 * do bad business and then qemu crashes !
3151 */
3152 gen_op_set_T0(0);
9a64fbe4 3153#endif
79aceca5
FB
3154 /* Generate the return instruction */
3155 gen_op_exit_tb();
3156 *gen_opc_ptr = INDEX_op_end;
9a64fbe4
FB
3157 if (search_pc) {
3158 j = gen_opc_ptr - gen_opc_buf;
3159 lj++;
3160 while (lj <= j)
3161 gen_opc_instr_start[lj++] = 0;
79aceca5 3162 tb->size = 0;
985a19d6 3163#if 0
9a64fbe4
FB
3164 if (loglevel > 0) {
3165 page_dump(logfile);
3166 }
985a19d6 3167#endif
9a64fbe4 3168 } else {
046d6672 3169 tb->size = ctx.nip - pc_start;
9a64fbe4 3170 }
79aceca5 3171#ifdef DEBUG_DISAS
9fddaa0c 3172 if (loglevel & CPU_LOG_TB_CPU) {
9a64fbe4
FB
3173 fprintf(logfile, "---------------- excp: %04x\n", ctx.exception);
3174 cpu_ppc_dump_state(env, logfile, 0);
9fddaa0c
FB
3175 }
3176 if (loglevel & CPU_LOG_TB_IN_ASM) {
79aceca5 3177 fprintf(logfile, "IN: %s\n", lookup_symbol((void *)pc_start));
046d6672 3178 disas(logfile, (void *)pc_start, ctx.nip - pc_start, 0, 0);
79aceca5 3179 fprintf(logfile, "\n");
9fddaa0c
FB
3180 }
3181 if (loglevel & CPU_LOG_TB_OP) {
79aceca5
FB
3182 fprintf(logfile, "OP:\n");
3183 dump_ops(gen_opc_buf, gen_opparam_buf);
3184 fprintf(logfile, "\n");
3185 }
3186#endif
4b3686fa 3187 env->access_type = ACCESS_INT;
79aceca5
FB
3188
3189 return 0;
3190}
3191
9a64fbe4 3192int gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
79aceca5
FB
3193{
3194 return gen_intermediate_code_internal(env, tb, 0);
3195}
3196
9a64fbe4 3197int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
79aceca5
FB
3198{
3199 return gen_intermediate_code_internal(env, tb, 1);
3200}