translate.c 308.9 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 4303 4304
    t0 = tcg_const_tl(SR(ctx->opcode));
    gen_helper_load_slb(cpu_gpr[rD(ctx->opcode)], t0);
    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 4323 4324
    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_slb(cpu_gpr[rD(ctx->opcode)], t0);
    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 4340 4341
    t0 = tcg_const_tl(SR(ctx->opcode));
    gen_helper_store_slb(t0, cpu_gpr[rS(ctx->opcode)]);
    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 4360 4361
    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_slb(t0, cpu_gpr[rS(ctx->opcode)]);
    tcg_temp_free(t0);
4362 4363 4364 4365
#endif
}
#endif /* defined(TARGET_PPC64) */

B
bellard 已提交
4366
/***                      Lookaside buffer management                      ***/
A
aurel32 已提交
4367
/* Optional & mem_idx only: */
B
bellard 已提交
4368
/* tlbia */
4369
GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA)
B
bellard 已提交
4370
{
4371
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
4372
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
4373
#else
A
aurel32 已提交
4374
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
4375
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
4376
        return;
4377
    }
4378
    gen_helper_tlbia();
4379
#endif
B
bellard 已提交
4380 4381 4382
}

/* tlbie */
4383
GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM_TLBIE)
B
bellard 已提交
4384
{
4385
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
4386
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
4387
#else
A
aurel32 已提交
4388
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
4389
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
4390
        return;
4391
    }
4392
#if defined(TARGET_PPC64)
4393 4394 4395 4396 4397 4398
    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
4399
#endif
4400
        gen_helper_tlbie(cpu_gpr[rB(ctx->opcode)]);
4401
#endif
B
bellard 已提交
4402 4403 4404
}

/* tlbsync */
4405
GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM_TLBSYNC)
B
bellard 已提交
4406
{
4407
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
4408
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
4409
#else
A
aurel32 已提交
4410
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
4411
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
4412
        return;
4413 4414 4415 4416
    }
    /* This has no effect: it should ensure that all previous
     * tlbie have completed
     */
A
aurel32 已提交
4417
    gen_stop_exception(ctx);
4418
#endif
B
bellard 已提交
4419 4420
}

J
j_mayer 已提交
4421 4422 4423 4424 4425
#if defined(TARGET_PPC64)
/* slbia */
GEN_HANDLER(slbia, 0x1F, 0x12, 0x0F, 0x03FFFC01, PPC_SLBI)
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
4426
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
J
j_mayer 已提交
4427
#else
A
aurel32 已提交
4428
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
4429
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
J
j_mayer 已提交
4430 4431
        return;
    }
4432
    gen_helper_slbia();
J
j_mayer 已提交
4433 4434 4435 4436 4437 4438 4439
#endif
}

/* slbie */
GEN_HANDLER(slbie, 0x1F, 0x12, 0x0D, 0x03FF0001, PPC_SLBI)
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
4440
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
J
j_mayer 已提交
4441
#else
A
aurel32 已提交
4442
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
4443
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
J
j_mayer 已提交
4444 4445
        return;
    }
4446
    gen_helper_slbie(cpu_gpr[rB(ctx->opcode)]);
J
j_mayer 已提交
4447 4448 4449 4450
#endif
}
#endif

B
bellard 已提交
4451 4452
/***                              External control                         ***/
/* Optional: */
4453
/* eciwx */
B
bellard 已提交
4454 4455
GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN)
{
A
aurel32 已提交
4456
    TCGv t0;
4457
    /* Should check EAR[E] ! */
A
aurel32 已提交
4458 4459 4460
    gen_set_access_type(ctx, ACCESS_EXT);
    t0 = tcg_temp_new();
    gen_addr_reg_index(ctx, t0);
4461
    gen_check_align(ctx, t0, 0x03);
A
aurel32 已提交
4462
    gen_qemu_ld32u(ctx, cpu_gpr[rD(ctx->opcode)], t0);
4463
    tcg_temp_free(t0);
4464 4465 4466 4467 4468
}

/* ecowx */
GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN)
{
A
aurel32 已提交
4469
    TCGv t0;
4470
    /* Should check EAR[E] ! */
A
aurel32 已提交
4471 4472 4473
    gen_set_access_type(ctx, ACCESS_EXT);
    t0 = tcg_temp_new();
    gen_addr_reg_index(ctx, t0);
4474
    gen_check_align(ctx, t0, 0x03);
A
aurel32 已提交
4475
    gen_qemu_st32(ctx, cpu_gpr[rD(ctx->opcode)], t0);
4476
    tcg_temp_free(t0);
4477 4478 4479 4480 4481 4482
}

/* PowerPC 601 specific instructions */
/* abs - abs. */
GEN_HANDLER(abs, 0x1F, 0x08, 0x0B, 0x0000F800, PPC_POWER_BR)
{
4483 4484 4485 4486 4487 4488 4489 4490
    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);
4491
    if (unlikely(Rc(ctx->opcode) != 0))
4492
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4493 4494 4495 4496 4497
}

/* abso - abso. */
GEN_HANDLER(abso, 0x1F, 0x08, 0x1B, 0x0000F800, PPC_POWER_BR)
{
4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512
    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);
4513
    if (unlikely(Rc(ctx->opcode) != 0))
4514
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4515 4516 4517
}

/* clcs */
4518
GEN_HANDLER(clcs, 0x1F, 0x10, 0x13, 0x0000F800, PPC_POWER_BR)
4519
{
4520 4521 4522
    TCGv_i32 t0 = tcg_const_i32(rA(ctx->opcode));
    gen_helper_clcs(cpu_gpr[rD(ctx->opcode)], t0);
    tcg_temp_free_i32(t0);
4523
    /* Rc=1 sets CR0 to an undefined state */
4524 4525 4526 4527 4528
}

/* div - div. */
GEN_HANDLER(div, 0x1F, 0x0B, 0x0A, 0x00000000, PPC_POWER_BR)
{
4529
    gen_helper_div(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
4530
    if (unlikely(Rc(ctx->opcode) != 0))
4531
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4532 4533 4534 4535 4536
}

/* divo - divo. */
GEN_HANDLER(divo, 0x1F, 0x0B, 0x1A, 0x00000000, PPC_POWER_BR)
{
4537
    gen_helper_divo(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
4538
    if (unlikely(Rc(ctx->opcode) != 0))
4539
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4540 4541 4542 4543 4544
}

/* divs - divs. */
GEN_HANDLER(divs, 0x1F, 0x0B, 0x0B, 0x00000000, PPC_POWER_BR)
{
4545
    gen_helper_divs(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
4546
    if (unlikely(Rc(ctx->opcode) != 0))
4547
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4548 4549 4550 4551 4552
}

/* divso - divso. */
GEN_HANDLER(divso, 0x1F, 0x0B, 0x1B, 0x00000000, PPC_POWER_BR)
{
4553
    gen_helper_divso(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
4554
    if (unlikely(Rc(ctx->opcode) != 0))
4555
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4556 4557 4558 4559 4560
}

/* doz - doz. */
GEN_HANDLER(doz, 0x1F, 0x08, 0x08, 0x00000000, PPC_POWER_BR)
{
4561 4562 4563 4564 4565 4566 4567 4568
    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);
4569
    if (unlikely(Rc(ctx->opcode) != 0))
4570
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4571 4572 4573 4574 4575
}

/* dozo - dozo. */
GEN_HANDLER(dozo, 0x1F, 0x08, 0x18, 0x00000000, PPC_POWER_BR)
{
4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597
    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);
4598
    if (unlikely(Rc(ctx->opcode) != 0))
4599
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4600 4601 4602 4603 4604
}

/* dozi */
GEN_HANDLER(dozi, 0x09, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR)
{
4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615
    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)]);
4616 4617 4618 4619 4620
}

/* lscbx - lscbx. */
GEN_HANDLER(lscbx, 0x1F, 0x15, 0x08, 0x00000000, PPC_POWER_BR)
{
4621 4622 4623 4624
    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));
4625

A
aurel32 已提交
4626
    gen_addr_reg_index(ctx, t0);
4627
    /* NIP cannot be restored if the memory exception comes from an helper */
4628
    gen_update_nip(ctx, ctx->nip - 4);
4629 4630 4631 4632
    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 已提交
4633
    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~0x7F);
4634
    tcg_gen_or_tl(cpu_xer, cpu_xer, t0);
4635
    if (unlikely(Rc(ctx->opcode) != 0))
4636 4637
        gen_set_Rc0(ctx, t0);
    tcg_temp_free(t0);
4638 4639 4640 4641 4642
}

/* maskg - maskg. */
GEN_HANDLER(maskg, 0x1F, 0x1D, 0x00, 0x00000000, PPC_POWER_BR)
{
4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661
    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);
4662
    if (unlikely(Rc(ctx->opcode) != 0))
4663
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4664 4665 4666 4667 4668
}

/* maskir - maskir. */
GEN_HANDLER(maskir, 0x1F, 0x1D, 0x10, 0x00000000, PPC_POWER_BR)
{
4669 4670 4671 4672 4673 4674 4675
    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);
4676
    if (unlikely(Rc(ctx->opcode) != 0))
4677
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4678 4679 4680 4681 4682
}

/* mul - mul. */
GEN_HANDLER(mul, 0x1F, 0x0B, 0x03, 0x00000000, PPC_POWER_BR)
{
4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695
    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);
4696
    if (unlikely(Rc(ctx->opcode) != 0))
4697
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4698 4699 4700 4701 4702
}

/* mulo - mulo. */
GEN_HANDLER(mulo, 0x1F, 0x0B, 0x13, 0x00000000, PPC_POWER_BR)
{
4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722
    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);
4723
    if (unlikely(Rc(ctx->opcode) != 0))
4724
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4725 4726 4727 4728 4729
}

/* nabs - nabs. */
GEN_HANDLER(nabs, 0x1F, 0x08, 0x0F, 0x00000000, PPC_POWER_BR)
{
4730 4731 4732 4733 4734 4735 4736 4737
    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);
4738
    if (unlikely(Rc(ctx->opcode) != 0))
4739
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4740 4741 4742 4743 4744
}

/* nabso - nabso. */
GEN_HANDLER(nabso, 0x1F, 0x08, 0x1F, 0x00000000, PPC_POWER_BR)
{
4745 4746 4747 4748 4749 4750 4751 4752 4753 4754
    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));
4755
    if (unlikely(Rc(ctx->opcode) != 0))
4756
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4757 4758 4759 4760 4761
}

/* rlmi - rlmi. */
GEN_HANDLER(rlmi, 0x16, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR)
{
4762 4763 4764 4765 4766 4767 4768 4769 4770
    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);
4771
    if (unlikely(Rc(ctx->opcode) != 0))
4772
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4773 4774 4775 4776 4777
}

/* rrib - rrib. */
GEN_HANDLER(rrib, 0x1F, 0x19, 0x10, 0x00000000, PPC_POWER_BR)
{
4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788
    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);
4789
    if (unlikely(Rc(ctx->opcode) != 0))
4790
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4791 4792 4793 4794 4795
}

/* sle - sle. */
GEN_HANDLER(sle, 0x1F, 0x19, 0x04, 0x00000000, PPC_POWER_BR)
{
4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806
    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);
4807
    if (unlikely(Rc(ctx->opcode) != 0))
4808
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4809 4810 4811 4812 4813
}

/* sleq - sleq. */
GEN_HANDLER(sleq, 0x1F, 0x19, 0x06, 0x00000000, PPC_POWER_BR)
{
4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828
    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);
4829
    if (unlikely(Rc(ctx->opcode) != 0))
4830
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4831 4832 4833 4834 4835
}

/* sliq - sliq. */
GEN_HANDLER(sliq, 0x1F, 0x18, 0x05, 0x00000000, PPC_POWER_BR)
{
4836 4837 4838 4839 4840 4841 4842 4843 4844 4845
    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);
4846
    if (unlikely(Rc(ctx->opcode) != 0))
4847
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4848 4849 4850 4851 4852
}

/* slliq - slliq. */
GEN_HANDLER(slliq, 0x1F, 0x18, 0x07, 0x00000000, PPC_POWER_BR)
{
4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863
    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);
4864
    if (unlikely(Rc(ctx->opcode) != 0))
4865
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4866 4867 4868 4869 4870
}

/* sllq - sllq. */
GEN_HANDLER(sllq, 0x1F, 0x18, 0x06, 0x00000000, PPC_POWER_BR)
{
4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892
    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);
4893
    if (unlikely(Rc(ctx->opcode) != 0))
4894
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4895 4896 4897 4898 4899
}

/* slq - slq. */
GEN_HANDLER(slq, 0x1F, 0x18, 0x04, 0x00000000, PPC_POWER_BR)
{
4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915
    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);
4916
    if (unlikely(Rc(ctx->opcode) != 0))
4917
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4918 4919
}

4920
/* sraiq - sraiq. */
4921 4922
GEN_HANDLER(sraiq, 0x1F, 0x18, 0x1D, 0x00000000, PPC_POWER_BR)
{
4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938
    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);
4939
    if (unlikely(Rc(ctx->opcode) != 0))
4940
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4941 4942 4943 4944 4945
}

/* sraq - sraq. */
GEN_HANDLER(sraq, 0x1F, 0x18, 0x1C, 0x00000000, PPC_POWER_BR)
{
4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971
    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);
4972
    if (unlikely(Rc(ctx->opcode) != 0))
4973
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4974 4975 4976 4977 4978
}

/* sre - sre. */
GEN_HANDLER(sre, 0x1F, 0x19, 0x14, 0x00000000, PPC_POWER_BR)
{
4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989
    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);
4990
    if (unlikely(Rc(ctx->opcode) != 0))
4991
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4992 4993 4994 4995 4996
}

/* srea - srea. */
GEN_HANDLER(srea, 0x1F, 0x19, 0x1C, 0x00000000, PPC_POWER_BR)
{
4997 4998 4999 5000 5001 5002 5003 5004
    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);
5005
    if (unlikely(Rc(ctx->opcode) != 0))
5006
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
5007 5008 5009 5010 5011
}

/* sreq */
GEN_HANDLER(sreq, 0x1F, 0x19, 0x16, 0x00000000, PPC_POWER_BR)
{
5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026
    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);
5027
    if (unlikely(Rc(ctx->opcode) != 0))
5028
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
5029 5030 5031 5032 5033
}

/* sriq */
GEN_HANDLER(sriq, 0x1F, 0x18, 0x15, 0x00000000, PPC_POWER_BR)
{
5034 5035 5036 5037 5038 5039 5040 5041 5042 5043
    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);
5044
    if (unlikely(Rc(ctx->opcode) != 0))
5045
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
5046 5047 5048 5049 5050
}

/* srliq */
GEN_HANDLER(srliq, 0x1F, 0x18, 0x17, 0x00000000, PPC_POWER_BR)
{
5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061
    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);
5062
    if (unlikely(Rc(ctx->opcode) != 0))
5063
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
5064 5065 5066 5067 5068
}

/* srlq */
GEN_HANDLER(srlq, 0x1F, 0x18, 0x16, 0x00000000, PPC_POWER_BR)
{
5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091
    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);
5092
    if (unlikely(Rc(ctx->opcode) != 0))
5093
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
5094 5095 5096 5097 5098
}

/* srq */
GEN_HANDLER(srq, 0x1F, 0x18, 0x14, 0x00000000, PPC_POWER_BR)
{
5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114
    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);
5115
    if (unlikely(Rc(ctx->opcode) != 0))
5116
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
5117 5118 5119 5120 5121 5122 5123
}

/* PowerPC 602 specific instructions */
/* dsa  */
GEN_HANDLER(dsa, 0x1F, 0x14, 0x13, 0x03FFF801, PPC_602_SPEC)
{
    /* XXX: TODO */
A
aurel32 已提交
5124
    gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
5125 5126 5127 5128 5129 5130
}

/* esa */
GEN_HANDLER(esa, 0x1F, 0x14, 0x12, 0x03FFF801, PPC_602_SPEC)
{
    /* XXX: TODO */
A
aurel32 已提交
5131
    gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
5132 5133 5134 5135 5136 5137
}

/* mfrom */
GEN_HANDLER(mfrom, 0x1F, 0x09, 0x08, 0x03E0F801, PPC_602_SPEC)
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5138
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5139
#else
A
aurel32 已提交
5140
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5141
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5142 5143
        return;
    }
5144
    gen_helper_602_mfrom(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
5145 5146 5147 5148 5149
#endif
}

/* 602 - 603 - G2 TLB management */
/* tlbld */
5150
GEN_HANDLER2(tlbld_6xx, "tlbld", 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB)
5151 5152
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5153
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5154
#else
A
aurel32 已提交
5155
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5156
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5157 5158
        return;
    }
5159
    gen_helper_6xx_tlbd(cpu_gpr[rB(ctx->opcode)]);
5160 5161 5162 5163
#endif
}

/* tlbli */
5164
GEN_HANDLER2(tlbli_6xx, "tlbli", 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB)
5165 5166
{
#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_6xx_tlbi(cpu_gpr[rB(ctx->opcode)]);
5174 5175 5176
#endif
}

5177 5178
/* 74xx TLB management */
/* tlbld */
5179
GEN_HANDLER2(tlbld_74xx, "tlbld", 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_74xx_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_74xx_tlbd(cpu_gpr[rB(ctx->opcode)]);
5189 5190 5191 5192
#endif
}

/* tlbli */
5193
GEN_HANDLER2(tlbli_74xx, "tlbli", 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_74xx_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_74xx_tlbi(cpu_gpr[rB(ctx->opcode)]);
5203 5204 5205
#endif
}

5206 5207 5208 5209 5210 5211 5212 5213 5214 5215
/* 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 已提交
5216
    /* Cache line invalidate: privileged and treated as no-op */
5217
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5218
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5219
#else
A
aurel32 已提交
5220
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5221
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235
        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 已提交
5236
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5237
#else
5238 5239 5240
    int ra = rA(ctx->opcode);
    int rd = rD(ctx->opcode);
    TCGv t0;
A
aurel32 已提交
5241
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5242
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5243 5244
        return;
    }
5245
    t0 = tcg_temp_new();
A
aurel32 已提交
5246
    gen_addr_reg_index(ctx, t0);
5247 5248 5249 5250
    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);
5251
    if (ra != 0 && ra != rd)
5252
        tcg_gen_mov_tl(cpu_gpr[ra], cpu_gpr[rd]);
5253 5254 5255 5256 5257 5258
#endif
}

GEN_HANDLER(rac, 0x1F, 0x12, 0x19, 0x00000001, PPC_POWER)
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5259
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5260
#else
5261
    TCGv t0;
A
aurel32 已提交
5262
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5263
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5264 5265
        return;
    }
5266
    t0 = tcg_temp_new();
A
aurel32 已提交
5267
    gen_addr_reg_index(ctx, t0);
5268 5269
    gen_helper_rac(cpu_gpr[rD(ctx->opcode)], t0);
    tcg_temp_free(t0);
5270 5271 5272 5273 5274 5275
#endif
}

GEN_HANDLER(rfsvc, 0x13, 0x12, 0x02, 0x03FFF0001, PPC_POWER)
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5276
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5277
#else
A
aurel32 已提交
5278
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5279
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5280 5281
        return;
    }
5282
    gen_helper_rfsvc();
A
aurel32 已提交
5283
    gen_sync_exception(ctx);
5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294
#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)
{
5295
    int rd = rD(ctx->opcode);
A
aurel32 已提交
5296 5297 5298 5299 5300 5301 5302
    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);
5303
    tcg_temp_free(t0);
5304 5305 5306 5307 5308 5309
}

/* lfqu */
GEN_HANDLER(lfqu, 0x39, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
{
    int ra = rA(ctx->opcode);
5310
    int rd = rD(ctx->opcode);
A
aurel32 已提交
5311 5312 5313 5314 5315 5316 5317 5318
    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);
5319
    if (ra != 0)
5320 5321 5322
        tcg_gen_mov_tl(cpu_gpr[ra], t0);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
5323 5324 5325 5326 5327 5328
}

/* lfqux */
GEN_HANDLER(lfqux, 0x1F, 0x17, 0x19, 0x00000001, PPC_POWER2)
{
    int ra = rA(ctx->opcode);
5329
    int rd = rD(ctx->opcode);
A
aurel32 已提交
5330 5331 5332 5333 5334 5335 5336 5337 5338
    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);
5339
    if (ra != 0)
5340 5341
        tcg_gen_mov_tl(cpu_gpr[ra], t0);
    tcg_temp_free(t0);
5342 5343 5344 5345 5346
}

/* lfqx */
GEN_HANDLER(lfqx, 0x1F, 0x17, 0x18, 0x00000001, PPC_POWER2)
{
5347
    int rd = rD(ctx->opcode);
A
aurel32 已提交
5348 5349 5350 5351 5352 5353 5354
    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);
5355
    tcg_temp_free(t0);
5356 5357 5358 5359 5360
}

/* stfq */
GEN_HANDLER(stfq, 0x3C, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
{
5361
    int rd = rD(ctx->opcode);
A
aurel32 已提交
5362 5363 5364 5365 5366 5367 5368
    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);
5369
    tcg_temp_free(t0);
5370 5371 5372 5373 5374 5375
}

/* stfqu */
GEN_HANDLER(stfqu, 0x3D, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
{
    int ra = rA(ctx->opcode);
5376
    int rd = rD(ctx->opcode);
A
aurel32 已提交
5377 5378 5379 5380 5381 5382 5383 5384 5385
    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);
5386
    if (ra != 0)
5387 5388
        tcg_gen_mov_tl(cpu_gpr[ra], t0);
    tcg_temp_free(t0);
5389 5390 5391 5392 5393 5394
}

/* stfqux */
GEN_HANDLER(stfqux, 0x1F, 0x17, 0x1D, 0x00000001, PPC_POWER2)
{
    int ra = rA(ctx->opcode);
5395
    int rd = rD(ctx->opcode);
A
aurel32 已提交
5396 5397 5398 5399 5400 5401 5402 5403 5404
    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);
5405
    if (ra != 0)
5406 5407
        tcg_gen_mov_tl(cpu_gpr[ra], t0);
    tcg_temp_free(t0);
5408 5409 5410 5411 5412
}

/* stfqx */
GEN_HANDLER(stfqx, 0x1F, 0x17, 0x1C, 0x00000001, PPC_POWER2)
{
5413
    int rd = rD(ctx->opcode);
A
aurel32 已提交
5414 5415 5416 5417 5418 5419 5420
    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);
5421
    tcg_temp_free(t0);
5422 5423 5424
}

/* BookE specific instructions */
5425
/* XXX: not implemented on 440 ? */
5426
GEN_HANDLER(mfapidi, 0x1F, 0x13, 0x08, 0x0000F801, PPC_MFAPIDI)
5427 5428
{
    /* XXX: TODO */
A
aurel32 已提交
5429
    gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
5430 5431
}

5432
/* XXX: not implemented on 440 ? */
5433
GEN_HANDLER(tlbiva, 0x1F, 0x12, 0x18, 0x03FFF801, PPC_TLBIVA)
5434 5435
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5436
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5437
#else
5438
    TCGv t0;
A
aurel32 已提交
5439
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5440
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5441 5442
        return;
    }
5443
    t0 = tcg_temp_new();
A
aurel32 已提交
5444
    gen_addr_reg_index(ctx, t0);
5445 5446
    gen_helper_tlbie(cpu_gpr[rB(ctx->opcode)]);
    tcg_temp_free(t0);
5447 5448 5449 5450
#endif
}

/* All 405 MAC instructions are translated here */
5451 5452 5453
static always_inline void gen_405_mulladd_insn (DisasContext *ctx,
                                                int opc2, int opc3,
                                                int ra, int rb, int rt, int Rc)
5454
{
5455 5456
    TCGv t0, t1;

P
pbrook 已提交
5457 5458
    t0 = tcg_temp_local_new();
    t1 = tcg_temp_local_new();
5459

5460 5461 5462 5463 5464 5465 5466
    switch (opc3 & 0x0D) {
    case 0x05:
        /* macchw    - macchw.    - macchwo   - macchwo.   */
        /* macchws   - macchws.   - macchwso  - macchwso.  */
        /* nmacchw   - nmacchw.   - nmacchwo  - nmacchwo.  */
        /* nmacchws  - nmacchws.  - nmacchwso - nmacchwso. */
        /* mulchw - mulchw. */
5467 5468 5469
        tcg_gen_ext16s_tl(t0, cpu_gpr[ra]);
        tcg_gen_sari_tl(t1, cpu_gpr[rb], 16);
        tcg_gen_ext16s_tl(t1, t1);
5470 5471 5472 5473 5474
        break;
    case 0x04:
        /* macchwu   - macchwu.   - macchwuo  - macchwuo.  */
        /* macchwsu  - macchwsu.  - macchwsuo - macchwsuo. */
        /* mulchwu - mulchwu. */
5475 5476 5477
        tcg_gen_ext16u_tl(t0, cpu_gpr[ra]);
        tcg_gen_shri_tl(t1, cpu_gpr[rb], 16);
        tcg_gen_ext16u_tl(t1, t1);
5478 5479 5480 5481 5482 5483 5484
        break;
    case 0x01:
        /* machhw    - machhw.    - machhwo   - machhwo.   */
        /* machhws   - machhws.   - machhwso  - machhwso.  */
        /* nmachhw   - nmachhw.   - nmachhwo  - nmachhwo.  */
        /* nmachhws  - nmachhws.  - nmachhwso - nmachhwso. */
        /* mulhhw - mulhhw. */
5485 5486 5487 5488
        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);
5489 5490 5491 5492 5493
        break;
    case 0x00:
        /* machhwu   - machhwu.   - machhwuo  - machhwuo.  */
        /* machhwsu  - machhwsu.  - machhwsuo - machhwsuo. */
        /* mulhhwu - mulhhwu. */
5494 5495 5496 5497
        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);
5498 5499 5500 5501 5502 5503 5504
        break;
    case 0x0D:
        /* maclhw    - maclhw.    - maclhwo   - maclhwo.   */
        /* maclhws   - maclhws.   - maclhwso  - maclhwso.  */
        /* nmaclhw   - nmaclhw.   - nmaclhwo  - nmaclhwo.  */
        /* nmaclhws  - nmaclhws.  - nmaclhwso - nmaclhwso. */
        /* mullhw - mullhw. */
5505 5506
        tcg_gen_ext16s_tl(t0, cpu_gpr[ra]);
        tcg_gen_ext16s_tl(t1, cpu_gpr[rb]);
5507 5508 5509 5510 5511
        break;
    case 0x0C:
        /* maclhwu   - maclhwu.   - maclhwuo  - maclhwuo.  */
        /* maclhwsu  - maclhwsu.  - maclhwsuo - maclhwsuo. */
        /* mullhwu - mullhwu. */
5512 5513
        tcg_gen_ext16u_tl(t0, cpu_gpr[ra]);
        tcg_gen_ext16u_tl(t1, cpu_gpr[rb]);
5514 5515 5516
        break;
    }
    if (opc2 & 0x04) {
5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540
        /* (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 已提交
5541
                if (opc3 & 0x02) {
5542 5543 5544 5545 5546 5547 5548
                    /* 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 已提交
5549
                if (opc3 & 0x02) {
5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562
                    /* 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);
5563
    }
5564 5565
    tcg_temp_free(t0);
    tcg_temp_free(t1);
5566 5567
    if (unlikely(Rc) != 0) {
        /* Update Rc0 */
5568
        gen_set_Rc0(ctx, cpu_gpr[rt]);
5569 5570 5571
    }
}

5572 5573
#define GEN_MAC_HANDLER(name, opc2, opc3)                                     \
GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_405_MAC)                  \
5574 5575 5576 5577 5578 5579
{                                                                             \
    gen_405_mulladd_insn(ctx, opc2, opc3, rA(ctx->opcode), rB(ctx->opcode),   \
                         rD(ctx->opcode), Rc(ctx->opcode));                   \
}

/* macchw    - macchw.    */
5580
GEN_MAC_HANDLER(macchw, 0x0C, 0x05);
5581
/* macchwo   - macchwo.   */
5582
GEN_MAC_HANDLER(macchwo, 0x0C, 0x15);
5583
/* macchws   - macchws.   */
5584
GEN_MAC_HANDLER(macchws, 0x0C, 0x07);
5585
/* macchwso  - macchwso.  */
5586
GEN_MAC_HANDLER(macchwso, 0x0C, 0x17);
5587
/* macchwsu  - macchwsu.  */
5588
GEN_MAC_HANDLER(macchwsu, 0x0C, 0x06);
5589
/* macchwsuo - macchwsuo. */
5590
GEN_MAC_HANDLER(macchwsuo, 0x0C, 0x16);
5591
/* macchwu   - macchwu.   */
5592
GEN_MAC_HANDLER(macchwu, 0x0C, 0x04);
5593
/* macchwuo  - macchwuo.  */
5594
GEN_MAC_HANDLER(macchwuo, 0x0C, 0x14);
5595
/* machhw    - machhw.    */
5596
GEN_MAC_HANDLER(machhw, 0x0C, 0x01);
5597
/* machhwo   - machhwo.   */
5598
GEN_MAC_HANDLER(machhwo, 0x0C, 0x11);
5599
/* machhws   - machhws.   */
5600
GEN_MAC_HANDLER(machhws, 0x0C, 0x03);
5601
/* machhwso  - machhwso.  */
5602
GEN_MAC_HANDLER(machhwso, 0x0C, 0x13);
5603
/* machhwsu  - machhwsu.  */
5604
GEN_MAC_HANDLER(machhwsu, 0x0C, 0x02);
5605
/* machhwsuo - machhwsuo. */
5606
GEN_MAC_HANDLER(machhwsuo, 0x0C, 0x12);
5607
/* machhwu   - machhwu.   */
5608
GEN_MAC_HANDLER(machhwu, 0x0C, 0x00);
5609
/* machhwuo  - machhwuo.  */
5610
GEN_MAC_HANDLER(machhwuo, 0x0C, 0x10);
5611
/* maclhw    - maclhw.    */
5612
GEN_MAC_HANDLER(maclhw, 0x0C, 0x0D);
5613
/* maclhwo   - maclhwo.   */
5614
GEN_MAC_HANDLER(maclhwo, 0x0C, 0x1D);
5615
/* maclhws   - maclhws.   */
5616
GEN_MAC_HANDLER(maclhws, 0x0C, 0x0F);
5617
/* maclhwso  - maclhwso.  */
5618
GEN_MAC_HANDLER(maclhwso, 0x0C, 0x1F);
5619
/* maclhwu   - maclhwu.   */
5620
GEN_MAC_HANDLER(maclhwu, 0x0C, 0x0C);
5621
/* maclhwuo  - maclhwuo.  */
5622
GEN_MAC_HANDLER(maclhwuo, 0x0C, 0x1C);
5623
/* maclhwsu  - maclhwsu.  */
5624
GEN_MAC_HANDLER(maclhwsu, 0x0C, 0x0E);
5625
/* maclhwsuo - maclhwsuo. */
5626
GEN_MAC_HANDLER(maclhwsuo, 0x0C, 0x1E);
5627
/* nmacchw   - nmacchw.   */
5628
GEN_MAC_HANDLER(nmacchw, 0x0E, 0x05);
5629
/* nmacchwo  - nmacchwo.  */
5630
GEN_MAC_HANDLER(nmacchwo, 0x0E, 0x15);
5631
/* nmacchws  - nmacchws.  */
5632
GEN_MAC_HANDLER(nmacchws, 0x0E, 0x07);
5633
/* nmacchwso - nmacchwso. */
5634
GEN_MAC_HANDLER(nmacchwso, 0x0E, 0x17);
5635
/* nmachhw   - nmachhw.   */
5636
GEN_MAC_HANDLER(nmachhw, 0x0E, 0x01);
5637
/* nmachhwo  - nmachhwo.  */
5638
GEN_MAC_HANDLER(nmachhwo, 0x0E, 0x11);
5639
/* nmachhws  - nmachhws.  */
5640
GEN_MAC_HANDLER(nmachhws, 0x0E, 0x03);
5641
/* nmachhwso - nmachhwso. */
5642
GEN_MAC_HANDLER(nmachhwso, 0x0E, 0x13);
5643
/* nmaclhw   - nmaclhw.   */
5644
GEN_MAC_HANDLER(nmaclhw, 0x0E, 0x0D);
5645
/* nmaclhwo  - nmaclhwo.  */
5646
GEN_MAC_HANDLER(nmaclhwo, 0x0E, 0x1D);
5647
/* nmaclhws  - nmaclhws.  */
5648
GEN_MAC_HANDLER(nmaclhws, 0x0E, 0x0F);
5649
/* nmaclhwso - nmaclhwso. */
5650
GEN_MAC_HANDLER(nmaclhwso, 0x0E, 0x1F);
5651 5652

/* mulchw  - mulchw.  */
5653
GEN_MAC_HANDLER(mulchw, 0x08, 0x05);
5654
/* mulchwu - mulchwu. */
5655
GEN_MAC_HANDLER(mulchwu, 0x08, 0x04);
5656
/* mulhhw  - mulhhw.  */
5657
GEN_MAC_HANDLER(mulhhw, 0x08, 0x01);
5658
/* mulhhwu - mulhhwu. */
5659
GEN_MAC_HANDLER(mulhhwu, 0x08, 0x00);
5660
/* mullhw  - mullhw.  */
5661
GEN_MAC_HANDLER(mullhw, 0x08, 0x0D);
5662
/* mullhwu - mullhwu. */
5663
GEN_MAC_HANDLER(mullhwu, 0x08, 0x0C);
5664 5665

/* mfdcr */
5666
GEN_HANDLER(mfdcr, 0x1F, 0x03, 0x0A, 0x00000001, PPC_DCR)
5667 5668
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5669
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
5670
#else
5671
    TCGv dcrn;
A
aurel32 已提交
5672
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5673
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
5674 5675
        return;
    }
5676 5677 5678 5679 5680
    /* 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);
5681 5682 5683 5684
#endif
}

/* mtdcr */
5685
GEN_HANDLER(mtdcr, 0x1F, 0x03, 0x0E, 0x00000001, PPC_DCR)
5686 5687
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5688
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
5689
#else
5690
    TCGv dcrn;
A
aurel32 已提交
5691
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5692
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
5693 5694
        return;
    }
5695 5696 5697 5698 5699
    /* 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);
5700 5701 5702 5703
#endif
}

/* mfdcrx */
5704
/* XXX: not implemented on 440 ? */
5705
GEN_HANDLER(mfdcrx, 0x1F, 0x03, 0x08, 0x00000000, PPC_DCRX)
5706 5707
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5708
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
5709
#else
A
aurel32 已提交
5710
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5711
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
5712 5713
        return;
    }
5714 5715 5716
    /* 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)]);
5717
    /* Note: Rc update flag set leads to undefined state of Rc0 */
5718 5719 5720 5721
#endif
}

/* mtdcrx */
5722
/* XXX: not implemented on 440 ? */
5723
GEN_HANDLER(mtdcrx, 0x1F, 0x03, 0x0C, 0x00000000, PPC_DCRX)
5724 5725
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5726
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
5727
#else
A
aurel32 已提交
5728
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5729
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
5730 5731
        return;
    }
5732 5733 5734
    /* 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)]);
5735
    /* Note: Rc update flag set leads to undefined state of Rc0 */
5736 5737 5738
#endif
}

5739 5740 5741
/* mfdcrux (PPC 460) : user-mode access to DCR */
GEN_HANDLER(mfdcrux, 0x1F, 0x03, 0x09, 0x00000000, PPC_DCRUX)
{
5742 5743 5744
    /* 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)]);
5745 5746 5747 5748 5749 5750
    /* 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)
{
5751 5752 5753
    /* 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)]);
5754 5755 5756
    /* Note: Rc update flag set leads to undefined state of Rc0 */
}

5757 5758 5759 5760
/* dccci */
GEN_HANDLER(dccci, 0x1F, 0x06, 0x0E, 0x03E00001, PPC_4xx_COMMON)
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5761
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5762
#else
A
aurel32 已提交
5763
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5764
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5765 5766 5767 5768 5769 5770 5771 5772 5773 5774
        return;
    }
    /* interpreted as no-op */
#endif
}

/* dcread */
GEN_HANDLER(dcread, 0x1F, 0x06, 0x0F, 0x00000001, PPC_4xx_COMMON)
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5775
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5776
#else
A
aurel32 已提交
5777
    TCGv EA, val;
A
aurel32 已提交
5778
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5779
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5780 5781
        return;
    }
A
aurel32 已提交
5782
    gen_set_access_type(ctx, ACCESS_CACHE);
P
pbrook 已提交
5783
    EA = tcg_temp_new();
A
aurel32 已提交
5784
    gen_addr_reg_index(ctx, EA);
P
pbrook 已提交
5785
    val = tcg_temp_new();
A
aurel32 已提交
5786
    gen_qemu_ld32u(ctx, val, EA);
A
aurel32 已提交
5787 5788 5789
    tcg_temp_free(val);
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], EA);
    tcg_temp_free(EA);
5790 5791 5792 5793
#endif
}

/* icbt */
5794
GEN_HANDLER2(icbt_40x, "icbt", 0x1F, 0x06, 0x08, 0x03E00001, PPC_40x_ICBT)
5795 5796 5797 5798 5799 5800 5801 5802 5803 5804 5805
{
    /* 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 已提交
5806
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5807
#else
A
aurel32 已提交
5808
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5809
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5810 5811 5812 5813 5814 5815 5816 5817 5818 5819
        return;
    }
    /* interpreted as no-op */
#endif
}

/* icread */
GEN_HANDLER(icread, 0x1F, 0x06, 0x1F, 0x03E00001, PPC_4xx_COMMON)
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5820
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5821
#else
A
aurel32 已提交
5822
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5823
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5824 5825 5826 5827 5828 5829
        return;
    }
    /* interpreted as no-op */
#endif
}

A
aurel32 已提交
5830
/* rfci (mem_idx only) */
5831
GEN_HANDLER2(rfci_40x, "rfci", 0x13, 0x13, 0x01, 0x03FF8001, PPC_40x_EXCP)
5832 5833
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5834
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5835
#else
A
aurel32 已提交
5836
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5837
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5838 5839 5840
        return;
    }
    /* Restore CPU state */
5841
    gen_helper_40x_rfci();
A
aurel32 已提交
5842
    gen_sync_exception(ctx);
5843 5844 5845 5846 5847 5848
#endif
}

GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE)
{
#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
        return;
    }
    /* Restore CPU state */
5856
    gen_helper_rfci();
A
aurel32 已提交
5857
    gen_sync_exception(ctx);
5858 5859 5860 5861
#endif
}

/* BookE specific */
5862
/* XXX: not implemented on 440 ? */
5863
GEN_HANDLER(rfdi, 0x13, 0x07, 0x01, 0x03FF8001, PPC_RFDI)
5864 5865
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5866
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5867
#else
A
aurel32 已提交
5868
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5869
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5870 5871 5872
        return;
    }
    /* Restore CPU state */
5873
    gen_helper_rfdi();
A
aurel32 已提交
5874
    gen_sync_exception(ctx);
5875 5876 5877
#endif
}

5878
/* XXX: not implemented on 440 ? */
5879
GEN_HANDLER(rfmci, 0x13, 0x06, 0x01, 0x03FF8001, PPC_RFMCI)
5880 5881
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5882
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5883
#else
A
aurel32 已提交
5884
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5885
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5886 5887 5888
        return;
    }
    /* Restore CPU state */
5889
    gen_helper_rfmci();
A
aurel32 已提交
5890
    gen_sync_exception(ctx);
5891 5892
#endif
}
5893

5894
/* TLB management - PowerPC 405 implementation */
5895
/* tlbre */
5896
GEN_HANDLER2(tlbre_40x, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_TLB)
5897 5898
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5899
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5900
#else
A
aurel32 已提交
5901
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5902
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5903 5904 5905 5906
        return;
    }
    switch (rB(ctx->opcode)) {
    case 0:
5907
        gen_helper_4xx_tlbre_hi(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
5908 5909
        break;
    case 1:
5910
        gen_helper_4xx_tlbre_lo(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
5911 5912
        break;
    default:
A
aurel32 已提交
5913
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
5914
        break;
5915
    }
5916 5917 5918
#endif
}

5919
/* tlbsx - tlbsx. */
5920
GEN_HANDLER2(tlbsx_40x, "tlbsx", 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_TLB)
5921 5922
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5923
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5924
#else
5925
    TCGv t0;
A
aurel32 已提交
5926
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5927
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5928 5929
        return;
    }
5930
    t0 = tcg_temp_new();
A
aurel32 已提交
5931
    gen_addr_reg_index(ctx, t0);
5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942
    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);
    }
5943
#endif
B
bellard 已提交
5944 5945
}

5946
/* tlbwe */
5947
GEN_HANDLER2(tlbwe_40x, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_TLB)
B
bellard 已提交
5948
{
5949
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5950
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5951
#else
A
aurel32 已提交
5952
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5953
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5954 5955 5956 5957
        return;
    }
    switch (rB(ctx->opcode)) {
    case 0:
5958
        gen_helper_4xx_tlbwe_hi(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
5959 5960
        break;
    case 1:
5961
        gen_helper_4xx_tlbwe_lo(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
5962 5963
        break;
    default:
A
aurel32 已提交
5964
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
5965
        break;
5966
    }
5967 5968 5969
#endif
}

5970
/* TLB management - PowerPC 440 implementation */
5971
/* tlbre */
5972
GEN_HANDLER2(tlbre_440, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE)
5973 5974
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5975
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5976
#else
A
aurel32 已提交
5977
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5978
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5979 5980 5981 5982 5983 5984
        return;
    }
    switch (rB(ctx->opcode)) {
    case 0:
    case 1:
    case 2:
5985 5986 5987 5988 5989
        {
            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);
        }
5990 5991
        break;
    default:
A
aurel32 已提交
5992
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
5993 5994 5995 5996 5997 5998
        break;
    }
#endif
}

/* tlbsx - tlbsx. */
5999
GEN_HANDLER2(tlbsx_440, "tlbsx", 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE)
6000 6001
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
6002
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
6003
#else
6004
    TCGv t0;
A
aurel32 已提交
6005
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
6006
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
6007 6008
        return;
    }
6009
    t0 = tcg_temp_new();
A
aurel32 已提交
6010
    gen_addr_reg_index(ctx, t0);
6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021
    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);
    }
6022 6023 6024 6025
#endif
}

/* tlbwe */
6026
GEN_HANDLER2(tlbwe_440, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE)
6027 6028
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
6029
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
6030
#else
A
aurel32 已提交
6031
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
6032
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
6033 6034 6035 6036 6037 6038
        return;
    }
    switch (rB(ctx->opcode)) {
    case 0:
    case 1:
    case 2:
6039 6040 6041 6042 6043
        {
            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);
        }
6044 6045
        break;
    default:
A
aurel32 已提交
6046
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
6047 6048 6049 6050 6051
        break;
    }
#endif
}

6052
/* wrtee */
6053
GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_WRTEE)
6054 6055
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
6056
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
6057
#else
6058
    TCGv t0;
A
aurel32 已提交
6059
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
6060
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
6061 6062
        return;
    }
6063 6064 6065 6066 6067
    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 已提交
6068 6069 6070
    /* Stop translation to have a chance to raise an exception
     * if we just set msr_ee to 1
     */
A
aurel32 已提交
6071
    gen_stop_exception(ctx);
6072 6073 6074 6075
#endif
}

/* wrteei */
6076
GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000EFC01, PPC_WRTEE)
6077 6078
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
6079
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
6080
#else
A
aurel32 已提交
6081
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
6082
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
6083 6084
        return;
    }
6085 6086 6087
    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 已提交
6088
        gen_stop_exception(ctx);
6089
    } else {
A
aurel32 已提交
6090
        tcg_gen_andi_tl(cpu_msr, cpu_msr, ~(1 << MSR_EE));
6091
    }
6092 6093 6094
#endif
}

J
j_mayer 已提交
6095
/* PowerPC 440 specific instructions */
6096 6097 6098
/* dlmzb */
GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC)
{
6099 6100 6101 6102
    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);
6103 6104 6105
}

/* mbar replaces eieio on 440 */
A
aurel32 已提交
6106
GEN_HANDLER(mbar, 0x1F, 0x16, 0x1a, 0x001FF801, PPC_BOOKE)
6107 6108 6109 6110 6111
{
    /* interpreted as no-op */
}

/* msync replaces sync on 440 */
6112
GEN_HANDLER(msync, 0x1F, 0x16, 0x12, 0x03FFF801, PPC_BOOKE)
6113 6114 6115 6116 6117
{
    /* interpreted as no-op */
}

/* icbt */
6118
GEN_HANDLER2(icbt_440, "icbt", 0x1F, 0x16, 0x00, 0x03E00001, PPC_BOOKE)
6119 6120 6121 6122 6123
{
    /* interpreted as no-op */
    /* XXX: specification say this is treated as a load by the MMU
     *      but does not generate any exception
     */
B
bellard 已提交
6124 6125
}

6126 6127 6128
/***                      Altivec vector extension                         ***/
/* Altivec registers moves */

A
aurel32 已提交
6129 6130
static always_inline TCGv_ptr gen_avr_ptr(int reg)
{
A
aurel32 已提交
6131
    TCGv_ptr r = tcg_temp_new_ptr();
A
aurel32 已提交
6132 6133 6134 6135
    tcg_gen_addi_ptr(r, cpu_env, offsetof(CPUPPCState, avr[reg]));
    return r;
}

6136
#define GEN_VR_LDX(name, opc2, opc3)                                          \
6137
GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC)                  \
6138
{                                                                             \
6139
    TCGv EA;                                                                  \
6140
    if (unlikely(!ctx->altivec_enabled)) {                                    \
A
aurel32 已提交
6141
        gen_exception(ctx, POWERPC_EXCP_VPU);                                 \
6142 6143
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
6144
    gen_set_access_type(ctx, ACCESS_INT);                                     \
6145
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
6146
    gen_addr_reg_index(ctx, EA);                                              \
6147
    tcg_gen_andi_tl(EA, EA, ~0xf);                                            \
A
aurel32 已提交
6148 6149
    if (ctx->le_mode) {                                                       \
        gen_qemu_ld64(ctx, cpu_avrl[rD(ctx->opcode)], EA);                    \
6150
        tcg_gen_addi_tl(EA, EA, 8);                                           \
A
aurel32 已提交
6151
        gen_qemu_ld64(ctx, cpu_avrh[rD(ctx->opcode)], EA);                    \
6152
    } else {                                                                  \
A
aurel32 已提交
6153
        gen_qemu_ld64(ctx, cpu_avrh[rD(ctx->opcode)], EA);                    \
6154
        tcg_gen_addi_tl(EA, EA, 8);                                           \
A
aurel32 已提交
6155
        gen_qemu_ld64(ctx, cpu_avrl[rD(ctx->opcode)], EA);                    \
6156 6157
    }                                                                         \
    tcg_temp_free(EA);                                                        \
6158 6159 6160 6161 6162
}

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

A
aurel32 已提交
6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219
#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);                                          \
    }

6220
GEN_VR_LDX(lvx, 0x07, 0x03);
6221
/* As we don't emulate the cache, lvxl is stricly equivalent to lvx */
6222
GEN_VR_LDX(lvxl, 0x07, 0x0B);
6223

A
aurel32 已提交
6224 6225 6226 6227
GEN_VR_LVE(bx, 0x07, 0x00);
GEN_VR_LVE(hx, 0x07, 0x01);
GEN_VR_LVE(wx, 0x07, 0x02);

6228
GEN_VR_STX(svx, 0x07, 0x07);
6229
/* As we don't emulate the cache, stvxl is stricly equivalent to stvx */
6230
GEN_VR_STX(svxl, 0x07, 0x0F);
6231

A
aurel32 已提交
6232 6233 6234 6235
GEN_VR_STVE(bx, 0x07, 0x04);
GEN_VR_STVE(hx, 0x07, 0x05);
GEN_VR_STVE(wx, 0x07, 0x06);

A
aurel32 已提交
6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267
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);
}

6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278
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);
6279
    tcg_temp_free_i32(t);
6280 6281 6282 6283
}

GEN_HANDLER(mtvscr, 0x04, 0x2, 0x19, 0x03ff0000, PPC_ALTIVEC)
{
A
aurel32 已提交
6284
    TCGv_ptr p;
6285 6286 6287 6288
    if (unlikely(!ctx->altivec_enabled)) {
        gen_exception(ctx, POWERPC_EXCP_VPU);
        return;
    }
A
aurel32 已提交
6289 6290 6291
    p = gen_avr_ptr(rD(ctx->opcode));
    gen_helper_mtvscr(p);
    tcg_temp_free_ptr(p);
6292 6293
}

6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311
/* 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);

6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328
#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 已提交
6329 6330 6331 6332 6333 6334
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);
6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346
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 已提交
6347 6348 6349 6350 6351 6352
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 已提交
6353 6354 6355 6356 6357 6358
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 已提交
6359 6360 6361 6362 6363 6364 6365 6366
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 已提交
6367 6368 6369
GEN_VXFORM(vslb, 2, 4);
GEN_VXFORM(vslh, 2, 5);
GEN_VXFORM(vslw, 2, 6);
A
aurel32 已提交
6370 6371 6372 6373 6374 6375
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 已提交
6376 6377
GEN_VXFORM(vslo, 6, 16);
GEN_VXFORM(vsro, 6, 17);
A
aurel32 已提交
6378 6379
GEN_VXFORM(vaddcuw, 0, 6);
GEN_VXFORM(vsubcuw, 0, 22);
6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391
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 已提交
6392 6393 6394
GEN_VXFORM(vrlb, 2, 0);
GEN_VXFORM(vrlh, 2, 1);
GEN_VXFORM(vrlw, 2, 2);
A
aurel32 已提交
6395 6396
GEN_VXFORM(vsl, 2, 7);
GEN_VXFORM(vsr, 2, 11);
6397 6398 6399 6400 6401 6402 6403 6404
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 已提交
6405
GEN_VXFORM(vpkpx, 7, 12);
6406 6407 6408 6409 6410
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);
6411 6412
GEN_VXFORM(vaddfp, 5, 0);
GEN_VXFORM(vsubfp, 5, 1);
6413 6414
GEN_VXFORM(vmaxfp, 5, 16);
GEN_VXFORM(vminfp, 5, 17);
A
aurel32 已提交
6415

6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436
#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)))

6437 6438 6439 6440 6441 6442 6443 6444 6445
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)
6446 6447 6448 6449
GEN_VXRFORM(vcmpeqfp, 3, 3)
GEN_VXRFORM(vcmpgefp, 3, 7)
GEN_VXRFORM(vcmpgtfp, 3, 11)
GEN_VXRFORM(vcmpbfp, 3, 15)
6450

A
aurel32 已提交
6451 6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470
#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);

6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485
#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 已提交
6486 6487 6488 6489
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 已提交
6490 6491
GEN_VXFORM_NOA(vupkhpx, 7, 13);
GEN_VXFORM_NOA(vupklpx, 7, 15);
A
aurel32 已提交
6492
GEN_VXFORM_NOA(vrefp, 5, 4);
A
aurel32 已提交
6493
GEN_VXFORM_NOA(vrsqrtefp, 5, 5);
6494
GEN_VXFORM_NOA(vlogefp, 5, 7);
A
aurel32 已提交
6495 6496 6497 6498
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 已提交
6499

6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515
#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);                                          \
    }

6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533
#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 已提交
6534 6535 6536
GEN_VXFORM_UIMM(vspltb, 6, 8);
GEN_VXFORM_UIMM(vsplth, 6, 9);
GEN_VXFORM_UIMM(vspltw, 6, 10);
A
aurel32 已提交
6537 6538
GEN_VXFORM_UIMM(vcfux, 5, 12);
GEN_VXFORM_UIMM(vcfsx, 5, 13);
6539 6540
GEN_VXFORM_UIMM(vctuxs, 5, 14);
GEN_VXFORM_UIMM(vctsxs, 5, 15);
A
aurel32 已提交
6541

A
aurel32 已提交
6542 6543 6544
GEN_HANDLER(vsldoi, 0x04, 0x16, 0xFF, 0x00000400, PPC_ALTIVEC)
{
    TCGv_ptr ra, rb, rd;
6545
    TCGv_i32 sh;
A
aurel32 已提交
6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557
    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);
6558
    tcg_temp_free_i32(sh);
A
aurel32 已提交
6559 6560
}

6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 6580 6581 6582 6583
#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 已提交
6584 6585
GEN_VAFORM_PAIRED(vmhaddshs, vmhraddshs, 16)

A
aurel32 已提交
6586 6587 6588 6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603
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 已提交
6604
GEN_VAFORM_PAIRED(vmsumubm, vmsummbm, 18)
A
aurel32 已提交
6605
GEN_VAFORM_PAIRED(vmsumuhm, vmsumuhs, 19)
A
aurel32 已提交
6606
GEN_VAFORM_PAIRED(vmsumshm, vmsumshs, 20)
A
aurel32 已提交
6607
GEN_VAFORM_PAIRED(vsel, vperm, 21)
6608
GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23)
A
aurel32 已提交
6609

6610 6611
/***                           SPE extension                               ***/
/* Register moves */
6612

P
pbrook 已提交
6613
static always_inline void gen_load_gpr64(TCGv_i64 t, int reg) {
A
aurel32 已提交
6614 6615 6616
#if defined(TARGET_PPC64)
    tcg_gen_mov_i64(t, cpu_gpr[reg]);
#else
P
pbrook 已提交
6617
    tcg_gen_concat_i32_i64(t, cpu_gpr[reg], cpu_gprh[reg]);
6618
#endif
A
aurel32 已提交
6619
}
6620

P
pbrook 已提交
6621
static always_inline void gen_store_gpr64(int reg, TCGv_i64 t) {
A
aurel32 已提交
6622 6623 6624
#if defined(TARGET_PPC64)
    tcg_gen_mov_i64(cpu_gpr[reg], t);
#else
P
pbrook 已提交
6625
    TCGv_i64 tmp = tcg_temp_new_i64();
A
aurel32 已提交
6626 6627 6628
    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 已提交
6629
    tcg_temp_free_i64(tmp);
6630
#endif
A
aurel32 已提交
6631
}
6632

6633 6634 6635 6636 6637 6638 6639 6640 6641 6642
#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 */
6643
static always_inline void gen_speundef (DisasContext *ctx)
6644
{
A
aurel32 已提交
6645
    gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
6646 6647
}

6648 6649 6650
/* SPE logic */
#if defined(TARGET_PPC64)
#define GEN_SPEOP_LOGIC2(name, tcg_op)                                        \
6651
static always_inline void gen_##name (DisasContext *ctx)                      \
6652 6653
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
6654
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6655 6656
        return;                                                               \
    }                                                                         \
6657 6658 6659 6660 6661 6662 6663 6664
    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 已提交
6665
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6666 6667 6668 6669 6670 6671
        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)]);                                        \
6672
}
6673 6674 6675 6676 6677 6678 6679 6680 6681 6682
#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);
6683

6684 6685 6686
/* SPE logic immediate */
#if defined(TARGET_PPC64)
#define GEN_SPEOP_TCG_LOGIC_IMM2(name, tcg_opi)                               \
6687 6688 6689
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
6690
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6691 6692
        return;                                                               \
    }                                                                         \
P
pbrook 已提交
6693 6694 6695
    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
    TCGv_i64 t2 = tcg_temp_local_new_i64();                                   \
6696 6697 6698 6699
    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 已提交
6700
    tcg_temp_free_i64(t2);                                                    \
6701 6702
    tcg_opi(t1, t1, rB(ctx->opcode));                                         \
    tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1);                 \
P
pbrook 已提交
6703 6704
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
6705
}
6706 6707
#else
#define GEN_SPEOP_TCG_LOGIC_IMM2(name, tcg_opi)                               \
6708
static always_inline void gen_##name (DisasContext *ctx)                      \
6709 6710
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
6711
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6712 6713
        return;                                                               \
    }                                                                         \
6714 6715 6716 6717
    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));                                                 \
6718
}
6719 6720 6721 6722 6723
#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);
6724

6725 6726 6727
/* SPE arithmetic */
#if defined(TARGET_PPC64)
#define GEN_SPEOP_ARITH1(name, tcg_op)                                        \
6728
static always_inline void gen_##name (DisasContext *ctx)                      \
6729 6730
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
6731
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6732 6733
        return;                                                               \
    }                                                                         \
P
pbrook 已提交
6734 6735 6736
    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
    TCGv_i64 t2 = tcg_temp_local_new_i64();                                   \
6737 6738 6739 6740
    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 已提交
6741
    tcg_temp_free_i64(t2);                                                    \
6742 6743
    tcg_op(t1, t1);                                                           \
    tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1);                 \
P
pbrook 已提交
6744 6745
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
6746
}
6747
#else
P
pbrook 已提交
6748
#define GEN_SPEOP_ARITH1(name, tcg_op)                                        \
6749 6750 6751
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
6752
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6753 6754 6755 6756 6757 6758
        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
6759

P
pbrook 已提交
6760
static always_inline void gen_op_evabs (TCGv_i32 ret, TCGv_i32 arg1)
6761 6762 6763
{
    int l1 = gen_new_label();
    int l2 = gen_new_label();
6764

6765 6766 6767 6768
    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 已提交
6769
    tcg_gen_mov_i32(ret, arg1);
6770 6771 6772 6773 6774 6775
    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 已提交
6776
static always_inline void gen_op_evrndw (TCGv_i32 ret, TCGv_i32 arg1)
6777
{
6778 6779 6780 6781
    tcg_gen_addi_i32(ret, arg1, 0x8000);
    tcg_gen_ext16u_i32(ret, ret);
}
GEN_SPEOP_ARITH1(evrndw, gen_op_evrndw);
P
pbrook 已提交
6782 6783
GEN_SPEOP_ARITH1(evcntlsw, gen_helper_cntlsw32);
GEN_SPEOP_ARITH1(evcntlzw, gen_helper_cntlzw32);
6784

6785 6786 6787
#if defined(TARGET_PPC64)
#define GEN_SPEOP_ARITH2(name, tcg_op)                                        \
static always_inline void gen_##name (DisasContext *ctx)                      \
6788 6789
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
6790
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6791 6792
        return;                                                               \
    }                                                                         \
P
pbrook 已提交
6793 6794 6795
    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t2 = tcg_temp_local_new_i32();                                   \
6796
    TCGv_i64 t3 = tcg_temp_local_new_i64();                                   \
6797 6798 6799 6800 6801 6802 6803
    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 已提交
6804
    tcg_temp_free_i64(t3);                                                    \
6805
    tcg_op(t1, t1, t2);                                                       \
P
pbrook 已提交
6806
    tcg_temp_free_i32(t2);                                                    \
6807
    tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1);                 \
P
pbrook 已提交
6808 6809
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
6810
}
6811 6812 6813
#else
#define GEN_SPEOP_ARITH2(name, tcg_op)                                        \
static always_inline void gen_##name (DisasContext *ctx)                      \
6814 6815
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
6816
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6817 6818
        return;                                                               \
    }                                                                         \
6819 6820 6821 6822
    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)]);                                        \
6823
}
6824
#endif
6825

P
pbrook 已提交
6826
static always_inline void gen_op_evsrwu (TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
6827
{
P
pbrook 已提交
6828
    TCGv_i32 t0;
6829
    int l1, l2;
6830

6831 6832
    l1 = gen_new_label();
    l2 = gen_new_label();
P
pbrook 已提交
6833
    t0 = tcg_temp_local_new_i32();
6834 6835 6836 6837 6838 6839 6840 6841
    /* 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 已提交
6842
    tcg_temp_free_i32(t0);
6843 6844
}
GEN_SPEOP_ARITH2(evsrwu, gen_op_evsrwu);
P
pbrook 已提交
6845
static always_inline void gen_op_evsrws (TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
6846
{
P
pbrook 已提交
6847
    TCGv_i32 t0;
6848 6849 6850 6851
    int l1, l2;

    l1 = gen_new_label();
    l2 = gen_new_label();
P
pbrook 已提交
6852
    t0 = tcg_temp_local_new_i32();
6853 6854 6855 6856 6857 6858 6859 6860
    /* 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 已提交
6861
    tcg_temp_free_i32(t0);
6862 6863
}
GEN_SPEOP_ARITH2(evsrws, gen_op_evsrws);
P
pbrook 已提交
6864
static always_inline void gen_op_evslw (TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
6865
{
P
pbrook 已提交
6866
    TCGv_i32 t0;
6867 6868 6869 6870
    int l1, l2;

    l1 = gen_new_label();
    l2 = gen_new_label();
P
pbrook 已提交
6871
    t0 = tcg_temp_local_new_i32();
6872 6873 6874 6875 6876 6877 6878 6879
    /* 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 已提交
6880
    tcg_temp_free_i32(t0);
6881 6882
}
GEN_SPEOP_ARITH2(evslw, gen_op_evslw);
P
pbrook 已提交
6883
static always_inline void gen_op_evrlw (TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
6884
{
P
pbrook 已提交
6885
    TCGv_i32 t0 = tcg_temp_new_i32();
6886 6887
    tcg_gen_andi_i32(t0, arg2, 0x1F);
    tcg_gen_rotl_i32(ret, arg1, t0);
P
pbrook 已提交
6888
    tcg_temp_free_i32(t0);
6889 6890 6891 6892 6893
}
GEN_SPEOP_ARITH2(evrlw, gen_op_evrlw);
static always_inline void gen_evmergehi (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
A
aurel32 已提交
6894
        gen_exception(ctx, POWERPC_EXCP_APU);
6895 6896 6897
        return;
    }
#if defined(TARGET_PPC64)
P
pbrook 已提交
6898 6899
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910
    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 已提交
6911
static always_inline void gen_op_evsubf (TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
6912
{
6913 6914 6915
    tcg_gen_sub_i32(ret, arg2, arg1);
}
GEN_SPEOP_ARITH2(evsubfw, gen_op_evsubf);
6916

6917 6918 6919 6920 6921 6922
/* 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 已提交
6923
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6924 6925
        return;                                                               \
    }                                                                         \
P
pbrook 已提交
6926 6927 6928
    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
    TCGv_i64 t2 = tcg_temp_local_new_i64();                                   \
6929 6930 6931 6932
    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 已提交
6933
    tcg_temp_free_i64(t2);                                                    \
6934 6935
    tcg_op(t1, t1, rA(ctx->opcode));                                          \
    tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1);                 \
P
pbrook 已提交
6936 6937
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
6938 6939 6940 6941 6942 6943
}
#else
#define GEN_SPEOP_ARITH_IMM2(name, tcg_op)                                    \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
6944
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6945 6946 6947 6948 6949 6950 6951 6952 6953 6954 6955 6956 6957 6958 6959 6960 6961
        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 已提交
6962
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6963 6964 6965 6966 6967 6968
        return;                                                               \
    }                                                                         \
    int l1 = gen_new_label();                                                 \
    int l2 = gen_new_label();                                                 \
    int l3 = gen_new_label();                                                 \
    int l4 = gen_new_label();                                                 \
P
pbrook 已提交
6969 6970 6971
    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
    TCGv_i64 t2 = tcg_temp_local_new_i64();                                   \
6972 6973 6974
    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 已提交
6975
    tcg_gen_movi_i32(cpu_crf[crfD(ctx->opcode)], 0);                          \
6976 6977 6978 6979 6980 6981 6982 6983 6984
    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 已提交
6985
    tcg_temp_free_i64(t2);                                                    \
6986 6987 6988 6989 6990 6991 6992 6993
    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 已提交
6994 6995
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
6996 6997 6998 6999 7000 7001
}
#else
#define GEN_SPEOP_COMP(name, tcg_cond)                                        \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
7002
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
7003 7004 7005 7006 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 7038
        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 已提交
7039 7040
    gen_helper_brinc(cpu_gpr[rD(ctx->opcode)],
                     cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
7041
}
7042 7043 7044
static always_inline void gen_evmergelo (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
A
aurel32 已提交
7045
        gen_exception(ctx, POWERPC_EXCP_APU);
7046 7047 7048
        return;
    }
#if defined(TARGET_PPC64)
P
pbrook 已提交
7049 7050
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
7051 7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 7062 7063
    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 已提交
7064
        gen_exception(ctx, POWERPC_EXCP_APU);
7065 7066 7067
        return;
    }
#if defined(TARGET_PPC64)
P
pbrook 已提交
7068 7069
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 7080 7081 7082
    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 已提交
7083
        gen_exception(ctx, POWERPC_EXCP_APU);
7084 7085 7086
        return;
    }
#if defined(TARGET_PPC64)
P
pbrook 已提交
7087 7088
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
7089 7090 7091 7092 7093 7094 7095 7096 7097 7098 7099 7100
    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)
{
7101
    uint64_t imm = ((int32_t)(rA(ctx->opcode) << 11)) >> 27;
7102

7103
#if defined(TARGET_PPC64)
7104
    tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], (imm << 32) | imm);
7105 7106 7107 7108 7109
#else
    tcg_gen_movi_i32(cpu_gpr[rD(ctx->opcode)], imm);
    tcg_gen_movi_i32(cpu_gprh[rD(ctx->opcode)], imm);
#endif
}
7110
static always_inline void gen_evsplatfi (DisasContext *ctx)
7111
{
7112
    uint64_t imm = rA(ctx->opcode) << 11;
7113

7114
#if defined(TARGET_PPC64)
7115
    tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], (imm << 32) | imm);
7116 7117 7118 7119
#else
    tcg_gen_movi_i32(cpu_gpr[rD(ctx->opcode)], imm);
    tcg_gen_movi_i32(cpu_gprh[rD(ctx->opcode)], imm);
#endif
7120 7121
}

7122 7123 7124 7125 7126 7127
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 已提交
7128
    TCGv_i32 t0 = tcg_temp_local_new_i32();
7129
#if defined(TARGET_PPC64)
P
pbrook 已提交
7130 7131
    TCGv t1 = tcg_temp_local_new();
    TCGv t2 = tcg_temp_local_new();
7132 7133 7134 7135 7136 7137 7138 7139 7140 7141 7142 7143 7144 7145 7146 7147 7148 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7160 7161 7162
#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 已提交
7163
    tcg_temp_free_i32(t0);
7164 7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 7182 7183 7184 7185
#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);
}
7186 7187 7188 7189 7190 7191 7192 7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212

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); ////

7213
/* SPE load and stores */
A
aurel32 已提交
7214
static always_inline void gen_addr_spe_imm_index (DisasContext *ctx, TCGv EA, int sh)
7215 7216 7217
{
    target_ulong uimm = rB(ctx->opcode);

A
aurel32 已提交
7218
    if (rA(ctx->opcode) == 0) {
7219
        tcg_gen_movi_tl(EA, uimm << sh);
A
aurel32 已提交
7220
    } else {
7221
        tcg_gen_addi_tl(EA, cpu_gpr[rA(ctx->opcode)], uimm << sh);
A
aurel32 已提交
7222 7223 7224 7225 7226 7227
#if defined(TARGET_PPC64)
        if (!ctx->sf_mode) {
            tcg_gen_ext32u_tl(EA, EA);
        }
#endif
    }
7228
}
7229 7230 7231 7232

static always_inline void gen_op_evldd(DisasContext *ctx, TCGv addr)
{
#if defined(TARGET_PPC64)
A
aurel32 已提交
7233
    gen_qemu_ld64(ctx, cpu_gpr[rD(ctx->opcode)], addr);
7234 7235
#else
    TCGv_i64 t0 = tcg_temp_new_i64();
A
aurel32 已提交
7236
    gen_qemu_ld64(ctx, t0, addr);
7237 7238 7239 7240 7241
    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
7242
}
7243 7244 7245

static always_inline void gen_op_evldw(DisasContext *ctx, TCGv addr)
{
7246
#if defined(TARGET_PPC64)
7247
    TCGv t0 = tcg_temp_new();
A
aurel32 已提交
7248
    gen_qemu_ld32u(ctx, t0, addr);
7249
    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 32);
A
aurel32 已提交
7250 7251
    gen_addr_add(ctx, addr, addr, 4);
    gen_qemu_ld32u(ctx, t0, addr);
7252 7253 7254
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
    tcg_temp_free(t0);
#else
A
aurel32 已提交
7255 7256 7257
    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);
7258
#endif
7259
}
7260 7261 7262 7263 7264

static always_inline void gen_op_evldh(DisasContext *ctx, TCGv addr)
{
    TCGv t0 = tcg_temp_new();
#if defined(TARGET_PPC64)
A
aurel32 已提交
7265
    gen_qemu_ld16u(ctx, t0, addr);
7266
    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 48);
A
aurel32 已提交
7267 7268
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, t0, addr);
7269 7270
    tcg_gen_shli_tl(t0, t0, 32);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
A
aurel32 已提交
7271 7272
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, t0, addr);
7273 7274
    tcg_gen_shli_tl(t0, t0, 16);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
A
aurel32 已提交
7275 7276
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, t0, addr);
7277
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
7278
#else
A
aurel32 已提交
7279
    gen_qemu_ld16u(ctx, t0, addr);
7280
    tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16);
A
aurel32 已提交
7281 7282
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, t0, addr);
7283
    tcg_gen_or_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rD(ctx->opcode)], t0);
A
aurel32 已提交
7284 7285
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, t0, addr);
7286
    tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16);
A
aurel32 已提交
7287 7288
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, t0, addr);
7289
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
7290
#endif
7291
    tcg_temp_free(t0);
7292 7293
}

7294 7295 7296
static always_inline void gen_op_evlhhesplat(DisasContext *ctx, TCGv addr)
{
    TCGv t0 = tcg_temp_new();
A
aurel32 已提交
7297
    gen_qemu_ld16u(ctx, t0, addr);
7298 7299 7300 7301 7302 7303 7304 7305 7306 7307
#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);
7308 7309
}

7310 7311 7312
static always_inline void gen_op_evlhhousplat(DisasContext *ctx, TCGv addr)
{
    TCGv t0 = tcg_temp_new();
A
aurel32 已提交
7313
    gen_qemu_ld16u(ctx, t0, addr);
7314 7315 7316 7317 7318 7319 7320 7321
#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);
7322 7323
}

7324 7325 7326
static always_inline void gen_op_evlhhossplat(DisasContext *ctx, TCGv addr)
{
    TCGv t0 = tcg_temp_new();
A
aurel32 已提交
7327
    gen_qemu_ld16s(ctx, t0, addr);
7328 7329 7330 7331 7332 7333 7334 7335 7336 7337 7338 7339 7340 7341 7342
#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 已提交
7343
    gen_qemu_ld16u(ctx, t0, addr);
7344
    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 48);
A
aurel32 已提交
7345 7346
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, t0, addr);
7347 7348 7349
    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 已提交
7350
    gen_qemu_ld16u(ctx, t0, addr);
7351
    tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16);
A
aurel32 已提交
7352 7353
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, t0, addr);
7354 7355 7356 7357 7358 7359 7360 7361 7362
    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 已提交
7363 7364 7365
    gen_qemu_ld16u(ctx, cpu_gpr[rD(ctx->opcode)], addr);
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, t0, addr);
7366 7367 7368 7369
    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 已提交
7370 7371 7372
    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);
7373 7374 7375 7376 7377 7378 7379
#endif
}

static always_inline void gen_op_evlwhos(DisasContext *ctx, TCGv addr)
{
#if defined(TARGET_PPC64)
    TCGv t0 = tcg_temp_new();
A
aurel32 已提交
7380
    gen_qemu_ld16s(ctx, t0, addr);
7381
    tcg_gen_ext32u_tl(cpu_gpr[rD(ctx->opcode)], t0);
A
aurel32 已提交
7382 7383
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16s(ctx, t0, addr);
7384 7385 7386 7387
    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 已提交
7388 7389 7390
    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);
7391 7392 7393 7394 7395 7396
#endif
}

static always_inline void gen_op_evlwwsplat(DisasContext *ctx, TCGv addr)
{
    TCGv t0 = tcg_temp_new();
A
aurel32 已提交
7397
    gen_qemu_ld32u(ctx, t0, addr);
7398
#if defined(TARGET_PPC64)
7399 7400 7401 7402 7403 7404 7405 7406 7407 7408 7409 7410 7411
    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 已提交
7412
    gen_qemu_ld16u(ctx, t0, addr);
7413 7414 7415
    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 已提交
7416 7417
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, t0, addr);
7418 7419 7420 7421
    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 已提交
7422
    gen_qemu_ld16u(ctx, t0, addr);
7423 7424
    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 已提交
7425 7426
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, t0, addr);
7427 7428
    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);
7429
#endif
7430 7431 7432 7433 7434 7435
    tcg_temp_free(t0);
}

static always_inline void gen_op_evstdd(DisasContext *ctx, TCGv addr)
{
#if defined(TARGET_PPC64)
A
aurel32 已提交
7436
    gen_qemu_st64(ctx, cpu_gpr[rS(ctx->opcode)], addr);
7437
#else
7438 7439
    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 已提交
7440
    gen_qemu_st64(ctx, t0, addr);
7441 7442 7443 7444 7445 7446
    tcg_temp_free_i64(t0);
#endif
}

static always_inline void gen_op_evstdw(DisasContext *ctx, TCGv addr)
{
7447
#if defined(TARGET_PPC64)
7448 7449
    TCGv t0 = tcg_temp_new();
    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 32);
A
aurel32 已提交
7450
    gen_qemu_st32(ctx, t0, addr);
7451 7452
    tcg_temp_free(t0);
#else
A
aurel32 已提交
7453
    gen_qemu_st32(ctx, cpu_gprh[rS(ctx->opcode)], addr);
7454
#endif
A
aurel32 已提交
7455 7456
    gen_addr_add(ctx, addr, addr, 4);
    gen_qemu_st32(ctx, cpu_gpr[rS(ctx->opcode)], addr);
7457 7458 7459 7460 7461 7462 7463 7464 7465 7466
}

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 已提交
7467 7468
    gen_qemu_st16(ctx, t0, addr);
    gen_addr_add(ctx, addr, addr, 2);
7469 7470
#if defined(TARGET_PPC64)
    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 32);
A
aurel32 已提交
7471
    gen_qemu_st16(ctx, t0, addr);
7472
#else
A
aurel32 已提交
7473
    gen_qemu_st16(ctx, cpu_gprh[rS(ctx->opcode)], addr);
7474
#endif
A
aurel32 已提交
7475
    gen_addr_add(ctx, addr, addr, 2);
7476
    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 16);
A
aurel32 已提交
7477
    gen_qemu_st16(ctx, t0, addr);
7478
    tcg_temp_free(t0);
A
aurel32 已提交
7479 7480
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_st16(ctx, cpu_gpr[rS(ctx->opcode)], addr);
7481 7482 7483 7484 7485 7486 7487 7488 7489 7490
}

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 已提交
7491 7492
    gen_qemu_st16(ctx, t0, addr);
    gen_addr_add(ctx, addr, addr, 2);
7493
    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 16);
A
aurel32 已提交
7494
    gen_qemu_st16(ctx, t0, addr);
7495 7496 7497 7498 7499 7500 7501 7502
    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 已提交
7503
    gen_qemu_st16(ctx, t0, addr);
7504 7505
    tcg_temp_free(t0);
#else
A
aurel32 已提交
7506
    gen_qemu_st16(ctx, cpu_gprh[rS(ctx->opcode)], addr);
7507
#endif
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
}

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 已提交
7517
    gen_qemu_st32(ctx, t0, addr);
7518 7519
    tcg_temp_free(t0);
#else
A
aurel32 已提交
7520
    gen_qemu_st32(ctx, cpu_gprh[rS(ctx->opcode)], addr);
7521 7522 7523 7524 7525
#endif
}

static always_inline void gen_op_evstwwo(DisasContext *ctx, TCGv addr)
{
A
aurel32 已提交
7526
    gen_qemu_st32(ctx, cpu_gpr[rS(ctx->opcode)], addr);
7527 7528 7529
}

#define GEN_SPEOP_LDST(name, opc2, sh)                                        \
A
aurel32 已提交
7530
GEN_HANDLER(name, 0x04, opc2, 0x0C, 0x00000000, PPC_SPE)                      \
7531 7532 7533
{                                                                             \
    TCGv t0;                                                                  \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
7534
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
7535 7536
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
7537
    gen_set_access_type(ctx, ACCESS_INT);                                     \
7538 7539
    t0 = tcg_temp_new();                                                      \
    if (Rc(ctx->opcode)) {                                                    \
A
aurel32 已提交
7540
        gen_addr_spe_imm_index(ctx, t0, sh);                                  \
7541
    } else {                                                                  \
A
aurel32 已提交
7542
        gen_addr_reg_index(ctx, t0);                                          \
7543 7544 7545 7546 7547 7548 7549 7550 7551 7552 7553 7554 7555 7556 7557 7558 7559 7560 7561 7562 7563 7564 7565 7566
    }                                                                         \
    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);
7567 7568 7569 7570 7571 7572 7573 7574 7575 7576 7577 7578 7579 7580 7581 7582 7583 7584 7585 7586 7587 7588 7589 7590 7591 7592 7593 7594 7595 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

/* 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 已提交
7645 7646
#if defined(TARGET_PPC64)
#define GEN_SPEFPUOP_CONV_32_32(name)                                         \
7647
static always_inline void gen_##name (DisasContext *ctx)                      \
7648
{                                                                             \
A
aurel32 已提交
7649 7650 7651 7652 7653 7654 7655 7656 7657 7658 7659 7660
    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);                                                        \
7661
}
A
aurel32 已提交
7662 7663 7664 7665 7666 7667 7668 7669 7670 7671 7672 7673 7674 7675 7676 7677 7678 7679 7680 7681 7682 7683 7684 7685 7686 7687 7688 7689 7690
#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)                                       \
7691 7692
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
A
aurel32 已提交
7693 7694
    TCGv_i32 t0, t1;                                                          \
    TCGv_i64 t2;                                                              \
7695
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
7696
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
7697 7698
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
7699 7700 7701 7702 7703 7704 7705 7706 7707 7708 7709 7710 7711
    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);                                                        \
7712
}
A
aurel32 已提交
7713
#define GEN_SPEFPUOP_ARITH2_64_64(name)                                       \
7714 7715 7716
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
7717
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
7718 7719
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
7720 7721
    gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],     \
                      cpu_gpr[rB(ctx->opcode)]);                              \
7722
}
A
aurel32 已提交
7723
#define GEN_SPEFPUOP_COMP_32(name)                                            \
7724 7725
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
A
aurel32 已提交
7726
    TCGv_i32 t0, t1;                                                          \
7727
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
7728
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
7729 7730
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
7731 7732 7733 7734 7735 7736 7737 7738 7739 7740 7741 7742
    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 已提交
7743
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
A
aurel32 已提交
7744 7745 7746 7747 7748 7749 7750 7751 7752 7753
        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)]);    \
7754
}
A
aurel32 已提交
7755 7756 7757 7758 7759 7760 7761 7762 7763 7764 7765 7766 7767 7768 7769 7770 7771 7772 7773 7774 7775 7776 7777 7778 7779 7780 7781 7782 7783
#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 已提交
7784
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
A
aurel32 已提交
7785 7786 7787 7788 7789 7790 7791 7792 7793 7794
        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 已提交
7795
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
A
aurel32 已提交
7796 7797 7798 7799 7800 7801 7802 7803 7804 7805 7806 7807 7808 7809 7810
        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 已提交
7811
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
A
aurel32 已提交
7812 7813 7814 7815 7816 7817 7818 7819 7820 7821
        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 已提交
7822
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
A
aurel32 已提交
7823 7824 7825 7826 7827 7828 7829 7830 7831 7832 7833
        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
7834

7835 7836
/* Single precision floating-point vectors operations */
/* Arithmetic */
A
aurel32 已提交
7837 7838 7839 7840 7841 7842 7843
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 已提交
7844
        gen_exception(ctx, POWERPC_EXCP_APU);
A
aurel32 已提交
7845 7846 7847 7848 7849 7850 7851 7852 7853 7854 7855 7856
        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 已提交
7857
        gen_exception(ctx, POWERPC_EXCP_APU);
A
aurel32 已提交
7858 7859 7860 7861 7862 7863 7864 7865 7866 7867 7868 7869
        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 已提交
7870
        gen_exception(ctx, POWERPC_EXCP_APU);
A
aurel32 已提交
7871 7872 7873 7874 7875 7876 7877 7878 7879 7880
        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
}

7881
/* Conversion */
A
aurel32 已提交
7882 7883 7884 7885 7886 7887 7888 7889 7890 7891 7892
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);

7893
/* Comparison */
A
aurel32 已提交
7894 7895 7896 7897 7898 7899
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);
7900 7901

/* Opcodes definitions */
7902 7903 7904 7905 7906 7907 7908 7909 7910 7911 7912 7913 7914 7915
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); //
7916 7917 7918

/* Single precision floating-point operations */
/* Arithmetic */
A
aurel32 已提交
7919 7920 7921 7922 7923 7924 7925
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 已提交
7926
        gen_exception(ctx, POWERPC_EXCP_APU);
A
aurel32 已提交
7927 7928 7929 7930 7931 7932 7933
        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 已提交
7934
        gen_exception(ctx, POWERPC_EXCP_APU);
A
aurel32 已提交
7935 7936 7937 7938 7939 7940 7941
        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 已提交
7942
        gen_exception(ctx, POWERPC_EXCP_APU);
A
aurel32 已提交
7943 7944 7945 7946 7947
        return;
    }
    tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
}

7948
/* Conversion */
A
aurel32 已提交
7949 7950 7951 7952 7953 7954 7955 7956 7957 7958 7959 7960
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);

7961
/* Comparison */
A
aurel32 已提交
7962 7963 7964 7965 7966 7967
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);
7968 7969

/* Opcodes definitions */
7970 7971 7972 7973 7974 7975 7976 7977 7978 7979 7980 7981 7982 7983
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); //
7984 7985 7986

/* Double precision floating-point operations */
/* Arithmetic */
A
aurel32 已提交
7987 7988 7989 7990 7991 7992 7993
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 已提交
7994
        gen_exception(ctx, POWERPC_EXCP_APU);
A
aurel32 已提交
7995 7996 7997 7998 7999 8000 8001 8002 8003 8004 8005
        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 已提交
8006
        gen_exception(ctx, POWERPC_EXCP_APU);
A
aurel32 已提交
8007 8008 8009 8010 8011 8012 8013 8014 8015 8016 8017
        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 已提交
8018
        gen_exception(ctx, POWERPC_EXCP_APU);
A
aurel32 已提交
8019 8020 8021 8022 8023 8024 8025 8026 8027
        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
}

8028
/* Conversion */
A
aurel32 已提交
8029 8030 8031 8032 8033 8034 8035 8036 8037 8038 8039 8040 8041 8042 8043
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);
8044 8045

/* Comparison */
A
aurel32 已提交
8046 8047 8048 8049 8050 8051
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);
8052 8053

/* Opcodes definitions */
8054 8055 8056 8057 8058 8059 8060 8061 8062 8063 8064 8065 8066 8067 8068 8069
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); //
8070

B
bellard 已提交
8071 8072 8073
/* End opcode list */
GEN_OPCODE_MARK(end);

8074
#include "translate_init.c"
8075
#include "helper_regs.h"
B
bellard 已提交
8076

8077
/*****************************************************************************/
8078
/* Misc PowerPC helpers */
8079 8080 8081
void cpu_dump_state (CPUState *env, FILE *f,
                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
                     int flags)
B
bellard 已提交
8082
{
8083 8084 8085
#define RGPL  4
#define RFPL  4

B
bellard 已提交
8086 8087
    int i;

J
j_mayer 已提交
8088
    cpu_fprintf(f, "NIP " ADDRX "   LR " ADDRX " CTR " ADDRX " XER %08x\n",
A
aurel32 已提交
8089
                env->nip, env->lr, env->ctr, env->xer);
8090 8091
    cpu_fprintf(f, "MSR " ADDRX " HID0 " ADDRX "  HF " ADDRX " idx %d\n",
                env->msr, env->spr[SPR_HID0], env->hflags, env->mmu_idx);
8092
#if !defined(NO_TIMER_DUMP)
J
j_mayer 已提交
8093
    cpu_fprintf(f, "TB %08x %08x "
8094 8095 8096 8097
#if !defined(CONFIG_USER_ONLY)
                "DECR %08x"
#endif
                "\n",
J
j_mayer 已提交
8098
                cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env)
8099 8100 8101 8102
#if !defined(CONFIG_USER_ONLY)
                , cpu_ppc_load_decr(env)
#endif
                );
J
j_mayer 已提交
8103
#endif
8104
    for (i = 0; i < 32; i++) {
8105 8106
        if ((i & (RGPL - 1)) == 0)
            cpu_fprintf(f, "GPR%02d", i);
8107
        cpu_fprintf(f, " " REGX, ppc_dump_gpr(env, i));
8108
        if ((i & (RGPL - 1)) == (RGPL - 1))
B
bellard 已提交
8109
            cpu_fprintf(f, "\n");
8110
    }
8111
    cpu_fprintf(f, "CR ");
8112
    for (i = 0; i < 8; i++)
B
bellard 已提交
8113 8114
        cpu_fprintf(f, "%01x", env->crf[i]);
    cpu_fprintf(f, "  [");
8115 8116 8117 8118 8119 8120 8121 8122
    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 已提交
8123
        cpu_fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' ');
8124
    }
8125
    cpu_fprintf(f, " ]             RES " ADDRX "\n", env->reserve);
8126 8127 8128
    for (i = 0; i < 32; i++) {
        if ((i & (RFPL - 1)) == 0)
            cpu_fprintf(f, "FPR%02d", i);
B
bellard 已提交
8129
        cpu_fprintf(f, " %016" PRIx64, *((uint64_t *)&env->fpr[i]));
8130
        if ((i & (RFPL - 1)) == (RFPL - 1))
B
bellard 已提交
8131
            cpu_fprintf(f, "\n");
B
bellard 已提交
8132
    }
8133
    cpu_fprintf(f, "FPSCR %08x\n", env->fpscr);
8134
#if !defined(CONFIG_USER_ONLY)
8135
    cpu_fprintf(f, "SRR0 " ADDRX " SRR1 " ADDRX " SDR1 " ADDRX "\n",
8136
                env->spr[SPR_SRR0], env->spr[SPR_SRR1], env->sdr1);
8137
#endif
B
bellard 已提交
8138

8139 8140
#undef RGPL
#undef RFPL
B
bellard 已提交
8141 8142
}

8143 8144 8145 8146 8147 8148 8149 8150 8151 8152 8153 8154 8155 8156 8157 8158 8159 8160 8161 8162 8163 8164 8165 8166 8167 8168 8169 8170 8171 8172 8173 8174 8175 8176 8177 8178 8179 8180 8181 8182 8183 8184 8185 8186 8187 8188 8189
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
}

8190
/*****************************************************************************/
8191 8192 8193
static always_inline void gen_intermediate_code_internal (CPUState *env,
                                                          TranslationBlock *tb,
                                                          int search_pc)
B
bellard 已提交
8194
{
8195
    DisasContext ctx, *ctxp = &ctx;
B
bellard 已提交
8196
    opc_handler_t **table, *handler;
B
bellard 已提交
8197
    target_ulong pc_start;
B
bellard 已提交
8198
    uint16_t *gen_opc_end;
8199
    CPUBreakpoint *bp;
B
bellard 已提交
8200
    int j, lj = -1;
P
pbrook 已提交
8201 8202
    int num_insns;
    int max_insns;
B
bellard 已提交
8203 8204 8205

    pc_start = tb->pc;
    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
B
bellard 已提交
8206
    ctx.nip = pc_start;
B
bellard 已提交
8207
    ctx.tb = tb;
8208
    ctx.exception = POWERPC_EXCP_NONE;
8209
    ctx.spr_cb = env->spr_cb;
A
aurel32 已提交
8210 8211 8212
    ctx.mem_idx = env->mmu_idx;
    ctx.access_type = -1;
    ctx.le_mode = env->hflags & (1 << MSR_LE) ? 1 : 0;
8213 8214
#if defined(TARGET_PPC64)
    ctx.sf_mode = msr_sf;
8215
#endif
B
bellard 已提交
8216
    ctx.fpu_enabled = msr_fp;
8217
    if ((env->flags & POWERPC_FLAG_SPE) && msr_spe)
8218 8219 8220
        ctx.spe_enabled = msr_spe;
    else
        ctx.spe_enabled = 0;
8221 8222 8223 8224
    if ((env->flags & POWERPC_FLAG_VRE) && msr_vr)
        ctx.altivec_enabled = msr_vr;
    else
        ctx.altivec_enabled = 0;
8225
    if ((env->flags & POWERPC_FLAG_SE) && msr_se)
8226
        ctx.singlestep_enabled = CPU_SINGLE_STEP;
8227
    else
8228
        ctx.singlestep_enabled = 0;
8229
    if ((env->flags & POWERPC_FLAG_BE) && msr_be)
8230 8231 8232
        ctx.singlestep_enabled |= CPU_BRANCH_STEP;
    if (unlikely(env->singlestep_enabled))
        ctx.singlestep_enabled |= GDBSTUB_SINGLE_STEP;
8233
#if defined (DO_SINGLE_STEP) && 0
8234 8235 8236
    /* Single step trace mode */
    msr_se = 1;
#endif
P
pbrook 已提交
8237 8238 8239 8240 8241 8242
    num_insns = 0;
    max_insns = tb->cflags & CF_COUNT_MASK;
    if (max_insns == 0)
        max_insns = CF_COUNT_MASK;

    gen_icount_start();
8243
    /* Set env in case of segfault during code fetch */
8244
    while (ctx.exception == POWERPC_EXCP_NONE && gen_opc_ptr < gen_opc_end) {
8245 8246
        if (unlikely(!TAILQ_EMPTY(&env->breakpoints))) {
            TAILQ_FOREACH(bp, &env->breakpoints, entry) {
8247
                if (bp->pc == ctx.nip) {
A
aurel32 已提交
8248
                    gen_debug_exception(ctxp);
8249 8250 8251 8252
                    break;
                }
            }
        }
8253
        if (unlikely(search_pc)) {
B
bellard 已提交
8254 8255 8256 8257 8258
            j = gen_opc_ptr - gen_opc_buf;
            if (lj < j) {
                lj++;
                while (lj < j)
                    gen_opc_instr_start[lj++] = 0;
B
bellard 已提交
8259
                gen_opc_pc[lj] = ctx.nip;
B
bellard 已提交
8260
                gen_opc_instr_start[lj] = 1;
P
pbrook 已提交
8261
                gen_opc_icount[lj] = num_insns;
B
bellard 已提交
8262 8263
            }
        }
8264 8265 8266
        LOG_DISAS("----------------\n");
        LOG_DISAS("nip=" ADDRX " super=%d ir=%d\n",
                  ctx.nip, ctx.mem_idx, (int)msr_ir);
P
pbrook 已提交
8267 8268
        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
            gen_io_start();
A
aurel32 已提交
8269
        if (unlikely(ctx.le_mode)) {
8270 8271 8272
            ctx.opcode = bswap32(ldl_code(ctx.nip));
        } else {
            ctx.opcode = ldl_code(ctx.nip);
8273
        }
8274
        LOG_DISAS("translate opcode %08x (%02x %02x %02x) (%s)\n",
8275
                    ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode),
8276
                    opc3(ctx.opcode), little_endian ? "little" : "big");
B
bellard 已提交
8277
        ctx.nip += 4;
8278
        table = env->opcodes;
P
pbrook 已提交
8279
        num_insns++;
B
bellard 已提交
8280 8281 8282 8283 8284 8285 8286 8287 8288 8289
        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 ? */
8290
        if (unlikely(handler->handler == &gen_invalid)) {
8291 8292 8293 8294 8295
            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 已提交
8296 8297
            } else {
                printf("invalid/unsupported opcode: "
8298
                       "%02x - %02x - %02x (%08x) " ADDRX " %d\n",
B
bellard 已提交
8299
                       opc1(ctx.opcode), opc2(ctx.opcode),
8300
                       opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, (int)msr_ir);
B
bellard 已提交
8301
            }
8302 8303
        } else {
            if (unlikely((ctx.opcode & handler->inval) != 0)) {
8304 8305 8306 8307 8308 8309
                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);
8310 8311
                } else {
                    printf("invalid bits: %08x for opcode: "
8312
                           "%02x - %02x - %02x (%08x) " ADDRX "\n",
8313 8314
                           ctx.opcode & handler->inval, opc1(ctx.opcode),
                           opc2(ctx.opcode), opc3(ctx.opcode),
B
bellard 已提交
8315
                           ctx.opcode, ctx.nip - 4);
8316
                }
A
aurel32 已提交
8317
                gen_inval_exception(ctxp, POWERPC_EXCP_INVAL_INVAL);
B
bellard 已提交
8318
                break;
B
bellard 已提交
8319 8320
            }
        }
B
bellard 已提交
8321
        (*(handler->handler))(&ctx);
8322 8323 8324
#if defined(DO_PPC_STATISTICS)
        handler->count++;
#endif
8325
        /* Check trace mode exceptions */
8326 8327 8328 8329 8330
        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 已提交
8331
            gen_exception(ctxp, POWERPC_EXCP_TRACE);
8332
        } else if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) ||
P
pbrook 已提交
8333 8334
                            (env->singlestep_enabled) ||
                            num_insns >= max_insns)) {
8335 8336 8337
            /* if we reach a page boundary or are single stepping, stop
             * generation
             */
8338
            break;
8339
        }
8340 8341 8342 8343
#if defined (DO_SINGLE_STEP)
        break;
#endif
    }
P
pbrook 已提交
8344 8345
    if (tb->cflags & CF_LAST_IO)
        gen_io_end();
8346
    if (ctx.exception == POWERPC_EXCP_NONE) {
8347
        gen_goto_tb(&ctx, 0, ctx.nip);
8348
    } else if (ctx.exception != POWERPC_EXCP_BRANCH) {
8349
        if (unlikely(env->singlestep_enabled)) {
A
aurel32 已提交
8350
            gen_debug_exception(ctxp);
8351
        }
8352
        /* Generate the return instruction */
B
bellard 已提交
8353
        tcg_gen_exit_tb(0);
8354
    }
P
pbrook 已提交
8355
    gen_icount_end(tb, num_insns);
B
bellard 已提交
8356
    *gen_opc_ptr = INDEX_op_end;
8357
    if (unlikely(search_pc)) {
8358 8359 8360 8361 8362
        j = gen_opc_ptr - gen_opc_buf;
        lj++;
        while (lj <= j)
            gen_opc_instr_start[lj++] = 0;
    } else {
B
bellard 已提交
8363
        tb->size = ctx.nip - pc_start;
P
pbrook 已提交
8364
        tb->icount = num_insns;
8365
    }
8366
#if defined(DEBUG_DISAS)
8367 8368
    qemu_log_mask(CPU_LOG_TB_CPU, "---------------- excp: %04x\n", ctx.exception);
    log_cpu_state_mask(CPU_LOG_TB_CPU, env, 0);
8369
    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
8370
        int flags;
8371
        flags = env->bfd_mach;
A
aurel32 已提交
8372
        flags |= ctx.le_mode << 16;
8373 8374 8375
        qemu_log("IN: %s\n", lookup_symbol(pc_start));
        log_target_disas(pc_start, ctx.nip - pc_start, flags);
        qemu_log("\n");
8376
    }
B
bellard 已提交
8377 8378 8379
#endif
}

8380
void gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
B
bellard 已提交
8381
{
8382
    gen_intermediate_code_internal(env, tb, 0);
B
bellard 已提交
8383 8384
}

8385
void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
B
bellard 已提交
8386
{
8387
    gen_intermediate_code_internal(env, tb, 1);
B
bellard 已提交
8388
}
A
aurel32 已提交
8389 8390 8391 8392 8393 8394

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