translate.c 115 KB
Newer Older
bellard's avatar
bellard committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
 *  PPC emulation for qemu: main translation routines.
 * 
 *  Copyright (c) 2003 Jocelyn Mayer
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
bellard's avatar
bellard committed
20
21
22
23
24
25
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>

bellard's avatar
bellard committed
26
#include "cpu.h"
bellard's avatar
bellard committed
27
#include "exec-all.h"
bellard's avatar
bellard committed
28
29
30
#include "disas.h"

//#define DO_SINGLE_STEP
31
//#define PPC_DEBUG_DISAS
bellard's avatar
bellard committed
32
33
34
35
36
37
38
39
40
41
42
43

enum {
#define DEF(s, n, copy_size) INDEX_op_ ## s,
#include "opc.h"
#undef DEF
    NB_OPS,
};

static uint16_t *gen_opc_ptr;
static uint32_t *gen_opparam_ptr;

#include "gen-op.h"
44
45

#define GEN8(func, NAME) \
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
static GenOpFunc *NAME ## _table [8] = {                                      \
NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3,                                   \
NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7,                                   \
};                                                                            \
static inline void func(int n)                                                \
{                                                                             \
    NAME ## _table[n]();                                                      \
}

#define GEN16(func, NAME)                                                     \
static GenOpFunc *NAME ## _table [16] = {                                     \
NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3,                                   \
NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7,                                   \
NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11,                                 \
NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15,                               \
};                                                                            \
static inline void func(int n)                                                \
{                                                                             \
    NAME ## _table[n]();                                                      \
65
66
67
}

#define GEN32(func, NAME) \
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
static GenOpFunc *NAME ## _table [32] = {                                     \
NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3,                                   \
NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7,                                   \
NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11,                                 \
NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15,                               \
NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19,                               \
NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23,                               \
NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27,                               \
NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31,                               \
};                                                                            \
static inline void func(int n)                                                \
{                                                                             \
    NAME ## _table[n]();                                                      \
}

/* Condition register moves */
GEN8(gen_op_load_crf_T0, gen_op_load_crf_T0_crf);
GEN8(gen_op_load_crf_T1, gen_op_load_crf_T1_crf);
GEN8(gen_op_store_T0_crf, gen_op_store_T0_crf_crf);
GEN8(gen_op_store_T1_crf, gen_op_store_T1_crf_crf);
88

bellard's avatar
bellard committed
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/* Floating point condition and status register moves */
GEN8(gen_op_load_fpscr_T0, gen_op_load_fpscr_T0_fpscr);
GEN8(gen_op_store_T0_fpscr, gen_op_store_T0_fpscr_fpscr);
GEN8(gen_op_clear_fpscr, gen_op_clear_fpscr_fpscr);
static GenOpFunc1 *gen_op_store_T0_fpscri_fpscr_table[8] = {
    &gen_op_store_T0_fpscri_fpscr0,
    &gen_op_store_T0_fpscri_fpscr1,
    &gen_op_store_T0_fpscri_fpscr2,
    &gen_op_store_T0_fpscri_fpscr3,
    &gen_op_store_T0_fpscri_fpscr4,
    &gen_op_store_T0_fpscri_fpscr5,
    &gen_op_store_T0_fpscri_fpscr6,
    &gen_op_store_T0_fpscri_fpscr7,
};
static inline void gen_op_store_T0_fpscri(int n, uint8_t param)
{
    (*gen_op_store_T0_fpscri_fpscr_table[n])(param);
}

108
109
110
/* Segment register moves */
GEN16(gen_op_load_sr, gen_op_load_sr);
GEN16(gen_op_store_sr, gen_op_store_sr);
111

112
113
114
115
116
117
118
119
/* General purpose registers moves */
GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr);
GEN32(gen_op_load_gpr_T1, gen_op_load_gpr_T1_gpr);
GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr);

GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr);
GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr);
GEN32(gen_op_store_T2_gpr, gen_op_store_T2_gpr_gpr);
120

bellard's avatar
bellard committed
121
122
123
124
125
126
127
/* floating point registers moves */
GEN32(gen_op_load_fpr_FT0, gen_op_load_fpr_FT0_fpr);
GEN32(gen_op_load_fpr_FT1, gen_op_load_fpr_FT1_fpr);
GEN32(gen_op_load_fpr_FT2, gen_op_load_fpr_FT2_fpr);
GEN32(gen_op_store_FT0_fpr, gen_op_store_FT0_fpr_fpr);
GEN32(gen_op_store_FT1_fpr, gen_op_store_FT1_fpr_fpr);
GEN32(gen_op_store_FT2_fpr, gen_op_store_FT2_fpr_fpr);
bellard's avatar
bellard committed
128
129
130
131
132
133

static uint8_t  spr_access[1024 / 2];

/* internal defines */
typedef struct DisasContext {
    struct TranslationBlock *tb;
bellard's avatar
bellard committed
134
    target_ulong nip;
bellard's avatar
bellard committed
135
    uint32_t opcode;
136
    uint32_t exception;
bellard's avatar
bellard committed
137
138
139
    /* Routine used to access memory */
    int mem_idx;
    /* Translation flags */
140
#if !defined(CONFIG_USER_ONLY)
bellard's avatar
bellard committed
141
    int supervisor;
142
#endif
bellard's avatar
bellard committed
143
    int fpu_enabled;
bellard's avatar
bellard committed
144
145
146
147
148
} DisasContext;

typedef struct opc_handler_t {
    /* invalid bits */
    uint32_t inval;
149
150
    /* instruction type */
    uint32_t type;
bellard's avatar
bellard committed
151
152
153
154
    /* handler */
    void (*handler)(DisasContext *ctx);
} opc_handler_t;

155
#define RET_EXCP(ctx, excp, error)                                            \
bellard's avatar
bellard committed
156
do {                                                                          \
157
158
159
160
161
    if ((ctx)->exception == EXCP_NONE) {                                      \
        gen_op_update_nip((ctx)->nip);                                        \
    }                                                                         \
    gen_op_raise_exception_err((excp), (error));                              \
    ctx->exception = (excp);                                                  \
bellard's avatar
bellard committed
162
163
} while (0)

164
165
166
167
168
#define RET_INVAL(ctx)                                                        \
RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL)

#define RET_PRIVOPC(ctx)                                                      \
RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_OPC)
169

170
171
#define RET_PRIVREG(ctx)                                                      \
RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG)
172

173
174
#define RET_MTMSR(ctx)                                                        \
RET_EXCP((ctx), EXCP_MTMSR, 0)
bellard's avatar
bellard committed
175
176
177
178
179
180
181
182

#define GEN_HANDLER(name, opc1, opc2, opc3, inval, type)                      \
static void gen_##name (DisasContext *ctx);                                   \
GEN_OPCODE(name, opc1, opc2, opc3, inval, type);                              \
static void gen_##name (DisasContext *ctx)

typedef struct opcode_t {
    unsigned char opc1, opc2, opc3;
183
184
185
186
187
#if HOST_LONG_BITS == 64 /* Explicitely align to 64 bits */
    unsigned char pad[5];
#else
    unsigned char pad[1];
#endif
bellard's avatar
bellard committed
188
189
190
191
192
193
194
195
196
197
198
199
200
    opc_handler_t handler;
} opcode_t;

/***                           Instruction decoding                        ***/
#define EXTRACT_HELPER(name, shift, nb)                                       \
static inline uint32_t name (uint32_t opcode)                                 \
{                                                                             \
    return (opcode >> (shift)) & ((1 << (nb)) - 1);                           \
}

#define EXTRACT_SHELPER(name, shift, nb)                                      \
static inline int32_t name (uint32_t opcode)                                  \
{                                                                             \
201
    return (int16_t)((opcode >> (shift)) & ((1 << (nb)) - 1));                \
bellard's avatar
bellard committed
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
}

/* Opcode part 1 */
EXTRACT_HELPER(opc1, 26, 6);
/* Opcode part 2 */
EXTRACT_HELPER(opc2, 1, 5);
/* Opcode part 3 */
EXTRACT_HELPER(opc3, 6, 5);
/* Update Cr0 flags */
EXTRACT_HELPER(Rc, 0, 1);
/* Destination */
EXTRACT_HELPER(rD, 21, 5);
/* Source */
EXTRACT_HELPER(rS, 21, 5);
/* First operand */
EXTRACT_HELPER(rA, 16, 5);
/* Second operand */
EXTRACT_HELPER(rB, 11, 5);
/* Third operand */
EXTRACT_HELPER(rC, 6, 5);
/***                               Get CRn                                 ***/
EXTRACT_HELPER(crfD, 23, 3);
EXTRACT_HELPER(crfS, 18, 3);
EXTRACT_HELPER(crbD, 21, 5);
EXTRACT_HELPER(crbA, 16, 5);
EXTRACT_HELPER(crbB, 11, 5);
/* SPR / TBL */
EXTRACT_HELPER(SPR, 11, 10);
/***                              Get constants                            ***/
EXTRACT_HELPER(IMM, 12, 8);
/* 16 bits signed immediate value */
EXTRACT_SHELPER(SIMM, 0, 16);
/* 16 bits unsigned immediate value */
EXTRACT_HELPER(UIMM, 0, 16);
/* Bit count */
EXTRACT_HELPER(NB, 11, 5);
/* Shift count */
EXTRACT_HELPER(SH, 11, 5);
/* Mask start */
EXTRACT_HELPER(MB, 6, 5);
/* Mask end */
EXTRACT_HELPER(ME, 1, 5);
bellard's avatar
bellard committed
244
245
/* Trap operand */
EXTRACT_HELPER(TO, 21, 5);
bellard's avatar
bellard committed
246
247
248
249

EXTRACT_HELPER(CRM, 12, 8);
EXTRACT_HELPER(FM, 17, 8);
EXTRACT_HELPER(SR, 16, 4);
bellard's avatar
bellard committed
250
251
EXTRACT_HELPER(FPIMM, 20, 4);

bellard's avatar
bellard committed
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
/***                            Jump target decoding                       ***/
/* Displacement */
EXTRACT_SHELPER(d, 0, 16);
/* Immediate address */
static inline uint32_t LI (uint32_t opcode)
{
    return (opcode >> 0) & 0x03FFFFFC;
}

static inline uint32_t BD (uint32_t opcode)
{
    return (opcode >> 0) & 0xFFFC;
}

EXTRACT_HELPER(BO, 21, 5);
EXTRACT_HELPER(BI, 16, 5);
/* Absolute/relative address */
EXTRACT_HELPER(AA, 1, 1);
/* Link */
EXTRACT_HELPER(LK, 0, 1);

/* Create a mask between <start> and <end> bits */
static inline uint32_t MASK (uint32_t start, uint32_t end)
{
    uint32_t ret;

    ret = (((uint32_t)(-1)) >> (start)) ^ (((uint32_t)(-1) >> (end)) >> 1);
    if (start > end)
        return ~ret;

    return ret;
}

bellard's avatar
bellard committed
285
#if defined(__APPLE__)
bellard's avatar
bellard committed
286
#define OPCODES_SECTION \
bellard's avatar
bellard committed
287
    __attribute__ ((section("__TEXT,__opcodes"), unused, aligned (8) ))
bellard's avatar
bellard committed
288
#else
bellard's avatar
bellard committed
289
290
#define OPCODES_SECTION \
    __attribute__ ((section(".opcodes"), unused, aligned (8) ))
bellard's avatar
bellard committed
291
292
#endif

bellard's avatar
bellard committed
293
#define GEN_OPCODE(name, op1, op2, op3, invl, _typ)                           \
294
OPCODES_SECTION opcode_t opc_##name = {                                       \
bellard's avatar
bellard committed
295
296
297
    .opc1 = op1,                                                              \
    .opc2 = op2,                                                              \
    .opc3 = op3,                                                              \
298
    .pad  = { 0, },                                                           \
bellard's avatar
bellard committed
299
300
    .handler = {                                                              \
        .inval   = invl,                                                      \
301
        .type = _typ,                                                         \
bellard's avatar
bellard committed
302
303
304
305
306
        .handler = &gen_##name,                                               \
    },                                                                        \
}

#define GEN_OPCODE_MARK(name)                                                 \
307
OPCODES_SECTION opcode_t opc_##name = {                                       \
bellard's avatar
bellard committed
308
309
310
    .opc1 = 0xFF,                                                             \
    .opc2 = 0xFF,                                                             \
    .opc3 = 0xFF,                                                             \
311
    .pad  = { 0, },                                                           \
bellard's avatar
bellard committed
312
313
    .handler = {                                                              \
        .inval   = 0x00000000,                                                \
314
        .type = 0x00,                                                         \
bellard's avatar
bellard committed
315
316
317
318
319
320
321
322
        .handler = NULL,                                                      \
    },                                                                        \
}

/* Start opcode list */
GEN_OPCODE_MARK(start);

/* Invalid instruction */
323
324
GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE)
{
325
    RET_INVAL(ctx);
326
327
}

bellard's avatar
bellard committed
328
329
static opc_handler_t invalid_handler = {
    .inval   = 0xFFFFFFFF,
330
    .type    = PPC_NONE,
bellard's avatar
bellard committed
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
    .handler = gen_invalid,
};

/***                           Integer arithmetic                          ***/
#define __GEN_INT_ARITH2(name, opc1, opc2, opc3, inval)                       \
GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER)                       \
{                                                                             \
    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
    gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
    gen_op_##name();                                                          \
    if (Rc(ctx->opcode) != 0)                                                 \
        gen_op_set_Rc0();                                                     \
    gen_op_store_T0_gpr(rD(ctx->opcode));                                     \
}

#define __GEN_INT_ARITH2_O(name, opc1, opc2, opc3, inval)                     \
GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER)                       \
{                                                                             \
    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
    gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
    gen_op_##name();                                                          \
    if (Rc(ctx->opcode) != 0)                                                 \
353
        gen_op_set_Rc0();                                                     \
bellard's avatar
bellard committed
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
    gen_op_store_T0_gpr(rD(ctx->opcode));                                     \
}

#define __GEN_INT_ARITH1(name, opc1, opc2, opc3)                              \
GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER)                  \
{                                                                             \
    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
    gen_op_##name();                                                          \
    if (Rc(ctx->opcode) != 0)                                                 \
        gen_op_set_Rc0();                                                     \
    gen_op_store_T0_gpr(rD(ctx->opcode));                                     \
}
#define __GEN_INT_ARITH1_O(name, opc1, opc2, opc3)                            \
GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER)                  \
{                                                                             \
    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
    gen_op_##name();                                                          \
    if (Rc(ctx->opcode) != 0)                                                 \
372
        gen_op_set_Rc0();                                                     \
bellard's avatar
bellard committed
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
    gen_op_store_T0_gpr(rD(ctx->opcode));                                     \
}

/* Two operands arithmetic functions */
#define GEN_INT_ARITH2(name, opc1, opc2, opc3)                                \
__GEN_INT_ARITH2(name, opc1, opc2, opc3, 0x00000000)                          \
__GEN_INT_ARITH2_O(name##o, opc1, opc2, opc3 | 0x10, 0x00000000)

/* Two operands arithmetic functions with no overflow allowed */
#define GEN_INT_ARITHN(name, opc1, opc2, opc3)                                \
__GEN_INT_ARITH2(name, opc1, opc2, opc3, 0x00000400)

/* One operand arithmetic functions */
#define GEN_INT_ARITH1(name, opc1, opc2, opc3)                                \
__GEN_INT_ARITH1(name, opc1, opc2, opc3)                                      \
__GEN_INT_ARITH1_O(name##o, opc1, opc2, opc3 | 0x10)

/* add    add.    addo    addo.    */
GEN_INT_ARITH2 (add,    0x1F, 0x0A, 0x08);
/* addc   addc.   addco   addco.   */
GEN_INT_ARITH2 (addc,   0x1F, 0x0A, 0x00);
/* adde   adde.   addeo   addeo.   */
GEN_INT_ARITH2 (adde,   0x1F, 0x0A, 0x04);
/* addme  addme.  addmeo  addmeo.  */
GEN_INT_ARITH1 (addme,  0x1F, 0x0A, 0x07);
/* addze  addze.  addzeo  addzeo.  */
GEN_INT_ARITH1 (addze,  0x1F, 0x0A, 0x06);
/* divw   divw.   divwo   divwo.   */
GEN_INT_ARITH2 (divw,   0x1F, 0x0B, 0x0F);
/* divwu  divwu.  divwuo  divwuo.  */
GEN_INT_ARITH2 (divwu,  0x1F, 0x0B, 0x0E);
/* mulhw  mulhw.                   */
GEN_INT_ARITHN (mulhw,  0x1F, 0x0B, 0x02);
/* mulhwu mulhwu.                  */
GEN_INT_ARITHN (mulhwu, 0x1F, 0x0B, 0x00);
/* mullw  mullw.  mullwo  mullwo.  */
GEN_INT_ARITH2 (mullw,  0x1F, 0x0B, 0x07);
/* neg    neg.    nego    nego.    */
GEN_INT_ARITH1 (neg,    0x1F, 0x08, 0x03);
/* subf   subf.   subfo   subfo.   */
GEN_INT_ARITH2 (subf,   0x1F, 0x08, 0x01);
/* subfc  subfc.  subfco  subfco.  */
GEN_INT_ARITH2 (subfc,  0x1F, 0x08, 0x00);
/* subfe  subfe.  subfeo  subfeo.  */
GEN_INT_ARITH2 (subfe,  0x1F, 0x08, 0x04);
/* subfme subfme. subfmeo subfmeo. */
GEN_INT_ARITH1 (subfme, 0x1F, 0x08, 0x07);
/* subfze subfze. subfzeo subfzeo. */
GEN_INT_ARITH1 (subfze, 0x1F, 0x08, 0x06);
/* addi */
GEN_HANDLER(addi, 0x0E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
    int32_t simm = SIMM(ctx->opcode);

    if (rA(ctx->opcode) == 0) {
        gen_op_set_T0(simm);
    } else {
        gen_op_load_gpr_T0(rA(ctx->opcode));
        gen_op_addi(simm);
    }
    gen_op_store_T0_gpr(rD(ctx->opcode));
}
/* addic */
GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
    gen_op_load_gpr_T0(rA(ctx->opcode));
    gen_op_addic(SIMM(ctx->opcode));
    gen_op_store_T0_gpr(rD(ctx->opcode));
}
/* addic. */
GEN_HANDLER(addic_, 0x0D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
    gen_op_load_gpr_T0(rA(ctx->opcode));
    gen_op_addic(SIMM(ctx->opcode));
    gen_op_set_Rc0();
    gen_op_store_T0_gpr(rD(ctx->opcode));
}
/* addis */
GEN_HANDLER(addis, 0x0F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
    int32_t simm = SIMM(ctx->opcode);

    if (rA(ctx->opcode) == 0) {
        gen_op_set_T0(simm << 16);
    } else {
        gen_op_load_gpr_T0(rA(ctx->opcode));
        gen_op_addi(simm << 16);
    }
    gen_op_store_T0_gpr(rD(ctx->opcode));
}
/* mulli */
GEN_HANDLER(mulli, 0x07, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
    gen_op_load_gpr_T0(rA(ctx->opcode));
    gen_op_mulli(SIMM(ctx->opcode));
    gen_op_store_T0_gpr(rD(ctx->opcode));
}
/* subfic */
GEN_HANDLER(subfic, 0x08, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
    gen_op_load_gpr_T0(rA(ctx->opcode));
    gen_op_subfic(SIMM(ctx->opcode));
    gen_op_store_T0_gpr(rD(ctx->opcode));
}

/***                           Integer comparison                          ***/
#define GEN_CMP(name, opc)                                                    \
GEN_HANDLER(name, 0x1F, 0x00, opc, 0x00400000, PPC_INTEGER)                   \
{                                                                             \
    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
    gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
    gen_op_##name();                                                          \
    gen_op_store_T0_crf(crfD(ctx->opcode));                                   \
}

/* cmp */
GEN_CMP(cmp, 0x00);
/* cmpi */
GEN_HANDLER(cmpi, 0x0B, 0xFF, 0xFF, 0x00400000, PPC_INTEGER)
{
    gen_op_load_gpr_T0(rA(ctx->opcode));
    gen_op_cmpi(SIMM(ctx->opcode));
    gen_op_store_T0_crf(crfD(ctx->opcode));
}
/* cmpl */
GEN_CMP(cmpl, 0x01);
/* cmpli */
GEN_HANDLER(cmpli, 0x0A, 0xFF, 0xFF, 0x00400000, PPC_INTEGER)
{
    gen_op_load_gpr_T0(rA(ctx->opcode));
    gen_op_cmpli(UIMM(ctx->opcode));
    gen_op_store_T0_crf(crfD(ctx->opcode));
}

/***                            Integer logical                            ***/
#define __GEN_LOGICAL2(name, opc2, opc3)                                      \
GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000000, PPC_INTEGER)                  \
{                                                                             \
    gen_op_load_gpr_T0(rS(ctx->opcode));                                      \
    gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
    gen_op_##name();                                                          \
    if (Rc(ctx->opcode) != 0)                                                 \
        gen_op_set_Rc0();                                                     \
    gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
}
#define GEN_LOGICAL2(name, opc)                                               \
__GEN_LOGICAL2(name, 0x1C, opc)

#define GEN_LOGICAL1(name, opc)                                               \
GEN_HANDLER(name, 0x1F, 0x1A, opc, 0x00000000, PPC_INTEGER)                   \
{                                                                             \
    gen_op_load_gpr_T0(rS(ctx->opcode));                                      \
    gen_op_##name();                                                          \
    if (Rc(ctx->opcode) != 0)                                                 \
        gen_op_set_Rc0();                                                     \
    gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
}

/* and & and. */
GEN_LOGICAL2(and, 0x00);
/* andc & andc. */
GEN_LOGICAL2(andc, 0x01);
/* andi. */
GEN_HANDLER(andi_, 0x1C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
    gen_op_load_gpr_T0(rS(ctx->opcode));
    gen_op_andi_(UIMM(ctx->opcode));
    gen_op_set_Rc0();
    gen_op_store_T0_gpr(rA(ctx->opcode));
}
/* andis. */
GEN_HANDLER(andis_, 0x1D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
    gen_op_load_gpr_T0(rS(ctx->opcode));
    gen_op_andi_(UIMM(ctx->opcode) << 16);
    gen_op_set_Rc0();
    gen_op_store_T0_gpr(rA(ctx->opcode));
}

/* cntlzw */
GEN_LOGICAL1(cntlzw, 0x00);
/* eqv & eqv. */
GEN_LOGICAL2(eqv, 0x08);
/* extsb & extsb. */
GEN_LOGICAL1(extsb, 0x1D);
/* extsh & extsh. */
GEN_LOGICAL1(extsh, 0x1C);
/* nand & nand. */
GEN_LOGICAL2(nand, 0x0E);
/* nor & nor. */
GEN_LOGICAL2(nor, 0x03);
564

bellard's avatar
bellard committed
565
/* or & or. */
566
567
568
569
570
571
572
573
574
575
576
577
578
GEN_HANDLER(or, 0x1F, 0x1C, 0x0D, 0x00000000, PPC_INTEGER)
{
    gen_op_load_gpr_T0(rS(ctx->opcode));
    /* Optimisation for mr case */
    if (rS(ctx->opcode) != rB(ctx->opcode)) {
        gen_op_load_gpr_T1(rB(ctx->opcode));
        gen_op_or();
    }
    if (Rc(ctx->opcode) != 0)
        gen_op_set_Rc0();
    gen_op_store_T0_gpr(rA(ctx->opcode));
}

bellard's avatar
bellard committed
579
580
581
/* orc & orc. */
GEN_LOGICAL2(orc, 0x0C);
/* xor & xor. */
582
583
584
585
586
587
588
589
590
591
592
593
594
595
GEN_HANDLER(xor, 0x1F, 0x1C, 0x09, 0x00000000, PPC_INTEGER)
{
    gen_op_load_gpr_T0(rS(ctx->opcode));
    /* Optimisation for "set to zero" case */
    if (rS(ctx->opcode) != rB(ctx->opcode)) {
        gen_op_load_gpr_T1(rB(ctx->opcode));
        gen_op_xor();
    } else {
        gen_op_set_T0(0);
    }
    if (Rc(ctx->opcode) != 0)
        gen_op_set_Rc0();
    gen_op_store_T0_gpr(rA(ctx->opcode));
}
bellard's avatar
bellard committed
596
597
598
599
600
/* ori */
GEN_HANDLER(ori, 0x18, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
    uint32_t uimm = UIMM(ctx->opcode);

601
602
603
    if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
        /* NOP */
        return;
bellard's avatar
bellard committed
604
605
        }
        gen_op_load_gpr_T0(rS(ctx->opcode));
606
    if (uimm != 0)
bellard's avatar
bellard committed
607
608
609
610
611
612
613
614
        gen_op_ori(uimm);
        gen_op_store_T0_gpr(rA(ctx->opcode));
}
/* oris */
GEN_HANDLER(oris, 0x19, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
    uint32_t uimm = UIMM(ctx->opcode);

615
616
617
    if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
        /* NOP */
        return;
bellard's avatar
bellard committed
618
619
        }
        gen_op_load_gpr_T0(rS(ctx->opcode));
620
    if (uimm != 0)
bellard's avatar
bellard committed
621
622
623
624
625
626
        gen_op_ori(uimm << 16);
        gen_op_store_T0_gpr(rA(ctx->opcode));
}
/* xori */
GEN_HANDLER(xori, 0x1A, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
627
628
629
630
631
632
    uint32_t uimm = UIMM(ctx->opcode);

    if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
        /* NOP */
        return;
    }
bellard's avatar
bellard committed
633
    gen_op_load_gpr_T0(rS(ctx->opcode));
634
    if (uimm != 0)
bellard's avatar
bellard committed
635
    gen_op_xori(uimm);
bellard's avatar
bellard committed
636
637
638
639
640
641
    gen_op_store_T0_gpr(rA(ctx->opcode));
}

/* xoris */
GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
642
643
644
645
646
647
    uint32_t uimm = UIMM(ctx->opcode);

    if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
        /* NOP */
        return;
    }
bellard's avatar
bellard committed
648
    gen_op_load_gpr_T0(rS(ctx->opcode));
649
    if (uimm != 0)
bellard's avatar
bellard committed
650
    gen_op_xori(uimm << 16);
bellard's avatar
bellard committed
651
652
653
654
655
656
657
658
659
660
661
662
    gen_op_store_T0_gpr(rA(ctx->opcode));
}

/***                             Integer rotate                            ***/
/* rlwimi & rlwimi. */
GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
    uint32_t mb, me;

    mb = MB(ctx->opcode);
    me = ME(ctx->opcode);
    gen_op_load_gpr_T0(rS(ctx->opcode));
bellard's avatar
bellard committed
663
    gen_op_load_gpr_T1(rA(ctx->opcode));
bellard's avatar
bellard committed
664
665
666
667
668
669
670
671
672
673
674
675
676
677
    gen_op_rlwimi(SH(ctx->opcode), MASK(mb, me), ~MASK(mb, me));
    if (Rc(ctx->opcode) != 0)
        gen_op_set_Rc0();
    gen_op_store_T0_gpr(rA(ctx->opcode));
}
/* rlwinm & rlwinm. */
GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
    uint32_t mb, me, sh;
    
    sh = SH(ctx->opcode);
    mb = MB(ctx->opcode);
    me = ME(ctx->opcode);
    gen_op_load_gpr_T0(rS(ctx->opcode));
bellard's avatar
bellard committed
678
679
680
681
682
683
#if 1 // TRY
    if (sh == 0) {
        gen_op_andi_(MASK(mb, me));
        goto store;
    }
#endif
bellard's avatar
bellard committed
684
685
686
687
    if (mb == 0) {
        if (me == 31) {
            gen_op_rotlwi(sh);
            goto store;
bellard's avatar
bellard committed
688
#if 0
bellard's avatar
bellard committed
689
690
691
        } else if (me == (31 - sh)) {
            gen_op_slwi(sh);
            goto store;
bellard's avatar
bellard committed
692
#endif
bellard's avatar
bellard committed
693
694
        }
    } else if (me == 31) {
bellard's avatar
bellard committed
695
#if 0
bellard's avatar
bellard committed
696
697
698
699
        if (sh == (32 - mb)) {
            gen_op_srwi(mb);
            goto store;
        }
bellard's avatar
bellard committed
700
#endif
bellard's avatar
bellard committed
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
    }
    gen_op_rlwinm(sh, MASK(mb, me));
store:
    if (Rc(ctx->opcode) != 0)
        gen_op_set_Rc0();
    gen_op_store_T0_gpr(rA(ctx->opcode));
}
/* rlwnm & rlwnm. */
GEN_HANDLER(rlwnm, 0x17, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
    uint32_t mb, me;

    mb = MB(ctx->opcode);
    me = ME(ctx->opcode);
    gen_op_load_gpr_T0(rS(ctx->opcode));
    gen_op_load_gpr_T1(rB(ctx->opcode));
    if (mb == 0 && me == 31) {
        gen_op_rotl();
    } else
    {
        gen_op_rlwnm(MASK(mb, me));
    }
    if (Rc(ctx->opcode) != 0)
        gen_op_set_Rc0();
    gen_op_store_T0_gpr(rA(ctx->opcode));
}

/***                             Integer shift                             ***/
/* slw & slw. */
__GEN_LOGICAL2(slw, 0x18, 0x00);
/* sraw & sraw. */
__GEN_LOGICAL2(sraw, 0x18, 0x18);
/* srawi & srawi. */
GEN_HANDLER(srawi, 0x1F, 0x18, 0x19, 0x00000000, PPC_INTEGER)
{
    gen_op_load_gpr_T0(rS(ctx->opcode));
737
    if (SH(ctx->opcode) != 0)
bellard's avatar
bellard committed
738
739
740
741
742
743
744
745
746
    gen_op_srawi(SH(ctx->opcode), MASK(32 - SH(ctx->opcode), 31));
    if (Rc(ctx->opcode) != 0)
        gen_op_set_Rc0();
    gen_op_store_T0_gpr(rA(ctx->opcode));
}
/* srw & srw. */
__GEN_LOGICAL2(srw, 0x18, 0x10);

/***                       Floating-Point arithmetic                       ***/
747
#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat)                           \
748
749
GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, PPC_FLOAT)                   \
{                                                                             \
bellard's avatar
bellard committed
750
751
752
753
    if (!ctx->fpu_enabled) {                                                  \
        RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
        return;                                                               \
    }                                                                         \
754
755
756
757
    gen_op_reset_scrfx();                                                     \
    gen_op_load_fpr_FT0(rA(ctx->opcode));                                     \
    gen_op_load_fpr_FT1(rC(ctx->opcode));                                     \
    gen_op_load_fpr_FT2(rB(ctx->opcode));                                     \
758
759
760
761
    gen_op_f##op();                                                           \
    if (isfloat) {                                                            \
        gen_op_frsp();                                                        \
    }                                                                         \
762
763
764
765
766
767
    gen_op_store_FT0_fpr(rD(ctx->opcode));                                    \
    if (Rc(ctx->opcode))                                                      \
        gen_op_set_Rc1();                                                     \
}

#define GEN_FLOAT_ACB(name, op2)                                              \
768
769
_GEN_FLOAT_ACB(name, name, 0x3F, op2, 0);                                     \
_GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1);
770

771
#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat)                     \
772
773
GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT)                        \
{                                                                             \
bellard's avatar
bellard committed
774
775
776
777
    if (!ctx->fpu_enabled) {                                                  \
        RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
        return;                                                               \
    }                                                                         \
778
779
780
    gen_op_reset_scrfx();                                                     \
    gen_op_load_fpr_FT0(rA(ctx->opcode));                                     \
    gen_op_load_fpr_FT1(rB(ctx->opcode));                                     \
781
782
783
784
    gen_op_f##op();                                                           \
    if (isfloat) {                                                            \
        gen_op_frsp();                                                        \
    }                                                                         \
785
786
787
788
789
    gen_op_store_FT0_fpr(rD(ctx->opcode));                                    \
    if (Rc(ctx->opcode))                                                      \
        gen_op_set_Rc1();                                                     \
}
#define GEN_FLOAT_AB(name, op2, inval)                                        \
790
791
_GEN_FLOAT_AB(name, name, 0x3F, op2, inval, 0);                               \
_GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1);
792

793
#define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat)                     \
794
795
GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT)                        \
{                                                                             \
bellard's avatar
bellard committed
796
797
798
799
    if (!ctx->fpu_enabled) {                                                  \
        RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
        return;                                                               \
    }                                                                         \
800
801
802
    gen_op_reset_scrfx();                                                     \
    gen_op_load_fpr_FT0(rA(ctx->opcode));                                     \
    gen_op_load_fpr_FT1(rC(ctx->opcode));                                     \
803
804
805
806
    gen_op_f##op();                                                           \
    if (isfloat) {                                                            \
        gen_op_frsp();                                                        \
    }                                                                         \
807
808
809
810
811
    gen_op_store_FT0_fpr(rD(ctx->opcode));                                    \
    if (Rc(ctx->opcode))                                                      \
        gen_op_set_Rc1();                                                     \
}
#define GEN_FLOAT_AC(name, op2, inval)                                        \
812
813
_GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0);                               \
_GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1);
814
815
816
817

#define GEN_FLOAT_B(name, op2, op3)                                           \
GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, PPC_FLOAT)                   \
{                                                                             \
bellard's avatar
bellard committed
818
819
820
821
    if (!ctx->fpu_enabled) {                                                  \
        RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
        return;                                                               \
    }                                                                         \
822
823
824
825
826
827
    gen_op_reset_scrfx();                                                     \
    gen_op_load_fpr_FT0(rB(ctx->opcode));                                     \
    gen_op_f##name();                                                         \
    gen_op_store_FT0_fpr(rD(ctx->opcode));                                    \
    if (Rc(ctx->opcode))                                                      \
        gen_op_set_Rc1();                                                     \
bellard's avatar
bellard committed
828
829
}

830
831
#define GEN_FLOAT_BS(name, op1, op2)                                          \
GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, PPC_FLOAT)                   \
832
{                                                                             \
bellard's avatar
bellard committed
833
834
835
836
    if (!ctx->fpu_enabled) {                                                  \
        RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
        return;                                                               \
    }                                                                         \
837
838
839
840
841
842
    gen_op_reset_scrfx();                                                     \
    gen_op_load_fpr_FT0(rB(ctx->opcode));                                     \
    gen_op_f##name();                                                         \
    gen_op_store_FT0_fpr(rD(ctx->opcode));                                    \
    if (Rc(ctx->opcode))                                                      \
        gen_op_set_Rc1();                                                     \
bellard's avatar
bellard committed
843
844
}

845
846
/* fadd - fadds */
GEN_FLOAT_AB(add, 0x15, 0x000007C0);
847
/* fdiv - fdivs */
848
GEN_FLOAT_AB(div, 0x12, 0x000007C0);
849
/* fmul - fmuls */
850
GEN_FLOAT_AC(mul, 0x19, 0x0000F800);
bellard's avatar
bellard committed
851
852

/* fres */
853
GEN_FLOAT_BS(res, 0x3B, 0x18);
bellard's avatar
bellard committed
854
855

/* frsqrte */
856
GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A);
bellard's avatar
bellard committed
857
858

/* fsel */
859
860
_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0);
/* fsub - fsubs */
861
GEN_FLOAT_AB(sub, 0x14, 0x000007C0);
bellard's avatar
bellard committed
862
863
/* Optional: */
/* fsqrt */
864
865
866
867
868
869
870
871
872
873
874
875
876
GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT)
{
    if (!ctx->fpu_enabled) {
        RET_EXCP(ctx, EXCP_NO_FP, 0);
        return;
    }
    gen_op_reset_scrfx();
    gen_op_load_fpr_FT0(rB(ctx->opcode));
    gen_op_fsqrt();
    gen_op_store_FT0_fpr(rD(ctx->opcode));
    if (Rc(ctx->opcode))
        gen_op_set_Rc1();
}
bellard's avatar
bellard committed
877

878
GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT)
bellard's avatar
bellard committed
879
{
bellard's avatar
bellard committed
880
881
882
883
    if (!ctx->fpu_enabled) {
        RET_EXCP(ctx, EXCP_NO_FP, 0);
        return;
    }
884
885
    gen_op_reset_scrfx();
    gen_op_load_fpr_FT0(rB(ctx->opcode));
886
887
    gen_op_fsqrt();
    gen_op_frsp();
888
889
890
    gen_op_store_FT0_fpr(rD(ctx->opcode));
    if (Rc(ctx->opcode))
        gen_op_set_Rc1();
bellard's avatar
bellard committed
891
892
893
}

/***                     Floating-Point multiply-and-add                   ***/
894
/* fmadd - fmadds */
895
GEN_FLOAT_ACB(madd, 0x1D);
896
/* fmsub - fmsubs */
897
GEN_FLOAT_ACB(msub, 0x1C);
898
/* fnmadd - fnmadds */
899
GEN_FLOAT_ACB(nmadd, 0x1F);
900
/* fnmsub - fnmsubs */
901
GEN_FLOAT_ACB(nmsub, 0x1E);
bellard's avatar
bellard committed
902
903
904

/***                     Floating-Point round & convert                    ***/
/* fctiw */
905
GEN_FLOAT_B(ctiw, 0x0E, 0x00);
bellard's avatar
bellard committed
906
/* fctiwz */
907
GEN_FLOAT_B(ctiwz, 0x0F, 0x00);
bellard's avatar
bellard committed
908
/* frsp */
909
GEN_FLOAT_B(rsp, 0x0C, 0x00);
bellard's avatar
bellard committed
910
911
912
913
914

/***                         Floating-Point compare                        ***/
/* fcmpo */
GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT)
{
bellard's avatar
bellard committed
915
916
917
918
    if (!ctx->fpu_enabled) {
        RET_EXCP(ctx, EXCP_NO_FP, 0);
        return;
    }
919
920
921
922
923
    gen_op_reset_scrfx();
    gen_op_load_fpr_FT0(rA(ctx->opcode));
    gen_op_load_fpr_FT1(rB(ctx->opcode));
    gen_op_fcmpo();
    gen_op_store_T0_crf(crfD(ctx->opcode));
bellard's avatar
bellard committed
924
925
926
927
928
}

/* fcmpu */
GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT)
{
bellard's avatar
bellard committed
929
930
931
932
    if (!ctx->fpu_enabled) {
        RET_EXCP(ctx, EXCP_NO_FP, 0);
        return;
    }
933
934
935
936
937
    gen_op_reset_scrfx();
    gen_op_load_fpr_FT0(rA(ctx->opcode));
    gen_op_load_fpr_FT1(rB(ctx->opcode));
    gen_op_fcmpu();
    gen_op_store_T0_crf(crfD(ctx->opcode));
bellard's avatar
bellard committed
938
939
}

940
941
942
943
944
945
946
/***                         Floating-point move                           ***/
/* fabs */
GEN_FLOAT_B(abs, 0x08, 0x08);

/* fmr  - fmr. */
GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT)
{
bellard's avatar
bellard committed
947
948
949
950
    if (!ctx->fpu_enabled) {
        RET_EXCP(ctx, EXCP_NO_FP, 0);
        return;
    }
951
952
953
954
955
956
957
958
959
960
961
962
    gen_op_reset_scrfx();
    gen_op_load_fpr_FT0(rB(ctx->opcode));
    gen_op_store_FT0_fpr(rD(ctx->opcode));
    if (Rc(ctx->opcode))
        gen_op_set_Rc1();
}

/* fnabs */
GEN_FLOAT_B(nabs, 0x08, 0x04);
/* fneg */
GEN_FLOAT_B(neg, 0x08, 0x01);

bellard's avatar
bellard committed
963
964
965
966
/***                  Floating-Point status & ctrl register                ***/
/* mcrfs */
GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT)
{
bellard's avatar
bellard committed
967
968
969
970
    if (!ctx->fpu_enabled) {
        RET_EXCP(ctx, EXCP_NO_FP, 0);
        return;
    }
bellard's avatar
bellard committed
971
972
973
    gen_op_load_fpscr_T0(crfS(ctx->opcode));
    gen_op_store_T0_crf(crfD(ctx->opcode));
    gen_op_clear_fpscr(crfS(ctx->opcode));
bellard's avatar
bellard committed
974
975
976
977
978
}

/* mffs */
GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT)
{
bellard's avatar
bellard committed
979
980
981
982
    if (!ctx->fpu_enabled) {
        RET_EXCP(ctx, EXCP_NO_FP, 0);
        return;
    }
983
    gen_op_load_fpscr();
bellard's avatar
bellard committed
984
985
986
    gen_op_store_FT0_fpr(rD(ctx->opcode));
    if (Rc(ctx->opcode))
        gen_op_set_Rc1();
bellard's avatar
bellard committed
987
988
989
990
991
}

/* mtfsb0 */
GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT)
{
bellard's avatar
bellard committed
992
993
    uint8_t crb;
    
bellard's avatar
bellard committed
994
995
996
997
    if (!ctx->fpu_enabled) {
        RET_EXCP(ctx, EXCP_NO_FP, 0);
        return;
    }
bellard's avatar
bellard committed
998
999
1000
1001
1002
1003
    crb = crbD(ctx->opcode) >> 2;
    gen_op_load_fpscr_T0(crb);
    gen_op_andi_(~(1 << (crbD(ctx->opcode) & 0x03)));
    gen_op_store_T0_fpscr(crb);
    if (Rc(ctx->opcode))
        gen_op_set_Rc1();
bellard's avatar
bellard committed
1004
1005
1006
1007
1008
}

/* mtfsb1 */
GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT)
{
bellard's avatar
bellard committed
1009
1010
    uint8_t crb;
    
bellard's avatar
bellard committed
1011
1012
1013
1014
    if (!ctx->fpu_enabled) {
        RET_EXCP(ctx, EXCP_NO_FP, 0);
        return;
    }
bellard's avatar
bellard committed
1015
1016
1017
1018
1019
1020
    crb = crbD(ctx->opcode) >> 2;
    gen_op_load_fpscr_T0(crb);
    gen_op_ori(1 << (crbD(ctx->opcode) & 0x03));
    gen_op_store_T0_fpscr(crb);
    if (Rc(ctx->opcode))
        gen_op_set_Rc1();
bellard's avatar
bellard committed
1021
1022
1023
1024
1025
}

/* mtfsf */
GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x02010000, PPC_FLOAT)
{
bellard's avatar
bellard committed
1026
1027
1028
1029
    if (!ctx->fpu_enabled) {
        RET_EXCP(ctx, EXCP_NO_FP, 0);
        return;
    }
bellard's avatar
bellard committed
1030
    gen_op_load_fpr_FT0(rB(ctx->opcode));
1031
    gen_op_store_fpscr(FM(ctx->opcode));
bellard's avatar
bellard committed
1032
1033
    if (Rc(ctx->opcode))
        gen_op_set_Rc1();
bellard's avatar
bellard committed
1034
1035
1036
1037
1038
}

/* mtfsfi */
GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT)
{
bellard's avatar
bellard committed
1039
1040
1041
1042
    if (!ctx->fpu_enabled) {
        RET_EXCP(ctx, EXCP_NO_FP, 0);
        return;
    }
bellard's avatar
bellard committed
1043
1044
1045
    gen_op_store_T0_fpscri(crbD(ctx->opcode) >> 2, FPIMM(ctx->opcode));
    if (Rc(ctx->opcode))
        gen_op_set_Rc1();
bellard's avatar
bellard committed
1046
1047
1048
}

/***                             Integer load                              ***/
1049
#define op_ldst(name)        (*gen_op_##name[ctx->mem_idx])()
1050
#if defined(CONFIG_USER_ONLY)
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
#define OP_LD_TABLE(width)                                                    \
static GenOpFunc *gen_op_l##width[] = {                                       \
    &gen_op_l##width##_raw,                                                   \
    &gen_op_l##width##_le_raw,                                                \
};
#define OP_ST_TABLE(width)                                                    \
static GenOpFunc *gen_op_st##width[] = {                                      \
    &gen_op_st##width##_raw,                                                  \
    &gen_op_st##width##_le_raw,                                               \
};
/* Byte access routine are endian safe */
#define gen_op_stb_le_raw gen_op_stb_raw
#define gen_op_lbz_le_raw gen_op_lbz_raw
1064
1065
1066
1067
#else
#define OP_LD_TABLE(width)                                                    \
static GenOpFunc *gen_op_l##width[] = {                                       \
    &gen_op_l##width##_user,                                                  \
1068
    &gen_op_l##width##_le_user,                                               \
1069
    &gen_op_l##width##_kernel,                                                \
1070
1071
    &gen_op_l##width##_le_kernel,                                             \
};
1072
1073
1074
#define OP_ST_TABLE(width)                                                    \
static GenOpFunc *gen_op_st##width[] = {                                      \
    &gen_op_st##width##_user,                                                 \
1075
    &gen_op_st##width##_le_user,                                              \
1076
    &gen_op_st##width##_kernel,                                               \
1077
1078
1079
1080
1081
1082
1083
    &gen_op_st##width##_le_kernel,                                            \
};
/* Byte access routine are endian safe */
#define gen_op_stb_le_user gen_op_stb_user
#define gen_op_lbz_le_user gen_op_lbz_user
#define gen_op_stb_le_kernel gen_op_stb_kernel
#define gen_op_lbz_le_kernel gen_op_lbz_kernel
1084
1085
1086
#endif

#define GEN_LD(width, opc)                                                    \
bellard's avatar
bellard committed
1087
1088
1089
1090
GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)               \
{                                                                             \
    uint32_t simm = SIMM(ctx->opcode);                                        \
    if (rA(ctx->opcode) == 0) {                                               \
1091
        gen_op_set_T0(simm);                                                  \
bellard's avatar
bellard committed
1092
1093
    } else {                                                                  \
        gen_op_load_gpr_T0(rA(ctx->opcode));                                  \
1094
1095
        if (simm != 0)                                                        \
            gen_op_addi(simm);                                                \
bellard's avatar
bellard committed
1096
    }                                                                         \
1097
    op_ldst(l##width);                                                        \
bellard's avatar
bellard committed
1098
1099
1100
    gen_op_store_T1_gpr(rD(ctx->opcode));                                     \
}

1101
#define GEN_LDU(width, opc)                                                   \
bellard's avatar
bellard committed
1102
1103
GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)            \
{                                                                             \
1104
    uint32_t simm = SIMM(ctx->opcode);                                        \
bellard's avatar
bellard committed
1105
    if (rA(ctx->opcode) == 0 ||                                               \
1106
        rA(ctx->opcode) == rD(ctx->opcode)) {                                 \
1107
1108
        RET_INVAL(ctx);                                                       \
        return;                                                               \
1109
    }                                                                         \
bellard's avatar
bellard committed
1110
    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
1111
1112
1113
    if (simm != 0)                                                            \
        gen_op_addi(simm);                                                    \
    op_ldst(l##width);                                                        \
bellard's avatar
bellard committed
1114
1115
1116
1117
    gen_op_store_T1_gpr(rD(ctx->opcode));                                     \
    gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
}

1118
#define GEN_LDUX(width, opc)                                                  \
bellard's avatar
bellard committed
1119
1120
1121
GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER)           \
{                                                                             \
    if (rA(ctx->opcode) == 0 ||                                               \
1122
        rA(ctx->opcode) == rD(ctx->opcode)) {                                 \
1123
1124
        RET_INVAL(ctx);                                                       \
        return;                                                               \
1125
    }                                                                         \
bellard's avatar
bellard committed
1126
1127
    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
    gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
1128
1129
    gen_op_add();                                                             \
    op_ldst(l##width);                                                        \
bellard's avatar
bellard committed
1130
1131
1132
1133
    gen_op_store_T1_gpr(rD(ctx->opcode));                                     \
    gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
}

1134
#define GEN_LDX(width, opc2, opc3)                                            \
bellard's avatar
bellard committed
1135
1136
1137
1138
1139
1140
1141
GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER)           \
{                                                                             \
    if (rA(ctx->opcode) == 0) {                                               \
        gen_op_load_gpr_T0(rB(ctx->opcode));                                  \
    } else {                                                                  \
        gen_op_load_gpr_T0(rA(ctx->opcode));                                  \
        gen_op_load_gpr_T1(rB(ctx->opcode));                                  \
1142
        gen_op_add();                                                         \
bellard's avatar
bellard committed
1143
    }                                                                         \
1144
    op_ldst(l##width);                                                        \
bellard's avatar
bellard committed
1145
1146
1147
    gen_op_store_T1_gpr(rD(ctx->opcode));                                     \
}

1148
1149
1150
1151
1152
1153
#define GEN_LDS(width, op)                                                    \
OP_LD_TABLE(width);                                                           \
GEN_LD(width, op | 0x20);                                                     \
GEN_LDU(width, op | 0x21);                                                    \
GEN_LDUX(width, op | 0x01);                                                   \
GEN_LDX(width, 0x17, op | 0x00)
bellard's avatar
bellard committed
1154
1155

/* lbz lbzu lbzux lbzx */
1156
GEN_LDS(bz, 0x02);
bellard's avatar
bellard committed
1157
/* lha lhau lhaux lhax */
1158
GEN_LDS(ha, 0x0A);
bellard's avatar
bellard committed
1159
/* lhz lhzu lhzux lhzx */
1160
GEN_LDS(hz, 0x08);
bellard's avatar
bellard committed
1161
/* lwz lwzu lwzux lwzx */
1162
GEN_LDS(wz, 0x00);
bellard's avatar
bellard committed
1163
1164

/***                              Integer store                            ***/
1165
#define GEN_ST(width, opc)                                                    \
bellard's avatar
bellard committed
1166
1167
1168
1169
GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)              \
{                                                                             \
    uint32_t simm = SIMM(ctx->opcode);                                        \
    if (rA(ctx->opcode) == 0) {                                               \
1170
        gen_op_set_T0(simm);                                                  \
bellard's avatar
bellard committed
1171
1172
    } else {                                                                  \
        gen_op_load_gpr_T0(rA(ctx->opcode));                                  \
1173
1174
        if (simm != 0)                                                        \
            gen_op_addi(simm);                                                \
bellard's avatar
bellard committed
1175
    }                                                                         \
1176
1177
    gen_op_load_gpr_T1(rS(ctx->opcode));                                      \
    op_ldst(st##width);                                                       \
bellard's avatar
bellard committed
1178
1179
}

1180
#define GEN_STU(width, opc)                                                   \
bellard's avatar
bellard committed
1181
1182
GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)           \
{                                                                             \
1183
1184
    uint32_t simm = SIMM(ctx->opcode);                                        \
    if (rA(ctx->opcode) == 0) {                                               \
1185
1186
        RET_INVAL(ctx);                                                       \
        return;                                                               \
1187
    }                                                                         \
bellard's avatar
bellard committed
1188
    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
1189
1190
    if (simm != 0)                                                            \
        gen_op_addi(simm);                                                    \
bellard's avatar
bellard committed
1191
    gen_op_load_gpr_T1(rS(ctx->opcode));                                      \
1192
    op_ldst(st##width);                                                       \
bellard's avatar
bellard committed
1193
1194
1195
    gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
}

1196
#define GEN_STUX(width, opc)                                                  \
bellard's avatar
bellard committed
1197
1198
GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER)          \
{                                                                             \
1199
    if (rA(ctx->opcode) == 0) {                                               \
1200
1201
        RET_INVAL(ctx);                                                       \
        return;                                                               \
1202
    }                                                                         \
bellard's avatar
bellard committed
1203
1204
    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
    gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
1205
1206
1207
    gen_op_add();                                                             \
    gen_op_load_gpr_T1(rS(ctx->opcode));                                      \
    op_ldst(st##width);                                                       \
bellard's avatar
bellard committed
1208
1209
1210
    gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
}

1211
#define GEN_STX(width, opc2, opc3)                                            \
bellard's avatar
bellard committed
1212
1213
1214
1215
1216
1217
1218
GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER)          \
{                                                                             \
    if (rA(ctx->opcode) == 0) {                                               \
        gen_op_load_gpr_T0(rB(ctx->opcode));                                  \
    } else {                                                                  \
        gen_op_load_gpr_T0(rA(ctx->opcode));                                  \
        gen_op_load_gpr_T1(rB(ctx->opcode));                                  \
1219
        gen_op_add();                                                         \
bellard's avatar
bellard committed
1220
    }                                                                         \
1221
1222
    gen_op_load_gpr_T1(rS(ctx->opcode));                                      \
    op_ldst(st##width);                                                       \
bellard's avatar
bellard committed
1223
1224
}

1225
1226
1227
1228
1229
1230
#define GEN_STS(width, op)                                                    \
OP_ST_TABLE(width);                                                           \
GEN_ST(width, op | 0x20);                                                     \
GEN_STU(width, op | 0x21);                                                    \
GEN_STUX(width, op | 0x01);                                                   \
GEN_STX(width, 0x17, op | 0x00)
bellard's avatar
bellard committed
1231
1232

/* stb stbu stbux stbx */
1233
GEN_STS(b, 0x06);
bellard's avatar
bellard committed
1234
/* sth sthu sthux sthx */
1235
GEN_STS(h, 0x0C);
bellard's avatar
bellard committed
1236
/* stw stwu stwux stwx */
1237
GEN_STS(w, 0x04);
bellard's avatar
bellard committed
1238
1239
1240

/***                Integer load and store with byte reverse               ***/
/* lhbrx */
1241
1242
OP_LD_TABLE(hbr);
GEN_LDX(hbr, 0x16, 0x18);
bellard's avatar
bellard committed
1243
/* lwbrx */
1244
1245
OP_LD_TABLE(wbr);
GEN_LDX(wbr, 0x16, 0x10);
bellard's avatar
bellard committed
1246
/* sthbrx */
1247
1248
OP_ST_TABLE(hbr);
GEN_STX(hbr, 0x16, 0x1C);
bellard's avatar
bellard committed
1249
/* stwbrx */
1250
1251
OP_ST_TABLE(wbr);
GEN_STX(wbr, 0x16, 0x14);
bellard's avatar
bellard committed
1252
1253

/***                    Integer load and store multiple                    ***/
1254
#define op_ldstm(name, reg) (*gen_op_##name[ctx->mem_idx])(reg)
1255
#if defined(CONFIG_USER_ONLY)
1256
1257
1258
1259
1260
1261
1262
1263
static GenOpFunc1 *gen_op_lmw[] = {
    &gen_op_lmw_raw,
    &gen_op_lmw_le_raw,
};
static GenOpFunc1 *gen_op_stmw[] = {
    &gen_op_stmw_raw,
    &gen_op_stmw_le_raw,
};
1264
1265
1266
#else
static GenOpFunc1 *gen_op_lmw[] = {
    &gen_op_lmw_user,
1267
    &gen_op_lmw_le_user,
1268
    &gen_op_lmw_kernel,
1269
    &gen_op_lmw_le_kernel,
1270
1271
1272
};
static GenOpFunc1 *gen_op_stmw[] = {
    &gen_op_stmw_user,
1273
    &gen_op_stmw_le_user,
1274
    &gen_op_stmw_kernel,
1275
    &gen_op_stmw_le_kernel,
1276
1277
1278
};
#endif

bellard's avatar
bellard committed
1279
1280
1281
/* lmw */
GEN_HANDLER(lmw, 0x2E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
1282
1283
    int simm = SIMM(ctx->opcode);

bellard's avatar
bellard committed
1284
    if (rA(ctx->opcode) == 0) {
1285
        gen_op_set_T0(simm);
bellard's avatar
bellard committed
1286
1287
    } else {
        gen_op_load_gpr_T0(rA(ctx->opcode));
1288
1289
        if (simm != 0)
            gen_op_addi(simm);
bellard's avatar
bellard committed
1290
    }
1291
    op_ldstm(lmw, rD(ctx->opcode));
bellard's avatar
bellard committed
1292
1293
1294
1295
1296
}

/* stmw */
GEN_HANDLER(stmw, 0x2F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
1297
1298
    int simm = SIMM(ctx->opcode);

bellard's avatar
bellard committed
1299
    if (rA(ctx->opcode) == 0) {
1300
        gen_op_set_T0(simm);
bellard's avatar
bellard committed
1301
1302
    } else {
        gen_op_load_gpr_T0(rA(ctx->opcode));
1303
1304
        if (simm != 0)
            gen_op_addi(simm);
bellard's avatar
bellard committed
1305
    }
1306
    op_ldstm(stmw, rS(ctx->opcode));
bellard's avatar
bellard committed
1307
1308
1309
}

/***                    Integer load and store strings                     ***/
1310
1311
#define op_ldsts(name, start) (*gen_op_##name[ctx->mem_idx])(start)
#define op_ldstsx(name, rd, ra, rb) (*gen_op_##name[ctx->mem_idx])(rd, ra, rb)
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
#if defined(CONFIG_USER_ONLY)
static GenOpFunc1 *gen_op_lswi[] = {
    &gen_op_lswi_raw,
    &gen_op_lswi_le_raw,
};
static GenOpFunc3 *gen_op_lswx[] = {
    &gen_op_lswx_raw,
    &gen_op_lswx_le_raw,
};
static GenOpFunc1 *gen_op_stsw[] = {
    &gen_op_stsw_raw,
    &gen_op_stsw_le_raw,
};
#else
1326
1327
static GenOpFunc1 *gen_op_lswi[] = {
    &gen_op_lswi_user,
1328
    &gen_op_lswi_le_user,
1329
    &gen_op_lswi_kernel,
1330
    &gen_op_lswi_le_kernel,
1331
1332
1333
};
static GenOpFunc3 *gen_op_lswx[] = {
    &gen_op_lswx_user,
1334
    &gen_op_lswx_le_user,
1335
    &gen_op_lswx_kernel,
1336
    &gen_op_lswx_le_kernel,
1337
1338
1339
};
static GenOpFunc1 *gen_op_stsw[] = {
    &gen_op_stsw_user,
1340
    &gen_op_stsw_le_user,
1341
    &gen_op_stsw_kernel,
1342
    &gen_op_stsw_le_kernel,
1343
1344
1345
};
#endif

bellard's avatar
bellard committed
1346
/* lswi */
1347
1348
1349
1350
1351
/* PPC32 specification says we must generate an exception if
 * rA is in the range of registers to be loaded.
 * In an other hand, IBM says this is valid, but rA won't be loaded.
 * For now, I'll follow the spec...
 */
bellard's avatar
bellard committed
1352
1353
1354
1355
GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_INTEGER)
{
    int nb = NB(ctx->opcode);
    int start = rD(ctx->opcode);
1356
    int ra = rA(ctx->opcode);
bellard's avatar
bellard committed
1357
1358
1359
1360
1361
    int nr;

    if (nb == 0)
        nb = 32;
    nr = nb / 4;
bellard's avatar
bellard committed
1362
1363
    if (((start + nr) > 32  && start <= ra && (start + nr - 32) > ra) ||
        ((start + nr) <= 32 && start <= ra && (start + nr) > ra)) {
1364
1365
        RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX);
        return;
bellard's avatar
bellard committed
1366
    }
1367
    if (ra == 0) {
bellard's avatar
bellard committed
1368
1369
        gen_op_set_T0(0);
    } else {
1370
        gen_op_load_gpr_T0(ra);
bellard's avatar
bellard committed
1371
    }
1372
    gen_op_set_T1(nb);
1373
1374
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_op_update_nip((ctx)->nip -