translate.c 309.6 KB
Newer Older
B
bellard 已提交
1
/*
2
 *  PowerPC emulation for qemu: main translation routines.
3
 *
4
 *  Copyright (c) 2003-2007 Jocelyn Mayer
B
bellard 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * 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
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
B
bellard 已提交
19
 */
B
bellard 已提交
20 21 22 23 24 25
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>

B
bellard 已提交
26
#include "cpu.h"
B
bellard 已提交
27
#include "exec-all.h"
B
bellard 已提交
28
#include "disas.h"
B
bellard 已提交
29
#include "tcg-op.h"
30
#include "qemu-common.h"
A
aurel32 已提交
31
#include "host-utils.h"
B
bellard 已提交
32

P
pbrook 已提交
33 34 35 36
#include "helper.h"
#define GEN_HELPER 1
#include "helper.h"

37 38 39 40
#define CPU_SINGLE_STEP 0x1
#define CPU_BRANCH_STEP 0x2
#define GDBSTUB_SINGLE_STEP 0x4

41
/* Include definitions for instructions classes and implementations flags */
A
aurel32 已提交
42
//#define DO_SINGLE_STEP
43
//#define PPC_DEBUG_DISAS
44
//#define DO_PPC_STATISTICS
B
bellard 已提交
45

46
#ifdef PPC_DEBUG_DISAS
47
#  define LOG_DISAS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__)
48 49 50
#else
#  define LOG_DISAS(...) do { } while (0)
#endif
51 52
/*****************************************************************************/
/* Code translation helpers                                                  */
B
bellard 已提交
53

A
aurel32 已提交
54
/* global register indexes */
P
pbrook 已提交
55
static TCGv_ptr cpu_env;
56
static char cpu_reg_names[10*3 + 22*4 /* GPR */
A
aurel32 已提交
57
#if !defined(TARGET_PPC64)
58
    + 10*4 + 22*5 /* SPE GPRh */
A
aurel32 已提交
59
#endif
A
aurel32 已提交
60
    + 10*4 + 22*5 /* FPR */
A
aurel32 已提交
61 62
    + 2*(10*6 + 22*7) /* AVRh, AVRl */
    + 8*5 /* CRF */];
A
aurel32 已提交
63 64 65 66
static TCGv cpu_gpr[32];
#if !defined(TARGET_PPC64)
static TCGv cpu_gprh[32];
#endif
P
pbrook 已提交
67 68 69
static TCGv_i64 cpu_fpr[32];
static TCGv_i64 cpu_avrh[32], cpu_avrl[32];
static TCGv_i32 cpu_crf[8];
A
aurel32 已提交
70
static TCGv cpu_nip;
71
static TCGv cpu_msr;
A
aurel32 已提交
72 73
static TCGv cpu_ctr;
static TCGv cpu_lr;
A
aurel32 已提交
74
static TCGv cpu_xer;
75
static TCGv cpu_reserve;
P
pbrook 已提交
76
static TCGv_i32 cpu_fpscr;
A
aurel32 已提交
77
static TCGv_i32 cpu_access_type;
A
aurel32 已提交
78

P
pbrook 已提交
79 80 81 82
#include "gen-icount.h"

void ppc_translate_init(void)
{
A
aurel32 已提交
83 84
    int i;
    char* p;
P
pbrook 已提交
85
    static int done_init = 0;
A
aurel32 已提交
86

P
pbrook 已提交
87 88
    if (done_init)
        return;
A
aurel32 已提交
89

P
pbrook 已提交
90 91
    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");

A
aurel32 已提交
92
    p = cpu_reg_names;
A
aurel32 已提交
93 94 95

    for (i = 0; i < 8; i++) {
        sprintf(p, "crf%d", i);
P
pbrook 已提交
96 97
        cpu_crf[i] = tcg_global_mem_new_i32(TCG_AREG0,
                                            offsetof(CPUState, crf[i]), p);
A
aurel32 已提交
98 99 100
        p += 5;
    }

A
aurel32 已提交
101 102
    for (i = 0; i < 32; i++) {
        sprintf(p, "r%d", i);
P
pbrook 已提交
103
        cpu_gpr[i] = tcg_global_mem_new(TCG_AREG0,
A
aurel32 已提交
104 105 106 107
                                        offsetof(CPUState, gpr[i]), p);
        p += (i < 10) ? 3 : 4;
#if !defined(TARGET_PPC64)
        sprintf(p, "r%dH", i);
P
pbrook 已提交
108 109
        cpu_gprh[i] = tcg_global_mem_new_i32(TCG_AREG0,
                                             offsetof(CPUState, gprh[i]), p);
A
aurel32 已提交
110 111
        p += (i < 10) ? 4 : 5;
#endif
112

A
aurel32 已提交
113
        sprintf(p, "fp%d", i);
P
pbrook 已提交
114 115
        cpu_fpr[i] = tcg_global_mem_new_i64(TCG_AREG0,
                                            offsetof(CPUState, fpr[i]), p);
A
aurel32 已提交
116
        p += (i < 10) ? 4 : 5;
A
aurel32 已提交
117

118
        sprintf(p, "avr%dH", i);
119 120 121 122
#ifdef WORDS_BIGENDIAN
        cpu_avrh[i] = tcg_global_mem_new_i64(TCG_AREG0,
                                             offsetof(CPUState, avr[i].u64[0]), p);
#else
P
pbrook 已提交
123
        cpu_avrh[i] = tcg_global_mem_new_i64(TCG_AREG0,
124 125
                                             offsetof(CPUState, avr[i].u64[1]), p);
#endif
126
        p += (i < 10) ? 6 : 7;
A
aurel32 已提交
127

128
        sprintf(p, "avr%dL", i);
129 130 131 132
#ifdef WORDS_BIGENDIAN
        cpu_avrl[i] = tcg_global_mem_new_i64(TCG_AREG0,
                                             offsetof(CPUState, avr[i].u64[1]), p);
#else
P
pbrook 已提交
133
        cpu_avrl[i] = tcg_global_mem_new_i64(TCG_AREG0,
134 135
                                             offsetof(CPUState, avr[i].u64[0]), p);
#endif
136
        p += (i < 10) ? 6 : 7;
A
aurel32 已提交
137
    }
A
aurel32 已提交
138

P
pbrook 已提交
139
    cpu_nip = tcg_global_mem_new(TCG_AREG0,
A
aurel32 已提交
140 141
                                 offsetof(CPUState, nip), "nip");

142 143 144
    cpu_msr = tcg_global_mem_new(TCG_AREG0,
                                 offsetof(CPUState, msr), "msr");

P
pbrook 已提交
145
    cpu_ctr = tcg_global_mem_new(TCG_AREG0,
A
aurel32 已提交
146 147
                                 offsetof(CPUState, ctr), "ctr");

P
pbrook 已提交
148
    cpu_lr = tcg_global_mem_new(TCG_AREG0,
A
aurel32 已提交
149 150
                                offsetof(CPUState, lr), "lr");

P
pbrook 已提交
151
    cpu_xer = tcg_global_mem_new(TCG_AREG0,
A
aurel32 已提交
152 153
                                 offsetof(CPUState, xer), "xer");

154 155 156
    cpu_reserve = tcg_global_mem_new(TCG_AREG0,
                                     offsetof(CPUState, reserve), "reserve");

P
pbrook 已提交
157 158
    cpu_fpscr = tcg_global_mem_new_i32(TCG_AREG0,
                                       offsetof(CPUState, fpscr), "fpscr");
159

A
aurel32 已提交
160 161 162
    cpu_access_type = tcg_global_mem_new_i32(TCG_AREG0,
                                             offsetof(CPUState, access_type), "access_type");

A
aurel32 已提交
163
    /* register helpers */
P
pbrook 已提交
164
#define GEN_HELPER 2
A
aurel32 已提交
165 166
#include "helper.h"

P
pbrook 已提交
167 168 169
    done_init = 1;
}

B
bellard 已提交
170 171 172
/* internal defines */
typedef struct DisasContext {
    struct TranslationBlock *tb;
B
bellard 已提交
173
    target_ulong nip;
B
bellard 已提交
174
    uint32_t opcode;
175
    uint32_t exception;
B
bellard 已提交
176 177
    /* Routine used to access memory */
    int mem_idx;
A
aurel32 已提交
178
    int access_type;
B
bellard 已提交
179
    /* Translation flags */
A
aurel32 已提交
180
    int le_mode;
181 182
#if defined(TARGET_PPC64)
    int sf_mode;
183
#endif
B
bellard 已提交
184
    int fpu_enabled;
185
    int altivec_enabled;
186
    int spe_enabled;
187
    ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */
188
    int singlestep_enabled;
B
bellard 已提交
189 190
} DisasContext;

191
struct opc_handler_t {
B
bellard 已提交
192 193
    /* invalid bits */
    uint32_t inval;
194
    /* instruction type */
195
    uint64_t type;
B
bellard 已提交
196 197
    /* handler */
    void (*handler)(DisasContext *ctx);
198
#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU)
199
    const char *oname;
200 201
#endif
#if defined(DO_PPC_STATISTICS)
202 203
    uint64_t count;
#endif
204
};
B
bellard 已提交
205

206 207 208
static always_inline void gen_reset_fpstatus (void)
{
#ifdef CONFIG_SOFTFLOAT
209
    gen_helper_reset_fpstatus();
210 211 212
#endif
}

213
static always_inline void gen_compute_fprf (TCGv_i64 arg, int set_fprf, int set_rc)
214
{
215
    TCGv_i32 t0 = tcg_temp_new_i32();
A
aurel32 已提交
216

217 218
    if (set_fprf != 0) {
        /* This case might be optimized later */
219
        tcg_gen_movi_i32(t0, 1);
A
aurel32 已提交
220
        gen_helper_compute_fprf(t0, arg, t0);
P
pbrook 已提交
221
        if (unlikely(set_rc)) {
222
            tcg_gen_mov_i32(cpu_crf[1], t0);
P
pbrook 已提交
223
        }
A
aurel32 已提交
224
        gen_helper_float_check_status();
225 226
    } else if (unlikely(set_rc)) {
        /* We always need to compute fpcc */
227
        tcg_gen_movi_i32(t0, 0);
A
aurel32 已提交
228
        gen_helper_compute_fprf(t0, arg, t0);
229
        tcg_gen_mov_i32(cpu_crf[1], t0);
230
    }
A
aurel32 已提交
231

232
    tcg_temp_free_i32(t0);
233 234
}

A
aurel32 已提交
235
static always_inline void gen_set_access_type (DisasContext *ctx, int access_type)
A
aurel32 已提交
236
{
A
aurel32 已提交
237 238 239 240
    if (ctx->access_type != access_type) {
        tcg_gen_movi_i32(cpu_access_type, access_type);
        ctx->access_type = access_type;
    }
A
aurel32 已提交
241 242
}

243
static always_inline void gen_update_nip (DisasContext *ctx, target_ulong nip)
244 245 246
{
#if defined(TARGET_PPC64)
    if (ctx->sf_mode)
A
aurel32 已提交
247
        tcg_gen_movi_tl(cpu_nip, nip);
248 249
    else
#endif
A
aurel32 已提交
250
        tcg_gen_movi_tl(cpu_nip, (uint32_t)nip);
251 252
}

A
aurel32 已提交
253 254 255 256 257 258 259 260 261 262 263 264 265
static always_inline void gen_exception_err (DisasContext *ctx, uint32_t excp, uint32_t error)
{
    TCGv_i32 t0, t1;
    if (ctx->exception == POWERPC_EXCP_NONE) {
        gen_update_nip(ctx, ctx->nip);
    }
    t0 = tcg_const_i32(excp);
    t1 = tcg_const_i32(error);
    gen_helper_raise_exception_err(t0, t1);
    tcg_temp_free_i32(t0);
    tcg_temp_free_i32(t1);
    ctx->exception = (excp);
}
266

A
aurel32 已提交
267 268 269 270 271 272 273 274 275 276 277
static always_inline void gen_exception (DisasContext *ctx, uint32_t excp)
{
    TCGv_i32 t0;
    if (ctx->exception == POWERPC_EXCP_NONE) {
        gen_update_nip(ctx, ctx->nip);
    }
    t0 = tcg_const_i32(excp);
    gen_helper_raise_exception(t0);
    tcg_temp_free_i32(t0);
    ctx->exception = (excp);
}
278

A
aurel32 已提交
279 280 281
static always_inline void gen_debug_exception (DisasContext *ctx)
{
    TCGv_i32 t0;
B
blueswir1 已提交
282 283 284

    if (ctx->exception != POWERPC_EXCP_BRANCH)
        gen_update_nip(ctx, ctx->nip);
A
aurel32 已提交
285 286 287 288
    t0 = tcg_const_i32(EXCP_DEBUG);
    gen_helper_raise_exception(t0);
    tcg_temp_free_i32(t0);
}
289

A
aurel32 已提交
290 291 292 293
static always_inline void gen_inval_exception (DisasContext *ctx, uint32_t error)
{
    gen_exception_err(ctx, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL | error);
}
294

295
/* Stop translation */
A
aurel32 已提交
296
static always_inline void gen_stop_exception (DisasContext *ctx)
297
{
298
    gen_update_nip(ctx, ctx->nip);
299
    ctx->exception = POWERPC_EXCP_STOP;
300 301
}

302
/* No need to update nip here, as execution flow will change */
A
aurel32 已提交
303
static always_inline void gen_sync_exception (DisasContext *ctx)
304
{
305
    ctx->exception = POWERPC_EXCP_SYNC;
306 307
}

B
bellard 已提交
308 309 310 311 312
#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)

313 314 315 316 317
#define GEN_HANDLER2(name, onam, opc1, opc2, opc3, inval, type)               \
static void gen_##name (DisasContext *ctx);                                   \
GEN_OPCODE2(name, onam, opc1, opc2, opc3, inval, type);                       \
static void gen_##name (DisasContext *ctx)

B
bellard 已提交
318 319
typedef struct opcode_t {
    unsigned char opc1, opc2, opc3;
T
ths 已提交
320
#if HOST_LONG_BITS == 64 /* Explicitly align to 64 bits */
321 322 323 324
    unsigned char pad[5];
#else
    unsigned char pad[1];
#endif
B
bellard 已提交
325
    opc_handler_t handler;
326
    const char *oname;
B
bellard 已提交
327 328
} opcode_t;

329
/*****************************************************************************/
B
bellard 已提交
330 331
/***                           Instruction decoding                        ***/
#define EXTRACT_HELPER(name, shift, nb)                                       \
332
static always_inline uint32_t name (uint32_t opcode)                          \
B
bellard 已提交
333 334 335 336 337
{                                                                             \
    return (opcode >> (shift)) & ((1 << (nb)) - 1);                           \
}

#define EXTRACT_SHELPER(name, shift, nb)                                      \
338
static always_inline int32_t name (uint32_t opcode)                           \
B
bellard 已提交
339
{                                                                             \
340
    return (int16_t)((opcode >> (shift)) & ((1 << (nb)) - 1));                \
B
bellard 已提交
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
}

/* 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 */
368
EXTRACT_HELPER(_SPR, 11, 10);
369
static always_inline uint32_t SPR (uint32_t opcode)
370 371 372 373 374
{
    uint32_t sprn = _SPR(opcode);

    return ((sprn >> 5) & 0x1F) | ((sprn & 0x1F) << 5);
}
B
bellard 已提交
375 376 377 378 379 380
/***                              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);
381 382
/* 5 bits signed immediate value */
EXTRACT_HELPER(SIMM5, 16, 5);
383 384
/* 5 bits signed immediate value */
EXTRACT_HELPER(UIMM5, 16, 5);
B
bellard 已提交
385 386 387 388
/* Bit count */
EXTRACT_HELPER(NB, 11, 5);
/* Shift count */
EXTRACT_HELPER(SH, 11, 5);
A
aurel32 已提交
389 390
/* Vector shift count */
EXTRACT_HELPER(VSH, 6, 4);
B
bellard 已提交
391 392 393 394
/* Mask start */
EXTRACT_HELPER(MB, 6, 5);
/* Mask end */
EXTRACT_HELPER(ME, 1, 5);
B
bellard 已提交
395 396
/* Trap operand */
EXTRACT_HELPER(TO, 21, 5);
B
bellard 已提交
397 398 399 400

EXTRACT_HELPER(CRM, 12, 8);
EXTRACT_HELPER(FM, 17, 8);
EXTRACT_HELPER(SR, 16, 4);
A
aurel32 已提交
401
EXTRACT_HELPER(FPIMM, 12, 4);
B
bellard 已提交
402

B
bellard 已提交
403 404 405 406
/***                            Jump target decoding                       ***/
/* Displacement */
EXTRACT_SHELPER(d, 0, 16);
/* Immediate address */
407
static always_inline target_ulong LI (uint32_t opcode)
B
bellard 已提交
408 409 410 411
{
    return (opcode >> 0) & 0x03FFFFFC;
}

412
static always_inline uint32_t BD (uint32_t opcode)
B
bellard 已提交
413 414 415 416 417 418 419 420 421 422 423 424
{
    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 */
425
static always_inline target_ulong MASK (uint32_t start, uint32_t end)
B
bellard 已提交
426
{
427
    target_ulong ret;
B
bellard 已提交
428

429 430
#if defined(TARGET_PPC64)
    if (likely(start == 0)) {
431
        ret = UINT64_MAX << (63 - end);
432
    } else if (likely(end == 63)) {
433
        ret = UINT64_MAX >> start;
434 435 436
    }
#else
    if (likely(start == 0)) {
437
        ret = UINT32_MAX << (31  - end);
438
    } else if (likely(end == 31)) {
439
        ret = UINT32_MAX >> start;
440 441 442 443 444 445 446 447
    }
#endif
    else {
        ret = (((target_ulong)(-1ULL)) >> (start)) ^
            (((target_ulong)(-1ULL) >> (end)) >> 1);
        if (unlikely(start > end))
            return ~ret;
    }
B
bellard 已提交
448 449 450 451

    return ret;
}

452 453 454
/*****************************************************************************/
/* PowerPC Instructions types definitions                                    */
enum {
455
    PPC_NONE           = 0x0000000000000000ULL,
456
    /* PowerPC base instructions set                                         */
457 458
    PPC_INSNS_BASE     = 0x0000000000000001ULL,
    /*   integer operations instructions                                     */
459
#define PPC_INTEGER PPC_INSNS_BASE
460
    /*   flow control instructions                                           */
461
#define PPC_FLOW    PPC_INSNS_BASE
462
    /*   virtual memory instructions                                         */
463
#define PPC_MEM     PPC_INSNS_BASE
464
    /*   ld/st with reservation instructions                                 */
465
#define PPC_RES     PPC_INSNS_BASE
466
    /*   spr/msr access instructions                                         */
467
#define PPC_MISC    PPC_INSNS_BASE
468 469
    /* Deprecated instruction sets                                           */
    /*   Original POWER instruction set                                      */
470
    PPC_POWER          = 0x0000000000000002ULL,
471
    /*   POWER2 instruction set extension                                    */
472
    PPC_POWER2         = 0x0000000000000004ULL,
473
    /*   Power RTC support                                                   */
474
    PPC_POWER_RTC      = 0x0000000000000008ULL,
475
    /*   Power-to-PowerPC bridge (601)                                       */
476
    PPC_POWER_BR       = 0x0000000000000010ULL,
477
    /* 64 bits PowerPC instruction set                                       */
478
    PPC_64B            = 0x0000000000000020ULL,
479
    /*   New 64 bits extensions (PowerPC 2.0x)                               */
480
    PPC_64BX           = 0x0000000000000040ULL,
481
    /*   64 bits hypervisor extensions                                       */
482
    PPC_64H            = 0x0000000000000080ULL,
483
    /*   New wait instruction (PowerPC 2.0x)                                 */
484
    PPC_WAIT           = 0x0000000000000100ULL,
485
    /*   Time base mftb instruction                                          */
486
    PPC_MFTB           = 0x0000000000000200ULL,
487 488 489

    /* Fixed-point unit extensions                                           */
    /*   PowerPC 602 specific                                                */
490
    PPC_602_SPEC       = 0x0000000000000400ULL,
491 492 493 494 495 496
    /*   isel instruction                                                    */
    PPC_ISEL           = 0x0000000000000800ULL,
    /*   popcntb instruction                                                 */
    PPC_POPCNTB        = 0x0000000000001000ULL,
    /*   string load / store                                                 */
    PPC_STRING         = 0x0000000000002000ULL,
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513

    /* Floating-point unit extensions                                        */
    /*   Optional floating point instructions                                */
    PPC_FLOAT          = 0x0000000000010000ULL,
    /* New floating-point extensions (PowerPC 2.0x)                          */
    PPC_FLOAT_EXT      = 0x0000000000020000ULL,
    PPC_FLOAT_FSQRT    = 0x0000000000040000ULL,
    PPC_FLOAT_FRES     = 0x0000000000080000ULL,
    PPC_FLOAT_FRSQRTE  = 0x0000000000100000ULL,
    PPC_FLOAT_FRSQRTES = 0x0000000000200000ULL,
    PPC_FLOAT_FSEL     = 0x0000000000400000ULL,
    PPC_FLOAT_STFIWX   = 0x0000000000800000ULL,

    /* Vector/SIMD extensions                                                */
    /*   Altivec support                                                     */
    PPC_ALTIVEC        = 0x0000000001000000ULL,
    /*   PowerPC 2.03 SPE extension                                          */
514
    PPC_SPE            = 0x0000000002000000ULL,
515 516 517 518
    /*   PowerPC 2.03 SPE single-precision floating-point extension          */
    PPC_SPE_SINGLE     = 0x0000000004000000ULL,
    /*   PowerPC 2.03 SPE double-precision floating-point extension          */
    PPC_SPE_DOUBLE     = 0x0000000008000000ULL,
519

520
    /* Optional memory control instructions                                  */
521 522 523 524 525 526 527 528 529
    PPC_MEM_TLBIA      = 0x0000000010000000ULL,
    PPC_MEM_TLBIE      = 0x0000000020000000ULL,
    PPC_MEM_TLBSYNC    = 0x0000000040000000ULL,
    /*   sync instruction                                                    */
    PPC_MEM_SYNC       = 0x0000000080000000ULL,
    /*   eieio instruction                                                   */
    PPC_MEM_EIEIO      = 0x0000000100000000ULL,

    /* Cache control instructions                                            */
530
    PPC_CACHE          = 0x0000000200000000ULL,
531
    /*   icbi instruction                                                    */
532
    PPC_CACHE_ICBI     = 0x0000000400000000ULL,
533
    /*   dcbz instruction with fixed cache line size                         */
534
    PPC_CACHE_DCBZ     = 0x0000000800000000ULL,
535
    /*   dcbz instruction with tunable cache line size                       */
536
    PPC_CACHE_DCBZT    = 0x0000001000000000ULL,
537
    /*   dcba instruction                                                    */
538 539 540
    PPC_CACHE_DCBA     = 0x0000002000000000ULL,
    /*   Freescale cache locking instructions                                */
    PPC_CACHE_LOCK     = 0x0000004000000000ULL,
541 542 543

    /* MMU related extensions                                                */
    /*   external control instructions                                       */
544
    PPC_EXTERN         = 0x0000010000000000ULL,
545
    /*   segment register access instructions                                */
546
    PPC_SEGMENT        = 0x0000020000000000ULL,
547
    /*   PowerPC 6xx TLB management instructions                             */
548
    PPC_6xx_TLB        = 0x0000040000000000ULL,
549
    /* PowerPC 74xx TLB management instructions                              */
550
    PPC_74xx_TLB       = 0x0000080000000000ULL,
551
    /*   PowerPC 40x TLB management instructions                             */
552
    PPC_40x_TLB        = 0x0000100000000000ULL,
553
    /*   segment register access instructions for PowerPC 64 "bridge"        */
554
    PPC_SEGMENT_64B    = 0x0000200000000000ULL,
555
    /*   SLB management                                                      */
556
    PPC_SLBI           = 0x0000400000000000ULL,
557

558
    /* Embedded PowerPC dedicated instructions                               */
559
    PPC_WRTEE          = 0x0001000000000000ULL,
560
    /* PowerPC 40x exception model                                           */
561
    PPC_40x_EXCP       = 0x0002000000000000ULL,
562
    /* PowerPC 405 Mac instructions                                          */
563
    PPC_405_MAC        = 0x0004000000000000ULL,
564
    /* PowerPC 440 specific instructions                                     */
565
    PPC_440_SPEC       = 0x0008000000000000ULL,
566
    /* BookE (embedded) PowerPC specification                                */
567 568 569 570 571 572 573
    PPC_BOOKE          = 0x0010000000000000ULL,
    /* mfapidi instruction                                                   */
    PPC_MFAPIDI        = 0x0020000000000000ULL,
    /* tlbiva instruction                                                    */
    PPC_TLBIVA         = 0x0040000000000000ULL,
    /* tlbivax instruction                                                   */
    PPC_TLBIVAX        = 0x0080000000000000ULL,
574
    /* PowerPC 4xx dedicated instructions                                    */
575
    PPC_4xx_COMMON     = 0x0100000000000000ULL,
576
    /* PowerPC 40x ibct instructions                                         */
577
    PPC_40x_ICBT       = 0x0200000000000000ULL,
578
    /* rfmci is not implemented in all BookE PowerPC                         */
579 580 581 582 583 584 585
    PPC_RFMCI          = 0x0400000000000000ULL,
    /* rfdi instruction                                                      */
    PPC_RFDI           = 0x0800000000000000ULL,
    /* DCR accesses                                                          */
    PPC_DCR            = 0x1000000000000000ULL,
    /* DCR extended accesse                                                  */
    PPC_DCRX           = 0x2000000000000000ULL,
586
    /* user-mode DCR access, implemented in PowerPC 460                      */
587
    PPC_DCRUX          = 0x4000000000000000ULL,
588 589 590 591
};

/*****************************************************************************/
/* PowerPC instructions table                                                */
592 593 594 595 596
#if HOST_LONG_BITS == 64
#define OPC_ALIGN 8
#else
#define OPC_ALIGN 4
#endif
B
bellard 已提交
597
#if defined(__APPLE__)
598
#define OPCODES_SECTION                                                       \
599
    __attribute__ ((section("__TEXT,__opcodes"), unused, aligned (OPC_ALIGN) ))
B
bellard 已提交
600
#else
601
#define OPCODES_SECTION                                                       \
602
    __attribute__ ((section(".opcodes"), unused, aligned (OPC_ALIGN) ))
B
bellard 已提交
603 604
#endif

605
#if defined(DO_PPC_STATISTICS)
B
bellard 已提交
606
#define GEN_OPCODE(name, op1, op2, op3, invl, _typ)                           \
607
extern opcode_t opc_##name;                                                   \
608
OPCODES_SECTION opcode_t opc_##name = {                                       \
B
bellard 已提交
609 610 611
    .opc1 = op1,                                                              \
    .opc2 = op2,                                                              \
    .opc3 = op3,                                                              \
612
    .pad  = { 0, },                                                           \
B
bellard 已提交
613 614
    .handler = {                                                              \
        .inval   = invl,                                                      \
615
        .type = _typ,                                                         \
B
bellard 已提交
616
        .handler = &gen_##name,                                               \
617
        .oname = stringify(name),                                             \
B
bellard 已提交
618
    },                                                                        \
619
    .oname = stringify(name),                                                 \
B
bellard 已提交
620
}
621 622 623 624 625 626 627 628 629 630 631 632 633 634
#define GEN_OPCODE2(name, onam, op1, op2, op3, invl, _typ)                    \
OPCODES_SECTION opcode_t opc_##name = {                                       \
    .opc1 = op1,                                                              \
    .opc2 = op2,                                                              \
    .opc3 = op3,                                                              \
    .pad  = { 0, },                                                           \
    .handler = {                                                              \
        .inval   = invl,                                                      \
        .type = _typ,                                                         \
        .handler = &gen_##name,                                               \
        .oname = onam,                                                        \
    },                                                                        \
    .oname = onam,                                                            \
}
635 636
#else
#define GEN_OPCODE(name, op1, op2, op3, invl, _typ)                           \
637
extern opcode_t opc_##name;                                                   \
638 639 640 641 642 643 644 645 646 647 648 649
OPCODES_SECTION opcode_t opc_##name = {                                       \
    .opc1 = op1,                                                              \
    .opc2 = op2,                                                              \
    .opc3 = op3,                                                              \
    .pad  = { 0, },                                                           \
    .handler = {                                                              \
        .inval   = invl,                                                      \
        .type = _typ,                                                         \
        .handler = &gen_##name,                                               \
    },                                                                        \
    .oname = stringify(name),                                                 \
}
650
#define GEN_OPCODE2(name, onam, op1, op2, op3, invl, _typ)                    \
651
extern opcode_t opc_##name;                                                   \
652 653 654 655 656 657 658 659 660 661 662 663
OPCODES_SECTION opcode_t opc_##name = {                                       \
    .opc1 = op1,                                                              \
    .opc2 = op2,                                                              \
    .opc3 = op3,                                                              \
    .pad  = { 0, },                                                           \
    .handler = {                                                              \
        .inval   = invl,                                                      \
        .type = _typ,                                                         \
        .handler = &gen_##name,                                               \
    },                                                                        \
    .oname = onam,                                                            \
}
664
#endif
B
bellard 已提交
665 666

#define GEN_OPCODE_MARK(name)                                                 \
667
extern opcode_t opc_##name;                                                   \
668
OPCODES_SECTION opcode_t opc_##name = {                                       \
B
bellard 已提交
669 670 671
    .opc1 = 0xFF,                                                             \
    .opc2 = 0xFF,                                                             \
    .opc3 = 0xFF,                                                             \
672
    .pad  = { 0, },                                                           \
B
bellard 已提交
673 674
    .handler = {                                                              \
        .inval   = 0x00000000,                                                \
675
        .type = 0x00,                                                         \
B
bellard 已提交
676 677
        .handler = NULL,                                                      \
    },                                                                        \
678
    .oname = stringify(name),                                                 \
B
bellard 已提交
679 680
}

681 682 683 684 685 686 687 688 689 690 691
/* SPR load/store helpers */
static always_inline void gen_load_spr(TCGv t, int reg)
{
    tcg_gen_ld_tl(t, cpu_env, offsetof(CPUState, spr[reg]));
}

static always_inline void gen_store_spr(int reg, TCGv t)
{
    tcg_gen_st_tl(t, cpu_env, offsetof(CPUState, spr[reg]));
}

B
bellard 已提交
692 693 694 695
/* Start opcode list */
GEN_OPCODE_MARK(start);

/* Invalid instruction */
696 697
GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE)
{
A
aurel32 已提交
698
    gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
699 700
}

B
bellard 已提交
701 702
static opc_handler_t invalid_handler = {
    .inval   = 0xFFFFFFFF,
703
    .type    = PPC_NONE,
B
bellard 已提交
704 705 706
    .handler = gen_invalid,
};

707 708
/***                           Integer comparison                          ***/

709
static always_inline void gen_op_cmp(TCGv arg0, TCGv arg1, int s, int crf)
710 711 712
{
    int l1, l2, l3;

713 714
    tcg_gen_trunc_tl_i32(cpu_crf[crf], cpu_xer);
    tcg_gen_shri_i32(cpu_crf[crf], cpu_crf[crf], XER_SO);
715 716 717 718 719 720
    tcg_gen_andi_i32(cpu_crf[crf], cpu_crf[crf], 1);

    l1 = gen_new_label();
    l2 = gen_new_label();
    l3 = gen_new_label();
    if (s) {
721 722
        tcg_gen_brcond_tl(TCG_COND_LT, arg0, arg1, l1);
        tcg_gen_brcond_tl(TCG_COND_GT, arg0, arg1, l2);
723
    } else {
724 725
        tcg_gen_brcond_tl(TCG_COND_LTU, arg0, arg1, l1);
        tcg_gen_brcond_tl(TCG_COND_GTU, arg0, arg1, l2);
726 727 728 729 730 731 732 733 734 735 736
    }
    tcg_gen_ori_i32(cpu_crf[crf], cpu_crf[crf], 1 << CRF_EQ);
    tcg_gen_br(l3);
    gen_set_label(l1);
    tcg_gen_ori_i32(cpu_crf[crf], cpu_crf[crf], 1 << CRF_LT);
    tcg_gen_br(l3);
    gen_set_label(l2);
    tcg_gen_ori_i32(cpu_crf[crf], cpu_crf[crf], 1 << CRF_GT);
    gen_set_label(l3);
}

737
static always_inline void gen_op_cmpi(TCGv arg0, target_ulong arg1, int s, int crf)
738
{
739 740 741
    TCGv t0 = tcg_const_local_tl(arg1);
    gen_op_cmp(arg0, t0, s, crf);
    tcg_temp_free(t0);
742 743 744
}

#if defined(TARGET_PPC64)
745
static always_inline void gen_op_cmp32(TCGv arg0, TCGv arg1, int s, int crf)
746
{
747
    TCGv t0, t1;
P
pbrook 已提交
748 749
    t0 = tcg_temp_local_new();
    t1 = tcg_temp_local_new();
750
    if (s) {
751 752
        tcg_gen_ext32s_tl(t0, arg0);
        tcg_gen_ext32s_tl(t1, arg1);
753
    } else {
754 755
        tcg_gen_ext32u_tl(t0, arg0);
        tcg_gen_ext32u_tl(t1, arg1);
756
    }
757 758 759
    gen_op_cmp(t0, t1, s, crf);
    tcg_temp_free(t1);
    tcg_temp_free(t0);
760 761
}

762
static always_inline void gen_op_cmpi32(TCGv arg0, target_ulong arg1, int s, int crf)
763
{
764 765 766
    TCGv t0 = tcg_const_local_tl(arg1);
    gen_op_cmp32(arg0, t0, s, crf);
    tcg_temp_free(t0);
767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837
}
#endif

static always_inline void gen_set_Rc0 (DisasContext *ctx, TCGv reg)
{
#if defined(TARGET_PPC64)
    if (!(ctx->sf_mode))
        gen_op_cmpi32(reg, 0, 1, 0);
    else
#endif
        gen_op_cmpi(reg, 0, 1, 0);
}

/* cmp */
GEN_HANDLER(cmp, 0x1F, 0x00, 0x00, 0x00400000, PPC_INTEGER)
{
#if defined(TARGET_PPC64)
    if (!(ctx->sf_mode && (ctx->opcode & 0x00200000)))
        gen_op_cmp32(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
                     1, crfD(ctx->opcode));
    else
#endif
        gen_op_cmp(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
                   1, crfD(ctx->opcode));
}

/* cmpi */
GEN_HANDLER(cmpi, 0x0B, 0xFF, 0xFF, 0x00400000, PPC_INTEGER)
{
#if defined(TARGET_PPC64)
    if (!(ctx->sf_mode && (ctx->opcode & 0x00200000)))
        gen_op_cmpi32(cpu_gpr[rA(ctx->opcode)], SIMM(ctx->opcode),
                      1, crfD(ctx->opcode));
    else
#endif
        gen_op_cmpi(cpu_gpr[rA(ctx->opcode)], SIMM(ctx->opcode),
                    1, crfD(ctx->opcode));
}

/* cmpl */
GEN_HANDLER(cmpl, 0x1F, 0x00, 0x01, 0x00400000, PPC_INTEGER)
{
#if defined(TARGET_PPC64)
    if (!(ctx->sf_mode && (ctx->opcode & 0x00200000)))
        gen_op_cmp32(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
                     0, crfD(ctx->opcode));
    else
#endif
        gen_op_cmp(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
                   0, crfD(ctx->opcode));
}

/* cmpli */
GEN_HANDLER(cmpli, 0x0A, 0xFF, 0xFF, 0x00400000, PPC_INTEGER)
{
#if defined(TARGET_PPC64)
    if (!(ctx->sf_mode && (ctx->opcode & 0x00200000)))
        gen_op_cmpi32(cpu_gpr[rA(ctx->opcode)], UIMM(ctx->opcode),
                      0, crfD(ctx->opcode));
    else
#endif
        gen_op_cmpi(cpu_gpr[rA(ctx->opcode)], UIMM(ctx->opcode),
                    0, crfD(ctx->opcode));
}

/* isel (PowerPC 2.03 specification) */
GEN_HANDLER(isel, 0x1F, 0x0F, 0xFF, 0x00000001, PPC_ISEL)
{
    int l1, l2;
    uint32_t bi = rC(ctx->opcode);
    uint32_t mask;
P
pbrook 已提交
838
    TCGv_i32 t0;
839 840 841 842 843

    l1 = gen_new_label();
    l2 = gen_new_label();

    mask = 1 << (3 - (bi & 0x03));
P
pbrook 已提交
844
    t0 = tcg_temp_new_i32();
845 846
    tcg_gen_andi_i32(t0, cpu_crf[bi >> 2], mask);
    tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l1);
847 848 849 850 851 852 853 854
    if (rA(ctx->opcode) == 0)
        tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], 0);
    else
        tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_br(l2);
    gen_set_label(l1);
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
    gen_set_label(l2);
P
pbrook 已提交
855
    tcg_temp_free_i32(t0);
856 857
}

B
bellard 已提交
858 859
/***                           Integer arithmetic                          ***/

860 861 862 863
static always_inline void gen_op_arith_compute_ov(DisasContext *ctx, TCGv arg0, TCGv arg1, TCGv arg2, int sub)
{
    int l1;
    TCGv t0;
B
bellard 已提交
864

865 866 867
    l1 = gen_new_label();
    /* Start with XER OV disabled, the most likely case */
    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
P
pbrook 已提交
868
    t0 = tcg_temp_local_new();
869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889
    tcg_gen_xor_tl(t0, arg0, arg1);
#if defined(TARGET_PPC64)
    if (!ctx->sf_mode)
        tcg_gen_ext32s_tl(t0, t0);
#endif
    if (sub)
        tcg_gen_brcondi_tl(TCG_COND_LT, t0, 0, l1);
    else
        tcg_gen_brcondi_tl(TCG_COND_GE, t0, 0, l1);
    tcg_gen_xor_tl(t0, arg1, arg2);
#if defined(TARGET_PPC64)
    if (!ctx->sf_mode)
        tcg_gen_ext32s_tl(t0, t0);
#endif
    if (sub)
        tcg_gen_brcondi_tl(TCG_COND_GE, t0, 0, l1);
    else
        tcg_gen_brcondi_tl(TCG_COND_LT, t0, 0, l1);
    tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
    gen_set_label(l1);
    tcg_temp_free(t0);
B
bellard 已提交
890 891
}

892 893 894
static always_inline void gen_op_arith_compute_ca(DisasContext *ctx, TCGv arg1, TCGv arg2, int sub)
{
    int l1 = gen_new_label();
895 896

#if defined(TARGET_PPC64)
897 898
    if (!(ctx->sf_mode)) {
        TCGv t0, t1;
P
pbrook 已提交
899 900
        t0 = tcg_temp_new();
        t1 = tcg_temp_new();
901

902 903 904 905
        tcg_gen_ext32u_tl(t0, arg1);
        tcg_gen_ext32u_tl(t1, arg2);
        if (sub) {
            tcg_gen_brcond_tl(TCG_COND_GTU, t0, t1, l1);
A
aurel32 已提交
906
        } else {
907 908
            tcg_gen_brcond_tl(TCG_COND_GEU, t0, t1, l1);
        }
909 910 911 912
        tcg_gen_ori_tl(cpu_xer, cpu_xer, 1 << XER_CA);
        gen_set_label(l1);
        tcg_temp_free(t0);
        tcg_temp_free(t1);
913 914
    } else
#endif
915 916 917 918 919 920 921 922
    {
        if (sub) {
            tcg_gen_brcond_tl(TCG_COND_GTU, arg1, arg2, l1);
        } else {
            tcg_gen_brcond_tl(TCG_COND_GEU, arg1, arg2, l1);
        }
        tcg_gen_ori_tl(cpu_xer, cpu_xer, 1 << XER_CA);
        gen_set_label(l1);
923
    }
924 925
}

926 927 928 929 930
/* Common add function */
static always_inline void gen_op_arith_add(DisasContext *ctx, TCGv ret, TCGv arg1, TCGv arg2,
                                           int add_ca, int compute_ca, int compute_ov)
{
    TCGv t0, t1;
931

932
    if ((!compute_ca && !compute_ov) ||
P
pbrook 已提交
933
        (!TCGV_EQUAL(ret,arg1) && !TCGV_EQUAL(ret, arg2)))  {
934 935
        t0 = ret;
    } else {
P
pbrook 已提交
936
        t0 = tcg_temp_local_new();
937
    }
B
bellard 已提交
938

939
    if (add_ca) {
P
pbrook 已提交
940
        t1 = tcg_temp_local_new();
941 942 943
        tcg_gen_andi_tl(t1, cpu_xer, (1 << XER_CA));
        tcg_gen_shri_tl(t1, t1, XER_CA);
    }
B
bellard 已提交
944

945 946 947 948 949 950 951 952 953 954
    if (compute_ca && compute_ov) {
        /* Start with XER CA and OV disabled, the most likely case */
        tcg_gen_andi_tl(cpu_xer, cpu_xer, ~((1 << XER_CA) | (1 << XER_OV)));
    } else if (compute_ca) {
        /* Start with XER CA disabled, the most likely case */
        tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
    } else if (compute_ov) {
        /* Start with XER OV disabled, the most likely case */
        tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
    }
B
bellard 已提交
955

956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972
    tcg_gen_add_tl(t0, arg1, arg2);

    if (compute_ca) {
        gen_op_arith_compute_ca(ctx, t0, arg1, 0);
    }
    if (add_ca) {
        tcg_gen_add_tl(t0, t0, t1);
        gen_op_arith_compute_ca(ctx, t0, t1, 0);
        tcg_temp_free(t1);
    }
    if (compute_ov) {
        gen_op_arith_compute_ov(ctx, t0, arg1, arg2, 0);
    }

    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, t0);

P
pbrook 已提交
973
    if (!TCGV_EQUAL(t0, ret)) {
974 975 976
        tcg_gen_mov_tl(ret, t0);
        tcg_temp_free(t0);
    }
A
aurel32 已提交
977
}
978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014
/* Add functions with two operands */
#define GEN_INT_ARITH_ADD(name, opc3, add_ca, compute_ca, compute_ov)         \
GEN_HANDLER(name, 0x1F, 0x0A, opc3, 0x00000000, PPC_INTEGER)                  \
{                                                                             \
    gen_op_arith_add(ctx, cpu_gpr[rD(ctx->opcode)],                           \
                     cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],      \
                     add_ca, compute_ca, compute_ov);                         \
}
/* Add functions with one operand and one immediate */
#define GEN_INT_ARITH_ADD_CONST(name, opc3, const_val,                        \
                                add_ca, compute_ca, compute_ov)               \
GEN_HANDLER(name, 0x1F, 0x0A, opc3, 0x0000F800, PPC_INTEGER)                  \
{                                                                             \
    TCGv t0 = tcg_const_local_tl(const_val);                                  \
    gen_op_arith_add(ctx, cpu_gpr[rD(ctx->opcode)],                           \
                     cpu_gpr[rA(ctx->opcode)], t0,                            \
                     add_ca, compute_ca, compute_ov);                         \
    tcg_temp_free(t0);                                                        \
}

/* add  add.  addo  addo. */
GEN_INT_ARITH_ADD(add, 0x08, 0, 0, 0)
GEN_INT_ARITH_ADD(addo, 0x18, 0, 0, 1)
/* addc  addc.  addco  addco. */
GEN_INT_ARITH_ADD(addc, 0x00, 0, 1, 0)
GEN_INT_ARITH_ADD(addco, 0x10, 0, 1, 1)
/* adde  adde.  addeo  addeo. */
GEN_INT_ARITH_ADD(adde, 0x04, 1, 1, 0)
GEN_INT_ARITH_ADD(addeo, 0x14, 1, 1, 1)
/* addme  addme.  addmeo  addmeo.  */
GEN_INT_ARITH_ADD_CONST(addme, 0x07, -1LL, 1, 1, 0)
GEN_INT_ARITH_ADD_CONST(addmeo, 0x17, -1LL, 1, 1, 1)
/* addze  addze.  addzeo  addzeo.*/
GEN_INT_ARITH_ADD_CONST(addze, 0x06, 0, 1, 1, 0)
GEN_INT_ARITH_ADD_CONST(addzeo, 0x16, 0, 1, 1, 1)
/* addi */
GEN_HANDLER(addi, 0x0E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
1015
{
1016 1017 1018 1019 1020 1021 1022 1023
    target_long simm = SIMM(ctx->opcode);

    if (rA(ctx->opcode) == 0) {
        /* li case */
        tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], simm);
    } else {
        tcg_gen_addi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], simm);
    }
1024
}
1025 1026 1027
/* addic  addic.*/
static always_inline void gen_op_addic (DisasContext *ctx, TCGv ret, TCGv arg1,
                                        int compute_Rc0)
1028
{
1029 1030 1031 1032 1033 1034
    target_long simm = SIMM(ctx->opcode);

    /* Start with XER CA and OV disabled, the most likely case */
    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));

    if (likely(simm != 0)) {
P
pbrook 已提交
1035
        TCGv t0 = tcg_temp_local_new();
1036 1037 1038 1039 1040 1041 1042 1043 1044 1045
        tcg_gen_addi_tl(t0, arg1, simm);
        gen_op_arith_compute_ca(ctx, t0, arg1, 0);
        tcg_gen_mov_tl(ret, t0);
        tcg_temp_free(t0);
    } else {
        tcg_gen_mov_tl(ret, arg1);
    }
    if (compute_Rc0) {
        gen_set_Rc0(ctx, ret);
    }
1046
}
1047
GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
1048
{
1049
    gen_op_addic(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0);
1050
}
1051
GEN_HANDLER2(addic_, "addic.", 0x0D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
1052
{
1053
    gen_op_addic(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 1);
1054
}
1055 1056
/* addis */
GEN_HANDLER(addis, 0x0F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
1057
{
1058 1059 1060 1061 1062 1063 1064 1065
    target_long simm = SIMM(ctx->opcode);

    if (rA(ctx->opcode) == 0) {
        /* lis case */
        tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], simm << 16);
    } else {
        tcg_gen_addi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], simm << 16);
    }
1066
}
1067 1068 1069

static always_inline void gen_op_arith_divw (DisasContext *ctx, TCGv ret, TCGv arg1, TCGv arg2,
                                             int sign, int compute_ov)
1070
{
1071 1072
    int l1 = gen_new_label();
    int l2 = gen_new_label();
P
pbrook 已提交
1073 1074
    TCGv_i32 t0 = tcg_temp_local_new_i32();
    TCGv_i32 t1 = tcg_temp_local_new_i32();
1075

1076 1077 1078
    tcg_gen_trunc_tl_i32(t0, arg1);
    tcg_gen_trunc_tl_i32(t1, arg2);
    tcg_gen_brcondi_i32(TCG_COND_EQ, t1, 0, l1);
1079
    if (sign) {
1080 1081 1082
        int l3 = gen_new_label();
        tcg_gen_brcondi_i32(TCG_COND_NE, t1, -1, l3);
        tcg_gen_brcondi_i32(TCG_COND_EQ, t0, INT32_MIN, l1);
1083
        gen_set_label(l3);
1084
        tcg_gen_div_i32(t0, t0, t1);
1085
    } else {
1086
        tcg_gen_divu_i32(t0, t0, t1);
1087 1088 1089 1090 1091 1092 1093
    }
    if (compute_ov) {
        tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
    }
    tcg_gen_br(l2);
    gen_set_label(l1);
    if (sign) {
1094
        tcg_gen_sari_i32(t0, t0, 31);
1095 1096 1097 1098 1099 1100 1101
    } else {
        tcg_gen_movi_i32(t0, 0);
    }
    if (compute_ov) {
        tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
    }
    gen_set_label(l2);
1102
    tcg_gen_extu_i32_tl(ret, t0);
P
pbrook 已提交
1103 1104
    tcg_temp_free_i32(t0);
    tcg_temp_free_i32(t1);
1105 1106
    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, ret);
1107
}
1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121
/* Div functions */
#define GEN_INT_ARITH_DIVW(name, opc3, sign, compute_ov)                      \
GEN_HANDLER(name, 0x1F, 0x0B, opc3, 0x00000000, PPC_INTEGER)                  \
{                                                                             \
    gen_op_arith_divw(ctx, cpu_gpr[rD(ctx->opcode)],                          \
                     cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],      \
                     sign, compute_ov);                                       \
}
/* divwu  divwu.  divwuo  divwuo.   */
GEN_INT_ARITH_DIVW(divwu, 0x0E, 0, 0);
GEN_INT_ARITH_DIVW(divwuo, 0x1E, 0, 1);
/* divw  divw.  divwo  divwo.   */
GEN_INT_ARITH_DIVW(divw, 0x0F, 1, 0);
GEN_INT_ARITH_DIVW(divwo, 0x1F, 1, 1);
1122
#if defined(TARGET_PPC64)
1123 1124
static always_inline void gen_op_arith_divd (DisasContext *ctx, TCGv ret, TCGv arg1, TCGv arg2,
                                             int sign, int compute_ov)
1125
{
1126 1127
    int l1 = gen_new_label();
    int l2 = gen_new_label();
1128 1129 1130

    tcg_gen_brcondi_i64(TCG_COND_EQ, arg2, 0, l1);
    if (sign) {
1131
        int l3 = gen_new_label();
1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154
        tcg_gen_brcondi_i64(TCG_COND_NE, arg2, -1, l3);
        tcg_gen_brcondi_i64(TCG_COND_EQ, arg1, INT64_MIN, l1);
        gen_set_label(l3);
        tcg_gen_div_i64(ret, arg1, arg2);
    } else {
        tcg_gen_divu_i64(ret, arg1, arg2);
    }
    if (compute_ov) {
        tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
    }
    tcg_gen_br(l2);
    gen_set_label(l1);
    if (sign) {
        tcg_gen_sari_i64(ret, arg1, 63);
    } else {
        tcg_gen_movi_i64(ret, 0);
    }
    if (compute_ov) {
        tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
    }
    gen_set_label(l2);
    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, ret);
1155
}
1156 1157 1158
#define GEN_INT_ARITH_DIVD(name, opc3, sign, compute_ov)                      \
GEN_HANDLER(name, 0x1F, 0x09, opc3, 0x00000000, PPC_64B)                      \
{                                                                             \
1159 1160 1161
    gen_op_arith_divd(ctx, cpu_gpr[rD(ctx->opcode)],                          \
                      cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],     \
                      sign, compute_ov);                                      \
1162 1163 1164 1165 1166 1167 1168
}
/* divwu  divwu.  divwuo  divwuo.   */
GEN_INT_ARITH_DIVD(divdu, 0x0E, 0, 0);
GEN_INT_ARITH_DIVD(divduo, 0x1E, 0, 1);
/* divw  divw.  divwo  divwo.   */
GEN_INT_ARITH_DIVD(divd, 0x0F, 1, 0);
GEN_INT_ARITH_DIVD(divdo, 0x1F, 1, 1);
1169
#endif
1170 1171 1172

/* mulhw  mulhw. */
GEN_HANDLER(mulhw, 0x1F, 0x0B, 0x02, 0x00000400, PPC_INTEGER)
1173
{
P
pbrook 已提交
1174
    TCGv_i64 t0, t1;
1175

P
pbrook 已提交
1176 1177
    t0 = tcg_temp_new_i64();
    t1 = tcg_temp_new_i64();
1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189
#if defined(TARGET_PPC64)
    tcg_gen_ext32s_tl(t0, cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_ext32s_tl(t1, cpu_gpr[rB(ctx->opcode)]);
    tcg_gen_mul_i64(t0, t0, t1);
    tcg_gen_shri_i64(cpu_gpr[rD(ctx->opcode)], t0, 32);
#else
    tcg_gen_ext_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_ext_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]);
    tcg_gen_mul_i64(t0, t0, t1);
    tcg_gen_shri_i64(t0, t0, 32);
    tcg_gen_trunc_i64_tl(cpu_gpr[rD(ctx->opcode)], t0);
#endif
P
pbrook 已提交
1190 1191
    tcg_temp_free_i64(t0);
    tcg_temp_free_i64(t1);
1192 1193
    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
1194
}
1195 1196
/* mulhwu  mulhwu.  */
GEN_HANDLER(mulhwu, 0x1F, 0x0B, 0x00, 0x00000400, PPC_INTEGER)
1197
{
P
pbrook 已提交
1198
    TCGv_i64 t0, t1;
1199

P
pbrook 已提交
1200 1201
    t0 = tcg_temp_new_i64();
    t1 = tcg_temp_new_i64();
1202
#if defined(TARGET_PPC64)
1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213
    tcg_gen_ext32u_i64(t0, cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_ext32u_i64(t1, cpu_gpr[rB(ctx->opcode)]);
    tcg_gen_mul_i64(t0, t0, t1);
    tcg_gen_shri_i64(cpu_gpr[rD(ctx->opcode)], t0, 32);
#else
    tcg_gen_extu_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_extu_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]);
    tcg_gen_mul_i64(t0, t0, t1);
    tcg_gen_shri_i64(t0, t0, 32);
    tcg_gen_trunc_i64_tl(cpu_gpr[rD(ctx->opcode)], t0);
#endif
P
pbrook 已提交
1214 1215
    tcg_temp_free_i64(t0);
    tcg_temp_free_i64(t1);
1216 1217
    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
1218
}
1219 1220
/* mullw  mullw. */
GEN_HANDLER(mullw, 0x1F, 0x0B, 0x07, 0x00000000, PPC_INTEGER)
1221
{
1222 1223
    tcg_gen_mul_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],
                   cpu_gpr[rB(ctx->opcode)]);
1224
    tcg_gen_ext32s_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)]);
1225 1226
    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
1227
}
1228 1229
/* mullwo  mullwo. */
GEN_HANDLER(mullwo, 0x1F, 0x0B, 0x17, 0x00000000, PPC_INTEGER)
1230
{
1231
    int l1;
P
pbrook 已提交
1232
    TCGv_i64 t0, t1;
1233

P
pbrook 已提交
1234 1235
    t0 = tcg_temp_new_i64();
    t1 = tcg_temp_new_i64();
1236 1237 1238 1239 1240 1241 1242 1243 1244
    l1 = gen_new_label();
    /* Start with XER OV disabled, the most likely case */
    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
#if defined(TARGET_PPC64)
    tcg_gen_ext32s_i64(t0, cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_ext32s_i64(t1, cpu_gpr[rB(ctx->opcode)]);
#else
    tcg_gen_ext_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_ext_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]);
1245
#endif
1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256
    tcg_gen_mul_i64(t0, t0, t1);
#if defined(TARGET_PPC64)
    tcg_gen_ext32s_i64(cpu_gpr[rD(ctx->opcode)], t0);
    tcg_gen_brcond_i64(TCG_COND_EQ, t0, cpu_gpr[rD(ctx->opcode)], l1);
#else
    tcg_gen_trunc_i64_tl(cpu_gpr[rD(ctx->opcode)], t0);
    tcg_gen_ext32s_i64(t1, t0);
    tcg_gen_brcond_i64(TCG_COND_EQ, t0, t1, l1);
#endif
    tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
    gen_set_label(l1);
P
pbrook 已提交
1257 1258
    tcg_temp_free_i64(t0);
    tcg_temp_free_i64(t1);
1259 1260
    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
1261
}
1262 1263
/* mulli */
GEN_HANDLER(mulli, 0x07, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
1264
{
1265 1266
    tcg_gen_muli_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],
                    SIMM(ctx->opcode));
1267 1268
}
#if defined(TARGET_PPC64)
1269 1270 1271
#define GEN_INT_ARITH_MUL_HELPER(name, opc3)                                  \
GEN_HANDLER(name, 0x1F, 0x09, opc3, 0x00000000, PPC_64B)                      \
{                                                                             \
P
pbrook 已提交
1272
    gen_helper_##name (cpu_gpr[rD(ctx->opcode)],                              \
1273 1274 1275
                       cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);   \
    if (unlikely(Rc(ctx->opcode) != 0))                                       \
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);                           \
1276
}
1277 1278 1279 1280 1281 1282
/* mulhd  mulhd. */
GEN_INT_ARITH_MUL_HELPER(mulhdu, 0x00);
/* mulhdu  mulhdu. */
GEN_INT_ARITH_MUL_HELPER(mulhd, 0x02);
/* mulld  mulld. */
GEN_HANDLER(mulld, 0x1F, 0x09, 0x07, 0x00000000, PPC_64B)
1283
{
1284 1285 1286 1287
    tcg_gen_mul_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],
                   cpu_gpr[rB(ctx->opcode)]);
    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
1288
}
1289 1290
/* mulldo  mulldo. */
GEN_INT_ARITH_MUL_HELPER(mulldo, 0x17);
1291
#endif
1292 1293

/* neg neg. nego nego. */
A
aurel32 已提交
1294
static always_inline void gen_op_arith_neg (DisasContext *ctx, TCGv ret, TCGv arg1, int ov_check)
1295
{
A
aurel32 已提交
1296 1297
    int l1 = gen_new_label();
    int l2 = gen_new_label();
P
pbrook 已提交
1298
    TCGv t0 = tcg_temp_local_new();
1299
#if defined(TARGET_PPC64)
1300
    if (ctx->sf_mode) {
A
aurel32 已提交
1301
        tcg_gen_mov_tl(t0, arg1);
A
aurel32 已提交
1302 1303 1304 1305 1306
        tcg_gen_brcondi_tl(TCG_COND_EQ, t0, INT64_MIN, l1);
    } else
#endif
    {
        tcg_gen_ext32s_tl(t0, arg1);
1307 1308 1309 1310 1311 1312 1313 1314
        tcg_gen_brcondi_tl(TCG_COND_EQ, t0, INT32_MIN, l1);
    }
    tcg_gen_neg_tl(ret, arg1);
    if (ov_check) {
        tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
    }
    tcg_gen_br(l2);
    gen_set_label(l1);
A
aurel32 已提交
1315
    tcg_gen_mov_tl(ret, t0);
1316 1317 1318 1319
    if (ov_check) {
        tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
    }
    gen_set_label(l2);
A
aurel32 已提交
1320
    tcg_temp_free(t0);
1321 1322 1323 1324
    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, ret);
}
GEN_HANDLER(neg, 0x1F, 0x08, 0x03, 0x0000F800, PPC_INTEGER)
1325
{
A
aurel32 已提交
1326
    gen_op_arith_neg(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0);
1327
}
1328
GEN_HANDLER(nego, 0x1F, 0x08, 0x13, 0x0000F800, PPC_INTEGER)
B
bellard 已提交
1329
{
A
aurel32 已提交
1330
    gen_op_arith_neg(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 1);
B
bellard 已提交
1331
}
1332 1333 1334 1335

/* Common subf function */
static always_inline void gen_op_arith_subf(DisasContext *ctx, TCGv ret, TCGv arg1, TCGv arg2,
                                            int add_ca, int compute_ca, int compute_ov)
B
bellard 已提交
1336
{
1337
    TCGv t0, t1;
1338

1339
    if ((!compute_ca && !compute_ov) ||
P
pbrook 已提交
1340
        (!TCGV_EQUAL(ret, arg1) && !TCGV_EQUAL(ret, arg2)))  {
1341
        t0 = ret;
J
j_mayer 已提交
1342
    } else {
P
pbrook 已提交
1343
        t0 = tcg_temp_local_new();
1344
    }
1345

1346
    if (add_ca) {
P
pbrook 已提交
1347
        t1 = tcg_temp_local_new();
1348 1349
        tcg_gen_andi_tl(t1, cpu_xer, (1 << XER_CA));
        tcg_gen_shri_tl(t1, t1, XER_CA);
1350
    }
B
bellard 已提交
1351

1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369
    if (compute_ca && compute_ov) {
        /* Start with XER CA and OV disabled, the most likely case */
        tcg_gen_andi_tl(cpu_xer, cpu_xer, ~((1 << XER_CA) | (1 << XER_OV)));
    } else if (compute_ca) {
        /* Start with XER CA disabled, the most likely case */
        tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
    } else if (compute_ov) {
        /* Start with XER OV disabled, the most likely case */
        tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
    }

    if (add_ca) {
        tcg_gen_not_tl(t0, arg1);
        tcg_gen_add_tl(t0, t0, arg2);
        gen_op_arith_compute_ca(ctx, t0, arg2, 0);
        tcg_gen_add_tl(t0, t0, t1);
        gen_op_arith_compute_ca(ctx, t0, t1, 0);
        tcg_temp_free(t1);
B
bellard 已提交
1370
    } else {
1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382
        tcg_gen_sub_tl(t0, arg2, arg1);
        if (compute_ca) {
            gen_op_arith_compute_ca(ctx, t0, arg2, 1);
        }
    }
    if (compute_ov) {
        gen_op_arith_compute_ov(ctx, t0, arg1, arg2, 1);
    }

    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, t0);

P
pbrook 已提交
1383
    if (!TCGV_EQUAL(t0, ret)) {
1384 1385
        tcg_gen_mov_tl(ret, t0);
        tcg_temp_free(t0);
B
bellard 已提交
1386 1387
    }
}
1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421
/* Sub functions with Two operands functions */
#define GEN_INT_ARITH_SUBF(name, opc3, add_ca, compute_ca, compute_ov)        \
GEN_HANDLER(name, 0x1F, 0x08, opc3, 0x00000000, PPC_INTEGER)                  \
{                                                                             \
    gen_op_arith_subf(ctx, cpu_gpr[rD(ctx->opcode)],                          \
                      cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],     \
                      add_ca, compute_ca, compute_ov);                        \
}
/* Sub functions with one operand and one immediate */
#define GEN_INT_ARITH_SUBF_CONST(name, opc3, const_val,                       \
                                add_ca, compute_ca, compute_ov)               \
GEN_HANDLER(name, 0x1F, 0x08, opc3, 0x0000F800, PPC_INTEGER)                  \
{                                                                             \
    TCGv t0 = tcg_const_local_tl(const_val);                                  \
    gen_op_arith_subf(ctx, cpu_gpr[rD(ctx->opcode)],                          \
                      cpu_gpr[rA(ctx->opcode)], t0,                           \
                      add_ca, compute_ca, compute_ov);                        \
    tcg_temp_free(t0);                                                        \
}
/* subf  subf.  subfo  subfo. */
GEN_INT_ARITH_SUBF(subf, 0x01, 0, 0, 0)
GEN_INT_ARITH_SUBF(subfo, 0x11, 0, 0, 1)
/* subfc  subfc.  subfco  subfco. */
GEN_INT_ARITH_SUBF(subfc, 0x00, 0, 1, 0)
GEN_INT_ARITH_SUBF(subfco, 0x10, 0, 1, 1)
/* subfe  subfe.  subfeo  subfo. */
GEN_INT_ARITH_SUBF(subfe, 0x04, 1, 1, 0)
GEN_INT_ARITH_SUBF(subfeo, 0x14, 1, 1, 1)
/* subfme  subfme.  subfmeo  subfmeo.  */
GEN_INT_ARITH_SUBF_CONST(subfme, 0x07, -1LL, 1, 1, 0)
GEN_INT_ARITH_SUBF_CONST(subfmeo, 0x17, -1LL, 1, 1, 1)
/* subfze  subfze.  subfzeo  subfzeo.*/
GEN_INT_ARITH_SUBF_CONST(subfze, 0x06, 0, 1, 1, 0)
GEN_INT_ARITH_SUBF_CONST(subfzeo, 0x16, 0, 1, 1, 1)
B
bellard 已提交
1422 1423 1424
/* subfic */
GEN_HANDLER(subfic, 0x08, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
1425 1426
    /* Start with XER CA and OV disabled, the most likely case */
    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
P
pbrook 已提交
1427
    TCGv t0 = tcg_temp_local_new();
1428 1429 1430 1431 1432 1433
    TCGv t1 = tcg_const_local_tl(SIMM(ctx->opcode));
    tcg_gen_sub_tl(t0, t1, cpu_gpr[rA(ctx->opcode)]);
    gen_op_arith_compute_ca(ctx, t0, t1, 1);
    tcg_temp_free(t1);
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0);
    tcg_temp_free(t0);
B
bellard 已提交
1434 1435 1436
}

/***                            Integer logical                            ***/
1437 1438
#define GEN_LOGICAL2(name, tcg_op, opc, type)                                 \
GEN_HANDLER(name, 0x1F, 0x1C, opc, 0x00000000, type)                          \
B
bellard 已提交
1439
{                                                                             \
1440 1441
    tcg_op(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)],                \
       cpu_gpr[rB(ctx->opcode)]);                                             \
1442
    if (unlikely(Rc(ctx->opcode) != 0))                                       \
1443
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);                           \
B
bellard 已提交
1444 1445
}

1446
#define GEN_LOGICAL1(name, tcg_op, opc, type)                                 \
1447
GEN_HANDLER(name, 0x1F, 0x1A, opc, 0x00000000, type)                          \
B
bellard 已提交
1448
{                                                                             \
1449
    tcg_op(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);               \
1450
    if (unlikely(Rc(ctx->opcode) != 0))                                       \
1451
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);                           \
B
bellard 已提交
1452 1453 1454
}

/* and & and. */
1455
GEN_LOGICAL2(and, tcg_gen_and_tl, 0x00, PPC_INTEGER);
B
bellard 已提交
1456
/* andc & andc. */
1457
GEN_LOGICAL2(andc, tcg_gen_andc_tl, 0x01, PPC_INTEGER);
B
bellard 已提交
1458
/* andi. */
1459
GEN_HANDLER2(andi_, "andi.", 0x1C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
B
bellard 已提交
1460
{
1461 1462
    tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], UIMM(ctx->opcode));
    gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
B
bellard 已提交
1463 1464
}
/* andis. */
1465
GEN_HANDLER2(andis_, "andis.", 0x1D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
B
bellard 已提交
1466
{
1467 1468
    tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], UIMM(ctx->opcode) << 16);
    gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
B
bellard 已提交
1469 1470
}
/* cntlzw */
1471 1472
GEN_HANDLER(cntlzw, 0x1F, 0x1A, 0x00, 0x00000000, PPC_INTEGER)
{
P
pbrook 已提交
1473
    gen_helper_cntlzw(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
1474
    if (unlikely(Rc(ctx->opcode) != 0))
P
pbrook 已提交
1475
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
1476
}
B
bellard 已提交
1477
/* eqv & eqv. */
1478
GEN_LOGICAL2(eqv, tcg_gen_eqv_tl, 0x08, PPC_INTEGER);
B
bellard 已提交
1479
/* extsb & extsb. */
1480
GEN_LOGICAL1(extsb, tcg_gen_ext8s_tl, 0x1D, PPC_INTEGER);
B
bellard 已提交
1481
/* extsh & extsh. */
1482
GEN_LOGICAL1(extsh, tcg_gen_ext16s_tl, 0x1C, PPC_INTEGER);
B
bellard 已提交
1483
/* nand & nand. */
1484
GEN_LOGICAL2(nand, tcg_gen_nand_tl, 0x0E, PPC_INTEGER);
B
bellard 已提交
1485
/* nor & nor. */
1486
GEN_LOGICAL2(nor, tcg_gen_nor_tl, 0x03, PPC_INTEGER);
B
bellard 已提交
1487
/* or & or. */
1488 1489
GEN_HANDLER(or, 0x1F, 0x1C, 0x0D, 0x00000000, PPC_INTEGER)
{
1490 1491 1492 1493 1494 1495 1496
    int rs, ra, rb;

    rs = rS(ctx->opcode);
    ra = rA(ctx->opcode);
    rb = rB(ctx->opcode);
    /* Optimisation for mr. ri case */
    if (rs != ra || rs != rb) {
1497 1498 1499 1500
        if (rs != rb)
            tcg_gen_or_tl(cpu_gpr[ra], cpu_gpr[rs], cpu_gpr[rb]);
        else
            tcg_gen_mov_tl(cpu_gpr[ra], cpu_gpr[rs]);
1501
        if (unlikely(Rc(ctx->opcode) != 0))
1502
            gen_set_Rc0(ctx, cpu_gpr[ra]);
1503
    } else if (unlikely(Rc(ctx->opcode) != 0)) {
1504
        gen_set_Rc0(ctx, cpu_gpr[rs]);
1505 1506
#if defined(TARGET_PPC64)
    } else {
1507 1508
        int prio = 0;

1509 1510 1511
        switch (rs) {
        case 1:
            /* Set process priority to low */
1512
            prio = 2;
1513 1514 1515
            break;
        case 6:
            /* Set process priority to medium-low */
1516
            prio = 3;
1517 1518 1519
            break;
        case 2:
            /* Set process priority to normal */
1520
            prio = 4;
1521
            break;
1522 1523
#if !defined(CONFIG_USER_ONLY)
        case 31:
A
aurel32 已提交
1524
            if (ctx->mem_idx > 0) {
1525
                /* Set process priority to very low */
1526
                prio = 1;
1527 1528 1529
            }
            break;
        case 5:
A
aurel32 已提交
1530
            if (ctx->mem_idx > 0) {
1531
                /* Set process priority to medium-hight */
1532
                prio = 5;
1533 1534 1535
            }
            break;
        case 3:
A
aurel32 已提交
1536
            if (ctx->mem_idx > 0) {
1537
                /* Set process priority to high */
1538
                prio = 6;
1539 1540 1541
            }
            break;
        case 7:
A
aurel32 已提交
1542
            if (ctx->mem_idx > 1) {
1543
                /* Set process priority to very high */
1544
                prio = 7;
1545 1546 1547
            }
            break;
#endif
1548 1549 1550 1551
        default:
            /* nop */
            break;
        }
1552
        if (prio) {
P
pbrook 已提交
1553
            TCGv t0 = tcg_temp_new();
1554
            gen_load_spr(t0, SPR_PPR);
1555 1556
            tcg_gen_andi_tl(t0, t0, ~0x001C000000000000ULL);
            tcg_gen_ori_tl(t0, t0, ((uint64_t)prio) << 50);
1557
            gen_store_spr(SPR_PPR, t0);
1558
            tcg_temp_free(t0);
1559
        }
1560
#endif
1561 1562
    }
}
B
bellard 已提交
1563
/* orc & orc. */
1564
GEN_LOGICAL2(orc, tcg_gen_orc_tl, 0x0C, PPC_INTEGER);
B
bellard 已提交
1565
/* xor & xor. */
1566 1567 1568
GEN_HANDLER(xor, 0x1F, 0x1C, 0x09, 0x00000000, PPC_INTEGER)
{
    /* Optimisation for "set to zero" case */
1569
    if (rS(ctx->opcode) != rB(ctx->opcode))
A
aurel32 已提交
1570
        tcg_gen_xor_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
1571 1572
    else
        tcg_gen_movi_tl(cpu_gpr[rA(ctx->opcode)], 0);
1573
    if (unlikely(Rc(ctx->opcode) != 0))
1574
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
1575
}
B
bellard 已提交
1576 1577 1578
/* ori */
GEN_HANDLER(ori, 0x18, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
1579
    target_ulong uimm = UIMM(ctx->opcode);
B
bellard 已提交
1580

1581 1582
    if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
        /* NOP */
1583
        /* XXX: should handle special NOPs for POWER series */
1584
        return;
1585
    }
1586
    tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], uimm);
B
bellard 已提交
1587 1588 1589 1590
}
/* oris */
GEN_HANDLER(oris, 0x19, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
1591
    target_ulong uimm = UIMM(ctx->opcode);
B
bellard 已提交
1592

1593 1594 1595
    if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
        /* NOP */
        return;
1596
    }
1597
    tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], uimm << 16);
B
bellard 已提交
1598 1599 1600 1601
}
/* xori */
GEN_HANDLER(xori, 0x1A, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
1602
    target_ulong uimm = UIMM(ctx->opcode);
1603 1604 1605 1606 1607

    if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
        /* NOP */
        return;
    }
1608
    tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], uimm);
B
bellard 已提交
1609 1610 1611 1612
}
/* xoris */
GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
1613
    target_ulong uimm = UIMM(ctx->opcode);
1614 1615 1616 1617 1618

    if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
        /* NOP */
        return;
    }
1619
    tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], uimm << 16);
B
bellard 已提交
1620
}
1621
/* popcntb : PowerPC 2.03 specification */
1622
GEN_HANDLER(popcntb, 0x1F, 0x03, 0x03, 0x0000F801, PPC_POPCNTB)
1623 1624 1625
{
#if defined(TARGET_PPC64)
    if (ctx->sf_mode)
P
pbrook 已提交
1626
        gen_helper_popcntb_64(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
1627 1628
    else
#endif
P
pbrook 已提交
1629
        gen_helper_popcntb(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
1630 1631 1632 1633
}

#if defined(TARGET_PPC64)
/* extsw & extsw. */
1634
GEN_LOGICAL1(extsw, tcg_gen_ext32s_tl, 0x1E, PPC_64B);
1635
/* cntlzd */
1636 1637
GEN_HANDLER(cntlzd, 0x1F, 0x1A, 0x01, 0x00000000, PPC_64B)
{
P
pbrook 已提交
1638
    gen_helper_cntlzd(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
1639 1640 1641
    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
}
1642 1643
#endif

B
bellard 已提交
1644 1645 1646 1647
/***                             Integer rotate                            ***/
/* rlwimi & rlwimi. */
GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
1648
    uint32_t mb, me, sh;
B
bellard 已提交
1649 1650 1651

    mb = MB(ctx->opcode);
    me = ME(ctx->opcode);
1652
    sh = SH(ctx->opcode);
1653 1654 1655 1656
    if (likely(sh == 0 && mb == 0 && me == 31)) {
        tcg_gen_ext32u_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
    } else {
        target_ulong mask;
P
pbrook 已提交
1657 1658
        TCGv t1;
        TCGv t0 = tcg_temp_new();
1659
#if defined(TARGET_PPC64)
P
pbrook 已提交
1660 1661 1662 1663 1664
        TCGv_i32 t2 = tcg_temp_new_i32();
        tcg_gen_trunc_i64_i32(t2, cpu_gpr[rS(ctx->opcode)]);
        tcg_gen_rotli_i32(t2, t2, sh);
        tcg_gen_extu_i32_i64(t0, t2);
        tcg_temp_free_i32(t2);
1665 1666 1667
#else
        tcg_gen_rotli_i32(t0, cpu_gpr[rS(ctx->opcode)], sh);
#endif
1668
#if defined(TARGET_PPC64)
1669 1670
        mb += 32;
        me += 32;
1671
#endif
1672
        mask = MASK(mb, me);
P
pbrook 已提交
1673
        t1 = tcg_temp_new();
1674 1675 1676 1677 1678 1679
        tcg_gen_andi_tl(t0, t0, mask);
        tcg_gen_andi_tl(t1, cpu_gpr[rA(ctx->opcode)], ~mask);
        tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
        tcg_temp_free(t0);
        tcg_temp_free(t1);
    }
1680
    if (unlikely(Rc(ctx->opcode) != 0))
1681
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
B
bellard 已提交
1682 1683 1684 1685 1686
}
/* rlwinm & rlwinm. */
GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
    uint32_t mb, me, sh;
1687

B
bellard 已提交
1688 1689 1690
    sh = SH(ctx->opcode);
    mb = MB(ctx->opcode);
    me = ME(ctx->opcode);
1691 1692 1693 1694 1695

    if (likely(mb == 0 && me == (31 - sh))) {
        if (likely(sh == 0)) {
            tcg_gen_ext32u_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
        } else {
P
pbrook 已提交
1696
            TCGv t0 = tcg_temp_new();
1697 1698 1699 1700
            tcg_gen_ext32u_tl(t0, cpu_gpr[rS(ctx->opcode)]);
            tcg_gen_shli_tl(t0, t0, sh);
            tcg_gen_ext32u_tl(cpu_gpr[rA(ctx->opcode)], t0);
            tcg_temp_free(t0);
B
bellard 已提交
1701
        }
1702
    } else if (likely(sh != 0 && me == 31 && sh == (32 - mb))) {
P
pbrook 已提交
1703
        TCGv t0 = tcg_temp_new();
1704 1705 1706 1707 1708
        tcg_gen_ext32u_tl(t0, cpu_gpr[rS(ctx->opcode)]);
        tcg_gen_shri_tl(t0, t0, mb);
        tcg_gen_ext32u_tl(cpu_gpr[rA(ctx->opcode)], t0);
        tcg_temp_free(t0);
    } else {
P
pbrook 已提交
1709
        TCGv t0 = tcg_temp_new();
1710
#if defined(TARGET_PPC64)
P
pbrook 已提交
1711
        TCGv_i32 t1 = tcg_temp_new_i32();
1712 1713 1714
        tcg_gen_trunc_i64_i32(t1, cpu_gpr[rS(ctx->opcode)]);
        tcg_gen_rotli_i32(t1, t1, sh);
        tcg_gen_extu_i32_i64(t0, t1);
P
pbrook 已提交
1715
        tcg_temp_free_i32(t1);
1716 1717 1718
#else
        tcg_gen_rotli_i32(t0, cpu_gpr[rS(ctx->opcode)], sh);
#endif
1719
#if defined(TARGET_PPC64)
1720 1721
        mb += 32;
        me += 32;
1722
#endif
1723 1724 1725
        tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], t0, MASK(mb, me));
        tcg_temp_free(t0);
    }
1726
    if (unlikely(Rc(ctx->opcode) != 0))
1727
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
B
bellard 已提交
1728 1729 1730 1731 1732
}
/* rlwnm & rlwnm. */
GEN_HANDLER(rlwnm, 0x17, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
    uint32_t mb, me;
1733 1734
    TCGv t0;
#if defined(TARGET_PPC64)
P
pbrook 已提交
1735
    TCGv_i32 t1, t2;
1736
#endif
B
bellard 已提交
1737 1738 1739

    mb = MB(ctx->opcode);
    me = ME(ctx->opcode);
P
pbrook 已提交
1740
    t0 = tcg_temp_new();
1741
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1f);
1742
#if defined(TARGET_PPC64)
P
pbrook 已提交
1743 1744
    t1 = tcg_temp_new_i32();
    t2 = tcg_temp_new_i32();
1745 1746 1747 1748
    tcg_gen_trunc_i64_i32(t1, cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_trunc_i64_i32(t2, t0);
    tcg_gen_rotl_i32(t1, t1, t2);
    tcg_gen_extu_i32_i64(t0, t1);
P
pbrook 已提交
1749 1750
    tcg_temp_free_i32(t1);
    tcg_temp_free_i32(t2);
1751 1752 1753
#else
    tcg_gen_rotl_i32(t0, cpu_gpr[rS(ctx->opcode)], t0);
#endif
1754 1755 1756 1757 1758
    if (unlikely(mb != 0 || me != 31)) {
#if defined(TARGET_PPC64)
        mb += 32;
        me += 32;
#endif
1759
        tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], t0, MASK(mb, me));
1760
    } else {
1761
        tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
B
bellard 已提交
1762
    }
1763
    tcg_temp_free(t0);
1764
    if (unlikely(Rc(ctx->opcode) != 0))
1765
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
B
bellard 已提交
1766 1767
}

1768 1769
#if defined(TARGET_PPC64)
#define GEN_PPC64_R2(name, opc1, opc2)                                        \
1770
GEN_HANDLER2(name##0, stringify(name), opc1, opc2, 0xFF, 0x00000000, PPC_64B) \
1771 1772 1773
{                                                                             \
    gen_##name(ctx, 0);                                                       \
}                                                                             \
1774 1775
GEN_HANDLER2(name##1, stringify(name), opc1, opc2 | 0x10, 0xFF, 0x00000000,   \
             PPC_64B)                                                         \
1776 1777 1778 1779
{                                                                             \
    gen_##name(ctx, 1);                                                       \
}
#define GEN_PPC64_R4(name, opc1, opc2)                                        \
1780
GEN_HANDLER2(name##0, stringify(name), opc1, opc2, 0xFF, 0x00000000, PPC_64B) \
1781 1782 1783
{                                                                             \
    gen_##name(ctx, 0, 0);                                                    \
}                                                                             \
1784 1785
GEN_HANDLER2(name##1, stringify(name), opc1, opc2 | 0x01, 0xFF, 0x00000000,   \
             PPC_64B)                                                         \
1786 1787 1788
{                                                                             \
    gen_##name(ctx, 0, 1);                                                    \
}                                                                             \
1789 1790
GEN_HANDLER2(name##2, stringify(name), opc1, opc2 | 0x10, 0xFF, 0x00000000,   \
             PPC_64B)                                                         \
1791 1792 1793
{                                                                             \
    gen_##name(ctx, 1, 0);                                                    \
}                                                                             \
1794 1795
GEN_HANDLER2(name##3, stringify(name), opc1, opc2 | 0x11, 0xFF, 0x00000000,   \
             PPC_64B)                                                         \
1796 1797 1798
{                                                                             \
    gen_##name(ctx, 1, 1);                                                    \
}
J
j_mayer 已提交
1799

1800 1801
static always_inline void gen_rldinm (DisasContext *ctx, uint32_t mb,
                                      uint32_t me, uint32_t sh)
J
j_mayer 已提交
1802
{
1803 1804 1805 1806 1807
    if (likely(sh != 0 && mb == 0 && me == (63 - sh))) {
        tcg_gen_shli_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], sh);
    } else if (likely(sh != 0 && me == 63 && sh == (64 - mb))) {
        tcg_gen_shri_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], mb);
    } else {
P
pbrook 已提交
1808
        TCGv t0 = tcg_temp_new();
1809
        tcg_gen_rotli_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
1810
        if (likely(mb == 0 && me == 63)) {
1811
            tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
1812 1813
        } else {
            tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], t0, MASK(mb, me));
J
j_mayer 已提交
1814
        }
1815
        tcg_temp_free(t0);
J
j_mayer 已提交
1816 1817
    }
    if (unlikely(Rc(ctx->opcode) != 0))
1818
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
J
j_mayer 已提交
1819
}
1820
/* rldicl - rldicl. */
1821
static always_inline void gen_rldicl (DisasContext *ctx, int mbn, int shn)
1822
{
J
j_mayer 已提交
1823
    uint32_t sh, mb;
1824

J
j_mayer 已提交
1825 1826
    sh = SH(ctx->opcode) | (shn << 5);
    mb = MB(ctx->opcode) | (mbn << 5);
J
j_mayer 已提交
1827
    gen_rldinm(ctx, mb, 63, sh);
1828
}
J
j_mayer 已提交
1829
GEN_PPC64_R4(rldicl, 0x1E, 0x00);
1830
/* rldicr - rldicr. */
1831
static always_inline void gen_rldicr (DisasContext *ctx, int men, int shn)
1832
{
J
j_mayer 已提交
1833
    uint32_t sh, me;
1834

J
j_mayer 已提交
1835 1836
    sh = SH(ctx->opcode) | (shn << 5);
    me = MB(ctx->opcode) | (men << 5);
J
j_mayer 已提交
1837
    gen_rldinm(ctx, 0, me, sh);
1838
}
J
j_mayer 已提交
1839
GEN_PPC64_R4(rldicr, 0x1E, 0x02);
1840
/* rldic - rldic. */
1841
static always_inline void gen_rldic (DisasContext *ctx, int mbn, int shn)
1842
{
J
j_mayer 已提交
1843
    uint32_t sh, mb;
1844

J
j_mayer 已提交
1845 1846
    sh = SH(ctx->opcode) | (shn << 5);
    mb = MB(ctx->opcode) | (mbn << 5);
J
j_mayer 已提交
1847 1848 1849 1850
    gen_rldinm(ctx, mb, 63 - sh, sh);
}
GEN_PPC64_R4(rldic, 0x1E, 0x04);

1851 1852
static always_inline void gen_rldnm (DisasContext *ctx, uint32_t mb,
                                     uint32_t me)
J
j_mayer 已提交
1853
{
1854
    TCGv t0;
1855 1856 1857

    mb = MB(ctx->opcode);
    me = ME(ctx->opcode);
P
pbrook 已提交
1858
    t0 = tcg_temp_new();
1859
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x3f);
1860
    tcg_gen_rotl_tl(t0, cpu_gpr[rS(ctx->opcode)], t0);
J
j_mayer 已提交
1861
    if (unlikely(mb != 0 || me != 63)) {
1862 1863 1864 1865 1866
        tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], t0, MASK(mb, me));
    } else {
        tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
    }
    tcg_temp_free(t0);
J
j_mayer 已提交
1867
    if (unlikely(Rc(ctx->opcode) != 0))
1868
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
1869
}
J
j_mayer 已提交
1870

1871
/* rldcl - rldcl. */
1872
static always_inline void gen_rldcl (DisasContext *ctx, int mbn)
1873
{
J
j_mayer 已提交
1874
    uint32_t mb;
1875

J
j_mayer 已提交
1876
    mb = MB(ctx->opcode) | (mbn << 5);
J
j_mayer 已提交
1877
    gen_rldnm(ctx, mb, 63);
1878
}
1879
GEN_PPC64_R2(rldcl, 0x1E, 0x08);
1880
/* rldcr - rldcr. */
1881
static always_inline void gen_rldcr (DisasContext *ctx, int men)
1882
{
J
j_mayer 已提交
1883
    uint32_t me;
1884

J
j_mayer 已提交
1885
    me = MB(ctx->opcode) | (men << 5);
J
j_mayer 已提交
1886
    gen_rldnm(ctx, 0, me);
1887
}
1888
GEN_PPC64_R2(rldcr, 0x1E, 0x09);
1889
/* rldimi - rldimi. */
1890
static always_inline void gen_rldimi (DisasContext *ctx, int mbn, int shn)
1891
{
1892
    uint32_t sh, mb, me;
1893

J
j_mayer 已提交
1894 1895
    sh = SH(ctx->opcode) | (shn << 5);
    mb = MB(ctx->opcode) | (mbn << 5);
1896
    me = 63 - sh;
1897 1898 1899 1900 1901 1902
    if (unlikely(sh == 0 && mb == 0)) {
        tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
    } else {
        TCGv t0, t1;
        target_ulong mask;

P
pbrook 已提交
1903
        t0 = tcg_temp_new();
1904
        tcg_gen_rotli_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
P
pbrook 已提交
1905
        t1 = tcg_temp_new();
1906 1907 1908 1909 1910 1911
        mask = MASK(mb, me);
        tcg_gen_andi_tl(t0, t0, mask);
        tcg_gen_andi_tl(t1, cpu_gpr[rA(ctx->opcode)], ~mask);
        tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
        tcg_temp_free(t0);
        tcg_temp_free(t1);
J
j_mayer 已提交
1912 1913
    }
    if (unlikely(Rc(ctx->opcode) != 0))
1914
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
1915
}
1916
GEN_PPC64_R4(rldimi, 0x1E, 0x06);
1917 1918
#endif

B
bellard 已提交
1919 1920
/***                             Integer shift                             ***/
/* slw & slw. */
1921 1922
GEN_HANDLER(slw, 0x1F, 0x18, 0x00, 0x00000000, PPC_INTEGER)
{
1923
    TCGv t0;
1924 1925 1926 1927
    int l1, l2;
    l1 = gen_new_label();
    l2 = gen_new_label();

P
pbrook 已提交
1928
    t0 = tcg_temp_local_new();
A
aurel32 已提交
1929 1930
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x3f);
    tcg_gen_brcondi_tl(TCG_COND_LT, t0, 0x20, l1);
1931 1932 1933
    tcg_gen_movi_tl(cpu_gpr[rA(ctx->opcode)], 0);
    tcg_gen_br(l2);
    gen_set_label(l1);
1934
    tcg_gen_shl_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], t0);
1935 1936
    tcg_gen_ext32u_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
    gen_set_label(l2);
1937
    tcg_temp_free(t0);
1938 1939 1940
    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
}
B
bellard 已提交
1941
/* sraw & sraw. */
1942 1943
GEN_HANDLER(sraw, 0x1F, 0x18, 0x18, 0x00000000, PPC_INTEGER)
{
P
pbrook 已提交
1944 1945
    gen_helper_sraw(cpu_gpr[rA(ctx->opcode)],
                    cpu_gpr[rS(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
1946 1947 1948
    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
}
B
bellard 已提交
1949 1950 1951
/* srawi & srawi. */
GEN_HANDLER(srawi, 0x1F, 0x18, 0x19, 0x00000000, PPC_INTEGER)
{
1952 1953 1954
    int sh = SH(ctx->opcode);
    if (sh != 0) {
        int l1, l2;
1955
        TCGv t0;
1956 1957
        l1 = gen_new_label();
        l2 = gen_new_label();
P
pbrook 已提交
1958
        t0 = tcg_temp_local_new();
1959 1960 1961 1962
        tcg_gen_ext32s_tl(t0, cpu_gpr[rS(ctx->opcode)]);
        tcg_gen_brcondi_tl(TCG_COND_GE, t0, 0, l1);
        tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)], (1ULL << sh) - 1);
        tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
1963
        tcg_gen_ori_tl(cpu_xer, cpu_xer, 1 << XER_CA);
1964 1965
        tcg_gen_br(l2);
        gen_set_label(l1);
1966
        tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
1967
        gen_set_label(l2);
1968 1969 1970
        tcg_gen_ext32s_tl(t0, cpu_gpr[rS(ctx->opcode)]);
        tcg_gen_sari_tl(cpu_gpr[rA(ctx->opcode)], t0, sh);
        tcg_temp_free(t0);
1971 1972
    } else {
        tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
1973
        tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
1974
    }
1975
    if (unlikely(Rc(ctx->opcode) != 0))
1976
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
B
bellard 已提交
1977 1978
}
/* srw & srw. */
1979 1980
GEN_HANDLER(srw, 0x1F, 0x18, 0x10, 0x00000000, PPC_INTEGER)
{
1981
    TCGv t0, t1;
1982 1983 1984
    int l1, l2;
    l1 = gen_new_label();
    l2 = gen_new_label();
1985

P
pbrook 已提交
1986
    t0 = tcg_temp_local_new();
A
aurel32 已提交
1987 1988
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x3f);
    tcg_gen_brcondi_tl(TCG_COND_LT, t0, 0x20, l1);
1989 1990 1991
    tcg_gen_movi_tl(cpu_gpr[rA(ctx->opcode)], 0);
    tcg_gen_br(l2);
    gen_set_label(l1);
P
pbrook 已提交
1992
    t1 = tcg_temp_new();
1993 1994 1995
    tcg_gen_ext32u_tl(t1, cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_shr_tl(cpu_gpr[rA(ctx->opcode)], t1, t0);
    tcg_temp_free(t1);
1996
    gen_set_label(l2);
1997
    tcg_temp_free(t0);
1998 1999 2000
    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
}
2001 2002
#if defined(TARGET_PPC64)
/* sld & sld. */
2003 2004
GEN_HANDLER(sld, 0x1F, 0x1B, 0x00, 0x00000000, PPC_64B)
{
2005
    TCGv t0;
2006 2007 2008 2009
    int l1, l2;
    l1 = gen_new_label();
    l2 = gen_new_label();

P
pbrook 已提交
2010
    t0 = tcg_temp_local_new();
A
aurel32 已提交
2011 2012
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x7f);
    tcg_gen_brcondi_tl(TCG_COND_LT, t0, 0x40, l1);
2013 2014 2015
    tcg_gen_movi_tl(cpu_gpr[rA(ctx->opcode)], 0);
    tcg_gen_br(l2);
    gen_set_label(l1);
2016
    tcg_gen_shl_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], t0);
2017
    gen_set_label(l2);
2018
    tcg_temp_free(t0);
2019 2020 2021
    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
}
2022
/* srad & srad. */
2023 2024
GEN_HANDLER(srad, 0x1F, 0x1A, 0x18, 0x00000000, PPC_64B)
{
P
pbrook 已提交
2025 2026
    gen_helper_srad(cpu_gpr[rA(ctx->opcode)],
                    cpu_gpr[rS(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
2027 2028 2029
    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
}
2030
/* sradi & sradi. */
2031
static always_inline void gen_sradi (DisasContext *ctx, int n)
2032
{
2033
    int sh = SH(ctx->opcode) + (n << 5);
2034
    if (sh != 0) {
2035
        int l1, l2;
2036
        TCGv t0;
2037 2038
        l1 = gen_new_label();
        l2 = gen_new_label();
P
pbrook 已提交
2039
        t0 = tcg_temp_local_new();
2040
        tcg_gen_brcondi_tl(TCG_COND_GE, cpu_gpr[rS(ctx->opcode)], 0, l1);
2041 2042
        tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)], (1ULL << sh) - 1);
        tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
2043
        tcg_gen_ori_tl(cpu_xer, cpu_xer, 1 << XER_CA);
2044 2045
        tcg_gen_br(l2);
        gen_set_label(l1);
2046
        tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
2047
        gen_set_label(l2);
2048
        tcg_temp_free(t0);
2049 2050 2051
        tcg_gen_sari_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], sh);
    } else {
        tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
2052
        tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
2053 2054
    }
    if (unlikely(Rc(ctx->opcode) != 0))
2055
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
2056
}
2057
GEN_HANDLER2(sradi0, "sradi", 0x1F, 0x1A, 0x19, 0x00000000, PPC_64B)
2058 2059 2060
{
    gen_sradi(ctx, 0);
}
2061
GEN_HANDLER2(sradi1, "sradi", 0x1F, 0x1B, 0x19, 0x00000000, PPC_64B)
2062 2063 2064 2065
{
    gen_sradi(ctx, 1);
}
/* srd & srd. */
2066 2067
GEN_HANDLER(srd, 0x1F, 0x1B, 0x10, 0x00000000, PPC_64B)
{
2068
    TCGv t0;
2069 2070 2071 2072
    int l1, l2;
    l1 = gen_new_label();
    l2 = gen_new_label();

P
pbrook 已提交
2073
    t0 = tcg_temp_local_new();
A
aurel32 已提交
2074 2075
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x7f);
    tcg_gen_brcondi_tl(TCG_COND_LT, t0, 0x40, l1);
2076 2077 2078
    tcg_gen_movi_tl(cpu_gpr[rA(ctx->opcode)], 0);
    tcg_gen_br(l2);
    gen_set_label(l1);
2079
    tcg_gen_shr_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], t0);
2080
    gen_set_label(l2);
2081
    tcg_temp_free(t0);
2082 2083 2084
    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
}
2085
#endif
B
bellard 已提交
2086 2087

/***                       Floating-Point arithmetic                       ***/
2088
#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat, set_fprf, type)           \
2089
GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, type)                        \
2090
{                                                                             \
2091
    if (unlikely(!ctx->fpu_enabled)) {                                        \
A
aurel32 已提交
2092
        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
B
bellard 已提交
2093 2094
        return;                                                               \
    }                                                                         \
2095 2096
    /* NIP cannot be restored if the memory exception comes from an helper */ \
    gen_update_nip(ctx, ctx->nip - 4);                                        \
2097
    gen_reset_fpstatus();                                                     \
A
aurel32 已提交
2098 2099
    gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)],      \
                     cpu_fpr[rC(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);     \
2100
    if (isfloat) {                                                            \
A
aurel32 已提交
2101
        gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]);  \
2102
    }                                                                         \
A
aurel32 已提交
2103 2104
    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], set_fprf,                      \
                     Rc(ctx->opcode) != 0);                                   \
2105 2106
}

2107 2108 2109
#define GEN_FLOAT_ACB(name, op2, set_fprf, type)                              \
_GEN_FLOAT_ACB(name, name, 0x3F, op2, 0, set_fprf, type);                     \
_GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1, set_fprf, type);
2110

2111 2112
#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat, set_fprf, type)     \
GEN_HANDLER(f##name, op1, op2, 0xFF, inval, type)                             \
2113
{                                                                             \
2114
    if (unlikely(!ctx->fpu_enabled)) {                                        \
A
aurel32 已提交
2115
        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
B
bellard 已提交
2116 2117
        return;                                                               \
    }                                                                         \
2118 2119
    /* NIP cannot be restored if the memory exception comes from an helper */ \
    gen_update_nip(ctx, ctx->nip - 4);                                        \
2120
    gen_reset_fpstatus();                                                     \
A
aurel32 已提交
2121 2122
    gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)],      \
                     cpu_fpr[rB(ctx->opcode)]);                               \
2123
    if (isfloat) {                                                            \
A
aurel32 已提交
2124
        gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]);  \
2125
    }                                                                         \
A
aurel32 已提交
2126 2127
    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)],                                \
                     set_fprf, Rc(ctx->opcode) != 0);                         \
2128
}
2129 2130 2131
#define GEN_FLOAT_AB(name, op2, inval, set_fprf, type)                        \
_GEN_FLOAT_AB(name, name, 0x3F, op2, inval, 0, set_fprf, type);               \
_GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1, set_fprf, type);
2132

2133 2134
#define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat, set_fprf, type)     \
GEN_HANDLER(f##name, op1, op2, 0xFF, inval, type)                             \
2135
{                                                                             \
2136
    if (unlikely(!ctx->fpu_enabled)) {                                        \
A
aurel32 已提交
2137
        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
B
bellard 已提交
2138 2139
        return;                                                               \
    }                                                                         \
2140 2141
    /* NIP cannot be restored if the memory exception comes from an helper */ \
    gen_update_nip(ctx, ctx->nip - 4);                                        \
2142
    gen_reset_fpstatus();                                                     \
A
aurel32 已提交
2143 2144
    gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)],      \
                       cpu_fpr[rC(ctx->opcode)]);                             \
2145
    if (isfloat) {                                                            \
A
aurel32 已提交
2146
        gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]);  \
2147
    }                                                                         \
A
aurel32 已提交
2148 2149
    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)],                                \
                     set_fprf, Rc(ctx->opcode) != 0);                         \
2150
}
2151 2152 2153
#define GEN_FLOAT_AC(name, op2, inval, set_fprf, type)                        \
_GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0, set_fprf, type);               \
_GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1, set_fprf, type);
2154

2155
#define GEN_FLOAT_B(name, op2, op3, set_fprf, type)                           \
2156
GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, type)                        \
2157
{                                                                             \
2158
    if (unlikely(!ctx->fpu_enabled)) {                                        \
A
aurel32 已提交
2159
        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
B
bellard 已提交
2160 2161
        return;                                                               \
    }                                                                         \
2162 2163
    /* NIP cannot be restored if the memory exception comes from an helper */ \
    gen_update_nip(ctx, ctx->nip - 4);                                        \
2164
    gen_reset_fpstatus();                                                     \
A
aurel32 已提交
2165 2166 2167
    gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);   \
    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)],                                \
                     set_fprf, Rc(ctx->opcode) != 0);                         \
B
bellard 已提交
2168 2169
}

2170
#define GEN_FLOAT_BS(name, op1, op2, set_fprf, type)                          \
2171
GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, type)                        \
2172
{                                                                             \
2173
    if (unlikely(!ctx->fpu_enabled)) {                                        \
A
aurel32 已提交
2174
        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
B
bellard 已提交
2175 2176
        return;                                                               \
    }                                                                         \
2177 2178
    /* NIP cannot be restored if the memory exception comes from an helper */ \
    gen_update_nip(ctx, ctx->nip - 4);                                        \
2179
    gen_reset_fpstatus();                                                     \
A
aurel32 已提交
2180 2181 2182
    gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);   \
    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)],                                \
                     set_fprf, Rc(ctx->opcode) != 0);                         \
B
bellard 已提交
2183 2184
}

2185
/* fadd - fadds */
2186
GEN_FLOAT_AB(add, 0x15, 0x000007C0, 1, PPC_FLOAT);
2187
/* fdiv - fdivs */
2188
GEN_FLOAT_AB(div, 0x12, 0x000007C0, 1, PPC_FLOAT);
2189
/* fmul - fmuls */
2190
GEN_FLOAT_AC(mul, 0x19, 0x0000F800, 1, PPC_FLOAT);
B
bellard 已提交
2191

2192
/* fre */
2193
GEN_FLOAT_BS(re, 0x3F, 0x18, 1, PPC_FLOAT_EXT);
2194

2195
/* fres */
2196
GEN_FLOAT_BS(res, 0x3B, 0x18, 1, PPC_FLOAT_FRES);
B
bellard 已提交
2197

2198
/* frsqrte */
2199 2200 2201
GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, 1, PPC_FLOAT_FRSQRTE);

/* frsqrtes */
A
aurel32 已提交
2202
GEN_HANDLER(frsqrtes, 0x3B, 0x1A, 0xFF, 0x001F07C0, PPC_FLOAT_FRSQRTES)
2203
{
A
aurel32 已提交
2204
    if (unlikely(!ctx->fpu_enabled)) {
A
aurel32 已提交
2205
        gen_exception(ctx, POWERPC_EXCP_FPU);
A
aurel32 已提交
2206 2207
        return;
    }
2208 2209
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
A
aurel32 已提交
2210 2211 2212 2213
    gen_reset_fpstatus();
    gen_helper_frsqrte(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);
    gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]);
    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 1, Rc(ctx->opcode) != 0);
2214
}
B
bellard 已提交
2215

2216
/* fsel */
2217
_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0, 0, PPC_FLOAT_FSEL);
2218
/* fsub - fsubs */
2219
GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT);
B
bellard 已提交
2220 2221
/* Optional: */
/* fsqrt */
2222
GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT)
2223
{
2224
    if (unlikely(!ctx->fpu_enabled)) {
A
aurel32 已提交
2225
        gen_exception(ctx, POWERPC_EXCP_FPU);
2226 2227
        return;
    }
2228 2229
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
2230
    gen_reset_fpstatus();
A
aurel32 已提交
2231 2232
    gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);
    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 1, Rc(ctx->opcode) != 0);
2233
}
B
bellard 已提交
2234

2235
GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT)
B
bellard 已提交
2236
{
2237
    if (unlikely(!ctx->fpu_enabled)) {
A
aurel32 已提交
2238
        gen_exception(ctx, POWERPC_EXCP_FPU);
B
bellard 已提交
2239 2240
        return;
    }
2241 2242
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
2243
    gen_reset_fpstatus();
A
aurel32 已提交
2244 2245 2246
    gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);
    gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]);
    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 1, Rc(ctx->opcode) != 0);
B
bellard 已提交
2247 2248 2249
}

/***                     Floating-Point multiply-and-add                   ***/
2250
/* fmadd - fmadds */
2251
GEN_FLOAT_ACB(madd, 0x1D, 1, PPC_FLOAT);
2252
/* fmsub - fmsubs */
2253
GEN_FLOAT_ACB(msub, 0x1C, 1, PPC_FLOAT);
2254
/* fnmadd - fnmadds */
2255
GEN_FLOAT_ACB(nmadd, 0x1F, 1, PPC_FLOAT);
2256
/* fnmsub - fnmsubs */
2257
GEN_FLOAT_ACB(nmsub, 0x1E, 1, PPC_FLOAT);
B
bellard 已提交
2258 2259 2260

/***                     Floating-Point round & convert                    ***/
/* fctiw */
2261
GEN_FLOAT_B(ctiw, 0x0E, 0x00, 0, PPC_FLOAT);
B
bellard 已提交
2262
/* fctiwz */
2263
GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT);
B
bellard 已提交
2264
/* frsp */
2265
GEN_FLOAT_B(rsp, 0x0C, 0x00, 1, PPC_FLOAT);
J
j_mayer 已提交
2266 2267
#if defined(TARGET_PPC64)
/* fcfid */
2268
GEN_FLOAT_B(cfid, 0x0E, 0x1A, 1, PPC_64B);
J
j_mayer 已提交
2269
/* fctid */
2270
GEN_FLOAT_B(ctid, 0x0E, 0x19, 0, PPC_64B);
J
j_mayer 已提交
2271
/* fctidz */
2272
GEN_FLOAT_B(ctidz, 0x0F, 0x19, 0, PPC_64B);
J
j_mayer 已提交
2273
#endif
B
bellard 已提交
2274

2275
/* frin */
2276
GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT);
2277
/* friz */
2278
GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT);
2279
/* frip */
2280
GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT);
2281
/* frim */
2282
GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT);
2283

B
bellard 已提交
2284 2285
/***                         Floating-Point compare                        ***/
/* fcmpo */
2286
GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT)
B
bellard 已提交
2287
{
A
aurel32 已提交
2288
    TCGv_i32 crf;
2289
    if (unlikely(!ctx->fpu_enabled)) {
A
aurel32 已提交
2290
        gen_exception(ctx, POWERPC_EXCP_FPU);
B
bellard 已提交
2291 2292
        return;
    }
2293 2294
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
2295
    gen_reset_fpstatus();
A
aurel32 已提交
2296 2297
    crf = tcg_const_i32(crfD(ctx->opcode));
    gen_helper_fcmpo(cpu_fpr[rA(ctx->opcode)], cpu_fpr[rB(ctx->opcode)], crf);
A
aurel32 已提交
2298
    tcg_temp_free_i32(crf);
A
aurel32 已提交
2299
    gen_helper_float_check_status();
B
bellard 已提交
2300 2301 2302
}

/* fcmpu */
2303
GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT)
B
bellard 已提交
2304
{
A
aurel32 已提交
2305
    TCGv_i32 crf;
2306
    if (unlikely(!ctx->fpu_enabled)) {
A
aurel32 已提交
2307
        gen_exception(ctx, POWERPC_EXCP_FPU);
B
bellard 已提交
2308 2309
        return;
    }
2310 2311
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
2312
    gen_reset_fpstatus();
A
aurel32 已提交
2313 2314
    crf = tcg_const_i32(crfD(ctx->opcode));
    gen_helper_fcmpu(cpu_fpr[rA(ctx->opcode)], cpu_fpr[rB(ctx->opcode)], crf);
A
aurel32 已提交
2315
    tcg_temp_free_i32(crf);
A
aurel32 已提交
2316
    gen_helper_float_check_status();
B
bellard 已提交
2317 2318
}

2319 2320
/***                         Floating-point move                           ***/
/* fabs */
2321 2322
/* XXX: beware that fabs never checks for NaNs nor update FPSCR */
GEN_FLOAT_B(abs, 0x08, 0x08, 0, PPC_FLOAT);
2323 2324

/* fmr  - fmr. */
2325
/* XXX: beware that fmr never checks for NaNs nor update FPSCR */
2326 2327
GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT)
{
2328
    if (unlikely(!ctx->fpu_enabled)) {
A
aurel32 已提交
2329
        gen_exception(ctx, POWERPC_EXCP_FPU);
B
bellard 已提交
2330 2331
        return;
    }
A
aurel32 已提交
2332 2333
    tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);
    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 0, Rc(ctx->opcode) != 0);
2334 2335 2336
}

/* fnabs */
2337 2338
/* XXX: beware that fnabs never checks for NaNs nor update FPSCR */
GEN_FLOAT_B(nabs, 0x08, 0x04, 0, PPC_FLOAT);
2339
/* fneg */
2340 2341
/* XXX: beware that fneg never checks for NaNs nor update FPSCR */
GEN_FLOAT_B(neg, 0x08, 0x01, 0, PPC_FLOAT);
2342

B
bellard 已提交
2343 2344 2345 2346
/***                  Floating-Point status & ctrl register                ***/
/* mcrfs */
GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT)
{
2347 2348
    int bfa;

2349
    if (unlikely(!ctx->fpu_enabled)) {
A
aurel32 已提交
2350
        gen_exception(ctx, POWERPC_EXCP_FPU);
B
bellard 已提交
2351 2352
        return;
    }
2353
    bfa = 4 * (7 - crfS(ctx->opcode));
2354 2355
    tcg_gen_shri_i32(cpu_crf[crfD(ctx->opcode)], cpu_fpscr, bfa);
    tcg_gen_andi_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)], 0xf);
A
aurel32 已提交
2356
    tcg_gen_andi_i32(cpu_fpscr, cpu_fpscr, ~(0xF << bfa));
B
bellard 已提交
2357 2358 2359 2360 2361
}

/* mffs */
GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT)
{
2362
    if (unlikely(!ctx->fpu_enabled)) {
A
aurel32 已提交
2363
        gen_exception(ctx, POWERPC_EXCP_FPU);
B
bellard 已提交
2364 2365
        return;
    }
2366
    gen_reset_fpstatus();
A
aurel32 已提交
2367 2368
    tcg_gen_extu_i32_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpscr);
    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 0, Rc(ctx->opcode) != 0);
B
bellard 已提交
2369 2370 2371 2372 2373
}

/* mtfsb0 */
GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT)
{
B
bellard 已提交
2374
    uint8_t crb;
2375

2376
    if (unlikely(!ctx->fpu_enabled)) {
A
aurel32 已提交
2377
        gen_exception(ctx, POWERPC_EXCP_FPU);
B
bellard 已提交
2378 2379
        return;
    }
A
aurel32 已提交
2380
    crb = 31 - crbD(ctx->opcode);
2381
    gen_reset_fpstatus();
A
aurel32 已提交
2382
    if (likely(crb != FPSCR_FEX && crb != FPSCR_VX)) {
2383 2384 2385 2386
        TCGv_i32 t0;
        /* NIP cannot be restored if the memory exception comes from an helper */
        gen_update_nip(ctx, ctx->nip - 4);
        t0 = tcg_const_i32(crb);
A
aurel32 已提交
2387 2388 2389
        gen_helper_fpscr_clrbit(t0);
        tcg_temp_free_i32(t0);
    }
2390
    if (unlikely(Rc(ctx->opcode) != 0)) {
2391
        tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX);
2392
    }
B
bellard 已提交
2393 2394 2395 2396 2397
}

/* mtfsb1 */
GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT)
{
B
bellard 已提交
2398
    uint8_t crb;
2399

2400
    if (unlikely(!ctx->fpu_enabled)) {
A
aurel32 已提交
2401
        gen_exception(ctx, POWERPC_EXCP_FPU);
B
bellard 已提交
2402 2403
        return;
    }
A
aurel32 已提交
2404
    crb = 31 - crbD(ctx->opcode);
2405 2406
    gen_reset_fpstatus();
    /* XXX: we pretend we can only do IEEE floating-point computations */
A
aurel32 已提交
2407
    if (likely(crb != FPSCR_FEX && crb != FPSCR_VX && crb != FPSCR_NI)) {
2408 2409 2410 2411
        TCGv_i32 t0;
        /* NIP cannot be restored if the memory exception comes from an helper */
        gen_update_nip(ctx, ctx->nip - 4);
        t0 = tcg_const_i32(crb);
A
aurel32 已提交
2412
        gen_helper_fpscr_setbit(t0);
2413
        tcg_temp_free_i32(t0);
A
aurel32 已提交
2414
    }
2415
    if (unlikely(Rc(ctx->opcode) != 0)) {
2416
        tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX);
2417 2418
    }
    /* We can raise a differed exception */
A
aurel32 已提交
2419
    gen_helper_float_check_status();
B
bellard 已提交
2420 2421 2422 2423 2424
}

/* mtfsf */
GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x02010000, PPC_FLOAT)
{
2425
    TCGv_i32 t0;
A
aurel32 已提交
2426

2427
    if (unlikely(!ctx->fpu_enabled)) {
A
aurel32 已提交
2428
        gen_exception(ctx, POWERPC_EXCP_FPU);
B
bellard 已提交
2429 2430
        return;
    }
2431 2432
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
2433
    gen_reset_fpstatus();
A
aurel32 已提交
2434 2435
    t0 = tcg_const_i32(FM(ctx->opcode));
    gen_helper_store_fpscr(cpu_fpr[rB(ctx->opcode)], t0);
2436
    tcg_temp_free_i32(t0);
2437
    if (unlikely(Rc(ctx->opcode) != 0)) {
2438
        tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX);
2439 2440
    }
    /* We can raise a differed exception */
A
aurel32 已提交
2441
    gen_helper_float_check_status();
B
bellard 已提交
2442 2443 2444 2445 2446
}

/* mtfsfi */
GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT)
{
2447
    int bf, sh;
2448 2449
    TCGv_i64 t0;
    TCGv_i32 t1;
2450

2451
    if (unlikely(!ctx->fpu_enabled)) {
A
aurel32 已提交
2452
        gen_exception(ctx, POWERPC_EXCP_FPU);
B
bellard 已提交
2453 2454
        return;
    }
2455 2456
    bf = crbD(ctx->opcode) >> 2;
    sh = 7 - bf;
2457 2458
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
2459
    gen_reset_fpstatus();
2460
    t0 = tcg_const_i64(FPIMM(ctx->opcode) << (4 * sh));
A
aurel32 已提交
2461 2462
    t1 = tcg_const_i32(1 << sh);
    gen_helper_store_fpscr(t0, t1);
2463 2464
    tcg_temp_free_i64(t0);
    tcg_temp_free_i32(t1);
2465
    if (unlikely(Rc(ctx->opcode) != 0)) {
2466
        tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX);
2467 2468
    }
    /* We can raise a differed exception */
A
aurel32 已提交
2469
    gen_helper_float_check_status();
B
bellard 已提交
2470 2471
}

2472 2473
/***                           Addressing modes                            ***/
/* Register indirect with immediate index : EA = (rA|0) + SIMM */
A
aurel32 已提交
2474
static always_inline void gen_addr_imm_index (DisasContext *ctx, TCGv EA, target_long maskl)
2475 2476 2477
{
    target_long simm = SIMM(ctx->opcode);

2478
    simm &= ~maskl;
A
aurel32 已提交
2479 2480 2481 2482 2483 2484
    if (rA(ctx->opcode) == 0) {
#if defined(TARGET_PPC64)
        if (!ctx->sf_mode) {
            tcg_gen_movi_tl(EA, (uint32_t)simm);
        } else
#endif
2485
        tcg_gen_movi_tl(EA, simm);
A
aurel32 已提交
2486
    } else if (likely(simm != 0)) {
2487
        tcg_gen_addi_tl(EA, cpu_gpr[rA(ctx->opcode)], simm);
A
aurel32 已提交
2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498
#if defined(TARGET_PPC64)
        if (!ctx->sf_mode) {
            tcg_gen_ext32u_tl(EA, EA);
        }
#endif
    } else {
#if defined(TARGET_PPC64)
        if (!ctx->sf_mode) {
            tcg_gen_ext32u_tl(EA, cpu_gpr[rA(ctx->opcode)]);
        } else
#endif
2499
        tcg_gen_mov_tl(EA, cpu_gpr[rA(ctx->opcode)]);
A
aurel32 已提交
2500
    }
2501 2502
}

A
aurel32 已提交
2503
static always_inline void gen_addr_reg_index (DisasContext *ctx, TCGv EA)
2504
{
A
aurel32 已提交
2505 2506 2507 2508 2509 2510
    if (rA(ctx->opcode) == 0) {
#if defined(TARGET_PPC64)
        if (!ctx->sf_mode) {
            tcg_gen_ext32u_tl(EA, cpu_gpr[rB(ctx->opcode)]);
        } else
#endif
2511
        tcg_gen_mov_tl(EA, cpu_gpr[rB(ctx->opcode)]);
A
aurel32 已提交
2512
    } else {
2513
        tcg_gen_add_tl(EA, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
A
aurel32 已提交
2514 2515 2516 2517 2518 2519
#if defined(TARGET_PPC64)
        if (!ctx->sf_mode) {
            tcg_gen_ext32u_tl(EA, EA);
        }
#endif
    }
2520 2521
}

A
aurel32 已提交
2522
static always_inline void gen_addr_register (DisasContext *ctx, TCGv EA)
2523
{
A
aurel32 已提交
2524
    if (rA(ctx->opcode) == 0) {
2525
        tcg_gen_movi_tl(EA, 0);
A
aurel32 已提交
2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543
    } else {
#if defined(TARGET_PPC64)
        if (!ctx->sf_mode) {
            tcg_gen_ext32u_tl(EA, cpu_gpr[rA(ctx->opcode)]);
        } else
#endif
            tcg_gen_mov_tl(EA, cpu_gpr[rA(ctx->opcode)]);
    }
}

static always_inline void gen_addr_add (DisasContext *ctx, TCGv ret, TCGv arg1, target_long val)
{
    tcg_gen_addi_tl(ret, arg1, val);
#if defined(TARGET_PPC64)
    if (!ctx->sf_mode) {
        tcg_gen_ext32u_tl(ret, ret);
    }
#endif
2544 2545
}

2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563
static always_inline void gen_check_align (DisasContext *ctx, TCGv EA, int mask)
{
    int l1 = gen_new_label();
    TCGv t0 = tcg_temp_new();
    TCGv_i32 t1, t2;
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
    tcg_gen_andi_tl(t0, EA, mask);
    tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
    t1 = tcg_const_i32(POWERPC_EXCP_ALIGN);
    t2 = tcg_const_i32(0);
    gen_helper_raise_exception_err(t1, t2);
    tcg_temp_free_i32(t1);
    tcg_temp_free_i32(t2);
    gen_set_label(l1);
    tcg_temp_free(t0);
}

2564
/***                             Integer load                              ***/
A
aurel32 已提交
2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578
static always_inline void gen_qemu_ld8u(DisasContext *ctx, TCGv arg1, TCGv arg2)
{
    tcg_gen_qemu_ld8u(arg1, arg2, ctx->mem_idx);
}

static always_inline void gen_qemu_ld8s(DisasContext *ctx, TCGv arg1, TCGv arg2)
{
    tcg_gen_qemu_ld8s(arg1, arg2, ctx->mem_idx);
}

static always_inline void gen_qemu_ld16u(DisasContext *ctx, TCGv arg1, TCGv arg2)
{
    tcg_gen_qemu_ld16u(arg1, arg2, ctx->mem_idx);
    if (unlikely(ctx->le_mode)) {
A
aurel32 已提交
2579
#if defined(TARGET_PPC64)
A
aurel32 已提交
2580 2581
        TCGv_i32 t0 = tcg_temp_new_i32();
        tcg_gen_trunc_tl_i32(t0, arg1);
2582
        tcg_gen_bswap16_i32(t0, t0);
A
aurel32 已提交
2583
        tcg_gen_extu_i32_tl(arg1, t0);
P
pbrook 已提交
2584
        tcg_temp_free_i32(t0);
A
aurel32 已提交
2585 2586 2587 2588
#else
        tcg_gen_bswap16_i32(arg1, arg1);
#endif
    }
A
aurel32 已提交
2589 2590
}

A
aurel32 已提交
2591
static always_inline void gen_qemu_ld16s(DisasContext *ctx, TCGv arg1, TCGv arg2)
A
aurel32 已提交
2592
{
A
aurel32 已提交
2593 2594
    if (unlikely(ctx->le_mode)) {
#if defined(TARGET_PPC64)
P
pbrook 已提交
2595
        TCGv_i32 t0;
A
aurel32 已提交
2596
        tcg_gen_qemu_ld16u(arg1, arg2, ctx->mem_idx);
P
pbrook 已提交
2597
        t0 = tcg_temp_new_i32();
A
aurel32 已提交
2598
        tcg_gen_trunc_tl_i32(t0, arg1);
2599
        tcg_gen_bswap16_i32(t0, t0);
A
aurel32 已提交
2600 2601
        tcg_gen_extu_i32_tl(arg1, t0);
        tcg_gen_ext16s_tl(arg1, arg1);
P
pbrook 已提交
2602
        tcg_temp_free_i32(t0);
A
aurel32 已提交
2603 2604 2605 2606 2607 2608 2609 2610
#else
        tcg_gen_qemu_ld16u(arg1, arg2, ctx->mem_idx);
        tcg_gen_bswap16_i32(arg1, arg1);
        tcg_gen_ext16s_i32(arg1, arg1);
#endif
    } else {
        tcg_gen_qemu_ld16s(arg1, arg2, ctx->mem_idx);
    }
A
aurel32 已提交
2611 2612
}

A
aurel32 已提交
2613
static always_inline void gen_qemu_ld32u(DisasContext *ctx, TCGv arg1, TCGv arg2)
A
aurel32 已提交
2614
{
A
aurel32 已提交
2615 2616 2617 2618 2619
    tcg_gen_qemu_ld32u(arg1, arg2, ctx->mem_idx);
    if (unlikely(ctx->le_mode)) {
#if defined(TARGET_PPC64)
        TCGv_i32 t0 = tcg_temp_new_i32();
        tcg_gen_trunc_tl_i32(t0, arg1);
2620
        tcg_gen_bswap_i32(t0, t0);
A
aurel32 已提交
2621
        tcg_gen_extu_i32_tl(arg1, t0);
P
pbrook 已提交
2622
        tcg_temp_free_i32(t0);
A
aurel32 已提交
2623 2624 2625 2626
#else
        tcg_gen_bswap_i32(arg1, arg1);
#endif
    }
A
aurel32 已提交
2627 2628
}

A
aurel32 已提交
2629 2630
#if defined(TARGET_PPC64)
static always_inline void gen_qemu_ld32s(DisasContext *ctx, TCGv arg1, TCGv arg2)
A
aurel32 已提交
2631
{
B
blueswir1 已提交
2632
    if (unlikely(ctx->le_mode)) {
P
pbrook 已提交
2633
        TCGv_i32 t0;
A
aurel32 已提交
2634
        tcg_gen_qemu_ld32u(arg1, arg2, ctx->mem_idx);
P
pbrook 已提交
2635
        t0 = tcg_temp_new_i32();
A
aurel32 已提交
2636
        tcg_gen_trunc_tl_i32(t0, arg1);
2637
        tcg_gen_bswap_i32(t0, t0);
A
aurel32 已提交
2638
        tcg_gen_ext_i32_tl(arg1, t0);
P
pbrook 已提交
2639
        tcg_temp_free_i32(t0);
A
aurel32 已提交
2640
    } else
A
aurel32 已提交
2641
        tcg_gen_qemu_ld32s(arg1, arg2, ctx->mem_idx);
A
aurel32 已提交
2642
}
A
aurel32 已提交
2643
#endif
A
aurel32 已提交
2644

A
aurel32 已提交
2645
static always_inline void gen_qemu_ld64(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
A
aurel32 已提交
2646
{
A
aurel32 已提交
2647 2648 2649 2650
    tcg_gen_qemu_ld64(arg1, arg2, ctx->mem_idx);
    if (unlikely(ctx->le_mode)) {
        tcg_gen_bswap_i64(arg1, arg1);
    }
A
aurel32 已提交
2651 2652
}

A
aurel32 已提交
2653
static always_inline void gen_qemu_st8(DisasContext *ctx, TCGv arg1, TCGv arg2)
A
aurel32 已提交
2654
{
A
aurel32 已提交
2655
    tcg_gen_qemu_st8(arg1, arg2, ctx->mem_idx);
A
aurel32 已提交
2656 2657
}

A
aurel32 已提交
2658
static always_inline void gen_qemu_st16(DisasContext *ctx, TCGv arg1, TCGv arg2)
A
aurel32 已提交
2659
{
A
aurel32 已提交
2660 2661
    if (unlikely(ctx->le_mode)) {
#if defined(TARGET_PPC64)
P
pbrook 已提交
2662
        TCGv_i32 t0;
A
aurel32 已提交
2663
        TCGv t1;
P
pbrook 已提交
2664
        t0 = tcg_temp_new_i32();
A
aurel32 已提交
2665
        tcg_gen_trunc_tl_i32(t0, arg1);
2666 2667
        tcg_gen_ext16u_i32(t0, t0);
        tcg_gen_bswap16_i32(t0, t0);
A
aurel32 已提交
2668
        t1 = tcg_temp_new();
2669
        tcg_gen_extu_i32_tl(t1, t0);
P
pbrook 已提交
2670
        tcg_temp_free_i32(t0);
A
aurel32 已提交
2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682
        tcg_gen_qemu_st16(t1, arg2, ctx->mem_idx);
        tcg_temp_free(t1);
#else
        TCGv t0 = tcg_temp_new();
        tcg_gen_ext16u_tl(t0, arg1);
        tcg_gen_bswap16_i32(t0, t0);
        tcg_gen_qemu_st16(t0, arg2, ctx->mem_idx);
        tcg_temp_free(t0);
#endif
    } else {
        tcg_gen_qemu_st16(arg1, arg2, ctx->mem_idx);
    }
A
aurel32 已提交
2683 2684
}

A
aurel32 已提交
2685
static always_inline void gen_qemu_st32(DisasContext *ctx, TCGv arg1, TCGv arg2)
A
aurel32 已提交
2686
{
A
aurel32 已提交
2687 2688
    if (unlikely(ctx->le_mode)) {
#if defined(TARGET_PPC64)
P
pbrook 已提交
2689
        TCGv_i32 t0;
A
aurel32 已提交
2690
        TCGv t1;
P
pbrook 已提交
2691
        t0 = tcg_temp_new_i32();
A
aurel32 已提交
2692
        tcg_gen_trunc_tl_i32(t0, arg1);
2693
        tcg_gen_bswap_i32(t0, t0);
A
aurel32 已提交
2694
        t1 = tcg_temp_new();
2695
        tcg_gen_extu_i32_tl(t1, t0);
P
pbrook 已提交
2696
        tcg_temp_free_i32(t0);
A
aurel32 已提交
2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707
        tcg_gen_qemu_st32(t1, arg2, ctx->mem_idx);
        tcg_temp_free(t1);
#else
        TCGv t0 = tcg_temp_new_i32();
        tcg_gen_bswap_i32(t0, arg1);
        tcg_gen_qemu_st32(t0, arg2, ctx->mem_idx);
        tcg_temp_free(t0);
#endif
    } else {
        tcg_gen_qemu_st32(arg1, arg2, ctx->mem_idx);
    }
A
aurel32 已提交
2708 2709
}

A
aurel32 已提交
2710
static always_inline void gen_qemu_st64(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
A
aurel32 已提交
2711
{
A
aurel32 已提交
2712
    if (unlikely(ctx->le_mode)) {
P
pbrook 已提交
2713
        TCGv_i64 t0 = tcg_temp_new_i64();
A
aurel32 已提交
2714 2715
        tcg_gen_bswap_i64(t0, arg1);
        tcg_gen_qemu_st64(t0, arg2, ctx->mem_idx);
P
pbrook 已提交
2716
        tcg_temp_free_i64(t0);
A
aurel32 已提交
2717
    } else
A
aurel32 已提交
2718
        tcg_gen_qemu_st64(arg1, arg2, ctx->mem_idx);
A
aurel32 已提交
2719 2720
}

2721 2722
#define GEN_LD(name, ldop, opc, type)                                         \
GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type)                          \
B
bellard 已提交
2723
{                                                                             \
A
aurel32 已提交
2724 2725 2726 2727 2728
    TCGv EA;                                                                  \
    gen_set_access_type(ctx, ACCESS_INT);                                     \
    EA = tcg_temp_new();                                                      \
    gen_addr_imm_index(ctx, EA, 0);                                           \
    gen_qemu_##ldop(ctx, cpu_gpr[rD(ctx->opcode)], EA);                       \
A
aurel32 已提交
2729
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2730 2731
}

2732 2733
#define GEN_LDU(name, ldop, opc, type)                                        \
GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type)                       \
B
bellard 已提交
2734
{                                                                             \
A
aurel32 已提交
2735
    TCGv EA;                                                                  \
2736 2737
    if (unlikely(rA(ctx->opcode) == 0 ||                                      \
                 rA(ctx->opcode) == rD(ctx->opcode))) {                       \
A
aurel32 已提交
2738
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);                   \
2739
        return;                                                               \
2740
    }                                                                         \
A
aurel32 已提交
2741
    gen_set_access_type(ctx, ACCESS_INT);                                     \
2742
    EA = tcg_temp_new();                                                      \
J
j_mayer 已提交
2743
    if (type == PPC_64B)                                                      \
A
aurel32 已提交
2744
        gen_addr_imm_index(ctx, EA, 0x03);                                    \
J
j_mayer 已提交
2745
    else                                                                      \
A
aurel32 已提交
2746 2747
        gen_addr_imm_index(ctx, EA, 0);                                       \
    gen_qemu_##ldop(ctx, cpu_gpr[rD(ctx->opcode)], EA);                       \
A
aurel32 已提交
2748 2749
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2750 2751
}

2752 2753
#define GEN_LDUX(name, ldop, opc2, opc3, type)                                \
GEN_HANDLER(name##ux, 0x1F, opc2, opc3, 0x00000001, type)                     \
B
bellard 已提交
2754
{                                                                             \
A
aurel32 已提交
2755
    TCGv EA;                                                                  \
2756 2757
    if (unlikely(rA(ctx->opcode) == 0 ||                                      \
                 rA(ctx->opcode) == rD(ctx->opcode))) {                       \
A
aurel32 已提交
2758
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);                   \
2759
        return;                                                               \
2760
    }                                                                         \
A
aurel32 已提交
2761
    gen_set_access_type(ctx, ACCESS_INT);                                     \
2762
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
2763 2764
    gen_addr_reg_index(ctx, EA);                                              \
    gen_qemu_##ldop(ctx, cpu_gpr[rD(ctx->opcode)], EA);                       \
A
aurel32 已提交
2765 2766
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2767 2768
}

2769 2770
#define GEN_LDX(name, ldop, opc2, opc3, type)                                 \
GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type)                      \
B
bellard 已提交
2771
{                                                                             \
A
aurel32 已提交
2772 2773 2774 2775 2776
    TCGv EA;                                                                  \
    gen_set_access_type(ctx, ACCESS_INT);                                     \
    EA = tcg_temp_new();                                                      \
    gen_addr_reg_index(ctx, EA);                                              \
    gen_qemu_##ldop(ctx, cpu_gpr[rD(ctx->opcode)], EA);                       \
A
aurel32 已提交
2777
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2778 2779
}

2780 2781 2782 2783 2784
#define GEN_LDS(name, ldop, op, type)                                         \
GEN_LD(name, ldop, op | 0x20, type);                                          \
GEN_LDU(name, ldop, op | 0x21, type);                                         \
GEN_LDUX(name, ldop, 0x17, op | 0x01, type);                                  \
GEN_LDX(name, ldop, 0x17, op | 0x00, type)
B
bellard 已提交
2785 2786

/* lbz lbzu lbzux lbzx */
2787
GEN_LDS(lbz, ld8u, 0x02, PPC_INTEGER);
B
bellard 已提交
2788
/* lha lhau lhaux lhax */
2789
GEN_LDS(lha, ld16s, 0x0A, PPC_INTEGER);
B
bellard 已提交
2790
/* lhz lhzu lhzux lhzx */
2791
GEN_LDS(lhz, ld16u, 0x08, PPC_INTEGER);
B
bellard 已提交
2792
/* lwz lwzu lwzux lwzx */
2793
GEN_LDS(lwz, ld32u, 0x00, PPC_INTEGER);
2794 2795
#if defined(TARGET_PPC64)
/* lwaux */
2796
GEN_LDUX(lwa, ld32s, 0x15, 0x0B, PPC_64B);
2797
/* lwax */
2798
GEN_LDX(lwa, ld32s, 0x15, 0x0A, PPC_64B);
2799
/* ldux */
2800
GEN_LDUX(ld, ld64, 0x15, 0x01, PPC_64B);
2801
/* ldx */
2802
GEN_LDX(ld, ld64, 0x15, 0x00, PPC_64B);
2803 2804
GEN_HANDLER(ld, 0x3A, 0xFF, 0xFF, 0x00000000, PPC_64B)
{
A
aurel32 已提交
2805
    TCGv EA;
2806 2807 2808
    if (Rc(ctx->opcode)) {
        if (unlikely(rA(ctx->opcode) == 0 ||
                     rA(ctx->opcode) == rD(ctx->opcode))) {
A
aurel32 已提交
2809
            gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
2810 2811 2812
            return;
        }
    }
A
aurel32 已提交
2813
    gen_set_access_type(ctx, ACCESS_INT);
P
pbrook 已提交
2814
    EA = tcg_temp_new();
A
aurel32 已提交
2815
    gen_addr_imm_index(ctx, EA, 0x03);
2816 2817
    if (ctx->opcode & 0x02) {
        /* lwa (lwau is undefined) */
A
aurel32 已提交
2818
        gen_qemu_ld32s(ctx, cpu_gpr[rD(ctx->opcode)], EA);
2819 2820
    } else {
        /* ld - ldu */
A
aurel32 已提交
2821
        gen_qemu_ld64(ctx, cpu_gpr[rD(ctx->opcode)], EA);
2822 2823
    }
    if (Rc(ctx->opcode))
A
aurel32 已提交
2824 2825
        tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);
    tcg_temp_free(EA);
2826
}
2827 2828 2829 2830
/* lq */
GEN_HANDLER(lq, 0x38, 0xFF, 0xFF, 0x00000000, PPC_64BX)
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
2831
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
2832 2833
#else
    int ra, rd;
A
aurel32 已提交
2834
    TCGv EA;
2835 2836

    /* Restore CPU state */
A
aurel32 已提交
2837
    if (unlikely(ctx->mem_idx == 0)) {
A
aurel32 已提交
2838
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
2839 2840 2841 2842 2843
        return;
    }
    ra = rA(ctx->opcode);
    rd = rD(ctx->opcode);
    if (unlikely((rd & 1) || rd == ra)) {
A
aurel32 已提交
2844
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
2845 2846
        return;
    }
A
aurel32 已提交
2847
    if (unlikely(ctx->le_mode)) {
2848
        /* Little-endian mode is not handled */
A
aurel32 已提交
2849
        gen_exception_err(ctx, POWERPC_EXCP_ALIGN, POWERPC_EXCP_ALIGN_LE);
2850 2851
        return;
    }
A
aurel32 已提交
2852
    gen_set_access_type(ctx, ACCESS_INT);
P
pbrook 已提交
2853
    EA = tcg_temp_new();
A
aurel32 已提交
2854 2855 2856 2857
    gen_addr_imm_index(ctx, EA, 0x0F);
    gen_qemu_ld64(ctx, cpu_gpr[rd], EA);
    gen_addr_add(ctx, EA, EA, 8);
    gen_qemu_ld64(ctx, cpu_gpr[rd+1], EA);
A
aurel32 已提交
2858
    tcg_temp_free(EA);
2859 2860
#endif
}
2861
#endif
B
bellard 已提交
2862 2863

/***                              Integer store                            ***/
2864 2865
#define GEN_ST(name, stop, opc, type)                                         \
GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type)                          \
B
bellard 已提交
2866
{                                                                             \
A
aurel32 已提交
2867 2868 2869 2870 2871
    TCGv EA;                                                                  \
    gen_set_access_type(ctx, ACCESS_INT);                                     \
    EA = tcg_temp_new();                                                      \
    gen_addr_imm_index(ctx, EA, 0);                                           \
    gen_qemu_##stop(ctx, cpu_gpr[rS(ctx->opcode)], EA);                       \
A
aurel32 已提交
2872
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2873 2874
}

2875 2876
#define GEN_STU(name, stop, opc, type)                                        \
GEN_HANDLER(stop##u, opc, 0xFF, 0xFF, 0x00000000, type)                       \
B
bellard 已提交
2877
{                                                                             \
A
aurel32 已提交
2878
    TCGv EA;                                                                  \
2879
    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
A
aurel32 已提交
2880
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);                   \
2881
        return;                                                               \
2882
    }                                                                         \
A
aurel32 已提交
2883
    gen_set_access_type(ctx, ACCESS_INT);                                     \
2884
    EA = tcg_temp_new();                                                      \
J
j_mayer 已提交
2885
    if (type == PPC_64B)                                                      \
A
aurel32 已提交
2886
        gen_addr_imm_index(ctx, EA, 0x03);                                    \
J
j_mayer 已提交
2887
    else                                                                      \
A
aurel32 已提交
2888 2889
        gen_addr_imm_index(ctx, EA, 0);                                       \
    gen_qemu_##stop(ctx, cpu_gpr[rS(ctx->opcode)], EA);                       \
A
aurel32 已提交
2890 2891
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2892 2893
}

2894 2895
#define GEN_STUX(name, stop, opc2, opc3, type)                                \
GEN_HANDLER(name##ux, 0x1F, opc2, opc3, 0x00000001, type)                     \
B
bellard 已提交
2896
{                                                                             \
A
aurel32 已提交
2897
    TCGv EA;                                                                  \
2898
    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
A
aurel32 已提交
2899
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);                   \
2900
        return;                                                               \
2901
    }                                                                         \
A
aurel32 已提交
2902
    gen_set_access_type(ctx, ACCESS_INT);                                     \
2903
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
2904 2905
    gen_addr_reg_index(ctx, EA);                                              \
    gen_qemu_##stop(ctx, cpu_gpr[rS(ctx->opcode)], EA);                       \
A
aurel32 已提交
2906 2907
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2908 2909
}

2910 2911
#define GEN_STX(name, stop, opc2, opc3, type)                                 \
GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type)                      \
B
bellard 已提交
2912
{                                                                             \
A
aurel32 已提交
2913 2914 2915 2916 2917
    TCGv EA;                                                                  \
    gen_set_access_type(ctx, ACCESS_INT);                                     \
    EA = tcg_temp_new();                                                      \
    gen_addr_reg_index(ctx, EA);                                              \
    gen_qemu_##stop(ctx, cpu_gpr[rS(ctx->opcode)], EA);                       \
A
aurel32 已提交
2918
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2919 2920
}

2921 2922 2923 2924 2925
#define GEN_STS(name, stop, op, type)                                         \
GEN_ST(name, stop, op | 0x20, type);                                          \
GEN_STU(name, stop, op | 0x21, type);                                         \
GEN_STUX(name, stop, 0x17, op | 0x01, type);                                  \
GEN_STX(name, stop, 0x17, op | 0x00, type)
B
bellard 已提交
2926 2927

/* stb stbu stbux stbx */
2928
GEN_STS(stb, st8, 0x06, PPC_INTEGER);
B
bellard 已提交
2929
/* sth sthu sthux sthx */
2930
GEN_STS(sth, st16, 0x0C, PPC_INTEGER);
B
bellard 已提交
2931
/* stw stwu stwux stwx */
2932
GEN_STS(stw, st32, 0x04, PPC_INTEGER);
2933
#if defined(TARGET_PPC64)
2934 2935
GEN_STUX(std, st64, 0x15, 0x05, PPC_64B);
GEN_STX(std, st64, 0x15, 0x04, PPC_64B);
2936
GEN_HANDLER(std, 0x3E, 0xFF, 0xFF, 0x00000000, PPC_64B)
2937
{
2938
    int rs;
A
aurel32 已提交
2939
    TCGv EA;
2940 2941 2942 2943

    rs = rS(ctx->opcode);
    if ((ctx->opcode & 0x3) == 0x2) {
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
2944
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
2945 2946
#else
        /* stq */
A
aurel32 已提交
2947
        if (unlikely(ctx->mem_idx == 0)) {
A
aurel32 已提交
2948
            gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
2949 2950 2951
            return;
        }
        if (unlikely(rs & 1)) {
A
aurel32 已提交
2952
            gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
2953 2954
            return;
        }
A
aurel32 已提交
2955
        if (unlikely(ctx->le_mode)) {
2956
            /* Little-endian mode is not handled */
A
aurel32 已提交
2957
            gen_exception_err(ctx, POWERPC_EXCP_ALIGN, POWERPC_EXCP_ALIGN_LE);
2958 2959
            return;
        }
A
aurel32 已提交
2960
        gen_set_access_type(ctx, ACCESS_INT);
P
pbrook 已提交
2961
        EA = tcg_temp_new();
A
aurel32 已提交
2962 2963 2964 2965
        gen_addr_imm_index(ctx, EA, 0x03);
        gen_qemu_st64(ctx, cpu_gpr[rs], EA);
        gen_addr_add(ctx, EA, EA, 8);
        gen_qemu_st64(ctx, cpu_gpr[rs+1], EA);
A
aurel32 已提交
2966
        tcg_temp_free(EA);
2967 2968 2969 2970 2971
#endif
    } else {
        /* std / stdu */
        if (Rc(ctx->opcode)) {
            if (unlikely(rA(ctx->opcode) == 0)) {
A
aurel32 已提交
2972
                gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
2973 2974 2975
                return;
            }
        }
A
aurel32 已提交
2976
        gen_set_access_type(ctx, ACCESS_INT);
P
pbrook 已提交
2977
        EA = tcg_temp_new();
A
aurel32 已提交
2978 2979
        gen_addr_imm_index(ctx, EA, 0x03);
        gen_qemu_st64(ctx, cpu_gpr[rs], EA);
2980
        if (Rc(ctx->opcode))
A
aurel32 已提交
2981 2982
            tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);
        tcg_temp_free(EA);
2983 2984 2985
    }
}
#endif
B
bellard 已提交
2986 2987
/***                Integer load and store with byte reverse               ***/
/* lhbrx */
A
aurel32 已提交
2988
static void always_inline gen_qemu_ld16ur(DisasContext *ctx, TCGv arg1, TCGv arg2)
A
aurel32 已提交
2989
{
A
aurel32 已提交
2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001
    tcg_gen_qemu_ld16u(arg1, arg2, ctx->mem_idx);
    if (likely(!ctx->le_mode)) {
#if defined(TARGET_PPC64)
        TCGv_i32 t0 = tcg_temp_new_i32();
        tcg_gen_trunc_tl_i32(t0, arg1);
        tcg_gen_bswap16_i32(t0, t0);
        tcg_gen_extu_i32_tl(arg1, t0);
        tcg_temp_free_i32(t0);
#else
        tcg_gen_bswap16_i32(arg1, arg1);
#endif
    }
A
aurel32 已提交
3002
}
3003
GEN_LDX(lhbr, ld16ur, 0x16, 0x18, PPC_INTEGER);
A
aurel32 已提交
3004

B
bellard 已提交
3005
/* lwbrx */
A
aurel32 已提交
3006
static void always_inline gen_qemu_ld32ur(DisasContext *ctx, TCGv arg1, TCGv arg2)
A
aurel32 已提交
3007
{
A
aurel32 已提交
3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019
    tcg_gen_qemu_ld32u(arg1, arg2, ctx->mem_idx);
    if (likely(!ctx->le_mode)) {
#if defined(TARGET_PPC64)
        TCGv_i32 t0 = tcg_temp_new_i32();
        tcg_gen_trunc_tl_i32(t0, arg1);
        tcg_gen_bswap_i32(t0, t0);
        tcg_gen_extu_i32_tl(arg1, t0);
        tcg_temp_free_i32(t0);
#else
        tcg_gen_bswap_i32(arg1, arg1);
#endif
    }
A
aurel32 已提交
3020
}
3021
GEN_LDX(lwbr, ld32ur, 0x16, 0x10, PPC_INTEGER);
A
aurel32 已提交
3022

B
bellard 已提交
3023
/* sthbrx */
A
aurel32 已提交
3024
static void always_inline gen_qemu_st16r(DisasContext *ctx, TCGv arg1, TCGv arg2)
A
aurel32 已提交
3025
{
A
aurel32 已提交
3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048
    if (likely(!ctx->le_mode)) {
#if defined(TARGET_PPC64)
        TCGv_i32 t0;
        TCGv t1;
        t0 = tcg_temp_new_i32();
        tcg_gen_trunc_tl_i32(t0, arg1);
        tcg_gen_ext16u_i32(t0, t0);
        tcg_gen_bswap16_i32(t0, t0);
        t1 = tcg_temp_new();
        tcg_gen_extu_i32_tl(t1, t0);
        tcg_temp_free_i32(t0);
        tcg_gen_qemu_st16(t1, arg2, ctx->mem_idx);
        tcg_temp_free(t1);
#else
        TCGv t0 = tcg_temp_new();
        tcg_gen_ext16u_tl(t0, arg1);
        tcg_gen_bswap16_i32(t0, t0);
        tcg_gen_qemu_st16(t0, arg2, ctx->mem_idx);
        tcg_temp_free(t0);
#endif
    } else {
        tcg_gen_qemu_st16(arg1, arg2, ctx->mem_idx);
    }
A
aurel32 已提交
3049
}
3050
GEN_STX(sthbr, st16r, 0x16, 0x1C, PPC_INTEGER);
A
aurel32 已提交
3051

B
bellard 已提交
3052
/* stwbrx */
A
aurel32 已提交
3053
static void always_inline gen_qemu_st32r(DisasContext *ctx, TCGv arg1, TCGv arg2)
A
aurel32 已提交
3054
{
A
aurel32 已提交
3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075
    if (likely(!ctx->le_mode)) {
#if defined(TARGET_PPC64)
        TCGv_i32 t0;
        TCGv t1;
        t0 = tcg_temp_new_i32();
        tcg_gen_trunc_tl_i32(t0, arg1);
        tcg_gen_bswap_i32(t0, t0);
        t1 = tcg_temp_new();
        tcg_gen_extu_i32_tl(t1, t0);
        tcg_temp_free_i32(t0);
        tcg_gen_qemu_st32(t1, arg2, ctx->mem_idx);
        tcg_temp_free(t1);
#else
        TCGv t0 = tcg_temp_new_i32();
        tcg_gen_bswap_i32(t0, arg1);
        tcg_gen_qemu_st32(t0, arg2, ctx->mem_idx);
        tcg_temp_free(t0);
#endif
    } else {
        tcg_gen_qemu_st32(arg1, arg2, ctx->mem_idx);
    }
A
aurel32 已提交
3076
}
3077
GEN_STX(stwbr, st32r, 0x16, 0x14, PPC_INTEGER);
B
bellard 已提交
3078 3079 3080 3081 3082

/***                    Integer load and store multiple                    ***/
/* lmw */
GEN_HANDLER(lmw, 0x2E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
A
aurel32 已提交
3083 3084 3085
    TCGv t0;
    TCGv_i32 t1;
    gen_set_access_type(ctx, ACCESS_INT);
3086
    /* NIP cannot be restored if the memory exception comes from an helper */
3087
    gen_update_nip(ctx, ctx->nip - 4);
A
aurel32 已提交
3088 3089 3090
    t0 = tcg_temp_new();
    t1 = tcg_const_i32(rD(ctx->opcode));
    gen_addr_imm_index(ctx, t0, 0);
3091 3092 3093
    gen_helper_lmw(t0, t1);
    tcg_temp_free(t0);
    tcg_temp_free_i32(t1);
B
bellard 已提交
3094 3095 3096 3097 3098
}

/* stmw */
GEN_HANDLER(stmw, 0x2F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
A
aurel32 已提交
3099 3100 3101
    TCGv t0;
    TCGv_i32 t1;
    gen_set_access_type(ctx, ACCESS_INT);
3102
    /* NIP cannot be restored if the memory exception comes from an helper */
3103
    gen_update_nip(ctx, ctx->nip - 4);
A
aurel32 已提交
3104 3105 3106
    t0 = tcg_temp_new();
    t1 = tcg_const_i32(rS(ctx->opcode));
    gen_addr_imm_index(ctx, t0, 0);
3107 3108 3109
    gen_helper_stmw(t0, t1);
    tcg_temp_free(t0);
    tcg_temp_free_i32(t1);
B
bellard 已提交
3110 3111 3112 3113
}

/***                    Integer load and store strings                     ***/
/* lswi */
3114
/* PowerPC32 specification says we must generate an exception if
3115 3116 3117 3118
 * 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...
 */
3119
GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_STRING)
B
bellard 已提交
3120
{
3121 3122
    TCGv t0;
    TCGv_i32 t1, t2;
B
bellard 已提交
3123 3124
    int nb = NB(ctx->opcode);
    int start = rD(ctx->opcode);
3125
    int ra = rA(ctx->opcode);
B
bellard 已提交
3126 3127 3128 3129 3130
    int nr;

    if (nb == 0)
        nb = 32;
    nr = nb / 4;
3131 3132 3133
    if (unlikely(((start + nr) > 32  &&
                  start <= ra && (start + nr - 32) > ra) ||
                 ((start + nr) <= 32 && start <= ra && (start + nr) > ra))) {
A
aurel32 已提交
3134
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_LSWX);
3135
        return;
B
bellard 已提交
3136
    }
A
aurel32 已提交
3137
    gen_set_access_type(ctx, ACCESS_INT);
3138
    /* NIP cannot be restored if the memory exception comes from an helper */
3139
    gen_update_nip(ctx, ctx->nip - 4);
3140
    t0 = tcg_temp_new();
A
aurel32 已提交
3141
    gen_addr_register(ctx, t0);
3142 3143 3144 3145 3146 3147
    t1 = tcg_const_i32(nb);
    t2 = tcg_const_i32(start);
    gen_helper_lsw(t0, t1, t2);
    tcg_temp_free(t0);
    tcg_temp_free_i32(t1);
    tcg_temp_free_i32(t2);
B
bellard 已提交
3148 3149 3150
}

/* lswx */
3151
GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001, PPC_STRING)
B
bellard 已提交
3152
{
A
aurel32 已提交
3153 3154 3155
    TCGv t0;
    TCGv_i32 t1, t2, t3;
    gen_set_access_type(ctx, ACCESS_INT);
3156
    /* NIP cannot be restored if the memory exception comes from an helper */
3157
    gen_update_nip(ctx, ctx->nip - 4);
A
aurel32 已提交
3158 3159 3160 3161 3162
    t0 = tcg_temp_new();
    gen_addr_reg_index(ctx, t0);
    t1 = tcg_const_i32(rD(ctx->opcode));
    t2 = tcg_const_i32(rA(ctx->opcode));
    t3 = tcg_const_i32(rB(ctx->opcode));
3163 3164 3165 3166 3167
    gen_helper_lswx(t0, t1, t2, t3);
    tcg_temp_free(t0);
    tcg_temp_free_i32(t1);
    tcg_temp_free_i32(t2);
    tcg_temp_free_i32(t3);
B
bellard 已提交
3168 3169 3170
}

/* stswi */
3171
GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_STRING)
B
bellard 已提交
3172
{
A
aurel32 已提交
3173 3174
    TCGv t0;
    TCGv_i32 t1, t2;
B
bellard 已提交
3175
    int nb = NB(ctx->opcode);
A
aurel32 已提交
3176
    gen_set_access_type(ctx, ACCESS_INT);
3177
    /* NIP cannot be restored if the memory exception comes from an helper */
3178
    gen_update_nip(ctx, ctx->nip - 4);
A
aurel32 已提交
3179 3180
    t0 = tcg_temp_new();
    gen_addr_register(ctx, t0);
B
bellard 已提交
3181 3182
    if (nb == 0)
        nb = 32;
3183
    t1 = tcg_const_i32(nb);
A
aurel32 已提交
3184
    t2 = tcg_const_i32(rS(ctx->opcode));
3185 3186 3187 3188
    gen_helper_stsw(t0, t1, t2);
    tcg_temp_free(t0);
    tcg_temp_free_i32(t1);
    tcg_temp_free_i32(t2);
B
bellard 已提交
3189 3190 3191
}

/* stswx */
3192
GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_STRING)
B
bellard 已提交
3193
{
A
aurel32 已提交
3194 3195 3196
    TCGv t0;
    TCGv_i32 t1, t2;
    gen_set_access_type(ctx, ACCESS_INT);
3197
    /* NIP cannot be restored if the memory exception comes from an helper */
3198
    gen_update_nip(ctx, ctx->nip - 4);
A
aurel32 已提交
3199 3200 3201
    t0 = tcg_temp_new();
    gen_addr_reg_index(ctx, t0);
    t1 = tcg_temp_new_i32();
3202 3203
    tcg_gen_trunc_tl_i32(t1, cpu_xer);
    tcg_gen_andi_i32(t1, t1, 0x7F);
A
aurel32 已提交
3204
    t2 = tcg_const_i32(rS(ctx->opcode));
3205 3206 3207 3208
    gen_helper_stsw(t0, t1, t2);
    tcg_temp_free(t0);
    tcg_temp_free_i32(t1);
    tcg_temp_free_i32(t2);
B
bellard 已提交
3209 3210 3211 3212
}

/***                        Memory synchronisation                         ***/
/* eieio */
3213
GEN_HANDLER(eieio, 0x1F, 0x16, 0x1A, 0x03FFF801, PPC_MEM_EIEIO)
B
bellard 已提交
3214 3215 3216 3217
{
}

/* isync */
3218
GEN_HANDLER(isync, 0x13, 0x16, 0x04, 0x03FFF801, PPC_MEM)
B
bellard 已提交
3219
{
A
aurel32 已提交
3220
    gen_stop_exception(ctx);
B
bellard 已提交
3221 3222
}

3223
/* lwarx */
3224
GEN_HANDLER(lwarx, 0x1F, 0x14, 0x00, 0x00000001, PPC_RES)
B
bellard 已提交
3225
{
A
aurel32 已提交
3226 3227 3228 3229
    TCGv t0;
    gen_set_access_type(ctx, ACCESS_RES);
    t0 = tcg_temp_local_new();
    gen_addr_reg_index(ctx, t0);
3230
    gen_check_align(ctx, t0, 0x03);
A
aurel32 已提交
3231
    gen_qemu_ld32u(ctx, cpu_gpr[rD(ctx->opcode)], t0);
3232 3233
    tcg_gen_mov_tl(cpu_reserve, t0);
    tcg_temp_free(t0);
B
bellard 已提交
3234 3235 3236
}

/* stwcx. */
3237
GEN_HANDLER2(stwcx_, "stwcx.", 0x1F, 0x16, 0x04, 0x00000000, PPC_RES)
B
bellard 已提交
3238
{
A
aurel32 已提交
3239 3240 3241 3242 3243
    int l1;
    TCGv t0;
    gen_set_access_type(ctx, ACCESS_RES);
    t0 = tcg_temp_local_new();
    gen_addr_reg_index(ctx, t0);
3244 3245 3246 3247
    gen_check_align(ctx, t0, 0x03);
    tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_xer);
    tcg_gen_shri_i32(cpu_crf[0], cpu_crf[0], XER_SO);
    tcg_gen_andi_i32(cpu_crf[0], cpu_crf[0], 1);
A
aurel32 已提交
3248
    l1 = gen_new_label();
3249 3250
    tcg_gen_brcond_tl(TCG_COND_NE, t0, cpu_reserve, l1);
    tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 1 << CRF_EQ);
A
aurel32 已提交
3251
    gen_qemu_st32(ctx, cpu_gpr[rS(ctx->opcode)], t0);
3252 3253 3254
    gen_set_label(l1);
    tcg_gen_movi_tl(cpu_reserve, -1);
    tcg_temp_free(t0);
B
bellard 已提交
3255 3256
}

J
j_mayer 已提交
3257 3258
#if defined(TARGET_PPC64)
/* ldarx */
3259
GEN_HANDLER(ldarx, 0x1F, 0x14, 0x02, 0x00000001, PPC_64B)
J
j_mayer 已提交
3260
{
A
aurel32 已提交
3261 3262 3263 3264
    TCGv t0;
    gen_set_access_type(ctx, ACCESS_RES);
    t0 = tcg_temp_local_new();
    gen_addr_reg_index(ctx, t0);
3265
    gen_check_align(ctx, t0, 0x07);
A
aurel32 已提交
3266
    gen_qemu_ld64(ctx, cpu_gpr[rD(ctx->opcode)], t0);
3267 3268
    tcg_gen_mov_tl(cpu_reserve, t0);
    tcg_temp_free(t0);
J
j_mayer 已提交
3269 3270 3271
}

/* stdcx. */
3272
GEN_HANDLER2(stdcx_, "stdcx.", 0x1F, 0x16, 0x06, 0x00000000, PPC_64B)
J
j_mayer 已提交
3273
{
A
aurel32 已提交
3274 3275 3276 3277 3278
    int l1;
    TCGv t0;
    gen_set_access_type(ctx, ACCESS_RES);
    t0 = tcg_temp_local_new();
    gen_addr_reg_index(ctx, t0);
3279 3280 3281 3282
    gen_check_align(ctx, t0, 0x07);
    tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_xer);
    tcg_gen_shri_i32(cpu_crf[0], cpu_crf[0], XER_SO);
    tcg_gen_andi_i32(cpu_crf[0], cpu_crf[0], 1);
A
aurel32 已提交
3283
    l1 = gen_new_label();
3284 3285
    tcg_gen_brcond_tl(TCG_COND_NE, t0, cpu_reserve, l1);
    tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 1 << CRF_EQ);
A
aurel32 已提交
3286
    gen_qemu_st64(ctx, cpu_gpr[rS(ctx->opcode)], t0);
3287 3288 3289
    gen_set_label(l1);
    tcg_gen_movi_tl(cpu_reserve, -1);
    tcg_temp_free(t0);
J
j_mayer 已提交
3290 3291 3292
}
#endif /* defined(TARGET_PPC64) */

B
bellard 已提交
3293
/* sync */
3294
GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x039FF801, PPC_MEM_SYNC)
B
bellard 已提交
3295 3296 3297
{
}

3298 3299 3300
/* wait */
GEN_HANDLER(wait, 0x1F, 0x1E, 0x01, 0x03FFF801, PPC_WAIT)
{
3301 3302 3303
    TCGv_i32 t0 = tcg_temp_new_i32();
    tcg_gen_st_i32(t0, cpu_env, offsetof(CPUState, halted));
    tcg_temp_free_i32(t0);
3304
    /* Stop translation, as the CPU is supposed to sleep from now */
A
aurel32 已提交
3305
    gen_exception_err(ctx, EXCP_HLT, 1);
3306 3307
}

B
bellard 已提交
3308
/***                         Floating-point load                           ***/
3309 3310
#define GEN_LDF(name, ldop, opc, type)                                        \
GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type)                          \
B
bellard 已提交
3311
{                                                                             \
3312
    TCGv EA;                                                                  \
3313
    if (unlikely(!ctx->fpu_enabled)) {                                        \
A
aurel32 已提交
3314
        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
3315 3316
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
3317
    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
3318
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
3319 3320
    gen_addr_imm_index(ctx, EA, 0);                                           \
    gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA);                       \
3321
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
3322 3323
}

3324 3325
#define GEN_LDUF(name, ldop, opc, type)                                       \
GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type)                       \
B
bellard 已提交
3326
{                                                                             \
3327
    TCGv EA;                                                                  \
3328
    if (unlikely(!ctx->fpu_enabled)) {                                        \
A
aurel32 已提交
3329
        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
3330 3331
        return;                                                               \
    }                                                                         \
3332
    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
A
aurel32 已提交
3333
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);                   \
3334
        return;                                                               \
3335
    }                                                                         \
A
aurel32 已提交
3336
    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
3337
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
3338 3339
    gen_addr_imm_index(ctx, EA, 0);                                           \
    gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA);                       \
3340 3341
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
3342 3343
}

3344 3345
#define GEN_LDUXF(name, ldop, opc, type)                                      \
GEN_HANDLER(name##ux, 0x1F, 0x17, opc, 0x00000001, type)                      \
B
bellard 已提交
3346
{                                                                             \
3347
    TCGv EA;                                                                  \
3348
    if (unlikely(!ctx->fpu_enabled)) {                                        \
A
aurel32 已提交
3349
        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
3350 3351
        return;                                                               \
    }                                                                         \
3352
    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
A
aurel32 已提交
3353
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);                   \
3354
        return;                                                               \
3355
    }                                                                         \
A
aurel32 已提交
3356
    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
3357
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
3358 3359
    gen_addr_reg_index(ctx, EA);                                              \
    gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA);                       \
3360 3361
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
3362 3363
}

3364 3365
#define GEN_LDXF(name, ldop, opc2, opc3, type)                                \
GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type)                      \
B
bellard 已提交
3366
{                                                                             \
3367
    TCGv EA;                                                                  \
3368
    if (unlikely(!ctx->fpu_enabled)) {                                        \
A
aurel32 已提交
3369
        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
3370 3371
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
3372
    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
3373
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
3374 3375
    gen_addr_reg_index(ctx, EA);                                              \
    gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA);                       \
3376
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
3377 3378
}

3379 3380 3381 3382 3383 3384
#define GEN_LDFS(name, ldop, op, type)                                        \
GEN_LDF(name, ldop, op | 0x20, type);                                         \
GEN_LDUF(name, ldop, op | 0x21, type);                                        \
GEN_LDUXF(name, ldop, op | 0x01, type);                                       \
GEN_LDXF(name, ldop, 0x17, op | 0x00, type)

A
aurel32 已提交
3385
static always_inline void gen_qemu_ld32fs(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
3386 3387 3388
{
    TCGv t0 = tcg_temp_new();
    TCGv_i32 t1 = tcg_temp_new_i32();
A
aurel32 已提交
3389
    gen_qemu_ld32u(ctx, t0, arg2);
3390 3391 3392 3393 3394
    tcg_gen_trunc_tl_i32(t1, t0);
    tcg_temp_free(t0);
    gen_helper_float32_to_float64(arg1, t1);
    tcg_temp_free_i32(t1);
}
B
bellard 已提交
3395

3396 3397 3398 3399
 /* lfd lfdu lfdux lfdx */
GEN_LDFS(lfd, ld64, 0x12, PPC_FLOAT);
 /* lfs lfsu lfsux lfsx */
GEN_LDFS(lfs, ld32fs, 0x10, PPC_FLOAT);
B
bellard 已提交
3400 3401

/***                         Floating-point store                          ***/
3402 3403
#define GEN_STF(name, stop, opc, type)                                        \
GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type)                          \
B
bellard 已提交
3404
{                                                                             \
3405
    TCGv EA;                                                                  \
3406
    if (unlikely(!ctx->fpu_enabled)) {                                        \
A
aurel32 已提交
3407
        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
3408 3409
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
3410
    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
3411
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
3412 3413
    gen_addr_imm_index(ctx, EA, 0);                                           \
    gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA);                       \
3414
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
3415 3416
}

3417 3418
#define GEN_STUF(name, stop, opc, type)                                       \
GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type)                       \
B
bellard 已提交
3419
{                                                                             \
3420
    TCGv EA;                                                                  \
3421
    if (unlikely(!ctx->fpu_enabled)) {                                        \
A
aurel32 已提交
3422
        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
3423 3424
        return;                                                               \
    }                                                                         \
3425
    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
A
aurel32 已提交
3426
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);                   \
3427
        return;                                                               \
3428
    }                                                                         \
A
aurel32 已提交
3429
    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
3430
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
3431 3432
    gen_addr_imm_index(ctx, EA, 0);                                           \
    gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA);                       \
3433 3434
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
3435 3436
}

3437 3438
#define GEN_STUXF(name, stop, opc, type)                                      \
GEN_HANDLER(name##ux, 0x1F, 0x17, opc, 0x00000001, type)                      \
B
bellard 已提交
3439
{                                                                             \
3440
    TCGv EA;                                                                  \
3441
    if (unlikely(!ctx->fpu_enabled)) {                                        \
A
aurel32 已提交
3442
        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
3443 3444
        return;                                                               \
    }                                                                         \
3445
    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
A
aurel32 已提交
3446
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);                   \
3447
        return;                                                               \
3448
    }                                                                         \
A
aurel32 已提交
3449
    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
3450
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
3451 3452
    gen_addr_reg_index(ctx, EA);                                              \
    gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA);                       \
3453 3454
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
3455 3456
}

3457 3458
#define GEN_STXF(name, stop, opc2, opc3, type)                                \
GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type)                      \
B
bellard 已提交
3459
{                                                                             \
3460
    TCGv EA;                                                                  \
3461
    if (unlikely(!ctx->fpu_enabled)) {                                        \
A
aurel32 已提交
3462
        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
3463 3464
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
3465
    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
3466
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
3467 3468
    gen_addr_reg_index(ctx, EA);                                              \
    gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA);                       \
3469
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
3470 3471
}

3472 3473 3474 3475 3476 3477
#define GEN_STFS(name, stop, op, type)                                        \
GEN_STF(name, stop, op | 0x20, type);                                         \
GEN_STUF(name, stop, op | 0x21, type);                                        \
GEN_STUXF(name, stop, op | 0x01, type);                                       \
GEN_STXF(name, stop, 0x17, op | 0x00, type)

A
aurel32 已提交
3478
static always_inline void gen_qemu_st32fs(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
3479 3480 3481 3482 3483 3484
{
    TCGv_i32 t0 = tcg_temp_new_i32();
    TCGv t1 = tcg_temp_new();
    gen_helper_float64_to_float32(t0, arg1);
    tcg_gen_extu_i32_tl(t1, t0);
    tcg_temp_free_i32(t0);
A
aurel32 已提交
3485
    gen_qemu_st32(ctx, t1, arg2);
3486 3487
    tcg_temp_free(t1);
}
B
bellard 已提交
3488 3489

/* stfd stfdu stfdux stfdx */
3490
GEN_STFS(stfd, st64, 0x16, PPC_FLOAT);
B
bellard 已提交
3491
/* stfs stfsu stfsux stfsx */
3492
GEN_STFS(stfs, st32fs, 0x14, PPC_FLOAT);
B
bellard 已提交
3493 3494

/* Optional: */
A
aurel32 已提交
3495
static always_inline void gen_qemu_st32fiw(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
3496 3497 3498
{
    TCGv t0 = tcg_temp_new();
    tcg_gen_trunc_i64_tl(t0, arg1),
A
aurel32 已提交
3499
    gen_qemu_st32(ctx, t0, arg2);
3500 3501
    tcg_temp_free(t0);
}
B
bellard 已提交
3502
/* stfiwx */
3503
GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX);
B
bellard 已提交
3504 3505

/***                                Branch                                 ***/
3506 3507
static always_inline void gen_goto_tb (DisasContext *ctx, int n,
                                       target_ulong dest)
3508 3509 3510
{
    TranslationBlock *tb;
    tb = ctx->tb;
3511 3512 3513 3514
#if defined(TARGET_PPC64)
    if (!ctx->sf_mode)
        dest = (uint32_t) dest;
#endif
B
bellard 已提交
3515
    if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) &&
3516
        likely(!ctx->singlestep_enabled)) {
B
bellard 已提交
3517
        tcg_gen_goto_tb(n);
3518
        tcg_gen_movi_tl(cpu_nip, dest & ~3);
B
bellard 已提交
3519
        tcg_gen_exit_tb((long)tb + n);
3520
    } else {
3521
        tcg_gen_movi_tl(cpu_nip, dest & ~3);
3522 3523
        if (unlikely(ctx->singlestep_enabled)) {
            if ((ctx->singlestep_enabled &
A
aurel32 已提交
3524
                (CPU_BRANCH_STEP | CPU_SINGLE_STEP)) &&
3525 3526 3527
                ctx->exception == POWERPC_EXCP_BRANCH) {
                target_ulong tmp = ctx->nip;
                ctx->nip = dest;
A
aurel32 已提交
3528
                gen_exception(ctx, POWERPC_EXCP_TRACE);
3529 3530 3531
                ctx->nip = tmp;
            }
            if (ctx->singlestep_enabled & GDBSTUB_SINGLE_STEP) {
A
aurel32 已提交
3532
                gen_debug_exception(ctx);
3533 3534
            }
        }
B
bellard 已提交
3535
        tcg_gen_exit_tb(0);
3536
    }
B
bellard 已提交
3537 3538
}

3539
static always_inline void gen_setlr (DisasContext *ctx, target_ulong nip)
3540 3541
{
#if defined(TARGET_PPC64)
3542 3543
    if (ctx->sf_mode == 0)
        tcg_gen_movi_tl(cpu_lr, (uint32_t)nip);
3544 3545
    else
#endif
3546
        tcg_gen_movi_tl(cpu_lr, nip);
3547 3548
}

B
bellard 已提交
3549 3550 3551
/* b ba bl bla */
GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
{
3552
    target_ulong li, target;
B
bellard 已提交
3553

3554
    ctx->exception = POWERPC_EXCP_BRANCH;
B
bellard 已提交
3555
    /* sign extend LI */
3556
#if defined(TARGET_PPC64)
3557 3558 3559
    if (ctx->sf_mode)
        li = ((int64_t)LI(ctx->opcode) << 38) >> 38;
    else
3560
#endif
3561
        li = ((int32_t)LI(ctx->opcode) << 6) >> 6;
3562
    if (likely(AA(ctx->opcode) == 0))
B
bellard 已提交
3563
        target = ctx->nip + li - 4;
B
bellard 已提交
3564
    else
3565
        target = li;
3566 3567
    if (LK(ctx->opcode))
        gen_setlr(ctx, ctx->nip);
3568
    gen_goto_tb(ctx, 0, target);
B
bellard 已提交
3569 3570
}

3571 3572 3573 3574
#define BCOND_IM  0
#define BCOND_LR  1
#define BCOND_CTR 2

3575
static always_inline void gen_bcond (DisasContext *ctx, int type)
3576 3577
{
    uint32_t bo = BO(ctx->opcode);
3578 3579
    int l1 = gen_new_label();
    TCGv target;
3580

3581
    ctx->exception = POWERPC_EXCP_BRANCH;
3582
    if (type == BCOND_LR || type == BCOND_CTR) {
P
pbrook 已提交
3583
        target = tcg_temp_local_new();
3584 3585 3586 3587
        if (type == BCOND_CTR)
            tcg_gen_mov_tl(target, cpu_ctr);
        else
            tcg_gen_mov_tl(target, cpu_lr);
3588
    }
3589 3590
    if (LK(ctx->opcode))
        gen_setlr(ctx, ctx->nip);
3591 3592 3593
    l1 = gen_new_label();
    if ((bo & 0x4) == 0) {
        /* Decrement and test CTR */
P
pbrook 已提交
3594
        TCGv temp = tcg_temp_new();
3595
        if (unlikely(type == BCOND_CTR)) {
A
aurel32 已提交
3596
            gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
3597 3598 3599
            return;
        }
        tcg_gen_subi_tl(cpu_ctr, cpu_ctr, 1);
3600
#if defined(TARGET_PPC64)
3601 3602 3603
        if (!ctx->sf_mode)
            tcg_gen_ext32u_tl(temp, cpu_ctr);
        else
3604
#endif
3605 3606 3607 3608 3609
            tcg_gen_mov_tl(temp, cpu_ctr);
        if (bo & 0x2) {
            tcg_gen_brcondi_tl(TCG_COND_NE, temp, 0, l1);
        } else {
            tcg_gen_brcondi_tl(TCG_COND_EQ, temp, 0, l1);
3610
        }
P
pbrook 已提交
3611
        tcg_temp_free(temp);
3612 3613 3614 3615 3616
    }
    if ((bo & 0x10) == 0) {
        /* Test CR */
        uint32_t bi = BI(ctx->opcode);
        uint32_t mask = 1 << (3 - (bi & 0x03));
P
pbrook 已提交
3617
        TCGv_i32 temp = tcg_temp_new_i32();
3618

3619
        if (bo & 0x8) {
3620 3621
            tcg_gen_andi_i32(temp, cpu_crf[bi >> 2], mask);
            tcg_gen_brcondi_i32(TCG_COND_EQ, temp, 0, l1);
3622
        } else {
3623 3624
            tcg_gen_andi_i32(temp, cpu_crf[bi >> 2], mask);
            tcg_gen_brcondi_i32(TCG_COND_NE, temp, 0, l1);
3625
        }
P
pbrook 已提交
3626
        tcg_temp_free_i32(temp);
3627
    }
3628
    if (type == BCOND_IM) {
3629 3630 3631 3632 3633 3634
        target_ulong li = (target_long)((int16_t)(BD(ctx->opcode)));
        if (likely(AA(ctx->opcode) == 0)) {
            gen_goto_tb(ctx, 0, ctx->nip + li - 4);
        } else {
            gen_goto_tb(ctx, 0, li);
        }
B
bellard 已提交
3635
        gen_set_label(l1);
3636
        gen_goto_tb(ctx, 1, ctx->nip);
3637
    } else {
3638
#if defined(TARGET_PPC64)
3639 3640 3641 3642 3643 3644 3645 3646 3647 3648
        if (!(ctx->sf_mode))
            tcg_gen_andi_tl(cpu_nip, target, (uint32_t)~3);
        else
#endif
            tcg_gen_andi_tl(cpu_nip, target, ~3);
        tcg_gen_exit_tb(0);
        gen_set_label(l1);
#if defined(TARGET_PPC64)
        if (!(ctx->sf_mode))
            tcg_gen_movi_tl(cpu_nip, (uint32_t)ctx->nip);
3649 3650
        else
#endif
3651
            tcg_gen_movi_tl(cpu_nip, ctx->nip);
B
bellard 已提交
3652
        tcg_gen_exit_tb(0);
J
j_mayer 已提交
3653
    }
3654 3655 3656
}

GEN_HANDLER(bc, 0x10, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
3657
{
3658 3659 3660 3661
    gen_bcond(ctx, BCOND_IM);
}

GEN_HANDLER(bcctr, 0x13, 0x10, 0x10, 0x00000000, PPC_FLOW)
3662
{
3663 3664 3665 3666
    gen_bcond(ctx, BCOND_CTR);
}

GEN_HANDLER(bclr, 0x13, 0x10, 0x00, 0x00000000, PPC_FLOW)
3667
{
3668 3669
    gen_bcond(ctx, BCOND_LR);
}
B
bellard 已提交
3670 3671

/***                      Condition register logical                       ***/
3672 3673
#define GEN_CRLOGIC(name, tcg_op, opc)                                        \
GEN_HANDLER(name, 0x13, 0x01, opc, 0x00000001, PPC_INTEGER)                   \
B
bellard 已提交
3674
{                                                                             \
3675 3676
    uint8_t bitmask;                                                          \
    int sh;                                                                   \
P
pbrook 已提交
3677
    TCGv_i32 t0, t1;                                                          \
3678
    sh = (crbD(ctx->opcode) & 0x03) - (crbA(ctx->opcode) & 0x03);             \
P
pbrook 已提交
3679
    t0 = tcg_temp_new_i32();                                                  \
3680
    if (sh > 0)                                                               \
3681
        tcg_gen_shri_i32(t0, cpu_crf[crbA(ctx->opcode) >> 2], sh);            \
3682
    else if (sh < 0)                                                          \
3683
        tcg_gen_shli_i32(t0, cpu_crf[crbA(ctx->opcode) >> 2], -sh);           \
3684
    else                                                                      \
3685
        tcg_gen_mov_i32(t0, cpu_crf[crbA(ctx->opcode) >> 2]);                 \
P
pbrook 已提交
3686
    t1 = tcg_temp_new_i32();                                                  \
3687 3688
    sh = (crbD(ctx->opcode) & 0x03) - (crbB(ctx->opcode) & 0x03);             \
    if (sh > 0)                                                               \
3689
        tcg_gen_shri_i32(t1, cpu_crf[crbB(ctx->opcode) >> 2], sh);            \
3690
    else if (sh < 0)                                                          \
3691
        tcg_gen_shli_i32(t1, cpu_crf[crbB(ctx->opcode) >> 2], -sh);           \
3692
    else                                                                      \
3693 3694
        tcg_gen_mov_i32(t1, cpu_crf[crbB(ctx->opcode) >> 2]);                 \
    tcg_op(t0, t0, t1);                                                       \
3695
    bitmask = 1 << (3 - (crbD(ctx->opcode) & 0x03));                          \
3696 3697 3698
    tcg_gen_andi_i32(t0, t0, bitmask);                                        \
    tcg_gen_andi_i32(t1, cpu_crf[crbD(ctx->opcode) >> 2], ~bitmask);          \
    tcg_gen_or_i32(cpu_crf[crbD(ctx->opcode) >> 2], t0, t1);                  \
P
pbrook 已提交
3699 3700
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
B
bellard 已提交
3701 3702 3703
}

/* crand */
3704
GEN_CRLOGIC(crand, tcg_gen_and_i32, 0x08);
B
bellard 已提交
3705
/* crandc */
3706
GEN_CRLOGIC(crandc, tcg_gen_andc_i32, 0x04);
B
bellard 已提交
3707
/* creqv */
3708
GEN_CRLOGIC(creqv, tcg_gen_eqv_i32, 0x09);
B
bellard 已提交
3709
/* crnand */
3710
GEN_CRLOGIC(crnand, tcg_gen_nand_i32, 0x07);
B
bellard 已提交
3711
/* crnor */
3712
GEN_CRLOGIC(crnor, tcg_gen_nor_i32, 0x01);
B
bellard 已提交
3713
/* cror */
3714
GEN_CRLOGIC(cror, tcg_gen_or_i32, 0x0E);
B
bellard 已提交
3715
/* crorc */
3716
GEN_CRLOGIC(crorc, tcg_gen_orc_i32, 0x0D);
B
bellard 已提交
3717
/* crxor */
3718
GEN_CRLOGIC(crxor, tcg_gen_xor_i32, 0x06);
B
bellard 已提交
3719 3720 3721
/* mcrf */
GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER)
{
A
aurel32 已提交
3722
    tcg_gen_mov_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfS(ctx->opcode)]);
B
bellard 已提交
3723 3724 3725
}

/***                           System linkage                              ***/
A
aurel32 已提交
3726
/* rfi (mem_idx only) */
3727
GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW)
B
bellard 已提交
3728
{
3729
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
3730
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
3731 3732
#else
    /* Restore CPU state */
A
aurel32 已提交
3733
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
3734
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
3735
        return;
3736
    }
3737
    gen_helper_rfi();
A
aurel32 已提交
3738
    gen_sync_exception(ctx);
3739
#endif
B
bellard 已提交
3740 3741
}

J
j_mayer 已提交
3742
#if defined(TARGET_PPC64)
3743
GEN_HANDLER(rfid, 0x13, 0x12, 0x00, 0x03FF8001, PPC_64B)
J
j_mayer 已提交
3744 3745
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
3746
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
J
j_mayer 已提交
3747 3748
#else
    /* Restore CPU state */
A
aurel32 已提交
3749
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
3750
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
J
j_mayer 已提交
3751 3752
        return;
    }
3753
    gen_helper_rfid();
A
aurel32 已提交
3754
    gen_sync_exception(ctx);
J
j_mayer 已提交
3755 3756 3757
#endif
}

J
j_mayer 已提交
3758
GEN_HANDLER(hrfid, 0x13, 0x12, 0x08, 0x03FF8001, PPC_64H)
3759 3760
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
3761
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
3762 3763
#else
    /* Restore CPU state */
A
aurel32 已提交
3764
    if (unlikely(ctx->mem_idx <= 1)) {
A
aurel32 已提交
3765
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
3766 3767
        return;
    }
3768
    gen_helper_hrfid();
A
aurel32 已提交
3769
    gen_sync_exception(ctx);
3770 3771 3772 3773
#endif
}
#endif

B
bellard 已提交
3774
/* sc */
3775 3776 3777 3778 3779
#if defined(CONFIG_USER_ONLY)
#define POWERPC_SYSCALL POWERPC_EXCP_SYSCALL_USER
#else
#define POWERPC_SYSCALL POWERPC_EXCP_SYSCALL
#endif
3780
GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFF01D, PPC_FLOW)
B
bellard 已提交
3781
{
3782 3783 3784
    uint32_t lev;

    lev = (ctx->opcode >> 5) & 0x7F;
A
aurel32 已提交
3785
    gen_exception_err(ctx, POWERPC_SYSCALL, lev);
B
bellard 已提交
3786 3787 3788 3789
}

/***                                Trap                                   ***/
/* tw */
3790
GEN_HANDLER(tw, 0x1F, 0x04, 0x00, 0x00000001, PPC_FLOW)
B
bellard 已提交
3791
{
3792
    TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
3793
    /* Update the nip since this might generate a trap exception */
3794
    gen_update_nip(ctx, ctx->nip);
3795 3796
    gen_helper_tw(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], t0);
    tcg_temp_free_i32(t0);
B
bellard 已提交
3797 3798 3799 3800 3801
}

/* twi */
GEN_HANDLER(twi, 0x03, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
{
3802 3803
    TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
    TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
3804 3805
    /* Update the nip since this might generate a trap exception */
    gen_update_nip(ctx, ctx->nip);
3806 3807 3808
    gen_helper_tw(cpu_gpr[rA(ctx->opcode)], t0, t1);
    tcg_temp_free(t0);
    tcg_temp_free_i32(t1);
B
bellard 已提交
3809 3810
}

3811 3812 3813 3814
#if defined(TARGET_PPC64)
/* td */
GEN_HANDLER(td, 0x1F, 0x04, 0x02, 0x00000001, PPC_64B)
{
3815
    TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
3816 3817
    /* Update the nip since this might generate a trap exception */
    gen_update_nip(ctx, ctx->nip);
3818 3819
    gen_helper_td(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], t0);
    tcg_temp_free_i32(t0);
3820 3821 3822 3823 3824
}

/* tdi */
GEN_HANDLER(tdi, 0x02, 0xFF, 0xFF, 0x00000000, PPC_64B)
{
3825 3826
    TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
    TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
3827 3828
    /* Update the nip since this might generate a trap exception */
    gen_update_nip(ctx, ctx->nip);
3829 3830 3831
    gen_helper_td(cpu_gpr[rA(ctx->opcode)], t0, t1);
    tcg_temp_free(t0);
    tcg_temp_free_i32(t1);
3832 3833 3834
}
#endif

B
bellard 已提交
3835 3836 3837 3838
/***                          Processor control                            ***/
/* mcrxr */
GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC)
{
A
aurel32 已提交
3839 3840
    tcg_gen_trunc_tl_i32(cpu_crf[crfD(ctx->opcode)], cpu_xer);
    tcg_gen_shri_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)], XER_CA);
3841
    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_SO | 1 << XER_OV | 1 << XER_CA));
B
bellard 已提交
3842 3843
}

A
aurel32 已提交
3844
/* mfcr mfocrf */
3845
GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x00000801, PPC_MISC)
B
bellard 已提交
3846
{
3847
    uint32_t crm, crn;
3848

3849 3850
    if (likely(ctx->opcode & 0x00100000)) {
        crm = CRM(ctx->opcode);
M
malc 已提交
3851
        if (likely(crm && ((crm & (crm - 1)) == 0))) {
A
aurel32 已提交
3852
            crn = ctz32 (crm);
3853
            tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], cpu_crf[7 - crn]);
M
malc 已提交
3854 3855
            tcg_gen_shli_i32(cpu_gpr[rD(ctx->opcode)],
                             cpu_gpr[rD(ctx->opcode)], crn * 4);
3856
        }
3857
    } else {
P
pbrook 已提交
3858
        gen_helper_load_cr(cpu_gpr[rD(ctx->opcode)]);
3859
    }
B
bellard 已提交
3860 3861 3862 3863 3864
}

/* mfmsr */
GEN_HANDLER(mfmsr, 0x1F, 0x13, 0x02, 0x001FF801, PPC_MISC)
{
3865
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
3866
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
3867
#else
A
aurel32 已提交
3868
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
3869
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
3870
        return;
3871
    }
3872
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_msr);
3873
#endif
B
bellard 已提交
3874 3875
}

J
j_mayer 已提交
3876
#if 1
3877
#define SPR_NOACCESS ((void *)(-1UL))
3878 3879 3880 3881 3882 3883 3884 3885 3886
#else
static void spr_noaccess (void *opaque, int sprn)
{
    sprn = ((sprn >> 5) & 0x1F) | ((sprn & 0x1F) << 5);
    printf("ERROR: try to access SPR %d !\n", sprn);
}
#define SPR_NOACCESS (&spr_noaccess)
#endif

B
bellard 已提交
3887
/* mfspr */
3888
static always_inline void gen_op_mfspr (DisasContext *ctx)
B
bellard 已提交
3889
{
A
aurel32 已提交
3890
    void (*read_cb)(void *opaque, int gprn, int sprn);
B
bellard 已提交
3891 3892
    uint32_t sprn = SPR(ctx->opcode);

3893
#if !defined(CONFIG_USER_ONLY)
A
aurel32 已提交
3894
    if (ctx->mem_idx == 2)
3895
        read_cb = ctx->spr_cb[sprn].hea_read;
A
aurel32 已提交
3896
    else if (ctx->mem_idx)
3897 3898
        read_cb = ctx->spr_cb[sprn].oea_read;
    else
3899
#endif
3900
        read_cb = ctx->spr_cb[sprn].uea_read;
3901 3902
    if (likely(read_cb != NULL)) {
        if (likely(read_cb != SPR_NOACCESS)) {
A
aurel32 已提交
3903
            (*read_cb)(ctx, rD(ctx->opcode), sprn);
3904 3905
        } else {
            /* Privilege exception */
3906 3907 3908 3909 3910
            /* This is a hack to avoid warnings when running Linux:
             * this OS breaks the PowerPC virtualisation model,
             * allowing userland application to read the PVR
             */
            if (sprn != SPR_PVR) {
3911
                qemu_log("Trying to read privileged spr %d %03x at "
J
j_mayer 已提交
3912 3913 3914
                            ADDRX "\n", sprn, sprn, ctx->nip);
                printf("Trying to read privileged spr %d %03x at " ADDRX "\n",
                       sprn, sprn, ctx->nip);
3915
            }
A
aurel32 已提交
3916
            gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
B
bellard 已提交
3917
        }
3918 3919
    } else {
        /* Not defined */
3920
        qemu_log("Trying to read invalid spr %d %03x at "
J
j_mayer 已提交
3921 3922 3923
                    ADDRX "\n", sprn, sprn, ctx->nip);
        printf("Trying to read invalid spr %d %03x at " ADDRX "\n",
               sprn, sprn, ctx->nip);
A
aurel32 已提交
3924
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_SPR);
B
bellard 已提交
3925 3926 3927
    }
}

3928
GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC)
B
bellard 已提交
3929
{
3930
    gen_op_mfspr(ctx);
3931
}
3932 3933

/* mftb */
3934
GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_MFTB)
3935 3936
{
    gen_op_mfspr(ctx);
B
bellard 已提交
3937 3938
}

A
aurel32 已提交
3939
/* mtcrf mtocrf*/
3940
GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00000801, PPC_MISC)
B
bellard 已提交
3941
{
3942
    uint32_t crm, crn;
3943

3944
    crm = CRM(ctx->opcode);
M
malc 已提交
3945 3946 3947
    if (likely((ctx->opcode & 0x00100000))) {
        if (crm && ((crm & (crm - 1)) == 0)) {
            TCGv_i32 temp = tcg_temp_new_i32();
A
aurel32 已提交
3948
            crn = ctz32 (crm);
M
malc 已提交
3949
            tcg_gen_trunc_tl_i32(temp, cpu_gpr[rS(ctx->opcode)]);
A
aurel32 已提交
3950 3951
            tcg_gen_shri_i32(temp, temp, crn * 4);
            tcg_gen_andi_i32(cpu_crf[7 - crn], temp, 0xf);
M
malc 已提交
3952 3953
            tcg_temp_free_i32(temp);
        }
3954
    } else {
P
pbrook 已提交
3955 3956 3957
        TCGv_i32 temp = tcg_const_i32(crm);
        gen_helper_store_cr(cpu_gpr[rS(ctx->opcode)], temp);
        tcg_temp_free_i32(temp);
3958
    }
B
bellard 已提交
3959 3960 3961
}

/* mtmsr */
J
j_mayer 已提交
3962
#if defined(TARGET_PPC64)
3963
GEN_HANDLER(mtmsrd, 0x1F, 0x12, 0x05, 0x001EF801, PPC_64B)
J
j_mayer 已提交
3964 3965
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
3966
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
J
j_mayer 已提交
3967
#else
A
aurel32 已提交
3968
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
3969
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
J
j_mayer 已提交
3970 3971
        return;
    }
3972 3973
    if (ctx->opcode & 0x00010000) {
        /* Special form that does not need any synchronisation */
3974 3975 3976 3977 3978
        TCGv t0 = tcg_temp_new();
        tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)], (1 << MSR_RI) | (1 << MSR_EE));
        tcg_gen_andi_tl(cpu_msr, cpu_msr, ~((1 << MSR_RI) | (1 << MSR_EE)));
        tcg_gen_or_tl(cpu_msr, cpu_msr, t0);
        tcg_temp_free(t0);
3979
    } else {
3980 3981 3982 3983
        /* XXX: we need to update nip before the store
         *      if we enter power saving mode, we will exit the loop
         *      directly from ppc_store_msr
         */
3984
        gen_update_nip(ctx, ctx->nip);
3985
        gen_helper_store_msr(cpu_gpr[rS(ctx->opcode)]);
3986 3987
        /* Must stop the translation as machine state (may have) changed */
        /* Note that mtmsr is not always defined as context-synchronizing */
A
aurel32 已提交
3988
        gen_stop_exception(ctx);
3989
    }
J
j_mayer 已提交
3990 3991 3992 3993
#endif
}
#endif

B
bellard 已提交
3994 3995
GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC)
{
3996
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
3997
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
3998
#else
A
aurel32 已提交
3999
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
4000
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
4001
        return;
4002
    }
4003 4004
    if (ctx->opcode & 0x00010000) {
        /* Special form that does not need any synchronisation */
4005 4006 4007 4008 4009
        TCGv t0 = tcg_temp_new();
        tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)], (1 << MSR_RI) | (1 << MSR_EE));
        tcg_gen_andi_tl(cpu_msr, cpu_msr, ~((1 << MSR_RI) | (1 << MSR_EE)));
        tcg_gen_or_tl(cpu_msr, cpu_msr, t0);
        tcg_temp_free(t0);
4010
    } else {
4011 4012 4013 4014
        /* XXX: we need to update nip before the store
         *      if we enter power saving mode, we will exit the loop
         *      directly from ppc_store_msr
         */
4015
        gen_update_nip(ctx, ctx->nip);
4016
#if defined(TARGET_PPC64)
4017 4018 4019 4020 4021 4022 4023 4024 4025 4026
        if (!ctx->sf_mode) {
            TCGv t0 = tcg_temp_new();
            TCGv t1 = tcg_temp_new();
            tcg_gen_andi_tl(t0, cpu_msr, 0xFFFFFFFF00000000ULL);
            tcg_gen_ext32u_tl(t1, cpu_gpr[rS(ctx->opcode)]);
            tcg_gen_or_tl(t0, t0, t1);
            tcg_temp_free(t1);
            gen_helper_store_msr(t0);
            tcg_temp_free(t0);
        } else
4027
#endif
4028
            gen_helper_store_msr(cpu_gpr[rS(ctx->opcode)]);
4029
        /* Must stop the translation as machine state (may have) changed */
4030
        /* Note that mtmsr is not always defined as context-synchronizing */
A
aurel32 已提交
4031
        gen_stop_exception(ctx);
4032
    }
4033
#endif
B
bellard 已提交
4034 4035 4036 4037 4038
}

/* mtspr */
GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC)
{
A
aurel32 已提交
4039
    void (*write_cb)(void *opaque, int sprn, int gprn);
B
bellard 已提交
4040 4041
    uint32_t sprn = SPR(ctx->opcode);

4042
#if !defined(CONFIG_USER_ONLY)
A
aurel32 已提交
4043
    if (ctx->mem_idx == 2)
4044
        write_cb = ctx->spr_cb[sprn].hea_write;
A
aurel32 已提交
4045
    else if (ctx->mem_idx)
4046 4047
        write_cb = ctx->spr_cb[sprn].oea_write;
    else
4048
#endif
4049
        write_cb = ctx->spr_cb[sprn].uea_write;
4050 4051
    if (likely(write_cb != NULL)) {
        if (likely(write_cb != SPR_NOACCESS)) {
A
aurel32 已提交
4052
            (*write_cb)(ctx, sprn, rS(ctx->opcode));
4053 4054
        } else {
            /* Privilege exception */
4055
            qemu_log("Trying to write privileged spr %d %03x at "
J
j_mayer 已提交
4056 4057 4058
                        ADDRX "\n", sprn, sprn, ctx->nip);
            printf("Trying to write privileged spr %d %03x at " ADDRX "\n",
                   sprn, sprn, ctx->nip);
A
aurel32 已提交
4059
            gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
4060
        }
4061 4062
    } else {
        /* Not defined */
4063
        qemu_log("Trying to write invalid spr %d %03x at "
J
j_mayer 已提交
4064 4065 4066
                    ADDRX "\n", sprn, sprn, ctx->nip);
        printf("Trying to write invalid spr %d %03x at " ADDRX "\n",
               sprn, sprn, ctx->nip);
A
aurel32 已提交
4067
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_SPR);
B
bellard 已提交
4068 4069 4070 4071 4072
    }
}

/***                         Cache management                              ***/
/* dcbf */
4073
GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03C00001, PPC_CACHE)
B
bellard 已提交
4074
{
J
j_mayer 已提交
4075
    /* XXX: specification says this is treated as a load by the MMU */
A
aurel32 已提交
4076 4077 4078 4079 4080
    TCGv t0;
    gen_set_access_type(ctx, ACCESS_CACHE);
    t0 = tcg_temp_new();
    gen_addr_reg_index(ctx, t0);
    gen_qemu_ld8u(ctx, t0, t0);
4081
    tcg_temp_free(t0);
B
bellard 已提交
4082 4083 4084
}

/* dcbi (Supervisor only) */
4085
GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE)
B
bellard 已提交
4086
{
4087
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
4088
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
4089
#else
A
aurel32 已提交
4090
    TCGv EA, val;
A
aurel32 已提交
4091
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
4092
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
4093
        return;
4094
    }
P
pbrook 已提交
4095
    EA = tcg_temp_new();
A
aurel32 已提交
4096 4097
    gen_set_access_type(ctx, ACCESS_CACHE);
    gen_addr_reg_index(ctx, EA);
P
pbrook 已提交
4098
    val = tcg_temp_new();
4099
    /* XXX: specification says this should be treated as a store by the MMU */
A
aurel32 已提交
4100 4101
    gen_qemu_ld8u(ctx, val, EA);
    gen_qemu_st8(ctx, val, EA);
A
aurel32 已提交
4102 4103
    tcg_temp_free(val);
    tcg_temp_free(EA);
4104
#endif
B
bellard 已提交
4105 4106 4107
}

/* dcdst */
4108
GEN_HANDLER(dcbst, 0x1F, 0x16, 0x01, 0x03E00001, PPC_CACHE)
B
bellard 已提交
4109
{
4110
    /* XXX: specification say this is treated as a load by the MMU */
A
aurel32 已提交
4111 4112 4113 4114 4115
    TCGv t0;
    gen_set_access_type(ctx, ACCESS_CACHE);
    t0 = tcg_temp_new();
    gen_addr_reg_index(ctx, t0);
    gen_qemu_ld8u(ctx, t0, t0);
4116
    tcg_temp_free(t0);
B
bellard 已提交
4117 4118 4119
}

/* dcbt */
4120
GEN_HANDLER(dcbt, 0x1F, 0x16, 0x08, 0x02000001, PPC_CACHE)
B
bellard 已提交
4121
{
4122
    /* interpreted as no-op */
4123 4124 4125
    /* XXX: specification say this is treated as a load by the MMU
     *      but does not generate any exception
     */
B
bellard 已提交
4126 4127 4128
}

/* dcbtst */
4129
GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x02000001, PPC_CACHE)
B
bellard 已提交
4130
{
4131
    /* interpreted as no-op */
4132 4133 4134
    /* XXX: specification say this is treated as a load by the MMU
     *      but does not generate any exception
     */
B
bellard 已提交
4135 4136 4137
}

/* dcbz */
4138
GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE_DCBZ)
B
bellard 已提交
4139
{
A
aurel32 已提交
4140 4141
    TCGv t0;
    gen_set_access_type(ctx, ACCESS_CACHE);
4142 4143
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
A
aurel32 已提交
4144 4145
    t0 = tcg_temp_new();
    gen_addr_reg_index(ctx, t0);
4146 4147
    gen_helper_dcbz(t0);
    tcg_temp_free(t0);
4148 4149
}

4150
GEN_HANDLER2(dcbz_970, "dcbz", 0x1F, 0x16, 0x1F, 0x03C00001, PPC_CACHE_DCBZT)
4151
{
A
aurel32 已提交
4152 4153
    TCGv t0;
    gen_set_access_type(ctx, ACCESS_CACHE);
4154 4155
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
A
aurel32 已提交
4156 4157
    t0 = tcg_temp_new();
    gen_addr_reg_index(ctx, t0);
4158
    if (ctx->opcode & 0x00200000)
4159
        gen_helper_dcbz(t0);
4160
    else
4161 4162
        gen_helper_dcbz_970(t0);
    tcg_temp_free(t0);
B
bellard 已提交
4163 4164
}

4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191
/* dst / dstt */
GEN_HANDLER(dst, 0x1F, 0x16, 0x0A, 0x01800001, PPC_ALTIVEC)
{
    if (rA(ctx->opcode) == 0) {
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_LSWX);
    } else {
        /* interpreted as no-op */
    }
}

/* dstst /dststt */
GEN_HANDLER(dstst, 0x1F, 0x16, 0x0B, 0x02000001, PPC_ALTIVEC)
{
    if (rA(ctx->opcode) == 0) {
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_LSWX);
    } else {
        /* interpreted as no-op */
    }

}

/* dss / dssall */
GEN_HANDLER(dss, 0x1F, 0x16, 0x19, 0x019FF801, PPC_ALTIVEC)
{
    /* interpreted as no-op */
}

B
bellard 已提交
4192
/* icbi */
4193
GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_CACHE_ICBI)
B
bellard 已提交
4194
{
A
aurel32 已提交
4195 4196
    TCGv t0;
    gen_set_access_type(ctx, ACCESS_CACHE);
4197 4198
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
A
aurel32 已提交
4199 4200
    t0 = tcg_temp_new();
    gen_addr_reg_index(ctx, t0);
4201 4202
    gen_helper_icbi(t0);
    tcg_temp_free(t0);
B
bellard 已提交
4203 4204 4205 4206
}

/* Optional: */
/* dcba */
4207
GEN_HANDLER(dcba, 0x1F, 0x16, 0x17, 0x03E00001, PPC_CACHE_DCBA)
B
bellard 已提交
4208
{
4209 4210 4211 4212
    /* interpreted as no-op */
    /* XXX: specification say this is treated as a store by the MMU
     *      but does not generate any exception
     */
B
bellard 已提交
4213 4214 4215 4216 4217 4218 4219
}

/***                    Segment register manipulation                      ***/
/* Supervisor only: */
/* mfsr */
GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT)
{
4220
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
4221
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
4222
#else
4223
    TCGv t0;
A
aurel32 已提交
4224
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
4225
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
4226
        return;
4227
    }
4228 4229 4230
    t0 = tcg_const_tl(SR(ctx->opcode));
    gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], t0);
    tcg_temp_free(t0);
4231
#endif
B
bellard 已提交
4232 4233 4234
}

/* mfsrin */
4235
GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT)
B
bellard 已提交
4236
{
4237
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
4238
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
4239
#else
4240
    TCGv t0;
A
aurel32 已提交
4241
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
4242
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
4243
        return;
4244
    }
4245 4246 4247 4248 4249
    t0 = tcg_temp_new();
    tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 28);
    tcg_gen_andi_tl(t0, t0, 0xF);
    gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], t0);
    tcg_temp_free(t0);
4250
#endif
B
bellard 已提交
4251 4252 4253
}

/* mtsr */
B
bellard 已提交
4254
GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT)
B
bellard 已提交
4255
{
4256
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
4257
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
4258
#else
4259
    TCGv t0;
A
aurel32 已提交
4260
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
4261
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
4262
        return;
4263
    }
4264 4265 4266
    t0 = tcg_const_tl(SR(ctx->opcode));
    gen_helper_store_sr(t0, cpu_gpr[rS(ctx->opcode)]);
    tcg_temp_free(t0);
4267
#endif
B
bellard 已提交
4268 4269 4270
}

/* mtsrin */
4271
GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT)
B
bellard 已提交
4272
{
4273
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
4274
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
4275
#else
4276
    TCGv t0;
A
aurel32 已提交
4277
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
4278
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
4279
        return;
4280
    }
4281 4282 4283 4284 4285
    t0 = tcg_temp_new();
    tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 28);
    tcg_gen_andi_tl(t0, t0, 0xF);
    gen_helper_store_sr(t0, cpu_gpr[rD(ctx->opcode)]);
    tcg_temp_free(t0);
4286
#endif
B
bellard 已提交
4287 4288
}

4289 4290 4291
#if defined(TARGET_PPC64)
/* Specific implementation for PowerPC 64 "bridge" emulation using SLB */
/* mfsr */
4292
GEN_HANDLER2(mfsr_64b, "mfsr", 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT_64B)
4293 4294
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
4295
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
4296
#else
4297
    TCGv t0;
A
aurel32 已提交
4298
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
4299
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
4300 4301
        return;
    }
4302
    t0 = tcg_const_tl(SR(ctx->opcode));
B
blueswir1 已提交
4303
    gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], t0);
4304
    tcg_temp_free(t0);
4305 4306 4307 4308
#endif
}

/* mfsrin */
4309 4310
GEN_HANDLER2(mfsrin_64b, "mfsrin", 0x1F, 0x13, 0x14, 0x001F0001,
             PPC_SEGMENT_64B)
4311 4312
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
4313
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
4314
#else
4315
    TCGv t0;
A
aurel32 已提交
4316
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
4317
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
4318 4319
        return;
    }
4320 4321 4322
    t0 = tcg_temp_new();
    tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 28);
    tcg_gen_andi_tl(t0, t0, 0xF);
B
blueswir1 已提交
4323
    gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], t0);
4324
    tcg_temp_free(t0);
4325 4326 4327 4328
#endif
}

/* mtsr */
4329
GEN_HANDLER2(mtsr_64b, "mtsr", 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT_64B)
4330 4331
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
4332
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
4333
#else
4334
    TCGv t0;
A
aurel32 已提交
4335
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
4336
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
4337 4338
        return;
    }
4339
    t0 = tcg_const_tl(SR(ctx->opcode));
B
blueswir1 已提交
4340
    gen_helper_store_sr(t0, cpu_gpr[rS(ctx->opcode)]);
4341
    tcg_temp_free(t0);
4342 4343 4344 4345
#endif
}

/* mtsrin */
4346 4347
GEN_HANDLER2(mtsrin_64b, "mtsrin", 0x1F, 0x12, 0x07, 0x001F0001,
             PPC_SEGMENT_64B)
4348 4349
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
4350
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
4351
#else
4352
    TCGv t0;
A
aurel32 已提交
4353
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
4354
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
4355 4356
        return;
    }
4357 4358 4359
    t0 = tcg_temp_new();
    tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 28);
    tcg_gen_andi_tl(t0, t0, 0xF);
B
blueswir1 已提交
4360
    gen_helper_store_sr(t0, cpu_gpr[rS(ctx->opcode)]);
4361
    tcg_temp_free(t0);
4362 4363
#endif
}
B
blueswir1 已提交
4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378

/* slbmte */
GEN_HANDLER2(slbmte, "slbmte", 0x1F, 0x12, 0x0C, 0x00000000, PPC_SEGMENT_64B)
{
#if defined(CONFIG_USER_ONLY)
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
#else
    if (unlikely(!ctx->mem_idx)) {
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
        return;
    }
    gen_helper_store_slb(cpu_gpr[rB(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
#endif
}

4379 4380
#endif /* defined(TARGET_PPC64) */

B
bellard 已提交
4381
/***                      Lookaside buffer management                      ***/
A
aurel32 已提交
4382
/* Optional & mem_idx only: */
B
bellard 已提交
4383
/* tlbia */
4384
GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA)
B
bellard 已提交
4385
{
4386
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
4387
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
4388
#else
A
aurel32 已提交
4389
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
4390
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
4391
        return;
4392
    }
4393
    gen_helper_tlbia();
4394
#endif
B
bellard 已提交
4395 4396
}

B
blueswir1 已提交
4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410
/* tlbiel */
GEN_HANDLER(tlbiel, 0x1F, 0x12, 0x08, 0x03FF0001, PPC_MEM_TLBIE)
{
#if defined(CONFIG_USER_ONLY)
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
#else
    if (unlikely(!ctx->mem_idx)) {
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
        return;
    }
    gen_helper_tlbie(cpu_gpr[rB(ctx->opcode)]);
#endif
}

B
bellard 已提交
4411
/* tlbie */
4412
GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM_TLBIE)
B
bellard 已提交
4413
{
4414
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
4415
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
4416
#else
A
aurel32 已提交
4417
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
4418
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
4419
        return;
4420
    }
4421
#if defined(TARGET_PPC64)
4422 4423 4424 4425 4426 4427
    if (!ctx->sf_mode) {
        TCGv t0 = tcg_temp_new();
        tcg_gen_ext32u_tl(t0, cpu_gpr[rB(ctx->opcode)]);
        gen_helper_tlbie(t0);
        tcg_temp_free(t0);
    } else
4428
#endif
4429
        gen_helper_tlbie(cpu_gpr[rB(ctx->opcode)]);
4430
#endif
B
bellard 已提交
4431 4432 4433
}

/* tlbsync */
4434
GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM_TLBSYNC)
B
bellard 已提交
4435
{
4436
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
4437
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
4438
#else
A
aurel32 已提交
4439
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
4440
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
4441
        return;
4442 4443 4444 4445
    }
    /* This has no effect: it should ensure that all previous
     * tlbie have completed
     */
A
aurel32 已提交
4446
    gen_stop_exception(ctx);
4447
#endif
B
bellard 已提交
4448 4449
}

J
j_mayer 已提交
4450 4451 4452 4453 4454
#if defined(TARGET_PPC64)
/* slbia */
GEN_HANDLER(slbia, 0x1F, 0x12, 0x0F, 0x03FFFC01, PPC_SLBI)
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
4455
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
J
j_mayer 已提交
4456
#else
A
aurel32 已提交
4457
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
4458
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
J
j_mayer 已提交
4459 4460
        return;
    }
4461
    gen_helper_slbia();
J
j_mayer 已提交
4462 4463 4464 4465 4466 4467 4468
#endif
}

/* slbie */
GEN_HANDLER(slbie, 0x1F, 0x12, 0x0D, 0x03FF0001, PPC_SLBI)
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
4469
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
J
j_mayer 已提交
4470
#else
A
aurel32 已提交
4471
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
4472
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
J
j_mayer 已提交
4473 4474
        return;
    }
4475
    gen_helper_slbie(cpu_gpr[rB(ctx->opcode)]);
J
j_mayer 已提交
4476 4477 4478 4479
#endif
}
#endif

B
bellard 已提交
4480 4481
/***                              External control                         ***/
/* Optional: */
4482
/* eciwx */
B
bellard 已提交
4483 4484
GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN)
{
A
aurel32 已提交
4485
    TCGv t0;
4486
    /* Should check EAR[E] ! */
A
aurel32 已提交
4487 4488 4489
    gen_set_access_type(ctx, ACCESS_EXT);
    t0 = tcg_temp_new();
    gen_addr_reg_index(ctx, t0);
4490
    gen_check_align(ctx, t0, 0x03);
A
aurel32 已提交
4491
    gen_qemu_ld32u(ctx, cpu_gpr[rD(ctx->opcode)], t0);
4492
    tcg_temp_free(t0);
4493 4494 4495 4496 4497
}

/* ecowx */
GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN)
{
A
aurel32 已提交
4498
    TCGv t0;
4499
    /* Should check EAR[E] ! */
A
aurel32 已提交
4500 4501 4502
    gen_set_access_type(ctx, ACCESS_EXT);
    t0 = tcg_temp_new();
    gen_addr_reg_index(ctx, t0);
4503
    gen_check_align(ctx, t0, 0x03);
A
aurel32 已提交
4504
    gen_qemu_st32(ctx, cpu_gpr[rD(ctx->opcode)], t0);
4505
    tcg_temp_free(t0);
4506 4507 4508 4509 4510 4511
}

/* PowerPC 601 specific instructions */
/* abs - abs. */
GEN_HANDLER(abs, 0x1F, 0x08, 0x0B, 0x0000F800, PPC_POWER_BR)
{
4512 4513 4514 4515 4516 4517 4518 4519
    int l1 = gen_new_label();
    int l2 = gen_new_label();
    tcg_gen_brcondi_tl(TCG_COND_GE, cpu_gpr[rA(ctx->opcode)], 0, l1);
    tcg_gen_neg_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_br(l2);
    gen_set_label(l1);
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
    gen_set_label(l2);
4520
    if (unlikely(Rc(ctx->opcode) != 0))
4521
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4522 4523 4524 4525 4526
}

/* abso - abso. */
GEN_HANDLER(abso, 0x1F, 0x08, 0x1B, 0x0000F800, PPC_POWER_BR)
{
4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541
    int l1 = gen_new_label();
    int l2 = gen_new_label();
    int l3 = gen_new_label();
    /* Start with XER OV disabled, the most likely case */
    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
    tcg_gen_brcondi_tl(TCG_COND_GE, cpu_gpr[rA(ctx->opcode)], 0, l2);
    tcg_gen_brcondi_tl(TCG_COND_NE, cpu_gpr[rA(ctx->opcode)], 0x80000000, l1);
    tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
    tcg_gen_br(l2);
    gen_set_label(l1);
    tcg_gen_neg_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_br(l3);
    gen_set_label(l2);
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
    gen_set_label(l3);
4542
    if (unlikely(Rc(ctx->opcode) != 0))
4543
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4544 4545 4546
}

/* clcs */
4547
GEN_HANDLER(clcs, 0x1F, 0x10, 0x13, 0x0000F800, PPC_POWER_BR)
4548
{
4549 4550 4551
    TCGv_i32 t0 = tcg_const_i32(rA(ctx->opcode));
    gen_helper_clcs(cpu_gpr[rD(ctx->opcode)], t0);
    tcg_temp_free_i32(t0);
4552
    /* Rc=1 sets CR0 to an undefined state */
4553 4554 4555 4556 4557
}

/* div - div. */
GEN_HANDLER(div, 0x1F, 0x0B, 0x0A, 0x00000000, PPC_POWER_BR)
{
4558
    gen_helper_div(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
4559
    if (unlikely(Rc(ctx->opcode) != 0))
4560
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4561 4562 4563 4564 4565
}

/* divo - divo. */
GEN_HANDLER(divo, 0x1F, 0x0B, 0x1A, 0x00000000, PPC_POWER_BR)
{
4566
    gen_helper_divo(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
4567
    if (unlikely(Rc(ctx->opcode) != 0))
4568
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4569 4570 4571 4572 4573
}

/* divs - divs. */
GEN_HANDLER(divs, 0x1F, 0x0B, 0x0B, 0x00000000, PPC_POWER_BR)
{
4574
    gen_helper_divs(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
4575
    if (unlikely(Rc(ctx->opcode) != 0))
4576
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4577 4578 4579 4580 4581
}

/* divso - divso. */
GEN_HANDLER(divso, 0x1F, 0x0B, 0x1B, 0x00000000, PPC_POWER_BR)
{
4582
    gen_helper_divso(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
4583
    if (unlikely(Rc(ctx->opcode) != 0))
4584
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4585 4586 4587 4588 4589
}

/* doz - doz. */
GEN_HANDLER(doz, 0x1F, 0x08, 0x08, 0x00000000, PPC_POWER_BR)
{
4590 4591 4592 4593 4594 4595 4596 4597
    int l1 = gen_new_label();
    int l2 = gen_new_label();
    tcg_gen_brcond_tl(TCG_COND_GE, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], l1);
    tcg_gen_sub_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_br(l2);
    gen_set_label(l1);
    tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], 0);
    gen_set_label(l2);
4598
    if (unlikely(Rc(ctx->opcode) != 0))
4599
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4600 4601 4602 4603 4604
}

/* dozo - dozo. */
GEN_HANDLER(dozo, 0x1F, 0x08, 0x18, 0x00000000, PPC_POWER_BR)
{
4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626
    int l1 = gen_new_label();
    int l2 = gen_new_label();
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    TCGv t2 = tcg_temp_new();
    /* Start with XER OV disabled, the most likely case */
    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
    tcg_gen_brcond_tl(TCG_COND_GE, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], l1);
    tcg_gen_sub_tl(t0, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_xor_tl(t1, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_xor_tl(t2, cpu_gpr[rA(ctx->opcode)], t0);
    tcg_gen_andc_tl(t1, t1, t2);
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0);
    tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l2);
    tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
    tcg_gen_br(l2);
    gen_set_label(l1);
    tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], 0);
    gen_set_label(l2);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
    tcg_temp_free(t2);
4627
    if (unlikely(Rc(ctx->opcode) != 0))
4628
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4629 4630 4631 4632 4633
}

/* dozi */
GEN_HANDLER(dozi, 0x09, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR)
{
4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644
    target_long simm = SIMM(ctx->opcode);
    int l1 = gen_new_label();
    int l2 = gen_new_label();
    tcg_gen_brcondi_tl(TCG_COND_LT, cpu_gpr[rA(ctx->opcode)], simm, l1);
    tcg_gen_subfi_tl(cpu_gpr[rD(ctx->opcode)], simm, cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_br(l2);
    gen_set_label(l1);
    tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], 0);
    gen_set_label(l2);
    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4645 4646 4647 4648 4649
}

/* lscbx - lscbx. */
GEN_HANDLER(lscbx, 0x1F, 0x15, 0x08, 0x00000000, PPC_POWER_BR)
{
4650 4651 4652 4653
    TCGv t0 = tcg_temp_new();
    TCGv_i32 t1 = tcg_const_i32(rD(ctx->opcode));
    TCGv_i32 t2 = tcg_const_i32(rA(ctx->opcode));
    TCGv_i32 t3 = tcg_const_i32(rB(ctx->opcode));
4654

A
aurel32 已提交
4655
    gen_addr_reg_index(ctx, t0);
4656
    /* NIP cannot be restored if the memory exception comes from an helper */
4657
    gen_update_nip(ctx, ctx->nip - 4);
4658 4659 4660 4661
    gen_helper_lscbx(t0, t0, t1, t2, t3);
    tcg_temp_free_i32(t1);
    tcg_temp_free_i32(t2);
    tcg_temp_free_i32(t3);
A
aurel32 已提交
4662
    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~0x7F);
4663
    tcg_gen_or_tl(cpu_xer, cpu_xer, t0);
4664
    if (unlikely(Rc(ctx->opcode) != 0))
4665 4666
        gen_set_Rc0(ctx, t0);
    tcg_temp_free(t0);
4667 4668 4669 4670 4671
}

/* maskg - maskg. */
GEN_HANDLER(maskg, 0x1F, 0x1D, 0x00, 0x00000000, PPC_POWER_BR)
{
4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690
    int l1 = gen_new_label();
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    TCGv t2 = tcg_temp_new();
    TCGv t3 = tcg_temp_new();
    tcg_gen_movi_tl(t3, 0xFFFFFFFF);
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1F);
    tcg_gen_andi_tl(t1, cpu_gpr[rS(ctx->opcode)], 0x1F);
    tcg_gen_addi_tl(t2, t0, 1);
    tcg_gen_shr_tl(t2, t3, t2);
    tcg_gen_shr_tl(t3, t3, t1);
    tcg_gen_xor_tl(cpu_gpr[rA(ctx->opcode)], t2, t3);
    tcg_gen_brcond_tl(TCG_COND_GE, t0, t1, l1);
    tcg_gen_neg_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
    gen_set_label(l1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
    tcg_temp_free(t2);
    tcg_temp_free(t3);
4691
    if (unlikely(Rc(ctx->opcode) != 0))
4692
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4693 4694 4695 4696 4697
}

/* maskir - maskir. */
GEN_HANDLER(maskir, 0x1F, 0x1D, 0x10, 0x00000000, PPC_POWER_BR)
{
4698 4699 4700 4701 4702 4703 4704
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    tcg_gen_and_tl(t0, cpu_gpr[rS(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
    tcg_gen_andc_tl(t1, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
    tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
4705
    if (unlikely(Rc(ctx->opcode) != 0))
4706
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4707 4708 4709 4710 4711
}

/* mul - mul. */
GEN_HANDLER(mul, 0x1F, 0x0B, 0x03, 0x00000000, PPC_POWER_BR)
{
4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724
    TCGv_i64 t0 = tcg_temp_new_i64();
    TCGv_i64 t1 = tcg_temp_new_i64();
    TCGv t2 = tcg_temp_new();
    tcg_gen_extu_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_extu_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]);
    tcg_gen_mul_i64(t0, t0, t1);
    tcg_gen_trunc_i64_tl(t2, t0);
    gen_store_spr(SPR_MQ, t2);
    tcg_gen_shri_i64(t1, t0, 32);
    tcg_gen_trunc_i64_tl(cpu_gpr[rD(ctx->opcode)], t1);
    tcg_temp_free_i64(t0);
    tcg_temp_free_i64(t1);
    tcg_temp_free(t2);
4725
    if (unlikely(Rc(ctx->opcode) != 0))
4726
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4727 4728 4729 4730 4731
}

/* mulo - mulo. */
GEN_HANDLER(mulo, 0x1F, 0x0B, 0x13, 0x00000000, PPC_POWER_BR)
{
4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751
    int l1 = gen_new_label();
    TCGv_i64 t0 = tcg_temp_new_i64();
    TCGv_i64 t1 = tcg_temp_new_i64();
    TCGv t2 = tcg_temp_new();
    /* Start with XER OV disabled, the most likely case */
    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
    tcg_gen_extu_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_extu_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]);
    tcg_gen_mul_i64(t0, t0, t1);
    tcg_gen_trunc_i64_tl(t2, t0);
    gen_store_spr(SPR_MQ, t2);
    tcg_gen_shri_i64(t1, t0, 32);
    tcg_gen_trunc_i64_tl(cpu_gpr[rD(ctx->opcode)], t1);
    tcg_gen_ext32s_i64(t1, t0);
    tcg_gen_brcond_i64(TCG_COND_EQ, t0, t1, l1);
    tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
    gen_set_label(l1);
    tcg_temp_free_i64(t0);
    tcg_temp_free_i64(t1);
    tcg_temp_free(t2);
4752
    if (unlikely(Rc(ctx->opcode) != 0))
4753
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4754 4755 4756 4757 4758
}

/* nabs - nabs. */
GEN_HANDLER(nabs, 0x1F, 0x08, 0x0F, 0x00000000, PPC_POWER_BR)
{
4759 4760 4761 4762 4763 4764 4765 4766
    int l1 = gen_new_label();
    int l2 = gen_new_label();
    tcg_gen_brcondi_tl(TCG_COND_GT, cpu_gpr[rA(ctx->opcode)], 0, l1);
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_br(l2);
    gen_set_label(l1);
    tcg_gen_neg_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
    gen_set_label(l2);
4767
    if (unlikely(Rc(ctx->opcode) != 0))
4768
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4769 4770 4771 4772 4773
}

/* nabso - nabso. */
GEN_HANDLER(nabso, 0x1F, 0x08, 0x1F, 0x00000000, PPC_POWER_BR)
{
4774 4775 4776 4777 4778 4779 4780 4781 4782 4783
    int l1 = gen_new_label();
    int l2 = gen_new_label();
    tcg_gen_brcondi_tl(TCG_COND_GT, cpu_gpr[rA(ctx->opcode)], 0, l1);
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_br(l2);
    gen_set_label(l1);
    tcg_gen_neg_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
    gen_set_label(l2);
    /* nabs never overflows */
    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
4784
    if (unlikely(Rc(ctx->opcode) != 0))
4785
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4786 4787 4788 4789 4790
}

/* rlmi - rlmi. */
GEN_HANDLER(rlmi, 0x16, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR)
{
4791 4792 4793 4794 4795 4796 4797 4798 4799
    uint32_t mb = MB(ctx->opcode);
    uint32_t me = ME(ctx->opcode);
    TCGv t0 = tcg_temp_new();
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1F);
    tcg_gen_rotl_tl(t0, cpu_gpr[rS(ctx->opcode)], t0);
    tcg_gen_andi_tl(t0, t0, MASK(mb, me));
    tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~MASK(mb, me));
    tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], t0);
    tcg_temp_free(t0);
4800
    if (unlikely(Rc(ctx->opcode) != 0))
4801
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4802 4803 4804 4805 4806
}

/* rrib - rrib. */
GEN_HANDLER(rrib, 0x1F, 0x19, 0x10, 0x00000000, PPC_POWER_BR)
{
4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1F);
    tcg_gen_movi_tl(t1, 0x80000000);
    tcg_gen_shr_tl(t1, t1, t0);
    tcg_gen_shr_tl(t0, cpu_gpr[rS(ctx->opcode)], t0);
    tcg_gen_and_tl(t0, t0, t1);
    tcg_gen_andc_tl(t1, cpu_gpr[rA(ctx->opcode)], t1);
    tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
4818
    if (unlikely(Rc(ctx->opcode) != 0))
4819
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4820 4821 4822 4823 4824
}

/* sle - sle. */
GEN_HANDLER(sle, 0x1F, 0x19, 0x04, 0x00000000, PPC_POWER_BR)
{
4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x1F);
    tcg_gen_shl_tl(t0, cpu_gpr[rS(ctx->opcode)], t1);
    tcg_gen_subfi_tl(t1, 32, t1);
    tcg_gen_shr_tl(t1, cpu_gpr[rS(ctx->opcode)], t1);
    tcg_gen_or_tl(t1, t0, t1);
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
    gen_store_spr(SPR_MQ, t1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
4836
    if (unlikely(Rc(ctx->opcode) != 0))
4837
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4838 4839 4840 4841 4842
}

/* sleq - sleq. */
GEN_HANDLER(sleq, 0x1F, 0x19, 0x06, 0x00000000, PPC_POWER_BR)
{
4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    TCGv t2 = tcg_temp_new();
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1F);
    tcg_gen_movi_tl(t2, 0xFFFFFFFF);
    tcg_gen_shl_tl(t2, t2, t0);
    tcg_gen_rotl_tl(t0, cpu_gpr[rS(ctx->opcode)], t0);
    gen_load_spr(t1, SPR_MQ);
    gen_store_spr(SPR_MQ, t0);
    tcg_gen_and_tl(t0, t0, t2);
    tcg_gen_andc_tl(t1, t1, t2);
    tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
    tcg_temp_free(t2);
4858
    if (unlikely(Rc(ctx->opcode) != 0))
4859
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4860 4861 4862 4863 4864
}

/* sliq - sliq. */
GEN_HANDLER(sliq, 0x1F, 0x18, 0x05, 0x00000000, PPC_POWER_BR)
{
4865 4866 4867 4868 4869 4870 4871 4872 4873 4874
    int sh = SH(ctx->opcode);
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    tcg_gen_shli_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
    tcg_gen_shri_tl(t1, cpu_gpr[rS(ctx->opcode)], 32 - sh);
    tcg_gen_or_tl(t1, t0, t1);
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
    gen_store_spr(SPR_MQ, t1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
4875
    if (unlikely(Rc(ctx->opcode) != 0))
4876
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4877 4878 4879 4880 4881
}

/* slliq - slliq. */
GEN_HANDLER(slliq, 0x1F, 0x18, 0x07, 0x00000000, PPC_POWER_BR)
{
4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892
    int sh = SH(ctx->opcode);
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    tcg_gen_rotli_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
    gen_load_spr(t1, SPR_MQ);
    gen_store_spr(SPR_MQ, t0);
    tcg_gen_andi_tl(t0, t0,  (0xFFFFFFFFU << sh));
    tcg_gen_andi_tl(t1, t1, ~(0xFFFFFFFFU << sh));
    tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
4893
    if (unlikely(Rc(ctx->opcode) != 0))
4894
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4895 4896 4897 4898 4899
}

/* sllq - sllq. */
GEN_HANDLER(sllq, 0x1F, 0x18, 0x06, 0x00000000, PPC_POWER_BR)
{
4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921
    int l1 = gen_new_label();
    int l2 = gen_new_label();
    TCGv t0 = tcg_temp_local_new();
    TCGv t1 = tcg_temp_local_new();
    TCGv t2 = tcg_temp_local_new();
    tcg_gen_andi_tl(t2, cpu_gpr[rB(ctx->opcode)], 0x1F);
    tcg_gen_movi_tl(t1, 0xFFFFFFFF);
    tcg_gen_shl_tl(t1, t1, t2);
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x20);
    tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
    gen_load_spr(t0, SPR_MQ);
    tcg_gen_and_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
    tcg_gen_br(l2);
    gen_set_label(l1);
    tcg_gen_shl_tl(t0, cpu_gpr[rS(ctx->opcode)], t2);
    gen_load_spr(t2, SPR_MQ);
    tcg_gen_andc_tl(t1, t2, t1);
    tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
    gen_set_label(l2);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
    tcg_temp_free(t2);
4922
    if (unlikely(Rc(ctx->opcode) != 0))
4923
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4924 4925 4926 4927 4928
}

/* slq - slq. */
GEN_HANDLER(slq, 0x1F, 0x18, 0x04, 0x00000000, PPC_POWER_BR)
{
4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944
    int l1 = gen_new_label();
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x1F);
    tcg_gen_shl_tl(t0, cpu_gpr[rS(ctx->opcode)], t1);
    tcg_gen_subfi_tl(t1, 32, t1);
    tcg_gen_shr_tl(t1, cpu_gpr[rS(ctx->opcode)], t1);
    tcg_gen_or_tl(t1, t0, t1);
    gen_store_spr(SPR_MQ, t1);
    tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x20);
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
    tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1);
    tcg_gen_movi_tl(cpu_gpr[rA(ctx->opcode)], 0);
    gen_set_label(l1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
4945
    if (unlikely(Rc(ctx->opcode) != 0))
4946
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4947 4948
}

4949
/* sraiq - sraiq. */
4950 4951
GEN_HANDLER(sraiq, 0x1F, 0x18, 0x1D, 0x00000000, PPC_POWER_BR)
{
4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967
    int sh = SH(ctx->opcode);
    int l1 = gen_new_label();
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
    tcg_gen_shli_tl(t1, cpu_gpr[rS(ctx->opcode)], 32 - sh);
    tcg_gen_or_tl(t0, t0, t1);
    gen_store_spr(SPR_MQ, t0);
    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
    tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1);
    tcg_gen_brcondi_tl(TCG_COND_GE, cpu_gpr[rS(ctx->opcode)], 0, l1);
    tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_CA));
    gen_set_label(l1);
    tcg_gen_sari_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], sh);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
4968
    if (unlikely(Rc(ctx->opcode) != 0))
4969
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4970 4971 4972 4973 4974
}

/* sraq - sraq. */
GEN_HANDLER(sraq, 0x1F, 0x18, 0x1C, 0x00000000, PPC_POWER_BR)
{
4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000
    int l1 = gen_new_label();
    int l2 = gen_new_label();
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_local_new();
    TCGv t2 = tcg_temp_local_new();
    tcg_gen_andi_tl(t2, cpu_gpr[rB(ctx->opcode)], 0x1F);
    tcg_gen_shr_tl(t0, cpu_gpr[rS(ctx->opcode)], t2);
    tcg_gen_sar_tl(t1, cpu_gpr[rS(ctx->opcode)], t2);
    tcg_gen_subfi_tl(t2, 32, t2);
    tcg_gen_shl_tl(t2, cpu_gpr[rS(ctx->opcode)], t2);
    tcg_gen_or_tl(t0, t0, t2);
    gen_store_spr(SPR_MQ, t0);
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x20);
    tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, l1);
    tcg_gen_mov_tl(t2, cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_sari_tl(t1, cpu_gpr[rS(ctx->opcode)], 31);
    gen_set_label(l1);
    tcg_temp_free(t0);
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t1);
    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
    tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l2);
    tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, l2);
    tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_CA));
    gen_set_label(l2);
    tcg_temp_free(t1);
    tcg_temp_free(t2);
5001
    if (unlikely(Rc(ctx->opcode) != 0))
5002
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
5003 5004 5005 5006 5007
}

/* sre - sre. */
GEN_HANDLER(sre, 0x1F, 0x19, 0x14, 0x00000000, PPC_POWER_BR)
{
5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x1F);
    tcg_gen_shr_tl(t0, cpu_gpr[rS(ctx->opcode)], t1);
    tcg_gen_subfi_tl(t1, 32, t1);
    tcg_gen_shl_tl(t1, cpu_gpr[rS(ctx->opcode)], t1);
    tcg_gen_or_tl(t1, t0, t1);
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
    gen_store_spr(SPR_MQ, t1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
5019
    if (unlikely(Rc(ctx->opcode) != 0))
5020
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
5021 5022 5023 5024 5025
}

/* srea - srea. */
GEN_HANDLER(srea, 0x1F, 0x19, 0x1C, 0x00000000, PPC_POWER_BR)
{
5026 5027 5028 5029 5030 5031 5032 5033
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x1F);
    tcg_gen_rotr_tl(t0, cpu_gpr[rS(ctx->opcode)], t1);
    gen_store_spr(SPR_MQ, t0);
    tcg_gen_sar_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], t1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
5034
    if (unlikely(Rc(ctx->opcode) != 0))
5035
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
5036 5037 5038 5039 5040
}

/* sreq */
GEN_HANDLER(sreq, 0x1F, 0x19, 0x16, 0x00000000, PPC_POWER_BR)
{
5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    TCGv t2 = tcg_temp_new();
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1F);
    tcg_gen_movi_tl(t1, 0xFFFFFFFF);
    tcg_gen_shr_tl(t1, t1, t0);
    tcg_gen_rotr_tl(t0, cpu_gpr[rS(ctx->opcode)], t0);
    gen_load_spr(t2, SPR_MQ);
    gen_store_spr(SPR_MQ, t0);
    tcg_gen_and_tl(t0, t0, t1);
    tcg_gen_andc_tl(t2, t2, t1);
    tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t2);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
    tcg_temp_free(t2);
5056
    if (unlikely(Rc(ctx->opcode) != 0))
5057
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
5058 5059 5060 5061 5062
}

/* sriq */
GEN_HANDLER(sriq, 0x1F, 0x18, 0x15, 0x00000000, PPC_POWER_BR)
{
5063 5064 5065 5066 5067 5068 5069 5070 5071 5072
    int sh = SH(ctx->opcode);
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
    tcg_gen_shli_tl(t1, cpu_gpr[rS(ctx->opcode)], 32 - sh);
    tcg_gen_or_tl(t1, t0, t1);
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
    gen_store_spr(SPR_MQ, t1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
5073
    if (unlikely(Rc(ctx->opcode) != 0))
5074
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
5075 5076 5077 5078 5079
}

/* srliq */
GEN_HANDLER(srliq, 0x1F, 0x18, 0x17, 0x00000000, PPC_POWER_BR)
{
5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090
    int sh = SH(ctx->opcode);
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    tcg_gen_rotri_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
    gen_load_spr(t1, SPR_MQ);
    gen_store_spr(SPR_MQ, t0);
    tcg_gen_andi_tl(t0, t0,  (0xFFFFFFFFU >> sh));
    tcg_gen_andi_tl(t1, t1, ~(0xFFFFFFFFU >> sh));
    tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
5091
    if (unlikely(Rc(ctx->opcode) != 0))
5092
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
5093 5094 5095 5096 5097
}

/* srlq */
GEN_HANDLER(srlq, 0x1F, 0x18, 0x16, 0x00000000, PPC_POWER_BR)
{
5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120
    int l1 = gen_new_label();
    int l2 = gen_new_label();
    TCGv t0 = tcg_temp_local_new();
    TCGv t1 = tcg_temp_local_new();
    TCGv t2 = tcg_temp_local_new();
    tcg_gen_andi_tl(t2, cpu_gpr[rB(ctx->opcode)], 0x1F);
    tcg_gen_movi_tl(t1, 0xFFFFFFFF);
    tcg_gen_shr_tl(t2, t1, t2);
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x20);
    tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
    gen_load_spr(t0, SPR_MQ);
    tcg_gen_and_tl(cpu_gpr[rA(ctx->opcode)], t0, t2);
    tcg_gen_br(l2);
    gen_set_label(l1);
    tcg_gen_shr_tl(t0, cpu_gpr[rS(ctx->opcode)], t2);
    tcg_gen_and_tl(t0, t0, t2);
    gen_load_spr(t1, SPR_MQ);
    tcg_gen_andc_tl(t1, t1, t2);
    tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
    gen_set_label(l2);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
    tcg_temp_free(t2);
5121
    if (unlikely(Rc(ctx->opcode) != 0))
5122
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
5123 5124 5125 5126 5127
}

/* srq */
GEN_HANDLER(srq, 0x1F, 0x18, 0x14, 0x00000000, PPC_POWER_BR)
{
5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143
    int l1 = gen_new_label();
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x1F);
    tcg_gen_shr_tl(t0, cpu_gpr[rS(ctx->opcode)], t1);
    tcg_gen_subfi_tl(t1, 32, t1);
    tcg_gen_shl_tl(t1, cpu_gpr[rS(ctx->opcode)], t1);
    tcg_gen_or_tl(t1, t0, t1);
    gen_store_spr(SPR_MQ, t1);
    tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x20);
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
    tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
    tcg_gen_movi_tl(cpu_gpr[rA(ctx->opcode)], 0);
    gen_set_label(l1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
5144
    if (unlikely(Rc(ctx->opcode) != 0))
5145
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
5146 5147 5148 5149 5150 5151 5152
}

/* PowerPC 602 specific instructions */
/* dsa  */
GEN_HANDLER(dsa, 0x1F, 0x14, 0x13, 0x03FFF801, PPC_602_SPEC)
{
    /* XXX: TODO */
A
aurel32 已提交
5153
    gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
5154 5155 5156 5157 5158 5159
}

/* esa */
GEN_HANDLER(esa, 0x1F, 0x14, 0x12, 0x03FFF801, PPC_602_SPEC)
{
    /* XXX: TODO */
A
aurel32 已提交
5160
    gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
5161 5162 5163 5164 5165 5166
}

/* mfrom */
GEN_HANDLER(mfrom, 0x1F, 0x09, 0x08, 0x03E0F801, PPC_602_SPEC)
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5167
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5168
#else
A
aurel32 已提交
5169
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5170
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5171 5172
        return;
    }
5173
    gen_helper_602_mfrom(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
5174 5175 5176 5177 5178
#endif
}

/* 602 - 603 - G2 TLB management */
/* tlbld */
5179
GEN_HANDLER2(tlbld_6xx, "tlbld", 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB)
5180 5181
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5182
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5183
#else
A
aurel32 已提交
5184
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5185
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5186 5187
        return;
    }
5188
    gen_helper_6xx_tlbd(cpu_gpr[rB(ctx->opcode)]);
5189 5190 5191 5192
#endif
}

/* tlbli */
5193
GEN_HANDLER2(tlbli_6xx, "tlbli", 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB)
5194 5195
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5196
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5197
#else
A
aurel32 已提交
5198
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5199
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5200 5201
        return;
    }
5202
    gen_helper_6xx_tlbi(cpu_gpr[rB(ctx->opcode)]);
5203 5204 5205
#endif
}

5206 5207
/* 74xx TLB management */
/* tlbld */
5208
GEN_HANDLER2(tlbld_74xx, "tlbld", 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_74xx_TLB)
5209 5210
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5211
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5212
#else
A
aurel32 已提交
5213
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5214
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5215 5216
        return;
    }
5217
    gen_helper_74xx_tlbd(cpu_gpr[rB(ctx->opcode)]);
5218 5219 5220 5221
#endif
}

/* tlbli */
5222
GEN_HANDLER2(tlbli_74xx, "tlbli", 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_74xx_TLB)
5223 5224
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5225
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5226
#else
A
aurel32 已提交
5227
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5228
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5229 5230
        return;
    }
5231
    gen_helper_74xx_tlbi(cpu_gpr[rB(ctx->opcode)]);
5232 5233 5234
#endif
}

5235 5236 5237 5238 5239 5240 5241 5242 5243 5244
/* POWER instructions not in PowerPC 601 */
/* clf */
GEN_HANDLER(clf, 0x1F, 0x16, 0x03, 0x03E00000, PPC_POWER)
{
    /* Cache line flush: implemented as no-op */
}

/* cli */
GEN_HANDLER(cli, 0x1F, 0x16, 0x0F, 0x03E00000, PPC_POWER)
{
B
blueswir1 已提交
5245
    /* Cache line invalidate: privileged and treated as no-op */
5246
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5247
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5248
#else
A
aurel32 已提交
5249
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5250
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264
        return;
    }
#endif
}

/* dclst */
GEN_HANDLER(dclst, 0x1F, 0x16, 0x13, 0x03E00000, PPC_POWER)
{
    /* Data cache line store: treated as no-op */
}

GEN_HANDLER(mfsri, 0x1F, 0x13, 0x13, 0x00000001, PPC_POWER)
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5265
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5266
#else
5267 5268 5269
    int ra = rA(ctx->opcode);
    int rd = rD(ctx->opcode);
    TCGv t0;
A
aurel32 已提交
5270
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5271
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5272 5273
        return;
    }
5274
    t0 = tcg_temp_new();
A
aurel32 已提交
5275
    gen_addr_reg_index(ctx, t0);
5276 5277 5278 5279
    tcg_gen_shri_tl(t0, t0, 28);
    tcg_gen_andi_tl(t0, t0, 0xF);
    gen_helper_load_sr(cpu_gpr[rd], t0);
    tcg_temp_free(t0);
5280
    if (ra != 0 && ra != rd)
5281
        tcg_gen_mov_tl(cpu_gpr[ra], cpu_gpr[rd]);
5282 5283 5284 5285 5286 5287
#endif
}

GEN_HANDLER(rac, 0x1F, 0x12, 0x19, 0x00000001, PPC_POWER)
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5288
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5289
#else
5290
    TCGv t0;
A
aurel32 已提交
5291
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5292
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5293 5294
        return;
    }
5295
    t0 = tcg_temp_new();
A
aurel32 已提交
5296
    gen_addr_reg_index(ctx, t0);
5297 5298
    gen_helper_rac(cpu_gpr[rD(ctx->opcode)], t0);
    tcg_temp_free(t0);
5299 5300 5301 5302 5303 5304
#endif
}

GEN_HANDLER(rfsvc, 0x13, 0x12, 0x02, 0x03FFF0001, PPC_POWER)
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5305
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5306
#else
A
aurel32 已提交
5307
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5308
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5309 5310
        return;
    }
5311
    gen_helper_rfsvc();
A
aurel32 已提交
5312
    gen_sync_exception(ctx);
5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323
#endif
}

/* svc is not implemented for now */

/* POWER2 specific instructions */
/* Quad manipulation (load/store two floats at a time) */

/* lfq */
GEN_HANDLER(lfq, 0x38, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
{
5324
    int rd = rD(ctx->opcode);
A
aurel32 已提交
5325 5326 5327 5328 5329 5330 5331
    TCGv t0;
    gen_set_access_type(ctx, ACCESS_FLOAT);
    t0 = tcg_temp_new();
    gen_addr_imm_index(ctx, t0, 0);
    gen_qemu_ld64(ctx, cpu_fpr[rd], t0);
    gen_addr_add(ctx, t0, t0, 8);
    gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t0);
5332
    tcg_temp_free(t0);
5333 5334 5335 5336 5337 5338
}

/* lfqu */
GEN_HANDLER(lfqu, 0x39, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
{
    int ra = rA(ctx->opcode);
5339
    int rd = rD(ctx->opcode);
A
aurel32 已提交
5340 5341 5342 5343 5344 5345 5346 5347
    TCGv t0, t1;
    gen_set_access_type(ctx, ACCESS_FLOAT);
    t0 = tcg_temp_new();
    t1 = tcg_temp_new();
    gen_addr_imm_index(ctx, t0, 0);
    gen_qemu_ld64(ctx, cpu_fpr[rd], t0);
    gen_addr_add(ctx, t1, t0, 8);
    gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t1);
5348
    if (ra != 0)
5349 5350 5351
        tcg_gen_mov_tl(cpu_gpr[ra], t0);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
5352 5353 5354 5355 5356 5357
}

/* lfqux */
GEN_HANDLER(lfqux, 0x1F, 0x17, 0x19, 0x00000001, PPC_POWER2)
{
    int ra = rA(ctx->opcode);
5358
    int rd = rD(ctx->opcode);
A
aurel32 已提交
5359 5360 5361 5362 5363 5364 5365 5366 5367
    gen_set_access_type(ctx, ACCESS_FLOAT);
    TCGv t0, t1;
    t0 = tcg_temp_new();
    gen_addr_reg_index(ctx, t0);
    gen_qemu_ld64(ctx, cpu_fpr[rd], t0);
    t1 = tcg_temp_new();
    gen_addr_add(ctx, t1, t0, 8);
    gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t1);
    tcg_temp_free(t1);
5368
    if (ra != 0)
5369 5370
        tcg_gen_mov_tl(cpu_gpr[ra], t0);
    tcg_temp_free(t0);
5371 5372 5373 5374 5375
}

/* lfqx */
GEN_HANDLER(lfqx, 0x1F, 0x17, 0x18, 0x00000001, PPC_POWER2)
{
5376
    int rd = rD(ctx->opcode);
A
aurel32 已提交
5377 5378 5379 5380 5381 5382 5383
    TCGv t0;
    gen_set_access_type(ctx, ACCESS_FLOAT);
    t0 = tcg_temp_new();
    gen_addr_reg_index(ctx, t0);
    gen_qemu_ld64(ctx, cpu_fpr[rd], t0);
    gen_addr_add(ctx, t0, t0, 8);
    gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t0);
5384
    tcg_temp_free(t0);
5385 5386 5387 5388 5389
}

/* stfq */
GEN_HANDLER(stfq, 0x3C, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
{
5390
    int rd = rD(ctx->opcode);
A
aurel32 已提交
5391 5392 5393 5394 5395 5396 5397
    TCGv t0;
    gen_set_access_type(ctx, ACCESS_FLOAT);
    t0 = tcg_temp_new();
    gen_addr_imm_index(ctx, t0, 0);
    gen_qemu_st64(ctx, cpu_fpr[rd], t0);
    gen_addr_add(ctx, t0, t0, 8);
    gen_qemu_st64(ctx, cpu_fpr[(rd + 1) % 32], t0);
5398
    tcg_temp_free(t0);
5399 5400 5401 5402 5403 5404
}

/* stfqu */
GEN_HANDLER(stfqu, 0x3D, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
{
    int ra = rA(ctx->opcode);
5405
    int rd = rD(ctx->opcode);
A
aurel32 已提交
5406 5407 5408 5409 5410 5411 5412 5413 5414
    TCGv t0, t1;
    gen_set_access_type(ctx, ACCESS_FLOAT);
    t0 = tcg_temp_new();
    gen_addr_imm_index(ctx, t0, 0);
    gen_qemu_st64(ctx, cpu_fpr[rd], t0);
    t1 = tcg_temp_new();
    gen_addr_add(ctx, t1, t0, 8);
    gen_qemu_st64(ctx, cpu_fpr[(rd + 1) % 32], t1);
    tcg_temp_free(t1);
5415
    if (ra != 0)
5416 5417
        tcg_gen_mov_tl(cpu_gpr[ra], t0);
    tcg_temp_free(t0);
5418 5419 5420 5421 5422 5423
}

/* stfqux */
GEN_HANDLER(stfqux, 0x1F, 0x17, 0x1D, 0x00000001, PPC_POWER2)
{
    int ra = rA(ctx->opcode);
5424
    int rd = rD(ctx->opcode);
A
aurel32 已提交
5425 5426 5427 5428 5429 5430 5431 5432 5433
    TCGv t0, t1;
    gen_set_access_type(ctx, ACCESS_FLOAT);
    t0 = tcg_temp_new();
    gen_addr_reg_index(ctx, t0);
    gen_qemu_st64(ctx, cpu_fpr[rd], t0);
    t1 = tcg_temp_new();
    gen_addr_add(ctx, t1, t0, 8);
    gen_qemu_st64(ctx, cpu_fpr[(rd + 1) % 32], t1);
    tcg_temp_free(t1);
5434
    if (ra != 0)
5435 5436
        tcg_gen_mov_tl(cpu_gpr[ra], t0);
    tcg_temp_free(t0);
5437 5438 5439 5440 5441
}

/* stfqx */
GEN_HANDLER(stfqx, 0x1F, 0x17, 0x1C, 0x00000001, PPC_POWER2)
{
5442
    int rd = rD(ctx->opcode);
A
aurel32 已提交
5443 5444 5445 5446 5447 5448 5449
    TCGv t0;
    gen_set_access_type(ctx, ACCESS_FLOAT);
    t0 = tcg_temp_new();
    gen_addr_reg_index(ctx, t0);
    gen_qemu_st64(ctx, cpu_fpr[rd], t0);
    gen_addr_add(ctx, t0, t0, 8);
    gen_qemu_st64(ctx, cpu_fpr[(rd + 1) % 32], t0);
5450
    tcg_temp_free(t0);
5451 5452 5453
}

/* BookE specific instructions */
5454
/* XXX: not implemented on 440 ? */
5455
GEN_HANDLER(mfapidi, 0x1F, 0x13, 0x08, 0x0000F801, PPC_MFAPIDI)
5456 5457
{
    /* XXX: TODO */
A
aurel32 已提交
5458
    gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
5459 5460
}

5461
/* XXX: not implemented on 440 ? */
5462
GEN_HANDLER(tlbiva, 0x1F, 0x12, 0x18, 0x03FFF801, PPC_TLBIVA)
5463 5464
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5465
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5466
#else
5467
    TCGv t0;
A
aurel32 已提交
5468
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5469
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5470 5471
        return;
    }
5472
    t0 = tcg_temp_new();
A
aurel32 已提交
5473
    gen_addr_reg_index(ctx, t0);
5474 5475
    gen_helper_tlbie(cpu_gpr[rB(ctx->opcode)]);
    tcg_temp_free(t0);
5476 5477 5478 5479
#endif
}

/* All 405 MAC instructions are translated here */
5480 5481 5482
static always_inline void gen_405_mulladd_insn (DisasContext *ctx,
                                                int opc2, int opc3,
                                                int ra, int rb, int rt, int Rc)
5483
{
5484 5485
    TCGv t0, t1;

P
pbrook 已提交
5486 5487
    t0 = tcg_temp_local_new();
    t1 = tcg_temp_local_new();
5488

5489 5490 5491 5492 5493 5494 5495
    switch (opc3 & 0x0D) {
    case 0x05:
        /* macchw    - macchw.    - macchwo   - macchwo.   */
        /* macchws   - macchws.   - macchwso  - macchwso.  */
        /* nmacchw   - nmacchw.   - nmacchwo  - nmacchwo.  */
        /* nmacchws  - nmacchws.  - nmacchwso - nmacchwso. */
        /* mulchw - mulchw. */
5496 5497 5498
        tcg_gen_ext16s_tl(t0, cpu_gpr[ra]);
        tcg_gen_sari_tl(t1, cpu_gpr[rb], 16);
        tcg_gen_ext16s_tl(t1, t1);
5499 5500 5501 5502 5503
        break;
    case 0x04:
        /* macchwu   - macchwu.   - macchwuo  - macchwuo.  */
        /* macchwsu  - macchwsu.  - macchwsuo - macchwsuo. */
        /* mulchwu - mulchwu. */
5504 5505 5506
        tcg_gen_ext16u_tl(t0, cpu_gpr[ra]);
        tcg_gen_shri_tl(t1, cpu_gpr[rb], 16);
        tcg_gen_ext16u_tl(t1, t1);
5507 5508 5509 5510 5511 5512 5513
        break;
    case 0x01:
        /* machhw    - machhw.    - machhwo   - machhwo.   */
        /* machhws   - machhws.   - machhwso  - machhwso.  */
        /* nmachhw   - nmachhw.   - nmachhwo  - nmachhwo.  */
        /* nmachhws  - nmachhws.  - nmachhwso - nmachhwso. */
        /* mulhhw - mulhhw. */
5514 5515 5516 5517
        tcg_gen_sari_tl(t0, cpu_gpr[ra], 16);
        tcg_gen_ext16s_tl(t0, t0);
        tcg_gen_sari_tl(t1, cpu_gpr[rb], 16);
        tcg_gen_ext16s_tl(t1, t1);
5518 5519 5520 5521 5522
        break;
    case 0x00:
        /* machhwu   - machhwu.   - machhwuo  - machhwuo.  */
        /* machhwsu  - machhwsu.  - machhwsuo - machhwsuo. */
        /* mulhhwu - mulhhwu. */
5523 5524 5525 5526
        tcg_gen_shri_tl(t0, cpu_gpr[ra], 16);
        tcg_gen_ext16u_tl(t0, t0);
        tcg_gen_shri_tl(t1, cpu_gpr[rb], 16);
        tcg_gen_ext16u_tl(t1, t1);
5527 5528 5529 5530 5531 5532 5533
        break;
    case 0x0D:
        /* maclhw    - maclhw.    - maclhwo   - maclhwo.   */
        /* maclhws   - maclhws.   - maclhwso  - maclhwso.  */
        /* nmaclhw   - nmaclhw.   - nmaclhwo  - nmaclhwo.  */
        /* nmaclhws  - nmaclhws.  - nmaclhwso - nmaclhwso. */
        /* mullhw - mullhw. */
5534 5535
        tcg_gen_ext16s_tl(t0, cpu_gpr[ra]);
        tcg_gen_ext16s_tl(t1, cpu_gpr[rb]);
5536 5537 5538 5539 5540
        break;
    case 0x0C:
        /* maclhwu   - maclhwu.   - maclhwuo  - maclhwuo.  */
        /* maclhwsu  - maclhwsu.  - maclhwsuo - maclhwsuo. */
        /* mullhwu - mullhwu. */
5541 5542
        tcg_gen_ext16u_tl(t0, cpu_gpr[ra]);
        tcg_gen_ext16u_tl(t1, cpu_gpr[rb]);
5543 5544 5545
        break;
    }
    if (opc2 & 0x04) {
5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569
        /* (n)multiply-and-accumulate (0x0C / 0x0E) */
        tcg_gen_mul_tl(t1, t0, t1);
        if (opc2 & 0x02) {
            /* nmultiply-and-accumulate (0x0E) */
            tcg_gen_sub_tl(t0, cpu_gpr[rt], t1);
        } else {
            /* multiply-and-accumulate (0x0C) */
            tcg_gen_add_tl(t0, cpu_gpr[rt], t1);
        }

        if (opc3 & 0x12) {
            /* Check overflow and/or saturate */
            int l1 = gen_new_label();

            if (opc3 & 0x10) {
                /* Start with XER OV disabled, the most likely case */
                tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
            }
            if (opc3 & 0x01) {
                /* Signed */
                tcg_gen_xor_tl(t1, cpu_gpr[rt], t1);
                tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1);
                tcg_gen_xor_tl(t1, cpu_gpr[rt], t0);
                tcg_gen_brcondi_tl(TCG_COND_LT, t1, 0, l1);
A
aurel32 已提交
5570
                if (opc3 & 0x02) {
5571 5572 5573 5574 5575 5576 5577
                    /* Saturate */
                    tcg_gen_sari_tl(t0, cpu_gpr[rt], 31);
                    tcg_gen_xori_tl(t0, t0, 0x7fffffff);
                }
            } else {
                /* Unsigned */
                tcg_gen_brcond_tl(TCG_COND_GEU, t0, t1, l1);
A
aurel32 已提交
5578
                if (opc3 & 0x02) {
5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591
                    /* Saturate */
                    tcg_gen_movi_tl(t0, UINT32_MAX);
                }
            }
            if (opc3 & 0x10) {
                /* Check overflow */
                tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
            }
            gen_set_label(l1);
            tcg_gen_mov_tl(cpu_gpr[rt], t0);
        }
    } else {
        tcg_gen_mul_tl(cpu_gpr[rt], t0, t1);
5592
    }
5593 5594
    tcg_temp_free(t0);
    tcg_temp_free(t1);
5595 5596
    if (unlikely(Rc) != 0) {
        /* Update Rc0 */
5597
        gen_set_Rc0(ctx, cpu_gpr[rt]);
5598 5599 5600
    }
}

5601 5602
#define GEN_MAC_HANDLER(name, opc2, opc3)                                     \
GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_405_MAC)                  \
5603 5604 5605 5606 5607 5608
{                                                                             \
    gen_405_mulladd_insn(ctx, opc2, opc3, rA(ctx->opcode), rB(ctx->opcode),   \
                         rD(ctx->opcode), Rc(ctx->opcode));                   \
}

/* macchw    - macchw.    */
5609
GEN_MAC_HANDLER(macchw, 0x0C, 0x05);
5610
/* macchwo   - macchwo.   */
5611
GEN_MAC_HANDLER(macchwo, 0x0C, 0x15);
5612
/* macchws   - macchws.   */
5613
GEN_MAC_HANDLER(macchws, 0x0C, 0x07);
5614
/* macchwso  - macchwso.  */
5615
GEN_MAC_HANDLER(macchwso, 0x0C, 0x17);
5616
/* macchwsu  - macchwsu.  */
5617
GEN_MAC_HANDLER(macchwsu, 0x0C, 0x06);
5618
/* macchwsuo - macchwsuo. */
5619
GEN_MAC_HANDLER(macchwsuo, 0x0C, 0x16);
5620
/* macchwu   - macchwu.   */
5621
GEN_MAC_HANDLER(macchwu, 0x0C, 0x04);
5622
/* macchwuo  - macchwuo.  */
5623
GEN_MAC_HANDLER(macchwuo, 0x0C, 0x14);
5624
/* machhw    - machhw.    */
5625
GEN_MAC_HANDLER(machhw, 0x0C, 0x01);
5626
/* machhwo   - machhwo.   */
5627
GEN_MAC_HANDLER(machhwo, 0x0C, 0x11);
5628
/* machhws   - machhws.   */
5629
GEN_MAC_HANDLER(machhws, 0x0C, 0x03);
5630
/* machhwso  - machhwso.  */
5631
GEN_MAC_HANDLER(machhwso, 0x0C, 0x13);
5632
/* machhwsu  - machhwsu.  */
5633
GEN_MAC_HANDLER(machhwsu, 0x0C, 0x02);
5634
/* machhwsuo - machhwsuo. */
5635
GEN_MAC_HANDLER(machhwsuo, 0x0C, 0x12);
5636
/* machhwu   - machhwu.   */
5637
GEN_MAC_HANDLER(machhwu, 0x0C, 0x00);
5638
/* machhwuo  - machhwuo.  */
5639
GEN_MAC_HANDLER(machhwuo, 0x0C, 0x10);
5640
/* maclhw    - maclhw.    */
5641
GEN_MAC_HANDLER(maclhw, 0x0C, 0x0D);
5642
/* maclhwo   - maclhwo.   */
5643
GEN_MAC_HANDLER(maclhwo, 0x0C, 0x1D);
5644
/* maclhws   - maclhws.   */
5645
GEN_MAC_HANDLER(maclhws, 0x0C, 0x0F);
5646
/* maclhwso  - maclhwso.  */
5647
GEN_MAC_HANDLER(maclhwso, 0x0C, 0x1F);
5648
/* maclhwu   - maclhwu.   */
5649
GEN_MAC_HANDLER(maclhwu, 0x0C, 0x0C);
5650
/* maclhwuo  - maclhwuo.  */
5651
GEN_MAC_HANDLER(maclhwuo, 0x0C, 0x1C);
5652
/* maclhwsu  - maclhwsu.  */
5653
GEN_MAC_HANDLER(maclhwsu, 0x0C, 0x0E);
5654
/* maclhwsuo - maclhwsuo. */
5655
GEN_MAC_HANDLER(maclhwsuo, 0x0C, 0x1E);
5656
/* nmacchw   - nmacchw.   */
5657
GEN_MAC_HANDLER(nmacchw, 0x0E, 0x05);
5658
/* nmacchwo  - nmacchwo.  */
5659
GEN_MAC_HANDLER(nmacchwo, 0x0E, 0x15);
5660
/* nmacchws  - nmacchws.  */
5661
GEN_MAC_HANDLER(nmacchws, 0x0E, 0x07);
5662
/* nmacchwso - nmacchwso. */
5663
GEN_MAC_HANDLER(nmacchwso, 0x0E, 0x17);
5664
/* nmachhw   - nmachhw.   */
5665
GEN_MAC_HANDLER(nmachhw, 0x0E, 0x01);
5666
/* nmachhwo  - nmachhwo.  */
5667
GEN_MAC_HANDLER(nmachhwo, 0x0E, 0x11);
5668
/* nmachhws  - nmachhws.  */
5669
GEN_MAC_HANDLER(nmachhws, 0x0E, 0x03);
5670
/* nmachhwso - nmachhwso. */
5671
GEN_MAC_HANDLER(nmachhwso, 0x0E, 0x13);
5672
/* nmaclhw   - nmaclhw.   */
5673
GEN_MAC_HANDLER(nmaclhw, 0x0E, 0x0D);
5674
/* nmaclhwo  - nmaclhwo.  */
5675
GEN_MAC_HANDLER(nmaclhwo, 0x0E, 0x1D);
5676
/* nmaclhws  - nmaclhws.  */
5677
GEN_MAC_HANDLER(nmaclhws, 0x0E, 0x0F);
5678
/* nmaclhwso - nmaclhwso. */
5679
GEN_MAC_HANDLER(nmaclhwso, 0x0E, 0x1F);
5680 5681

/* mulchw  - mulchw.  */
5682
GEN_MAC_HANDLER(mulchw, 0x08, 0x05);
5683
/* mulchwu - mulchwu. */
5684
GEN_MAC_HANDLER(mulchwu, 0x08, 0x04);
5685
/* mulhhw  - mulhhw.  */
5686
GEN_MAC_HANDLER(mulhhw, 0x08, 0x01);
5687
/* mulhhwu - mulhhwu. */
5688
GEN_MAC_HANDLER(mulhhwu, 0x08, 0x00);
5689
/* mullhw  - mullhw.  */
5690
GEN_MAC_HANDLER(mullhw, 0x08, 0x0D);
5691
/* mullhwu - mullhwu. */
5692
GEN_MAC_HANDLER(mullhwu, 0x08, 0x0C);
5693 5694

/* mfdcr */
5695
GEN_HANDLER(mfdcr, 0x1F, 0x03, 0x0A, 0x00000001, PPC_DCR)
5696 5697
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5698
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
5699
#else
5700
    TCGv dcrn;
A
aurel32 已提交
5701
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5702
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
5703 5704
        return;
    }
5705 5706 5707 5708 5709
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
    dcrn = tcg_const_tl(SPR(ctx->opcode));
    gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], dcrn);
    tcg_temp_free(dcrn);
5710 5711 5712 5713
#endif
}

/* mtdcr */
5714
GEN_HANDLER(mtdcr, 0x1F, 0x03, 0x0E, 0x00000001, PPC_DCR)
5715 5716
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5717
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
5718
#else
5719
    TCGv dcrn;
A
aurel32 已提交
5720
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5721
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
5722 5723
        return;
    }
5724 5725 5726 5727 5728
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
    dcrn = tcg_const_tl(SPR(ctx->opcode));
    gen_helper_store_dcr(dcrn, cpu_gpr[rS(ctx->opcode)]);
    tcg_temp_free(dcrn);
5729 5730 5731 5732
#endif
}

/* mfdcrx */
5733
/* XXX: not implemented on 440 ? */
5734
GEN_HANDLER(mfdcrx, 0x1F, 0x03, 0x08, 0x00000000, PPC_DCRX)
5735 5736
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5737
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
5738
#else
A
aurel32 已提交
5739
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5740
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
5741 5742
        return;
    }
5743 5744 5745
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
    gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
5746
    /* Note: Rc update flag set leads to undefined state of Rc0 */
5747 5748 5749 5750
#endif
}

/* mtdcrx */
5751
/* XXX: not implemented on 440 ? */
5752
GEN_HANDLER(mtdcrx, 0x1F, 0x03, 0x0C, 0x00000000, PPC_DCRX)
5753 5754
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5755
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
5756
#else
A
aurel32 已提交
5757
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5758
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
5759 5760
        return;
    }
5761 5762 5763
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
    gen_helper_store_dcr(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
5764
    /* Note: Rc update flag set leads to undefined state of Rc0 */
5765 5766 5767
#endif
}

5768 5769 5770
/* mfdcrux (PPC 460) : user-mode access to DCR */
GEN_HANDLER(mfdcrux, 0x1F, 0x03, 0x09, 0x00000000, PPC_DCRUX)
{
5771 5772 5773
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
    gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
5774 5775 5776 5777 5778 5779
    /* Note: Rc update flag set leads to undefined state of Rc0 */
}

/* mtdcrux (PPC 460) : user-mode access to DCR */
GEN_HANDLER(mtdcrux, 0x1F, 0x03, 0x0D, 0x00000000, PPC_DCRUX)
{
5780 5781 5782
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
    gen_helper_store_dcr(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
5783 5784 5785
    /* Note: Rc update flag set leads to undefined state of Rc0 */
}

5786 5787 5788 5789
/* dccci */
GEN_HANDLER(dccci, 0x1F, 0x06, 0x0E, 0x03E00001, PPC_4xx_COMMON)
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5790
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5791
#else
A
aurel32 已提交
5792
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5793
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5794 5795 5796 5797 5798 5799 5800 5801 5802 5803
        return;
    }
    /* interpreted as no-op */
#endif
}

/* dcread */
GEN_HANDLER(dcread, 0x1F, 0x06, 0x0F, 0x00000001, PPC_4xx_COMMON)
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5804
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5805
#else
A
aurel32 已提交
5806
    TCGv EA, val;
A
aurel32 已提交
5807
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5808
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5809 5810
        return;
    }
A
aurel32 已提交
5811
    gen_set_access_type(ctx, ACCESS_CACHE);
P
pbrook 已提交
5812
    EA = tcg_temp_new();
A
aurel32 已提交
5813
    gen_addr_reg_index(ctx, EA);
P
pbrook 已提交
5814
    val = tcg_temp_new();
A
aurel32 已提交
5815
    gen_qemu_ld32u(ctx, val, EA);
A
aurel32 已提交
5816 5817 5818
    tcg_temp_free(val);
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], EA);
    tcg_temp_free(EA);
5819 5820 5821 5822
#endif
}

/* icbt */
5823
GEN_HANDLER2(icbt_40x, "icbt", 0x1F, 0x06, 0x08, 0x03E00001, PPC_40x_ICBT)
5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834
{
    /* interpreted as no-op */
    /* XXX: specification say this is treated as a load by the MMU
     *      but does not generate any exception
     */
}

/* iccci */
GEN_HANDLER(iccci, 0x1F, 0x06, 0x1E, 0x00000001, PPC_4xx_COMMON)
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5835
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5836
#else
A
aurel32 已提交
5837
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5838
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5839 5840 5841 5842 5843 5844 5845 5846 5847 5848
        return;
    }
    /* interpreted as no-op */
#endif
}

/* icread */
GEN_HANDLER(icread, 0x1F, 0x06, 0x1F, 0x03E00001, PPC_4xx_COMMON)
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5849
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5850
#else
A
aurel32 已提交
5851
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5852
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5853 5854 5855 5856 5857 5858
        return;
    }
    /* interpreted as no-op */
#endif
}

A
aurel32 已提交
5859
/* rfci (mem_idx only) */
5860
GEN_HANDLER2(rfci_40x, "rfci", 0x13, 0x13, 0x01, 0x03FF8001, PPC_40x_EXCP)
5861 5862
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5863
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5864
#else
A
aurel32 已提交
5865
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5866
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5867 5868 5869
        return;
    }
    /* Restore CPU state */
5870
    gen_helper_40x_rfci();
A
aurel32 已提交
5871
    gen_sync_exception(ctx);
5872 5873 5874 5875 5876 5877
#endif
}

GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE)
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5878
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5879
#else
A
aurel32 已提交
5880
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5881
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5882 5883 5884
        return;
    }
    /* Restore CPU state */
5885
    gen_helper_rfci();
A
aurel32 已提交
5886
    gen_sync_exception(ctx);
5887 5888 5889 5890
#endif
}

/* BookE specific */
5891
/* XXX: not implemented on 440 ? */
5892
GEN_HANDLER(rfdi, 0x13, 0x07, 0x01, 0x03FF8001, PPC_RFDI)
5893 5894
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5895
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5896
#else
A
aurel32 已提交
5897
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5898
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5899 5900 5901
        return;
    }
    /* Restore CPU state */
5902
    gen_helper_rfdi();
A
aurel32 已提交
5903
    gen_sync_exception(ctx);
5904 5905 5906
#endif
}

5907
/* XXX: not implemented on 440 ? */
5908
GEN_HANDLER(rfmci, 0x13, 0x06, 0x01, 0x03FF8001, PPC_RFMCI)
5909 5910
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5911
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5912
#else
A
aurel32 已提交
5913
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5914
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5915 5916 5917
        return;
    }
    /* Restore CPU state */
5918
    gen_helper_rfmci();
A
aurel32 已提交
5919
    gen_sync_exception(ctx);
5920 5921
#endif
}
5922

5923
/* TLB management - PowerPC 405 implementation */
5924
/* tlbre */
5925
GEN_HANDLER2(tlbre_40x, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_TLB)
5926 5927
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5928
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5929
#else
A
aurel32 已提交
5930
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5931
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5932 5933 5934 5935
        return;
    }
    switch (rB(ctx->opcode)) {
    case 0:
5936
        gen_helper_4xx_tlbre_hi(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
5937 5938
        break;
    case 1:
5939
        gen_helper_4xx_tlbre_lo(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
5940 5941
        break;
    default:
A
aurel32 已提交
5942
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
5943
        break;
5944
    }
5945 5946 5947
#endif
}

5948
/* tlbsx - tlbsx. */
5949
GEN_HANDLER2(tlbsx_40x, "tlbsx", 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_TLB)
5950 5951
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5952
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5953
#else
5954
    TCGv t0;
A
aurel32 已提交
5955
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5956
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5957 5958
        return;
    }
5959
    t0 = tcg_temp_new();
A
aurel32 已提交
5960
    gen_addr_reg_index(ctx, t0);
5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971
    gen_helper_4xx_tlbsx(cpu_gpr[rD(ctx->opcode)], t0);
    tcg_temp_free(t0);
    if (Rc(ctx->opcode)) {
        int l1 = gen_new_label();
        tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_xer);
        tcg_gen_shri_i32(cpu_crf[0], cpu_crf[0], XER_SO);
        tcg_gen_andi_i32(cpu_crf[0], cpu_crf[0], 1);
        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[rD(ctx->opcode)], -1, l1);
        tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 0x02);
        gen_set_label(l1);
    }
5972
#endif
B
bellard 已提交
5973 5974
}

5975
/* tlbwe */
5976
GEN_HANDLER2(tlbwe_40x, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_TLB)
B
bellard 已提交
5977
{
5978
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5979
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5980
#else
A
aurel32 已提交
5981
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5982
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5983 5984 5985 5986
        return;
    }
    switch (rB(ctx->opcode)) {
    case 0:
5987
        gen_helper_4xx_tlbwe_hi(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
5988 5989
        break;
    case 1:
5990
        gen_helper_4xx_tlbwe_lo(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
5991 5992
        break;
    default:
A
aurel32 已提交
5993
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
5994
        break;
5995
    }
5996 5997 5998
#endif
}

5999
/* TLB management - PowerPC 440 implementation */
6000
/* tlbre */
6001
GEN_HANDLER2(tlbre_440, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE)
6002 6003
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
6004
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
6005
#else
A
aurel32 已提交
6006
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
6007
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
6008 6009 6010 6011 6012 6013
        return;
    }
    switch (rB(ctx->opcode)) {
    case 0:
    case 1:
    case 2:
6014 6015 6016 6017 6018
        {
            TCGv_i32 t0 = tcg_const_i32(rB(ctx->opcode));
            gen_helper_440_tlbwe(t0, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
            tcg_temp_free_i32(t0);
        }
6019 6020
        break;
    default:
A
aurel32 已提交
6021
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
6022 6023 6024 6025 6026 6027
        break;
    }
#endif
}

/* tlbsx - tlbsx. */
6028
GEN_HANDLER2(tlbsx_440, "tlbsx", 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE)
6029 6030
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
6031
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
6032
#else
6033
    TCGv t0;
A
aurel32 已提交
6034
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
6035
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
6036 6037
        return;
    }
6038
    t0 = tcg_temp_new();
A
aurel32 已提交
6039
    gen_addr_reg_index(ctx, t0);
6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050
    gen_helper_440_tlbsx(cpu_gpr[rD(ctx->opcode)], t0);
    tcg_temp_free(t0);
    if (Rc(ctx->opcode)) {
        int l1 = gen_new_label();
        tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_xer);
        tcg_gen_shri_i32(cpu_crf[0], cpu_crf[0], XER_SO);
        tcg_gen_andi_i32(cpu_crf[0], cpu_crf[0], 1);
        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[rD(ctx->opcode)], -1, l1);
        tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 0x02);
        gen_set_label(l1);
    }
6051 6052 6053 6054
#endif
}

/* tlbwe */
6055
GEN_HANDLER2(tlbwe_440, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE)
6056 6057
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
6058
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
6059
#else
A
aurel32 已提交
6060
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
6061
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
6062 6063 6064 6065 6066 6067
        return;
    }
    switch (rB(ctx->opcode)) {
    case 0:
    case 1:
    case 2:
6068 6069 6070 6071 6072
        {
            TCGv_i32 t0 = tcg_const_i32(rB(ctx->opcode));
            gen_helper_440_tlbwe(t0, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
            tcg_temp_free_i32(t0);
        }
6073 6074
        break;
    default:
A
aurel32 已提交
6075
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
6076 6077 6078 6079 6080
        break;
    }
#endif
}

6081
/* wrtee */
6082
GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_WRTEE)
6083 6084
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
6085
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
6086
#else
6087
    TCGv t0;
A
aurel32 已提交
6088
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
6089
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
6090 6091
        return;
    }
6092 6093 6094 6095 6096
    t0 = tcg_temp_new();
    tcg_gen_andi_tl(t0, cpu_gpr[rD(ctx->opcode)], (1 << MSR_EE));
    tcg_gen_andi_tl(cpu_msr, cpu_msr, ~(1 << MSR_EE));
    tcg_gen_or_tl(cpu_msr, cpu_msr, t0);
    tcg_temp_free(t0);
J
j_mayer 已提交
6097 6098 6099
    /* Stop translation to have a chance to raise an exception
     * if we just set msr_ee to 1
     */
A
aurel32 已提交
6100
    gen_stop_exception(ctx);
6101 6102 6103 6104
#endif
}

/* wrteei */
6105
GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000EFC01, PPC_WRTEE)
6106 6107
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
6108
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
6109
#else
A
aurel32 已提交
6110
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
6111
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
6112 6113
        return;
    }
6114 6115 6116
    if (ctx->opcode & 0x00010000) {
        tcg_gen_ori_tl(cpu_msr, cpu_msr, (1 << MSR_EE));
        /* Stop translation to have a chance to raise an exception */
A
aurel32 已提交
6117
        gen_stop_exception(ctx);
6118
    } else {
A
aurel32 已提交
6119
        tcg_gen_andi_tl(cpu_msr, cpu_msr, ~(1 << MSR_EE));
6120
    }
6121 6122 6123
#endif
}

J
j_mayer 已提交
6124
/* PowerPC 440 specific instructions */
6125 6126 6127
/* dlmzb */
GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC)
{
6128 6129 6130 6131
    TCGv_i32 t0 = tcg_const_i32(Rc(ctx->opcode));
    gen_helper_dlmzb(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)],
                     cpu_gpr[rB(ctx->opcode)], t0);
    tcg_temp_free_i32(t0);
6132 6133 6134
}

/* mbar replaces eieio on 440 */
A
aurel32 已提交
6135
GEN_HANDLER(mbar, 0x1F, 0x16, 0x1a, 0x001FF801, PPC_BOOKE)
6136 6137 6138 6139 6140
{
    /* interpreted as no-op */
}

/* msync replaces sync on 440 */
6141
GEN_HANDLER(msync, 0x1F, 0x16, 0x12, 0x03FFF801, PPC_BOOKE)
6142 6143 6144 6145 6146
{
    /* interpreted as no-op */
}

/* icbt */
6147
GEN_HANDLER2(icbt_440, "icbt", 0x1F, 0x16, 0x00, 0x03E00001, PPC_BOOKE)
6148 6149 6150 6151 6152
{
    /* interpreted as no-op */
    /* XXX: specification say this is treated as a load by the MMU
     *      but does not generate any exception
     */
B
bellard 已提交
6153 6154
}

6155 6156 6157
/***                      Altivec vector extension                         ***/
/* Altivec registers moves */

A
aurel32 已提交
6158 6159
static always_inline TCGv_ptr gen_avr_ptr(int reg)
{
A
aurel32 已提交
6160
    TCGv_ptr r = tcg_temp_new_ptr();
A
aurel32 已提交
6161 6162 6163 6164
    tcg_gen_addi_ptr(r, cpu_env, offsetof(CPUPPCState, avr[reg]));
    return r;
}

6165
#define GEN_VR_LDX(name, opc2, opc3)                                          \
6166
GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC)                  \
6167
{                                                                             \
6168
    TCGv EA;                                                                  \
6169
    if (unlikely(!ctx->altivec_enabled)) {                                    \
A
aurel32 已提交
6170
        gen_exception(ctx, POWERPC_EXCP_VPU);                                 \
6171 6172
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
6173
    gen_set_access_type(ctx, ACCESS_INT);                                     \
6174
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
6175
    gen_addr_reg_index(ctx, EA);                                              \
6176
    tcg_gen_andi_tl(EA, EA, ~0xf);                                            \
A
aurel32 已提交
6177 6178
    if (ctx->le_mode) {                                                       \
        gen_qemu_ld64(ctx, cpu_avrl[rD(ctx->opcode)], EA);                    \
6179
        tcg_gen_addi_tl(EA, EA, 8);                                           \
A
aurel32 已提交
6180
        gen_qemu_ld64(ctx, cpu_avrh[rD(ctx->opcode)], EA);                    \
6181
    } else {                                                                  \
A
aurel32 已提交
6182
        gen_qemu_ld64(ctx, cpu_avrh[rD(ctx->opcode)], EA);                    \
6183
        tcg_gen_addi_tl(EA, EA, 8);                                           \
A
aurel32 已提交
6184
        gen_qemu_ld64(ctx, cpu_avrl[rD(ctx->opcode)], EA);                    \
6185 6186
    }                                                                         \
    tcg_temp_free(EA);                                                        \
6187 6188 6189 6190 6191
}

#define GEN_VR_STX(name, opc2, opc3)                                          \
GEN_HANDLER(st##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC)              \
{                                                                             \
6192
    TCGv EA;                                                                  \
6193
    if (unlikely(!ctx->altivec_enabled)) {                                    \
A
aurel32 已提交
6194
        gen_exception(ctx, POWERPC_EXCP_VPU);                                 \
6195 6196
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
6197
    gen_set_access_type(ctx, ACCESS_INT);                                     \
6198
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
6199
    gen_addr_reg_index(ctx, EA);                                              \
6200
    tcg_gen_andi_tl(EA, EA, ~0xf);                                            \
A
aurel32 已提交
6201 6202
    if (ctx->le_mode) {                                                       \
        gen_qemu_st64(ctx, cpu_avrl[rD(ctx->opcode)], EA);                    \
6203
        tcg_gen_addi_tl(EA, EA, 8);                                           \
A
aurel32 已提交
6204
        gen_qemu_st64(ctx, cpu_avrh[rD(ctx->opcode)], EA);                    \
6205
    } else {                                                                  \
A
aurel32 已提交
6206
        gen_qemu_st64(ctx, cpu_avrh[rD(ctx->opcode)], EA);                    \
6207
        tcg_gen_addi_tl(EA, EA, 8);                                           \
A
aurel32 已提交
6208
        gen_qemu_st64(ctx, cpu_avrl[rD(ctx->opcode)], EA);                    \
6209 6210
    }                                                                         \
    tcg_temp_free(EA);                                                        \
6211 6212
}

A
aurel32 已提交
6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248
#define GEN_VR_LVE(name, opc2, opc3)                                    \
    GEN_HANDLER(lve##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC)   \
    {                                                                   \
        TCGv EA;                                                        \
        TCGv_ptr rs;                                                    \
        if (unlikely(!ctx->altivec_enabled)) {                          \
            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
            return;                                                     \
        }                                                               \
        gen_set_access_type(ctx, ACCESS_INT);                           \
        EA = tcg_temp_new();                                            \
        gen_addr_reg_index(ctx, EA);                                    \
        rs = gen_avr_ptr(rS(ctx->opcode));                              \
        gen_helper_lve##name (rs, EA);                                  \
        tcg_temp_free(EA);                                              \
        tcg_temp_free_ptr(rs);                                          \
    }

#define GEN_VR_STVE(name, opc2, opc3)                                   \
    GEN_HANDLER(stve##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC)  \
    {                                                                   \
        TCGv EA;                                                        \
        TCGv_ptr rs;                                                    \
        if (unlikely(!ctx->altivec_enabled)) {                          \
            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
            return;                                                     \
        }                                                               \
        gen_set_access_type(ctx, ACCESS_INT);                           \
        EA = tcg_temp_new();                                            \
        gen_addr_reg_index(ctx, EA);                                    \
        rs = gen_avr_ptr(rS(ctx->opcode));                              \
        gen_helper_stve##name (rs, EA);                                 \
        tcg_temp_free(EA);                                              \
        tcg_temp_free_ptr(rs);                                          \
    }

6249
GEN_VR_LDX(lvx, 0x07, 0x03);
6250
/* As we don't emulate the cache, lvxl is stricly equivalent to lvx */
6251
GEN_VR_LDX(lvxl, 0x07, 0x0B);
6252

A
aurel32 已提交
6253 6254 6255 6256
GEN_VR_LVE(bx, 0x07, 0x00);
GEN_VR_LVE(hx, 0x07, 0x01);
GEN_VR_LVE(wx, 0x07, 0x02);

6257
GEN_VR_STX(svx, 0x07, 0x07);
6258
/* As we don't emulate the cache, stvxl is stricly equivalent to stvx */
6259
GEN_VR_STX(svxl, 0x07, 0x0F);
6260

A
aurel32 已提交
6261 6262 6263 6264
GEN_VR_STVE(bx, 0x07, 0x04);
GEN_VR_STVE(hx, 0x07, 0x05);
GEN_VR_STVE(wx, 0x07, 0x06);

A
aurel32 已提交
6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296
GEN_HANDLER(lvsl, 0x1f, 0x06, 0x00, 0x00000001, PPC_ALTIVEC)
{
    TCGv_ptr rd;
    TCGv EA;
    if (unlikely(!ctx->altivec_enabled)) {
        gen_exception(ctx, POWERPC_EXCP_VPU);
        return;
    }
    EA = tcg_temp_new();
    gen_addr_reg_index(ctx, EA);
    rd = gen_avr_ptr(rD(ctx->opcode));
    gen_helper_lvsl(rd, EA);
    tcg_temp_free(EA);
    tcg_temp_free_ptr(rd);
}

GEN_HANDLER(lvsr, 0x1f, 0x06, 0x01, 0x00000001, PPC_ALTIVEC)
{
    TCGv_ptr rd;
    TCGv EA;
    if (unlikely(!ctx->altivec_enabled)) {
        gen_exception(ctx, POWERPC_EXCP_VPU);
        return;
    }
    EA = tcg_temp_new();
    gen_addr_reg_index(ctx, EA);
    rd = gen_avr_ptr(rD(ctx->opcode));
    gen_helper_lvsr(rd, EA);
    tcg_temp_free(EA);
    tcg_temp_free_ptr(rd);
}

6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307
GEN_HANDLER(mfvscr, 0x04, 0x2, 0x18, 0x001ff800, PPC_ALTIVEC)
{
    TCGv_i32 t;
    if (unlikely(!ctx->altivec_enabled)) {
        gen_exception(ctx, POWERPC_EXCP_VPU);
        return;
    }
    tcg_gen_movi_i64(cpu_avrh[rD(ctx->opcode)], 0);
    t = tcg_temp_new_i32();
    tcg_gen_ld_i32(t, cpu_env, offsetof(CPUState, vscr));
    tcg_gen_extu_i32_i64(cpu_avrl[rD(ctx->opcode)], t);
6308
    tcg_temp_free_i32(t);
6309 6310 6311 6312
}

GEN_HANDLER(mtvscr, 0x04, 0x2, 0x19, 0x03ff0000, PPC_ALTIVEC)
{
A
aurel32 已提交
6313
    TCGv_ptr p;
6314 6315 6316 6317
    if (unlikely(!ctx->altivec_enabled)) {
        gen_exception(ctx, POWERPC_EXCP_VPU);
        return;
    }
A
aurel32 已提交
6318 6319 6320
    p = gen_avr_ptr(rD(ctx->opcode));
    gen_helper_mtvscr(p);
    tcg_temp_free_ptr(p);
6321 6322
}

6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340
/* Logical operations */
#define GEN_VX_LOGICAL(name, tcg_op, opc2, opc3)                        \
GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC)            \
{                                                                       \
    if (unlikely(!ctx->altivec_enabled)) {                              \
        gen_exception(ctx, POWERPC_EXCP_VPU);                           \
        return;                                                         \
    }                                                                   \
    tcg_op(cpu_avrh[rD(ctx->opcode)], cpu_avrh[rA(ctx->opcode)], cpu_avrh[rB(ctx->opcode)]); \
    tcg_op(cpu_avrl[rD(ctx->opcode)], cpu_avrl[rA(ctx->opcode)], cpu_avrl[rB(ctx->opcode)]); \
}

GEN_VX_LOGICAL(vand, tcg_gen_and_i64, 2, 16);
GEN_VX_LOGICAL(vandc, tcg_gen_andc_i64, 2, 17);
GEN_VX_LOGICAL(vor, tcg_gen_or_i64, 2, 18);
GEN_VX_LOGICAL(vxor, tcg_gen_xor_i64, 2, 19);
GEN_VX_LOGICAL(vnor, tcg_gen_nor_i64, 2, 20);

6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357
#define GEN_VXFORM(name, opc2, opc3)                                    \
GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC)            \
{                                                                       \
    TCGv_ptr ra, rb, rd;                                                \
    if (unlikely(!ctx->altivec_enabled)) {                              \
        gen_exception(ctx, POWERPC_EXCP_VPU);                           \
        return;                                                         \
    }                                                                   \
    ra = gen_avr_ptr(rA(ctx->opcode));                                  \
    rb = gen_avr_ptr(rB(ctx->opcode));                                  \
    rd = gen_avr_ptr(rD(ctx->opcode));                                  \
    gen_helper_##name (rd, ra, rb);                                     \
    tcg_temp_free_ptr(ra);                                              \
    tcg_temp_free_ptr(rb);                                              \
    tcg_temp_free_ptr(rd);                                              \
}

A
aurel32 已提交
6358 6359 6360 6361 6362 6363
GEN_VXFORM(vaddubm, 0, 0);
GEN_VXFORM(vadduhm, 0, 1);
GEN_VXFORM(vadduwm, 0, 2);
GEN_VXFORM(vsububm, 0, 16);
GEN_VXFORM(vsubuhm, 0, 17);
GEN_VXFORM(vsubuwm, 0, 18);
6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375
GEN_VXFORM(vmaxub, 1, 0);
GEN_VXFORM(vmaxuh, 1, 1);
GEN_VXFORM(vmaxuw, 1, 2);
GEN_VXFORM(vmaxsb, 1, 4);
GEN_VXFORM(vmaxsh, 1, 5);
GEN_VXFORM(vmaxsw, 1, 6);
GEN_VXFORM(vminub, 1, 8);
GEN_VXFORM(vminuh, 1, 9);
GEN_VXFORM(vminuw, 1, 10);
GEN_VXFORM(vminsb, 1, 12);
GEN_VXFORM(vminsh, 1, 13);
GEN_VXFORM(vminsw, 1, 14);
A
aurel32 已提交
6376 6377 6378 6379 6380 6381
GEN_VXFORM(vavgub, 1, 16);
GEN_VXFORM(vavguh, 1, 17);
GEN_VXFORM(vavguw, 1, 18);
GEN_VXFORM(vavgsb, 1, 20);
GEN_VXFORM(vavgsh, 1, 21);
GEN_VXFORM(vavgsw, 1, 22);
A
aurel32 已提交
6382 6383 6384 6385 6386 6387
GEN_VXFORM(vmrghb, 6, 0);
GEN_VXFORM(vmrghh, 6, 1);
GEN_VXFORM(vmrghw, 6, 2);
GEN_VXFORM(vmrglb, 6, 4);
GEN_VXFORM(vmrglh, 6, 5);
GEN_VXFORM(vmrglw, 6, 6);
A
aurel32 已提交
6388 6389 6390 6391 6392 6393 6394 6395
GEN_VXFORM(vmuloub, 4, 0);
GEN_VXFORM(vmulouh, 4, 1);
GEN_VXFORM(vmulosb, 4, 4);
GEN_VXFORM(vmulosh, 4, 5);
GEN_VXFORM(vmuleub, 4, 8);
GEN_VXFORM(vmuleuh, 4, 9);
GEN_VXFORM(vmulesb, 4, 12);
GEN_VXFORM(vmulesh, 4, 13);
A
aurel32 已提交
6396 6397 6398
GEN_VXFORM(vslb, 2, 4);
GEN_VXFORM(vslh, 2, 5);
GEN_VXFORM(vslw, 2, 6);
A
aurel32 已提交
6399 6400 6401 6402 6403 6404
GEN_VXFORM(vsrb, 2, 8);
GEN_VXFORM(vsrh, 2, 9);
GEN_VXFORM(vsrw, 2, 10);
GEN_VXFORM(vsrab, 2, 12);
GEN_VXFORM(vsrah, 2, 13);
GEN_VXFORM(vsraw, 2, 14);
A
aurel32 已提交
6405 6406
GEN_VXFORM(vslo, 6, 16);
GEN_VXFORM(vsro, 6, 17);
A
aurel32 已提交
6407 6408
GEN_VXFORM(vaddcuw, 0, 6);
GEN_VXFORM(vsubcuw, 0, 22);
6409 6410 6411 6412 6413 6414 6415 6416 6417 6418 6419 6420
GEN_VXFORM(vaddubs, 0, 8);
GEN_VXFORM(vadduhs, 0, 9);
GEN_VXFORM(vadduws, 0, 10);
GEN_VXFORM(vaddsbs, 0, 12);
GEN_VXFORM(vaddshs, 0, 13);
GEN_VXFORM(vaddsws, 0, 14);
GEN_VXFORM(vsububs, 0, 24);
GEN_VXFORM(vsubuhs, 0, 25);
GEN_VXFORM(vsubuws, 0, 26);
GEN_VXFORM(vsubsbs, 0, 28);
GEN_VXFORM(vsubshs, 0, 29);
GEN_VXFORM(vsubsws, 0, 30);
A
aurel32 已提交
6421 6422 6423
GEN_VXFORM(vrlb, 2, 0);
GEN_VXFORM(vrlh, 2, 1);
GEN_VXFORM(vrlw, 2, 2);
A
aurel32 已提交
6424 6425
GEN_VXFORM(vsl, 2, 7);
GEN_VXFORM(vsr, 2, 11);
6426 6427 6428 6429 6430 6431 6432 6433
GEN_VXFORM(vpkuhum, 7, 0);
GEN_VXFORM(vpkuwum, 7, 1);
GEN_VXFORM(vpkuhus, 7, 2);
GEN_VXFORM(vpkuwus, 7, 3);
GEN_VXFORM(vpkshus, 7, 4);
GEN_VXFORM(vpkswus, 7, 5);
GEN_VXFORM(vpkshss, 7, 6);
GEN_VXFORM(vpkswss, 7, 7);
A
aurel32 已提交
6434
GEN_VXFORM(vpkpx, 7, 12);
6435 6436 6437 6438 6439
GEN_VXFORM(vsum4ubs, 4, 24);
GEN_VXFORM(vsum4sbs, 4, 28);
GEN_VXFORM(vsum4shs, 4, 25);
GEN_VXFORM(vsum2sws, 4, 26);
GEN_VXFORM(vsumsws, 4, 30);
6440 6441
GEN_VXFORM(vaddfp, 5, 0);
GEN_VXFORM(vsubfp, 5, 1);
6442 6443
GEN_VXFORM(vmaxfp, 5, 16);
GEN_VXFORM(vminfp, 5, 17);
A
aurel32 已提交
6444

6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465
#define GEN_VXRFORM1(opname, name, str, opc2, opc3)                     \
    GEN_HANDLER2(name, str, 0x4, opc2, opc3, 0x00000000, PPC_ALTIVEC)   \
    {                                                                   \
        TCGv_ptr ra, rb, rd;                                            \
        if (unlikely(!ctx->altivec_enabled)) {                          \
            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
            return;                                                     \
        }                                                               \
        ra = gen_avr_ptr(rA(ctx->opcode));                              \
        rb = gen_avr_ptr(rB(ctx->opcode));                              \
        rd = gen_avr_ptr(rD(ctx->opcode));                              \
        gen_helper_##opname (rd, ra, rb);                               \
        tcg_temp_free_ptr(ra);                                          \
        tcg_temp_free_ptr(rb);                                          \
        tcg_temp_free_ptr(rd);                                          \
    }

#define GEN_VXRFORM(name, opc2, opc3)                                \
    GEN_VXRFORM1(name, name, #name, opc2, opc3)                      \
    GEN_VXRFORM1(name##_dot, name##_, #name ".", opc2, (opc3 | (0x1 << 4)))

6466 6467 6468 6469 6470 6471 6472 6473 6474
GEN_VXRFORM(vcmpequb, 3, 0)
GEN_VXRFORM(vcmpequh, 3, 1)
GEN_VXRFORM(vcmpequw, 3, 2)
GEN_VXRFORM(vcmpgtsb, 3, 12)
GEN_VXRFORM(vcmpgtsh, 3, 13)
GEN_VXRFORM(vcmpgtsw, 3, 14)
GEN_VXRFORM(vcmpgtub, 3, 8)
GEN_VXRFORM(vcmpgtuh, 3, 9)
GEN_VXRFORM(vcmpgtuw, 3, 10)
6475 6476 6477 6478
GEN_VXRFORM(vcmpeqfp, 3, 3)
GEN_VXRFORM(vcmpgefp, 3, 7)
GEN_VXRFORM(vcmpgtfp, 3, 11)
GEN_VXRFORM(vcmpbfp, 3, 15)
6479

A
aurel32 已提交
6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499
#define GEN_VXFORM_SIMM(name, opc2, opc3)                               \
    GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC)        \
    {                                                                   \
        TCGv_ptr rd;                                                    \
        TCGv_i32 simm;                                                  \
        if (unlikely(!ctx->altivec_enabled)) {                          \
            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
            return;                                                     \
        }                                                               \
        simm = tcg_const_i32(SIMM5(ctx->opcode));                       \
        rd = gen_avr_ptr(rD(ctx->opcode));                              \
        gen_helper_##name (rd, simm);                                   \
        tcg_temp_free_i32(simm);                                        \
        tcg_temp_free_ptr(rd);                                          \
    }

GEN_VXFORM_SIMM(vspltisb, 6, 12);
GEN_VXFORM_SIMM(vspltish, 6, 13);
GEN_VXFORM_SIMM(vspltisw, 6, 14);

6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514
#define GEN_VXFORM_NOA(name, opc2, opc3)                                \
    GEN_HANDLER(name, 0x04, opc2, opc3, 0x001f0000, PPC_ALTIVEC)        \
    {                                                                   \
        TCGv_ptr rb, rd;                                                \
        if (unlikely(!ctx->altivec_enabled)) {                          \
            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
            return;                                                     \
        }                                                               \
        rb = gen_avr_ptr(rB(ctx->opcode));                              \
        rd = gen_avr_ptr(rD(ctx->opcode));                              \
        gen_helper_##name (rd, rb);                                     \
        tcg_temp_free_ptr(rb);                                          \
        tcg_temp_free_ptr(rd);                                         \
    }

A
aurel32 已提交
6515 6516 6517 6518
GEN_VXFORM_NOA(vupkhsb, 7, 8);
GEN_VXFORM_NOA(vupkhsh, 7, 9);
GEN_VXFORM_NOA(vupklsb, 7, 10);
GEN_VXFORM_NOA(vupklsh, 7, 11);
A
aurel32 已提交
6519 6520
GEN_VXFORM_NOA(vupkhpx, 7, 13);
GEN_VXFORM_NOA(vupklpx, 7, 15);
A
aurel32 已提交
6521
GEN_VXFORM_NOA(vrefp, 5, 4);
A
aurel32 已提交
6522
GEN_VXFORM_NOA(vrsqrtefp, 5, 5);
6523
GEN_VXFORM_NOA(vlogefp, 5, 7);
A
aurel32 已提交
6524 6525 6526 6527
GEN_VXFORM_NOA(vrfim, 5, 8);
GEN_VXFORM_NOA(vrfin, 5, 9);
GEN_VXFORM_NOA(vrfip, 5, 10);
GEN_VXFORM_NOA(vrfiz, 5, 11);
A
aurel32 已提交
6528

6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544
#define GEN_VXFORM_SIMM(name, opc2, opc3)                               \
    GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC)        \
    {                                                                   \
        TCGv_ptr rd;                                                    \
        TCGv_i32 simm;                                                  \
        if (unlikely(!ctx->altivec_enabled)) {                          \
            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
            return;                                                     \
        }                                                               \
        simm = tcg_const_i32(SIMM5(ctx->opcode));                       \
        rd = gen_avr_ptr(rD(ctx->opcode));                              \
        gen_helper_##name (rd, simm);                                   \
        tcg_temp_free_i32(simm);                                        \
        tcg_temp_free_ptr(rd);                                          \
    }

6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562
#define GEN_VXFORM_UIMM(name, opc2, opc3)                               \
    GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC)        \
    {                                                                   \
        TCGv_ptr rb, rd;                                                \
        TCGv_i32 uimm;                                                  \
        if (unlikely(!ctx->altivec_enabled)) {                          \
            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
            return;                                                     \
        }                                                               \
        uimm = tcg_const_i32(UIMM5(ctx->opcode));                       \
        rb = gen_avr_ptr(rB(ctx->opcode));                              \
        rd = gen_avr_ptr(rD(ctx->opcode));                              \
        gen_helper_##name (rd, rb, uimm);                               \
        tcg_temp_free_i32(uimm);                                        \
        tcg_temp_free_ptr(rb);                                          \
        tcg_temp_free_ptr(rd);                                          \
    }

A
aurel32 已提交
6563 6564 6565
GEN_VXFORM_UIMM(vspltb, 6, 8);
GEN_VXFORM_UIMM(vsplth, 6, 9);
GEN_VXFORM_UIMM(vspltw, 6, 10);
A
aurel32 已提交
6566 6567
GEN_VXFORM_UIMM(vcfux, 5, 12);
GEN_VXFORM_UIMM(vcfsx, 5, 13);
6568 6569
GEN_VXFORM_UIMM(vctuxs, 5, 14);
GEN_VXFORM_UIMM(vctsxs, 5, 15);
A
aurel32 已提交
6570

A
aurel32 已提交
6571 6572 6573
GEN_HANDLER(vsldoi, 0x04, 0x16, 0xFF, 0x00000400, PPC_ALTIVEC)
{
    TCGv_ptr ra, rb, rd;
6574
    TCGv_i32 sh;
A
aurel32 已提交
6575 6576 6577 6578 6579 6580 6581 6582 6583 6584 6585 6586
    if (unlikely(!ctx->altivec_enabled)) {
        gen_exception(ctx, POWERPC_EXCP_VPU);
        return;
    }
    ra = gen_avr_ptr(rA(ctx->opcode));
    rb = gen_avr_ptr(rB(ctx->opcode));
    rd = gen_avr_ptr(rD(ctx->opcode));
    sh = tcg_const_i32(VSH(ctx->opcode));
    gen_helper_vsldoi (rd, ra, rb, sh);
    tcg_temp_free_ptr(ra);
    tcg_temp_free_ptr(rb);
    tcg_temp_free_ptr(rd);
6587
    tcg_temp_free_i32(sh);
A
aurel32 已提交
6588 6589
}

6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604 6605 6606 6607 6608 6609 6610 6611 6612
#define GEN_VAFORM_PAIRED(name0, name1, opc2)                           \
    GEN_HANDLER(name0##_##name1, 0x04, opc2, 0xFF, 0x00000000, PPC_ALTIVEC) \
    {                                                                   \
        TCGv_ptr ra, rb, rc, rd;                                        \
        if (unlikely(!ctx->altivec_enabled)) {                          \
            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
            return;                                                     \
        }                                                               \
        ra = gen_avr_ptr(rA(ctx->opcode));                              \
        rb = gen_avr_ptr(rB(ctx->opcode));                              \
        rc = gen_avr_ptr(rC(ctx->opcode));                              \
        rd = gen_avr_ptr(rD(ctx->opcode));                              \
        if (Rc(ctx->opcode)) {                                          \
            gen_helper_##name1 (rd, ra, rb, rc);                        \
        } else {                                                        \
            gen_helper_##name0 (rd, ra, rb, rc);                        \
        }                                                               \
        tcg_temp_free_ptr(ra);                                          \
        tcg_temp_free_ptr(rb);                                          \
        tcg_temp_free_ptr(rc);                                          \
        tcg_temp_free_ptr(rd);                                          \
    }

A
aurel32 已提交
6613 6614
GEN_VAFORM_PAIRED(vmhaddshs, vmhraddshs, 16)

A
aurel32 已提交
6615 6616 6617 6618 6619 6620 6621 6622 6623 6624 6625 6626 6627 6628 6629 6630 6631 6632
GEN_HANDLER(vmladduhm, 0x04, 0x11, 0xFF, 0x00000000, PPC_ALTIVEC)
{
    TCGv_ptr ra, rb, rc, rd;
    if (unlikely(!ctx->altivec_enabled)) {
        gen_exception(ctx, POWERPC_EXCP_VPU);
        return;
    }
    ra = gen_avr_ptr(rA(ctx->opcode));
    rb = gen_avr_ptr(rB(ctx->opcode));
    rc = gen_avr_ptr(rC(ctx->opcode));
    rd = gen_avr_ptr(rD(ctx->opcode));
    gen_helper_vmladduhm(rd, ra, rb, rc);
    tcg_temp_free_ptr(ra);
    tcg_temp_free_ptr(rb);
    tcg_temp_free_ptr(rc);
    tcg_temp_free_ptr(rd);
}

A
aurel32 已提交
6633
GEN_VAFORM_PAIRED(vmsumubm, vmsummbm, 18)
A
aurel32 已提交
6634
GEN_VAFORM_PAIRED(vmsumuhm, vmsumuhs, 19)
A
aurel32 已提交
6635
GEN_VAFORM_PAIRED(vmsumshm, vmsumshs, 20)
A
aurel32 已提交
6636
GEN_VAFORM_PAIRED(vsel, vperm, 21)
6637
GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23)
A
aurel32 已提交
6638

6639 6640
/***                           SPE extension                               ***/
/* Register moves */
6641

P
pbrook 已提交
6642
static always_inline void gen_load_gpr64(TCGv_i64 t, int reg) {
A
aurel32 已提交
6643 6644 6645
#if defined(TARGET_PPC64)
    tcg_gen_mov_i64(t, cpu_gpr[reg]);
#else
P
pbrook 已提交
6646
    tcg_gen_concat_i32_i64(t, cpu_gpr[reg], cpu_gprh[reg]);
6647
#endif
A
aurel32 已提交
6648
}
6649

P
pbrook 已提交
6650
static always_inline void gen_store_gpr64(int reg, TCGv_i64 t) {
A
aurel32 已提交
6651 6652 6653
#if defined(TARGET_PPC64)
    tcg_gen_mov_i64(cpu_gpr[reg], t);
#else
P
pbrook 已提交
6654
    TCGv_i64 tmp = tcg_temp_new_i64();
A
aurel32 已提交
6655 6656 6657
    tcg_gen_trunc_i64_i32(cpu_gpr[reg], t);
    tcg_gen_shri_i64(tmp, t, 32);
    tcg_gen_trunc_i64_i32(cpu_gprh[reg], tmp);
P
pbrook 已提交
6658
    tcg_temp_free_i64(tmp);
6659
#endif
A
aurel32 已提交
6660
}
6661

6662 6663 6664 6665 6666 6667 6668 6669 6670 6671
#define GEN_SPE(name0, name1, opc2, opc3, inval, type)                        \
GEN_HANDLER(name0##_##name1, 0x04, opc2, opc3, inval, type)                   \
{                                                                             \
    if (Rc(ctx->opcode))                                                      \
        gen_##name1(ctx);                                                     \
    else                                                                      \
        gen_##name0(ctx);                                                     \
}

/* Handler for undefined SPE opcodes */
6672
static always_inline void gen_speundef (DisasContext *ctx)
6673
{
A
aurel32 已提交
6674
    gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
6675 6676
}

6677 6678 6679
/* SPE logic */
#if defined(TARGET_PPC64)
#define GEN_SPEOP_LOGIC2(name, tcg_op)                                        \
6680
static always_inline void gen_##name (DisasContext *ctx)                      \
6681 6682
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
6683
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6684 6685
        return;                                                               \
    }                                                                         \
6686 6687 6688 6689 6690 6691 6692 6693
    tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],                \
           cpu_gpr[rB(ctx->opcode)]);                                         \
}
#else
#define GEN_SPEOP_LOGIC2(name, tcg_op)                                        \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
6694
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6695 6696 6697 6698 6699 6700
        return;                                                               \
    }                                                                         \
    tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],                \
           cpu_gpr[rB(ctx->opcode)]);                                         \
    tcg_op(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)],              \
           cpu_gprh[rB(ctx->opcode)]);                                        \
6701
}
6702 6703 6704 6705 6706 6707 6708 6709 6710 6711
#endif

GEN_SPEOP_LOGIC2(evand, tcg_gen_and_tl);
GEN_SPEOP_LOGIC2(evandc, tcg_gen_andc_tl);
GEN_SPEOP_LOGIC2(evxor, tcg_gen_xor_tl);
GEN_SPEOP_LOGIC2(evor, tcg_gen_or_tl);
GEN_SPEOP_LOGIC2(evnor, tcg_gen_nor_tl);
GEN_SPEOP_LOGIC2(eveqv, tcg_gen_eqv_tl);
GEN_SPEOP_LOGIC2(evorc, tcg_gen_orc_tl);
GEN_SPEOP_LOGIC2(evnand, tcg_gen_nand_tl);
6712

6713 6714 6715
/* SPE logic immediate */
#if defined(TARGET_PPC64)
#define GEN_SPEOP_TCG_LOGIC_IMM2(name, tcg_opi)                               \
6716 6717 6718
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
6719
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6720 6721
        return;                                                               \
    }                                                                         \
P
pbrook 已提交
6722 6723 6724
    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
    TCGv_i64 t2 = tcg_temp_local_new_i64();                                   \
6725 6726 6727 6728
    tcg_gen_trunc_i64_i32(t0, cpu_gpr[rA(ctx->opcode)]);                      \
    tcg_opi(t0, t0, rB(ctx->opcode));                                         \
    tcg_gen_shri_i64(t2, cpu_gpr[rA(ctx->opcode)], 32);                       \
    tcg_gen_trunc_i64_i32(t1, t2);                                            \
P
pbrook 已提交
6729
    tcg_temp_free_i64(t2);                                                    \
6730 6731
    tcg_opi(t1, t1, rB(ctx->opcode));                                         \
    tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1);                 \
P
pbrook 已提交
6732 6733
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
6734
}
6735 6736
#else
#define GEN_SPEOP_TCG_LOGIC_IMM2(name, tcg_opi)                               \
6737
static always_inline void gen_##name (DisasContext *ctx)                      \
6738 6739
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
6740
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6741 6742
        return;                                                               \
    }                                                                         \
6743 6744 6745 6746
    tcg_opi(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],               \
            rB(ctx->opcode));                                                 \
    tcg_opi(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)],             \
            rB(ctx->opcode));                                                 \
6747
}
6748 6749 6750 6751 6752
#endif
GEN_SPEOP_TCG_LOGIC_IMM2(evslwi, tcg_gen_shli_i32);
GEN_SPEOP_TCG_LOGIC_IMM2(evsrwiu, tcg_gen_shri_i32);
GEN_SPEOP_TCG_LOGIC_IMM2(evsrwis, tcg_gen_sari_i32);
GEN_SPEOP_TCG_LOGIC_IMM2(evrlwi, tcg_gen_rotli_i32);
6753

6754 6755 6756
/* SPE arithmetic */
#if defined(TARGET_PPC64)
#define GEN_SPEOP_ARITH1(name, tcg_op)                                        \
6757
static always_inline void gen_##name (DisasContext *ctx)                      \
6758 6759
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
6760
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6761 6762
        return;                                                               \
    }                                                                         \
P
pbrook 已提交
6763 6764 6765
    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
    TCGv_i64 t2 = tcg_temp_local_new_i64();                                   \
6766 6767 6768 6769
    tcg_gen_trunc_i64_i32(t0, cpu_gpr[rA(ctx->opcode)]);                      \
    tcg_op(t0, t0);                                                           \
    tcg_gen_shri_i64(t2, cpu_gpr[rA(ctx->opcode)], 32);                       \
    tcg_gen_trunc_i64_i32(t1, t2);                                            \
P
pbrook 已提交
6770
    tcg_temp_free_i64(t2);                                                    \
6771 6772
    tcg_op(t1, t1);                                                           \
    tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1);                 \
P
pbrook 已提交
6773 6774
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
6775
}
6776
#else
P
pbrook 已提交
6777
#define GEN_SPEOP_ARITH1(name, tcg_op)                                        \
6778 6779 6780
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
6781
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6782 6783 6784 6785 6786 6787
        return;                                                               \
    }                                                                         \
    tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);               \
    tcg_op(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]);             \
}
#endif
6788

P
pbrook 已提交
6789
static always_inline void gen_op_evabs (TCGv_i32 ret, TCGv_i32 arg1)
6790 6791 6792
{
    int l1 = gen_new_label();
    int l2 = gen_new_label();
6793

6794 6795 6796 6797
    tcg_gen_brcondi_i32(TCG_COND_GE, arg1, 0, l1);
    tcg_gen_neg_i32(ret, arg1);
    tcg_gen_br(l2);
    gen_set_label(l1);
P
pbrook 已提交
6798
    tcg_gen_mov_i32(ret, arg1);
6799 6800 6801 6802 6803 6804
    gen_set_label(l2);
}
GEN_SPEOP_ARITH1(evabs, gen_op_evabs);
GEN_SPEOP_ARITH1(evneg, tcg_gen_neg_i32);
GEN_SPEOP_ARITH1(evextsb, tcg_gen_ext8s_i32);
GEN_SPEOP_ARITH1(evextsh, tcg_gen_ext16s_i32);
P
pbrook 已提交
6805
static always_inline void gen_op_evrndw (TCGv_i32 ret, TCGv_i32 arg1)
6806
{
6807 6808 6809 6810
    tcg_gen_addi_i32(ret, arg1, 0x8000);
    tcg_gen_ext16u_i32(ret, ret);
}
GEN_SPEOP_ARITH1(evrndw, gen_op_evrndw);
P
pbrook 已提交
6811 6812
GEN_SPEOP_ARITH1(evcntlsw, gen_helper_cntlsw32);
GEN_SPEOP_ARITH1(evcntlzw, gen_helper_cntlzw32);
6813

6814 6815 6816
#if defined(TARGET_PPC64)
#define GEN_SPEOP_ARITH2(name, tcg_op)                                        \
static always_inline void gen_##name (DisasContext *ctx)                      \
6817 6818
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
6819
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6820 6821
        return;                                                               \
    }                                                                         \
P
pbrook 已提交
6822 6823 6824
    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t2 = tcg_temp_local_new_i32();                                   \
6825
    TCGv_i64 t3 = tcg_temp_local_new_i64();                                   \
6826 6827 6828 6829 6830 6831 6832
    tcg_gen_trunc_i64_i32(t0, cpu_gpr[rA(ctx->opcode)]);                      \
    tcg_gen_trunc_i64_i32(t2, cpu_gpr[rB(ctx->opcode)]);                      \
    tcg_op(t0, t0, t2);                                                       \
    tcg_gen_shri_i64(t3, cpu_gpr[rA(ctx->opcode)], 32);                       \
    tcg_gen_trunc_i64_i32(t1, t3);                                            \
    tcg_gen_shri_i64(t3, cpu_gpr[rB(ctx->opcode)], 32);                       \
    tcg_gen_trunc_i64_i32(t2, t3);                                            \
P
pbrook 已提交
6833
    tcg_temp_free_i64(t3);                                                    \
6834
    tcg_op(t1, t1, t2);                                                       \
P
pbrook 已提交
6835
    tcg_temp_free_i32(t2);                                                    \
6836
    tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1);                 \
P
pbrook 已提交
6837 6838
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
6839
}
6840 6841 6842
#else
#define GEN_SPEOP_ARITH2(name, tcg_op)                                        \
static always_inline void gen_##name (DisasContext *ctx)                      \
6843 6844
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
6845
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6846 6847
        return;                                                               \
    }                                                                         \
6848 6849 6850 6851
    tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],                \
           cpu_gpr[rB(ctx->opcode)]);                                         \
    tcg_op(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)],              \
           cpu_gprh[rB(ctx->opcode)]);                                        \
6852
}
6853
#endif
6854

P
pbrook 已提交
6855
static always_inline void gen_op_evsrwu (TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
6856
{
P
pbrook 已提交
6857
    TCGv_i32 t0;
6858
    int l1, l2;
6859

6860 6861
    l1 = gen_new_label();
    l2 = gen_new_label();
P
pbrook 已提交
6862
    t0 = tcg_temp_local_new_i32();
6863 6864 6865 6866 6867 6868 6869 6870
    /* No error here: 6 bits are used */
    tcg_gen_andi_i32(t0, arg2, 0x3F);
    tcg_gen_brcondi_i32(TCG_COND_GE, t0, 32, l1);
    tcg_gen_shr_i32(ret, arg1, t0);
    tcg_gen_br(l2);
    gen_set_label(l1);
    tcg_gen_movi_i32(ret, 0);
    tcg_gen_br(l2);
P
pbrook 已提交
6871
    tcg_temp_free_i32(t0);
6872 6873
}
GEN_SPEOP_ARITH2(evsrwu, gen_op_evsrwu);
P
pbrook 已提交
6874
static always_inline void gen_op_evsrws (TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
6875
{
P
pbrook 已提交
6876
    TCGv_i32 t0;
6877 6878 6879 6880
    int l1, l2;

    l1 = gen_new_label();
    l2 = gen_new_label();
P
pbrook 已提交
6881
    t0 = tcg_temp_local_new_i32();
6882 6883 6884 6885 6886 6887 6888 6889
    /* No error here: 6 bits are used */
    tcg_gen_andi_i32(t0, arg2, 0x3F);
    tcg_gen_brcondi_i32(TCG_COND_GE, t0, 32, l1);
    tcg_gen_sar_i32(ret, arg1, t0);
    tcg_gen_br(l2);
    gen_set_label(l1);
    tcg_gen_movi_i32(ret, 0);
    tcg_gen_br(l2);
P
pbrook 已提交
6890
    tcg_temp_free_i32(t0);
6891 6892
}
GEN_SPEOP_ARITH2(evsrws, gen_op_evsrws);
P
pbrook 已提交
6893
static always_inline void gen_op_evslw (TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
6894
{
P
pbrook 已提交
6895
    TCGv_i32 t0;
6896 6897 6898 6899
    int l1, l2;

    l1 = gen_new_label();
    l2 = gen_new_label();
P
pbrook 已提交
6900
    t0 = tcg_temp_local_new_i32();
6901 6902 6903 6904 6905 6906 6907 6908
    /* No error here: 6 bits are used */
    tcg_gen_andi_i32(t0, arg2, 0x3F);
    tcg_gen_brcondi_i32(TCG_COND_GE, t0, 32, l1);
    tcg_gen_shl_i32(ret, arg1, t0);
    tcg_gen_br(l2);
    gen_set_label(l1);
    tcg_gen_movi_i32(ret, 0);
    tcg_gen_br(l2);
P
pbrook 已提交
6909
    tcg_temp_free_i32(t0);
6910 6911
}
GEN_SPEOP_ARITH2(evslw, gen_op_evslw);
P
pbrook 已提交
6912
static always_inline void gen_op_evrlw (TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
6913
{
P
pbrook 已提交
6914
    TCGv_i32 t0 = tcg_temp_new_i32();
6915 6916
    tcg_gen_andi_i32(t0, arg2, 0x1F);
    tcg_gen_rotl_i32(ret, arg1, t0);
P
pbrook 已提交
6917
    tcg_temp_free_i32(t0);
6918 6919 6920 6921 6922
}
GEN_SPEOP_ARITH2(evrlw, gen_op_evrlw);
static always_inline void gen_evmergehi (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
A
aurel32 已提交
6923
        gen_exception(ctx, POWERPC_EXCP_APU);
6924 6925 6926
        return;
    }
#if defined(TARGET_PPC64)
P
pbrook 已提交
6927 6928
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939
    tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 32);
    tcg_gen_andi_tl(t1, cpu_gpr[rA(ctx->opcode)], 0xFFFFFFFF0000000ULL);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], t0, t1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
#else
    tcg_gen_mov_i32(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]);
    tcg_gen_mov_i32(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]);
#endif
}
GEN_SPEOP_ARITH2(evaddw, tcg_gen_add_i32);
P
pbrook 已提交
6940
static always_inline void gen_op_evsubf (TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
6941
{
6942 6943 6944
    tcg_gen_sub_i32(ret, arg2, arg1);
}
GEN_SPEOP_ARITH2(evsubfw, gen_op_evsubf);
6945

6946 6947 6948 6949 6950 6951
/* SPE arithmetic immediate */
#if defined(TARGET_PPC64)
#define GEN_SPEOP_ARITH_IMM2(name, tcg_op)                                    \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
6952
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6953 6954
        return;                                                               \
    }                                                                         \
P
pbrook 已提交
6955 6956 6957
    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
    TCGv_i64 t2 = tcg_temp_local_new_i64();                                   \
6958 6959 6960 6961
    tcg_gen_trunc_i64_i32(t0, cpu_gpr[rB(ctx->opcode)]);                      \
    tcg_op(t0, t0, rA(ctx->opcode));                                          \
    tcg_gen_shri_i64(t2, cpu_gpr[rB(ctx->opcode)], 32);                       \
    tcg_gen_trunc_i64_i32(t1, t2);                                            \
A
aurel32 已提交
6962
    tcg_temp_free_i64(t2);                                                    \
6963 6964
    tcg_op(t1, t1, rA(ctx->opcode));                                          \
    tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1);                 \
P
pbrook 已提交
6965 6966
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
6967 6968 6969 6970 6971 6972
}
#else
#define GEN_SPEOP_ARITH_IMM2(name, tcg_op)                                    \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
6973
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 6987 6988 6989 6990
        return;                                                               \
    }                                                                         \
    tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],                \
           rA(ctx->opcode));                                                  \
    tcg_op(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)],              \
           rA(ctx->opcode));                                                  \
}
#endif
GEN_SPEOP_ARITH_IMM2(evaddiw, tcg_gen_addi_i32);
GEN_SPEOP_ARITH_IMM2(evsubifw, tcg_gen_subi_i32);

/* SPE comparison */
#if defined(TARGET_PPC64)
#define GEN_SPEOP_COMP(name, tcg_cond)                                        \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
6991
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6992 6993 6994 6995 6996 6997
        return;                                                               \
    }                                                                         \
    int l1 = gen_new_label();                                                 \
    int l2 = gen_new_label();                                                 \
    int l3 = gen_new_label();                                                 \
    int l4 = gen_new_label();                                                 \
P
pbrook 已提交
6998 6999 7000
    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
    TCGv_i64 t2 = tcg_temp_local_new_i64();                                   \
7001 7002 7003
    tcg_gen_trunc_i64_i32(t0, cpu_gpr[rA(ctx->opcode)]);                      \
    tcg_gen_trunc_i64_i32(t1, cpu_gpr[rB(ctx->opcode)]);                      \
    tcg_gen_brcond_i32(tcg_cond, t0, t1, l1);                                 \
P
pbrook 已提交
7004
    tcg_gen_movi_i32(cpu_crf[crfD(ctx->opcode)], 0);                          \
7005 7006 7007 7008 7009 7010 7011 7012 7013
    tcg_gen_br(l2);                                                           \
    gen_set_label(l1);                                                        \
    tcg_gen_movi_i32(cpu_crf[crfD(ctx->opcode)],                              \
                     CRF_CL | CRF_CH_OR_CL | CRF_CH_AND_CL);                  \
    gen_set_label(l2);                                                        \
    tcg_gen_shri_i64(t2, cpu_gpr[rA(ctx->opcode)], 32);                       \
    tcg_gen_trunc_i64_i32(t0, t2);                                            \
    tcg_gen_shri_i64(t2, cpu_gpr[rB(ctx->opcode)], 32);                       \
    tcg_gen_trunc_i64_i32(t1, t2);                                            \
P
pbrook 已提交
7014
    tcg_temp_free_i64(t2);                                                    \
7015 7016 7017 7018 7019 7020 7021 7022
    tcg_gen_brcond_i32(tcg_cond, t0, t1, l3);                                 \
    tcg_gen_andi_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)],  \
                     ~(CRF_CH | CRF_CH_AND_CL));                              \
    tcg_gen_br(l4);                                                           \
    gen_set_label(l3);                                                        \
    tcg_gen_ori_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)],   \
                    CRF_CH | CRF_CH_OR_CL);                                   \
    gen_set_label(l4);                                                        \
P
pbrook 已提交
7023 7024
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
7025 7026 7027 7028 7029 7030
}
#else
#define GEN_SPEOP_COMP(name, tcg_cond)                                        \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
7031
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066 7067
        return;                                                               \
    }                                                                         \
    int l1 = gen_new_label();                                                 \
    int l2 = gen_new_label();                                                 \
    int l3 = gen_new_label();                                                 \
    int l4 = gen_new_label();                                                 \
                                                                              \
    tcg_gen_brcond_i32(tcg_cond, cpu_gpr[rA(ctx->opcode)],                    \
                       cpu_gpr[rB(ctx->opcode)], l1);                         \
    tcg_gen_movi_tl(cpu_crf[crfD(ctx->opcode)], 0);                           \
    tcg_gen_br(l2);                                                           \
    gen_set_label(l1);                                                        \
    tcg_gen_movi_i32(cpu_crf[crfD(ctx->opcode)],                              \
                     CRF_CL | CRF_CH_OR_CL | CRF_CH_AND_CL);                  \
    gen_set_label(l2);                                                        \
    tcg_gen_brcond_i32(tcg_cond, cpu_gprh[rA(ctx->opcode)],                   \
                       cpu_gprh[rB(ctx->opcode)], l3);                        \
    tcg_gen_andi_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)],  \
                     ~(CRF_CH | CRF_CH_AND_CL));                              \
    tcg_gen_br(l4);                                                           \
    gen_set_label(l3);                                                        \
    tcg_gen_ori_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)],   \
                    CRF_CH | CRF_CH_OR_CL);                                   \
    gen_set_label(l4);                                                        \
}
#endif
GEN_SPEOP_COMP(evcmpgtu, TCG_COND_GTU);
GEN_SPEOP_COMP(evcmpgts, TCG_COND_GT);
GEN_SPEOP_COMP(evcmpltu, TCG_COND_LTU);
GEN_SPEOP_COMP(evcmplts, TCG_COND_LT);
GEN_SPEOP_COMP(evcmpeq, TCG_COND_EQ);

/* SPE misc */
static always_inline void gen_brinc (DisasContext *ctx)
{
    /* Note: brinc is usable even if SPE is disabled */
P
pbrook 已提交
7068 7069
    gen_helper_brinc(cpu_gpr[rD(ctx->opcode)],
                     cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
7070
}
7071 7072 7073
static always_inline void gen_evmergelo (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
A
aurel32 已提交
7074
        gen_exception(ctx, POWERPC_EXCP_APU);
7075 7076 7077
        return;
    }
#if defined(TARGET_PPC64)
P
pbrook 已提交
7078 7079
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
7080 7081 7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x00000000FFFFFFFFLL);
    tcg_gen_shli_tl(t1, cpu_gpr[rA(ctx->opcode)], 32);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], t0, t1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
#else
    tcg_gen_mov_i32(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
    tcg_gen_mov_i32(cpu_gprh[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
#endif
}
static always_inline void gen_evmergehilo (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
A
aurel32 已提交
7093
        gen_exception(ctx, POWERPC_EXCP_APU);
7094 7095 7096
        return;
    }
#if defined(TARGET_PPC64)
P
pbrook 已提交
7097 7098
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
7099 7100 7101 7102 7103 7104 7105 7106 7107 7108 7109 7110 7111
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x00000000FFFFFFFFLL);
    tcg_gen_andi_tl(t1, cpu_gpr[rA(ctx->opcode)], 0xFFFFFFFF0000000ULL);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], t0, t1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
#else
    tcg_gen_mov_i32(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
    tcg_gen_mov_i32(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]);
#endif
}
static always_inline void gen_evmergelohi (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
A
aurel32 已提交
7112
        gen_exception(ctx, POWERPC_EXCP_APU);
7113 7114 7115
        return;
    }
#if defined(TARGET_PPC64)
P
pbrook 已提交
7116 7117
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
7118 7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129
    tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 32);
    tcg_gen_shli_tl(t1, cpu_gpr[rA(ctx->opcode)], 32);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], t0, t1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
#else
    tcg_gen_mov_i32(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]);
    tcg_gen_mov_i32(cpu_gprh[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
#endif
}
static always_inline void gen_evsplati (DisasContext *ctx)
{
7130
    uint64_t imm = ((int32_t)(rA(ctx->opcode) << 11)) >> 27;
7131

7132
#if defined(TARGET_PPC64)
7133
    tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], (imm << 32) | imm);
7134 7135 7136 7137 7138
#else
    tcg_gen_movi_i32(cpu_gpr[rD(ctx->opcode)], imm);
    tcg_gen_movi_i32(cpu_gprh[rD(ctx->opcode)], imm);
#endif
}
7139
static always_inline void gen_evsplatfi (DisasContext *ctx)
7140
{
7141
    uint64_t imm = rA(ctx->opcode) << 11;
7142

7143
#if defined(TARGET_PPC64)
7144
    tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], (imm << 32) | imm);
7145 7146 7147 7148
#else
    tcg_gen_movi_i32(cpu_gpr[rD(ctx->opcode)], imm);
    tcg_gen_movi_i32(cpu_gprh[rD(ctx->opcode)], imm);
#endif
7149 7150
}

7151 7152 7153 7154 7155 7156
static always_inline void gen_evsel (DisasContext *ctx)
{
    int l1 = gen_new_label();
    int l2 = gen_new_label();
    int l3 = gen_new_label();
    int l4 = gen_new_label();
P
pbrook 已提交
7157
    TCGv_i32 t0 = tcg_temp_local_new_i32();
7158
#if defined(TARGET_PPC64)
P
pbrook 已提交
7159 7160
    TCGv t1 = tcg_temp_local_new();
    TCGv t2 = tcg_temp_local_new();
7161 7162 7163 7164 7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 7182 7183 7184 7185 7186 7187 7188 7189 7190 7191
#endif
    tcg_gen_andi_i32(t0, cpu_crf[ctx->opcode & 0x07], 1 << 3);
    tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l1);
#if defined(TARGET_PPC64)
    tcg_gen_andi_tl(t1, cpu_gpr[rA(ctx->opcode)], 0xFFFFFFFF00000000ULL);
#else
    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]);
#endif
    tcg_gen_br(l2);
    gen_set_label(l1);
#if defined(TARGET_PPC64)
    tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0xFFFFFFFF00000000ULL);
#else
    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)]);
#endif
    gen_set_label(l2);
    tcg_gen_andi_i32(t0, cpu_crf[ctx->opcode & 0x07], 1 << 2);
    tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l3);
#if defined(TARGET_PPC64)
    tcg_gen_andi_tl(t2, cpu_gpr[rA(ctx->opcode)], 0x00000000FFFFFFFFULL);
#else
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
#endif
    tcg_gen_br(l4);
    gen_set_label(l3);
#if defined(TARGET_PPC64)
    tcg_gen_andi_tl(t2, cpu_gpr[rB(ctx->opcode)], 0x00000000FFFFFFFFULL);
#else
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
#endif
    gen_set_label(l4);
P
pbrook 已提交
7192
    tcg_temp_free_i32(t0);
7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212 7213 7214
#if defined(TARGET_PPC64)
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], t1, t2);
    tcg_temp_free(t1);
    tcg_temp_free(t2);
#endif
}
GEN_HANDLER2(evsel0, "evsel", 0x04, 0x1c, 0x09, 0x00000000, PPC_SPE)
{
    gen_evsel(ctx);
}
GEN_HANDLER2(evsel1, "evsel", 0x04, 0x1d, 0x09, 0x00000000, PPC_SPE)
{
    gen_evsel(ctx);
}
GEN_HANDLER2(evsel2, "evsel", 0x04, 0x1e, 0x09, 0x00000000, PPC_SPE)
{
    gen_evsel(ctx);
}
GEN_HANDLER2(evsel3, "evsel", 0x04, 0x1f, 0x09, 0x00000000, PPC_SPE)
{
    gen_evsel(ctx);
}
7215 7216 7217 7218 7219 7220 7221 7222 7223 7224 7225 7226 7227 7228 7229 7230 7231 7232 7233 7234 7235 7236 7237 7238 7239 7240 7241

GEN_SPE(evaddw,         speundef,      0x00, 0x08, 0x00000000, PPC_SPE); ////
GEN_SPE(evaddiw,        speundef,      0x01, 0x08, 0x00000000, PPC_SPE);
GEN_SPE(evsubfw,        speundef,      0x02, 0x08, 0x00000000, PPC_SPE); ////
GEN_SPE(evsubifw,       speundef,      0x03, 0x08, 0x00000000, PPC_SPE);
GEN_SPE(evabs,          evneg,         0x04, 0x08, 0x0000F800, PPC_SPE); ////
GEN_SPE(evextsb,        evextsh,       0x05, 0x08, 0x0000F800, PPC_SPE); ////
GEN_SPE(evrndw,         evcntlzw,      0x06, 0x08, 0x0000F800, PPC_SPE); ////
GEN_SPE(evcntlsw,       brinc,         0x07, 0x08, 0x00000000, PPC_SPE); //
GEN_SPE(speundef,       evand,         0x08, 0x08, 0x00000000, PPC_SPE); ////
GEN_SPE(evandc,         speundef,      0x09, 0x08, 0x00000000, PPC_SPE); ////
GEN_SPE(evxor,          evor,          0x0B, 0x08, 0x00000000, PPC_SPE); ////
GEN_SPE(evnor,          eveqv,         0x0C, 0x08, 0x00000000, PPC_SPE); ////
GEN_SPE(speundef,       evorc,         0x0D, 0x08, 0x00000000, PPC_SPE); ////
GEN_SPE(evnand,         speundef,      0x0F, 0x08, 0x00000000, PPC_SPE); ////
GEN_SPE(evsrwu,         evsrws,        0x10, 0x08, 0x00000000, PPC_SPE); ////
GEN_SPE(evsrwiu,        evsrwis,       0x11, 0x08, 0x00000000, PPC_SPE);
GEN_SPE(evslw,          speundef,      0x12, 0x08, 0x00000000, PPC_SPE); ////
GEN_SPE(evslwi,         speundef,      0x13, 0x08, 0x00000000, PPC_SPE);
GEN_SPE(evrlw,          evsplati,      0x14, 0x08, 0x00000000, PPC_SPE); //
GEN_SPE(evrlwi,         evsplatfi,     0x15, 0x08, 0x00000000, PPC_SPE);
GEN_SPE(evmergehi,      evmergelo,     0x16, 0x08, 0x00000000, PPC_SPE); ////
GEN_SPE(evmergehilo,    evmergelohi,   0x17, 0x08, 0x00000000, PPC_SPE); ////
GEN_SPE(evcmpgtu,       evcmpgts,      0x18, 0x08, 0x00600000, PPC_SPE); ////
GEN_SPE(evcmpltu,       evcmplts,      0x19, 0x08, 0x00600000, PPC_SPE); ////
GEN_SPE(evcmpeq,        speundef,      0x1A, 0x08, 0x00600000, PPC_SPE); ////

7242
/* SPE load and stores */
A
aurel32 已提交
7243
static always_inline void gen_addr_spe_imm_index (DisasContext *ctx, TCGv EA, int sh)
7244 7245 7246
{
    target_ulong uimm = rB(ctx->opcode);

A
aurel32 已提交
7247
    if (rA(ctx->opcode) == 0) {
7248
        tcg_gen_movi_tl(EA, uimm << sh);
A
aurel32 已提交
7249
    } else {
7250
        tcg_gen_addi_tl(EA, cpu_gpr[rA(ctx->opcode)], uimm << sh);
A
aurel32 已提交
7251 7252 7253 7254 7255 7256
#if defined(TARGET_PPC64)
        if (!ctx->sf_mode) {
            tcg_gen_ext32u_tl(EA, EA);
        }
#endif
    }
7257
}
7258 7259 7260 7261

static always_inline void gen_op_evldd(DisasContext *ctx, TCGv addr)
{
#if defined(TARGET_PPC64)
A
aurel32 已提交
7262
    gen_qemu_ld64(ctx, cpu_gpr[rD(ctx->opcode)], addr);
7263 7264
#else
    TCGv_i64 t0 = tcg_temp_new_i64();
A
aurel32 已提交
7265
    gen_qemu_ld64(ctx, t0, addr);
7266 7267 7268 7269 7270
    tcg_gen_trunc_i64_i32(cpu_gpr[rD(ctx->opcode)], t0);
    tcg_gen_shri_i64(t0, t0, 32);
    tcg_gen_trunc_i64_i32(cpu_gprh[rD(ctx->opcode)], t0);
    tcg_temp_free_i64(t0);
#endif
7271
}
7272 7273 7274

static always_inline void gen_op_evldw(DisasContext *ctx, TCGv addr)
{
7275
#if defined(TARGET_PPC64)
7276
    TCGv t0 = tcg_temp_new();
A
aurel32 已提交
7277
    gen_qemu_ld32u(ctx, t0, addr);
7278
    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 32);
A
aurel32 已提交
7279 7280
    gen_addr_add(ctx, addr, addr, 4);
    gen_qemu_ld32u(ctx, t0, addr);
7281 7282 7283
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
    tcg_temp_free(t0);
#else
A
aurel32 已提交
7284 7285 7286
    gen_qemu_ld32u(ctx, cpu_gprh[rD(ctx->opcode)], addr);
    gen_addr_add(ctx, addr, addr, 4);
    gen_qemu_ld32u(ctx, cpu_gpr[rD(ctx->opcode)], addr);
7287
#endif
7288
}
7289 7290 7291 7292 7293

static always_inline void gen_op_evldh(DisasContext *ctx, TCGv addr)
{
    TCGv t0 = tcg_temp_new();
#if defined(TARGET_PPC64)
A
aurel32 已提交
7294
    gen_qemu_ld16u(ctx, t0, addr);
7295
    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 48);
A
aurel32 已提交
7296 7297
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, t0, addr);
7298 7299
    tcg_gen_shli_tl(t0, t0, 32);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
A
aurel32 已提交
7300 7301
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, t0, addr);
7302 7303
    tcg_gen_shli_tl(t0, t0, 16);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
A
aurel32 已提交
7304 7305
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, t0, addr);
7306
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
7307
#else
A
aurel32 已提交
7308
    gen_qemu_ld16u(ctx, t0, addr);
7309
    tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16);
A
aurel32 已提交
7310 7311
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, t0, addr);
7312
    tcg_gen_or_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rD(ctx->opcode)], t0);
A
aurel32 已提交
7313 7314
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, t0, addr);
7315
    tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16);
A
aurel32 已提交
7316 7317
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, t0, addr);
7318
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
7319
#endif
7320
    tcg_temp_free(t0);
7321 7322
}

7323 7324 7325
static always_inline void gen_op_evlhhesplat(DisasContext *ctx, TCGv addr)
{
    TCGv t0 = tcg_temp_new();
A
aurel32 已提交
7326
    gen_qemu_ld16u(ctx, t0, addr);
7327 7328 7329 7330 7331 7332 7333 7334 7335 7336
#if defined(TARGET_PPC64)
    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 48);
    tcg_gen_shli_tl(t0, t0, 16);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
#else
    tcg_gen_shli_tl(t0, t0, 16);
    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0);
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0);
#endif
    tcg_temp_free(t0);
7337 7338
}

7339 7340 7341
static always_inline void gen_op_evlhhousplat(DisasContext *ctx, TCGv addr)
{
    TCGv t0 = tcg_temp_new();
A
aurel32 已提交
7342
    gen_qemu_ld16u(ctx, t0, addr);
7343 7344 7345 7346 7347 7348 7349 7350
#if defined(TARGET_PPC64)
    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 32);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
#else
    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0);
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0);
#endif
    tcg_temp_free(t0);
7351 7352
}

7353 7354 7355
static always_inline void gen_op_evlhhossplat(DisasContext *ctx, TCGv addr)
{
    TCGv t0 = tcg_temp_new();
A
aurel32 已提交
7356
    gen_qemu_ld16s(ctx, t0, addr);
7357 7358 7359 7360 7361 7362 7363 7364 7365 7366 7367 7368 7369 7370 7371
#if defined(TARGET_PPC64)
    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 32);
    tcg_gen_ext32u_tl(t0, t0);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
#else
    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0);
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0);
#endif
    tcg_temp_free(t0);
}

static always_inline void gen_op_evlwhe(DisasContext *ctx, TCGv addr)
{
    TCGv t0 = tcg_temp_new();
#if defined(TARGET_PPC64)
A
aurel32 已提交
7372
    gen_qemu_ld16u(ctx, t0, addr);
7373
    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 48);
A
aurel32 已提交
7374 7375
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, t0, addr);
7376 7377 7378
    tcg_gen_shli_tl(t0, t0, 16);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
#else
A
aurel32 已提交
7379
    gen_qemu_ld16u(ctx, t0, addr);
7380
    tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16);
A
aurel32 已提交
7381 7382
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, t0, addr);
7383 7384 7385 7386 7387 7388 7389 7390 7391
    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 16);
#endif
    tcg_temp_free(t0);
}

static always_inline void gen_op_evlwhou(DisasContext *ctx, TCGv addr)
{
#if defined(TARGET_PPC64)
    TCGv t0 = tcg_temp_new();
A
aurel32 已提交
7392 7393 7394
    gen_qemu_ld16u(ctx, cpu_gpr[rD(ctx->opcode)], addr);
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, t0, addr);
7395 7396 7397 7398
    tcg_gen_shli_tl(t0, t0, 32);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
    tcg_temp_free(t0);
#else
A
aurel32 已提交
7399 7400 7401
    gen_qemu_ld16u(ctx, cpu_gprh[rD(ctx->opcode)], addr);
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, cpu_gpr[rD(ctx->opcode)], addr);
7402 7403 7404 7405 7406 7407 7408
#endif
}

static always_inline void gen_op_evlwhos(DisasContext *ctx, TCGv addr)
{
#if defined(TARGET_PPC64)
    TCGv t0 = tcg_temp_new();
A
aurel32 已提交
7409
    gen_qemu_ld16s(ctx, t0, addr);
7410
    tcg_gen_ext32u_tl(cpu_gpr[rD(ctx->opcode)], t0);
A
aurel32 已提交
7411 7412
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16s(ctx, t0, addr);
7413 7414 7415 7416
    tcg_gen_shli_tl(t0, t0, 32);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
    tcg_temp_free(t0);
#else
A
aurel32 已提交
7417 7418 7419
    gen_qemu_ld16s(ctx, cpu_gprh[rD(ctx->opcode)], addr);
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16s(ctx, cpu_gpr[rD(ctx->opcode)], addr);
7420 7421 7422 7423 7424 7425
#endif
}

static always_inline void gen_op_evlwwsplat(DisasContext *ctx, TCGv addr)
{
    TCGv t0 = tcg_temp_new();
A
aurel32 已提交
7426
    gen_qemu_ld32u(ctx, t0, addr);
7427
#if defined(TARGET_PPC64)
7428 7429 7430 7431 7432 7433 7434 7435 7436 7437 7438 7439 7440
    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 32);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
#else
    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0);
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0);
#endif
    tcg_temp_free(t0);
}

static always_inline void gen_op_evlwhsplat(DisasContext *ctx, TCGv addr)
{
    TCGv t0 = tcg_temp_new();
#if defined(TARGET_PPC64)
A
aurel32 已提交
7441
    gen_qemu_ld16u(ctx, t0, addr);
7442 7443 7444
    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 48);
    tcg_gen_shli_tl(t0, t0, 32);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
A
aurel32 已提交
7445 7446
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, t0, addr);
7447 7448 7449 7450
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
    tcg_gen_shli_tl(t0, t0, 16);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
#else
A
aurel32 已提交
7451
    gen_qemu_ld16u(ctx, t0, addr);
7452 7453
    tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16);
    tcg_gen_or_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rD(ctx->opcode)], t0);
A
aurel32 已提交
7454 7455
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, t0, addr);
7456 7457
    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 16);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gprh[rD(ctx->opcode)], t0);
7458
#endif
7459 7460 7461 7462 7463 7464
    tcg_temp_free(t0);
}

static always_inline void gen_op_evstdd(DisasContext *ctx, TCGv addr)
{
#if defined(TARGET_PPC64)
A
aurel32 已提交
7465
    gen_qemu_st64(ctx, cpu_gpr[rS(ctx->opcode)], addr);
7466
#else
7467 7468
    TCGv_i64 t0 = tcg_temp_new_i64();
    tcg_gen_concat_i32_i64(t0, cpu_gpr[rS(ctx->opcode)], cpu_gprh[rS(ctx->opcode)]);
A
aurel32 已提交
7469
    gen_qemu_st64(ctx, t0, addr);
7470 7471 7472 7473 7474 7475
    tcg_temp_free_i64(t0);
#endif
}

static always_inline void gen_op_evstdw(DisasContext *ctx, TCGv addr)
{
7476
#if defined(TARGET_PPC64)
7477 7478
    TCGv t0 = tcg_temp_new();
    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 32);
A
aurel32 已提交
7479
    gen_qemu_st32(ctx, t0, addr);
7480 7481
    tcg_temp_free(t0);
#else
A
aurel32 已提交
7482
    gen_qemu_st32(ctx, cpu_gprh[rS(ctx->opcode)], addr);
7483
#endif
A
aurel32 已提交
7484 7485
    gen_addr_add(ctx, addr, addr, 4);
    gen_qemu_st32(ctx, cpu_gpr[rS(ctx->opcode)], addr);
7486 7487 7488 7489 7490 7491 7492 7493 7494 7495
}

static always_inline void gen_op_evstdh(DisasContext *ctx, TCGv addr)
{
    TCGv t0 = tcg_temp_new();
#if defined(TARGET_PPC64)
    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 48);
#else
    tcg_gen_shri_tl(t0, cpu_gprh[rS(ctx->opcode)], 16);
#endif
A
aurel32 已提交
7496 7497
    gen_qemu_st16(ctx, t0, addr);
    gen_addr_add(ctx, addr, addr, 2);
7498 7499
#if defined(TARGET_PPC64)
    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 32);
A
aurel32 已提交
7500
    gen_qemu_st16(ctx, t0, addr);
7501
#else
A
aurel32 已提交
7502
    gen_qemu_st16(ctx, cpu_gprh[rS(ctx->opcode)], addr);
7503
#endif
A
aurel32 已提交
7504
    gen_addr_add(ctx, addr, addr, 2);
7505
    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 16);
A
aurel32 已提交
7506
    gen_qemu_st16(ctx, t0, addr);
7507
    tcg_temp_free(t0);
A
aurel32 已提交
7508 7509
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_st16(ctx, cpu_gpr[rS(ctx->opcode)], addr);
7510 7511 7512 7513 7514 7515 7516 7517 7518 7519
}

static always_inline void gen_op_evstwhe(DisasContext *ctx, TCGv addr)
{
    TCGv t0 = tcg_temp_new();
#if defined(TARGET_PPC64)
    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 48);
#else
    tcg_gen_shri_tl(t0, cpu_gprh[rS(ctx->opcode)], 16);
#endif
A
aurel32 已提交
7520 7521
    gen_qemu_st16(ctx, t0, addr);
    gen_addr_add(ctx, addr, addr, 2);
7522
    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 16);
A
aurel32 已提交
7523
    gen_qemu_st16(ctx, t0, addr);
7524 7525 7526 7527 7528 7529 7530 7531
    tcg_temp_free(t0);
}

static always_inline void gen_op_evstwho(DisasContext *ctx, TCGv addr)
{
#if defined(TARGET_PPC64)
    TCGv t0 = tcg_temp_new();
    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 32);
A
aurel32 已提交
7532
    gen_qemu_st16(ctx, t0, addr);
7533 7534
    tcg_temp_free(t0);
#else
A
aurel32 已提交
7535
    gen_qemu_st16(ctx, cpu_gprh[rS(ctx->opcode)], addr);
7536
#endif
A
aurel32 已提交
7537 7538
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_st16(ctx, cpu_gpr[rS(ctx->opcode)], addr);
7539 7540 7541 7542 7543 7544 7545
}

static always_inline void gen_op_evstwwe(DisasContext *ctx, TCGv addr)
{
#if defined(TARGET_PPC64)
    TCGv t0 = tcg_temp_new();
    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 32);
A
aurel32 已提交
7546
    gen_qemu_st32(ctx, t0, addr);
7547 7548
    tcg_temp_free(t0);
#else
A
aurel32 已提交
7549
    gen_qemu_st32(ctx, cpu_gprh[rS(ctx->opcode)], addr);
7550 7551 7552 7553 7554
#endif
}

static always_inline void gen_op_evstwwo(DisasContext *ctx, TCGv addr)
{
A
aurel32 已提交
7555
    gen_qemu_st32(ctx, cpu_gpr[rS(ctx->opcode)], addr);
7556 7557 7558
}

#define GEN_SPEOP_LDST(name, opc2, sh)                                        \
A
aurel32 已提交
7559
GEN_HANDLER(name, 0x04, opc2, 0x0C, 0x00000000, PPC_SPE)                      \
7560 7561 7562
{                                                                             \
    TCGv t0;                                                                  \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
7563
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
7564 7565
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
7566
    gen_set_access_type(ctx, ACCESS_INT);                                     \
7567 7568
    t0 = tcg_temp_new();                                                      \
    if (Rc(ctx->opcode)) {                                                    \
A
aurel32 已提交
7569
        gen_addr_spe_imm_index(ctx, t0, sh);                                  \
7570
    } else {                                                                  \
A
aurel32 已提交
7571
        gen_addr_reg_index(ctx, t0);                                          \
7572 7573 7574 7575 7576 7577 7578 7579 7580 7581 7582 7583 7584 7585 7586 7587 7588 7589 7590 7591 7592 7593 7594 7595
    }                                                                         \
    gen_op_##name(ctx, t0);                                                   \
    tcg_temp_free(t0);                                                        \
}

GEN_SPEOP_LDST(evldd, 0x00, 3);
GEN_SPEOP_LDST(evldw, 0x01, 3);
GEN_SPEOP_LDST(evldh, 0x02, 3);
GEN_SPEOP_LDST(evlhhesplat, 0x04, 1);
GEN_SPEOP_LDST(evlhhousplat, 0x06, 1);
GEN_SPEOP_LDST(evlhhossplat, 0x07, 1);
GEN_SPEOP_LDST(evlwhe, 0x08, 2);
GEN_SPEOP_LDST(evlwhou, 0x0A, 2);
GEN_SPEOP_LDST(evlwhos, 0x0B, 2);
GEN_SPEOP_LDST(evlwwsplat, 0x0C, 2);
GEN_SPEOP_LDST(evlwhsplat, 0x0E, 2);

GEN_SPEOP_LDST(evstdd, 0x10, 3);
GEN_SPEOP_LDST(evstdw, 0x11, 3);
GEN_SPEOP_LDST(evstdh, 0x12, 3);
GEN_SPEOP_LDST(evstwhe, 0x18, 2);
GEN_SPEOP_LDST(evstwho, 0x1A, 2);
GEN_SPEOP_LDST(evstwwe, 0x1C, 2);
GEN_SPEOP_LDST(evstwwo, 0x1E, 2);
7596 7597 7598 7599 7600 7601 7602 7603 7604 7605 7606 7607 7608 7609 7610 7611 7612 7613 7614 7615 7616 7617 7618 7619 7620 7621 7622 7623 7624 7625 7626 7627 7628 7629 7630 7631 7632 7633 7634 7635 7636 7637 7638 7639 7640 7641 7642 7643 7644 7645 7646 7647 7648 7649 7650 7651 7652 7653 7654 7655 7656 7657 7658 7659 7660 7661 7662 7663 7664 7665 7666 7667 7668 7669 7670 7671 7672 7673

/* Multiply and add - TODO */
#if 0
GEN_SPE(speundef,       evmhessf,      0x01, 0x10, 0x00000000, PPC_SPE);
GEN_SPE(speundef,       evmhossf,      0x03, 0x10, 0x00000000, PPC_SPE);
GEN_SPE(evmheumi,       evmhesmi,      0x04, 0x10, 0x00000000, PPC_SPE);
GEN_SPE(speundef,       evmhesmf,      0x05, 0x10, 0x00000000, PPC_SPE);
GEN_SPE(evmhoumi,       evmhosmi,      0x06, 0x10, 0x00000000, PPC_SPE);
GEN_SPE(speundef,       evmhosmf,      0x07, 0x10, 0x00000000, PPC_SPE);
GEN_SPE(speundef,       evmhessfa,     0x11, 0x10, 0x00000000, PPC_SPE);
GEN_SPE(speundef,       evmhossfa,     0x13, 0x10, 0x00000000, PPC_SPE);
GEN_SPE(evmheumia,      evmhesmia,     0x14, 0x10, 0x00000000, PPC_SPE);
GEN_SPE(speundef,       evmhesmfa,     0x15, 0x10, 0x00000000, PPC_SPE);
GEN_SPE(evmhoumia,      evmhosmia,     0x16, 0x10, 0x00000000, PPC_SPE);
GEN_SPE(speundef,       evmhosmfa,     0x17, 0x10, 0x00000000, PPC_SPE);

GEN_SPE(speundef,       evmwhssf,      0x03, 0x11, 0x00000000, PPC_SPE);
GEN_SPE(evmwlumi,       speundef,      0x04, 0x11, 0x00000000, PPC_SPE);
GEN_SPE(evmwhumi,       evmwhsmi,      0x06, 0x11, 0x00000000, PPC_SPE);
GEN_SPE(speundef,       evmwhsmf,      0x07, 0x11, 0x00000000, PPC_SPE);
GEN_SPE(speundef,       evmwssf,       0x09, 0x11, 0x00000000, PPC_SPE);
GEN_SPE(evmwumi,        evmwsmi,       0x0C, 0x11, 0x00000000, PPC_SPE);
GEN_SPE(speundef,       evmwsmf,       0x0D, 0x11, 0x00000000, PPC_SPE);
GEN_SPE(speundef,       evmwhssfa,     0x13, 0x11, 0x00000000, PPC_SPE);
GEN_SPE(evmwlumia,      speundef,      0x14, 0x11, 0x00000000, PPC_SPE);
GEN_SPE(evmwhumia,      evmwhsmia,     0x16, 0x11, 0x00000000, PPC_SPE);
GEN_SPE(speundef,       evmwhsmfa,     0x17, 0x11, 0x00000000, PPC_SPE);
GEN_SPE(speundef,       evmwssfa,      0x19, 0x11, 0x00000000, PPC_SPE);
GEN_SPE(evmwumia,       evmwsmia,      0x1C, 0x11, 0x00000000, PPC_SPE);
GEN_SPE(speundef,       evmwsmfa,      0x1D, 0x11, 0x00000000, PPC_SPE);

GEN_SPE(evadduiaaw,     evaddsiaaw,    0x00, 0x13, 0x0000F800, PPC_SPE);
GEN_SPE(evsubfusiaaw,   evsubfssiaaw,  0x01, 0x13, 0x0000F800, PPC_SPE);
GEN_SPE(evaddumiaaw,    evaddsmiaaw,   0x04, 0x13, 0x0000F800, PPC_SPE);
GEN_SPE(evsubfumiaaw,   evsubfsmiaaw,  0x05, 0x13, 0x0000F800, PPC_SPE);
GEN_SPE(evdivws,        evdivwu,       0x06, 0x13, 0x00000000, PPC_SPE);
GEN_SPE(evmra,          speundef,      0x07, 0x13, 0x0000F800, PPC_SPE);

GEN_SPE(evmheusiaaw,    evmhessiaaw,   0x00, 0x14, 0x00000000, PPC_SPE);
GEN_SPE(speundef,       evmhessfaaw,   0x01, 0x14, 0x00000000, PPC_SPE);
GEN_SPE(evmhousiaaw,    evmhossiaaw,   0x02, 0x14, 0x00000000, PPC_SPE);
GEN_SPE(speundef,       evmhossfaaw,   0x03, 0x14, 0x00000000, PPC_SPE);
GEN_SPE(evmheumiaaw,    evmhesmiaaw,   0x04, 0x14, 0x00000000, PPC_SPE);
GEN_SPE(speundef,       evmhesmfaaw,   0x05, 0x14, 0x00000000, PPC_SPE);
GEN_SPE(evmhoumiaaw,    evmhosmiaaw,   0x06, 0x14, 0x00000000, PPC_SPE);
GEN_SPE(speundef,       evmhosmfaaw,   0x07, 0x14, 0x00000000, PPC_SPE);
GEN_SPE(evmhegumiaa,    evmhegsmiaa,   0x14, 0x14, 0x00000000, PPC_SPE);
GEN_SPE(speundef,       evmhegsmfaa,   0x15, 0x14, 0x00000000, PPC_SPE);
GEN_SPE(evmhogumiaa,    evmhogsmiaa,   0x16, 0x14, 0x00000000, PPC_SPE);
GEN_SPE(speundef,       evmhogsmfaa,   0x17, 0x14, 0x00000000, PPC_SPE);

GEN_SPE(evmwlusiaaw,    evmwlssiaaw,   0x00, 0x15, 0x00000000, PPC_SPE);
GEN_SPE(evmwlumiaaw,    evmwlsmiaaw,   0x04, 0x15, 0x00000000, PPC_SPE);
GEN_SPE(speundef,       evmwssfaa,     0x09, 0x15, 0x00000000, PPC_SPE);
GEN_SPE(evmwumiaa,      evmwsmiaa,     0x0C, 0x15, 0x00000000, PPC_SPE);
GEN_SPE(speundef,       evmwsmfaa,     0x0D, 0x15, 0x00000000, PPC_SPE);

GEN_SPE(evmheusianw,    evmhessianw,   0x00, 0x16, 0x00000000, PPC_SPE);
GEN_SPE(speundef,       evmhessfanw,   0x01, 0x16, 0x00000000, PPC_SPE);
GEN_SPE(evmhousianw,    evmhossianw,   0x02, 0x16, 0x00000000, PPC_SPE);
GEN_SPE(speundef,       evmhossfanw,   0x03, 0x16, 0x00000000, PPC_SPE);
GEN_SPE(evmheumianw,    evmhesmianw,   0x04, 0x16, 0x00000000, PPC_SPE);
GEN_SPE(speundef,       evmhesmfanw,   0x05, 0x16, 0x00000000, PPC_SPE);
GEN_SPE(evmhoumianw,    evmhosmianw,   0x06, 0x16, 0x00000000, PPC_SPE);
GEN_SPE(speundef,       evmhosmfanw,   0x07, 0x16, 0x00000000, PPC_SPE);
GEN_SPE(evmhegumian,    evmhegsmian,   0x14, 0x16, 0x00000000, PPC_SPE);
GEN_SPE(speundef,       evmhegsmfan,   0x15, 0x16, 0x00000000, PPC_SPE);
GEN_SPE(evmhigumian,    evmhigsmian,   0x16, 0x16, 0x00000000, PPC_SPE);
GEN_SPE(speundef,       evmhogsmfan,   0x17, 0x16, 0x00000000, PPC_SPE);

GEN_SPE(evmwlusianw,    evmwlssianw,   0x00, 0x17, 0x00000000, PPC_SPE);
GEN_SPE(evmwlumianw,    evmwlsmianw,   0x04, 0x17, 0x00000000, PPC_SPE);
GEN_SPE(speundef,       evmwssfan,     0x09, 0x17, 0x00000000, PPC_SPE);
GEN_SPE(evmwumian,      evmwsmian,     0x0C, 0x17, 0x00000000, PPC_SPE);
GEN_SPE(speundef,       evmwsmfan,     0x0D, 0x17, 0x00000000, PPC_SPE);
#endif

/***                      SPE floating-point extension                     ***/
A
aurel32 已提交
7674 7675
#if defined(TARGET_PPC64)
#define GEN_SPEFPUOP_CONV_32_32(name)                                         \
7676
static always_inline void gen_##name (DisasContext *ctx)                      \
7677
{                                                                             \
A
aurel32 已提交
7678 7679 7680 7681 7682 7683 7684 7685 7686 7687 7688 7689
    TCGv_i32 t0;                                                              \
    TCGv t1;                                                                  \
    t0 = tcg_temp_new_i32();                                                  \
    tcg_gen_trunc_tl_i32(t0, cpu_gpr[rB(ctx->opcode)]);                       \
    gen_helper_##name(t0, t0);                                                \
    t1 = tcg_temp_new();                                                      \
    tcg_gen_extu_i32_tl(t1, t0);                                              \
    tcg_temp_free_i32(t0);                                                    \
    tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)],       \
                    0xFFFFFFFF00000000ULL);                                   \
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t1);    \
    tcg_temp_free(t1);                                                        \
7690
}
A
aurel32 已提交
7691 7692 7693 7694 7695 7696 7697 7698 7699 7700 7701 7702 7703 7704 7705 7706 7707 7708 7709 7710 7711 7712 7713 7714 7715 7716 7717 7718 7719
#define GEN_SPEFPUOP_CONV_32_64(name)                                         \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    TCGv_i32 t0;                                                              \
    TCGv t1;                                                                  \
    t0 = tcg_temp_new_i32();                                                  \
    gen_helper_##name(t0, cpu_gpr[rB(ctx->opcode)]);                          \
    t1 = tcg_temp_new();                                                      \
    tcg_gen_extu_i32_tl(t1, t0);                                              \
    tcg_temp_free_i32(t0);                                                    \
    tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)],       \
                    0xFFFFFFFF00000000ULL);                                   \
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t1);    \
    tcg_temp_free(t1);                                                        \
}
#define GEN_SPEFPUOP_CONV_64_32(name)                                         \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    TCGv_i32 t0 = tcg_temp_new_i32();                                         \
    tcg_gen_trunc_tl_i32(t0, cpu_gpr[rB(ctx->opcode)]);                       \
    gen_helper_##name(cpu_gpr[rD(ctx->opcode)], t0);                          \
    tcg_temp_free_i32(t0);                                                    \
}
#define GEN_SPEFPUOP_CONV_64_64(name)                                         \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);    \
}
#define GEN_SPEFPUOP_ARITH2_32_32(name)                                       \
7720 7721
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
A
aurel32 已提交
7722 7723
    TCGv_i32 t0, t1;                                                          \
    TCGv_i64 t2;                                                              \
7724
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
7725
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
7726 7727
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
7728 7729 7730 7731 7732 7733 7734 7735 7736 7737 7738 7739 7740
    t0 = tcg_temp_new_i32();                                                  \
    t1 = tcg_temp_new_i32();                                                  \
    tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]);                       \
    tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]);                       \
    gen_helper_##name(t0, t0, t1);                                            \
    tcg_temp_free_i32(t1);                                                    \
    t2 = tcg_temp_new();                                                      \
    tcg_gen_extu_i32_tl(t2, t0);                                              \
    tcg_temp_free_i32(t0);                                                    \
    tcg_gen_andi_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)],       \
                    0xFFFFFFFF00000000ULL);                                   \
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t2);    \
    tcg_temp_free(t2);                                                        \
7741
}
A
aurel32 已提交
7742
#define GEN_SPEFPUOP_ARITH2_64_64(name)                                       \
7743 7744 7745
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
7746
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
7747 7748
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
7749 7750
    gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],     \
                      cpu_gpr[rB(ctx->opcode)]);                              \
7751
}
A
aurel32 已提交
7752
#define GEN_SPEFPUOP_COMP_32(name)                                            \
7753 7754
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
A
aurel32 已提交
7755
    TCGv_i32 t0, t1;                                                          \
7756
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
7757
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
7758 7759
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
7760 7761 7762 7763 7764 7765 7766 7767 7768 7769 7770 7771
    t0 = tcg_temp_new_i32();                                                  \
    t1 = tcg_temp_new_i32();                                                  \
    tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]);                       \
    tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]);                       \
    gen_helper_##name(cpu_crf[crfD(ctx->opcode)], t0, t1);                    \
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
}
#define GEN_SPEFPUOP_COMP_64(name)                                            \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
7772
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
A
aurel32 已提交
7773 7774 7775 7776 7777 7778 7779 7780 7781 7782
        return;                                                               \
    }                                                                         \
    gen_helper_##name(cpu_crf[crfD(ctx->opcode)],                             \
                      cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);    \
}
#else
#define GEN_SPEFPUOP_CONV_32_32(name)                                         \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);    \
7783
}
A
aurel32 已提交
7784 7785 7786 7787 7788 7789 7790 7791 7792 7793 7794 7795 7796 7797 7798 7799 7800 7801 7802 7803 7804 7805 7806 7807 7808 7809 7810 7811 7812
#define GEN_SPEFPUOP_CONV_32_64(name)                                         \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    TCGv_i64 t0 = tcg_temp_new_i64();                                         \
    gen_load_gpr64(t0, rB(ctx->opcode));                                      \
    gen_helper_##name(cpu_gpr[rD(ctx->opcode)], t0);                          \
    tcg_temp_free_i64(t0);                                                    \
}
#define GEN_SPEFPUOP_CONV_64_32(name)                                         \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    TCGv_i64 t0 = tcg_temp_new_i64();                                         \
    gen_helper_##name(t0, cpu_gpr[rB(ctx->opcode)]);                          \
    gen_store_gpr64(rD(ctx->opcode), t0);                                     \
    tcg_temp_free_i64(t0);                                                    \
}
#define GEN_SPEFPUOP_CONV_64_64(name)                                         \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    TCGv_i64 t0 = tcg_temp_new_i64();                                         \
    gen_load_gpr64(t0, rB(ctx->opcode));                                      \
    gen_helper_##name(t0, t0);                                                \
    gen_store_gpr64(rD(ctx->opcode), t0);                                     \
    tcg_temp_free_i64(t0);                                                    \
}
#define GEN_SPEFPUOP_ARITH2_32_32(name)                                       \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
7813
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
A
aurel32 已提交
7814 7815 7816 7817 7818 7819 7820 7821 7822 7823
        return;                                                               \
    }                                                                         \
    gen_helper_##name(cpu_gpr[rD(ctx->opcode)],                               \
                      cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);    \
}
#define GEN_SPEFPUOP_ARITH2_64_64(name)                                       \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    TCGv_i64 t0, t1;                                                          \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
7824
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
A
aurel32 已提交
7825 7826 7827 7828 7829 7830 7831 7832 7833 7834 7835 7836 7837 7838 7839
        return;                                                               \
    }                                                                         \
    t0 = tcg_temp_new_i64();                                                  \
    t1 = tcg_temp_new_i64();                                                  \
    gen_load_gpr64(t0, rA(ctx->opcode));                                      \
    gen_load_gpr64(t1, rB(ctx->opcode));                                      \
    gen_helper_##name(t0, t0, t1);                                            \
    gen_store_gpr64(rD(ctx->opcode), t0);                                     \
    tcg_temp_free_i64(t0);                                                    \
    tcg_temp_free_i64(t1);                                                    \
}
#define GEN_SPEFPUOP_COMP_32(name)                                            \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
7840
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
A
aurel32 已提交
7841 7842 7843 7844 7845 7846 7847 7848 7849 7850
        return;                                                               \
    }                                                                         \
    gen_helper_##name(cpu_crf[crfD(ctx->opcode)],                             \
                      cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);    \
}
#define GEN_SPEFPUOP_COMP_64(name)                                            \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    TCGv_i64 t0, t1;                                                          \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
7851
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
A
aurel32 已提交
7852 7853 7854 7855 7856 7857 7858 7859 7860 7861 7862
        return;                                                               \
    }                                                                         \
    t0 = tcg_temp_new_i64();                                                  \
    t1 = tcg_temp_new_i64();                                                  \
    gen_load_gpr64(t0, rA(ctx->opcode));                                      \
    gen_load_gpr64(t1, rB(ctx->opcode));                                      \
    gen_helper_##name(cpu_crf[crfD(ctx->opcode)], t0, t1);                    \
    tcg_temp_free_i64(t0);                                                    \
    tcg_temp_free_i64(t1);                                                    \
}
#endif
7863

7864 7865
/* Single precision floating-point vectors operations */
/* Arithmetic */
A
aurel32 已提交
7866 7867 7868 7869 7870 7871 7872
GEN_SPEFPUOP_ARITH2_64_64(evfsadd);
GEN_SPEFPUOP_ARITH2_64_64(evfssub);
GEN_SPEFPUOP_ARITH2_64_64(evfsmul);
GEN_SPEFPUOP_ARITH2_64_64(evfsdiv);
static always_inline void gen_evfsabs (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
A
aurel32 已提交
7873
        gen_exception(ctx, POWERPC_EXCP_APU);
A
aurel32 已提交
7874 7875 7876 7877 7878 7879 7880 7881 7882 7883 7884 7885
        return;
    }
#if defined(TARGET_PPC64)
    tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~0x8000000080000000LL);
#else
    tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~0x80000000);
    tcg_gen_andi_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], ~0x80000000);
#endif
}
static always_inline void gen_evfsnabs (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
A
aurel32 已提交
7886
        gen_exception(ctx, POWERPC_EXCP_APU);
A
aurel32 已提交
7887 7888 7889 7890 7891 7892 7893 7894 7895 7896 7897 7898
        return;
    }
#if defined(TARGET_PPC64)
    tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000080000000LL);
#else
    tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
    tcg_gen_ori_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000);
#endif
}
static always_inline void gen_evfsneg (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
A
aurel32 已提交
7899
        gen_exception(ctx, POWERPC_EXCP_APU);
A
aurel32 已提交
7900 7901 7902 7903 7904 7905 7906 7907 7908 7909
        return;
    }
#if defined(TARGET_PPC64)
    tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000080000000LL);
#else
    tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
    tcg_gen_xori_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000);
#endif
}

7910
/* Conversion */
A
aurel32 已提交
7911 7912 7913 7914 7915 7916 7917 7918 7919 7920 7921
GEN_SPEFPUOP_CONV_64_64(evfscfui);
GEN_SPEFPUOP_CONV_64_64(evfscfsi);
GEN_SPEFPUOP_CONV_64_64(evfscfuf);
GEN_SPEFPUOP_CONV_64_64(evfscfsf);
GEN_SPEFPUOP_CONV_64_64(evfsctui);
GEN_SPEFPUOP_CONV_64_64(evfsctsi);
GEN_SPEFPUOP_CONV_64_64(evfsctuf);
GEN_SPEFPUOP_CONV_64_64(evfsctsf);
GEN_SPEFPUOP_CONV_64_64(evfsctuiz);
GEN_SPEFPUOP_CONV_64_64(evfsctsiz);

7922
/* Comparison */
A
aurel32 已提交
7923 7924 7925 7926 7927 7928
GEN_SPEFPUOP_COMP_64(evfscmpgt);
GEN_SPEFPUOP_COMP_64(evfscmplt);
GEN_SPEFPUOP_COMP_64(evfscmpeq);
GEN_SPEFPUOP_COMP_64(evfststgt);
GEN_SPEFPUOP_COMP_64(evfststlt);
GEN_SPEFPUOP_COMP_64(evfststeq);
7929 7930

/* Opcodes definitions */
7931 7932 7933 7934 7935 7936 7937 7938 7939 7940 7941 7942 7943 7944
GEN_SPE(evfsadd,        evfssub,       0x00, 0x0A, 0x00000000, PPC_SPE_SINGLE); //
GEN_SPE(evfsabs,        evfsnabs,      0x02, 0x0A, 0x0000F800, PPC_SPE_SINGLE); //
GEN_SPE(evfsneg,        speundef,      0x03, 0x0A, 0x0000F800, PPC_SPE_SINGLE); //
GEN_SPE(evfsmul,        evfsdiv,       0x04, 0x0A, 0x00000000, PPC_SPE_SINGLE); //
GEN_SPE(evfscmpgt,      evfscmplt,     0x06, 0x0A, 0x00600000, PPC_SPE_SINGLE); //
GEN_SPE(evfscmpeq,      speundef,      0x07, 0x0A, 0x00600000, PPC_SPE_SINGLE); //
GEN_SPE(evfscfui,       evfscfsi,      0x08, 0x0A, 0x00180000, PPC_SPE_SINGLE); //
GEN_SPE(evfscfuf,       evfscfsf,      0x09, 0x0A, 0x00180000, PPC_SPE_SINGLE); //
GEN_SPE(evfsctui,       evfsctsi,      0x0A, 0x0A, 0x00180000, PPC_SPE_SINGLE); //
GEN_SPE(evfsctuf,       evfsctsf,      0x0B, 0x0A, 0x00180000, PPC_SPE_SINGLE); //
GEN_SPE(evfsctuiz,      speundef,      0x0C, 0x0A, 0x00180000, PPC_SPE_SINGLE); //
GEN_SPE(evfsctsiz,      speundef,      0x0D, 0x0A, 0x00180000, PPC_SPE_SINGLE); //
GEN_SPE(evfststgt,      evfststlt,     0x0E, 0x0A, 0x00600000, PPC_SPE_SINGLE); //
GEN_SPE(evfststeq,      speundef,      0x0F, 0x0A, 0x00600000, PPC_SPE_SINGLE); //
7945 7946 7947

/* Single precision floating-point operations */
/* Arithmetic */
A
aurel32 已提交
7948 7949 7950 7951 7952 7953 7954
GEN_SPEFPUOP_ARITH2_32_32(efsadd);
GEN_SPEFPUOP_ARITH2_32_32(efssub);
GEN_SPEFPUOP_ARITH2_32_32(efsmul);
GEN_SPEFPUOP_ARITH2_32_32(efsdiv);
static always_inline void gen_efsabs (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
A
aurel32 已提交
7955
        gen_exception(ctx, POWERPC_EXCP_APU);
A
aurel32 已提交
7956 7957 7958 7959 7960 7961 7962
        return;
    }
    tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], (target_long)~0x80000000LL);
}
static always_inline void gen_efsnabs (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
A
aurel32 已提交
7963
        gen_exception(ctx, POWERPC_EXCP_APU);
A
aurel32 已提交
7964 7965 7966 7967 7968 7969 7970
        return;
    }
    tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
}
static always_inline void gen_efsneg (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
A
aurel32 已提交
7971
        gen_exception(ctx, POWERPC_EXCP_APU);
A
aurel32 已提交
7972 7973 7974 7975 7976
        return;
    }
    tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
}

7977
/* Conversion */
A
aurel32 已提交
7978 7979 7980 7981 7982 7983 7984 7985 7986 7987 7988 7989
GEN_SPEFPUOP_CONV_32_32(efscfui);
GEN_SPEFPUOP_CONV_32_32(efscfsi);
GEN_SPEFPUOP_CONV_32_32(efscfuf);
GEN_SPEFPUOP_CONV_32_32(efscfsf);
GEN_SPEFPUOP_CONV_32_32(efsctui);
GEN_SPEFPUOP_CONV_32_32(efsctsi);
GEN_SPEFPUOP_CONV_32_32(efsctuf);
GEN_SPEFPUOP_CONV_32_32(efsctsf);
GEN_SPEFPUOP_CONV_32_32(efsctuiz);
GEN_SPEFPUOP_CONV_32_32(efsctsiz);
GEN_SPEFPUOP_CONV_32_64(efscfd);

7990
/* Comparison */
A
aurel32 已提交
7991 7992 7993 7994 7995 7996
GEN_SPEFPUOP_COMP_32(efscmpgt);
GEN_SPEFPUOP_COMP_32(efscmplt);
GEN_SPEFPUOP_COMP_32(efscmpeq);
GEN_SPEFPUOP_COMP_32(efststgt);
GEN_SPEFPUOP_COMP_32(efststlt);
GEN_SPEFPUOP_COMP_32(efststeq);
7997 7998

/* Opcodes definitions */
7999 8000 8001 8002 8003 8004 8005 8006 8007 8008 8009 8010 8011 8012
GEN_SPE(efsadd,         efssub,        0x00, 0x0B, 0x00000000, PPC_SPE_SINGLE); //
GEN_SPE(efsabs,         efsnabs,       0x02, 0x0B, 0x0000F800, PPC_SPE_SINGLE); //
GEN_SPE(efsneg,         speundef,      0x03, 0x0B, 0x0000F800, PPC_SPE_SINGLE); //
GEN_SPE(efsmul,         efsdiv,        0x04, 0x0B, 0x00000000, PPC_SPE_SINGLE); //
GEN_SPE(efscmpgt,       efscmplt,      0x06, 0x0B, 0x00600000, PPC_SPE_SINGLE); //
GEN_SPE(efscmpeq,       efscfd,        0x07, 0x0B, 0x00600000, PPC_SPE_SINGLE); //
GEN_SPE(efscfui,        efscfsi,       0x08, 0x0B, 0x00180000, PPC_SPE_SINGLE); //
GEN_SPE(efscfuf,        efscfsf,       0x09, 0x0B, 0x00180000, PPC_SPE_SINGLE); //
GEN_SPE(efsctui,        efsctsi,       0x0A, 0x0B, 0x00180000, PPC_SPE_SINGLE); //
GEN_SPE(efsctuf,        efsctsf,       0x0B, 0x0B, 0x00180000, PPC_SPE_SINGLE); //
GEN_SPE(efsctuiz,       speundef,      0x0C, 0x0B, 0x00180000, PPC_SPE_SINGLE); //
GEN_SPE(efsctsiz,       speundef,      0x0D, 0x0B, 0x00180000, PPC_SPE_SINGLE); //
GEN_SPE(efststgt,       efststlt,      0x0E, 0x0B, 0x00600000, PPC_SPE_SINGLE); //
GEN_SPE(efststeq,       speundef,      0x0F, 0x0B, 0x00600000, PPC_SPE_SINGLE); //
8013 8014 8015

/* Double precision floating-point operations */
/* Arithmetic */
A
aurel32 已提交
8016 8017 8018 8019 8020 8021 8022
GEN_SPEFPUOP_ARITH2_64_64(efdadd);
GEN_SPEFPUOP_ARITH2_64_64(efdsub);
GEN_SPEFPUOP_ARITH2_64_64(efdmul);
GEN_SPEFPUOP_ARITH2_64_64(efddiv);
static always_inline void gen_efdabs (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
A
aurel32 已提交
8023
        gen_exception(ctx, POWERPC_EXCP_APU);
A
aurel32 已提交
8024 8025 8026 8027 8028 8029 8030 8031 8032 8033 8034
        return;
    }
#if defined(TARGET_PPC64)
    tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~0x8000000000000000LL);
#else
    tcg_gen_andi_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], ~0x80000000);
#endif
}
static always_inline void gen_efdnabs (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
A
aurel32 已提交
8035
        gen_exception(ctx, POWERPC_EXCP_APU);
A
aurel32 已提交
8036 8037 8038 8039 8040 8041 8042 8043 8044 8045 8046
        return;
    }
#if defined(TARGET_PPC64)
    tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000000000000LL);
#else
    tcg_gen_ori_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000);
#endif
}
static always_inline void gen_efdneg (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
A
aurel32 已提交
8047
        gen_exception(ctx, POWERPC_EXCP_APU);
A
aurel32 已提交
8048 8049 8050 8051 8052 8053 8054 8055 8056
        return;
    }
#if defined(TARGET_PPC64)
    tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000000000000LL);
#else
    tcg_gen_xori_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000);
#endif
}

8057
/* Conversion */
A
aurel32 已提交
8058 8059 8060 8061 8062 8063 8064 8065 8066 8067 8068 8069 8070 8071 8072
GEN_SPEFPUOP_CONV_64_32(efdcfui);
GEN_SPEFPUOP_CONV_64_32(efdcfsi);
GEN_SPEFPUOP_CONV_64_32(efdcfuf);
GEN_SPEFPUOP_CONV_64_32(efdcfsf);
GEN_SPEFPUOP_CONV_32_64(efdctui);
GEN_SPEFPUOP_CONV_32_64(efdctsi);
GEN_SPEFPUOP_CONV_32_64(efdctuf);
GEN_SPEFPUOP_CONV_32_64(efdctsf);
GEN_SPEFPUOP_CONV_32_64(efdctuiz);
GEN_SPEFPUOP_CONV_32_64(efdctsiz);
GEN_SPEFPUOP_CONV_64_32(efdcfs);
GEN_SPEFPUOP_CONV_64_64(efdcfuid);
GEN_SPEFPUOP_CONV_64_64(efdcfsid);
GEN_SPEFPUOP_CONV_64_64(efdctuidz);
GEN_SPEFPUOP_CONV_64_64(efdctsidz);
8073 8074

/* Comparison */
A
aurel32 已提交
8075 8076 8077 8078 8079 8080
GEN_SPEFPUOP_COMP_64(efdcmpgt);
GEN_SPEFPUOP_COMP_64(efdcmplt);
GEN_SPEFPUOP_COMP_64(efdcmpeq);
GEN_SPEFPUOP_COMP_64(efdtstgt);
GEN_SPEFPUOP_COMP_64(efdtstlt);
GEN_SPEFPUOP_COMP_64(efdtsteq);
8081 8082

/* Opcodes definitions */
8083 8084 8085 8086 8087 8088 8089 8090 8091 8092 8093 8094 8095 8096 8097 8098
GEN_SPE(efdadd,         efdsub,        0x10, 0x0B, 0x00000000, PPC_SPE_DOUBLE); //
GEN_SPE(efdcfuid,       efdcfsid,      0x11, 0x0B, 0x00180000, PPC_SPE_DOUBLE); //
GEN_SPE(efdabs,         efdnabs,       0x12, 0x0B, 0x0000F800, PPC_SPE_DOUBLE); //
GEN_SPE(efdneg,         speundef,      0x13, 0x0B, 0x0000F800, PPC_SPE_DOUBLE); //
GEN_SPE(efdmul,         efddiv,        0x14, 0x0B, 0x00000000, PPC_SPE_DOUBLE); //
GEN_SPE(efdctuidz,      efdctsidz,     0x15, 0x0B, 0x00180000, PPC_SPE_DOUBLE); //
GEN_SPE(efdcmpgt,       efdcmplt,      0x16, 0x0B, 0x00600000, PPC_SPE_DOUBLE); //
GEN_SPE(efdcmpeq,       efdcfs,        0x17, 0x0B, 0x00600000, PPC_SPE_DOUBLE); //
GEN_SPE(efdcfui,        efdcfsi,       0x18, 0x0B, 0x00180000, PPC_SPE_DOUBLE); //
GEN_SPE(efdcfuf,        efdcfsf,       0x19, 0x0B, 0x00180000, PPC_SPE_DOUBLE); //
GEN_SPE(efdctui,        efdctsi,       0x1A, 0x0B, 0x00180000, PPC_SPE_DOUBLE); //
GEN_SPE(efdctuf,        efdctsf,       0x1B, 0x0B, 0x00180000, PPC_SPE_DOUBLE); //
GEN_SPE(efdctuiz,       speundef,      0x1C, 0x0B, 0x00180000, PPC_SPE_DOUBLE); //
GEN_SPE(efdctsiz,       speundef,      0x1D, 0x0B, 0x00180000, PPC_SPE_DOUBLE); //
GEN_SPE(efdtstgt,       efdtstlt,      0x1E, 0x0B, 0x00600000, PPC_SPE_DOUBLE); //
GEN_SPE(efdtsteq,       speundef,      0x1F, 0x0B, 0x00600000, PPC_SPE_DOUBLE); //
8099

B
bellard 已提交
8100 8101 8102
/* End opcode list */
GEN_OPCODE_MARK(end);

8103
#include "translate_init.c"
8104
#include "helper_regs.h"
B
bellard 已提交
8105

8106
/*****************************************************************************/
8107
/* Misc PowerPC helpers */
8108 8109 8110
void cpu_dump_state (CPUState *env, FILE *f,
                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
                     int flags)
B
bellard 已提交
8111
{
8112 8113 8114
#define RGPL  4
#define RFPL  4

B
bellard 已提交
8115 8116
    int i;

J
j_mayer 已提交
8117
    cpu_fprintf(f, "NIP " ADDRX "   LR " ADDRX " CTR " ADDRX " XER %08x\n",
A
aurel32 已提交
8118
                env->nip, env->lr, env->ctr, env->xer);
8119 8120
    cpu_fprintf(f, "MSR " ADDRX " HID0 " ADDRX "  HF " ADDRX " idx %d\n",
                env->msr, env->spr[SPR_HID0], env->hflags, env->mmu_idx);
8121
#if !defined(NO_TIMER_DUMP)
J
j_mayer 已提交
8122
    cpu_fprintf(f, "TB %08x %08x "
8123 8124 8125 8126
#if !defined(CONFIG_USER_ONLY)
                "DECR %08x"
#endif
                "\n",
J
j_mayer 已提交
8127
                cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env)
8128 8129 8130 8131
#if !defined(CONFIG_USER_ONLY)
                , cpu_ppc_load_decr(env)
#endif
                );
J
j_mayer 已提交
8132
#endif
8133
    for (i = 0; i < 32; i++) {
8134 8135
        if ((i & (RGPL - 1)) == 0)
            cpu_fprintf(f, "GPR%02d", i);
8136
        cpu_fprintf(f, " " REGX, ppc_dump_gpr(env, i));
8137
        if ((i & (RGPL - 1)) == (RGPL - 1))
B
bellard 已提交
8138
            cpu_fprintf(f, "\n");
8139
    }
8140
    cpu_fprintf(f, "CR ");
8141
    for (i = 0; i < 8; i++)
B
bellard 已提交
8142 8143
        cpu_fprintf(f, "%01x", env->crf[i]);
    cpu_fprintf(f, "  [");
8144 8145 8146 8147 8148 8149 8150 8151
    for (i = 0; i < 8; i++) {
        char a = '-';
        if (env->crf[i] & 0x08)
            a = 'L';
        else if (env->crf[i] & 0x04)
            a = 'G';
        else if (env->crf[i] & 0x02)
            a = 'E';
B
bellard 已提交
8152
        cpu_fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' ');
8153
    }
8154
    cpu_fprintf(f, " ]             RES " ADDRX "\n", env->reserve);
8155 8156 8157
    for (i = 0; i < 32; i++) {
        if ((i & (RFPL - 1)) == 0)
            cpu_fprintf(f, "FPR%02d", i);
B
bellard 已提交
8158
        cpu_fprintf(f, " %016" PRIx64, *((uint64_t *)&env->fpr[i]));
8159
        if ((i & (RFPL - 1)) == (RFPL - 1))
B
bellard 已提交
8160
            cpu_fprintf(f, "\n");
B
bellard 已提交
8161
    }
8162
    cpu_fprintf(f, "FPSCR %08x\n", env->fpscr);
8163
#if !defined(CONFIG_USER_ONLY)
8164
    cpu_fprintf(f, "SRR0 " ADDRX " SRR1 " ADDRX " SDR1 " ADDRX "\n",
8165
                env->spr[SPR_SRR0], env->spr[SPR_SRR1], env->sdr1);
8166
#endif
B
bellard 已提交
8167

8168 8169
#undef RGPL
#undef RFPL
B
bellard 已提交
8170 8171
}

8172 8173 8174 8175 8176 8177 8178 8179 8180 8181 8182 8183 8184 8185 8186 8187 8188 8189 8190 8191 8192 8193 8194 8195 8196 8197 8198 8199 8200 8201 8202 8203 8204 8205 8206 8207 8208 8209 8210 8211 8212 8213 8214 8215 8216 8217 8218
void cpu_dump_statistics (CPUState *env, FILE*f,
                          int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
                          int flags)
{
#if defined(DO_PPC_STATISTICS)
    opc_handler_t **t1, **t2, **t3, *handler;
    int op1, op2, op3;

    t1 = env->opcodes;
    for (op1 = 0; op1 < 64; op1++) {
        handler = t1[op1];
        if (is_indirect_opcode(handler)) {
            t2 = ind_table(handler);
            for (op2 = 0; op2 < 32; op2++) {
                handler = t2[op2];
                if (is_indirect_opcode(handler)) {
                    t3 = ind_table(handler);
                    for (op3 = 0; op3 < 32; op3++) {
                        handler = t3[op3];
                        if (handler->count == 0)
                            continue;
                        cpu_fprintf(f, "%02x %02x %02x (%02x %04d) %16s: "
                                    "%016llx %lld\n",
                                    op1, op2, op3, op1, (op3 << 5) | op2,
                                    handler->oname,
                                    handler->count, handler->count);
                    }
                } else {
                    if (handler->count == 0)
                        continue;
                    cpu_fprintf(f, "%02x %02x    (%02x %04d) %16s: "
                                "%016llx %lld\n",
                                op1, op2, op1, op2, handler->oname,
                                handler->count, handler->count);
                }
            }
        } else {
            if (handler->count == 0)
                continue;
            cpu_fprintf(f, "%02x       (%02x     ) %16s: %016llx %lld\n",
                        op1, op1, handler->oname,
                        handler->count, handler->count);
        }
    }
#endif
}

8219
/*****************************************************************************/
8220 8221 8222
static always_inline void gen_intermediate_code_internal (CPUState *env,
                                                          TranslationBlock *tb,
                                                          int search_pc)
B
bellard 已提交
8223
{
8224
    DisasContext ctx, *ctxp = &ctx;
B
bellard 已提交
8225
    opc_handler_t **table, *handler;
B
bellard 已提交
8226
    target_ulong pc_start;
B
bellard 已提交
8227
    uint16_t *gen_opc_end;
8228
    CPUBreakpoint *bp;
B
bellard 已提交
8229
    int j, lj = -1;
P
pbrook 已提交
8230 8231
    int num_insns;
    int max_insns;
B
bellard 已提交
8232 8233 8234

    pc_start = tb->pc;
    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
B
bellard 已提交
8235
    ctx.nip = pc_start;
B
bellard 已提交
8236
    ctx.tb = tb;
8237
    ctx.exception = POWERPC_EXCP_NONE;
8238
    ctx.spr_cb = env->spr_cb;
A
aurel32 已提交
8239 8240 8241
    ctx.mem_idx = env->mmu_idx;
    ctx.access_type = -1;
    ctx.le_mode = env->hflags & (1 << MSR_LE) ? 1 : 0;
8242 8243
#if defined(TARGET_PPC64)
    ctx.sf_mode = msr_sf;
8244
#endif
B
bellard 已提交
8245
    ctx.fpu_enabled = msr_fp;
8246
    if ((env->flags & POWERPC_FLAG_SPE) && msr_spe)
8247 8248 8249
        ctx.spe_enabled = msr_spe;
    else
        ctx.spe_enabled = 0;
8250 8251 8252 8253
    if ((env->flags & POWERPC_FLAG_VRE) && msr_vr)
        ctx.altivec_enabled = msr_vr;
    else
        ctx.altivec_enabled = 0;
8254
    if ((env->flags & POWERPC_FLAG_SE) && msr_se)
8255
        ctx.singlestep_enabled = CPU_SINGLE_STEP;
8256
    else
8257
        ctx.singlestep_enabled = 0;
8258
    if ((env->flags & POWERPC_FLAG_BE) && msr_be)
8259 8260 8261
        ctx.singlestep_enabled |= CPU_BRANCH_STEP;
    if (unlikely(env->singlestep_enabled))
        ctx.singlestep_enabled |= GDBSTUB_SINGLE_STEP;
8262
#if defined (DO_SINGLE_STEP) && 0
8263 8264 8265
    /* Single step trace mode */
    msr_se = 1;
#endif
P
pbrook 已提交
8266 8267 8268 8269 8270 8271
    num_insns = 0;
    max_insns = tb->cflags & CF_COUNT_MASK;
    if (max_insns == 0)
        max_insns = CF_COUNT_MASK;

    gen_icount_start();
8272
    /* Set env in case of segfault during code fetch */
8273
    while (ctx.exception == POWERPC_EXCP_NONE && gen_opc_ptr < gen_opc_end) {
8274 8275
        if (unlikely(!TAILQ_EMPTY(&env->breakpoints))) {
            TAILQ_FOREACH(bp, &env->breakpoints, entry) {
8276
                if (bp->pc == ctx.nip) {
A
aurel32 已提交
8277
                    gen_debug_exception(ctxp);
8278 8279 8280 8281
                    break;
                }
            }
        }
8282
        if (unlikely(search_pc)) {
B
bellard 已提交
8283 8284 8285 8286 8287
            j = gen_opc_ptr - gen_opc_buf;
            if (lj < j) {
                lj++;
                while (lj < j)
                    gen_opc_instr_start[lj++] = 0;
B
bellard 已提交
8288
                gen_opc_pc[lj] = ctx.nip;
B
bellard 已提交
8289
                gen_opc_instr_start[lj] = 1;
P
pbrook 已提交
8290
                gen_opc_icount[lj] = num_insns;
B
bellard 已提交
8291 8292
            }
        }
8293 8294 8295
        LOG_DISAS("----------------\n");
        LOG_DISAS("nip=" ADDRX " super=%d ir=%d\n",
                  ctx.nip, ctx.mem_idx, (int)msr_ir);
P
pbrook 已提交
8296 8297
        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
            gen_io_start();
A
aurel32 已提交
8298
        if (unlikely(ctx.le_mode)) {
8299 8300 8301
            ctx.opcode = bswap32(ldl_code(ctx.nip));
        } else {
            ctx.opcode = ldl_code(ctx.nip);
8302
        }
8303
        LOG_DISAS("translate opcode %08x (%02x %02x %02x) (%s)\n",
8304
                    ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode),
8305
                    opc3(ctx.opcode), little_endian ? "little" : "big");
B
bellard 已提交
8306
        ctx.nip += 4;
8307
        table = env->opcodes;
P
pbrook 已提交
8308
        num_insns++;
B
bellard 已提交
8309 8310 8311 8312 8313 8314 8315 8316 8317 8318
        handler = table[opc1(ctx.opcode)];
        if (is_indirect_opcode(handler)) {
            table = ind_table(handler);
            handler = table[opc2(ctx.opcode)];
            if (is_indirect_opcode(handler)) {
                table = ind_table(handler);
                handler = table[opc3(ctx.opcode)];
            }
        }
        /* Is opcode *REALLY* valid ? */
8319
        if (unlikely(handler->handler == &gen_invalid)) {
8320 8321 8322 8323 8324
            if (qemu_log_enabled()) {
                qemu_log("invalid/unsupported opcode: "
                          "%02x - %02x - %02x (%08x) " ADDRX " %d\n",
                          opc1(ctx.opcode), opc2(ctx.opcode),
                          opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, (int)msr_ir);
B
bellard 已提交
8325 8326
            } else {
                printf("invalid/unsupported opcode: "
8327
                       "%02x - %02x - %02x (%08x) " ADDRX " %d\n",
B
bellard 已提交
8328
                       opc1(ctx.opcode), opc2(ctx.opcode),
8329
                       opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, (int)msr_ir);
B
bellard 已提交
8330
            }
8331 8332
        } else {
            if (unlikely((ctx.opcode & handler->inval) != 0)) {
8333 8334 8335 8336 8337 8338
                if (qemu_log_enabled()) {
                    qemu_log("invalid bits: %08x for opcode: "
                              "%02x - %02x - %02x (%08x) " ADDRX "\n",
                              ctx.opcode & handler->inval, opc1(ctx.opcode),
                              opc2(ctx.opcode), opc3(ctx.opcode),
                              ctx.opcode, ctx.nip - 4);
8339 8340
                } else {
                    printf("invalid bits: %08x for opcode: "
8341
                           "%02x - %02x - %02x (%08x) " ADDRX "\n",
8342 8343
                           ctx.opcode & handler->inval, opc1(ctx.opcode),
                           opc2(ctx.opcode), opc3(ctx.opcode),
B
bellard 已提交
8344
                           ctx.opcode, ctx.nip - 4);
8345
                }
A
aurel32 已提交
8346
                gen_inval_exception(ctxp, POWERPC_EXCP_INVAL_INVAL);
B
bellard 已提交
8347
                break;
B
bellard 已提交
8348 8349
            }
        }
B
bellard 已提交
8350
        (*(handler->handler))(&ctx);
8351 8352 8353
#if defined(DO_PPC_STATISTICS)
        handler->count++;
#endif
8354
        /* Check trace mode exceptions */
8355 8356 8357 8358 8359
        if (unlikely(ctx.singlestep_enabled & CPU_SINGLE_STEP &&
                     (ctx.nip <= 0x100 || ctx.nip > 0xF00) &&
                     ctx.exception != POWERPC_SYSCALL &&
                     ctx.exception != POWERPC_EXCP_TRAP &&
                     ctx.exception != POWERPC_EXCP_BRANCH)) {
A
aurel32 已提交
8360
            gen_exception(ctxp, POWERPC_EXCP_TRACE);
8361
        } else if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) ||
P
pbrook 已提交
8362 8363
                            (env->singlestep_enabled) ||
                            num_insns >= max_insns)) {
8364 8365 8366
            /* if we reach a page boundary or are single stepping, stop
             * generation
             */
8367
            break;
8368
        }
8369 8370 8371 8372
#if defined (DO_SINGLE_STEP)
        break;
#endif
    }
P
pbrook 已提交
8373 8374
    if (tb->cflags & CF_LAST_IO)
        gen_io_end();
8375
    if (ctx.exception == POWERPC_EXCP_NONE) {
8376
        gen_goto_tb(&ctx, 0, ctx.nip);
8377
    } else if (ctx.exception != POWERPC_EXCP_BRANCH) {
8378
        if (unlikely(env->singlestep_enabled)) {
A
aurel32 已提交
8379
            gen_debug_exception(ctxp);
8380
        }
8381
        /* Generate the return instruction */
B
bellard 已提交
8382
        tcg_gen_exit_tb(0);
8383
    }
P
pbrook 已提交
8384
    gen_icount_end(tb, num_insns);
B
bellard 已提交
8385
    *gen_opc_ptr = INDEX_op_end;
8386
    if (unlikely(search_pc)) {
8387 8388 8389 8390 8391
        j = gen_opc_ptr - gen_opc_buf;
        lj++;
        while (lj <= j)
            gen_opc_instr_start[lj++] = 0;
    } else {
B
bellard 已提交
8392
        tb->size = ctx.nip - pc_start;
P
pbrook 已提交
8393
        tb->icount = num_insns;
8394
    }
8395
#if defined(DEBUG_DISAS)
8396 8397
    qemu_log_mask(CPU_LOG_TB_CPU, "---------------- excp: %04x\n", ctx.exception);
    log_cpu_state_mask(CPU_LOG_TB_CPU, env, 0);
8398
    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
8399
        int flags;
8400
        flags = env->bfd_mach;
A
aurel32 已提交
8401
        flags |= ctx.le_mode << 16;
8402 8403 8404
        qemu_log("IN: %s\n", lookup_symbol(pc_start));
        log_target_disas(pc_start, ctx.nip - pc_start, flags);
        qemu_log("\n");
8405
    }
B
bellard 已提交
8406 8407 8408
#endif
}

8409
void gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
B
bellard 已提交
8410
{
8411
    gen_intermediate_code_internal(env, tb, 0);
B
bellard 已提交
8412 8413
}

8414
void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
B
bellard 已提交
8415
{
8416
    gen_intermediate_code_internal(env, tb, 1);
B
bellard 已提交
8417
}
A
aurel32 已提交
8418 8419 8420 8421 8422 8423

void gen_pc_load(CPUState *env, TranslationBlock *tb,
                unsigned long searched_pc, int pc_pos, void *puc)
{
    env->nip = gen_opc_pc[pc_pos];
}