|
|
1.1 root 1: /*
2: * PowerPC emulation for qemu: main translation routines.
3: *
4: * Copyright (c) 2003-2005 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: */
20: #include <stdarg.h>
21: #include <stdlib.h>
22: #include <stdio.h>
23: #include <string.h>
24: #include <inttypes.h>
25:
26: #include "cpu.h"
27: #include "exec-all.h"
28: #include "disas.h"
29:
30: //#define DO_SINGLE_STEP
31: //#define PPC_DEBUG_DISAS
32:
33: enum {
34: #define DEF(s, n, copy_size) INDEX_op_ ## s,
35: #include "opc.h"
36: #undef DEF
37: NB_OPS,
38: };
39:
40: static uint16_t *gen_opc_ptr;
41: static uint32_t *gen_opparam_ptr;
42:
43: #include "gen-op.h"
44:
45: #define GEN8(func, NAME) \
46: static GenOpFunc *NAME ## _table [8] = { \
47: NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \
48: NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \
49: }; \
50: static inline void func(int n) \
51: { \
52: NAME ## _table[n](); \
53: }
54:
55: #define GEN16(func, NAME) \
56: static GenOpFunc *NAME ## _table [16] = { \
57: NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \
58: NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \
59: NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \
60: NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \
61: }; \
62: static inline void func(int n) \
63: { \
64: NAME ## _table[n](); \
65: }
66:
67: #define GEN32(func, NAME) \
68: static GenOpFunc *NAME ## _table [32] = { \
69: NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \
70: NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \
71: NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \
72: NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \
73: NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \
74: NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \
75: NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \
76: NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \
77: }; \
78: static inline void func(int n) \
79: { \
80: NAME ## _table[n](); \
81: }
82:
83: /* Condition register moves */
84: GEN8(gen_op_load_crf_T0, gen_op_load_crf_T0_crf);
85: GEN8(gen_op_load_crf_T1, gen_op_load_crf_T1_crf);
86: GEN8(gen_op_store_T0_crf, gen_op_store_T0_crf_crf);
87: GEN8(gen_op_store_T1_crf, gen_op_store_T1_crf_crf);
88:
89: /* Floating point condition and status register moves */
90: GEN8(gen_op_load_fpscr_T0, gen_op_load_fpscr_T0_fpscr);
91: GEN8(gen_op_store_T0_fpscr, gen_op_store_T0_fpscr_fpscr);
92: GEN8(gen_op_clear_fpscr, gen_op_clear_fpscr_fpscr);
93: static 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: };
103: static 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:
108: /* Segment register moves */
109: GEN16(gen_op_load_sr, gen_op_load_sr);
110: GEN16(gen_op_store_sr, gen_op_store_sr);
111:
112: /* General purpose registers moves */
113: GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr);
114: GEN32(gen_op_load_gpr_T1, gen_op_load_gpr_T1_gpr);
115: GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr);
116:
117: GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr);
118: GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr);
119: GEN32(gen_op_store_T2_gpr, gen_op_store_T2_gpr_gpr);
120:
121: /* floating point registers moves */
122: GEN32(gen_op_load_fpr_FT0, gen_op_load_fpr_FT0_fpr);
123: GEN32(gen_op_load_fpr_FT1, gen_op_load_fpr_FT1_fpr);
124: GEN32(gen_op_load_fpr_FT2, gen_op_load_fpr_FT2_fpr);
125: GEN32(gen_op_store_FT0_fpr, gen_op_store_FT0_fpr_fpr);
126: GEN32(gen_op_store_FT1_fpr, gen_op_store_FT1_fpr_fpr);
127: GEN32(gen_op_store_FT2_fpr, gen_op_store_FT2_fpr_fpr);
128:
129: static uint8_t spr_access[1024 / 2];
130:
131: /* internal defines */
132: typedef struct DisasContext {
133: struct TranslationBlock *tb;
134: target_ulong nip;
135: uint32_t opcode;
136: uint32_t exception;
137: /* Routine used to access memory */
138: int mem_idx;
139: /* Translation flags */
140: #if !defined(CONFIG_USER_ONLY)
141: int supervisor;
142: #endif
143: int fpu_enabled;
144: ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */
145: } DisasContext;
146:
147: struct opc_handler_t {
148: /* invalid bits */
149: uint32_t inval;
150: /* instruction type */
151: uint32_t type;
152: /* handler */
153: void (*handler)(DisasContext *ctx);
154: };
155:
156: #define RET_EXCP(ctx, excp, error) \
157: do { \
158: if ((ctx)->exception == EXCP_NONE) { \
159: gen_op_update_nip((ctx)->nip); \
160: } \
161: gen_op_raise_exception_err((excp), (error)); \
162: ctx->exception = (excp); \
163: } while (0)
164:
165: #define RET_INVAL(ctx) \
166: RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL)
167:
168: #define RET_PRIVOPC(ctx) \
169: RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_OPC)
170:
171: #define RET_PRIVREG(ctx) \
172: RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG)
173:
174: #define RET_MTMSR(ctx) \
175: RET_EXCP((ctx), EXCP_MTMSR, 0)
176:
177: static inline void RET_STOP (DisasContext *ctx)
178: {
179: RET_EXCP(ctx, EXCP_MTMSR, 0);
180: }
181:
182: static inline void RET_CHG_FLOW (DisasContext *ctx)
183: {
184: gen_op_raise_exception_err(EXCP_MTMSR, 0);
185: ctx->exception = EXCP_MTMSR;
186: }
187:
188: #define GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \
189: static void gen_##name (DisasContext *ctx); \
190: GEN_OPCODE(name, opc1, opc2, opc3, inval, type); \
191: static void gen_##name (DisasContext *ctx)
192:
193: typedef struct opcode_t {
194: unsigned char opc1, opc2, opc3;
195: #if HOST_LONG_BITS == 64 /* Explicitely align to 64 bits */
196: unsigned char pad[5];
197: #else
198: unsigned char pad[1];
199: #endif
200: opc_handler_t handler;
201: const unsigned char *oname;
202: } opcode_t;
203:
204: /*** Instruction decoding ***/
205: #define EXTRACT_HELPER(name, shift, nb) \
206: static inline uint32_t name (uint32_t opcode) \
207: { \
208: return (opcode >> (shift)) & ((1 << (nb)) - 1); \
209: }
210:
211: #define EXTRACT_SHELPER(name, shift, nb) \
212: static inline int32_t name (uint32_t opcode) \
213: { \
214: return (int16_t)((opcode >> (shift)) & ((1 << (nb)) - 1)); \
215: }
216:
217: /* Opcode part 1 */
218: EXTRACT_HELPER(opc1, 26, 6);
219: /* Opcode part 2 */
220: EXTRACT_HELPER(opc2, 1, 5);
221: /* Opcode part 3 */
222: EXTRACT_HELPER(opc3, 6, 5);
223: /* Update Cr0 flags */
224: EXTRACT_HELPER(Rc, 0, 1);
225: /* Destination */
226: EXTRACT_HELPER(rD, 21, 5);
227: /* Source */
228: EXTRACT_HELPER(rS, 21, 5);
229: /* First operand */
230: EXTRACT_HELPER(rA, 16, 5);
231: /* Second operand */
232: EXTRACT_HELPER(rB, 11, 5);
233: /* Third operand */
234: EXTRACT_HELPER(rC, 6, 5);
235: /*** Get CRn ***/
236: EXTRACT_HELPER(crfD, 23, 3);
237: EXTRACT_HELPER(crfS, 18, 3);
238: EXTRACT_HELPER(crbD, 21, 5);
239: EXTRACT_HELPER(crbA, 16, 5);
240: EXTRACT_HELPER(crbB, 11, 5);
241: /* SPR / TBL */
242: EXTRACT_HELPER(_SPR, 11, 10);
243: static inline uint32_t SPR (uint32_t opcode)
244: {
245: uint32_t sprn = _SPR(opcode);
246:
247: return ((sprn >> 5) & 0x1F) | ((sprn & 0x1F) << 5);
248: }
249: /*** Get constants ***/
250: EXTRACT_HELPER(IMM, 12, 8);
251: /* 16 bits signed immediate value */
252: EXTRACT_SHELPER(SIMM, 0, 16);
253: /* 16 bits unsigned immediate value */
254: EXTRACT_HELPER(UIMM, 0, 16);
255: /* Bit count */
256: EXTRACT_HELPER(NB, 11, 5);
257: /* Shift count */
258: EXTRACT_HELPER(SH, 11, 5);
259: /* Mask start */
260: EXTRACT_HELPER(MB, 6, 5);
261: /* Mask end */
262: EXTRACT_HELPER(ME, 1, 5);
263: /* Trap operand */
264: EXTRACT_HELPER(TO, 21, 5);
265:
266: EXTRACT_HELPER(CRM, 12, 8);
267: EXTRACT_HELPER(FM, 17, 8);
268: EXTRACT_HELPER(SR, 16, 4);
269: EXTRACT_HELPER(FPIMM, 20, 4);
270:
271: /*** Jump target decoding ***/
272: /* Displacement */
273: EXTRACT_SHELPER(d, 0, 16);
274: /* Immediate address */
275: static inline uint32_t LI (uint32_t opcode)
276: {
277: return (opcode >> 0) & 0x03FFFFFC;
278: }
279:
280: static inline uint32_t BD (uint32_t opcode)
281: {
282: return (opcode >> 0) & 0xFFFC;
283: }
284:
285: EXTRACT_HELPER(BO, 21, 5);
286: EXTRACT_HELPER(BI, 16, 5);
287: /* Absolute/relative address */
288: EXTRACT_HELPER(AA, 1, 1);
289: /* Link */
290: EXTRACT_HELPER(LK, 0, 1);
291:
292: /* Create a mask between <start> and <end> bits */
293: static inline uint32_t MASK (uint32_t start, uint32_t end)
294: {
295: uint32_t ret;
296:
297: ret = (((uint32_t)(-1)) >> (start)) ^ (((uint32_t)(-1) >> (end)) >> 1);
298: if (start > end)
299: return ~ret;
300:
301: return ret;
302: }
303:
304: #if HOST_LONG_BITS == 64
305: #define OPC_ALIGN 8
306: #else
307: #define OPC_ALIGN 4
308: #endif
309: #if defined(__APPLE__)
310: #define OPCODES_SECTION \
311: __attribute__ ((section("__TEXT,__opcodes"), unused, aligned (OPC_ALIGN) ))
312: #else
313: #define OPCODES_SECTION \
314: __attribute__ ((section(".opcodes"), unused, aligned (OPC_ALIGN) ))
315: #endif
316:
317: #define GEN_OPCODE(name, op1, op2, op3, invl, _typ) \
318: OPCODES_SECTION opcode_t opc_##name = { \
319: .opc1 = op1, \
320: .opc2 = op2, \
321: .opc3 = op3, \
322: .pad = { 0, }, \
323: .handler = { \
324: .inval = invl, \
325: .type = _typ, \
326: .handler = &gen_##name, \
327: }, \
328: .oname = stringify(name), \
329: }
330:
331: #define GEN_OPCODE_MARK(name) \
332: OPCODES_SECTION opcode_t opc_##name = { \
333: .opc1 = 0xFF, \
334: .opc2 = 0xFF, \
335: .opc3 = 0xFF, \
336: .pad = { 0, }, \
337: .handler = { \
338: .inval = 0x00000000, \
339: .type = 0x00, \
340: .handler = NULL, \
341: }, \
342: .oname = stringify(name), \
343: }
344:
345: /* Start opcode list */
346: GEN_OPCODE_MARK(start);
347:
348: /* Invalid instruction */
349: GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE)
350: {
351: RET_INVAL(ctx);
352: }
353:
354: static opc_handler_t invalid_handler = {
355: .inval = 0xFFFFFFFF,
356: .type = PPC_NONE,
357: .handler = gen_invalid,
358: };
359:
360: /*** Integer arithmetic ***/
361: #define __GEN_INT_ARITH2(name, opc1, opc2, opc3, inval) \
362: GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER) \
363: { \
364: gen_op_load_gpr_T0(rA(ctx->opcode)); \
365: gen_op_load_gpr_T1(rB(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)); \
370: }
371:
372: #define __GEN_INT_ARITH2_O(name, opc1, opc2, opc3, inval) \
373: GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER) \
374: { \
375: gen_op_load_gpr_T0(rA(ctx->opcode)); \
376: gen_op_load_gpr_T1(rB(ctx->opcode)); \
377: gen_op_##name(); \
378: if (Rc(ctx->opcode) != 0) \
379: gen_op_set_Rc0(); \
380: gen_op_store_T0_gpr(rD(ctx->opcode)); \
381: }
382:
383: #define __GEN_INT_ARITH1(name, opc1, opc2, opc3) \
384: GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER) \
385: { \
386: gen_op_load_gpr_T0(rA(ctx->opcode)); \
387: gen_op_##name(); \
388: if (Rc(ctx->opcode) != 0) \
389: gen_op_set_Rc0(); \
390: gen_op_store_T0_gpr(rD(ctx->opcode)); \
391: }
392: #define __GEN_INT_ARITH1_O(name, opc1, opc2, opc3) \
393: GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER) \
394: { \
395: gen_op_load_gpr_T0(rA(ctx->opcode)); \
396: gen_op_##name(); \
397: if (Rc(ctx->opcode) != 0) \
398: gen_op_set_Rc0(); \
399: gen_op_store_T0_gpr(rD(ctx->opcode)); \
400: }
401:
402: /* Two operands arithmetic functions */
403: #define GEN_INT_ARITH2(name, opc1, opc2, opc3) \
404: __GEN_INT_ARITH2(name, opc1, opc2, opc3, 0x00000000) \
405: __GEN_INT_ARITH2_O(name##o, opc1, opc2, opc3 | 0x10, 0x00000000)
406:
407: /* Two operands arithmetic functions with no overflow allowed */
408: #define GEN_INT_ARITHN(name, opc1, opc2, opc3) \
409: __GEN_INT_ARITH2(name, opc1, opc2, opc3, 0x00000400)
410:
411: /* One operand arithmetic functions */
412: #define GEN_INT_ARITH1(name, opc1, opc2, opc3) \
413: __GEN_INT_ARITH1(name, opc1, opc2, opc3) \
414: __GEN_INT_ARITH1_O(name##o, opc1, opc2, opc3 | 0x10)
415:
416: /* add add. addo addo. */
417: GEN_INT_ARITH2 (add, 0x1F, 0x0A, 0x08);
418: /* addc addc. addco addco. */
419: GEN_INT_ARITH2 (addc, 0x1F, 0x0A, 0x00);
420: /* adde adde. addeo addeo. */
421: GEN_INT_ARITH2 (adde, 0x1F, 0x0A, 0x04);
422: /* addme addme. addmeo addmeo. */
423: GEN_INT_ARITH1 (addme, 0x1F, 0x0A, 0x07);
424: /* addze addze. addzeo addzeo. */
425: GEN_INT_ARITH1 (addze, 0x1F, 0x0A, 0x06);
426: /* divw divw. divwo divwo. */
427: GEN_INT_ARITH2 (divw, 0x1F, 0x0B, 0x0F);
428: /* divwu divwu. divwuo divwuo. */
429: GEN_INT_ARITH2 (divwu, 0x1F, 0x0B, 0x0E);
430: /* mulhw mulhw. */
431: GEN_INT_ARITHN (mulhw, 0x1F, 0x0B, 0x02);
432: /* mulhwu mulhwu. */
433: GEN_INT_ARITHN (mulhwu, 0x1F, 0x0B, 0x00);
434: /* mullw mullw. mullwo mullwo. */
435: GEN_INT_ARITH2 (mullw, 0x1F, 0x0B, 0x07);
436: /* neg neg. nego nego. */
437: GEN_INT_ARITH1 (neg, 0x1F, 0x08, 0x03);
438: /* subf subf. subfo subfo. */
439: GEN_INT_ARITH2 (subf, 0x1F, 0x08, 0x01);
440: /* subfc subfc. subfco subfco. */
441: GEN_INT_ARITH2 (subfc, 0x1F, 0x08, 0x00);
442: /* subfe subfe. subfeo subfeo. */
443: GEN_INT_ARITH2 (subfe, 0x1F, 0x08, 0x04);
444: /* subfme subfme. subfmeo subfmeo. */
445: GEN_INT_ARITH1 (subfme, 0x1F, 0x08, 0x07);
446: /* subfze subfze. subfzeo subfzeo. */
447: GEN_INT_ARITH1 (subfze, 0x1F, 0x08, 0x06);
448: /* addi */
449: GEN_HANDLER(addi, 0x0E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
450: {
451: int32_t simm = SIMM(ctx->opcode);
452:
453: if (rA(ctx->opcode) == 0) {
454: gen_op_set_T0(simm);
455: } else {
456: gen_op_load_gpr_T0(rA(ctx->opcode));
457: gen_op_addi(simm);
458: }
459: gen_op_store_T0_gpr(rD(ctx->opcode));
460: }
461: /* addic */
462: GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
463: {
464: gen_op_load_gpr_T0(rA(ctx->opcode));
465: gen_op_addic(SIMM(ctx->opcode));
466: gen_op_store_T0_gpr(rD(ctx->opcode));
467: }
468: /* addic. */
469: GEN_HANDLER(addic_, 0x0D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
470: {
471: gen_op_load_gpr_T0(rA(ctx->opcode));
472: gen_op_addic(SIMM(ctx->opcode));
473: gen_op_set_Rc0();
474: gen_op_store_T0_gpr(rD(ctx->opcode));
475: }
476: /* addis */
477: GEN_HANDLER(addis, 0x0F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
478: {
479: int32_t simm = SIMM(ctx->opcode);
480:
481: if (rA(ctx->opcode) == 0) {
482: gen_op_set_T0(simm << 16);
483: } else {
484: gen_op_load_gpr_T0(rA(ctx->opcode));
485: gen_op_addi(simm << 16);
486: }
487: gen_op_store_T0_gpr(rD(ctx->opcode));
488: }
489: /* mulli */
490: GEN_HANDLER(mulli, 0x07, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
491: {
492: gen_op_load_gpr_T0(rA(ctx->opcode));
493: gen_op_mulli(SIMM(ctx->opcode));
494: gen_op_store_T0_gpr(rD(ctx->opcode));
495: }
496: /* subfic */
497: GEN_HANDLER(subfic, 0x08, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
498: {
499: gen_op_load_gpr_T0(rA(ctx->opcode));
500: gen_op_subfic(SIMM(ctx->opcode));
501: gen_op_store_T0_gpr(rD(ctx->opcode));
502: }
503:
504: /*** Integer comparison ***/
505: #define GEN_CMP(name, opc) \
506: GEN_HANDLER(name, 0x1F, 0x00, opc, 0x00400000, PPC_INTEGER) \
507: { \
508: gen_op_load_gpr_T0(rA(ctx->opcode)); \
509: gen_op_load_gpr_T1(rB(ctx->opcode)); \
510: gen_op_##name(); \
511: gen_op_store_T0_crf(crfD(ctx->opcode)); \
512: }
513:
514: /* cmp */
515: GEN_CMP(cmp, 0x00);
516: /* cmpi */
517: GEN_HANDLER(cmpi, 0x0B, 0xFF, 0xFF, 0x00400000, PPC_INTEGER)
518: {
519: gen_op_load_gpr_T0(rA(ctx->opcode));
520: gen_op_cmpi(SIMM(ctx->opcode));
521: gen_op_store_T0_crf(crfD(ctx->opcode));
522: }
523: /* cmpl */
524: GEN_CMP(cmpl, 0x01);
525: /* cmpli */
526: GEN_HANDLER(cmpli, 0x0A, 0xFF, 0xFF, 0x00400000, PPC_INTEGER)
527: {
528: gen_op_load_gpr_T0(rA(ctx->opcode));
529: gen_op_cmpli(UIMM(ctx->opcode));
530: gen_op_store_T0_crf(crfD(ctx->opcode));
531: }
532:
533: /*** Integer logical ***/
534: #define __GEN_LOGICAL2(name, opc2, opc3) \
535: GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000000, PPC_INTEGER) \
536: { \
537: gen_op_load_gpr_T0(rS(ctx->opcode)); \
538: gen_op_load_gpr_T1(rB(ctx->opcode)); \
539: gen_op_##name(); \
540: if (Rc(ctx->opcode) != 0) \
541: gen_op_set_Rc0(); \
542: gen_op_store_T0_gpr(rA(ctx->opcode)); \
543: }
544: #define GEN_LOGICAL2(name, opc) \
545: __GEN_LOGICAL2(name, 0x1C, opc)
546:
547: #define GEN_LOGICAL1(name, opc) \
548: GEN_HANDLER(name, 0x1F, 0x1A, opc, 0x00000000, PPC_INTEGER) \
549: { \
550: gen_op_load_gpr_T0(rS(ctx->opcode)); \
551: gen_op_##name(); \
552: if (Rc(ctx->opcode) != 0) \
553: gen_op_set_Rc0(); \
554: gen_op_store_T0_gpr(rA(ctx->opcode)); \
555: }
556:
557: /* and & and. */
558: GEN_LOGICAL2(and, 0x00);
559: /* andc & andc. */
560: GEN_LOGICAL2(andc, 0x01);
561: /* andi. */
562: GEN_HANDLER(andi_, 0x1C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
563: {
564: gen_op_load_gpr_T0(rS(ctx->opcode));
565: gen_op_andi_(UIMM(ctx->opcode));
566: gen_op_set_Rc0();
567: gen_op_store_T0_gpr(rA(ctx->opcode));
568: }
569: /* andis. */
570: GEN_HANDLER(andis_, 0x1D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
571: {
572: gen_op_load_gpr_T0(rS(ctx->opcode));
573: gen_op_andi_(UIMM(ctx->opcode) << 16);
574: gen_op_set_Rc0();
575: gen_op_store_T0_gpr(rA(ctx->opcode));
576: }
577:
578: /* cntlzw */
579: GEN_LOGICAL1(cntlzw, 0x00);
580: /* eqv & eqv. */
581: GEN_LOGICAL2(eqv, 0x08);
582: /* extsb & extsb. */
583: GEN_LOGICAL1(extsb, 0x1D);
584: /* extsh & extsh. */
585: GEN_LOGICAL1(extsh, 0x1C);
586: /* nand & nand. */
587: GEN_LOGICAL2(nand, 0x0E);
588: /* nor & nor. */
589: GEN_LOGICAL2(nor, 0x03);
590:
591: /* or & or. */
592: GEN_HANDLER(or, 0x1F, 0x1C, 0x0D, 0x00000000, PPC_INTEGER)
593: {
594: gen_op_load_gpr_T0(rS(ctx->opcode));
595: /* Optimisation for mr case */
596: if (rS(ctx->opcode) != rB(ctx->opcode)) {
597: gen_op_load_gpr_T1(rB(ctx->opcode));
598: gen_op_or();
599: }
600: if (Rc(ctx->opcode) != 0)
601: gen_op_set_Rc0();
602: gen_op_store_T0_gpr(rA(ctx->opcode));
603: }
604:
605: /* orc & orc. */
606: GEN_LOGICAL2(orc, 0x0C);
607: /* xor & xor. */
608: GEN_HANDLER(xor, 0x1F, 0x1C, 0x09, 0x00000000, PPC_INTEGER)
609: {
610: gen_op_load_gpr_T0(rS(ctx->opcode));
611: /* Optimisation for "set to zero" case */
612: if (rS(ctx->opcode) != rB(ctx->opcode)) {
613: gen_op_load_gpr_T1(rB(ctx->opcode));
614: gen_op_xor();
615: } else {
616: gen_op_set_T0(0);
617: }
618: if (Rc(ctx->opcode) != 0)
619: gen_op_set_Rc0();
620: gen_op_store_T0_gpr(rA(ctx->opcode));
621: }
622: /* ori */
623: GEN_HANDLER(ori, 0x18, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
624: {
625: uint32_t uimm = UIMM(ctx->opcode);
626:
627: if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
628: /* NOP */
629: return;
630: }
631: gen_op_load_gpr_T0(rS(ctx->opcode));
632: if (uimm != 0)
633: gen_op_ori(uimm);
634: gen_op_store_T0_gpr(rA(ctx->opcode));
635: }
636: /* oris */
637: GEN_HANDLER(oris, 0x19, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
638: {
639: uint32_t uimm = UIMM(ctx->opcode);
640:
641: if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
642: /* NOP */
643: return;
644: }
645: gen_op_load_gpr_T0(rS(ctx->opcode));
646: if (uimm != 0)
647: gen_op_ori(uimm << 16);
648: gen_op_store_T0_gpr(rA(ctx->opcode));
649: }
650: /* xori */
651: GEN_HANDLER(xori, 0x1A, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
652: {
653: uint32_t uimm = UIMM(ctx->opcode);
654:
655: if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
656: /* NOP */
657: return;
658: }
659: gen_op_load_gpr_T0(rS(ctx->opcode));
660: if (uimm != 0)
661: gen_op_xori(uimm);
662: gen_op_store_T0_gpr(rA(ctx->opcode));
663: }
664:
665: /* xoris */
666: GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
667: {
668: uint32_t uimm = UIMM(ctx->opcode);
669:
670: if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
671: /* NOP */
672: return;
673: }
674: gen_op_load_gpr_T0(rS(ctx->opcode));
675: if (uimm != 0)
676: gen_op_xori(uimm << 16);
677: gen_op_store_T0_gpr(rA(ctx->opcode));
678: }
679:
680: /*** Integer rotate ***/
681: /* rlwimi & rlwimi. */
682: GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
683: {
684: uint32_t mb, me;
685:
686: mb = MB(ctx->opcode);
687: me = ME(ctx->opcode);
688: gen_op_load_gpr_T0(rS(ctx->opcode));
689: gen_op_load_gpr_T1(rA(ctx->opcode));
690: gen_op_rlwimi(SH(ctx->opcode), MASK(mb, me), ~MASK(mb, me));
691: if (Rc(ctx->opcode) != 0)
692: gen_op_set_Rc0();
693: gen_op_store_T0_gpr(rA(ctx->opcode));
694: }
695: /* rlwinm & rlwinm. */
696: GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
697: {
698: uint32_t mb, me, sh;
699:
700: sh = SH(ctx->opcode);
701: mb = MB(ctx->opcode);
702: me = ME(ctx->opcode);
703: gen_op_load_gpr_T0(rS(ctx->opcode));
704: #if 1 // TRY
705: if (sh == 0) {
706: gen_op_andi_(MASK(mb, me));
707: goto store;
708: }
709: #endif
710: if (mb == 0) {
711: if (me == 31) {
712: gen_op_rotlwi(sh);
713: goto store;
714: #if 0
715: } else if (me == (31 - sh)) {
716: gen_op_slwi(sh);
717: goto store;
718: #endif
719: }
720: } else if (me == 31) {
721: #if 0
722: if (sh == (32 - mb)) {
723: gen_op_srwi(mb);
724: goto store;
725: }
726: #endif
727: }
728: gen_op_rlwinm(sh, MASK(mb, me));
729: store:
730: if (Rc(ctx->opcode) != 0)
731: gen_op_set_Rc0();
732: gen_op_store_T0_gpr(rA(ctx->opcode));
733: }
734: /* rlwnm & rlwnm. */
735: GEN_HANDLER(rlwnm, 0x17, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
736: {
737: uint32_t mb, me;
738:
739: mb = MB(ctx->opcode);
740: me = ME(ctx->opcode);
741: gen_op_load_gpr_T0(rS(ctx->opcode));
742: gen_op_load_gpr_T1(rB(ctx->opcode));
743: if (mb == 0 && me == 31) {
744: gen_op_rotl();
745: } else
746: {
747: gen_op_rlwnm(MASK(mb, me));
748: }
749: if (Rc(ctx->opcode) != 0)
750: gen_op_set_Rc0();
751: gen_op_store_T0_gpr(rA(ctx->opcode));
752: }
753:
754: /*** Integer shift ***/
755: /* slw & slw. */
756: __GEN_LOGICAL2(slw, 0x18, 0x00);
757: /* sraw & sraw. */
758: __GEN_LOGICAL2(sraw, 0x18, 0x18);
759: /* srawi & srawi. */
760: GEN_HANDLER(srawi, 0x1F, 0x18, 0x19, 0x00000000, PPC_INTEGER)
761: {
762: gen_op_load_gpr_T0(rS(ctx->opcode));
763: if (SH(ctx->opcode) != 0)
764: gen_op_srawi(SH(ctx->opcode), MASK(32 - SH(ctx->opcode), 31));
765: if (Rc(ctx->opcode) != 0)
766: gen_op_set_Rc0();
767: gen_op_store_T0_gpr(rA(ctx->opcode));
768: }
769: /* srw & srw. */
770: __GEN_LOGICAL2(srw, 0x18, 0x10);
771:
772: /*** Floating-Point arithmetic ***/
773: #define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat) \
774: GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, PPC_FLOAT) \
775: { \
776: if (!ctx->fpu_enabled) { \
777: RET_EXCP(ctx, EXCP_NO_FP, 0); \
778: return; \
779: } \
780: gen_op_reset_scrfx(); \
781: gen_op_load_fpr_FT0(rA(ctx->opcode)); \
782: gen_op_load_fpr_FT1(rC(ctx->opcode)); \
783: gen_op_load_fpr_FT2(rB(ctx->opcode)); \
784: gen_op_f##op(); \
785: if (isfloat) { \
786: gen_op_frsp(); \
787: } \
788: gen_op_store_FT0_fpr(rD(ctx->opcode)); \
789: if (Rc(ctx->opcode)) \
790: gen_op_set_Rc1(); \
791: }
792:
793: #define GEN_FLOAT_ACB(name, op2) \
794: _GEN_FLOAT_ACB(name, name, 0x3F, op2, 0); \
795: _GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1);
796:
797: #define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat) \
798: GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \
799: { \
800: if (!ctx->fpu_enabled) { \
801: RET_EXCP(ctx, EXCP_NO_FP, 0); \
802: return; \
803: } \
804: gen_op_reset_scrfx(); \
805: gen_op_load_fpr_FT0(rA(ctx->opcode)); \
806: gen_op_load_fpr_FT1(rB(ctx->opcode)); \
807: gen_op_f##op(); \
808: if (isfloat) { \
809: gen_op_frsp(); \
810: } \
811: gen_op_store_FT0_fpr(rD(ctx->opcode)); \
812: if (Rc(ctx->opcode)) \
813: gen_op_set_Rc1(); \
814: }
815: #define GEN_FLOAT_AB(name, op2, inval) \
816: _GEN_FLOAT_AB(name, name, 0x3F, op2, inval, 0); \
817: _GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1);
818:
819: #define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat) \
820: GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \
821: { \
822: if (!ctx->fpu_enabled) { \
823: RET_EXCP(ctx, EXCP_NO_FP, 0); \
824: return; \
825: } \
826: gen_op_reset_scrfx(); \
827: gen_op_load_fpr_FT0(rA(ctx->opcode)); \
828: gen_op_load_fpr_FT1(rC(ctx->opcode)); \
829: gen_op_f##op(); \
830: if (isfloat) { \
831: gen_op_frsp(); \
832: } \
833: gen_op_store_FT0_fpr(rD(ctx->opcode)); \
834: if (Rc(ctx->opcode)) \
835: gen_op_set_Rc1(); \
836: }
837: #define GEN_FLOAT_AC(name, op2, inval) \
838: _GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0); \
839: _GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1);
840:
841: #define GEN_FLOAT_B(name, op2, op3) \
842: GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, PPC_FLOAT) \
843: { \
844: if (!ctx->fpu_enabled) { \
845: RET_EXCP(ctx, EXCP_NO_FP, 0); \
846: return; \
847: } \
848: gen_op_reset_scrfx(); \
849: gen_op_load_fpr_FT0(rB(ctx->opcode)); \
850: gen_op_f##name(); \
851: gen_op_store_FT0_fpr(rD(ctx->opcode)); \
852: if (Rc(ctx->opcode)) \
853: gen_op_set_Rc1(); \
854: }
855:
856: #define GEN_FLOAT_BS(name, op1, op2) \
857: GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, PPC_FLOAT) \
858: { \
859: if (!ctx->fpu_enabled) { \
860: RET_EXCP(ctx, EXCP_NO_FP, 0); \
861: return; \
862: } \
863: gen_op_reset_scrfx(); \
864: gen_op_load_fpr_FT0(rB(ctx->opcode)); \
865: gen_op_f##name(); \
866: gen_op_store_FT0_fpr(rD(ctx->opcode)); \
867: if (Rc(ctx->opcode)) \
868: gen_op_set_Rc1(); \
869: }
870:
871: /* fadd - fadds */
872: GEN_FLOAT_AB(add, 0x15, 0x000007C0);
873: /* fdiv - fdivs */
874: GEN_FLOAT_AB(div, 0x12, 0x000007C0);
875: /* fmul - fmuls */
876: GEN_FLOAT_AC(mul, 0x19, 0x0000F800);
877:
878: /* fres */
879: GEN_FLOAT_BS(res, 0x3B, 0x18);
880:
881: /* frsqrte */
882: GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A);
883:
884: /* fsel */
885: _GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0);
886: /* fsub - fsubs */
887: GEN_FLOAT_AB(sub, 0x14, 0x000007C0);
888: /* Optional: */
889: /* fsqrt */
890: GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT)
891: {
892: if (!ctx->fpu_enabled) {
893: RET_EXCP(ctx, EXCP_NO_FP, 0);
894: return;
895: }
896: gen_op_reset_scrfx();
897: gen_op_load_fpr_FT0(rB(ctx->opcode));
898: gen_op_fsqrt();
899: gen_op_store_FT0_fpr(rD(ctx->opcode));
900: if (Rc(ctx->opcode))
901: gen_op_set_Rc1();
902: }
903:
904: GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT)
905: {
906: if (!ctx->fpu_enabled) {
907: RET_EXCP(ctx, EXCP_NO_FP, 0);
908: return;
909: }
910: gen_op_reset_scrfx();
911: gen_op_load_fpr_FT0(rB(ctx->opcode));
912: gen_op_fsqrt();
913: gen_op_frsp();
914: gen_op_store_FT0_fpr(rD(ctx->opcode));
915: if (Rc(ctx->opcode))
916: gen_op_set_Rc1();
917: }
918:
919: /*** Floating-Point multiply-and-add ***/
920: /* fmadd - fmadds */
921: GEN_FLOAT_ACB(madd, 0x1D);
922: /* fmsub - fmsubs */
923: GEN_FLOAT_ACB(msub, 0x1C);
924: /* fnmadd - fnmadds */
925: GEN_FLOAT_ACB(nmadd, 0x1F);
926: /* fnmsub - fnmsubs */
927: GEN_FLOAT_ACB(nmsub, 0x1E);
928:
929: /*** Floating-Point round & convert ***/
930: /* fctiw */
931: GEN_FLOAT_B(ctiw, 0x0E, 0x00);
932: /* fctiwz */
933: GEN_FLOAT_B(ctiwz, 0x0F, 0x00);
934: /* frsp */
935: GEN_FLOAT_B(rsp, 0x0C, 0x00);
936:
937: /*** Floating-Point compare ***/
938: /* fcmpo */
939: GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT)
940: {
941: if (!ctx->fpu_enabled) {
942: RET_EXCP(ctx, EXCP_NO_FP, 0);
943: return;
944: }
945: gen_op_reset_scrfx();
946: gen_op_load_fpr_FT0(rA(ctx->opcode));
947: gen_op_load_fpr_FT1(rB(ctx->opcode));
948: gen_op_fcmpo();
949: gen_op_store_T0_crf(crfD(ctx->opcode));
950: }
951:
952: /* fcmpu */
953: GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT)
954: {
955: if (!ctx->fpu_enabled) {
956: RET_EXCP(ctx, EXCP_NO_FP, 0);
957: return;
958: }
959: gen_op_reset_scrfx();
960: gen_op_load_fpr_FT0(rA(ctx->opcode));
961: gen_op_load_fpr_FT1(rB(ctx->opcode));
962: gen_op_fcmpu();
963: gen_op_store_T0_crf(crfD(ctx->opcode));
964: }
965:
966: /*** Floating-point move ***/
967: /* fabs */
968: GEN_FLOAT_B(abs, 0x08, 0x08);
969:
970: /* fmr - fmr. */
971: GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT)
972: {
973: if (!ctx->fpu_enabled) {
974: RET_EXCP(ctx, EXCP_NO_FP, 0);
975: return;
976: }
977: gen_op_reset_scrfx();
978: gen_op_load_fpr_FT0(rB(ctx->opcode));
979: gen_op_store_FT0_fpr(rD(ctx->opcode));
980: if (Rc(ctx->opcode))
981: gen_op_set_Rc1();
982: }
983:
984: /* fnabs */
985: GEN_FLOAT_B(nabs, 0x08, 0x04);
986: /* fneg */
987: GEN_FLOAT_B(neg, 0x08, 0x01);
988:
989: /*** Floating-Point status & ctrl register ***/
990: /* mcrfs */
991: GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT)
992: {
993: if (!ctx->fpu_enabled) {
994: RET_EXCP(ctx, EXCP_NO_FP, 0);
995: return;
996: }
997: gen_op_load_fpscr_T0(crfS(ctx->opcode));
998: gen_op_store_T0_crf(crfD(ctx->opcode));
999: gen_op_clear_fpscr(crfS(ctx->opcode));
1000: }
1001:
1002: /* mffs */
1003: GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT)
1004: {
1005: if (!ctx->fpu_enabled) {
1006: RET_EXCP(ctx, EXCP_NO_FP, 0);
1007: return;
1008: }
1009: gen_op_load_fpscr();
1010: gen_op_store_FT0_fpr(rD(ctx->opcode));
1011: if (Rc(ctx->opcode))
1012: gen_op_set_Rc1();
1013: }
1014:
1015: /* mtfsb0 */
1016: GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT)
1017: {
1018: uint8_t crb;
1019:
1020: if (!ctx->fpu_enabled) {
1021: RET_EXCP(ctx, EXCP_NO_FP, 0);
1022: return;
1023: }
1024: crb = crbD(ctx->opcode) >> 2;
1025: gen_op_load_fpscr_T0(crb);
1026: gen_op_andi_(~(1 << (crbD(ctx->opcode) & 0x03)));
1027: gen_op_store_T0_fpscr(crb);
1028: if (Rc(ctx->opcode))
1029: gen_op_set_Rc1();
1030: }
1031:
1032: /* mtfsb1 */
1033: GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT)
1034: {
1035: uint8_t crb;
1036:
1037: if (!ctx->fpu_enabled) {
1038: RET_EXCP(ctx, EXCP_NO_FP, 0);
1039: return;
1040: }
1041: crb = crbD(ctx->opcode) >> 2;
1042: gen_op_load_fpscr_T0(crb);
1043: gen_op_ori(1 << (crbD(ctx->opcode) & 0x03));
1044: gen_op_store_T0_fpscr(crb);
1045: if (Rc(ctx->opcode))
1046: gen_op_set_Rc1();
1047: }
1048:
1049: /* mtfsf */
1050: GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x02010000, PPC_FLOAT)
1051: {
1052: if (!ctx->fpu_enabled) {
1053: RET_EXCP(ctx, EXCP_NO_FP, 0);
1054: return;
1055: }
1056: gen_op_load_fpr_FT0(rB(ctx->opcode));
1057: gen_op_store_fpscr(FM(ctx->opcode));
1058: if (Rc(ctx->opcode))
1059: gen_op_set_Rc1();
1060: }
1061:
1062: /* mtfsfi */
1063: GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT)
1064: {
1065: if (!ctx->fpu_enabled) {
1066: RET_EXCP(ctx, EXCP_NO_FP, 0);
1067: return;
1068: }
1069: gen_op_store_T0_fpscri(crbD(ctx->opcode) >> 2, FPIMM(ctx->opcode));
1070: if (Rc(ctx->opcode))
1071: gen_op_set_Rc1();
1072: }
1073:
1074: /*** Integer load ***/
1075: #define op_ldst(name) (*gen_op_##name[ctx->mem_idx])()
1076: #if defined(CONFIG_USER_ONLY)
1077: #define OP_LD_TABLE(width) \
1078: static GenOpFunc *gen_op_l##width[] = { \
1079: &gen_op_l##width##_raw, \
1080: &gen_op_l##width##_le_raw, \
1081: };
1082: #define OP_ST_TABLE(width) \
1083: static GenOpFunc *gen_op_st##width[] = { \
1084: &gen_op_st##width##_raw, \
1085: &gen_op_st##width##_le_raw, \
1086: };
1087: /* Byte access routine are endian safe */
1088: #define gen_op_stb_le_raw gen_op_stb_raw
1089: #define gen_op_lbz_le_raw gen_op_lbz_raw
1090: #else
1091: #define OP_LD_TABLE(width) \
1092: static GenOpFunc *gen_op_l##width[] = { \
1093: &gen_op_l##width##_user, \
1094: &gen_op_l##width##_le_user, \
1095: &gen_op_l##width##_kernel, \
1096: &gen_op_l##width##_le_kernel, \
1097: };
1098: #define OP_ST_TABLE(width) \
1099: static GenOpFunc *gen_op_st##width[] = { \
1100: &gen_op_st##width##_user, \
1101: &gen_op_st##width##_le_user, \
1102: &gen_op_st##width##_kernel, \
1103: &gen_op_st##width##_le_kernel, \
1104: };
1105: /* Byte access routine are endian safe */
1106: #define gen_op_stb_le_user gen_op_stb_user
1107: #define gen_op_lbz_le_user gen_op_lbz_user
1108: #define gen_op_stb_le_kernel gen_op_stb_kernel
1109: #define gen_op_lbz_le_kernel gen_op_lbz_kernel
1110: #endif
1111:
1112: #define GEN_LD(width, opc) \
1113: GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
1114: { \
1115: uint32_t simm = SIMM(ctx->opcode); \
1116: if (rA(ctx->opcode) == 0) { \
1117: gen_op_set_T0(simm); \
1118: } else { \
1119: gen_op_load_gpr_T0(rA(ctx->opcode)); \
1120: if (simm != 0) \
1121: gen_op_addi(simm); \
1122: } \
1123: op_ldst(l##width); \
1124: gen_op_store_T1_gpr(rD(ctx->opcode)); \
1125: }
1126:
1127: #define GEN_LDU(width, opc) \
1128: GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
1129: { \
1130: uint32_t simm = SIMM(ctx->opcode); \
1131: if (rA(ctx->opcode) == 0 || \
1132: rA(ctx->opcode) == rD(ctx->opcode)) { \
1133: RET_INVAL(ctx); \
1134: return; \
1135: } \
1136: gen_op_load_gpr_T0(rA(ctx->opcode)); \
1137: if (simm != 0) \
1138: gen_op_addi(simm); \
1139: op_ldst(l##width); \
1140: gen_op_store_T1_gpr(rD(ctx->opcode)); \
1141: gen_op_store_T0_gpr(rA(ctx->opcode)); \
1142: }
1143:
1144: #define GEN_LDUX(width, opc) \
1145: GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \
1146: { \
1147: if (rA(ctx->opcode) == 0 || \
1148: rA(ctx->opcode) == rD(ctx->opcode)) { \
1149: RET_INVAL(ctx); \
1150: return; \
1151: } \
1152: gen_op_load_gpr_T0(rA(ctx->opcode)); \
1153: gen_op_load_gpr_T1(rB(ctx->opcode)); \
1154: gen_op_add(); \
1155: op_ldst(l##width); \
1156: gen_op_store_T1_gpr(rD(ctx->opcode)); \
1157: gen_op_store_T0_gpr(rA(ctx->opcode)); \
1158: }
1159:
1160: #define GEN_LDX(width, opc2, opc3) \
1161: GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \
1162: { \
1163: if (rA(ctx->opcode) == 0) { \
1164: gen_op_load_gpr_T0(rB(ctx->opcode)); \
1165: } else { \
1166: gen_op_load_gpr_T0(rA(ctx->opcode)); \
1167: gen_op_load_gpr_T1(rB(ctx->opcode)); \
1168: gen_op_add(); \
1169: } \
1170: op_ldst(l##width); \
1171: gen_op_store_T1_gpr(rD(ctx->opcode)); \
1172: }
1173:
1174: #define GEN_LDS(width, op) \
1175: OP_LD_TABLE(width); \
1176: GEN_LD(width, op | 0x20); \
1177: GEN_LDU(width, op | 0x21); \
1178: GEN_LDUX(width, op | 0x01); \
1179: GEN_LDX(width, 0x17, op | 0x00)
1180:
1181: /* lbz lbzu lbzux lbzx */
1182: GEN_LDS(bz, 0x02);
1183: /* lha lhau lhaux lhax */
1184: GEN_LDS(ha, 0x0A);
1185: /* lhz lhzu lhzux lhzx */
1186: GEN_LDS(hz, 0x08);
1187: /* lwz lwzu lwzux lwzx */
1188: GEN_LDS(wz, 0x00);
1189:
1190: /*** Integer store ***/
1191: #define GEN_ST(width, opc) \
1192: GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
1193: { \
1194: uint32_t simm = SIMM(ctx->opcode); \
1195: if (rA(ctx->opcode) == 0) { \
1196: gen_op_set_T0(simm); \
1197: } else { \
1198: gen_op_load_gpr_T0(rA(ctx->opcode)); \
1199: if (simm != 0) \
1200: gen_op_addi(simm); \
1201: } \
1202: gen_op_load_gpr_T1(rS(ctx->opcode)); \
1203: op_ldst(st##width); \
1204: }
1205:
1206: #define GEN_STU(width, opc) \
1207: GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
1208: { \
1209: uint32_t simm = SIMM(ctx->opcode); \
1210: if (rA(ctx->opcode) == 0) { \
1211: RET_INVAL(ctx); \
1212: return; \
1213: } \
1214: gen_op_load_gpr_T0(rA(ctx->opcode)); \
1215: if (simm != 0) \
1216: gen_op_addi(simm); \
1217: gen_op_load_gpr_T1(rS(ctx->opcode)); \
1218: op_ldst(st##width); \
1219: gen_op_store_T0_gpr(rA(ctx->opcode)); \
1220: }
1221:
1222: #define GEN_STUX(width, opc) \
1223: GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \
1224: { \
1225: if (rA(ctx->opcode) == 0) { \
1226: RET_INVAL(ctx); \
1227: return; \
1228: } \
1229: gen_op_load_gpr_T0(rA(ctx->opcode)); \
1230: gen_op_load_gpr_T1(rB(ctx->opcode)); \
1231: gen_op_add(); \
1232: gen_op_load_gpr_T1(rS(ctx->opcode)); \
1233: op_ldst(st##width); \
1234: gen_op_store_T0_gpr(rA(ctx->opcode)); \
1235: }
1236:
1237: #define GEN_STX(width, opc2, opc3) \
1238: GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \
1239: { \
1240: if (rA(ctx->opcode) == 0) { \
1241: gen_op_load_gpr_T0(rB(ctx->opcode)); \
1242: } else { \
1243: gen_op_load_gpr_T0(rA(ctx->opcode)); \
1244: gen_op_load_gpr_T1(rB(ctx->opcode)); \
1245: gen_op_add(); \
1246: } \
1247: gen_op_load_gpr_T1(rS(ctx->opcode)); \
1248: op_ldst(st##width); \
1249: }
1250:
1251: #define GEN_STS(width, op) \
1252: OP_ST_TABLE(width); \
1253: GEN_ST(width, op | 0x20); \
1254: GEN_STU(width, op | 0x21); \
1255: GEN_STUX(width, op | 0x01); \
1256: GEN_STX(width, 0x17, op | 0x00)
1257:
1258: /* stb stbu stbux stbx */
1259: GEN_STS(b, 0x06);
1260: /* sth sthu sthux sthx */
1261: GEN_STS(h, 0x0C);
1262: /* stw stwu stwux stwx */
1263: GEN_STS(w, 0x04);
1264:
1265: /*** Integer load and store with byte reverse ***/
1266: /* lhbrx */
1267: OP_LD_TABLE(hbr);
1268: GEN_LDX(hbr, 0x16, 0x18);
1269: /* lwbrx */
1270: OP_LD_TABLE(wbr);
1271: GEN_LDX(wbr, 0x16, 0x10);
1272: /* sthbrx */
1273: OP_ST_TABLE(hbr);
1274: GEN_STX(hbr, 0x16, 0x1C);
1275: /* stwbrx */
1276: OP_ST_TABLE(wbr);
1277: GEN_STX(wbr, 0x16, 0x14);
1278:
1279: /*** Integer load and store multiple ***/
1280: #define op_ldstm(name, reg) (*gen_op_##name[ctx->mem_idx])(reg)
1281: #if defined(CONFIG_USER_ONLY)
1282: static GenOpFunc1 *gen_op_lmw[] = {
1283: &gen_op_lmw_raw,
1284: &gen_op_lmw_le_raw,
1285: };
1286: static GenOpFunc1 *gen_op_stmw[] = {
1287: &gen_op_stmw_raw,
1288: &gen_op_stmw_le_raw,
1289: };
1290: #else
1291: static GenOpFunc1 *gen_op_lmw[] = {
1292: &gen_op_lmw_user,
1293: &gen_op_lmw_le_user,
1294: &gen_op_lmw_kernel,
1295: &gen_op_lmw_le_kernel,
1296: };
1297: static GenOpFunc1 *gen_op_stmw[] = {
1298: &gen_op_stmw_user,
1299: &gen_op_stmw_le_user,
1300: &gen_op_stmw_kernel,
1301: &gen_op_stmw_le_kernel,
1302: };
1303: #endif
1304:
1305: /* lmw */
1306: GEN_HANDLER(lmw, 0x2E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
1307: {
1308: int simm = SIMM(ctx->opcode);
1309:
1310: if (rA(ctx->opcode) == 0) {
1311: gen_op_set_T0(simm);
1312: } else {
1313: gen_op_load_gpr_T0(rA(ctx->opcode));
1314: if (simm != 0)
1315: gen_op_addi(simm);
1316: }
1317: op_ldstm(lmw, rD(ctx->opcode));
1318: }
1319:
1320: /* stmw */
1321: GEN_HANDLER(stmw, 0x2F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
1322: {
1323: int simm = SIMM(ctx->opcode);
1324:
1325: if (rA(ctx->opcode) == 0) {
1326: gen_op_set_T0(simm);
1327: } else {
1328: gen_op_load_gpr_T0(rA(ctx->opcode));
1329: if (simm != 0)
1330: gen_op_addi(simm);
1331: }
1332: op_ldstm(stmw, rS(ctx->opcode));
1333: }
1334:
1335: /*** Integer load and store strings ***/
1336: #define op_ldsts(name, start) (*gen_op_##name[ctx->mem_idx])(start)
1337: #define op_ldstsx(name, rd, ra, rb) (*gen_op_##name[ctx->mem_idx])(rd, ra, rb)
1338: #if defined(CONFIG_USER_ONLY)
1339: static GenOpFunc1 *gen_op_lswi[] = {
1340: &gen_op_lswi_raw,
1341: &gen_op_lswi_le_raw,
1342: };
1343: static GenOpFunc3 *gen_op_lswx[] = {
1344: &gen_op_lswx_raw,
1345: &gen_op_lswx_le_raw,
1346: };
1347: static GenOpFunc1 *gen_op_stsw[] = {
1348: &gen_op_stsw_raw,
1349: &gen_op_stsw_le_raw,
1350: };
1351: #else
1352: static GenOpFunc1 *gen_op_lswi[] = {
1353: &gen_op_lswi_user,
1354: &gen_op_lswi_le_user,
1355: &gen_op_lswi_kernel,
1356: &gen_op_lswi_le_kernel,
1357: };
1358: static GenOpFunc3 *gen_op_lswx[] = {
1359: &gen_op_lswx_user,
1360: &gen_op_lswx_le_user,
1361: &gen_op_lswx_kernel,
1362: &gen_op_lswx_le_kernel,
1363: };
1364: static GenOpFunc1 *gen_op_stsw[] = {
1365: &gen_op_stsw_user,
1366: &gen_op_stsw_le_user,
1367: &gen_op_stsw_kernel,
1368: &gen_op_stsw_le_kernel,
1369: };
1370: #endif
1371:
1372: /* lswi */
1373: /* PowerPC32 specification says we must generate an exception if
1374: * rA is in the range of registers to be loaded.
1375: * In an other hand, IBM says this is valid, but rA won't be loaded.
1376: * For now, I'll follow the spec...
1377: */
1378: GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_INTEGER)
1379: {
1380: int nb = NB(ctx->opcode);
1381: int start = rD(ctx->opcode);
1382: int ra = rA(ctx->opcode);
1383: int nr;
1384:
1385: if (nb == 0)
1386: nb = 32;
1387: nr = nb / 4;
1388: if (((start + nr) > 32 && start <= ra && (start + nr - 32) > ra) ||
1389: ((start + nr) <= 32 && start <= ra && (start + nr) > ra)) {
1390: RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX);
1391: return;
1392: }
1393: if (ra == 0) {
1394: gen_op_set_T0(0);
1395: } else {
1396: gen_op_load_gpr_T0(ra);
1397: }
1398: gen_op_set_T1(nb);
1399: /* NIP cannot be restored if the memory exception comes from an helper */
1400: gen_op_update_nip((ctx)->nip - 4);
1401: op_ldsts(lswi, start);
1402: }
1403:
1404: /* lswx */
1405: GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001, PPC_INTEGER)
1406: {
1407: int ra = rA(ctx->opcode);
1408: int rb = rB(ctx->opcode);
1409:
1410: if (ra == 0) {
1411: gen_op_load_gpr_T0(rb);
1412: ra = rb;
1413: } else {
1414: gen_op_load_gpr_T0(ra);
1415: gen_op_load_gpr_T1(rb);
1416: gen_op_add();
1417: }
1418: gen_op_load_xer_bc();
1419: /* NIP cannot be restored if the memory exception comes from an helper */
1420: gen_op_update_nip((ctx)->nip - 4);
1421: op_ldstsx(lswx, rD(ctx->opcode), ra, rb);
1422: }
1423:
1424: /* stswi */
1425: GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_INTEGER)
1426: {
1427: int nb = NB(ctx->opcode);
1428:
1429: if (rA(ctx->opcode) == 0) {
1430: gen_op_set_T0(0);
1431: } else {
1432: gen_op_load_gpr_T0(rA(ctx->opcode));
1433: }
1434: if (nb == 0)
1435: nb = 32;
1436: gen_op_set_T1(nb);
1437: /* NIP cannot be restored if the memory exception comes from an helper */
1438: gen_op_update_nip((ctx)->nip - 4);
1439: op_ldsts(stsw, rS(ctx->opcode));
1440: }
1441:
1442: /* stswx */
1443: GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_INTEGER)
1444: {
1445: int ra = rA(ctx->opcode);
1446:
1447: if (ra == 0) {
1448: gen_op_load_gpr_T0(rB(ctx->opcode));
1449: ra = rB(ctx->opcode);
1450: } else {
1451: gen_op_load_gpr_T0(ra);
1452: gen_op_load_gpr_T1(rB(ctx->opcode));
1453: gen_op_add();
1454: }
1455: gen_op_load_xer_bc();
1456: /* NIP cannot be restored if the memory exception comes from an helper */
1457: gen_op_update_nip((ctx)->nip - 4);
1458: op_ldsts(stsw, rS(ctx->opcode));
1459: }
1460:
1461: /*** Memory synchronisation ***/
1462: /* eieio */
1463: GEN_HANDLER(eieio, 0x1F, 0x16, 0x1A, 0x03FF0801, PPC_MEM)
1464: {
1465: }
1466:
1467: /* isync */
1468: GEN_HANDLER(isync, 0x13, 0x16, 0xFF, 0x03FF0801, PPC_MEM)
1469: {
1470: }
1471:
1472: #define op_lwarx() (*gen_op_lwarx[ctx->mem_idx])()
1473: #define op_stwcx() (*gen_op_stwcx[ctx->mem_idx])()
1474: #if defined(CONFIG_USER_ONLY)
1475: static GenOpFunc *gen_op_lwarx[] = {
1476: &gen_op_lwarx_raw,
1477: &gen_op_lwarx_le_raw,
1478: };
1479: static GenOpFunc *gen_op_stwcx[] = {
1480: &gen_op_stwcx_raw,
1481: &gen_op_stwcx_le_raw,
1482: };
1483: #else
1484: static GenOpFunc *gen_op_lwarx[] = {
1485: &gen_op_lwarx_user,
1486: &gen_op_lwarx_le_user,
1487: &gen_op_lwarx_kernel,
1488: &gen_op_lwarx_le_kernel,
1489: };
1490: static GenOpFunc *gen_op_stwcx[] = {
1491: &gen_op_stwcx_user,
1492: &gen_op_stwcx_le_user,
1493: &gen_op_stwcx_kernel,
1494: &gen_op_stwcx_le_kernel,
1495: };
1496: #endif
1497:
1498: /* lwarx */
1499: GEN_HANDLER(lwarx, 0x1F, 0x14, 0xFF, 0x00000001, PPC_RES)
1500: {
1501: if (rA(ctx->opcode) == 0) {
1502: gen_op_load_gpr_T0(rB(ctx->opcode));
1503: } else {
1504: gen_op_load_gpr_T0(rA(ctx->opcode));
1505: gen_op_load_gpr_T1(rB(ctx->opcode));
1506: gen_op_add();
1507: }
1508: op_lwarx();
1509: gen_op_store_T1_gpr(rD(ctx->opcode));
1510: }
1511:
1512: /* stwcx. */
1513: GEN_HANDLER(stwcx_, 0x1F, 0x16, 0x04, 0x00000000, PPC_RES)
1514: {
1515: if (rA(ctx->opcode) == 0) {
1516: gen_op_load_gpr_T0(rB(ctx->opcode));
1517: } else {
1518: gen_op_load_gpr_T0(rA(ctx->opcode));
1519: gen_op_load_gpr_T1(rB(ctx->opcode));
1520: gen_op_add();
1521: }
1522: gen_op_load_gpr_T1(rS(ctx->opcode));
1523: op_stwcx();
1524: }
1525:
1526: /* sync */
1527: GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_MEM)
1528: {
1529: }
1530:
1531: /*** Floating-point load ***/
1532: #define GEN_LDF(width, opc) \
1533: GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
1534: { \
1535: uint32_t simm = SIMM(ctx->opcode); \
1536: if (!ctx->fpu_enabled) { \
1537: RET_EXCP(ctx, EXCP_NO_FP, 0); \
1538: return; \
1539: } \
1540: if (rA(ctx->opcode) == 0) { \
1541: gen_op_set_T0(simm); \
1542: } else { \
1543: gen_op_load_gpr_T0(rA(ctx->opcode)); \
1544: if (simm != 0) \
1545: gen_op_addi(simm); \
1546: } \
1547: op_ldst(l##width); \
1548: gen_op_store_FT1_fpr(rD(ctx->opcode)); \
1549: }
1550:
1551: #define GEN_LDUF(width, opc) \
1552: GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
1553: { \
1554: uint32_t simm = SIMM(ctx->opcode); \
1555: if (!ctx->fpu_enabled) { \
1556: RET_EXCP(ctx, EXCP_NO_FP, 0); \
1557: return; \
1558: } \
1559: if (rA(ctx->opcode) == 0 || \
1560: rA(ctx->opcode) == rD(ctx->opcode)) { \
1561: RET_INVAL(ctx); \
1562: return; \
1563: } \
1564: gen_op_load_gpr_T0(rA(ctx->opcode)); \
1565: if (simm != 0) \
1566: gen_op_addi(simm); \
1567: op_ldst(l##width); \
1568: gen_op_store_FT1_fpr(rD(ctx->opcode)); \
1569: gen_op_store_T0_gpr(rA(ctx->opcode)); \
1570: }
1571:
1572: #define GEN_LDUXF(width, opc) \
1573: GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \
1574: { \
1575: if (!ctx->fpu_enabled) { \
1576: RET_EXCP(ctx, EXCP_NO_FP, 0); \
1577: return; \
1578: } \
1579: if (rA(ctx->opcode) == 0 || \
1580: rA(ctx->opcode) == rD(ctx->opcode)) { \
1581: RET_INVAL(ctx); \
1582: return; \
1583: } \
1584: gen_op_load_gpr_T0(rA(ctx->opcode)); \
1585: gen_op_load_gpr_T1(rB(ctx->opcode)); \
1586: gen_op_add(); \
1587: op_ldst(l##width); \
1588: gen_op_store_FT1_fpr(rD(ctx->opcode)); \
1589: gen_op_store_T0_gpr(rA(ctx->opcode)); \
1590: }
1591:
1592: #define GEN_LDXF(width, opc2, opc3) \
1593: GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_FLOAT) \
1594: { \
1595: if (!ctx->fpu_enabled) { \
1596: RET_EXCP(ctx, EXCP_NO_FP, 0); \
1597: return; \
1598: } \
1599: if (rA(ctx->opcode) == 0) { \
1600: gen_op_load_gpr_T0(rB(ctx->opcode)); \
1601: } else { \
1602: gen_op_load_gpr_T0(rA(ctx->opcode)); \
1603: gen_op_load_gpr_T1(rB(ctx->opcode)); \
1604: gen_op_add(); \
1605: } \
1606: op_ldst(l##width); \
1607: gen_op_store_FT1_fpr(rD(ctx->opcode)); \
1608: }
1609:
1610: #define GEN_LDFS(width, op) \
1611: OP_LD_TABLE(width); \
1612: GEN_LDF(width, op | 0x20); \
1613: GEN_LDUF(width, op | 0x21); \
1614: GEN_LDUXF(width, op | 0x01); \
1615: GEN_LDXF(width, 0x17, op | 0x00)
1616:
1617: /* lfd lfdu lfdux lfdx */
1618: GEN_LDFS(fd, 0x12);
1619: /* lfs lfsu lfsux lfsx */
1620: GEN_LDFS(fs, 0x10);
1621:
1622: /*** Floating-point store ***/
1623: #define GEN_STF(width, opc) \
1624: GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
1625: { \
1626: uint32_t simm = SIMM(ctx->opcode); \
1627: if (!ctx->fpu_enabled) { \
1628: RET_EXCP(ctx, EXCP_NO_FP, 0); \
1629: return; \
1630: } \
1631: if (rA(ctx->opcode) == 0) { \
1632: gen_op_set_T0(simm); \
1633: } else { \
1634: gen_op_load_gpr_T0(rA(ctx->opcode)); \
1635: if (simm != 0) \
1636: gen_op_addi(simm); \
1637: } \
1638: gen_op_load_fpr_FT1(rS(ctx->opcode)); \
1639: op_ldst(st##width); \
1640: }
1641:
1642: #define GEN_STUF(width, opc) \
1643: GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
1644: { \
1645: uint32_t simm = SIMM(ctx->opcode); \
1646: if (!ctx->fpu_enabled) { \
1647: RET_EXCP(ctx, EXCP_NO_FP, 0); \
1648: return; \
1649: } \
1650: if (rA(ctx->opcode) == 0) { \
1651: RET_INVAL(ctx); \
1652: return; \
1653: } \
1654: gen_op_load_gpr_T0(rA(ctx->opcode)); \
1655: if (simm != 0) \
1656: gen_op_addi(simm); \
1657: gen_op_load_fpr_FT1(rS(ctx->opcode)); \
1658: op_ldst(st##width); \
1659: gen_op_store_T0_gpr(rA(ctx->opcode)); \
1660: }
1661:
1662: #define GEN_STUXF(width, opc) \
1663: GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \
1664: { \
1665: if (!ctx->fpu_enabled) { \
1666: RET_EXCP(ctx, EXCP_NO_FP, 0); \
1667: return; \
1668: } \
1669: if (rA(ctx->opcode) == 0) { \
1670: RET_INVAL(ctx); \
1671: return; \
1672: } \
1673: gen_op_load_gpr_T0(rA(ctx->opcode)); \
1674: gen_op_load_gpr_T1(rB(ctx->opcode)); \
1675: gen_op_add(); \
1676: gen_op_load_fpr_FT1(rS(ctx->opcode)); \
1677: op_ldst(st##width); \
1678: gen_op_store_T0_gpr(rA(ctx->opcode)); \
1679: }
1680:
1681: #define GEN_STXF(width, opc2, opc3) \
1682: GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_FLOAT) \
1683: { \
1684: if (!ctx->fpu_enabled) { \
1685: RET_EXCP(ctx, EXCP_NO_FP, 0); \
1686: return; \
1687: } \
1688: if (rA(ctx->opcode) == 0) { \
1689: gen_op_load_gpr_T0(rB(ctx->opcode)); \
1690: } else { \
1691: gen_op_load_gpr_T0(rA(ctx->opcode)); \
1692: gen_op_load_gpr_T1(rB(ctx->opcode)); \
1693: gen_op_add(); \
1694: } \
1695: gen_op_load_fpr_FT1(rS(ctx->opcode)); \
1696: op_ldst(st##width); \
1697: }
1698:
1699: #define GEN_STFS(width, op) \
1700: OP_ST_TABLE(width); \
1701: GEN_STF(width, op | 0x20); \
1702: GEN_STUF(width, op | 0x21); \
1703: GEN_STUXF(width, op | 0x01); \
1704: GEN_STXF(width, 0x17, op | 0x00)
1705:
1706: /* stfd stfdu stfdux stfdx */
1707: GEN_STFS(fd, 0x16);
1708: /* stfs stfsu stfsux stfsx */
1709: GEN_STFS(fs, 0x14);
1710:
1711: /* Optional: */
1712: /* stfiwx */
1713: GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT)
1714: {
1715: if (!ctx->fpu_enabled) {
1716: RET_EXCP(ctx, EXCP_NO_FP, 0);
1717: return;
1718: }
1719: RET_INVAL(ctx);
1720: }
1721:
1722: /*** Branch ***/
1723:
1724: /* b ba bl bla */
1725: GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
1726: {
1727: uint32_t li, target;
1728:
1729: /* sign extend LI */
1730: li = ((int32_t)LI(ctx->opcode) << 6) >> 6;
1731:
1732: if (AA(ctx->opcode) == 0)
1733: target = ctx->nip + li - 4;
1734: else
1735: target = li;
1736: if (LK(ctx->opcode)) {
1737: gen_op_setlr(ctx->nip);
1738: }
1739: gen_op_b((long)ctx->tb, target);
1740: ctx->exception = EXCP_BRANCH;
1741: }
1742:
1743: #define BCOND_IM 0
1744: #define BCOND_LR 1
1745: #define BCOND_CTR 2
1746:
1747: static inline void gen_bcond(DisasContext *ctx, int type)
1748: {
1749: uint32_t target = 0;
1750: uint32_t bo = BO(ctx->opcode);
1751: uint32_t bi = BI(ctx->opcode);
1752: uint32_t mask;
1753: uint32_t li;
1754:
1755: if ((bo & 0x4) == 0)
1756: gen_op_dec_ctr();
1757: switch(type) {
1758: case BCOND_IM:
1759: li = (int32_t)((int16_t)(BD(ctx->opcode)));
1760: if (AA(ctx->opcode) == 0) {
1761: target = ctx->nip + li - 4;
1762: } else {
1763: target = li;
1764: }
1765: break;
1766: case BCOND_CTR:
1767: gen_op_movl_T1_ctr();
1768: break;
1769: default:
1770: case BCOND_LR:
1771: gen_op_movl_T1_lr();
1772: break;
1773: }
1774: if (LK(ctx->opcode)) {
1775: gen_op_setlr(ctx->nip);
1776: }
1777: if (bo & 0x10) {
1778: /* No CR condition */
1779: switch (bo & 0x6) {
1780: case 0:
1781: gen_op_test_ctr();
1782: break;
1783: case 2:
1784: gen_op_test_ctrz();
1785: break;
1786: default:
1787: case 4:
1788: case 6:
1789: if (type == BCOND_IM) {
1790: gen_op_b((long)ctx->tb, target);
1791: } else {
1792: gen_op_b_T1();
1793: }
1794: goto no_test;
1795: }
1796: } else {
1797: mask = 1 << (3 - (bi & 0x03));
1798: gen_op_load_crf_T0(bi >> 2);
1799: if (bo & 0x8) {
1800: switch (bo & 0x6) {
1801: case 0:
1802: gen_op_test_ctr_true(mask);
1803: break;
1804: case 2:
1805: gen_op_test_ctrz_true(mask);
1806: break;
1807: default:
1808: case 4:
1809: case 6:
1810: gen_op_test_true(mask);
1811: break;
1812: }
1813: } else {
1814: switch (bo & 0x6) {
1815: case 0:
1816: gen_op_test_ctr_false(mask);
1817: break;
1818: case 2:
1819: gen_op_test_ctrz_false(mask);
1820: break;
1821: default:
1822: case 4:
1823: case 6:
1824: gen_op_test_false(mask);
1825: break;
1826: }
1827: }
1828: }
1829: if (type == BCOND_IM) {
1830: gen_op_btest((long)ctx->tb, target, ctx->nip);
1831: } else {
1832: gen_op_btest_T1(ctx->nip);
1833: }
1834: no_test:
1835: ctx->exception = EXCP_BRANCH;
1836: }
1837:
1838: GEN_HANDLER(bc, 0x10, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
1839: {
1840: gen_bcond(ctx, BCOND_IM);
1841: }
1842:
1843: GEN_HANDLER(bcctr, 0x13, 0x10, 0x10, 0x00000000, PPC_FLOW)
1844: {
1845: gen_bcond(ctx, BCOND_CTR);
1846: }
1847:
1848: GEN_HANDLER(bclr, 0x13, 0x10, 0x00, 0x00000000, PPC_FLOW)
1849: {
1850: gen_bcond(ctx, BCOND_LR);
1851: }
1852:
1853: /*** Condition register logical ***/
1854: #define GEN_CRLOGIC(op, opc) \
1855: GEN_HANDLER(cr##op, 0x13, 0x01, opc, 0x00000001, PPC_INTEGER) \
1856: { \
1857: gen_op_load_crf_T0(crbA(ctx->opcode) >> 2); \
1858: gen_op_getbit_T0(3 - (crbA(ctx->opcode) & 0x03)); \
1859: gen_op_load_crf_T1(crbB(ctx->opcode) >> 2); \
1860: gen_op_getbit_T1(3 - (crbB(ctx->opcode) & 0x03)); \
1861: gen_op_##op(); \
1862: gen_op_load_crf_T1(crbD(ctx->opcode) >> 2); \
1863: gen_op_setcrfbit(~(1 << (3 - (crbD(ctx->opcode) & 0x03))), \
1864: 3 - (crbD(ctx->opcode) & 0x03)); \
1865: gen_op_store_T1_crf(crbD(ctx->opcode) >> 2); \
1866: }
1867:
1868: /* crand */
1869: GEN_CRLOGIC(and, 0x08)
1870: /* crandc */
1871: GEN_CRLOGIC(andc, 0x04)
1872: /* creqv */
1873: GEN_CRLOGIC(eqv, 0x09)
1874: /* crnand */
1875: GEN_CRLOGIC(nand, 0x07)
1876: /* crnor */
1877: GEN_CRLOGIC(nor, 0x01)
1878: /* cror */
1879: GEN_CRLOGIC(or, 0x0E)
1880: /* crorc */
1881: GEN_CRLOGIC(orc, 0x0D)
1882: /* crxor */
1883: GEN_CRLOGIC(xor, 0x06)
1884: /* mcrf */
1885: GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER)
1886: {
1887: gen_op_load_crf_T0(crfS(ctx->opcode));
1888: gen_op_store_T0_crf(crfD(ctx->opcode));
1889: }
1890:
1891: /*** System linkage ***/
1892: /* rfi (supervisor only) */
1893: GEN_HANDLER(rfi, 0x13, 0x12, 0xFF, 0x03FF8001, PPC_FLOW)
1894: {
1895: #if defined(CONFIG_USER_ONLY)
1896: RET_PRIVOPC(ctx);
1897: #else
1898: /* Restore CPU state */
1899: if (!ctx->supervisor) {
1900: RET_PRIVOPC(ctx);
1901: return;
1902: }
1903: gen_op_rfi();
1904: RET_CHG_FLOW(ctx);
1905: #endif
1906: }
1907:
1908: /* sc */
1909: GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFFFFD, PPC_FLOW)
1910: {
1911: #if defined(CONFIG_USER_ONLY)
1912: RET_EXCP(ctx, EXCP_SYSCALL_USER, 0);
1913: #else
1914: RET_EXCP(ctx, EXCP_SYSCALL, 0);
1915: #endif
1916: }
1917:
1918: /*** Trap ***/
1919: /* tw */
1920: GEN_HANDLER(tw, 0x1F, 0x04, 0xFF, 0x00000001, PPC_FLOW)
1921: {
1922: gen_op_load_gpr_T0(rA(ctx->opcode));
1923: gen_op_load_gpr_T1(rB(ctx->opcode));
1924: gen_op_tw(TO(ctx->opcode));
1925: }
1926:
1927: /* twi */
1928: GEN_HANDLER(twi, 0x03, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
1929: {
1930: gen_op_load_gpr_T0(rA(ctx->opcode));
1931: #if 0
1932: printf("%s: param=0x%04x T0=0x%04x\n", __func__,
1933: SIMM(ctx->opcode), TO(ctx->opcode));
1934: #endif
1935: gen_op_twi(SIMM(ctx->opcode), TO(ctx->opcode));
1936: }
1937:
1938: /*** Processor control ***/
1939: static inline int check_spr_access (int spr, int rw, int supervisor)
1940: {
1941: uint32_t rights = spr_access[spr >> 1] >> (4 * (spr & 1));
1942:
1943: #if 0
1944: if (spr != LR && spr != CTR) {
1945: if (loglevel > 0) {
1946: fprintf(logfile, "%s reg=%d s=%d rw=%d r=0x%02x 0x%02x\n", __func__,
1947: SPR_ENCODE(spr), supervisor, rw, rights,
1948: (rights >> ((2 * supervisor) + rw)) & 1);
1949: } else {
1950: printf("%s reg=%d s=%d rw=%d r=0x%02x 0x%02x\n", __func__,
1951: SPR_ENCODE(spr), supervisor, rw, rights,
1952: (rights >> ((2 * supervisor) + rw)) & 1);
1953: }
1954: }
1955: #endif
1956: if (rights == 0)
1957: return -1;
1958: rights = rights >> (2 * supervisor);
1959: rights = rights >> rw;
1960:
1961: return rights & 1;
1962: }
1963:
1964: /* mcrxr */
1965: GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC)
1966: {
1967: gen_op_load_xer_cr();
1968: gen_op_store_T0_crf(crfD(ctx->opcode));
1969: gen_op_clear_xer_cr();
1970: }
1971:
1972: /* mfcr */
1973: GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x001FF801, PPC_MISC)
1974: {
1975: gen_op_load_cr();
1976: gen_op_store_T0_gpr(rD(ctx->opcode));
1977: }
1978:
1979: /* mfmsr */
1980: GEN_HANDLER(mfmsr, 0x1F, 0x13, 0x02, 0x001FF801, PPC_MISC)
1981: {
1982: #if defined(CONFIG_USER_ONLY)
1983: RET_PRIVREG(ctx);
1984: #else
1985: if (!ctx->supervisor) {
1986: RET_PRIVREG(ctx);
1987: return;
1988: }
1989: gen_op_load_msr();
1990: gen_op_store_T0_gpr(rD(ctx->opcode));
1991: #endif
1992: }
1993:
1994: #if 0
1995: #define SPR_NOACCESS ((void *)(-1))
1996: #else
1997: static void spr_noaccess (void *opaque, int sprn)
1998: {
1999: sprn = ((sprn >> 5) & 0x1F) | ((sprn & 0x1F) << 5);
2000: printf("ERROR: try to access SPR %d !\n", sprn);
2001: }
2002: #define SPR_NOACCESS (&spr_noaccess)
2003: #endif
2004:
2005: /* mfspr */
2006: static inline void gen_op_mfspr (DisasContext *ctx)
2007: {
2008: void (*read_cb)(void *opaque, int sprn);
2009: uint32_t sprn = SPR(ctx->opcode);
2010:
2011: #if !defined(CONFIG_USER_ONLY)
2012: if (ctx->supervisor)
2013: read_cb = ctx->spr_cb[sprn].oea_read;
2014: else
2015: #endif
2016: read_cb = ctx->spr_cb[sprn].uea_read;
2017: if (read_cb != NULL) {
2018: if (read_cb != SPR_NOACCESS) {
2019: (*read_cb)(ctx, sprn);
2020: gen_op_store_T0_gpr(rD(ctx->opcode));
2021: } else {
2022: /* Privilege exception */
2023: printf("Trying to read priviledged spr %d %03x\n", sprn, sprn);
2024: RET_PRIVREG(ctx);
2025: }
2026: } else {
2027: /* Not defined */
2028: printf("Trying to read invalid spr %d %03x\n", sprn, sprn);
2029: RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
2030: }
2031: }
2032:
2033: GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC)
2034: {
2035: gen_op_mfspr(ctx);
2036: }
2037:
2038: /* mftb */
2039: GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_TB)
2040: {
2041: gen_op_mfspr(ctx);
2042: }
2043:
2044: /* mtcrf */
2045: /* The mask should be 0x00100801, but Mac OS X 10.4 use an alternate form */
2046: GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00000801, PPC_MISC)
2047: {
2048: gen_op_load_gpr_T0(rS(ctx->opcode));
2049: gen_op_store_cr(CRM(ctx->opcode));
2050: }
2051:
2052: /* mtmsr */
2053: GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC)
2054: {
2055: #if defined(CONFIG_USER_ONLY)
2056: RET_PRIVREG(ctx);
2057: #else
2058: if (!ctx->supervisor) {
2059: RET_PRIVREG(ctx);
2060: return;
2061: }
2062: gen_op_load_gpr_T0(rS(ctx->opcode));
2063: gen_op_store_msr();
2064: /* Must stop the translation as machine state (may have) changed */
2065: RET_MTMSR(ctx);
2066: #endif
2067: }
2068:
2069: /* mtspr */
2070: GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC)
2071: {
2072: void (*write_cb)(void *opaque, int sprn);
2073: uint32_t sprn = SPR(ctx->opcode);
2074:
2075: #if !defined(CONFIG_USER_ONLY)
2076: if (ctx->supervisor)
2077: write_cb = ctx->spr_cb[sprn].oea_write;
2078: else
2079: #endif
2080: write_cb = ctx->spr_cb[sprn].uea_write;
2081: if (write_cb != NULL) {
2082: if (write_cb != SPR_NOACCESS) {
2083: gen_op_load_gpr_T0(rS(ctx->opcode));
2084: (*write_cb)(ctx, sprn);
2085: } else {
2086: /* Privilege exception */
2087: printf("Trying to write priviledged spr %d %03x\n", sprn, sprn);
2088: RET_PRIVREG(ctx);
2089: }
2090: } else {
2091: /* Not defined */
2092: printf("Trying to write invalid spr %d %03x\n", sprn, sprn);
2093: RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
2094: }
2095: }
2096:
2097: /*** Cache management ***/
2098: /* For now, all those will be implemented as nop:
2099: * this is valid, regarding the PowerPC specs...
2100: * We just have to flush tb while invalidating instruction cache lines...
2101: */
2102: /* dcbf */
2103: GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03E00001, PPC_CACHE)
2104: {
2105: if (rA(ctx->opcode) == 0) {
2106: gen_op_load_gpr_T0(rB(ctx->opcode));
2107: } else {
2108: gen_op_load_gpr_T0(rA(ctx->opcode));
2109: gen_op_load_gpr_T1(rB(ctx->opcode));
2110: gen_op_add();
2111: }
2112: op_ldst(lbz);
2113: }
2114:
2115: /* dcbi (Supervisor only) */
2116: GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE)
2117: {
2118: #if defined(CONFIG_USER_ONLY)
2119: RET_PRIVOPC(ctx);
2120: #else
2121: if (!ctx->supervisor) {
2122: RET_PRIVOPC(ctx);
2123: return;
2124: }
2125: if (rA(ctx->opcode) == 0) {
2126: gen_op_load_gpr_T0(rB(ctx->opcode));
2127: } else {
2128: gen_op_load_gpr_T0(rA(ctx->opcode));
2129: gen_op_load_gpr_T1(rB(ctx->opcode));
2130: gen_op_add();
2131: }
2132: op_ldst(lbz);
2133: op_ldst(stb);
2134: #endif
2135: }
2136:
2137: /* dcdst */
2138: GEN_HANDLER(dcbst, 0x1F, 0x16, 0x01, 0x03E00001, PPC_CACHE)
2139: {
2140: if (rA(ctx->opcode) == 0) {
2141: gen_op_load_gpr_T0(rB(ctx->opcode));
2142: } else {
2143: gen_op_load_gpr_T0(rA(ctx->opcode));
2144: gen_op_load_gpr_T1(rB(ctx->opcode));
2145: gen_op_add();
2146: }
2147: op_ldst(lbz);
2148: }
2149:
2150: /* dcbt */
2151: GEN_HANDLER(dcbt, 0x1F, 0x16, 0x08, 0x03E00001, PPC_CACHE)
2152: {
2153: }
2154:
2155: /* dcbtst */
2156: GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x03E00001, PPC_CACHE)
2157: {
2158: }
2159:
2160: /* dcbz */
2161: #if defined(CONFIG_USER_ONLY)
2162: #define op_dcbz() gen_op_dcbz_raw()
2163: #else
2164: #define op_dcbz() (*gen_op_dcbz[ctx->mem_idx])()
2165: static GenOpFunc *gen_op_dcbz[] = {
2166: &gen_op_dcbz_user,
2167: &gen_op_dcbz_user,
2168: &gen_op_dcbz_kernel,
2169: &gen_op_dcbz_kernel,
2170: };
2171: #endif
2172:
2173: GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE)
2174: {
2175: if (rA(ctx->opcode) == 0) {
2176: gen_op_load_gpr_T0(rB(ctx->opcode));
2177: } else {
2178: gen_op_load_gpr_T0(rA(ctx->opcode));
2179: gen_op_load_gpr_T1(rB(ctx->opcode));
2180: gen_op_add();
2181: }
2182: op_dcbz();
2183: gen_op_check_reservation();
2184: }
2185:
2186: /* icbi */
2187: GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_CACHE)
2188: {
2189: if (rA(ctx->opcode) == 0) {
2190: gen_op_load_gpr_T0(rB(ctx->opcode));
2191: } else {
2192: gen_op_load_gpr_T0(rA(ctx->opcode));
2193: gen_op_load_gpr_T1(rB(ctx->opcode));
2194: gen_op_add();
2195: }
2196: gen_op_icbi();
2197: }
2198:
2199: /* Optional: */
2200: /* dcba */
2201: GEN_HANDLER(dcba, 0x1F, 0x16, 0x17, 0x03E00001, PPC_CACHE_OPT)
2202: {
2203: }
2204:
2205: /*** Segment register manipulation ***/
2206: /* Supervisor only: */
2207: /* mfsr */
2208: GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT)
2209: {
2210: #if defined(CONFIG_USER_ONLY)
2211: RET_PRIVREG(ctx);
2212: #else
2213: if (!ctx->supervisor) {
2214: RET_PRIVREG(ctx);
2215: return;
2216: }
2217: gen_op_load_sr(SR(ctx->opcode));
2218: gen_op_store_T0_gpr(rD(ctx->opcode));
2219: #endif
2220: }
2221:
2222: /* mfsrin */
2223: GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT)
2224: {
2225: #if defined(CONFIG_USER_ONLY)
2226: RET_PRIVREG(ctx);
2227: #else
2228: if (!ctx->supervisor) {
2229: RET_PRIVREG(ctx);
2230: return;
2231: }
2232: gen_op_load_gpr_T1(rB(ctx->opcode));
2233: gen_op_load_srin();
2234: gen_op_store_T0_gpr(rD(ctx->opcode));
2235: #endif
2236: }
2237:
2238: /* mtsr */
2239: GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT)
2240: {
2241: #if defined(CONFIG_USER_ONLY)
2242: RET_PRIVREG(ctx);
2243: #else
2244: if (!ctx->supervisor) {
2245: RET_PRIVREG(ctx);
2246: return;
2247: }
2248: gen_op_load_gpr_T0(rS(ctx->opcode));
2249: gen_op_store_sr(SR(ctx->opcode));
2250: #endif
2251: }
2252:
2253: /* mtsrin */
2254: GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT)
2255: {
2256: #if defined(CONFIG_USER_ONLY)
2257: RET_PRIVREG(ctx);
2258: #else
2259: if (!ctx->supervisor) {
2260: RET_PRIVREG(ctx);
2261: return;
2262: }
2263: gen_op_load_gpr_T0(rS(ctx->opcode));
2264: gen_op_load_gpr_T1(rB(ctx->opcode));
2265: gen_op_store_srin();
2266: #endif
2267: }
2268:
2269: /*** Lookaside buffer management ***/
2270: /* Optional & supervisor only: */
2271: /* tlbia */
2272: GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA)
2273: {
2274: #if defined(CONFIG_USER_ONLY)
2275: RET_PRIVOPC(ctx);
2276: #else
2277: if (!ctx->supervisor) {
2278: if (loglevel)
2279: fprintf(logfile, "%s: ! supervisor\n", __func__);
2280: RET_PRIVOPC(ctx);
2281: return;
2282: }
2283: gen_op_tlbia();
2284: RET_MTMSR(ctx);
2285: #endif
2286: }
2287:
2288: /* tlbie */
2289: GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM)
2290: {
2291: #if defined(CONFIG_USER_ONLY)
2292: RET_PRIVOPC(ctx);
2293: #else
2294: if (!ctx->supervisor) {
2295: RET_PRIVOPC(ctx);
2296: return;
2297: }
2298: gen_op_load_gpr_T0(rB(ctx->opcode));
2299: gen_op_tlbie();
2300: RET_MTMSR(ctx);
2301: #endif
2302: }
2303:
2304: /* tlbsync */
2305: GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM)
2306: {
2307: #if defined(CONFIG_USER_ONLY)
2308: RET_PRIVOPC(ctx);
2309: #else
2310: if (!ctx->supervisor) {
2311: RET_PRIVOPC(ctx);
2312: return;
2313: }
2314: /* This has no effect: it should ensure that all previous
2315: * tlbie have completed
2316: */
2317: RET_MTMSR(ctx);
2318: #endif
2319: }
2320:
2321: /*** External control ***/
2322: /* Optional: */
2323: #define op_eciwx() (*gen_op_eciwx[ctx->mem_idx])()
2324: #define op_ecowx() (*gen_op_ecowx[ctx->mem_idx])()
2325: #if defined(CONFIG_USER_ONLY)
2326: static GenOpFunc *gen_op_eciwx[] = {
2327: &gen_op_eciwx_raw,
2328: &gen_op_eciwx_le_raw,
2329: };
2330: static GenOpFunc *gen_op_ecowx[] = {
2331: &gen_op_ecowx_raw,
2332: &gen_op_ecowx_le_raw,
2333: };
2334: #else
2335: static GenOpFunc *gen_op_eciwx[] = {
2336: &gen_op_eciwx_user,
2337: &gen_op_eciwx_le_user,
2338: &gen_op_eciwx_kernel,
2339: &gen_op_eciwx_le_kernel,
2340: };
2341: static GenOpFunc *gen_op_ecowx[] = {
2342: &gen_op_ecowx_user,
2343: &gen_op_ecowx_le_user,
2344: &gen_op_ecowx_kernel,
2345: &gen_op_ecowx_le_kernel,
2346: };
2347: #endif
2348:
2349: /* eciwx */
2350: GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN)
2351: {
2352: /* Should check EAR[E] & alignment ! */
2353: if (rA(ctx->opcode) == 0) {
2354: gen_op_load_gpr_T0(rB(ctx->opcode));
2355: } else {
2356: gen_op_load_gpr_T0(rA(ctx->opcode));
2357: gen_op_load_gpr_T1(rB(ctx->opcode));
2358: gen_op_add();
2359: }
2360: op_eciwx();
2361: gen_op_store_T0_gpr(rD(ctx->opcode));
2362: }
2363:
2364: /* ecowx */
2365: GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN)
2366: {
2367: /* Should check EAR[E] & alignment ! */
2368: if (rA(ctx->opcode) == 0) {
2369: gen_op_load_gpr_T0(rB(ctx->opcode));
2370: } else {
2371: gen_op_load_gpr_T0(rA(ctx->opcode));
2372: gen_op_load_gpr_T1(rB(ctx->opcode));
2373: gen_op_add();
2374: }
2375: gen_op_load_gpr_T2(rS(ctx->opcode));
2376: op_ecowx();
2377: }
2378:
2379: /* End opcode list */
2380: GEN_OPCODE_MARK(end);
2381:
2382: #include "translate_init.c"
2383:
2384: /*****************************************************************************/
2385: /* Misc PowerPC helpers */
2386: void cpu_dump_state(CPUState *env, FILE *f,
2387: int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
2388: int flags)
2389: {
2390: #if defined(TARGET_PPC64) || 1
2391: #define FILL ""
2392: #define REGX "%016llx"
2393: #define RGPL 4
2394: #define RFPL 4
2395: #else
2396: #define FILL " "
2397: #define REGX "%08llx"
2398: #define RGPL 8
2399: #define RFPL 4
2400: #endif
2401:
2402: int i;
2403:
2404: cpu_fprintf(f, "NIP " REGX " LR " REGX " CTR " REGX "\n",
2405: env->nip, env->lr, env->ctr);
2406: cpu_fprintf(f, "MSR " REGX FILL " XER %08x TB %08x %08x DECR %08x\n",
2407: do_load_msr(env), do_load_xer(env), cpu_ppc_load_tbu(env),
2408: cpu_ppc_load_tbl(env), cpu_ppc_load_decr(env));
2409: for (i = 0; i < 32; i++) {
2410: if ((i & (RGPL - 1)) == 0)
2411: cpu_fprintf(f, "GPR%02d", i);
2412: cpu_fprintf(f, " " REGX, env->gpr[i]);
2413: if ((i & (RGPL - 1)) == (RGPL - 1))
2414: cpu_fprintf(f, "\n");
2415: }
2416: cpu_fprintf(f, "CR ");
2417: for (i = 0; i < 8; i++)
2418: cpu_fprintf(f, "%01x", env->crf[i]);
2419: cpu_fprintf(f, " [");
2420: for (i = 0; i < 8; i++) {
2421: char a = '-';
2422: if (env->crf[i] & 0x08)
2423: a = 'L';
2424: else if (env->crf[i] & 0x04)
2425: a = 'G';
2426: else if (env->crf[i] & 0x02)
2427: a = 'E';
2428: cpu_fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' ');
2429: }
2430: cpu_fprintf(f, " ] " FILL "RES " REGX "\n", env->reserve);
2431: for (i = 0; i < 32; i++) {
2432: if ((i & (RFPL - 1)) == 0)
2433: cpu_fprintf(f, "FPR%02d", i);
2434: cpu_fprintf(f, " %016llx", *((uint64_t *)&env->fpr[i]));
2435: if ((i & (RFPL - 1)) == (RFPL - 1))
2436: cpu_fprintf(f, "\n");
2437: }
2438: cpu_fprintf(f, "SRR0 " REGX " SRR1 " REGX " " FILL FILL FILL
2439: "SDR1 " REGX "\n",
2440: env->spr[SPR_SRR0], env->spr[SPR_SRR1], env->sdr1);
2441:
2442: #undef REGX
2443: #undef RGPL
2444: #undef RFPL
2445: #undef FILL
2446: }
2447:
2448: /*****************************************************************************/
2449: int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
2450: int search_pc)
2451: {
2452: DisasContext ctx, *ctxp = &ctx;
2453: opc_handler_t **table, *handler;
2454: target_ulong pc_start;
2455: uint16_t *gen_opc_end;
2456: int j, lj = -1;
2457:
2458: pc_start = tb->pc;
2459: gen_opc_ptr = gen_opc_buf;
2460: gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
2461: gen_opparam_ptr = gen_opparam_buf;
2462: ctx.nip = pc_start;
2463: ctx.tb = tb;
2464: ctx.exception = EXCP_NONE;
2465: ctx.spr_cb = env->spr_cb;
2466: #if defined(CONFIG_USER_ONLY)
2467: ctx.mem_idx = msr_le;
2468: #else
2469: ctx.supervisor = 1 - msr_pr;
2470: ctx.mem_idx = ((1 - msr_pr) << 1) | msr_le;
2471: #endif
2472: ctx.fpu_enabled = msr_fp;
2473: #if defined (DO_SINGLE_STEP) && 0
2474: /* Single step trace mode */
2475: msr_se = 1;
2476: #endif
2477: /* Set env in case of segfault during code fetch */
2478: while (ctx.exception == EXCP_NONE && gen_opc_ptr < gen_opc_end) {
2479: if (search_pc) {
2480: j = gen_opc_ptr - gen_opc_buf;
2481: if (lj < j) {
2482: lj++;
2483: while (lj < j)
2484: gen_opc_instr_start[lj++] = 0;
2485: gen_opc_pc[lj] = ctx.nip;
2486: gen_opc_instr_start[lj] = 1;
2487: }
2488: }
2489: #if defined PPC_DEBUG_DISAS
2490: if (loglevel & CPU_LOG_TB_IN_ASM) {
2491: fprintf(logfile, "----------------\n");
2492: fprintf(logfile, "nip=%08x super=%d ir=%d\n",
2493: ctx.nip, 1 - msr_pr, msr_ir);
2494: }
2495: #endif
2496: ctx.opcode = ldl_code(ctx.nip);
2497: if (msr_le) {
2498: ctx.opcode = ((ctx.opcode & 0xFF000000) >> 24) |
2499: ((ctx.opcode & 0x00FF0000) >> 8) |
2500: ((ctx.opcode & 0x0000FF00) << 8) |
2501: ((ctx.opcode & 0x000000FF) << 24);
2502: }
2503: #if defined PPC_DEBUG_DISAS
2504: if (loglevel & CPU_LOG_TB_IN_ASM) {
2505: fprintf(logfile, "translate opcode %08x (%02x %02x %02x) (%s)\n",
2506: ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode),
2507: opc3(ctx.opcode), msr_le ? "little" : "big");
2508: }
2509: #endif
2510: ctx.nip += 4;
2511: table = env->opcodes;
2512: handler = table[opc1(ctx.opcode)];
2513: if (is_indirect_opcode(handler)) {
2514: table = ind_table(handler);
2515: handler = table[opc2(ctx.opcode)];
2516: if (is_indirect_opcode(handler)) {
2517: table = ind_table(handler);
2518: handler = table[opc3(ctx.opcode)];
2519: }
2520: }
2521: /* Is opcode *REALLY* valid ? */
2522: if (handler->handler == &gen_invalid) {
2523: if (loglevel > 0) {
2524: fprintf(logfile, "invalid/unsupported opcode: "
2525: "%02x - %02x - %02x (%08x) 0x%08x %d\n",
2526: opc1(ctx.opcode), opc2(ctx.opcode),
2527: opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir);
2528: } else {
2529: printf("invalid/unsupported opcode: "
2530: "%02x - %02x - %02x (%08x) 0x%08x %d\n",
2531: opc1(ctx.opcode), opc2(ctx.opcode),
2532: opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir);
2533: }
2534: } else {
2535: if ((ctx.opcode & handler->inval) != 0) {
2536: if (loglevel > 0) {
2537: fprintf(logfile, "invalid bits: %08x for opcode: "
2538: "%02x -%02x - %02x (0x%08x) (0x%08x)\n",
2539: ctx.opcode & handler->inval, opc1(ctx.opcode),
2540: opc2(ctx.opcode), opc3(ctx.opcode),
2541: ctx.opcode, ctx.nip - 4);
2542: } else {
2543: printf("invalid bits: %08x for opcode: "
2544: "%02x -%02x - %02x (0x%08x) (0x%08x)\n",
2545: ctx.opcode & handler->inval, opc1(ctx.opcode),
2546: opc2(ctx.opcode), opc3(ctx.opcode),
2547: ctx.opcode, ctx.nip - 4);
2548: }
2549: RET_INVAL(ctxp);
2550: break;
2551: }
2552: }
2553: (*(handler->handler))(&ctx);
2554: /* Check trace mode exceptions */
2555: if ((msr_be && ctx.exception == EXCP_BRANCH) ||
2556: /* Check in single step trace mode
2557: * we need to stop except if:
2558: * - rfi, trap or syscall
2559: * - first instruction of an exception handler
2560: */
2561: (msr_se && (ctx.nip < 0x100 ||
2562: ctx.nip > 0xF00 ||
2563: (ctx.nip & 0xFC) != 0x04) &&
2564: ctx.exception != EXCP_SYSCALL &&
2565: ctx.exception != EXCP_SYSCALL_USER &&
2566: ctx.exception != EXCP_TRAP)) {
2567: RET_EXCP(ctxp, EXCP_TRACE, 0);
2568: }
2569: /* if we reach a page boundary, stop generation */
2570: if ((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) {
2571: break;
2572: }
2573: #if defined (DO_SINGLE_STEP)
2574: break;
2575: #endif
2576: }
2577: if (ctx.exception == EXCP_NONE) {
2578: gen_op_b((unsigned long)ctx.tb, ctx.nip);
2579: } else if (ctx.exception != EXCP_BRANCH) {
2580: gen_op_set_T0(0);
2581: }
2582: #if 1
2583: /* TO BE FIXED: T0 hasn't got a proper value, which makes tb_add_jump
2584: * do bad business and then qemu crashes !
2585: */
2586: gen_op_set_T0(0);
2587: #endif
2588: /* Generate the return instruction */
2589: gen_op_exit_tb();
2590: *gen_opc_ptr = INDEX_op_end;
2591: if (search_pc) {
2592: j = gen_opc_ptr - gen_opc_buf;
2593: lj++;
2594: while (lj <= j)
2595: gen_opc_instr_start[lj++] = 0;
2596: tb->size = 0;
2597: #if 0
2598: if (loglevel > 0) {
2599: page_dump(logfile);
2600: }
2601: #endif
2602: } else {
2603: tb->size = ctx.nip - pc_start;
2604: }
2605: #ifdef DEBUG_DISAS
2606: if (loglevel & CPU_LOG_TB_CPU) {
2607: fprintf(logfile, "---------------- excp: %04x\n", ctx.exception);
2608: cpu_dump_state(env, logfile, fprintf, 0);
2609: }
2610: if (loglevel & CPU_LOG_TB_IN_ASM) {
2611: fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
2612: target_disas(logfile, pc_start, ctx.nip - pc_start, 0);
2613: fprintf(logfile, "\n");
2614: }
2615: if (loglevel & CPU_LOG_TB_OP) {
2616: fprintf(logfile, "OP:\n");
2617: dump_ops(gen_opc_buf, gen_opparam_buf);
2618: fprintf(logfile, "\n");
2619: }
2620: #endif
2621: return 0;
2622: }
2623:
2624: int gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
2625: {
2626: return gen_intermediate_code_internal(env, tb, 0);
2627: }
2628:
2629: int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
2630: {
2631: return gen_intermediate_code_internal(env, tb, 1);
2632: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.