translate.c 283.1 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 18 19
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
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"
B
bellard 已提交
31

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

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

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

46 47
/*****************************************************************************/
/* Code translation helpers                                                  */
B
bellard 已提交
48

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

/* dyngen register indexes */
static TCGv cpu_T[3];
P
pbrook 已提交
75 76 77 78 79

#include "gen-icount.h"

void ppc_translate_init(void)
{
A
aurel32 已提交
80 81
    int i;
    char* p;
P
pbrook 已提交
82
    static int done_init = 0;
A
aurel32 已提交
83

P
pbrook 已提交
84 85
    if (done_init)
        return;
A
aurel32 已提交
86

P
pbrook 已提交
87
    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
A
aurel32 已提交
88
#if TARGET_LONG_BITS > HOST_LONG_BITS
P
pbrook 已提交
89 90 91
    cpu_T[0] = tcg_global_mem_new(TCG_AREG0, offsetof(CPUState, t0), "T0");
    cpu_T[1] = tcg_global_mem_new(TCG_AREG0, offsetof(CPUState, t1), "T1");
    cpu_T[2] = tcg_global_mem_new(TCG_AREG0, offsetof(CPUState, t2), "T2");
A
aurel32 已提交
92
#else
P
pbrook 已提交
93 94
    cpu_T[0] = tcg_global_reg_new(TCG_AREG1, "T0");
    cpu_T[1] = tcg_global_reg_new(TCG_AREG2, "T1");
95 96 97 98 99
#ifdef HOST_I386
    /* XXX: This is a temporary workaround for i386.
     *      On i386 qemu_st32 runs out of registers.
     *      The proper fix is to remove cpu_T.
     */
P
pbrook 已提交
100
    cpu_T[2] = tcg_global_mem_new(TCG_AREG0, offsetof(CPUState, t2), "T2");
101
#else
P
pbrook 已提交
102
    cpu_T[2] = tcg_global_reg_new(TCG_AREG3, "T2");
A
aurel32 已提交
103
#endif
P
pbrook 已提交
104 105
#endif

A
aurel32 已提交
106
    p = cpu_reg_names;
A
aurel32 已提交
107 108 109

    for (i = 0; i < 8; i++) {
        sprintf(p, "crf%d", i);
P
pbrook 已提交
110 111
        cpu_crf[i] = tcg_global_mem_new_i32(TCG_AREG0,
                                            offsetof(CPUState, crf[i]), p);
A
aurel32 已提交
112 113 114
        p += 5;
    }

A
aurel32 已提交
115 116
    for (i = 0; i < 32; i++) {
        sprintf(p, "r%d", i);
P
pbrook 已提交
117
        cpu_gpr[i] = tcg_global_mem_new(TCG_AREG0,
A
aurel32 已提交
118 119 120 121
                                        offsetof(CPUState, gpr[i]), p);
        p += (i < 10) ? 3 : 4;
#if !defined(TARGET_PPC64)
        sprintf(p, "r%dH", i);
P
pbrook 已提交
122 123
        cpu_gprh[i] = tcg_global_mem_new_i32(TCG_AREG0,
                                             offsetof(CPUState, gprh[i]), p);
A
aurel32 已提交
124 125
        p += (i < 10) ? 4 : 5;
#endif
126

A
aurel32 已提交
127
        sprintf(p, "fp%d", i);
P
pbrook 已提交
128 129
        cpu_fpr[i] = tcg_global_mem_new_i64(TCG_AREG0,
                                            offsetof(CPUState, fpr[i]), p);
A
aurel32 已提交
130
        p += (i < 10) ? 4 : 5;
A
aurel32 已提交
131

132
        sprintf(p, "avr%dH", i);
133 134 135 136
#ifdef WORDS_BIGENDIAN
        cpu_avrh[i] = tcg_global_mem_new_i64(TCG_AREG0,
                                             offsetof(CPUState, avr[i].u64[0]), p);
#else
P
pbrook 已提交
137
        cpu_avrh[i] = tcg_global_mem_new_i64(TCG_AREG0,
138 139
                                             offsetof(CPUState, avr[i].u64[1]), p);
#endif
140
        p += (i < 10) ? 6 : 7;
A
aurel32 已提交
141

142
        sprintf(p, "avr%dL", i);
143 144 145 146
#ifdef WORDS_BIGENDIAN
        cpu_avrl[i] = tcg_global_mem_new_i64(TCG_AREG0,
                                             offsetof(CPUState, avr[i].u64[1]), p);
#else
P
pbrook 已提交
147
        cpu_avrl[i] = tcg_global_mem_new_i64(TCG_AREG0,
148 149
                                             offsetof(CPUState, avr[i].u64[0]), p);
#endif
150
        p += (i < 10) ? 6 : 7;
A
aurel32 已提交
151
    }
A
aurel32 已提交
152

P
pbrook 已提交
153
    cpu_nip = tcg_global_mem_new(TCG_AREG0,
A
aurel32 已提交
154 155
                                 offsetof(CPUState, nip), "nip");

P
pbrook 已提交
156
    cpu_ctr = tcg_global_mem_new(TCG_AREG0,
A
aurel32 已提交
157 158
                                 offsetof(CPUState, ctr), "ctr");

P
pbrook 已提交
159
    cpu_lr = tcg_global_mem_new(TCG_AREG0,
A
aurel32 已提交
160 161
                                offsetof(CPUState, lr), "lr");

P
pbrook 已提交
162
    cpu_xer = tcg_global_mem_new(TCG_AREG0,
A
aurel32 已提交
163 164
                                 offsetof(CPUState, xer), "xer");

165 166 167
    cpu_reserve = tcg_global_mem_new(TCG_AREG0,
                                     offsetof(CPUState, reserve), "reserve");

P
pbrook 已提交
168 169
    cpu_fpscr = tcg_global_mem_new_i32(TCG_AREG0,
                                       offsetof(CPUState, fpscr), "fpscr");
170

A
aurel32 已提交
171 172 173
    cpu_access_type = tcg_global_mem_new_i32(TCG_AREG0,
                                             offsetof(CPUState, access_type), "access_type");

A
aurel32 已提交
174
    /* register helpers */
P
pbrook 已提交
175
#define GEN_HELPER 2
A
aurel32 已提交
176 177
#include "helper.h"

P
pbrook 已提交
178 179 180
    done_init = 1;
}

181 182 183 184
#if defined(OPTIMIZE_FPRF_UPDATE)
static uint16_t *gen_fprf_buf[OPC_BUF_SIZE];
static uint16_t **gen_fprf_ptr;
#endif
B
bellard 已提交
185 186 187 188

/* internal defines */
typedef struct DisasContext {
    struct TranslationBlock *tb;
B
bellard 已提交
189
    target_ulong nip;
B
bellard 已提交
190
    uint32_t opcode;
191
    uint32_t exception;
B
bellard 已提交
192 193 194
    /* Routine used to access memory */
    int mem_idx;
    /* Translation flags */
195
#if !defined(CONFIG_USER_ONLY)
B
bellard 已提交
196
    int supervisor;
197 198 199
#endif
#if defined(TARGET_PPC64)
    int sf_mode;
200
#endif
B
bellard 已提交
201
    int fpu_enabled;
202
    int altivec_enabled;
203
    int spe_enabled;
204
    ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */
205
    int singlestep_enabled;
B
bellard 已提交
206 207
} DisasContext;

208
struct opc_handler_t {
B
bellard 已提交
209 210
    /* invalid bits */
    uint32_t inval;
211
    /* instruction type */
212
    uint64_t type;
B
bellard 已提交
213 214
    /* handler */
    void (*handler)(DisasContext *ctx);
215
#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU)
216
    const char *oname;
217 218
#endif
#if defined(DO_PPC_STATISTICS)
219 220
    uint64_t count;
#endif
221
};
B
bellard 已提交
222

223 224 225 226 227 228 229
static always_inline void gen_reset_fpstatus (void)
{
#ifdef CONFIG_SOFTFLOAT
    gen_op_reset_fpstatus();
#endif
}

230
static always_inline void gen_compute_fprf (TCGv_i64 arg, int set_fprf, int set_rc)
231
{
232
    TCGv_i32 t0 = tcg_temp_new_i32();
A
aurel32 已提交
233

234 235 236 237 238
    if (set_fprf != 0) {
        /* This case might be optimized later */
#if defined(OPTIMIZE_FPRF_UPDATE)
        *gen_fprf_ptr++ = gen_opc_ptr;
#endif
239
        tcg_gen_movi_i32(t0, 1);
A
aurel32 已提交
240
        gen_helper_compute_fprf(t0, arg, t0);
P
pbrook 已提交
241
        if (unlikely(set_rc)) {
242
            tcg_gen_mov_i32(cpu_crf[1], t0);
P
pbrook 已提交
243
        }
A
aurel32 已提交
244
        gen_helper_float_check_status();
245 246
    } else if (unlikely(set_rc)) {
        /* We always need to compute fpcc */
247
        tcg_gen_movi_i32(t0, 0);
A
aurel32 已提交
248
        gen_helper_compute_fprf(t0, arg, t0);
249
        tcg_gen_mov_i32(cpu_crf[1], t0);
250
        if (set_fprf)
A
aurel32 已提交
251
            gen_helper_float_check_status();
252
    }
A
aurel32 已提交
253

254
    tcg_temp_free_i32(t0);
255 256 257 258 259 260 261 262 263 264 265 266 267
}

static always_inline void gen_optimize_fprf (void)
{
#if defined(OPTIMIZE_FPRF_UPDATE)
    uint16_t **ptr;

    for (ptr = gen_fprf_buf; ptr != (gen_fprf_ptr - 1); ptr++)
        *ptr = INDEX_op_nop1;
    gen_fprf_ptr = gen_fprf_buf;
#endif
}

A
aurel32 已提交
268 269 270 271 272
static always_inline void gen_set_access_type(int access_type)
{
    tcg_gen_movi_i32(cpu_access_type, access_type);
}

273
static always_inline void gen_update_nip (DisasContext *ctx, target_ulong nip)
274 275 276
{
#if defined(TARGET_PPC64)
    if (ctx->sf_mode)
A
aurel32 已提交
277
        tcg_gen_movi_tl(cpu_nip, nip);
278 279
    else
#endif
A
aurel32 已提交
280
        tcg_gen_movi_tl(cpu_nip, (uint32_t)nip);
281 282
}

283
#define GEN_EXCP(ctx, excp, error)                                            \
B
bellard 已提交
284
do {                                                                          \
285 286
    TCGv_i32 t0 = tcg_const_i32(excp);                                        \
    TCGv_i32 t1 = tcg_const_i32(error);                                       \
287
    if ((ctx)->exception == POWERPC_EXCP_NONE) {                              \
288
        gen_update_nip(ctx, (ctx)->nip);                                      \
289
    }                                                                         \
290 291 292
    gen_helper_raise_exception_err(t0, t1);                                   \
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
293
    ctx->exception = (excp);                                                  \
B
bellard 已提交
294 295
} while (0)

296 297 298
#define GEN_EXCP_INVAL(ctx)                                                   \
GEN_EXCP((ctx), POWERPC_EXCP_PROGRAM,                                         \
         POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL)
299

300 301 302
#define GEN_EXCP_PRIVOPC(ctx)                                                 \
GEN_EXCP((ctx), POWERPC_EXCP_PROGRAM,                                         \
         POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_OPC)
303

304 305 306 307 308 309 310 311 312
#define GEN_EXCP_PRIVREG(ctx)                                                 \
GEN_EXCP((ctx), POWERPC_EXCP_PROGRAM,                                         \
         POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG)

#define GEN_EXCP_NO_FP(ctx)                                                   \
GEN_EXCP(ctx, POWERPC_EXCP_FPU, 0)

#define GEN_EXCP_NO_AP(ctx)                                                   \
GEN_EXCP(ctx, POWERPC_EXCP_APU, 0)
313

314 315 316
#define GEN_EXCP_NO_VR(ctx)                                                   \
GEN_EXCP(ctx, POWERPC_EXCP_VPU, 0)

317
/* Stop translation */
318
static always_inline void GEN_STOP (DisasContext *ctx)
319
{
320
    gen_update_nip(ctx, ctx->nip);
321
    ctx->exception = POWERPC_EXCP_STOP;
322 323
}

324
/* No need to update nip here, as execution flow will change */
325
static always_inline void GEN_SYNC (DisasContext *ctx)
326
{
327
    ctx->exception = POWERPC_EXCP_SYNC;
328 329
}

B
bellard 已提交
330 331 332 333 334
#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)

335 336 337 338 339
#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 已提交
340 341
typedef struct opcode_t {
    unsigned char opc1, opc2, opc3;
T
ths 已提交
342
#if HOST_LONG_BITS == 64 /* Explicitly align to 64 bits */
343 344 345 346
    unsigned char pad[5];
#else
    unsigned char pad[1];
#endif
B
bellard 已提交
347
    opc_handler_t handler;
348
    const char *oname;
B
bellard 已提交
349 350
} opcode_t;

351
/*****************************************************************************/
B
bellard 已提交
352 353
/***                           Instruction decoding                        ***/
#define EXTRACT_HELPER(name, shift, nb)                                       \
354
static always_inline uint32_t name (uint32_t opcode)                          \
B
bellard 已提交
355 356 357 358 359
{                                                                             \
    return (opcode >> (shift)) & ((1 << (nb)) - 1);                           \
}

#define EXTRACT_SHELPER(name, shift, nb)                                      \
360
static always_inline int32_t name (uint32_t opcode)                           \
B
bellard 已提交
361
{                                                                             \
362
    return (int16_t)((opcode >> (shift)) & ((1 << (nb)) - 1));                \
B
bellard 已提交
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389
}

/* 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 */
390
EXTRACT_HELPER(_SPR, 11, 10);
391
static always_inline uint32_t SPR (uint32_t opcode)
392 393 394 395 396
{
    uint32_t sprn = _SPR(opcode);

    return ((sprn >> 5) & 0x1F) | ((sprn & 0x1F) << 5);
}
B
bellard 已提交
397 398 399 400 401 402 403 404 405 406 407 408 409 410
/***                              Get constants                            ***/
EXTRACT_HELPER(IMM, 12, 8);
/* 16 bits signed immediate value */
EXTRACT_SHELPER(SIMM, 0, 16);
/* 16 bits unsigned immediate value */
EXTRACT_HELPER(UIMM, 0, 16);
/* Bit count */
EXTRACT_HELPER(NB, 11, 5);
/* Shift count */
EXTRACT_HELPER(SH, 11, 5);
/* Mask start */
EXTRACT_HELPER(MB, 6, 5);
/* Mask end */
EXTRACT_HELPER(ME, 1, 5);
B
bellard 已提交
411 412
/* Trap operand */
EXTRACT_HELPER(TO, 21, 5);
B
bellard 已提交
413 414 415 416

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

B
bellard 已提交
419 420 421 422
/***                            Jump target decoding                       ***/
/* Displacement */
EXTRACT_SHELPER(d, 0, 16);
/* Immediate address */
423
static always_inline target_ulong LI (uint32_t opcode)
B
bellard 已提交
424 425 426 427
{
    return (opcode >> 0) & 0x03FFFFFC;
}

428
static always_inline uint32_t BD (uint32_t opcode)
B
bellard 已提交
429 430 431 432 433 434 435 436 437 438 439 440
{
    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 */
441
static always_inline target_ulong MASK (uint32_t start, uint32_t end)
B
bellard 已提交
442
{
443
    target_ulong ret;
B
bellard 已提交
444

445 446
#if defined(TARGET_PPC64)
    if (likely(start == 0)) {
447
        ret = UINT64_MAX << (63 - end);
448
    } else if (likely(end == 63)) {
449
        ret = UINT64_MAX >> start;
450 451 452
    }
#else
    if (likely(start == 0)) {
453
        ret = UINT32_MAX << (31  - end);
454
    } else if (likely(end == 31)) {
455
        ret = UINT32_MAX >> start;
456 457 458 459 460 461 462 463
    }
#endif
    else {
        ret = (((target_ulong)(-1ULL)) >> (start)) ^
            (((target_ulong)(-1ULL) >> (end)) >> 1);
        if (unlikely(start > end))
            return ~ret;
    }
B
bellard 已提交
464 465 466 467

    return ret;
}

468 469 470
/*****************************************************************************/
/* PowerPC Instructions types definitions                                    */
enum {
471
    PPC_NONE           = 0x0000000000000000ULL,
472
    /* PowerPC base instructions set                                         */
473 474
    PPC_INSNS_BASE     = 0x0000000000000001ULL,
    /*   integer operations instructions                                     */
475
#define PPC_INTEGER PPC_INSNS_BASE
476
    /*   flow control instructions                                           */
477
#define PPC_FLOW    PPC_INSNS_BASE
478
    /*   virtual memory instructions                                         */
479
#define PPC_MEM     PPC_INSNS_BASE
480
    /*   ld/st with reservation instructions                                 */
481
#define PPC_RES     PPC_INSNS_BASE
482
    /*   spr/msr access instructions                                         */
483
#define PPC_MISC    PPC_INSNS_BASE
484 485
    /* Deprecated instruction sets                                           */
    /*   Original POWER instruction set                                      */
486
    PPC_POWER          = 0x0000000000000002ULL,
487
    /*   POWER2 instruction set extension                                    */
488
    PPC_POWER2         = 0x0000000000000004ULL,
489
    /*   Power RTC support                                                   */
490
    PPC_POWER_RTC      = 0x0000000000000008ULL,
491
    /*   Power-to-PowerPC bridge (601)                                       */
492
    PPC_POWER_BR       = 0x0000000000000010ULL,
493
    /* 64 bits PowerPC instruction set                                       */
494
    PPC_64B            = 0x0000000000000020ULL,
495
    /*   New 64 bits extensions (PowerPC 2.0x)                               */
496
    PPC_64BX           = 0x0000000000000040ULL,
497
    /*   64 bits hypervisor extensions                                       */
498
    PPC_64H            = 0x0000000000000080ULL,
499
    /*   New wait instruction (PowerPC 2.0x)                                 */
500
    PPC_WAIT           = 0x0000000000000100ULL,
501
    /*   Time base mftb instruction                                          */
502
    PPC_MFTB           = 0x0000000000000200ULL,
503 504 505

    /* Fixed-point unit extensions                                           */
    /*   PowerPC 602 specific                                                */
506
    PPC_602_SPEC       = 0x0000000000000400ULL,
507 508 509 510 511 512
    /*   isel instruction                                                    */
    PPC_ISEL           = 0x0000000000000800ULL,
    /*   popcntb instruction                                                 */
    PPC_POPCNTB        = 0x0000000000001000ULL,
    /*   string load / store                                                 */
    PPC_STRING         = 0x0000000000002000ULL,
513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529

    /* 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                                          */
530
    PPC_SPE            = 0x0000000002000000ULL,
531
    /*   PowerPC 2.03 SPE floating-point extension                           */
532
    PPC_SPEFPU         = 0x0000000004000000ULL,
533

534
    /* Optional memory control instructions                                  */
535 536 537 538 539 540 541 542 543
    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                                            */
544
    PPC_CACHE          = 0x0000000200000000ULL,
545
    /*   icbi instruction                                                    */
546
    PPC_CACHE_ICBI     = 0x0000000400000000ULL,
547
    /*   dcbz instruction with fixed cache line size                         */
548
    PPC_CACHE_DCBZ     = 0x0000000800000000ULL,
549
    /*   dcbz instruction with tunable cache line size                       */
550
    PPC_CACHE_DCBZT    = 0x0000001000000000ULL,
551
    /*   dcba instruction                                                    */
552 553 554
    PPC_CACHE_DCBA     = 0x0000002000000000ULL,
    /*   Freescale cache locking instructions                                */
    PPC_CACHE_LOCK     = 0x0000004000000000ULL,
555 556 557

    /* MMU related extensions                                                */
    /*   external control instructions                                       */
558
    PPC_EXTERN         = 0x0000010000000000ULL,
559
    /*   segment register access instructions                                */
560
    PPC_SEGMENT        = 0x0000020000000000ULL,
561
    /*   PowerPC 6xx TLB management instructions                             */
562
    PPC_6xx_TLB        = 0x0000040000000000ULL,
563
    /* PowerPC 74xx TLB management instructions                              */
564
    PPC_74xx_TLB       = 0x0000080000000000ULL,
565
    /*   PowerPC 40x TLB management instructions                             */
566
    PPC_40x_TLB        = 0x0000100000000000ULL,
567
    /*   segment register access instructions for PowerPC 64 "bridge"        */
568
    PPC_SEGMENT_64B    = 0x0000200000000000ULL,
569
    /*   SLB management                                                      */
570
    PPC_SLBI           = 0x0000400000000000ULL,
571

572
    /* Embedded PowerPC dedicated instructions                               */
573
    PPC_WRTEE          = 0x0001000000000000ULL,
574
    /* PowerPC 40x exception model                                           */
575
    PPC_40x_EXCP       = 0x0002000000000000ULL,
576
    /* PowerPC 405 Mac instructions                                          */
577
    PPC_405_MAC        = 0x0004000000000000ULL,
578
    /* PowerPC 440 specific instructions                                     */
579
    PPC_440_SPEC       = 0x0008000000000000ULL,
580
    /* BookE (embedded) PowerPC specification                                */
581 582 583 584 585 586 587
    PPC_BOOKE          = 0x0010000000000000ULL,
    /* mfapidi instruction                                                   */
    PPC_MFAPIDI        = 0x0020000000000000ULL,
    /* tlbiva instruction                                                    */
    PPC_TLBIVA         = 0x0040000000000000ULL,
    /* tlbivax instruction                                                   */
    PPC_TLBIVAX        = 0x0080000000000000ULL,
588
    /* PowerPC 4xx dedicated instructions                                    */
589
    PPC_4xx_COMMON     = 0x0100000000000000ULL,
590
    /* PowerPC 40x ibct instructions                                         */
591
    PPC_40x_ICBT       = 0x0200000000000000ULL,
592
    /* rfmci is not implemented in all BookE PowerPC                         */
593 594 595 596 597 598 599
    PPC_RFMCI          = 0x0400000000000000ULL,
    /* rfdi instruction                                                      */
    PPC_RFDI           = 0x0800000000000000ULL,
    /* DCR accesses                                                          */
    PPC_DCR            = 0x1000000000000000ULL,
    /* DCR extended accesse                                                  */
    PPC_DCRX           = 0x2000000000000000ULL,
600
    /* user-mode DCR access, implemented in PowerPC 460                      */
601
    PPC_DCRUX          = 0x4000000000000000ULL,
602 603 604 605
};

/*****************************************************************************/
/* PowerPC instructions table                                                */
606 607 608 609 610
#if HOST_LONG_BITS == 64
#define OPC_ALIGN 8
#else
#define OPC_ALIGN 4
#endif
B
bellard 已提交
611
#if defined(__APPLE__)
612
#define OPCODES_SECTION                                                       \
613
    __attribute__ ((section("__TEXT,__opcodes"), unused, aligned (OPC_ALIGN) ))
B
bellard 已提交
614
#else
615
#define OPCODES_SECTION                                                       \
616
    __attribute__ ((section(".opcodes"), unused, aligned (OPC_ALIGN) ))
B
bellard 已提交
617 618
#endif

619
#if defined(DO_PPC_STATISTICS)
B
bellard 已提交
620
#define GEN_OPCODE(name, op1, op2, op3, invl, _typ)                           \
621
OPCODES_SECTION opcode_t opc_##name = {                                       \
B
bellard 已提交
622 623 624
    .opc1 = op1,                                                              \
    .opc2 = op2,                                                              \
    .opc3 = op3,                                                              \
625
    .pad  = { 0, },                                                           \
B
bellard 已提交
626 627
    .handler = {                                                              \
        .inval   = invl,                                                      \
628
        .type = _typ,                                                         \
B
bellard 已提交
629
        .handler = &gen_##name,                                               \
630
        .oname = stringify(name),                                             \
B
bellard 已提交
631
    },                                                                        \
632
    .oname = stringify(name),                                                 \
B
bellard 已提交
633
}
634 635 636 637 638 639 640 641 642 643 644 645 646 647
#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,                                                            \
}
648 649 650 651 652 653 654 655 656 657 658 659 660 661
#else
#define GEN_OPCODE(name, 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 = stringify(name),                                                 \
}
662 663 664 665 666 667 668 669 670 671 672 673 674
#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,                                                            \
}
675
#endif
B
bellard 已提交
676 677

#define GEN_OPCODE_MARK(name)                                                 \
678
OPCODES_SECTION opcode_t opc_##name = {                                       \
B
bellard 已提交
679 680 681
    .opc1 = 0xFF,                                                             \
    .opc2 = 0xFF,                                                             \
    .opc3 = 0xFF,                                                             \
682
    .pad  = { 0, },                                                           \
B
bellard 已提交
683 684
    .handler = {                                                              \
        .inval   = 0x00000000,                                                \
685
        .type = 0x00,                                                         \
B
bellard 已提交
686 687
        .handler = NULL,                                                      \
    },                                                                        \
688
    .oname = stringify(name),                                                 \
B
bellard 已提交
689 690
}

691 692 693 694 695 696 697 698 699 700 701
/* 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 已提交
702 703 704 705
/* Start opcode list */
GEN_OPCODE_MARK(start);

/* Invalid instruction */
706 707
GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE)
{
708
    GEN_EXCP_INVAL(ctx);
709 710
}

B
bellard 已提交
711 712
static opc_handler_t invalid_handler = {
    .inval   = 0xFFFFFFFF,
713
    .type    = PPC_NONE,
B
bellard 已提交
714 715 716
    .handler = gen_invalid,
};

717 718
/***                           Integer comparison                          ***/

719
static always_inline void gen_op_cmp(TCGv arg0, TCGv arg1, int s, int crf)
720 721 722
{
    int l1, l2, l3;

723 724
    tcg_gen_trunc_tl_i32(cpu_crf[crf], cpu_xer);
    tcg_gen_shri_i32(cpu_crf[crf], cpu_crf[crf], XER_SO);
725 726 727 728 729 730
    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) {
731 732
        tcg_gen_brcond_tl(TCG_COND_LT, arg0, arg1, l1);
        tcg_gen_brcond_tl(TCG_COND_GT, arg0, arg1, l2);
733
    } else {
734 735
        tcg_gen_brcond_tl(TCG_COND_LTU, arg0, arg1, l1);
        tcg_gen_brcond_tl(TCG_COND_GTU, arg0, arg1, l2);
736 737 738 739 740 741 742 743 744 745 746
    }
    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);
}

747
static always_inline void gen_op_cmpi(TCGv arg0, target_ulong arg1, int s, int crf)
748
{
749 750 751
    TCGv t0 = tcg_const_local_tl(arg1);
    gen_op_cmp(arg0, t0, s, crf);
    tcg_temp_free(t0);
752 753 754
}

#if defined(TARGET_PPC64)
755
static always_inline void gen_op_cmp32(TCGv arg0, TCGv arg1, int s, int crf)
756
{
757
    TCGv t0, t1;
P
pbrook 已提交
758 759
    t0 = tcg_temp_local_new();
    t1 = tcg_temp_local_new();
760
    if (s) {
761 762
        tcg_gen_ext32s_tl(t0, arg0);
        tcg_gen_ext32s_tl(t1, arg1);
763
    } else {
764 765
        tcg_gen_ext32u_tl(t0, arg0);
        tcg_gen_ext32u_tl(t1, arg1);
766
    }
767 768 769
    gen_op_cmp(t0, t1, s, crf);
    tcg_temp_free(t1);
    tcg_temp_free(t0);
770 771
}

772
static always_inline void gen_op_cmpi32(TCGv arg0, target_ulong arg1, int s, int crf)
773
{
774 775 776
    TCGv t0 = tcg_const_local_tl(arg1);
    gen_op_cmp32(arg0, t0, s, crf);
    tcg_temp_free(t0);
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 838 839 840 841 842 843 844 845 846 847
}
#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 已提交
848
    TCGv_i32 t0;
849 850 851 852 853

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

    mask = 1 << (3 - (bi & 0x03));
P
pbrook 已提交
854
    t0 = tcg_temp_new_i32();
855 856
    tcg_gen_andi_i32(t0, cpu_crf[bi >> 2], mask);
    tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l1);
857 858 859 860 861 862 863 864
    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 已提交
865
    tcg_temp_free_i32(t0);
866 867
}

B
bellard 已提交
868 869
/***                           Integer arithmetic                          ***/

870 871 872 873
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 已提交
874

875 876 877
    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 已提交
878
    t0 = tcg_temp_local_new();
879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899
    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 已提交
900 901
}

902 903 904
static always_inline void gen_op_arith_compute_ca(DisasContext *ctx, TCGv arg1, TCGv arg2, int sub)
{
    int l1 = gen_new_label();
905 906

#if defined(TARGET_PPC64)
907 908
    if (!(ctx->sf_mode)) {
        TCGv t0, t1;
P
pbrook 已提交
909 910
        t0 = tcg_temp_new();
        t1 = tcg_temp_new();
911

912 913 914 915
        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 已提交
916
        } else {
917 918
            tcg_gen_brcond_tl(TCG_COND_GEU, t0, t1, l1);
        }
919 920 921 922
        tcg_gen_ori_tl(cpu_xer, cpu_xer, 1 << XER_CA);
        gen_set_label(l1);
        tcg_temp_free(t0);
        tcg_temp_free(t1);
923 924
    } else
#endif
925 926 927 928 929 930 931 932
    {
        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);
933
    }
934 935
}

936 937 938 939 940
/* 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;
941

942
    if ((!compute_ca && !compute_ov) ||
P
pbrook 已提交
943
        (!TCGV_EQUAL(ret,arg1) && !TCGV_EQUAL(ret, arg2)))  {
944 945
        t0 = ret;
    } else {
P
pbrook 已提交
946
        t0 = tcg_temp_local_new();
947
    }
B
bellard 已提交
948

949
    if (add_ca) {
P
pbrook 已提交
950
        t1 = tcg_temp_local_new();
951 952 953
        tcg_gen_andi_tl(t1, cpu_xer, (1 << XER_CA));
        tcg_gen_shri_tl(t1, t1, XER_CA);
    }
B
bellard 已提交
954

955 956 957 958 959 960 961 962 963 964
    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 已提交
965

966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982
    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 已提交
983
    if (!TCGV_EQUAL(t0, ret)) {
984 985 986
        tcg_gen_mov_tl(ret, t0);
        tcg_temp_free(t0);
    }
A
aurel32 已提交
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 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024
/* 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)
1025
{
1026 1027 1028 1029 1030 1031 1032 1033
    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);
    }
1034
}
1035 1036 1037
/* addic  addic.*/
static always_inline void gen_op_addic (DisasContext *ctx, TCGv ret, TCGv arg1,
                                        int compute_Rc0)
1038
{
1039 1040 1041 1042 1043 1044
    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 已提交
1045
        TCGv t0 = tcg_temp_local_new();
1046 1047 1048 1049 1050 1051 1052 1053 1054 1055
        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);
    }
1056
}
1057
GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
1058
{
1059
    gen_op_addic(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0);
1060
}
1061
GEN_HANDLER2(addic_, "addic.", 0x0D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
1062
{
1063
    gen_op_addic(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 1);
1064
}
1065 1066
/* addis */
GEN_HANDLER(addis, 0x0F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
1067
{
1068 1069 1070 1071 1072 1073 1074 1075
    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);
    }
1076
}
1077 1078 1079

static always_inline void gen_op_arith_divw (DisasContext *ctx, TCGv ret, TCGv arg1, TCGv arg2,
                                             int sign, int compute_ov)
1080
{
1081 1082
    int l1 = gen_new_label();
    int l2 = gen_new_label();
P
pbrook 已提交
1083 1084
    TCGv_i32 t0 = tcg_temp_local_new_i32();
    TCGv_i32 t1 = tcg_temp_local_new_i32();
1085

1086 1087 1088
    tcg_gen_trunc_tl_i32(t0, arg1);
    tcg_gen_trunc_tl_i32(t1, arg2);
    tcg_gen_brcondi_i32(TCG_COND_EQ, t1, 0, l1);
1089
    if (sign) {
1090 1091 1092
        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);
1093
        gen_set_label(l3);
1094
        tcg_gen_div_i32(t0, t0, t1);
1095
    } else {
1096
        tcg_gen_divu_i32(t0, t0, t1);
1097 1098 1099 1100 1101 1102 1103
    }
    if (compute_ov) {
        tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
    }
    tcg_gen_br(l2);
    gen_set_label(l1);
    if (sign) {
1104
        tcg_gen_sari_i32(t0, t0, 31);
1105 1106 1107 1108 1109 1110 1111
    } 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);
1112
    tcg_gen_extu_i32_tl(ret, t0);
P
pbrook 已提交
1113 1114
    tcg_temp_free_i32(t0);
    tcg_temp_free_i32(t1);
1115 1116
    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, ret);
1117
}
1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131
/* 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);
1132
#if defined(TARGET_PPC64)
1133 1134
static always_inline void gen_op_arith_divd (DisasContext *ctx, TCGv ret, TCGv arg1, TCGv arg2,
                                             int sign, int compute_ov)
1135
{
1136 1137
    int l1 = gen_new_label();
    int l2 = gen_new_label();
1138 1139 1140

    tcg_gen_brcondi_i64(TCG_COND_EQ, arg2, 0, l1);
    if (sign) {
1141
        int l3 = gen_new_label();
1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164
        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);
1165
}
1166 1167 1168
#define GEN_INT_ARITH_DIVD(name, opc3, sign, compute_ov)                      \
GEN_HANDLER(name, 0x1F, 0x09, opc3, 0x00000000, PPC_64B)                      \
{                                                                             \
1169 1170 1171
    gen_op_arith_divd(ctx, cpu_gpr[rD(ctx->opcode)],                          \
                      cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],     \
                      sign, compute_ov);                                      \
1172 1173 1174 1175 1176 1177 1178
}
/* 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);
1179
#endif
1180 1181 1182

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

P
pbrook 已提交
1186 1187
    t0 = tcg_temp_new_i64();
    t1 = tcg_temp_new_i64();
1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199
#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 已提交
1200 1201
    tcg_temp_free_i64(t0);
    tcg_temp_free_i64(t1);
1202 1203
    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
1204
}
1205 1206
/* mulhwu  mulhwu.  */
GEN_HANDLER(mulhwu, 0x1F, 0x0B, 0x00, 0x00000400, PPC_INTEGER)
1207
{
P
pbrook 已提交
1208
    TCGv_i64 t0, t1;
1209

P
pbrook 已提交
1210 1211
    t0 = tcg_temp_new_i64();
    t1 = tcg_temp_new_i64();
1212
#if defined(TARGET_PPC64)
1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223
    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 已提交
1224 1225
    tcg_temp_free_i64(t0);
    tcg_temp_free_i64(t1);
1226 1227
    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
1228
}
1229 1230
/* mullw  mullw. */
GEN_HANDLER(mullw, 0x1F, 0x0B, 0x07, 0x00000000, PPC_INTEGER)
1231
{
1232 1233
    tcg_gen_mul_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],
                   cpu_gpr[rB(ctx->opcode)]);
1234
    tcg_gen_ext32s_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)]);
1235 1236
    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
1237
}
1238 1239
/* mullwo  mullwo. */
GEN_HANDLER(mullwo, 0x1F, 0x0B, 0x17, 0x00000000, PPC_INTEGER)
1240
{
1241
    int l1;
P
pbrook 已提交
1242
    TCGv_i64 t0, t1;
1243

P
pbrook 已提交
1244 1245
    t0 = tcg_temp_new_i64();
    t1 = tcg_temp_new_i64();
1246 1247 1248 1249 1250 1251 1252 1253 1254
    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)]);
1255
#endif
1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266
    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 已提交
1267 1268
    tcg_temp_free_i64(t0);
    tcg_temp_free_i64(t1);
1269 1270
    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
1271
}
1272 1273
/* mulli */
GEN_HANDLER(mulli, 0x07, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
1274
{
1275 1276
    tcg_gen_muli_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],
                    SIMM(ctx->opcode));
1277 1278
}
#if defined(TARGET_PPC64)
1279 1280 1281
#define GEN_INT_ARITH_MUL_HELPER(name, opc3)                                  \
GEN_HANDLER(name, 0x1F, 0x09, opc3, 0x00000000, PPC_64B)                      \
{                                                                             \
P
pbrook 已提交
1282
    gen_helper_##name (cpu_gpr[rD(ctx->opcode)],                              \
1283 1284 1285
                       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)]);                           \
1286
}
1287 1288 1289 1290 1291 1292
/* 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)
1293
{
1294 1295 1296 1297
    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)]);
1298
}
1299 1300
/* mulldo  mulldo. */
GEN_INT_ARITH_MUL_HELPER(mulldo, 0x17);
1301
#endif
1302 1303

/* neg neg. nego nego. */
A
aurel32 已提交
1304
static always_inline void gen_op_arith_neg (DisasContext *ctx, TCGv ret, TCGv arg1, int ov_check)
1305
{
A
aurel32 已提交
1306 1307
    int l1 = gen_new_label();
    int l2 = gen_new_label();
P
pbrook 已提交
1308
    TCGv t0 = tcg_temp_local_new();
1309
#if defined(TARGET_PPC64)
1310
    if (ctx->sf_mode) {
A
aurel32 已提交
1311
        tcg_gen_mov_tl(t0, arg1);
A
aurel32 已提交
1312 1313 1314 1315 1316
        tcg_gen_brcondi_tl(TCG_COND_EQ, t0, INT64_MIN, l1);
    } else
#endif
    {
        tcg_gen_ext32s_tl(t0, arg1);
1317 1318 1319 1320 1321 1322 1323 1324
        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 已提交
1325
    tcg_gen_mov_tl(ret, t0);
1326 1327 1328 1329
    if (ov_check) {
        tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
    }
    gen_set_label(l2);
A
aurel32 已提交
1330
    tcg_temp_free(t0);
1331 1332 1333 1334
    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, ret);
}
GEN_HANDLER(neg, 0x1F, 0x08, 0x03, 0x0000F800, PPC_INTEGER)
1335
{
A
aurel32 已提交
1336
    gen_op_arith_neg(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0);
1337
}
1338
GEN_HANDLER(nego, 0x1F, 0x08, 0x13, 0x0000F800, PPC_INTEGER)
B
bellard 已提交
1339
{
A
aurel32 已提交
1340
    gen_op_arith_neg(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 1);
B
bellard 已提交
1341
}
1342 1343 1344 1345

/* 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 已提交
1346
{
1347
    TCGv t0, t1;
1348

1349
    if ((!compute_ca && !compute_ov) ||
P
pbrook 已提交
1350
        (!TCGV_EQUAL(ret, arg1) && !TCGV_EQUAL(ret, arg2)))  {
1351
        t0 = ret;
J
j_mayer 已提交
1352
    } else {
P
pbrook 已提交
1353
        t0 = tcg_temp_local_new();
1354
    }
1355

1356
    if (add_ca) {
P
pbrook 已提交
1357
        t1 = tcg_temp_local_new();
1358 1359
        tcg_gen_andi_tl(t1, cpu_xer, (1 << XER_CA));
        tcg_gen_shri_tl(t1, t1, XER_CA);
1360
    }
B
bellard 已提交
1361

1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379
    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 已提交
1380
    } else {
1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392
        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 已提交
1393
    if (!TCGV_EQUAL(t0, ret)) {
1394 1395
        tcg_gen_mov_tl(ret, t0);
        tcg_temp_free(t0);
B
bellard 已提交
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 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431
/* 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 已提交
1432 1433 1434
/* subfic */
GEN_HANDLER(subfic, 0x08, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
1435 1436
    /* Start with XER CA and OV disabled, the most likely case */
    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
P
pbrook 已提交
1437
    TCGv t0 = tcg_temp_local_new();
1438 1439 1440 1441 1442 1443
    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 已提交
1444 1445 1446
}

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

1456
#define GEN_LOGICAL1(name, tcg_op, opc, type)                                 \
1457
GEN_HANDLER(name, 0x1F, 0x1A, opc, 0x00000000, type)                          \
B
bellard 已提交
1458
{                                                                             \
1459
    tcg_op(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);               \
1460
    if (unlikely(Rc(ctx->opcode) != 0))                                       \
1461
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);                           \
B
bellard 已提交
1462 1463 1464
}

/* and & and. */
1465
GEN_LOGICAL2(and, tcg_gen_and_tl, 0x00, PPC_INTEGER);
B
bellard 已提交
1466
/* andc & andc. */
1467
GEN_LOGICAL2(andc, tcg_gen_andc_tl, 0x01, PPC_INTEGER);
B
bellard 已提交
1468
/* andi. */
1469
GEN_HANDLER2(andi_, "andi.", 0x1C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
B
bellard 已提交
1470
{
1471 1472
    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 已提交
1473 1474
}
/* andis. */
1475
GEN_HANDLER2(andis_, "andis.", 0x1D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
B
bellard 已提交
1476
{
1477 1478
    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 已提交
1479 1480
}
/* cntlzw */
1481 1482
GEN_HANDLER(cntlzw, 0x1F, 0x1A, 0x00, 0x00000000, PPC_INTEGER)
{
P
pbrook 已提交
1483
    gen_helper_cntlzw(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
1484
    if (unlikely(Rc(ctx->opcode) != 0))
P
pbrook 已提交
1485
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
1486
}
B
bellard 已提交
1487
/* eqv & eqv. */
1488
GEN_LOGICAL2(eqv, tcg_gen_eqv_tl, 0x08, PPC_INTEGER);
B
bellard 已提交
1489
/* extsb & extsb. */
1490
GEN_LOGICAL1(extsb, tcg_gen_ext8s_tl, 0x1D, PPC_INTEGER);
B
bellard 已提交
1491
/* extsh & extsh. */
1492
GEN_LOGICAL1(extsh, tcg_gen_ext16s_tl, 0x1C, PPC_INTEGER);
B
bellard 已提交
1493
/* nand & nand. */
1494
GEN_LOGICAL2(nand, tcg_gen_nand_tl, 0x0E, PPC_INTEGER);
B
bellard 已提交
1495
/* nor & nor. */
1496
GEN_LOGICAL2(nor, tcg_gen_nor_tl, 0x03, PPC_INTEGER);
B
bellard 已提交
1497
/* or & or. */
1498 1499
GEN_HANDLER(or, 0x1F, 0x1C, 0x0D, 0x00000000, PPC_INTEGER)
{
1500 1501 1502 1503 1504 1505 1506
    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) {
1507 1508 1509 1510
        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]);
1511
        if (unlikely(Rc(ctx->opcode) != 0))
1512
            gen_set_Rc0(ctx, cpu_gpr[ra]);
1513
    } else if (unlikely(Rc(ctx->opcode) != 0)) {
1514
        gen_set_Rc0(ctx, cpu_gpr[rs]);
1515 1516
#if defined(TARGET_PPC64)
    } else {
1517 1518
        int prio = 0;

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

1591 1592
    if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
        /* NOP */
1593
        /* XXX: should handle special NOPs for POWER series */
1594
        return;
1595
    }
1596
    tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], uimm);
B
bellard 已提交
1597 1598 1599 1600
}
/* oris */
GEN_HANDLER(oris, 0x19, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
1601
    target_ulong uimm = UIMM(ctx->opcode);
B
bellard 已提交
1602

1603 1604 1605
    if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
        /* NOP */
        return;
1606
    }
1607
    tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], uimm << 16);
B
bellard 已提交
1608 1609 1610 1611
}
/* xori */
GEN_HANDLER(xori, 0x1A, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
1612
    target_ulong uimm = UIMM(ctx->opcode);
1613 1614 1615 1616 1617

    if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
        /* NOP */
        return;
    }
1618
    tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], uimm);
B
bellard 已提交
1619 1620 1621 1622
}
/* xoris */
GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
1623
    target_ulong uimm = UIMM(ctx->opcode);
1624 1625 1626 1627 1628

    if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
        /* NOP */
        return;
    }
1629
    tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], uimm << 16);
B
bellard 已提交
1630
}
1631
/* popcntb : PowerPC 2.03 specification */
1632
GEN_HANDLER(popcntb, 0x1F, 0x03, 0x03, 0x0000F801, PPC_POPCNTB)
1633 1634 1635
{
#if defined(TARGET_PPC64)
    if (ctx->sf_mode)
P
pbrook 已提交
1636
        gen_helper_popcntb_64(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
1637 1638
    else
#endif
P
pbrook 已提交
1639
        gen_helper_popcntb(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
1640 1641 1642 1643
}

#if defined(TARGET_PPC64)
/* extsw & extsw. */
1644
GEN_LOGICAL1(extsw, tcg_gen_ext32s_tl, 0x1E, PPC_64B);
1645
/* cntlzd */
1646 1647
GEN_HANDLER(cntlzd, 0x1F, 0x1A, 0x01, 0x00000000, PPC_64B)
{
P
pbrook 已提交
1648
    gen_helper_cntlzd(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
1649 1650 1651
    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
}
1652 1653
#endif

B
bellard 已提交
1654 1655 1656 1657
/***                             Integer rotate                            ***/
/* rlwimi & rlwimi. */
GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
1658
    uint32_t mb, me, sh;
B
bellard 已提交
1659 1660 1661

    mb = MB(ctx->opcode);
    me = ME(ctx->opcode);
1662
    sh = SH(ctx->opcode);
1663 1664 1665 1666
    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 已提交
1667 1668
        TCGv t1;
        TCGv t0 = tcg_temp_new();
1669
#if defined(TARGET_PPC64)
P
pbrook 已提交
1670 1671 1672 1673 1674
        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);
1675 1676 1677
#else
        tcg_gen_rotli_i32(t0, cpu_gpr[rS(ctx->opcode)], sh);
#endif
1678
#if defined(TARGET_PPC64)
1679 1680
        mb += 32;
        me += 32;
1681
#endif
1682
        mask = MASK(mb, me);
P
pbrook 已提交
1683
        t1 = tcg_temp_new();
1684 1685 1686 1687 1688 1689
        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);
    }
1690
    if (unlikely(Rc(ctx->opcode) != 0))
1691
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
B
bellard 已提交
1692 1693 1694 1695 1696
}
/* rlwinm & rlwinm. */
GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
    uint32_t mb, me, sh;
1697

B
bellard 已提交
1698 1699 1700
    sh = SH(ctx->opcode);
    mb = MB(ctx->opcode);
    me = ME(ctx->opcode);
1701 1702 1703 1704 1705

    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 已提交
1706
            TCGv t0 = tcg_temp_new();
1707 1708 1709 1710
            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 已提交
1711
        }
1712
    } else if (likely(sh != 0 && me == 31 && sh == (32 - mb))) {
P
pbrook 已提交
1713
        TCGv t0 = tcg_temp_new();
1714 1715 1716 1717 1718
        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 已提交
1719
        TCGv t0 = tcg_temp_new();
1720
#if defined(TARGET_PPC64)
P
pbrook 已提交
1721
        TCGv_i32 t1 = tcg_temp_new_i32();
1722 1723 1724
        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 已提交
1725
        tcg_temp_free_i32(t1);
1726 1727 1728
#else
        tcg_gen_rotli_i32(t0, cpu_gpr[rS(ctx->opcode)], sh);
#endif
1729
#if defined(TARGET_PPC64)
1730 1731
        mb += 32;
        me += 32;
1732
#endif
1733 1734 1735
        tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], t0, MASK(mb, me));
        tcg_temp_free(t0);
    }
1736
    if (unlikely(Rc(ctx->opcode) != 0))
1737
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
B
bellard 已提交
1738 1739 1740 1741 1742
}
/* rlwnm & rlwnm. */
GEN_HANDLER(rlwnm, 0x17, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
    uint32_t mb, me;
1743 1744
    TCGv t0;
#if defined(TARGET_PPC64)
P
pbrook 已提交
1745
    TCGv_i32 t1, t2;
1746
#endif
B
bellard 已提交
1747 1748 1749

    mb = MB(ctx->opcode);
    me = ME(ctx->opcode);
P
pbrook 已提交
1750
    t0 = tcg_temp_new();
1751
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1f);
1752
#if defined(TARGET_PPC64)
P
pbrook 已提交
1753 1754
    t1 = tcg_temp_new_i32();
    t2 = tcg_temp_new_i32();
1755 1756 1757 1758
    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 已提交
1759 1760
    tcg_temp_free_i32(t1);
    tcg_temp_free_i32(t2);
1761 1762 1763
#else
    tcg_gen_rotl_i32(t0, cpu_gpr[rS(ctx->opcode)], t0);
#endif
1764 1765 1766 1767 1768
    if (unlikely(mb != 0 || me != 31)) {
#if defined(TARGET_PPC64)
        mb += 32;
        me += 32;
#endif
1769
        tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], t0, MASK(mb, me));
1770
    } else {
1771
        tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
B
bellard 已提交
1772
    }
1773
    tcg_temp_free(t0);
1774
    if (unlikely(Rc(ctx->opcode) != 0))
1775
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
B
bellard 已提交
1776 1777
}

1778 1779
#if defined(TARGET_PPC64)
#define GEN_PPC64_R2(name, opc1, opc2)                                        \
1780
GEN_HANDLER2(name##0, stringify(name), opc1, opc2, 0xFF, 0x00000000, PPC_64B) \
1781 1782 1783
{                                                                             \
    gen_##name(ctx, 0);                                                       \
}                                                                             \
1784 1785
GEN_HANDLER2(name##1, stringify(name), opc1, opc2 | 0x10, 0xFF, 0x00000000,   \
             PPC_64B)                                                         \
1786 1787 1788 1789
{                                                                             \
    gen_##name(ctx, 1);                                                       \
}
#define GEN_PPC64_R4(name, opc1, opc2)                                        \
1790
GEN_HANDLER2(name##0, stringify(name), opc1, opc2, 0xFF, 0x00000000, PPC_64B) \
1791 1792 1793
{                                                                             \
    gen_##name(ctx, 0, 0);                                                    \
}                                                                             \
1794 1795
GEN_HANDLER2(name##1, stringify(name), opc1, opc2 | 0x01, 0xFF, 0x00000000,   \
             PPC_64B)                                                         \
1796 1797 1798
{                                                                             \
    gen_##name(ctx, 0, 1);                                                    \
}                                                                             \
1799 1800
GEN_HANDLER2(name##2, stringify(name), opc1, opc2 | 0x10, 0xFF, 0x00000000,   \
             PPC_64B)                                                         \
1801 1802 1803
{                                                                             \
    gen_##name(ctx, 1, 0);                                                    \
}                                                                             \
1804 1805
GEN_HANDLER2(name##3, stringify(name), opc1, opc2 | 0x11, 0xFF, 0x00000000,   \
             PPC_64B)                                                         \
1806 1807 1808
{                                                                             \
    gen_##name(ctx, 1, 1);                                                    \
}
J
j_mayer 已提交
1809

1810 1811
static always_inline void gen_rldinm (DisasContext *ctx, uint32_t mb,
                                      uint32_t me, uint32_t sh)
J
j_mayer 已提交
1812
{
1813 1814 1815 1816 1817
    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 已提交
1818
        TCGv t0 = tcg_temp_new();
1819
        tcg_gen_rotli_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
1820
        if (likely(mb == 0 && me == 63)) {
1821
            tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
1822 1823
        } else {
            tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], t0, MASK(mb, me));
J
j_mayer 已提交
1824
        }
1825
        tcg_temp_free(t0);
J
j_mayer 已提交
1826 1827
    }
    if (unlikely(Rc(ctx->opcode) != 0))
1828
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
J
j_mayer 已提交
1829
}
1830
/* rldicl - rldicl. */
1831
static always_inline void gen_rldicl (DisasContext *ctx, int mbn, int shn)
1832
{
J
j_mayer 已提交
1833
    uint32_t sh, mb;
1834

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

J
j_mayer 已提交
1845 1846
    sh = SH(ctx->opcode) | (shn << 5);
    me = MB(ctx->opcode) | (men << 5);
J
j_mayer 已提交
1847
    gen_rldinm(ctx, 0, me, sh);
1848
}
J
j_mayer 已提交
1849
GEN_PPC64_R4(rldicr, 0x1E, 0x02);
1850
/* rldic - rldic. */
1851
static always_inline void gen_rldic (DisasContext *ctx, int mbn, int shn)
1852
{
J
j_mayer 已提交
1853
    uint32_t sh, mb;
1854

J
j_mayer 已提交
1855 1856
    sh = SH(ctx->opcode) | (shn << 5);
    mb = MB(ctx->opcode) | (mbn << 5);
J
j_mayer 已提交
1857 1858 1859 1860
    gen_rldinm(ctx, mb, 63 - sh, sh);
}
GEN_PPC64_R4(rldic, 0x1E, 0x04);

1861 1862
static always_inline void gen_rldnm (DisasContext *ctx, uint32_t mb,
                                     uint32_t me)
J
j_mayer 已提交
1863
{
1864
    TCGv t0;
1865 1866 1867

    mb = MB(ctx->opcode);
    me = ME(ctx->opcode);
P
pbrook 已提交
1868
    t0 = tcg_temp_new();
1869
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x3f);
1870
    tcg_gen_rotl_tl(t0, cpu_gpr[rS(ctx->opcode)], t0);
J
j_mayer 已提交
1871
    if (unlikely(mb != 0 || me != 63)) {
1872 1873 1874 1875 1876
        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 已提交
1877
    if (unlikely(Rc(ctx->opcode) != 0))
1878
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
1879
}
J
j_mayer 已提交
1880

1881
/* rldcl - rldcl. */
1882
static always_inline void gen_rldcl (DisasContext *ctx, int mbn)
1883
{
J
j_mayer 已提交
1884
    uint32_t mb;
1885

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

J
j_mayer 已提交
1895
    me = MB(ctx->opcode) | (men << 5);
J
j_mayer 已提交
1896
    gen_rldnm(ctx, 0, me);
1897
}
1898
GEN_PPC64_R2(rldcr, 0x1E, 0x09);
1899
/* rldimi - rldimi. */
1900
static always_inline void gen_rldimi (DisasContext *ctx, int mbn, int shn)
1901
{
1902
    uint32_t sh, mb, me;
1903

J
j_mayer 已提交
1904 1905
    sh = SH(ctx->opcode) | (shn << 5);
    mb = MB(ctx->opcode) | (mbn << 5);
1906
    me = 63 - sh;
1907 1908 1909 1910 1911 1912
    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 已提交
1913
        t0 = tcg_temp_new();
1914
        tcg_gen_rotli_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
P
pbrook 已提交
1915
        t1 = tcg_temp_new();
1916 1917 1918 1919 1920 1921
        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 已提交
1922 1923
    }
    if (unlikely(Rc(ctx->opcode) != 0))
1924
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
1925
}
1926
GEN_PPC64_R4(rldimi, 0x1E, 0x06);
1927 1928
#endif

B
bellard 已提交
1929 1930
/***                             Integer shift                             ***/
/* slw & slw. */
1931 1932
GEN_HANDLER(slw, 0x1F, 0x18, 0x00, 0x00000000, PPC_INTEGER)
{
1933
    TCGv t0;
1934 1935 1936 1937
    int l1, l2;
    l1 = gen_new_label();
    l2 = gen_new_label();

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

P
pbrook 已提交
1996
    t0 = tcg_temp_local_new();
A
aurel32 已提交
1997 1998
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x3f);
    tcg_gen_brcondi_tl(TCG_COND_LT, t0, 0x20, l1);
1999 2000 2001
    tcg_gen_movi_tl(cpu_gpr[rA(ctx->opcode)], 0);
    tcg_gen_br(l2);
    gen_set_label(l1);
P
pbrook 已提交
2002
    t1 = tcg_temp_new();
2003 2004 2005
    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);
2006
    gen_set_label(l2);
2007
    tcg_temp_free(t0);
2008 2009 2010
    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
}
2011 2012
#if defined(TARGET_PPC64)
/* sld & sld. */
2013 2014
GEN_HANDLER(sld, 0x1F, 0x1B, 0x00, 0x00000000, PPC_64B)
{
2015
    TCGv t0;
2016 2017 2018 2019
    int l1, l2;
    l1 = gen_new_label();
    l2 = gen_new_label();

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

P
pbrook 已提交
2083
    t0 = tcg_temp_local_new();
A
aurel32 已提交
2084 2085
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x7f);
    tcg_gen_brcondi_tl(TCG_COND_LT, t0, 0x40, l1);
2086 2087 2088
    tcg_gen_movi_tl(cpu_gpr[rA(ctx->opcode)], 0);
    tcg_gen_br(l2);
    gen_set_label(l1);
2089
    tcg_gen_shr_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], t0);
2090
    gen_set_label(l2);
2091
    tcg_temp_free(t0);
2092 2093 2094
    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
}
2095
#endif
B
bellard 已提交
2096 2097

/***                       Floating-Point arithmetic                       ***/
2098
#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat, set_fprf, type)           \
2099
GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, type)                        \
2100
{                                                                             \
2101
    if (unlikely(!ctx->fpu_enabled)) {                                        \
2102
        GEN_EXCP_NO_FP(ctx);                                                  \
B
bellard 已提交
2103 2104
        return;                                                               \
    }                                                                         \
2105
    gen_reset_fpstatus();                                                     \
A
aurel32 已提交
2106 2107
    gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)],      \
                     cpu_fpr[rC(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);     \
2108
    if (isfloat) {                                                            \
A
aurel32 已提交
2109
        gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]);  \
2110
    }                                                                         \
A
aurel32 已提交
2111 2112
    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], set_fprf,                      \
                     Rc(ctx->opcode) != 0);                                   \
2113 2114
}

2115 2116 2117
#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);
2118

2119 2120
#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat, set_fprf, type)     \
GEN_HANDLER(f##name, op1, op2, 0xFF, inval, type)                             \
2121
{                                                                             \
2122
    if (unlikely(!ctx->fpu_enabled)) {                                        \
2123
        GEN_EXCP_NO_FP(ctx);                                                  \
B
bellard 已提交
2124 2125
        return;                                                               \
    }                                                                         \
2126
    gen_reset_fpstatus();                                                     \
A
aurel32 已提交
2127 2128
    gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)],      \
                     cpu_fpr[rB(ctx->opcode)]);                               \
2129
    if (isfloat) {                                                            \
A
aurel32 已提交
2130
        gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]);  \
2131
    }                                                                         \
A
aurel32 已提交
2132 2133
    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)],                                \
                     set_fprf, Rc(ctx->opcode) != 0);                         \
2134
}
2135 2136 2137
#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);
2138

2139 2140
#define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat, set_fprf, type)     \
GEN_HANDLER(f##name, op1, op2, 0xFF, inval, type)                             \
2141
{                                                                             \
2142
    if (unlikely(!ctx->fpu_enabled)) {                                        \
2143
        GEN_EXCP_NO_FP(ctx);                                                  \
B
bellard 已提交
2144 2145
        return;                                                               \
    }                                                                         \
2146
    gen_reset_fpstatus();                                                     \
A
aurel32 已提交
2147 2148
    gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)],      \
                       cpu_fpr[rC(ctx->opcode)]);                             \
2149
    if (isfloat) {                                                            \
A
aurel32 已提交
2150
        gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]);  \
2151
    }                                                                         \
A
aurel32 已提交
2152 2153
    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)],                                \
                     set_fprf, Rc(ctx->opcode) != 0);                         \
2154
}
2155 2156 2157
#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);
2158

2159
#define GEN_FLOAT_B(name, op2, op3, set_fprf, type)                           \
2160
GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, type)                        \
2161
{                                                                             \
2162
    if (unlikely(!ctx->fpu_enabled)) {                                        \
2163
        GEN_EXCP_NO_FP(ctx);                                                  \
B
bellard 已提交
2164 2165
        return;                                                               \
    }                                                                         \
2166
    gen_reset_fpstatus();                                                     \
A
aurel32 已提交
2167 2168 2169
    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 已提交
2170 2171
}

2172
#define GEN_FLOAT_BS(name, op1, op2, set_fprf, type)                          \
2173
GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, type)                        \
2174
{                                                                             \
2175
    if (unlikely(!ctx->fpu_enabled)) {                                        \
2176
        GEN_EXCP_NO_FP(ctx);                                                  \
B
bellard 已提交
2177 2178
        return;                                                               \
    }                                                                         \
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 2205 2206 2207 2208 2209 2210 2211
    if (unlikely(!ctx->fpu_enabled)) {
        GEN_EXCP_NO_FP(ctx);
        return;
    }
    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);
2212
}
B
bellard 已提交
2213

2214
/* fsel */
2215
_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0, 0, PPC_FLOAT_FSEL);
2216
/* fsub - fsubs */
2217
GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT);
B
bellard 已提交
2218 2219
/* Optional: */
/* fsqrt */
2220
GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT)
2221
{
2222
    if (unlikely(!ctx->fpu_enabled)) {
2223
        GEN_EXCP_NO_FP(ctx);
2224 2225
        return;
    }
2226
    gen_reset_fpstatus();
A
aurel32 已提交
2227 2228
    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);
2229
}
B
bellard 已提交
2230

2231
GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT)
B
bellard 已提交
2232
{
2233
    if (unlikely(!ctx->fpu_enabled)) {
2234
        GEN_EXCP_NO_FP(ctx);
B
bellard 已提交
2235 2236
        return;
    }
2237
    gen_reset_fpstatus();
A
aurel32 已提交
2238 2239 2240
    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 已提交
2241 2242 2243
}

/***                     Floating-Point multiply-and-add                   ***/
2244
/* fmadd - fmadds */
2245
GEN_FLOAT_ACB(madd, 0x1D, 1, PPC_FLOAT);
2246
/* fmsub - fmsubs */
2247
GEN_FLOAT_ACB(msub, 0x1C, 1, PPC_FLOAT);
2248
/* fnmadd - fnmadds */
2249
GEN_FLOAT_ACB(nmadd, 0x1F, 1, PPC_FLOAT);
2250
/* fnmsub - fnmsubs */
2251
GEN_FLOAT_ACB(nmsub, 0x1E, 1, PPC_FLOAT);
B
bellard 已提交
2252 2253 2254

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

2269
/* frin */
2270
GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT);
2271
/* friz */
2272
GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT);
2273
/* frip */
2274
GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT);
2275
/* frim */
2276
GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT);
2277

B
bellard 已提交
2278 2279
/***                         Floating-Point compare                        ***/
/* fcmpo */
2280
GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT)
B
bellard 已提交
2281
{
2282
    if (unlikely(!ctx->fpu_enabled)) {
2283
        GEN_EXCP_NO_FP(ctx);
B
bellard 已提交
2284 2285
        return;
    }
2286
    gen_reset_fpstatus();
A
aurel32 已提交
2287 2288 2289
    gen_helper_fcmpo(cpu_crf[crfD(ctx->opcode)],
                     cpu_fpr[rA(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);
    gen_helper_float_check_status();
B
bellard 已提交
2290 2291 2292
}

/* fcmpu */
2293
GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT)
B
bellard 已提交
2294
{
2295
    if (unlikely(!ctx->fpu_enabled)) {
2296
        GEN_EXCP_NO_FP(ctx);
B
bellard 已提交
2297 2298
        return;
    }
2299
    gen_reset_fpstatus();
A
aurel32 已提交
2300 2301 2302
    gen_helper_fcmpu(cpu_crf[crfD(ctx->opcode)],
                     cpu_fpr[rA(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);
    gen_helper_float_check_status();
B
bellard 已提交
2303 2304
}

2305 2306
/***                         Floating-point move                           ***/
/* fabs */
2307 2308
/* XXX: beware that fabs never checks for NaNs nor update FPSCR */
GEN_FLOAT_B(abs, 0x08, 0x08, 0, PPC_FLOAT);
2309 2310

/* fmr  - fmr. */
2311
/* XXX: beware that fmr never checks for NaNs nor update FPSCR */
2312 2313
GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT)
{
2314
    if (unlikely(!ctx->fpu_enabled)) {
2315
        GEN_EXCP_NO_FP(ctx);
B
bellard 已提交
2316 2317
        return;
    }
A
aurel32 已提交
2318 2319
    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);
2320 2321 2322
}

/* fnabs */
2323 2324
/* XXX: beware that fnabs never checks for NaNs nor update FPSCR */
GEN_FLOAT_B(nabs, 0x08, 0x04, 0, PPC_FLOAT);
2325
/* fneg */
2326 2327
/* XXX: beware that fneg never checks for NaNs nor update FPSCR */
GEN_FLOAT_B(neg, 0x08, 0x01, 0, PPC_FLOAT);
2328

B
bellard 已提交
2329 2330 2331 2332
/***                  Floating-Point status & ctrl register                ***/
/* mcrfs */
GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT)
{
2333 2334
    int bfa;

2335
    if (unlikely(!ctx->fpu_enabled)) {
2336
        GEN_EXCP_NO_FP(ctx);
B
bellard 已提交
2337 2338
        return;
    }
2339 2340
    gen_optimize_fprf();
    bfa = 4 * (7 - crfS(ctx->opcode));
2341 2342
    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 已提交
2343
    tcg_gen_andi_i32(cpu_fpscr, cpu_fpscr, ~(0xF << bfa));
B
bellard 已提交
2344 2345 2346 2347 2348
}

/* mffs */
GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT)
{
2349
    if (unlikely(!ctx->fpu_enabled)) {
2350
        GEN_EXCP_NO_FP(ctx);
B
bellard 已提交
2351 2352
        return;
    }
2353 2354
    gen_optimize_fprf();
    gen_reset_fpstatus();
A
aurel32 已提交
2355 2356
    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 已提交
2357 2358 2359 2360 2361
}

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

2364
    if (unlikely(!ctx->fpu_enabled)) {
2365
        GEN_EXCP_NO_FP(ctx);
B
bellard 已提交
2366 2367
        return;
    }
2368 2369 2370 2371
    crb = 32 - (crbD(ctx->opcode) >> 2);
    gen_optimize_fprf();
    gen_reset_fpstatus();
    if (likely(crb != 30 && crb != 29))
A
aurel32 已提交
2372
        tcg_gen_andi_i32(cpu_fpscr, cpu_fpscr, ~(1 << crb));
2373
    if (unlikely(Rc(ctx->opcode) != 0)) {
2374
        tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX);
2375
    }
B
bellard 已提交
2376 2377 2378 2379 2380
}

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

2383
    if (unlikely(!ctx->fpu_enabled)) {
2384
        GEN_EXCP_NO_FP(ctx);
B
bellard 已提交
2385 2386
        return;
    }
2387 2388 2389 2390
    crb = 32 - (crbD(ctx->opcode) >> 2);
    gen_optimize_fprf();
    gen_reset_fpstatus();
    /* XXX: we pretend we can only do IEEE floating-point computations */
A
aurel32 已提交
2391
    if (likely(crb != FPSCR_FEX && crb != FPSCR_VX && crb != FPSCR_NI)) {
2392
        TCGv_i32 t0 = tcg_const_i32(crb);
A
aurel32 已提交
2393
        gen_helper_fpscr_setbit(t0);
2394
        tcg_temp_free_i32(t0);
A
aurel32 已提交
2395
    }
2396
    if (unlikely(Rc(ctx->opcode) != 0)) {
2397
        tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX);
2398 2399
    }
    /* We can raise a differed exception */
A
aurel32 已提交
2400
    gen_helper_float_check_status();
B
bellard 已提交
2401 2402 2403 2404 2405
}

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

2408
    if (unlikely(!ctx->fpu_enabled)) {
2409
        GEN_EXCP_NO_FP(ctx);
B
bellard 已提交
2410 2411
        return;
    }
2412 2413
    gen_optimize_fprf();
    gen_reset_fpstatus();
A
aurel32 已提交
2414 2415
    t0 = tcg_const_i32(FM(ctx->opcode));
    gen_helper_store_fpscr(cpu_fpr[rB(ctx->opcode)], t0);
2416
    tcg_temp_free_i32(t0);
2417
    if (unlikely(Rc(ctx->opcode) != 0)) {
2418
        tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX);
2419 2420
    }
    /* We can raise a differed exception */
A
aurel32 已提交
2421
    gen_helper_float_check_status();
B
bellard 已提交
2422 2423 2424 2425 2426
}

/* mtfsfi */
GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT)
{
2427
    int bf, sh;
2428 2429
    TCGv_i64 t0;
    TCGv_i32 t1;
2430

2431
    if (unlikely(!ctx->fpu_enabled)) {
2432
        GEN_EXCP_NO_FP(ctx);
B
bellard 已提交
2433 2434
        return;
    }
2435 2436 2437 2438
    bf = crbD(ctx->opcode) >> 2;
    sh = 7 - bf;
    gen_optimize_fprf();
    gen_reset_fpstatus();
2439
    t0 = tcg_const_i64(FPIMM(ctx->opcode) << (4 * sh));
A
aurel32 已提交
2440 2441
    t1 = tcg_const_i32(1 << sh);
    gen_helper_store_fpscr(t0, t1);
2442 2443
    tcg_temp_free_i64(t0);
    tcg_temp_free_i32(t1);
2444
    if (unlikely(Rc(ctx->opcode) != 0)) {
2445
        tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX);
2446 2447
    }
    /* We can raise a differed exception */
A
aurel32 已提交
2448
    gen_helper_float_check_status();
B
bellard 已提交
2449 2450
}

2451 2452
/***                           Addressing modes                            ***/
/* Register indirect with immediate index : EA = (rA|0) + SIMM */
2453 2454
static always_inline void gen_addr_imm_index (TCGv EA,
                                              DisasContext *ctx,
2455
                                              target_long maskl)
2456 2457 2458
{
    target_long simm = SIMM(ctx->opcode);

2459
    simm &= ~maskl;
2460 2461 2462 2463 2464 2465
    if (rA(ctx->opcode) == 0)
        tcg_gen_movi_tl(EA, simm);
    else if (likely(simm != 0))
        tcg_gen_addi_tl(EA, cpu_gpr[rA(ctx->opcode)], simm);
    else
        tcg_gen_mov_tl(EA, cpu_gpr[rA(ctx->opcode)]);
2466 2467
}

2468 2469
static always_inline void gen_addr_reg_index (TCGv EA,
                                              DisasContext *ctx)
2470
{
2471 2472 2473 2474
    if (rA(ctx->opcode) == 0)
        tcg_gen_mov_tl(EA, cpu_gpr[rB(ctx->opcode)]);
    else
        tcg_gen_add_tl(EA, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
2475 2476
}

2477 2478
static always_inline void gen_addr_register (TCGv EA,
                                             DisasContext *ctx)
2479
{
2480 2481 2482 2483
    if (rA(ctx->opcode) == 0)
        tcg_gen_movi_tl(EA, 0);
    else
        tcg_gen_mov_tl(EA, cpu_gpr[rA(ctx->opcode)]);
2484 2485
}

2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503
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);
}

2504
/***                             Integer load                              ***/
A
aurel32 已提交
2505 2506 2507 2508 2509 2510 2511
#if defined(TARGET_PPC64)
#define GEN_QEMU_LD_PPC64(width)                                                 \
static always_inline void gen_qemu_ld##width##_ppc64(TCGv t0, TCGv t1, int flags)\
{                                                                                \
    if (likely(flags & 2))                                                       \
        tcg_gen_qemu_ld##width(t0, t1, flags >> 2);                              \
    else {                                                                       \
P
pbrook 已提交
2512
        TCGv addr = tcg_temp_new();                                   \
A
aurel32 已提交
2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531
        tcg_gen_ext32u_tl(addr, t1);                                             \
        tcg_gen_qemu_ld##width(t0, addr, flags >> 2);                            \
        tcg_temp_free(addr);                                                     \
    }                                                                            \
}
GEN_QEMU_LD_PPC64(8u)
GEN_QEMU_LD_PPC64(8s)
GEN_QEMU_LD_PPC64(16u)
GEN_QEMU_LD_PPC64(16s)
GEN_QEMU_LD_PPC64(32u)
GEN_QEMU_LD_PPC64(32s)
GEN_QEMU_LD_PPC64(64)

#define GEN_QEMU_ST_PPC64(width)                                                 \
static always_inline void gen_qemu_st##width##_ppc64(TCGv t0, TCGv t1, int flags)\
{                                                                                \
    if (likely(flags & 2))                                                       \
        tcg_gen_qemu_st##width(t0, t1, flags >> 2);                              \
    else {                                                                       \
P
pbrook 已提交
2532
        TCGv addr = tcg_temp_new();                                   \
A
aurel32 已提交
2533 2534 2535 2536 2537 2538 2539 2540 2541 2542
        tcg_gen_ext32u_tl(addr, t1);                                             \
        tcg_gen_qemu_st##width(t0, addr, flags >> 2);                            \
        tcg_temp_free(addr);                                                     \
    }                                                                            \
}
GEN_QEMU_ST_PPC64(8)
GEN_QEMU_ST_PPC64(16)
GEN_QEMU_ST_PPC64(32)
GEN_QEMU_ST_PPC64(64)

2543
static always_inline void gen_qemu_ld8u(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2544
{
2545
    gen_qemu_ld8u_ppc64(arg0, arg1, flags);
A
aurel32 已提交
2546 2547
}

2548
static always_inline void gen_qemu_ld8s(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2549
{
2550
    gen_qemu_ld8s_ppc64(arg0, arg1, flags);
A
aurel32 已提交
2551 2552
}

2553
static always_inline void gen_qemu_ld16u(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2554 2555
{
    if (unlikely(flags & 1)) {
P
pbrook 已提交
2556
        TCGv_i32 t0;
2557
        gen_qemu_ld16u_ppc64(arg0, arg1, flags);
P
pbrook 已提交
2558
        t0 = tcg_temp_new_i32();
2559 2560 2561
        tcg_gen_trunc_tl_i32(t0, arg0);
        tcg_gen_bswap16_i32(t0, t0);
        tcg_gen_extu_i32_tl(arg0, t0);
P
pbrook 已提交
2562
        tcg_temp_free_i32(t0);
A
aurel32 已提交
2563
    } else
2564
        gen_qemu_ld16u_ppc64(arg0, arg1, flags);
A
aurel32 已提交
2565 2566
}

2567
static always_inline void gen_qemu_ld16s(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2568 2569
{
    if (unlikely(flags & 1)) {
P
pbrook 已提交
2570
        TCGv_i32 t0;
2571
        gen_qemu_ld16u_ppc64(arg0, arg1, flags);
P
pbrook 已提交
2572
        t0 = tcg_temp_new_i32();
2573 2574 2575 2576
        tcg_gen_trunc_tl_i32(t0, arg0);
        tcg_gen_bswap16_i32(t0, t0);
        tcg_gen_extu_i32_tl(arg0, t0);
        tcg_gen_ext16s_tl(arg0, arg0);
P
pbrook 已提交
2577
        tcg_temp_free_i32(t0);
A
aurel32 已提交
2578
    } else
2579
        gen_qemu_ld16s_ppc64(arg0, arg1, flags);
A
aurel32 已提交
2580 2581
}

2582
static always_inline void gen_qemu_ld32u(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2583 2584
{
    if (unlikely(flags & 1)) {
P
pbrook 已提交
2585
        TCGv_i32 t0;
2586
        gen_qemu_ld32u_ppc64(arg0, arg1, flags);
P
pbrook 已提交
2587
        t0 = tcg_temp_new_i32();
2588 2589 2590
        tcg_gen_trunc_tl_i32(t0, arg0);
        tcg_gen_bswap_i32(t0, t0);
        tcg_gen_extu_i32_tl(arg0, t0);
P
pbrook 已提交
2591
        tcg_temp_free_i32(t0);
A
aurel32 已提交
2592
    } else
2593
        gen_qemu_ld32u_ppc64(arg0, arg1, flags);
A
aurel32 已提交
2594 2595
}

2596
static always_inline void gen_qemu_ld32s(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2597 2598
{
    if (unlikely(flags & 1)) {
P
pbrook 已提交
2599
        TCGv_i32 t0;
2600
        gen_qemu_ld32u_ppc64(arg0, arg1, flags);
P
pbrook 已提交
2601
        t0 = tcg_temp_new_i32();
2602 2603 2604
        tcg_gen_trunc_tl_i32(t0, arg0);
        tcg_gen_bswap_i32(t0, t0);
        tcg_gen_ext_i32_tl(arg0, t0);
P
pbrook 已提交
2605
        tcg_temp_free_i32(t0);
A
aurel32 已提交
2606
    } else
2607
        gen_qemu_ld32s_ppc64(arg0, arg1, flags);
A
aurel32 已提交
2608 2609
}

2610
static always_inline void gen_qemu_ld64(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2611
{
2612
    gen_qemu_ld64_ppc64(arg0, arg1, flags);
A
aurel32 已提交
2613
    if (unlikely(flags & 1))
2614
        tcg_gen_bswap_i64(arg0, arg0);
A
aurel32 已提交
2615 2616
}

2617
static always_inline void gen_qemu_st8(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2618
{
2619
    gen_qemu_st8_ppc64(arg0, arg1, flags);
A
aurel32 已提交
2620 2621
}

2622
static always_inline void gen_qemu_st16(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2623 2624
{
    if (unlikely(flags & 1)) {
P
pbrook 已提交
2625 2626 2627
        TCGv_i32 t0;
        TCGv_i64 t1;
        t0 = tcg_temp_new_i32();
2628 2629 2630
        tcg_gen_trunc_tl_i32(t0, arg0);
        tcg_gen_ext16u_i32(t0, t0);
        tcg_gen_bswap16_i32(t0, t0);
P
pbrook 已提交
2631
        t1 = tcg_temp_new_i64();
2632
        tcg_gen_extu_i32_tl(t1, t0);
P
pbrook 已提交
2633
        tcg_temp_free_i32(t0);
2634
        gen_qemu_st16_ppc64(t1, arg1, flags);
P
pbrook 已提交
2635
        tcg_temp_free_i64(t1);
A
aurel32 已提交
2636
    } else
2637
        gen_qemu_st16_ppc64(arg0, arg1, flags);
A
aurel32 已提交
2638 2639
}

2640
static always_inline void gen_qemu_st32(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2641 2642
{
    if (unlikely(flags & 1)) {
P
pbrook 已提交
2643 2644 2645
        TCGv_i32 t0;
        TCGv_i64 t1;
        t0 = tcg_temp_new_i32();
2646 2647
        tcg_gen_trunc_tl_i32(t0, arg0);
        tcg_gen_bswap_i32(t0, t0);
P
pbrook 已提交
2648
        t1 = tcg_temp_new_i64();
2649
        tcg_gen_extu_i32_tl(t1, t0);
P
pbrook 已提交
2650
        tcg_temp_free_i32(t0);
2651
        gen_qemu_st32_ppc64(t1, arg1, flags);
P
pbrook 已提交
2652
        tcg_temp_free_i64(t1);
A
aurel32 已提交
2653
    } else
2654
        gen_qemu_st32_ppc64(arg0, arg1, flags);
A
aurel32 已提交
2655 2656
}

2657
static always_inline void gen_qemu_st64(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2658 2659
{
    if (unlikely(flags & 1)) {
P
pbrook 已提交
2660
        TCGv_i64 t0 = tcg_temp_new_i64();
2661 2662
        tcg_gen_bswap_i64(t0, arg0);
        gen_qemu_st64_ppc64(t0, arg1, flags);
P
pbrook 已提交
2663
        tcg_temp_free_i64(t0);
A
aurel32 已提交
2664
    } else
2665
        gen_qemu_st64_ppc64(arg0, arg1, flags);
A
aurel32 已提交
2666 2667 2668 2669
}


#else /* defined(TARGET_PPC64) */
2670 2671 2672 2673
#define GEN_QEMU_LD_PPC32(width)                                                      \
static always_inline void gen_qemu_ld##width##_ppc32(TCGv arg0, TCGv arg1, int flags) \
{                                                                                     \
    tcg_gen_qemu_ld##width(arg0, arg1, flags >> 1);                                   \
A
aurel32 已提交
2674 2675 2676 2677 2678 2679 2680
}
GEN_QEMU_LD_PPC32(8u)
GEN_QEMU_LD_PPC32(8s)
GEN_QEMU_LD_PPC32(16u)
GEN_QEMU_LD_PPC32(16s)
GEN_QEMU_LD_PPC32(32u)
GEN_QEMU_LD_PPC32(32s)
2681 2682 2683 2684
static always_inline void gen_qemu_ld64_ppc32(TCGv_i64 arg0, TCGv arg1, int flags)
{
    tcg_gen_qemu_ld64(arg0, arg1, flags >> 1);
}
A
aurel32 已提交
2685

2686 2687 2688 2689
#define GEN_QEMU_ST_PPC32(width)                                                      \
static always_inline void gen_qemu_st##width##_ppc32(TCGv arg0, TCGv arg1, int flags) \
{                                                                                     \
    tcg_gen_qemu_st##width(arg0, arg1, flags >> 1);                                   \
A
aurel32 已提交
2690 2691 2692 2693
}
GEN_QEMU_ST_PPC32(8)
GEN_QEMU_ST_PPC32(16)
GEN_QEMU_ST_PPC32(32)
2694 2695 2696 2697
static always_inline void gen_qemu_st64_ppc32(TCGv_i64 arg0, TCGv arg1, int flags)
{
    tcg_gen_qemu_st64(arg0, arg1, flags >> 1);
}
A
aurel32 已提交
2698

2699
static always_inline void gen_qemu_ld8u(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2700
{
2701
    gen_qemu_ld8u_ppc32(arg0, arg1, flags >> 1);
A
aurel32 已提交
2702 2703
}

2704
static always_inline void gen_qemu_ld8s(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2705
{
2706
    gen_qemu_ld8s_ppc32(arg0, arg1, flags >> 1);
A
aurel32 已提交
2707 2708
}

2709
static always_inline void gen_qemu_ld16u(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2710
{
2711
    gen_qemu_ld16u_ppc32(arg0, arg1, flags >> 1);
A
aurel32 已提交
2712
    if (unlikely(flags & 1))
2713
        tcg_gen_bswap16_i32(arg0, arg0);
A
aurel32 已提交
2714 2715
}

2716
static always_inline void gen_qemu_ld16s(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2717 2718
{
    if (unlikely(flags & 1)) {
2719 2720 2721
        gen_qemu_ld16u_ppc32(arg0, arg1, flags);
        tcg_gen_bswap16_i32(arg0, arg0);
        tcg_gen_ext16s_i32(arg0, arg0);
A
aurel32 已提交
2722
    } else
2723
        gen_qemu_ld16s_ppc32(arg0, arg1, flags);
A
aurel32 已提交
2724 2725
}

2726
static always_inline void gen_qemu_ld32u(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2727
{
2728
    gen_qemu_ld32u_ppc32(arg0, arg1, flags);
A
aurel32 已提交
2729
    if (unlikely(flags & 1))
2730
        tcg_gen_bswap_i32(arg0, arg0);
A
aurel32 已提交
2731 2732
}

2733 2734 2735 2736 2737 2738 2739
static always_inline void gen_qemu_ld64(TCGv_i64 arg0, TCGv arg1, int flags)
{
    gen_qemu_ld64_ppc32(arg0, arg1, flags);
    if (unlikely(flags & 1))
        tcg_gen_bswap_i64(arg0, arg0);
}

2740
static always_inline void gen_qemu_st8(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2741
{
2742
    gen_qemu_st8_ppc32(arg0, arg1, flags);
A
aurel32 已提交
2743 2744
}

2745
static always_inline void gen_qemu_st16(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2746 2747
{
    if (unlikely(flags & 1)) {
P
pbrook 已提交
2748
        TCGv_i32 temp = tcg_temp_new_i32();
2749
        tcg_gen_ext16u_i32(temp, arg0);
A
aurel32 已提交
2750
        tcg_gen_bswap16_i32(temp, temp);
2751
        gen_qemu_st16_ppc32(temp, arg1, flags);
P
pbrook 已提交
2752
        tcg_temp_free_i32(temp);
A
aurel32 已提交
2753
    } else
2754
        gen_qemu_st16_ppc32(arg0, arg1, flags);
A
aurel32 已提交
2755 2756
}

2757
static always_inline void gen_qemu_st32(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2758 2759
{
    if (unlikely(flags & 1)) {
P
pbrook 已提交
2760
        TCGv_i32 temp = tcg_temp_new_i32();
2761
        tcg_gen_bswap_i32(temp, arg0);
2762
        gen_qemu_st32_ppc32(temp, arg1, flags);
P
pbrook 已提交
2763
        tcg_temp_free_i32(temp);
A
aurel32 已提交
2764
    } else
2765
        gen_qemu_st32_ppc32(arg0, arg1, flags);
A
aurel32 已提交
2766 2767
}

2768 2769 2770 2771 2772 2773 2774 2775 2776 2777
static always_inline void gen_qemu_st64(TCGv_i64 arg0, TCGv arg1, int flags)
{
    if (unlikely(flags & 1)) {
        TCGv_i64 temp = tcg_temp_new_i64();
        tcg_gen_bswap_i64(temp, arg0);
        gen_qemu_st64_ppc32(temp, arg1, flags);
        tcg_temp_free_i64(temp);
    } else
        gen_qemu_st64_ppc32(arg0, arg1, flags);
}
A
aurel32 已提交
2778 2779
#endif

2780 2781
#define GEN_LD(name, ldop, opc, type)                                         \
GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type)                          \
B
bellard 已提交
2782
{                                                                             \
2783
    TCGv EA = tcg_temp_new();                                                 \
A
aurel32 已提交
2784
    gen_set_access_type(ACCESS_INT);                                          \
A
aurel32 已提交
2785
    gen_addr_imm_index(EA, ctx, 0);                                           \
2786
    gen_qemu_##ldop(cpu_gpr[rD(ctx->opcode)], EA, ctx->mem_idx);              \
A
aurel32 已提交
2787
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2788 2789
}

2790 2791
#define GEN_LDU(name, ldop, opc, type)                                        \
GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type)                       \
B
bellard 已提交
2792
{                                                                             \
A
aurel32 已提交
2793
    TCGv EA;                                                                  \
2794 2795
    if (unlikely(rA(ctx->opcode) == 0 ||                                      \
                 rA(ctx->opcode) == rD(ctx->opcode))) {                       \
2796
        GEN_EXCP_INVAL(ctx);                                                  \
2797
        return;                                                               \
2798
    }                                                                         \
2799
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
2800
    gen_set_access_type(ACCESS_INT);                                          \
J
j_mayer 已提交
2801
    if (type == PPC_64B)                                                      \
A
aurel32 已提交
2802
        gen_addr_imm_index(EA, ctx, 0x03);                                    \
J
j_mayer 已提交
2803
    else                                                                      \
A
aurel32 已提交
2804
        gen_addr_imm_index(EA, ctx, 0);                                       \
2805
    gen_qemu_##ldop(cpu_gpr[rD(ctx->opcode)], EA, ctx->mem_idx);              \
A
aurel32 已提交
2806 2807
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2808 2809
}

2810 2811
#define GEN_LDUX(name, ldop, opc2, opc3, type)                                \
GEN_HANDLER(name##ux, 0x1F, opc2, opc3, 0x00000001, type)                     \
B
bellard 已提交
2812
{                                                                             \
A
aurel32 已提交
2813
    TCGv EA;                                                                  \
2814 2815
    if (unlikely(rA(ctx->opcode) == 0 ||                                      \
                 rA(ctx->opcode) == rD(ctx->opcode))) {                       \
2816
        GEN_EXCP_INVAL(ctx);                                                  \
2817
        return;                                                               \
2818
    }                                                                         \
2819
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
2820
    gen_set_access_type(ACCESS_INT);                                          \
A
aurel32 已提交
2821
    gen_addr_reg_index(EA, ctx);                                              \
2822
    gen_qemu_##ldop(cpu_gpr[rD(ctx->opcode)], EA, ctx->mem_idx);              \
A
aurel32 已提交
2823 2824
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2825 2826
}

2827 2828
#define GEN_LDX(name, ldop, opc2, opc3, type)                                 \
GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type)                      \
B
bellard 已提交
2829
{                                                                             \
2830
    TCGv EA = tcg_temp_new();                                                 \
A
aurel32 已提交
2831
    gen_set_access_type(ACCESS_INT);                                          \
A
aurel32 已提交
2832
    gen_addr_reg_index(EA, ctx);                                              \
2833
    gen_qemu_##ldop(cpu_gpr[rD(ctx->opcode)], EA, ctx->mem_idx);              \
A
aurel32 已提交
2834
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2835 2836
}

2837 2838 2839 2840 2841
#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 已提交
2842 2843

/* lbz lbzu lbzux lbzx */
2844
GEN_LDS(lbz, ld8u, 0x02, PPC_INTEGER);
B
bellard 已提交
2845
/* lha lhau lhaux lhax */
2846
GEN_LDS(lha, ld16s, 0x0A, PPC_INTEGER);
B
bellard 已提交
2847
/* lhz lhzu lhzux lhzx */
2848
GEN_LDS(lhz, ld16u, 0x08, PPC_INTEGER);
B
bellard 已提交
2849
/* lwz lwzu lwzux lwzx */
2850
GEN_LDS(lwz, ld32u, 0x00, PPC_INTEGER);
2851 2852
#if defined(TARGET_PPC64)
/* lwaux */
2853
GEN_LDUX(lwa, ld32s, 0x15, 0x0B, PPC_64B);
2854
/* lwax */
2855
GEN_LDX(lwa, ld32s, 0x15, 0x0A, PPC_64B);
2856
/* ldux */
2857
GEN_LDUX(ld, ld64, 0x15, 0x01, PPC_64B);
2858
/* ldx */
2859
GEN_LDX(ld, ld64, 0x15, 0x00, PPC_64B);
2860 2861
GEN_HANDLER(ld, 0x3A, 0xFF, 0xFF, 0x00000000, PPC_64B)
{
A
aurel32 已提交
2862
    TCGv EA;
2863 2864 2865
    if (Rc(ctx->opcode)) {
        if (unlikely(rA(ctx->opcode) == 0 ||
                     rA(ctx->opcode) == rD(ctx->opcode))) {
2866
            GEN_EXCP_INVAL(ctx);
2867 2868 2869
            return;
        }
    }
P
pbrook 已提交
2870
    EA = tcg_temp_new();
A
aurel32 已提交
2871
    gen_set_access_type(ACCESS_INT);
A
aurel32 已提交
2872
    gen_addr_imm_index(EA, ctx, 0x03);
2873 2874
    if (ctx->opcode & 0x02) {
        /* lwa (lwau is undefined) */
A
aurel32 已提交
2875
        gen_qemu_ld32s(cpu_gpr[rD(ctx->opcode)], EA, ctx->mem_idx);
2876 2877
    } else {
        /* ld - ldu */
A
aurel32 已提交
2878
        gen_qemu_ld64(cpu_gpr[rD(ctx->opcode)], EA, ctx->mem_idx);
2879 2880
    }
    if (Rc(ctx->opcode))
A
aurel32 已提交
2881 2882
        tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);
    tcg_temp_free(EA);
2883
}
2884 2885 2886 2887 2888 2889 2890
/* lq */
GEN_HANDLER(lq, 0x38, 0xFF, 0xFF, 0x00000000, PPC_64BX)
{
#if defined(CONFIG_USER_ONLY)
    GEN_EXCP_PRIVOPC(ctx);
#else
    int ra, rd;
A
aurel32 已提交
2891
    TCGv EA;
2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908

    /* Restore CPU state */
    if (unlikely(ctx->supervisor == 0)) {
        GEN_EXCP_PRIVOPC(ctx);
        return;
    }
    ra = rA(ctx->opcode);
    rd = rD(ctx->opcode);
    if (unlikely((rd & 1) || rd == ra)) {
        GEN_EXCP_INVAL(ctx);
        return;
    }
    if (unlikely(ctx->mem_idx & 1)) {
        /* Little-endian mode is not handled */
        GEN_EXCP(ctx, POWERPC_EXCP_ALIGN, POWERPC_EXCP_ALIGN_LE);
        return;
    }
P
pbrook 已提交
2909
    EA = tcg_temp_new();
A
aurel32 已提交
2910
    gen_set_access_type(ACCESS_INT);
A
aurel32 已提交
2911 2912 2913 2914 2915
    gen_addr_imm_index(EA, ctx, 0x0F);
    gen_qemu_ld64(cpu_gpr[rd], EA, ctx->mem_idx);
    tcg_gen_addi_tl(EA, EA, 8);
    gen_qemu_ld64(cpu_gpr[rd+1], EA, ctx->mem_idx);
    tcg_temp_free(EA);
2916 2917
#endif
}
2918
#endif
B
bellard 已提交
2919 2920

/***                              Integer store                            ***/
2921 2922
#define GEN_ST(name, stop, opc, type)                                         \
GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type)                          \
B
bellard 已提交
2923
{                                                                             \
2924
    TCGv EA = tcg_temp_new();                                                 \
A
aurel32 已提交
2925
    gen_set_access_type(ACCESS_INT);                                          \
A
aurel32 已提交
2926
    gen_addr_imm_index(EA, ctx, 0);                                           \
2927
    gen_qemu_##stop(cpu_gpr[rS(ctx->opcode)], EA, ctx->mem_idx);              \
A
aurel32 已提交
2928
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2929 2930
}

2931 2932
#define GEN_STU(name, stop, opc, type)                                        \
GEN_HANDLER(stop##u, opc, 0xFF, 0xFF, 0x00000000, type)                       \
B
bellard 已提交
2933
{                                                                             \
A
aurel32 已提交
2934
    TCGv EA;                                                                  \
2935
    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
2936
        GEN_EXCP_INVAL(ctx);                                                  \
2937
        return;                                                               \
2938
    }                                                                         \
2939
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
2940
    gen_set_access_type(ACCESS_INT);                                          \
J
j_mayer 已提交
2941
    if (type == PPC_64B)                                                      \
A
aurel32 已提交
2942
        gen_addr_imm_index(EA, ctx, 0x03);                                    \
J
j_mayer 已提交
2943
    else                                                                      \
A
aurel32 已提交
2944
        gen_addr_imm_index(EA, ctx, 0);                                       \
2945
    gen_qemu_##stop(cpu_gpr[rS(ctx->opcode)], EA, ctx->mem_idx);              \
A
aurel32 已提交
2946 2947
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2948 2949
}

2950 2951
#define GEN_STUX(name, stop, opc2, opc3, type)                                \
GEN_HANDLER(name##ux, 0x1F, opc2, opc3, 0x00000001, type)                     \
B
bellard 已提交
2952
{                                                                             \
A
aurel32 已提交
2953
    TCGv EA;                                                                  \
2954
    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
2955
        GEN_EXCP_INVAL(ctx);                                                  \
2956
        return;                                                               \
2957
    }                                                                         \
2958
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
2959
    gen_set_access_type(ACCESS_INT);                                          \
A
aurel32 已提交
2960
    gen_addr_reg_index(EA, ctx);                                              \
2961
    gen_qemu_##stop(cpu_gpr[rS(ctx->opcode)], EA, ctx->mem_idx);              \
A
aurel32 已提交
2962 2963
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2964 2965
}

2966 2967
#define GEN_STX(name, stop, opc2, opc3, type)                                 \
GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type)                      \
B
bellard 已提交
2968
{                                                                             \
2969
    TCGv EA = tcg_temp_new();                                                 \
A
aurel32 已提交
2970
    gen_set_access_type(ACCESS_INT);                                          \
A
aurel32 已提交
2971
    gen_addr_reg_index(EA, ctx);                                              \
2972
    gen_qemu_##stop(cpu_gpr[rS(ctx->opcode)], EA, ctx->mem_idx);              \
A
aurel32 已提交
2973
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2974 2975
}

2976 2977 2978 2979 2980
#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 已提交
2981 2982

/* stb stbu stbux stbx */
2983
GEN_STS(stb, st8, 0x06, PPC_INTEGER);
B
bellard 已提交
2984
/* sth sthu sthux sthx */
2985
GEN_STS(sth, st16, 0x0C, PPC_INTEGER);
B
bellard 已提交
2986
/* stw stwu stwux stwx */
2987
GEN_STS(stw, st32, 0x04, PPC_INTEGER);
2988
#if defined(TARGET_PPC64)
2989 2990
GEN_STUX(std, st64, 0x15, 0x05, PPC_64B);
GEN_STX(std, st64, 0x15, 0x04, PPC_64B);
2991
GEN_HANDLER(std, 0x3E, 0xFF, 0xFF, 0x00000000, PPC_64B)
2992
{
2993
    int rs;
A
aurel32 已提交
2994
    TCGv EA;
2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006

    rs = rS(ctx->opcode);
    if ((ctx->opcode & 0x3) == 0x2) {
#if defined(CONFIG_USER_ONLY)
        GEN_EXCP_PRIVOPC(ctx);
#else
        /* stq */
        if (unlikely(ctx->supervisor == 0)) {
            GEN_EXCP_PRIVOPC(ctx);
            return;
        }
        if (unlikely(rs & 1)) {
3007
            GEN_EXCP_INVAL(ctx);
3008 3009
            return;
        }
3010 3011 3012 3013 3014
        if (unlikely(ctx->mem_idx & 1)) {
            /* Little-endian mode is not handled */
            GEN_EXCP(ctx, POWERPC_EXCP_ALIGN, POWERPC_EXCP_ALIGN_LE);
            return;
        }
P
pbrook 已提交
3015
        EA = tcg_temp_new();
A
aurel32 已提交
3016
        gen_set_access_type(ACCESS_INT);
A
aurel32 已提交
3017 3018 3019 3020 3021
        gen_addr_imm_index(EA, ctx, 0x03);
        gen_qemu_st64(cpu_gpr[rs], EA, ctx->mem_idx);
        tcg_gen_addi_tl(EA, EA, 8);
        gen_qemu_st64(cpu_gpr[rs+1], EA, ctx->mem_idx);
        tcg_temp_free(EA);
3022 3023 3024 3025 3026 3027 3028 3029 3030
#endif
    } else {
        /* std / stdu */
        if (Rc(ctx->opcode)) {
            if (unlikely(rA(ctx->opcode) == 0)) {
                GEN_EXCP_INVAL(ctx);
                return;
            }
        }
P
pbrook 已提交
3031
        EA = tcg_temp_new();
A
aurel32 已提交
3032
        gen_set_access_type(ACCESS_INT);
A
aurel32 已提交
3033 3034
        gen_addr_imm_index(EA, ctx, 0x03);
        gen_qemu_st64(cpu_gpr[rs], EA, ctx->mem_idx);
3035
        if (Rc(ctx->opcode))
A
aurel32 已提交
3036 3037
            tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);
        tcg_temp_free(EA);
3038 3039 3040
    }
}
#endif
B
bellard 已提交
3041 3042
/***                Integer load and store with byte reverse               ***/
/* lhbrx */
A
aurel32 已提交
3043 3044
void always_inline gen_qemu_ld16ur(TCGv t0, TCGv t1, int flags)
{
P
pbrook 已提交
3045 3046 3047
    TCGv_i32 temp = tcg_temp_new_i32();
    gen_qemu_ld16u(t0, t1, flags);
    tcg_gen_trunc_tl_i32(temp, t0);
A
aurel32 已提交
3048 3049
    tcg_gen_bswap16_i32(temp, temp);
    tcg_gen_extu_i32_tl(t0, temp);
P
pbrook 已提交
3050
    tcg_temp_free_i32(temp);
A
aurel32 已提交
3051
}
3052
GEN_LDX(lhbr, ld16ur, 0x16, 0x18, PPC_INTEGER);
A
aurel32 已提交
3053

B
bellard 已提交
3054
/* lwbrx */
A
aurel32 已提交
3055 3056
void always_inline gen_qemu_ld32ur(TCGv t0, TCGv t1, int flags)
{
P
pbrook 已提交
3057 3058 3059
    TCGv_i32 temp = tcg_temp_new_i32();
    gen_qemu_ld32u(t0, t1, flags);
    tcg_gen_trunc_tl_i32(temp, t0);
A
aurel32 已提交
3060 3061
    tcg_gen_bswap_i32(temp, temp);
    tcg_gen_extu_i32_tl(t0, temp);
P
pbrook 已提交
3062
    tcg_temp_free_i32(temp);
A
aurel32 已提交
3063
}
3064
GEN_LDX(lwbr, ld32ur, 0x16, 0x10, PPC_INTEGER);
A
aurel32 已提交
3065

B
bellard 已提交
3066
/* sthbrx */
A
aurel32 已提交
3067 3068
void always_inline gen_qemu_st16r(TCGv t0, TCGv t1, int flags)
{
P
pbrook 已提交
3069 3070
    TCGv_i32 temp = tcg_temp_new_i32();
    TCGv t2 = tcg_temp_new();
A
aurel32 已提交
3071 3072 3073
    tcg_gen_trunc_tl_i32(temp, t0);
    tcg_gen_ext16u_i32(temp, temp);
    tcg_gen_bswap16_i32(temp, temp);
P
pbrook 已提交
3074 3075 3076 3077
    tcg_gen_extu_i32_tl(t2, temp);
    tcg_temp_free_i32(temp);
    gen_qemu_st16(t2, t1, flags);
    tcg_temp_free(t2);
A
aurel32 已提交
3078
}
3079
GEN_STX(sthbr, st16r, 0x16, 0x1C, PPC_INTEGER);
A
aurel32 已提交
3080

B
bellard 已提交
3081
/* stwbrx */
A
aurel32 已提交
3082 3083
void always_inline gen_qemu_st32r(TCGv t0, TCGv t1, int flags)
{
P
pbrook 已提交
3084 3085
    TCGv_i32 temp = tcg_temp_new_i32();
    TCGv t2 = tcg_temp_new();
A
aurel32 已提交
3086 3087
    tcg_gen_trunc_tl_i32(temp, t0);
    tcg_gen_bswap_i32(temp, temp);
P
pbrook 已提交
3088 3089
    tcg_gen_extu_i32_tl(t2, temp);
    tcg_temp_free_i32(temp);
3090
    gen_qemu_st32(t2, t1, flags);
P
pbrook 已提交
3091
    tcg_temp_free(t2);
A
aurel32 已提交
3092
}
3093
GEN_STX(stwbr, st32r, 0x16, 0x14, PPC_INTEGER);
B
bellard 已提交
3094 3095 3096 3097 3098

/***                    Integer load and store multiple                    ***/
/* lmw */
GEN_HANDLER(lmw, 0x2E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
3099 3100
    TCGv t0 = tcg_temp_new();
    TCGv_i32 t1 = tcg_const_i32(rD(ctx->opcode));
3101
    /* NIP cannot be restored if the memory exception comes from an helper */
3102
    gen_update_nip(ctx, ctx->nip - 4);
3103 3104 3105 3106
    gen_addr_imm_index(t0, ctx, 0);
    gen_helper_lmw(t0, t1);
    tcg_temp_free(t0);
    tcg_temp_free_i32(t1);
B
bellard 已提交
3107 3108 3109 3110 3111
}

/* stmw */
GEN_HANDLER(stmw, 0x2F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
3112 3113
    TCGv t0 = tcg_temp_new();
    TCGv_i32 t1 = tcg_const_i32(rS(ctx->opcode));
3114
    /* NIP cannot be restored if the memory exception comes from an helper */
3115
    gen_update_nip(ctx, ctx->nip - 4);
3116 3117 3118 3119
    gen_addr_imm_index(t0, ctx, 0);
    gen_helper_stmw(t0, t1);
    tcg_temp_free(t0);
    tcg_temp_free_i32(t1);
B
bellard 已提交
3120 3121 3122 3123
}

/***                    Integer load and store strings                     ***/
/* lswi */
3124
/* PowerPC32 specification says we must generate an exception if
3125 3126 3127 3128
 * 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...
 */
3129
GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_STRING)
B
bellard 已提交
3130
{
3131 3132
    TCGv t0;
    TCGv_i32 t1, t2;
B
bellard 已提交
3133 3134
    int nb = NB(ctx->opcode);
    int start = rD(ctx->opcode);
3135
    int ra = rA(ctx->opcode);
B
bellard 已提交
3136 3137 3138 3139 3140
    int nr;

    if (nb == 0)
        nb = 32;
    nr = nb / 4;
3141 3142 3143
    if (unlikely(((start + nr) > 32  &&
                  start <= ra && (start + nr - 32) > ra) ||
                 ((start + nr) <= 32 && start <= ra && (start + nr) > ra))) {
3144 3145
        GEN_EXCP(ctx, POWERPC_EXCP_PROGRAM,
                 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_LSWX);
3146
        return;
B
bellard 已提交
3147
    }
3148
    /* NIP cannot be restored if the memory exception comes from an helper */
3149
    gen_update_nip(ctx, ctx->nip - 4);
3150 3151 3152 3153 3154 3155 3156 3157
    t0 = tcg_temp_new();
    gen_addr_register(t0, ctx);
    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 已提交
3158 3159 3160
}

/* lswx */
3161
GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001, PPC_STRING)
B
bellard 已提交
3162
{
3163 3164 3165 3166
    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));
3167
    /* NIP cannot be restored if the memory exception comes from an helper */
3168
    gen_update_nip(ctx, ctx->nip - 4);
3169 3170 3171 3172 3173 3174
    gen_addr_reg_index(t0, ctx);
    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 已提交
3175 3176 3177
}

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

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

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

/* isync */
3220
GEN_HANDLER(isync, 0x13, 0x16, 0x04, 0x03FFF801, PPC_MEM)
B
bellard 已提交
3221
{
3222
    GEN_STOP(ctx);
B
bellard 已提交
3223 3224
}

3225
/* lwarx */
3226
GEN_HANDLER(lwarx, 0x1F, 0x14, 0x00, 0x00000001, PPC_RES)
B
bellard 已提交
3227
{
3228
    TCGv t0 = tcg_temp_local_new();
A
aurel32 已提交
3229
    gen_set_access_type(ACCESS_RES);
3230 3231 3232 3233 3234 3235 3236 3237 3238
    gen_addr_reg_index(t0, ctx);
    gen_check_align(ctx, t0, 0x03);
#if defined(TARGET_PPC64)
    if (!ctx->sf_mode)
        tcg_gen_ext32u_tl(t0, t0);
#endif
    gen_qemu_ld32u(cpu_gpr[rD(ctx->opcode)], t0, ctx->mem_idx);
    tcg_gen_mov_tl(cpu_reserve, t0);
    tcg_temp_free(t0);
B
bellard 已提交
3239 3240 3241
}

/* stwcx. */
3242
GEN_HANDLER2(stwcx_, "stwcx.", 0x1F, 0x16, 0x04, 0x00000000, PPC_RES)
B
bellard 已提交
3243
{
3244 3245
    int l1 = gen_new_label();
    TCGv t0 = tcg_temp_local_new();
A
aurel32 已提交
3246
    gen_set_access_type(ACCESS_RES);
3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261
    gen_addr_reg_index(t0, ctx);
    gen_check_align(ctx, t0, 0x03);
#if defined(TARGET_PPC64)
    if (!ctx->sf_mode)
        tcg_gen_ext32u_tl(t0, t0);
#endif
    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_brcond_tl(TCG_COND_NE, t0, cpu_reserve, l1);
    tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 1 << CRF_EQ);
    gen_qemu_st32(cpu_gpr[rS(ctx->opcode)], t0, ctx->mem_idx);
    gen_set_label(l1);
    tcg_gen_movi_tl(cpu_reserve, -1);
    tcg_temp_free(t0);
B
bellard 已提交
3262 3263
}

J
j_mayer 已提交
3264 3265
#if defined(TARGET_PPC64)
/* ldarx */
3266
GEN_HANDLER(ldarx, 0x1F, 0x14, 0x02, 0x00000001, PPC_64B)
J
j_mayer 已提交
3267
{
3268
    TCGv t0 = tcg_temp_local_new();
A
aurel32 已提交
3269
    gen_set_access_type(ACCESS_RES);
3270 3271 3272 3273 3274 3275 3276
    gen_addr_reg_index(t0, ctx);
    gen_check_align(ctx, t0, 0x07);
    if (!ctx->sf_mode)
        tcg_gen_ext32u_tl(t0, t0);
    gen_qemu_ld64(cpu_gpr[rD(ctx->opcode)], t0, ctx->mem_idx);
    tcg_gen_mov_tl(cpu_reserve, t0);
    tcg_temp_free(t0);
J
j_mayer 已提交
3277 3278 3279
}

/* stdcx. */
3280
GEN_HANDLER2(stdcx_, "stdcx.", 0x1F, 0x16, 0x06, 0x00000000, PPC_64B)
J
j_mayer 已提交
3281
{
3282 3283
    int l1 = gen_new_label();
    TCGv t0 = tcg_temp_local_new();
A
aurel32 已提交
3284
    gen_set_access_type(ACCESS_RES);
3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297
    gen_addr_reg_index(t0, ctx);
    gen_check_align(ctx, t0, 0x07);
    if (!ctx->sf_mode)
        tcg_gen_ext32u_tl(t0, t0);
    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_brcond_tl(TCG_COND_NE, t0, cpu_reserve, l1);
    tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 1 << CRF_EQ);
    gen_qemu_st64(cpu_gpr[rS(ctx->opcode)], t0, ctx->mem_idx);
    gen_set_label(l1);
    tcg_gen_movi_tl(cpu_reserve, -1);
    tcg_temp_free(t0);
J
j_mayer 已提交
3298 3299 3300
}
#endif /* defined(TARGET_PPC64) */

B
bellard 已提交
3301
/* sync */
3302
GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x039FF801, PPC_MEM_SYNC)
B
bellard 已提交
3303 3304 3305
{
}

3306 3307 3308
/* wait */
GEN_HANDLER(wait, 0x1F, 0x1E, 0x01, 0x03FFF801, PPC_WAIT)
{
3309 3310 3311
    TCGv_i32 t0 = tcg_temp_new_i32();
    tcg_gen_st_i32(t0, cpu_env, offsetof(CPUState, halted));
    tcg_temp_free_i32(t0);
3312
    /* Stop translation, as the CPU is supposed to sleep from now */
3313
    GEN_EXCP(ctx, EXCP_HLT, 1);
3314 3315
}

B
bellard 已提交
3316
/***                         Floating-point load                           ***/
3317 3318
#define GEN_LDF(name, ldop, opc, type)                                        \
GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type)                          \
B
bellard 已提交
3319
{                                                                             \
3320
    TCGv EA;                                                                  \
3321
    if (unlikely(!ctx->fpu_enabled)) {                                        \
3322
        GEN_EXCP_NO_FP(ctx);                                                  \
3323 3324
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
3325
    gen_set_access_type(ACCESS_FLOAT);                                        \
3326 3327 3328 3329
    EA = tcg_temp_new();                                                      \
    gen_addr_imm_index(EA, ctx, 0);                                           \
    gen_qemu_##ldop(cpu_fpr[rD(ctx->opcode)], EA, ctx->mem_idx);              \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
3330 3331
}

3332 3333
#define GEN_LDUF(name, ldop, opc, type)                                       \
GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type)                       \
B
bellard 已提交
3334
{                                                                             \
3335
    TCGv EA;                                                                  \
3336
    if (unlikely(!ctx->fpu_enabled)) {                                        \
3337
        GEN_EXCP_NO_FP(ctx);                                                  \
3338 3339
        return;                                                               \
    }                                                                         \
3340
    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
3341
        GEN_EXCP_INVAL(ctx);                                                  \
3342
        return;                                                               \
3343
    }                                                                         \
A
aurel32 已提交
3344
    gen_set_access_type(ACCESS_FLOAT);                                        \
3345 3346 3347 3348 3349
    EA = tcg_temp_new();                                                      \
    gen_addr_imm_index(EA, ctx, 0);                                           \
    gen_qemu_##ldop(cpu_fpr[rD(ctx->opcode)], EA, ctx->mem_idx);              \
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
3350 3351
}

3352 3353
#define GEN_LDUXF(name, ldop, opc, type)                                      \
GEN_HANDLER(name##ux, 0x1F, 0x17, opc, 0x00000001, type)                      \
B
bellard 已提交
3354
{                                                                             \
3355
    TCGv EA;                                                                  \
3356
    if (unlikely(!ctx->fpu_enabled)) {                                        \
3357
        GEN_EXCP_NO_FP(ctx);                                                  \
3358 3359
        return;                                                               \
    }                                                                         \
3360
    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
3361
        GEN_EXCP_INVAL(ctx);                                                  \
3362
        return;                                                               \
3363
    }                                                                         \
A
aurel32 已提交
3364
    gen_set_access_type(ACCESS_FLOAT);                                        \
3365 3366 3367 3368 3369
    EA = tcg_temp_new();                                                      \
    gen_addr_reg_index(EA, ctx);                                              \
    gen_qemu_##ldop(cpu_fpr[rD(ctx->opcode)], EA, ctx->mem_idx);              \
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
3370 3371
}

3372 3373
#define GEN_LDXF(name, ldop, opc2, opc3, type)                                \
GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type)                      \
B
bellard 已提交
3374
{                                                                             \
3375
    TCGv EA;                                                                  \
3376
    if (unlikely(!ctx->fpu_enabled)) {                                        \
3377
        GEN_EXCP_NO_FP(ctx);                                                  \
3378 3379
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
3380
    gen_set_access_type(ACCESS_FLOAT);                                        \
3381 3382 3383 3384
    EA = tcg_temp_new();                                                      \
    gen_addr_reg_index(EA, ctx);                                              \
    gen_qemu_##ldop(cpu_fpr[rD(ctx->opcode)], EA, ctx->mem_idx);              \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
3385 3386
}

3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402
#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)

static always_inline void gen_qemu_ld32fs(TCGv_i64 arg1, TCGv arg2, int flags)
{
    TCGv t0 = tcg_temp_new();
    TCGv_i32 t1 = tcg_temp_new_i32();
    gen_qemu_ld32u(t0, arg2, flags);
    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 已提交
3403

3404 3405 3406 3407
 /* lfd lfdu lfdux lfdx */
GEN_LDFS(lfd, ld64, 0x12, PPC_FLOAT);
 /* lfs lfsu lfsux lfsx */
GEN_LDFS(lfs, ld32fs, 0x10, PPC_FLOAT);
B
bellard 已提交
3408 3409

/***                         Floating-point store                          ***/
3410 3411
#define GEN_STF(name, stop, opc, type)                                        \
GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type)                          \
B
bellard 已提交
3412
{                                                                             \
3413
    TCGv EA;                                                                  \
3414
    if (unlikely(!ctx->fpu_enabled)) {                                        \
3415
        GEN_EXCP_NO_FP(ctx);                                                  \
3416 3417
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
3418
    gen_set_access_type(ACCESS_FLOAT);                                        \
3419 3420 3421 3422
    EA = tcg_temp_new();                                                      \
    gen_addr_imm_index(EA, ctx, 0);                                           \
    gen_qemu_##stop(cpu_fpr[rS(ctx->opcode)], EA, ctx->mem_idx);              \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
3423 3424
}

3425 3426
#define GEN_STUF(name, stop, opc, type)                                       \
GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type)                       \
B
bellard 已提交
3427
{                                                                             \
3428
    TCGv EA;                                                                  \
3429
    if (unlikely(!ctx->fpu_enabled)) {                                        \
3430
        GEN_EXCP_NO_FP(ctx);                                                  \
3431 3432
        return;                                                               \
    }                                                                         \
3433
    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
3434
        GEN_EXCP_INVAL(ctx);                                                  \
3435
        return;                                                               \
3436
    }                                                                         \
A
aurel32 已提交
3437
    gen_set_access_type(ACCESS_FLOAT);                                        \
3438 3439 3440 3441 3442
    EA = tcg_temp_new();                                                      \
    gen_addr_imm_index(EA, ctx, 0);                                           \
    gen_qemu_##stop(cpu_fpr[rS(ctx->opcode)], EA, ctx->mem_idx);              \
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
3443 3444
}

3445 3446
#define GEN_STUXF(name, stop, opc, type)                                      \
GEN_HANDLER(name##ux, 0x1F, 0x17, opc, 0x00000001, type)                      \
B
bellard 已提交
3447
{                                                                             \
3448
    TCGv EA;                                                                  \
3449
    if (unlikely(!ctx->fpu_enabled)) {                                        \
3450
        GEN_EXCP_NO_FP(ctx);                                                  \
3451 3452
        return;                                                               \
    }                                                                         \
3453
    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
3454
        GEN_EXCP_INVAL(ctx);                                                  \
3455
        return;                                                               \
3456
    }                                                                         \
A
aurel32 已提交
3457
    gen_set_access_type(ACCESS_FLOAT);                                        \
3458 3459 3460 3461 3462
    EA = tcg_temp_new();                                                      \
    gen_addr_reg_index(EA, ctx);                                              \
    gen_qemu_##stop(cpu_fpr[rS(ctx->opcode)], EA, ctx->mem_idx);              \
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
3463 3464
}

3465 3466
#define GEN_STXF(name, stop, opc2, opc3, type)                                \
GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type)                      \
B
bellard 已提交
3467
{                                                                             \
3468
    TCGv EA;                                                                  \
3469
    if (unlikely(!ctx->fpu_enabled)) {                                        \
3470
        GEN_EXCP_NO_FP(ctx);                                                  \
3471 3472
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
3473
    gen_set_access_type(ACCESS_FLOAT);                                        \
3474 3475 3476 3477
    EA = tcg_temp_new();                                                      \
    gen_addr_reg_index(EA, ctx);                                              \
    gen_qemu_##stop(cpu_fpr[rS(ctx->opcode)], EA, ctx->mem_idx);              \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
3478 3479
}

3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495
#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)

static always_inline void gen_qemu_st32fs(TCGv_i64 arg1, TCGv arg2, int flags)
{
    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);
    gen_qemu_st32(t1, arg2, flags);
    tcg_temp_free(t1);
}
B
bellard 已提交
3496 3497

/* stfd stfdu stfdux stfdx */
3498
GEN_STFS(stfd, st64, 0x16, PPC_FLOAT);
B
bellard 已提交
3499
/* stfs stfsu stfsux stfsx */
3500
GEN_STFS(stfs, st32fs, 0x14, PPC_FLOAT);
B
bellard 已提交
3501 3502

/* Optional: */
3503 3504 3505 3506 3507 3508 3509
static always_inline void gen_qemu_st32fiw(TCGv_i64 arg1, TCGv arg2, int flags)
{
    TCGv t0 = tcg_temp_new();
    tcg_gen_trunc_i64_tl(t0, arg1),
    gen_qemu_st32(t0, arg2, flags);
    tcg_temp_free(t0);
}
B
bellard 已提交
3510
/* stfiwx */
3511
GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX);
B
bellard 已提交
3512 3513

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

3548
static always_inline void gen_setlr (DisasContext *ctx, target_ulong nip)
3549 3550
{
#if defined(TARGET_PPC64)
3551 3552
    if (ctx->sf_mode == 0)
        tcg_gen_movi_tl(cpu_lr, (uint32_t)nip);
3553 3554
    else
#endif
3555
        tcg_gen_movi_tl(cpu_lr, nip);
3556 3557
}

B
bellard 已提交
3558 3559 3560
/* b ba bl bla */
GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
{
3561
    target_ulong li, target;
B
bellard 已提交
3562

3563
    ctx->exception = POWERPC_EXCP_BRANCH;
B
bellard 已提交
3564
    /* sign extend LI */
3565
#if defined(TARGET_PPC64)
3566 3567 3568
    if (ctx->sf_mode)
        li = ((int64_t)LI(ctx->opcode) << 38) >> 38;
    else
3569
#endif
3570
        li = ((int32_t)LI(ctx->opcode) << 6) >> 6;
3571
    if (likely(AA(ctx->opcode) == 0))
B
bellard 已提交
3572
        target = ctx->nip + li - 4;
B
bellard 已提交
3573
    else
3574
        target = li;
3575 3576
    if (LK(ctx->opcode))
        gen_setlr(ctx, ctx->nip);
3577
    gen_goto_tb(ctx, 0, target);
B
bellard 已提交
3578 3579
}

3580 3581 3582 3583
#define BCOND_IM  0
#define BCOND_LR  1
#define BCOND_CTR 2

3584
static always_inline void gen_bcond (DisasContext *ctx, int type)
3585 3586
{
    uint32_t bo = BO(ctx->opcode);
3587 3588
    int l1 = gen_new_label();
    TCGv target;
3589

3590
    ctx->exception = POWERPC_EXCP_BRANCH;
3591
    if (type == BCOND_LR || type == BCOND_CTR) {
P
pbrook 已提交
3592
        target = tcg_temp_local_new();
3593 3594 3595 3596
        if (type == BCOND_CTR)
            tcg_gen_mov_tl(target, cpu_ctr);
        else
            tcg_gen_mov_tl(target, cpu_lr);
3597
    }
3598 3599
    if (LK(ctx->opcode))
        gen_setlr(ctx, ctx->nip);
3600 3601 3602
    l1 = gen_new_label();
    if ((bo & 0x4) == 0) {
        /* Decrement and test CTR */
P
pbrook 已提交
3603
        TCGv temp = tcg_temp_new();
3604 3605 3606 3607 3608
        if (unlikely(type == BCOND_CTR)) {
            GEN_EXCP_INVAL(ctx);
            return;
        }
        tcg_gen_subi_tl(cpu_ctr, cpu_ctr, 1);
3609
#if defined(TARGET_PPC64)
3610 3611 3612
        if (!ctx->sf_mode)
            tcg_gen_ext32u_tl(temp, cpu_ctr);
        else
3613
#endif
3614 3615 3616 3617 3618
            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);
3619
        }
P
pbrook 已提交
3620
        tcg_temp_free(temp);
3621 3622 3623 3624 3625
    }
    if ((bo & 0x10) == 0) {
        /* Test CR */
        uint32_t bi = BI(ctx->opcode);
        uint32_t mask = 1 << (3 - (bi & 0x03));
P
pbrook 已提交
3626
        TCGv_i32 temp = tcg_temp_new_i32();
3627

3628
        if (bo & 0x8) {
3629 3630
            tcg_gen_andi_i32(temp, cpu_crf[bi >> 2], mask);
            tcg_gen_brcondi_i32(TCG_COND_EQ, temp, 0, l1);
3631
        } else {
3632 3633
            tcg_gen_andi_i32(temp, cpu_crf[bi >> 2], mask);
            tcg_gen_brcondi_i32(TCG_COND_NE, temp, 0, l1);
3634
        }
P
pbrook 已提交
3635
        tcg_temp_free_i32(temp);
3636
    }
3637
    if (type == BCOND_IM) {
3638 3639 3640 3641 3642 3643
        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 已提交
3644
        gen_set_label(l1);
3645
        gen_goto_tb(ctx, 1, ctx->nip);
3646
    } else {
3647
#if defined(TARGET_PPC64)
3648 3649 3650 3651 3652 3653 3654 3655 3656 3657
        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);
3658 3659
        else
#endif
3660
            tcg_gen_movi_tl(cpu_nip, ctx->nip);
B
bellard 已提交
3661
        tcg_gen_exit_tb(0);
J
j_mayer 已提交
3662
    }
3663 3664 3665
}

GEN_HANDLER(bc, 0x10, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
3666
{
3667 3668 3669 3670
    gen_bcond(ctx, BCOND_IM);
}

GEN_HANDLER(bcctr, 0x13, 0x10, 0x10, 0x00000000, PPC_FLOW)
3671
{
3672 3673 3674 3675
    gen_bcond(ctx, BCOND_CTR);
}

GEN_HANDLER(bclr, 0x13, 0x10, 0x00, 0x00000000, PPC_FLOW)
3676
{
3677 3678
    gen_bcond(ctx, BCOND_LR);
}
B
bellard 已提交
3679 3680

/***                      Condition register logical                       ***/
3681 3682
#define GEN_CRLOGIC(name, tcg_op, opc)                                        \
GEN_HANDLER(name, 0x13, 0x01, opc, 0x00000001, PPC_INTEGER)                   \
B
bellard 已提交
3683
{                                                                             \
3684 3685
    uint8_t bitmask;                                                          \
    int sh;                                                                   \
P
pbrook 已提交
3686
    TCGv_i32 t0, t1;                                                          \
3687
    sh = (crbD(ctx->opcode) & 0x03) - (crbA(ctx->opcode) & 0x03);             \
P
pbrook 已提交
3688
    t0 = tcg_temp_new_i32();                                                  \
3689
    if (sh > 0)                                                               \
3690
        tcg_gen_shri_i32(t0, cpu_crf[crbA(ctx->opcode) >> 2], sh);            \
3691
    else if (sh < 0)                                                          \
3692
        tcg_gen_shli_i32(t0, cpu_crf[crbA(ctx->opcode) >> 2], -sh);           \
3693
    else                                                                      \
3694
        tcg_gen_mov_i32(t0, cpu_crf[crbA(ctx->opcode) >> 2]);                 \
P
pbrook 已提交
3695
    t1 = tcg_temp_new_i32();                                                  \
3696 3697
    sh = (crbD(ctx->opcode) & 0x03) - (crbB(ctx->opcode) & 0x03);             \
    if (sh > 0)                                                               \
3698
        tcg_gen_shri_i32(t1, cpu_crf[crbB(ctx->opcode) >> 2], sh);            \
3699
    else if (sh < 0)                                                          \
3700
        tcg_gen_shli_i32(t1, cpu_crf[crbB(ctx->opcode) >> 2], -sh);           \
3701
    else                                                                      \
3702 3703
        tcg_gen_mov_i32(t1, cpu_crf[crbB(ctx->opcode) >> 2]);                 \
    tcg_op(t0, t0, t1);                                                       \
3704
    bitmask = 1 << (3 - (crbD(ctx->opcode) & 0x03));                          \
3705 3706 3707
    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 已提交
3708 3709
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
B
bellard 已提交
3710 3711 3712
}

/* crand */
3713
GEN_CRLOGIC(crand, tcg_gen_and_i32, 0x08);
B
bellard 已提交
3714
/* crandc */
3715
GEN_CRLOGIC(crandc, tcg_gen_andc_i32, 0x04);
B
bellard 已提交
3716
/* creqv */
3717
GEN_CRLOGIC(creqv, tcg_gen_eqv_i32, 0x09);
B
bellard 已提交
3718
/* crnand */
3719
GEN_CRLOGIC(crnand, tcg_gen_nand_i32, 0x07);
B
bellard 已提交
3720
/* crnor */
3721
GEN_CRLOGIC(crnor, tcg_gen_nor_i32, 0x01);
B
bellard 已提交
3722
/* cror */
3723
GEN_CRLOGIC(cror, tcg_gen_or_i32, 0x0E);
B
bellard 已提交
3724
/* crorc */
3725
GEN_CRLOGIC(crorc, tcg_gen_orc_i32, 0x0D);
B
bellard 已提交
3726
/* crxor */
3727
GEN_CRLOGIC(crxor, tcg_gen_xor_i32, 0x06);
B
bellard 已提交
3728 3729 3730
/* mcrf */
GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER)
{
A
aurel32 已提交
3731
    tcg_gen_mov_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfS(ctx->opcode)]);
B
bellard 已提交
3732 3733 3734 3735
}

/***                           System linkage                              ***/
/* rfi (supervisor only) */
3736
GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW)
B
bellard 已提交
3737
{
3738
#if defined(CONFIG_USER_ONLY)
3739
    GEN_EXCP_PRIVOPC(ctx);
3740 3741
#else
    /* Restore CPU state */
3742
    if (unlikely(!ctx->supervisor)) {
3743
        GEN_EXCP_PRIVOPC(ctx);
3744
        return;
3745
    }
3746
    gen_helper_rfi();
3747
    GEN_SYNC(ctx);
3748
#endif
B
bellard 已提交
3749 3750
}

J
j_mayer 已提交
3751
#if defined(TARGET_PPC64)
3752
GEN_HANDLER(rfid, 0x13, 0x12, 0x00, 0x03FF8001, PPC_64B)
J
j_mayer 已提交
3753 3754
{
#if defined(CONFIG_USER_ONLY)
3755
    GEN_EXCP_PRIVOPC(ctx);
J
j_mayer 已提交
3756 3757 3758
#else
    /* Restore CPU state */
    if (unlikely(!ctx->supervisor)) {
3759
        GEN_EXCP_PRIVOPC(ctx);
J
j_mayer 已提交
3760 3761
        return;
    }
3762
    gen_helper_rfid();
3763
    GEN_SYNC(ctx);
J
j_mayer 已提交
3764 3765 3766
#endif
}

J
j_mayer 已提交
3767
GEN_HANDLER(hrfid, 0x13, 0x12, 0x08, 0x03FF8001, PPC_64H)
3768 3769 3770 3771 3772 3773 3774 3775 3776
{
#if defined(CONFIG_USER_ONLY)
    GEN_EXCP_PRIVOPC(ctx);
#else
    /* Restore CPU state */
    if (unlikely(ctx->supervisor <= 1)) {
        GEN_EXCP_PRIVOPC(ctx);
        return;
    }
3777
    gen_helper_hrfid();
3778 3779 3780 3781 3782
    GEN_SYNC(ctx);
#endif
}
#endif

B
bellard 已提交
3783
/* sc */
3784 3785 3786 3787 3788
#if defined(CONFIG_USER_ONLY)
#define POWERPC_SYSCALL POWERPC_EXCP_SYSCALL_USER
#else
#define POWERPC_SYSCALL POWERPC_EXCP_SYSCALL
#endif
3789
GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFF01D, PPC_FLOW)
B
bellard 已提交
3790
{
3791 3792 3793
    uint32_t lev;

    lev = (ctx->opcode >> 5) & 0x7F;
3794
    GEN_EXCP(ctx, POWERPC_SYSCALL, lev);
B
bellard 已提交
3795 3796 3797 3798
}

/***                                Trap                                   ***/
/* tw */
3799
GEN_HANDLER(tw, 0x1F, 0x04, 0x00, 0x00000001, PPC_FLOW)
B
bellard 已提交
3800
{
3801
    TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
3802
    /* Update the nip since this might generate a trap exception */
3803
    gen_update_nip(ctx, ctx->nip);
3804 3805
    gen_helper_tw(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], t0);
    tcg_temp_free_i32(t0);
B
bellard 已提交
3806 3807 3808 3809 3810
}

/* twi */
GEN_HANDLER(twi, 0x03, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
{
3811 3812
    TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
    TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
3813 3814
    /* Update the nip since this might generate a trap exception */
    gen_update_nip(ctx, ctx->nip);
3815 3816 3817
    gen_helper_tw(cpu_gpr[rA(ctx->opcode)], t0, t1);
    tcg_temp_free(t0);
    tcg_temp_free_i32(t1);
B
bellard 已提交
3818 3819
}

3820 3821 3822 3823
#if defined(TARGET_PPC64)
/* td */
GEN_HANDLER(td, 0x1F, 0x04, 0x02, 0x00000001, PPC_64B)
{
3824
    TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
3825 3826
    /* Update the nip since this might generate a trap exception */
    gen_update_nip(ctx, ctx->nip);
3827 3828
    gen_helper_td(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], t0);
    tcg_temp_free_i32(t0);
3829 3830 3831 3832 3833
}

/* tdi */
GEN_HANDLER(tdi, 0x02, 0xFF, 0xFF, 0x00000000, PPC_64B)
{
3834 3835
    TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
    TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
3836 3837
    /* Update the nip since this might generate a trap exception */
    gen_update_nip(ctx, ctx->nip);
3838 3839 3840
    gen_helper_td(cpu_gpr[rA(ctx->opcode)], t0, t1);
    tcg_temp_free(t0);
    tcg_temp_free_i32(t1);
3841 3842 3843
}
#endif

B
bellard 已提交
3844 3845 3846 3847
/***                          Processor control                            ***/
/* mcrxr */
GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC)
{
A
aurel32 已提交
3848 3849
    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);
3850
    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_SO | 1 << XER_OV | 1 << XER_CA));
B
bellard 已提交
3851 3852 3853
}

/* mfcr */
3854
GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x00000801, PPC_MISC)
B
bellard 已提交
3855
{
3856
    uint32_t crm, crn;
3857

3858 3859 3860 3861
    if (likely(ctx->opcode & 0x00100000)) {
        crm = CRM(ctx->opcode);
        if (likely((crm ^ (crm - 1)) == 0)) {
            crn = ffs(crm);
3862
            tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], cpu_crf[7 - crn]);
3863
        }
3864
    } else {
P
pbrook 已提交
3865
        gen_helper_load_cr(cpu_gpr[rD(ctx->opcode)]);
3866
    }
B
bellard 已提交
3867 3868 3869 3870 3871
}

/* mfmsr */
GEN_HANDLER(mfmsr, 0x1F, 0x13, 0x02, 0x001FF801, PPC_MISC)
{
3872
#if defined(CONFIG_USER_ONLY)
3873
    GEN_EXCP_PRIVREG(ctx);
3874
#else
3875
    if (unlikely(!ctx->supervisor)) {
3876
        GEN_EXCP_PRIVREG(ctx);
3877
        return;
3878
    }
A
aurel32 已提交
3879
    gen_op_load_msr();
A
aurel32 已提交
3880
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
3881
#endif
B
bellard 已提交
3882 3883
}

J
j_mayer 已提交
3884
#if 1
3885
#define SPR_NOACCESS ((void *)(-1UL))
3886 3887 3888 3889 3890 3891 3892 3893 3894
#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 已提交
3895
/* mfspr */
3896
static always_inline void gen_op_mfspr (DisasContext *ctx)
B
bellard 已提交
3897
{
3898
    void (*read_cb)(void *opaque, int sprn);
B
bellard 已提交
3899 3900
    uint32_t sprn = SPR(ctx->opcode);

3901
#if !defined(CONFIG_USER_ONLY)
3902 3903
    if (ctx->supervisor == 2)
        read_cb = ctx->spr_cb[sprn].hea_read;
3904
    else if (ctx->supervisor)
3905 3906
        read_cb = ctx->spr_cb[sprn].oea_read;
    else
3907
#endif
3908
        read_cb = ctx->spr_cb[sprn].uea_read;
3909 3910
    if (likely(read_cb != NULL)) {
        if (likely(read_cb != SPR_NOACCESS)) {
3911
            (*read_cb)(ctx, sprn);
A
aurel32 已提交
3912
            tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
3913 3914
        } else {
            /* Privilege exception */
3915 3916 3917 3918 3919 3920
            /* 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) {
                if (loglevel != 0) {
3921
                    fprintf(logfile, "Trying to read privileged spr %d %03x at "
J
j_mayer 已提交
3922
                            ADDRX "\n", sprn, sprn, ctx->nip);
3923
                }
J
j_mayer 已提交
3924 3925
                printf("Trying to read privileged spr %d %03x at " ADDRX "\n",
                       sprn, sprn, ctx->nip);
3926
            }
3927
            GEN_EXCP_PRIVREG(ctx);
B
bellard 已提交
3928
        }
3929 3930
    } else {
        /* Not defined */
J
j_mayer 已提交
3931
        if (loglevel != 0) {
J
j_mayer 已提交
3932 3933
            fprintf(logfile, "Trying to read invalid spr %d %03x at "
                    ADDRX "\n", sprn, sprn, ctx->nip);
3934
        }
J
j_mayer 已提交
3935 3936
        printf("Trying to read invalid spr %d %03x at " ADDRX "\n",
               sprn, sprn, ctx->nip);
3937 3938
        GEN_EXCP(ctx, POWERPC_EXCP_PROGRAM,
                 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_SPR);
B
bellard 已提交
3939 3940 3941
    }
}

3942
GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC)
B
bellard 已提交
3943
{
3944
    gen_op_mfspr(ctx);
3945
}
3946 3947

/* mftb */
3948
GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_MFTB)
3949 3950
{
    gen_op_mfspr(ctx);
B
bellard 已提交
3951 3952 3953
}

/* mtcrf */
3954
GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00000801, PPC_MISC)
B
bellard 已提交
3955
{
3956
    uint32_t crm, crn;
3957

3958 3959
    crm = CRM(ctx->opcode);
    if (likely((ctx->opcode & 0x00100000) || (crm ^ (crm - 1)) == 0)) {
P
pbrook 已提交
3960
        TCGv_i32 temp = tcg_temp_new_i32();
3961
        crn = ffs(crm);
P
pbrook 已提交
3962 3963
        tcg_gen_trunc_tl_i32(temp, cpu_gpr[rS(ctx->opcode)]);
        tcg_gen_shri_i32(cpu_crf[7 - crn], temp, crn * 4);
3964
        tcg_gen_andi_i32(cpu_crf[7 - crn], cpu_crf[7 - crn], 0xf);
P
pbrook 已提交
3965
        tcg_temp_free_i32(temp);
3966
    } else {
P
pbrook 已提交
3967 3968 3969
        TCGv_i32 temp = tcg_const_i32(crm);
        gen_helper_store_cr(cpu_gpr[rS(ctx->opcode)], temp);
        tcg_temp_free_i32(temp);
3970
    }
B
bellard 已提交
3971 3972 3973
}

/* mtmsr */
J
j_mayer 已提交
3974
#if defined(TARGET_PPC64)
3975
GEN_HANDLER(mtmsrd, 0x1F, 0x12, 0x05, 0x001EF801, PPC_64B)
J
j_mayer 已提交
3976 3977
{
#if defined(CONFIG_USER_ONLY)
3978
    GEN_EXCP_PRIVREG(ctx);
J
j_mayer 已提交
3979 3980
#else
    if (unlikely(!ctx->supervisor)) {
3981
        GEN_EXCP_PRIVREG(ctx);
J
j_mayer 已提交
3982 3983
        return;
    }
A
aurel32 已提交
3984
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
3985 3986 3987 3988
    if (ctx->opcode & 0x00010000) {
        /* Special form that does not need any synchronisation */
        gen_op_update_riee();
    } else {
3989 3990 3991 3992
        /* 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
         */
3993
        gen_update_nip(ctx, ctx->nip);
A
aurel32 已提交
3994
        gen_op_store_msr();
3995 3996
        /* Must stop the translation as machine state (may have) changed */
        /* Note that mtmsr is not always defined as context-synchronizing */
3997
        ctx->exception = POWERPC_EXCP_STOP;
3998
    }
J
j_mayer 已提交
3999 4000 4001 4002
#endif
}
#endif

B
bellard 已提交
4003 4004
GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC)
{
4005
#if defined(CONFIG_USER_ONLY)
4006
    GEN_EXCP_PRIVREG(ctx);
4007
#else
4008
    if (unlikely(!ctx->supervisor)) {
4009
        GEN_EXCP_PRIVREG(ctx);
4010
        return;
4011
    }
A
aurel32 已提交
4012
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
4013 4014 4015 4016
    if (ctx->opcode & 0x00010000) {
        /* Special form that does not need any synchronisation */
        gen_op_update_riee();
    } else {
4017 4018 4019 4020
        /* 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
         */
4021
        gen_update_nip(ctx, ctx->nip);
4022
#if defined(TARGET_PPC64)
4023
        if (!ctx->sf_mode)
A
aurel32 已提交
4024
            gen_op_store_msr_32();
4025
        else
4026
#endif
A
aurel32 已提交
4027
            gen_op_store_msr();
4028 4029
        /* Must stop the translation as machine state (may have) changed */
        /* Note that mtmsrd is not always defined as context-synchronizing */
4030
        ctx->exception = POWERPC_EXCP_STOP;
4031
    }
4032
#endif
B
bellard 已提交
4033 4034 4035 4036 4037
}

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

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

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

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

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

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

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

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

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

/* icbi */
4165
GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_CACHE_ICBI)
B
bellard 已提交
4166
{
4167
    TCGv t0 = tcg_temp_new();
4168 4169
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
4170 4171 4172
    gen_addr_reg_index(t0, ctx);
    gen_helper_icbi(t0);
    tcg_temp_free(t0);
B
bellard 已提交
4173 4174 4175 4176
}

/* Optional: */
/* dcba */
4177
GEN_HANDLER(dcba, 0x1F, 0x16, 0x17, 0x03E00001, PPC_CACHE_DCBA)
B
bellard 已提交
4178
{
4179 4180 4181 4182
    /* interpreted as no-op */
    /* XXX: specification say this is treated as a store by the MMU
     *      but does not generate any exception
     */
B
bellard 已提交
4183 4184 4185 4186 4187 4188 4189
}

/***                    Segment register manipulation                      ***/
/* Supervisor only: */
/* mfsr */
GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT)
{
4190
#if defined(CONFIG_USER_ONLY)
4191
    GEN_EXCP_PRIVREG(ctx);
4192
#else
4193
    if (unlikely(!ctx->supervisor)) {
4194
        GEN_EXCP_PRIVREG(ctx);
4195
        return;
4196
    }
4197
    tcg_gen_movi_tl(cpu_T[1], SR(ctx->opcode));
4198
    gen_op_load_sr();
A
aurel32 已提交
4199
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4200
#endif
B
bellard 已提交
4201 4202 4203
}

/* mfsrin */
4204
GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT)
B
bellard 已提交
4205
{
4206
#if defined(CONFIG_USER_ONLY)
4207
    GEN_EXCP_PRIVREG(ctx);
4208
#else
4209
    if (unlikely(!ctx->supervisor)) {
4210
        GEN_EXCP_PRIVREG(ctx);
4211
        return;
4212
    }
A
aurel32 已提交
4213
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4214 4215
    gen_op_srli_T1(28);
    gen_op_load_sr();
A
aurel32 已提交
4216
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4217
#endif
B
bellard 已提交
4218 4219 4220
}

/* mtsr */
B
bellard 已提交
4221
GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT)
B
bellard 已提交
4222
{
4223
#if defined(CONFIG_USER_ONLY)
4224
    GEN_EXCP_PRIVREG(ctx);
4225
#else
4226
    if (unlikely(!ctx->supervisor)) {
4227
        GEN_EXCP_PRIVREG(ctx);
4228
        return;
4229
    }
A
aurel32 已提交
4230
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
4231
    tcg_gen_movi_tl(cpu_T[1], SR(ctx->opcode));
4232
    gen_op_store_sr();
4233
#endif
B
bellard 已提交
4234 4235 4236
}

/* mtsrin */
4237
GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT)
B
bellard 已提交
4238
{
4239
#if defined(CONFIG_USER_ONLY)
4240
    GEN_EXCP_PRIVREG(ctx);
4241
#else
4242
    if (unlikely(!ctx->supervisor)) {
4243
        GEN_EXCP_PRIVREG(ctx);
4244
        return;
4245
    }
A
aurel32 已提交
4246 4247
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4248 4249
    gen_op_srli_T1(28);
    gen_op_store_sr();
4250
#endif
B
bellard 已提交
4251 4252
}

4253 4254 4255
#if defined(TARGET_PPC64)
/* Specific implementation for PowerPC 64 "bridge" emulation using SLB */
/* mfsr */
4256
GEN_HANDLER2(mfsr_64b, "mfsr", 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT_64B)
4257 4258 4259 4260 4261 4262 4263 4264
{
#if defined(CONFIG_USER_ONLY)
    GEN_EXCP_PRIVREG(ctx);
#else
    if (unlikely(!ctx->supervisor)) {
        GEN_EXCP_PRIVREG(ctx);
        return;
    }
4265
    tcg_gen_movi_tl(cpu_T[1], SR(ctx->opcode));
4266
    gen_op_load_slb();
A
aurel32 已提交
4267
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4268 4269 4270 4271
#endif
}

/* mfsrin */
4272 4273
GEN_HANDLER2(mfsrin_64b, "mfsrin", 0x1F, 0x13, 0x14, 0x001F0001,
             PPC_SEGMENT_64B)
4274 4275 4276 4277 4278 4279 4280 4281
{
#if defined(CONFIG_USER_ONLY)
    GEN_EXCP_PRIVREG(ctx);
#else
    if (unlikely(!ctx->supervisor)) {
        GEN_EXCP_PRIVREG(ctx);
        return;
    }
A
aurel32 已提交
4282
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4283 4284
    gen_op_srli_T1(28);
    gen_op_load_slb();
A
aurel32 已提交
4285
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4286 4287 4288 4289
#endif
}

/* mtsr */
4290
GEN_HANDLER2(mtsr_64b, "mtsr", 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT_64B)
4291 4292 4293 4294 4295 4296 4297 4298
{
#if defined(CONFIG_USER_ONLY)
    GEN_EXCP_PRIVREG(ctx);
#else
    if (unlikely(!ctx->supervisor)) {
        GEN_EXCP_PRIVREG(ctx);
        return;
    }
A
aurel32 已提交
4299
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
4300
    tcg_gen_movi_tl(cpu_T[1], SR(ctx->opcode));
4301 4302 4303 4304 4305
    gen_op_store_slb();
#endif
}

/* mtsrin */
4306 4307
GEN_HANDLER2(mtsrin_64b, "mtsrin", 0x1F, 0x12, 0x07, 0x001F0001,
             PPC_SEGMENT_64B)
4308 4309 4310 4311 4312 4313 4314 4315
{
#if defined(CONFIG_USER_ONLY)
    GEN_EXCP_PRIVREG(ctx);
#else
    if (unlikely(!ctx->supervisor)) {
        GEN_EXCP_PRIVREG(ctx);
        return;
    }
A
aurel32 已提交
4316 4317
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4318 4319 4320 4321 4322 4323
    gen_op_srli_T1(28);
    gen_op_store_slb();
#endif
}
#endif /* defined(TARGET_PPC64) */

B
bellard 已提交
4324 4325 4326
/***                      Lookaside buffer management                      ***/
/* Optional & supervisor only: */
/* tlbia */
4327
GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA)
B
bellard 已提交
4328
{
4329
#if defined(CONFIG_USER_ONLY)
4330
    GEN_EXCP_PRIVOPC(ctx);
4331
#else
4332
    if (unlikely(!ctx->supervisor)) {
4333
        GEN_EXCP_PRIVOPC(ctx);
4334
        return;
4335 4336 4337
    }
    gen_op_tlbia();
#endif
B
bellard 已提交
4338 4339 4340
}

/* tlbie */
4341
GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM_TLBIE)
B
bellard 已提交
4342
{
4343
#if defined(CONFIG_USER_ONLY)
4344
    GEN_EXCP_PRIVOPC(ctx);
4345
#else
4346
    if (unlikely(!ctx->supervisor)) {
4347
        GEN_EXCP_PRIVOPC(ctx);
4348
        return;
4349
    }
A
aurel32 已提交
4350
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rB(ctx->opcode)]);
4351 4352 4353 4354 4355 4356
#if defined(TARGET_PPC64)
    if (ctx->sf_mode)
        gen_op_tlbie_64();
    else
#endif
        gen_op_tlbie();
4357
#endif
B
bellard 已提交
4358 4359 4360
}

/* tlbsync */
4361
GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM_TLBSYNC)
B
bellard 已提交
4362
{
4363
#if defined(CONFIG_USER_ONLY)
4364
    GEN_EXCP_PRIVOPC(ctx);
4365
#else
4366
    if (unlikely(!ctx->supervisor)) {
4367
        GEN_EXCP_PRIVOPC(ctx);
4368
        return;
4369 4370 4371 4372
    }
    /* This has no effect: it should ensure that all previous
     * tlbie have completed
     */
4373
    GEN_STOP(ctx);
4374
#endif
B
bellard 已提交
4375 4376
}

J
j_mayer 已提交
4377 4378 4379 4380 4381
#if defined(TARGET_PPC64)
/* slbia */
GEN_HANDLER(slbia, 0x1F, 0x12, 0x0F, 0x03FFFC01, PPC_SLBI)
{
#if defined(CONFIG_USER_ONLY)
4382
    GEN_EXCP_PRIVOPC(ctx);
J
j_mayer 已提交
4383 4384
#else
    if (unlikely(!ctx->supervisor)) {
4385
        GEN_EXCP_PRIVOPC(ctx);
J
j_mayer 已提交
4386 4387 4388 4389 4390 4391 4392 4393 4394 4395
        return;
    }
    gen_op_slbia();
#endif
}

/* slbie */
GEN_HANDLER(slbie, 0x1F, 0x12, 0x0D, 0x03FF0001, PPC_SLBI)
{
#if defined(CONFIG_USER_ONLY)
4396
    GEN_EXCP_PRIVOPC(ctx);
J
j_mayer 已提交
4397 4398
#else
    if (unlikely(!ctx->supervisor)) {
4399
        GEN_EXCP_PRIVOPC(ctx);
J
j_mayer 已提交
4400 4401
        return;
    }
A
aurel32 已提交
4402
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rB(ctx->opcode)]);
J
j_mayer 已提交
4403 4404 4405 4406 4407
    gen_op_slbie();
#endif
}
#endif

B
bellard 已提交
4408 4409
/***                              External control                         ***/
/* Optional: */
4410
/* eciwx */
B
bellard 已提交
4411 4412
GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN)
{
4413 4414
    /* Should check EAR[E] ! */
    TCGv t0 = tcg_temp_new();
A
aurel32 已提交
4415
    gen_set_access_type(ACCESS_RES);
4416 4417 4418 4419
    gen_addr_reg_index(t0, ctx);
    gen_check_align(ctx, t0, 0x03);
    gen_qemu_ld32u(cpu_gpr[rD(ctx->opcode)], t0, ctx->mem_idx);
    tcg_temp_free(t0);
4420 4421 4422 4423 4424
}

/* ecowx */
GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN)
{
4425 4426 4427 4428 4429 4430 4431
    /* Should check EAR[E] ! */
    TCGv t0 = tcg_temp_new();
    gen_set_access_type(ACCESS_RES);
    gen_addr_reg_index(t0, ctx);
    gen_check_align(ctx, t0, 0x03);
    gen_qemu_st32(cpu_gpr[rD(ctx->opcode)], t0, ctx->mem_idx);
    tcg_temp_free(t0);
4432 4433 4434 4435 4436 4437
}

/* PowerPC 601 specific instructions */
/* abs - abs. */
GEN_HANDLER(abs, 0x1F, 0x08, 0x0B, 0x0000F800, PPC_POWER_BR)
{
A
aurel32 已提交
4438
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
4439
    gen_op_POWER_abs();
A
aurel32 已提交
4440
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4441
    if (unlikely(Rc(ctx->opcode) != 0))
4442
        gen_set_Rc0(ctx, cpu_T[0]);
4443 4444 4445 4446 4447
}

/* abso - abso. */
GEN_HANDLER(abso, 0x1F, 0x08, 0x1B, 0x0000F800, PPC_POWER_BR)
{
A
aurel32 已提交
4448
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
4449
    gen_op_POWER_abso();
A
aurel32 已提交
4450
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4451
    if (unlikely(Rc(ctx->opcode) != 0))
4452
        gen_set_Rc0(ctx, cpu_T[0]);
4453 4454 4455
}

/* clcs */
4456
GEN_HANDLER(clcs, 0x1F, 0x10, 0x13, 0x0000F800, PPC_POWER_BR)
4457
{
A
aurel32 已提交
4458
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
4459
    gen_op_POWER_clcs();
4460
    /* Rc=1 sets CR0 to an undefined state */
A
aurel32 已提交
4461
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4462 4463 4464 4465 4466
}

/* div - div. */
GEN_HANDLER(div, 0x1F, 0x0B, 0x0A, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4467 4468
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4469
    gen_op_POWER_div();
A
aurel32 已提交
4470
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4471
    if (unlikely(Rc(ctx->opcode) != 0))
4472
        gen_set_Rc0(ctx, cpu_T[0]);
4473 4474 4475 4476 4477
}

/* divo - divo. */
GEN_HANDLER(divo, 0x1F, 0x0B, 0x1A, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4478 4479
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4480
    gen_op_POWER_divo();
A
aurel32 已提交
4481
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4482
    if (unlikely(Rc(ctx->opcode) != 0))
4483
        gen_set_Rc0(ctx, cpu_T[0]);
4484 4485 4486 4487 4488
}

/* divs - divs. */
GEN_HANDLER(divs, 0x1F, 0x0B, 0x0B, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4489 4490
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4491
    gen_op_POWER_divs();
A
aurel32 已提交
4492
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4493
    if (unlikely(Rc(ctx->opcode) != 0))
4494
        gen_set_Rc0(ctx, cpu_T[0]);
4495 4496 4497 4498 4499
}

/* divso - divso. */
GEN_HANDLER(divso, 0x1F, 0x0B, 0x1B, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4500 4501
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4502
    gen_op_POWER_divso();
A
aurel32 已提交
4503
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4504
    if (unlikely(Rc(ctx->opcode) != 0))
4505
        gen_set_Rc0(ctx, cpu_T[0]);
4506 4507 4508 4509 4510
}

/* doz - doz. */
GEN_HANDLER(doz, 0x1F, 0x08, 0x08, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4511 4512
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4513
    gen_op_POWER_doz();
A
aurel32 已提交
4514
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4515
    if (unlikely(Rc(ctx->opcode) != 0))
4516
        gen_set_Rc0(ctx, cpu_T[0]);
4517 4518 4519 4520 4521
}

/* dozo - dozo. */
GEN_HANDLER(dozo, 0x1F, 0x08, 0x18, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4522 4523
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4524
    gen_op_POWER_dozo();
A
aurel32 已提交
4525
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4526
    if (unlikely(Rc(ctx->opcode) != 0))
4527
        gen_set_Rc0(ctx, cpu_T[0]);
4528 4529 4530 4531 4532
}

/* dozi */
GEN_HANDLER(dozi, 0x09, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4533
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
4534
    tcg_gen_movi_tl(cpu_T[1], SIMM(ctx->opcode));
4535
    gen_op_POWER_doz();
A
aurel32 已提交
4536
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4537 4538 4539 4540 4541
}

/* lscbx - lscbx. */
GEN_HANDLER(lscbx, 0x1F, 0x15, 0x08, 0x00000000, PPC_POWER_BR)
{
4542 4543 4544 4545
    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));
4546

4547
    gen_addr_reg_index(t0, ctx);
4548
    /* NIP cannot be restored if the memory exception comes from an helper */
4549
    gen_update_nip(ctx, ctx->nip - 4);
4550 4551 4552 4553
    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 已提交
4554
    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~0x7F);
4555
    tcg_gen_or_tl(cpu_xer, cpu_xer, t0);
4556
    if (unlikely(Rc(ctx->opcode) != 0))
4557 4558
        gen_set_Rc0(ctx, t0);
    tcg_temp_free(t0);
4559 4560 4561 4562 4563
}

/* maskg - maskg. */
GEN_HANDLER(maskg, 0x1F, 0x1D, 0x00, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4564 4565
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4566
    gen_op_POWER_maskg();
A
aurel32 已提交
4567
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4568
    if (unlikely(Rc(ctx->opcode) != 0))
4569
        gen_set_Rc0(ctx, cpu_T[0]);
4570 4571 4572 4573 4574
}

/* maskir - maskir. */
GEN_HANDLER(maskir, 0x1F, 0x1D, 0x10, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4575 4576 4577
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[2], cpu_gpr[rB(ctx->opcode)]);
4578
    gen_op_POWER_maskir();
A
aurel32 已提交
4579
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4580
    if (unlikely(Rc(ctx->opcode) != 0))
4581
        gen_set_Rc0(ctx, cpu_T[0]);
4582 4583 4584 4585 4586
}

/* mul - mul. */
GEN_HANDLER(mul, 0x1F, 0x0B, 0x03, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4587 4588
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4589
    gen_op_POWER_mul();
A
aurel32 已提交
4590
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4591
    if (unlikely(Rc(ctx->opcode) != 0))
4592
        gen_set_Rc0(ctx, cpu_T[0]);
4593 4594 4595 4596 4597
}

/* mulo - mulo. */
GEN_HANDLER(mulo, 0x1F, 0x0B, 0x13, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4598 4599
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4600
    gen_op_POWER_mulo();
A
aurel32 已提交
4601
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4602
    if (unlikely(Rc(ctx->opcode) != 0))
4603
        gen_set_Rc0(ctx, cpu_T[0]);
4604 4605 4606 4607 4608
}

/* nabs - nabs. */
GEN_HANDLER(nabs, 0x1F, 0x08, 0x0F, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4609
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
4610
    gen_op_POWER_nabs();
A
aurel32 已提交
4611
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4612
    if (unlikely(Rc(ctx->opcode) != 0))
4613
        gen_set_Rc0(ctx, cpu_T[0]);
4614 4615 4616 4617 4618
}

/* nabso - nabso. */
GEN_HANDLER(nabso, 0x1F, 0x08, 0x1F, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4619
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
4620
    gen_op_POWER_nabso();
A
aurel32 已提交
4621
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4622
    if (unlikely(Rc(ctx->opcode) != 0))
4623
        gen_set_Rc0(ctx, cpu_T[0]);
4624 4625 4626 4627 4628
}

/* rlmi - rlmi. */
GEN_HANDLER(rlmi, 0x16, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR)
{
4629 4630 4631 4632 4633 4634 4635 4636 4637
    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);
4638
    if (unlikely(Rc(ctx->opcode) != 0))
4639
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4640 4641 4642 4643 4644
}

/* rrib - rrib. */
GEN_HANDLER(rrib, 0x1F, 0x19, 0x10, 0x00000000, PPC_POWER_BR)
{
4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655
    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);
4656
    if (unlikely(Rc(ctx->opcode) != 0))
4657
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4658 4659 4660 4661 4662
}

/* sle - sle. */
GEN_HANDLER(sle, 0x1F, 0x19, 0x04, 0x00000000, PPC_POWER_BR)
{
4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673
    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);
4674
    if (unlikely(Rc(ctx->opcode) != 0))
4675
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4676 4677 4678 4679 4680
}

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

/* sliq - sliq. */
GEN_HANDLER(sliq, 0x1F, 0x18, 0x05, 0x00000000, PPC_POWER_BR)
{
4703 4704 4705 4706 4707 4708 4709 4710 4711 4712
    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);
4713
    if (unlikely(Rc(ctx->opcode) != 0))
4714
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4715 4716 4717 4718 4719
}

/* slliq - slliq. */
GEN_HANDLER(slliq, 0x1F, 0x18, 0x07, 0x00000000, PPC_POWER_BR)
{
4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730
    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);
4731
    if (unlikely(Rc(ctx->opcode) != 0))
4732
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4733 4734 4735 4736 4737
}

/* sllq - sllq. */
GEN_HANDLER(sllq, 0x1F, 0x18, 0x06, 0x00000000, PPC_POWER_BR)
{
4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759
    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);
4760
    if (unlikely(Rc(ctx->opcode) != 0))
4761
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4762 4763 4764 4765 4766
}

/* slq - slq. */
GEN_HANDLER(slq, 0x1F, 0x18, 0x04, 0x00000000, PPC_POWER_BR)
{
4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782
    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);
4783
    if (unlikely(Rc(ctx->opcode) != 0))
4784
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4785 4786
}

4787
/* sraiq - sraiq. */
4788 4789
GEN_HANDLER(sraiq, 0x1F, 0x18, 0x1D, 0x00000000, PPC_POWER_BR)
{
4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805
    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);
4806
    if (unlikely(Rc(ctx->opcode) != 0))
4807
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4808 4809 4810 4811 4812
}

/* sraq - sraq. */
GEN_HANDLER(sraq, 0x1F, 0x18, 0x1C, 0x00000000, PPC_POWER_BR)
{
4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838
    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);
4839
    if (unlikely(Rc(ctx->opcode) != 0))
4840
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4841 4842 4843 4844 4845
}

/* sre - sre. */
GEN_HANDLER(sre, 0x1F, 0x19, 0x14, 0x00000000, PPC_POWER_BR)
{
4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856
    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);
4857
    if (unlikely(Rc(ctx->opcode) != 0))
4858
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4859 4860 4861 4862 4863
}

/* srea - srea. */
GEN_HANDLER(srea, 0x1F, 0x19, 0x1C, 0x00000000, PPC_POWER_BR)
{
4864 4865 4866 4867 4868 4869 4870 4871
    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);
4872
    if (unlikely(Rc(ctx->opcode) != 0))
4873
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4874 4875 4876 4877 4878
}

/* sreq */
GEN_HANDLER(sreq, 0x1F, 0x19, 0x16, 0x00000000, PPC_POWER_BR)
{
4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893
    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);
4894
    if (unlikely(Rc(ctx->opcode) != 0))
4895
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4896 4897 4898 4899 4900
}

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

/* srliq */
GEN_HANDLER(srliq, 0x1F, 0x18, 0x17, 0x00000000, PPC_POWER_BR)
{
4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928
    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);
4929
    if (unlikely(Rc(ctx->opcode) != 0))
4930
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4931 4932 4933 4934 4935
}

/* srlq */
GEN_HANDLER(srlq, 0x1F, 0x18, 0x16, 0x00000000, PPC_POWER_BR)
{
4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958
    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);
4959
    if (unlikely(Rc(ctx->opcode) != 0))
4960
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4961 4962 4963 4964 4965
}

/* srq */
GEN_HANDLER(srq, 0x1F, 0x18, 0x14, 0x00000000, PPC_POWER_BR)
{
4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981
    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);
4982
    if (unlikely(Rc(ctx->opcode) != 0))
4983
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4984 4985 4986 4987 4988 4989 4990
}

/* PowerPC 602 specific instructions */
/* dsa  */
GEN_HANDLER(dsa, 0x1F, 0x14, 0x13, 0x03FFF801, PPC_602_SPEC)
{
    /* XXX: TODO */
4991
    GEN_EXCP_INVAL(ctx);
4992 4993 4994 4995 4996 4997
}

/* esa */
GEN_HANDLER(esa, 0x1F, 0x14, 0x12, 0x03FFF801, PPC_602_SPEC)
{
    /* XXX: TODO */
4998
    GEN_EXCP_INVAL(ctx);
4999 5000 5001 5002 5003 5004
}

/* mfrom */
GEN_HANDLER(mfrom, 0x1F, 0x09, 0x08, 0x03E0F801, PPC_602_SPEC)
{
#if defined(CONFIG_USER_ONLY)
5005
    GEN_EXCP_PRIVOPC(ctx);
5006 5007
#else
    if (unlikely(!ctx->supervisor)) {
5008
        GEN_EXCP_PRIVOPC(ctx);
5009 5010
        return;
    }
5011
    gen_helper_602_mfrom(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
5012 5013 5014 5015 5016
#endif
}

/* 602 - 603 - G2 TLB management */
/* tlbld */
5017
GEN_HANDLER2(tlbld_6xx, "tlbld", 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB)
5018 5019
{
#if defined(CONFIG_USER_ONLY)
5020
    GEN_EXCP_PRIVOPC(ctx);
5021 5022
#else
    if (unlikely(!ctx->supervisor)) {
5023
        GEN_EXCP_PRIVOPC(ctx);
5024 5025
        return;
    }
5026
    gen_helper_load_6xx_tlbd(cpu_gpr[rB(ctx->opcode)]);
5027 5028 5029 5030
#endif
}

/* tlbli */
5031
GEN_HANDLER2(tlbli_6xx, "tlbli", 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB)
5032 5033
{
#if defined(CONFIG_USER_ONLY)
5034
    GEN_EXCP_PRIVOPC(ctx);
5035 5036
#else
    if (unlikely(!ctx->supervisor)) {
5037
        GEN_EXCP_PRIVOPC(ctx);
5038 5039
        return;
    }
5040
    gen_helper_load_6xx_tlbi(cpu_gpr[rB(ctx->opcode)]);
5041 5042 5043
#endif
}

5044 5045
/* 74xx TLB management */
/* tlbld */
5046
GEN_HANDLER2(tlbld_74xx, "tlbld", 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_74xx_TLB)
5047 5048 5049 5050 5051 5052 5053 5054
{
#if defined(CONFIG_USER_ONLY)
    GEN_EXCP_PRIVOPC(ctx);
#else
    if (unlikely(!ctx->supervisor)) {
        GEN_EXCP_PRIVOPC(ctx);
        return;
    }
5055
    gen_helper_load_74xx_tlbd(cpu_gpr[rB(ctx->opcode)]);
5056 5057 5058 5059
#endif
}

/* tlbli */
5060
GEN_HANDLER2(tlbli_74xx, "tlbli", 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_74xx_TLB)
5061 5062 5063 5064 5065 5066 5067 5068
{
#if defined(CONFIG_USER_ONLY)
    GEN_EXCP_PRIVOPC(ctx);
#else
    if (unlikely(!ctx->supervisor)) {
        GEN_EXCP_PRIVOPC(ctx);
        return;
    }
5069
    gen_helper_load_74xx_tlbi(cpu_gpr[rB(ctx->opcode)]);
5070 5071 5072
#endif
}

5073 5074 5075 5076 5077 5078 5079 5080 5081 5082
/* 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 已提交
5083
    /* Cache line invalidate: privileged and treated as no-op */
5084
#if defined(CONFIG_USER_ONLY)
5085
    GEN_EXCP_PRIVOPC(ctx);
5086 5087
#else
    if (unlikely(!ctx->supervisor)) {
5088
        GEN_EXCP_PRIVOPC(ctx);
5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102
        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)
5103
    GEN_EXCP_PRIVOPC(ctx);
5104 5105
#else
    if (unlikely(!ctx->supervisor)) {
5106
        GEN_EXCP_PRIVOPC(ctx);
5107 5108 5109 5110 5111
        return;
    }
    int ra = rA(ctx->opcode);
    int rd = rD(ctx->opcode);

5112
    gen_addr_reg_index(cpu_T[0], ctx);
5113
    gen_op_POWER_mfsri();
A
aurel32 已提交
5114
    tcg_gen_mov_tl(cpu_gpr[rd], cpu_T[0]);
5115
    if (ra != 0 && ra != rd)
A
aurel32 已提交
5116
        tcg_gen_mov_tl(cpu_gpr[ra], cpu_T[1]);
5117 5118 5119 5120 5121 5122
#endif
}

GEN_HANDLER(rac, 0x1F, 0x12, 0x19, 0x00000001, PPC_POWER)
{
#if defined(CONFIG_USER_ONLY)
5123
    GEN_EXCP_PRIVOPC(ctx);
5124 5125
#else
    if (unlikely(!ctx->supervisor)) {
5126
        GEN_EXCP_PRIVOPC(ctx);
5127 5128
        return;
    }
5129
    gen_addr_reg_index(cpu_T[0], ctx);
5130
    gen_op_POWER_rac();
A
aurel32 已提交
5131
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
5132 5133 5134 5135 5136 5137
#endif
}

GEN_HANDLER(rfsvc, 0x13, 0x12, 0x02, 0x03FFF0001, PPC_POWER)
{
#if defined(CONFIG_USER_ONLY)
5138
    GEN_EXCP_PRIVOPC(ctx);
5139 5140
#else
    if (unlikely(!ctx->supervisor)) {
5141
        GEN_EXCP_PRIVOPC(ctx);
5142 5143
        return;
    }
5144
    gen_helper_rfsvc();
5145
    GEN_SYNC(ctx);
5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156
#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)
{
5157 5158 5159 5160 5161 5162 5163
    int rd = rD(ctx->opcode);
    TCGv t0 = tcg_temp_new();
    gen_addr_imm_index(t0, ctx, 0);
    gen_qemu_ld64(cpu_fpr[rd], t0, ctx->mem_idx);
    tcg_gen_addi_tl(t0, t0, 8);
    gen_qemu_ld64(cpu_fpr[(rd + 1) % 32], t0, ctx->mem_idx);
    tcg_temp_free(t0);
5164 5165 5166 5167 5168 5169
}

/* lfqu */
GEN_HANDLER(lfqu, 0x39, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
{
    int ra = rA(ctx->opcode);
5170 5171 5172 5173 5174 5175 5176
    int rd = rD(ctx->opcode);
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    gen_addr_imm_index(t0, ctx, 0);
    gen_qemu_ld64(cpu_fpr[rd], t0, ctx->mem_idx);
    tcg_gen_addi_tl(t1, t0, 8);
    gen_qemu_ld64(cpu_fpr[(rd + 1) % 32], t1, ctx->mem_idx);
5177
    if (ra != 0)
5178 5179 5180
        tcg_gen_mov_tl(cpu_gpr[ra], t0);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
5181 5182 5183 5184 5185 5186
}

/* lfqux */
GEN_HANDLER(lfqux, 0x1F, 0x17, 0x19, 0x00000001, PPC_POWER2)
{
    int ra = rA(ctx->opcode);
5187 5188 5189 5190 5191 5192 5193
    int rd = rD(ctx->opcode);
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    gen_addr_reg_index(t0, ctx);
    gen_qemu_ld64(cpu_fpr[rd], t0, ctx->mem_idx);
    tcg_gen_addi_tl(t1, t0, 8);
    gen_qemu_ld64(cpu_fpr[(rd + 1) % 32], t1, ctx->mem_idx);
5194
    if (ra != 0)
5195 5196 5197
        tcg_gen_mov_tl(cpu_gpr[ra], t0);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
5198 5199 5200 5201 5202
}

/* lfqx */
GEN_HANDLER(lfqx, 0x1F, 0x17, 0x18, 0x00000001, PPC_POWER2)
{
5203 5204 5205 5206 5207 5208 5209
    int rd = rD(ctx->opcode);
    TCGv t0 = tcg_temp_new();
    gen_addr_reg_index(t0, ctx);
    gen_qemu_ld64(cpu_fpr[rd], t0, ctx->mem_idx);
    tcg_gen_addi_tl(t0, t0, 8);
    gen_qemu_ld64(cpu_fpr[(rd + 1) % 32], t0, ctx->mem_idx);
    tcg_temp_free(t0);
5210 5211 5212 5213 5214
}

/* stfq */
GEN_HANDLER(stfq, 0x3C, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
{
5215 5216 5217 5218 5219 5220 5221
    int rd = rD(ctx->opcode);
    TCGv t0 = tcg_temp_new();
    gen_addr_imm_index(t0, ctx, 0);
    gen_qemu_st64(cpu_fpr[rd], t0, ctx->mem_idx);
    tcg_gen_addi_tl(t0, t0, 8);
    gen_qemu_st64(cpu_fpr[(rd + 1) % 32], t0, ctx->mem_idx);
    tcg_temp_free(t0);
5222 5223 5224 5225 5226 5227
}

/* stfqu */
GEN_HANDLER(stfqu, 0x3D, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
{
    int ra = rA(ctx->opcode);
5228 5229 5230 5231 5232 5233 5234
    int rd = rD(ctx->opcode);
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    gen_addr_imm_index(t0, ctx, 0);
    gen_qemu_st64(cpu_fpr[rd], t0, ctx->mem_idx);
    tcg_gen_addi_tl(t1, t0, 8);
    gen_qemu_st64(cpu_fpr[(rd + 1) % 32], t1, ctx->mem_idx);
5235
    if (ra != 0)
5236 5237 5238
        tcg_gen_mov_tl(cpu_gpr[ra], t0);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
5239 5240 5241 5242 5243 5244
}

/* stfqux */
GEN_HANDLER(stfqux, 0x1F, 0x17, 0x1D, 0x00000001, PPC_POWER2)
{
    int ra = rA(ctx->opcode);
5245 5246 5247 5248 5249 5250 5251
    int rd = rD(ctx->opcode);
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    gen_addr_reg_index(t0, ctx);
    gen_qemu_st64(cpu_fpr[rd], t0, ctx->mem_idx);
    tcg_gen_addi_tl(t1, t0, 8);
    gen_qemu_st64(cpu_fpr[(rd + 1) % 32], t1, ctx->mem_idx);
5252
    if (ra != 0)
5253 5254 5255
        tcg_gen_mov_tl(cpu_gpr[ra], t0);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
5256 5257 5258 5259 5260
}

/* stfqx */
GEN_HANDLER(stfqx, 0x1F, 0x17, 0x1C, 0x00000001, PPC_POWER2)
{
5261 5262 5263 5264 5265 5266 5267
    int rd = rD(ctx->opcode);
    TCGv t0 = tcg_temp_new();
    gen_addr_reg_index(t0, ctx);
    gen_qemu_st64(cpu_fpr[rd], t0, ctx->mem_idx);
    tcg_gen_addi_tl(t0, t0, 8);
    gen_qemu_st64(cpu_fpr[(rd + 1) % 32], t0, ctx->mem_idx);
    tcg_temp_free(t0);
5268 5269 5270
}

/* BookE specific instructions */
5271
/* XXX: not implemented on 440 ? */
5272
GEN_HANDLER(mfapidi, 0x1F, 0x13, 0x08, 0x0000F801, PPC_MFAPIDI)
5273 5274
{
    /* XXX: TODO */
5275
    GEN_EXCP_INVAL(ctx);
5276 5277
}

5278
/* XXX: not implemented on 440 ? */
5279
GEN_HANDLER(tlbiva, 0x1F, 0x12, 0x18, 0x03FFF801, PPC_TLBIVA)
5280 5281
{
#if defined(CONFIG_USER_ONLY)
5282
    GEN_EXCP_PRIVOPC(ctx);
5283 5284
#else
    if (unlikely(!ctx->supervisor)) {
5285
        GEN_EXCP_PRIVOPC(ctx);
5286 5287
        return;
    }
5288
    gen_addr_reg_index(cpu_T[0], ctx);
5289
    /* Use the same micro-ops as for tlbie */
5290 5291 5292 5293 5294 5295
#if defined(TARGET_PPC64)
    if (ctx->sf_mode)
        gen_op_tlbie_64();
    else
#endif
        gen_op_tlbie();
5296 5297 5298 5299
#endif
}

/* All 405 MAC instructions are translated here */
5300 5301 5302
static always_inline void gen_405_mulladd_insn (DisasContext *ctx,
                                                int opc2, int opc3,
                                                int ra, int rb, int rt, int Rc)
5303
{
5304 5305
    TCGv t0, t1;

P
pbrook 已提交
5306 5307
    t0 = tcg_temp_local_new();
    t1 = tcg_temp_local_new();
5308

5309 5310 5311 5312 5313 5314 5315
    switch (opc3 & 0x0D) {
    case 0x05:
        /* macchw    - macchw.    - macchwo   - macchwo.   */
        /* macchws   - macchws.   - macchwso  - macchwso.  */
        /* nmacchw   - nmacchw.   - nmacchwo  - nmacchwo.  */
        /* nmacchws  - nmacchws.  - nmacchwso - nmacchwso. */
        /* mulchw - mulchw. */
5316 5317 5318
        tcg_gen_ext16s_tl(t0, cpu_gpr[ra]);
        tcg_gen_sari_tl(t1, cpu_gpr[rb], 16);
        tcg_gen_ext16s_tl(t1, t1);
5319 5320 5321 5322 5323
        break;
    case 0x04:
        /* macchwu   - macchwu.   - macchwuo  - macchwuo.  */
        /* macchwsu  - macchwsu.  - macchwsuo - macchwsuo. */
        /* mulchwu - mulchwu. */
5324 5325 5326
        tcg_gen_ext16u_tl(t0, cpu_gpr[ra]);
        tcg_gen_shri_tl(t1, cpu_gpr[rb], 16);
        tcg_gen_ext16u_tl(t1, t1);
5327 5328 5329 5330 5331 5332 5333
        break;
    case 0x01:
        /* machhw    - machhw.    - machhwo   - machhwo.   */
        /* machhws   - machhws.   - machhwso  - machhwso.  */
        /* nmachhw   - nmachhw.   - nmachhwo  - nmachhwo.  */
        /* nmachhws  - nmachhws.  - nmachhwso - nmachhwso. */
        /* mulhhw - mulhhw. */
5334 5335 5336 5337
        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);
5338 5339 5340 5341 5342
        break;
    case 0x00:
        /* machhwu   - machhwu.   - machhwuo  - machhwuo.  */
        /* machhwsu  - machhwsu.  - machhwsuo - machhwsuo. */
        /* mulhhwu - mulhhwu. */
5343 5344 5345 5346
        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);
5347 5348 5349 5350 5351 5352 5353
        break;
    case 0x0D:
        /* maclhw    - maclhw.    - maclhwo   - maclhwo.   */
        /* maclhws   - maclhws.   - maclhwso  - maclhwso.  */
        /* nmaclhw   - nmaclhw.   - nmaclhwo  - nmaclhwo.  */
        /* nmaclhws  - nmaclhws.  - nmaclhwso - nmaclhwso. */
        /* mullhw - mullhw. */
5354 5355
        tcg_gen_ext16s_tl(t0, cpu_gpr[ra]);
        tcg_gen_ext16s_tl(t1, cpu_gpr[rb]);
5356 5357 5358 5359 5360
        break;
    case 0x0C:
        /* maclhwu   - maclhwu.   - maclhwuo  - maclhwuo.  */
        /* maclhwsu  - maclhwsu.  - maclhwsuo - maclhwsuo. */
        /* mullhwu - mullhwu. */
5361 5362
        tcg_gen_ext16u_tl(t0, cpu_gpr[ra]);
        tcg_gen_ext16u_tl(t1, cpu_gpr[rb]);
5363 5364 5365
        break;
    }
    if (opc2 & 0x04) {
5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389
        /* (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 已提交
5390
                if (opc3 & 0x02) {
5391 5392 5393 5394 5395 5396 5397
                    /* 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 已提交
5398
                if (opc3 & 0x02) {
5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411
                    /* 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);
5412
    }
5413 5414
    tcg_temp_free(t0);
    tcg_temp_free(t1);
5415 5416
    if (unlikely(Rc) != 0) {
        /* Update Rc0 */
5417
        gen_set_Rc0(ctx, cpu_gpr[rt]);
5418 5419 5420
    }
}

5421 5422
#define GEN_MAC_HANDLER(name, opc2, opc3)                                     \
GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_405_MAC)                  \
5423 5424 5425 5426 5427 5428
{                                                                             \
    gen_405_mulladd_insn(ctx, opc2, opc3, rA(ctx->opcode), rB(ctx->opcode),   \
                         rD(ctx->opcode), Rc(ctx->opcode));                   \
}

/* macchw    - macchw.    */
5429
GEN_MAC_HANDLER(macchw, 0x0C, 0x05);
5430
/* macchwo   - macchwo.   */
5431
GEN_MAC_HANDLER(macchwo, 0x0C, 0x15);
5432
/* macchws   - macchws.   */
5433
GEN_MAC_HANDLER(macchws, 0x0C, 0x07);
5434
/* macchwso  - macchwso.  */
5435
GEN_MAC_HANDLER(macchwso, 0x0C, 0x17);
5436
/* macchwsu  - macchwsu.  */
5437
GEN_MAC_HANDLER(macchwsu, 0x0C, 0x06);
5438
/* macchwsuo - macchwsuo. */
5439
GEN_MAC_HANDLER(macchwsuo, 0x0C, 0x16);
5440
/* macchwu   - macchwu.   */
5441
GEN_MAC_HANDLER(macchwu, 0x0C, 0x04);
5442
/* macchwuo  - macchwuo.  */
5443
GEN_MAC_HANDLER(macchwuo, 0x0C, 0x14);
5444
/* machhw    - machhw.    */
5445
GEN_MAC_HANDLER(machhw, 0x0C, 0x01);
5446
/* machhwo   - machhwo.   */
5447
GEN_MAC_HANDLER(machhwo, 0x0C, 0x11);
5448
/* machhws   - machhws.   */
5449
GEN_MAC_HANDLER(machhws, 0x0C, 0x03);
5450
/* machhwso  - machhwso.  */
5451
GEN_MAC_HANDLER(machhwso, 0x0C, 0x13);
5452
/* machhwsu  - machhwsu.  */
5453
GEN_MAC_HANDLER(machhwsu, 0x0C, 0x02);
5454
/* machhwsuo - machhwsuo. */
5455
GEN_MAC_HANDLER(machhwsuo, 0x0C, 0x12);
5456
/* machhwu   - machhwu.   */
5457
GEN_MAC_HANDLER(machhwu, 0x0C, 0x00);
5458
/* machhwuo  - machhwuo.  */
5459
GEN_MAC_HANDLER(machhwuo, 0x0C, 0x10);
5460
/* maclhw    - maclhw.    */
5461
GEN_MAC_HANDLER(maclhw, 0x0C, 0x0D);
5462
/* maclhwo   - maclhwo.   */
5463
GEN_MAC_HANDLER(maclhwo, 0x0C, 0x1D);
5464
/* maclhws   - maclhws.   */
5465
GEN_MAC_HANDLER(maclhws, 0x0C, 0x0F);
5466
/* maclhwso  - maclhwso.  */
5467
GEN_MAC_HANDLER(maclhwso, 0x0C, 0x1F);
5468
/* maclhwu   - maclhwu.   */
5469
GEN_MAC_HANDLER(maclhwu, 0x0C, 0x0C);
5470
/* maclhwuo  - maclhwuo.  */
5471
GEN_MAC_HANDLER(maclhwuo, 0x0C, 0x1C);
5472
/* maclhwsu  - maclhwsu.  */
5473
GEN_MAC_HANDLER(maclhwsu, 0x0C, 0x0E);
5474
/* maclhwsuo - maclhwsuo. */
5475
GEN_MAC_HANDLER(maclhwsuo, 0x0C, 0x1E);
5476
/* nmacchw   - nmacchw.   */
5477
GEN_MAC_HANDLER(nmacchw, 0x0E, 0x05);
5478
/* nmacchwo  - nmacchwo.  */
5479
GEN_MAC_HANDLER(nmacchwo, 0x0E, 0x15);
5480
/* nmacchws  - nmacchws.  */
5481
GEN_MAC_HANDLER(nmacchws, 0x0E, 0x07);
5482
/* nmacchwso - nmacchwso. */
5483
GEN_MAC_HANDLER(nmacchwso, 0x0E, 0x17);
5484
/* nmachhw   - nmachhw.   */
5485
GEN_MAC_HANDLER(nmachhw, 0x0E, 0x01);
5486
/* nmachhwo  - nmachhwo.  */
5487
GEN_MAC_HANDLER(nmachhwo, 0x0E, 0x11);
5488
/* nmachhws  - nmachhws.  */
5489
GEN_MAC_HANDLER(nmachhws, 0x0E, 0x03);
5490
/* nmachhwso - nmachhwso. */
5491
GEN_MAC_HANDLER(nmachhwso, 0x0E, 0x13);
5492
/* nmaclhw   - nmaclhw.   */
5493
GEN_MAC_HANDLER(nmaclhw, 0x0E, 0x0D);
5494
/* nmaclhwo  - nmaclhwo.  */
5495
GEN_MAC_HANDLER(nmaclhwo, 0x0E, 0x1D);
5496
/* nmaclhws  - nmaclhws.  */
5497
GEN_MAC_HANDLER(nmaclhws, 0x0E, 0x0F);
5498
/* nmaclhwso - nmaclhwso. */
5499
GEN_MAC_HANDLER(nmaclhwso, 0x0E, 0x1F);
5500 5501

/* mulchw  - mulchw.  */
5502
GEN_MAC_HANDLER(mulchw, 0x08, 0x05);
5503
/* mulchwu - mulchwu. */
5504
GEN_MAC_HANDLER(mulchwu, 0x08, 0x04);
5505
/* mulhhw  - mulhhw.  */
5506
GEN_MAC_HANDLER(mulhhw, 0x08, 0x01);
5507
/* mulhhwu - mulhhwu. */
5508
GEN_MAC_HANDLER(mulhhwu, 0x08, 0x00);
5509
/* mullhw  - mullhw.  */
5510
GEN_MAC_HANDLER(mullhw, 0x08, 0x0D);
5511
/* mullhwu - mullhwu. */
5512
GEN_MAC_HANDLER(mullhwu, 0x08, 0x0C);
5513 5514

/* mfdcr */
5515
GEN_HANDLER(mfdcr, 0x1F, 0x03, 0x0A, 0x00000001, PPC_DCR)
5516 5517
{
#if defined(CONFIG_USER_ONLY)
5518
    GEN_EXCP_PRIVREG(ctx);
5519 5520 5521 5522
#else
    uint32_t dcrn = SPR(ctx->opcode);

    if (unlikely(!ctx->supervisor)) {
5523
        GEN_EXCP_PRIVREG(ctx);
5524 5525
        return;
    }
5526
    tcg_gen_movi_tl(cpu_T[0], dcrn);
5527
    gen_op_load_dcr();
A
aurel32 已提交
5528
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
5529 5530 5531 5532
#endif
}

/* mtdcr */
5533
GEN_HANDLER(mtdcr, 0x1F, 0x03, 0x0E, 0x00000001, PPC_DCR)
5534 5535
{
#if defined(CONFIG_USER_ONLY)
5536
    GEN_EXCP_PRIVREG(ctx);
5537 5538 5539 5540
#else
    uint32_t dcrn = SPR(ctx->opcode);

    if (unlikely(!ctx->supervisor)) {
5541
        GEN_EXCP_PRIVREG(ctx);
5542 5543
        return;
    }
5544
    tcg_gen_movi_tl(cpu_T[0], dcrn);
A
aurel32 已提交
5545
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]);
5546 5547 5548 5549 5550
    gen_op_store_dcr();
#endif
}

/* mfdcrx */
5551
/* XXX: not implemented on 440 ? */
5552
GEN_HANDLER(mfdcrx, 0x1F, 0x03, 0x08, 0x00000000, PPC_DCRX)
5553 5554
{
#if defined(CONFIG_USER_ONLY)
5555
    GEN_EXCP_PRIVREG(ctx);
5556 5557
#else
    if (unlikely(!ctx->supervisor)) {
5558
        GEN_EXCP_PRIVREG(ctx);
5559 5560
        return;
    }
A
aurel32 已提交
5561
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
5562
    gen_op_load_dcr();
A
aurel32 已提交
5563
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
5564
    /* Note: Rc update flag set leads to undefined state of Rc0 */
5565 5566 5567 5568
#endif
}

/* mtdcrx */
5569
/* XXX: not implemented on 440 ? */
5570
GEN_HANDLER(mtdcrx, 0x1F, 0x03, 0x0C, 0x00000000, PPC_DCRX)
5571 5572
{
#if defined(CONFIG_USER_ONLY)
5573
    GEN_EXCP_PRIVREG(ctx);
5574 5575
#else
    if (unlikely(!ctx->supervisor)) {
5576
        GEN_EXCP_PRIVREG(ctx);
5577 5578
        return;
    }
A
aurel32 已提交
5579 5580
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]);
5581
    gen_op_store_dcr();
5582
    /* Note: Rc update flag set leads to undefined state of Rc0 */
5583 5584 5585
#endif
}

5586 5587 5588
/* mfdcrux (PPC 460) : user-mode access to DCR */
GEN_HANDLER(mfdcrux, 0x1F, 0x03, 0x09, 0x00000000, PPC_DCRUX)
{
A
aurel32 已提交
5589
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
5590
    gen_op_load_dcr();
A
aurel32 已提交
5591
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
5592 5593 5594 5595 5596 5597
    /* 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)
{
A
aurel32 已提交
5598 5599
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]);
5600 5601 5602 5603
    gen_op_store_dcr();
    /* Note: Rc update flag set leads to undefined state of Rc0 */
}

5604 5605 5606 5607
/* dccci */
GEN_HANDLER(dccci, 0x1F, 0x06, 0x0E, 0x03E00001, PPC_4xx_COMMON)
{
#if defined(CONFIG_USER_ONLY)
5608
    GEN_EXCP_PRIVOPC(ctx);
5609 5610
#else
    if (unlikely(!ctx->supervisor)) {
5611
        GEN_EXCP_PRIVOPC(ctx);
5612 5613 5614 5615 5616 5617 5618 5619 5620 5621
        return;
    }
    /* interpreted as no-op */
#endif
}

/* dcread */
GEN_HANDLER(dcread, 0x1F, 0x06, 0x0F, 0x00000001, PPC_4xx_COMMON)
{
#if defined(CONFIG_USER_ONLY)
5622
    GEN_EXCP_PRIVOPC(ctx);
5623
#else
A
aurel32 已提交
5624
    TCGv EA, val;
5625
    if (unlikely(!ctx->supervisor)) {
5626
        GEN_EXCP_PRIVOPC(ctx);
5627 5628
        return;
    }
P
pbrook 已提交
5629
    EA = tcg_temp_new();
A
aurel32 已提交
5630
    gen_set_access_type(ACCESS_CACHE);
A
aurel32 已提交
5631
    gen_addr_reg_index(EA, ctx);
P
pbrook 已提交
5632
    val = tcg_temp_new();
A
aurel32 已提交
5633 5634 5635 5636
    gen_qemu_ld32u(val, EA, ctx->mem_idx);
    tcg_temp_free(val);
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], EA);
    tcg_temp_free(EA);
5637 5638 5639 5640
#endif
}

/* icbt */
5641
GEN_HANDLER2(icbt_40x, "icbt", 0x1F, 0x06, 0x08, 0x03E00001, PPC_40x_ICBT)
5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652
{
    /* 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)
5653
    GEN_EXCP_PRIVOPC(ctx);
5654 5655
#else
    if (unlikely(!ctx->supervisor)) {
5656
        GEN_EXCP_PRIVOPC(ctx);
5657 5658 5659 5660 5661 5662 5663 5664 5665 5666
        return;
    }
    /* interpreted as no-op */
#endif
}

/* icread */
GEN_HANDLER(icread, 0x1F, 0x06, 0x1F, 0x03E00001, PPC_4xx_COMMON)
{
#if defined(CONFIG_USER_ONLY)
5667
    GEN_EXCP_PRIVOPC(ctx);
5668 5669
#else
    if (unlikely(!ctx->supervisor)) {
5670
        GEN_EXCP_PRIVOPC(ctx);
5671 5672 5673 5674 5675 5676 5677
        return;
    }
    /* interpreted as no-op */
#endif
}

/* rfci (supervisor only) */
5678
GEN_HANDLER2(rfci_40x, "rfci", 0x13, 0x13, 0x01, 0x03FF8001, PPC_40x_EXCP)
5679 5680
{
#if defined(CONFIG_USER_ONLY)
5681
    GEN_EXCP_PRIVOPC(ctx);
5682 5683
#else
    if (unlikely(!ctx->supervisor)) {
5684
        GEN_EXCP_PRIVOPC(ctx);
5685 5686 5687
        return;
    }
    /* Restore CPU state */
5688
    gen_helper_40x_rfci();
5689
    GEN_SYNC(ctx);
5690 5691 5692 5693 5694 5695
#endif
}

GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE)
{
#if defined(CONFIG_USER_ONLY)
5696
    GEN_EXCP_PRIVOPC(ctx);
5697 5698
#else
    if (unlikely(!ctx->supervisor)) {
5699
        GEN_EXCP_PRIVOPC(ctx);
5700 5701 5702
        return;
    }
    /* Restore CPU state */
5703
    gen_helper_rfci();
5704
    GEN_SYNC(ctx);
5705 5706 5707 5708
#endif
}

/* BookE specific */
5709
/* XXX: not implemented on 440 ? */
5710
GEN_HANDLER(rfdi, 0x13, 0x07, 0x01, 0x03FF8001, PPC_RFDI)
5711 5712
{
#if defined(CONFIG_USER_ONLY)
5713
    GEN_EXCP_PRIVOPC(ctx);
5714 5715
#else
    if (unlikely(!ctx->supervisor)) {
5716
        GEN_EXCP_PRIVOPC(ctx);
5717 5718 5719
        return;
    }
    /* Restore CPU state */
5720
    gen_helper_rfdi();
5721
    GEN_SYNC(ctx);
5722 5723 5724
#endif
}

5725
/* XXX: not implemented on 440 ? */
5726
GEN_HANDLER(rfmci, 0x13, 0x06, 0x01, 0x03FF8001, PPC_RFMCI)
5727 5728
{
#if defined(CONFIG_USER_ONLY)
5729
    GEN_EXCP_PRIVOPC(ctx);
5730 5731
#else
    if (unlikely(!ctx->supervisor)) {
5732
        GEN_EXCP_PRIVOPC(ctx);
5733 5734 5735
        return;
    }
    /* Restore CPU state */
5736
    gen_helper_rfmci();
5737
    GEN_SYNC(ctx);
5738 5739
#endif
}
5740

5741
/* TLB management - PowerPC 405 implementation */
5742
/* tlbre */
5743
GEN_HANDLER2(tlbre_40x, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_TLB)
5744 5745
{
#if defined(CONFIG_USER_ONLY)
5746
    GEN_EXCP_PRIVOPC(ctx);
5747 5748
#else
    if (unlikely(!ctx->supervisor)) {
5749
        GEN_EXCP_PRIVOPC(ctx);
5750 5751 5752 5753
        return;
    }
    switch (rB(ctx->opcode)) {
    case 0:
A
aurel32 已提交
5754
        tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
5755
        gen_op_4xx_tlbre_hi();
A
aurel32 已提交
5756
        tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
5757 5758
        break;
    case 1:
A
aurel32 已提交
5759
        tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
5760
        gen_op_4xx_tlbre_lo();
A
aurel32 已提交
5761
        tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
5762 5763
        break;
    default:
5764
        GEN_EXCP_INVAL(ctx);
5765
        break;
5766
    }
5767 5768 5769
#endif
}

5770
/* tlbsx - tlbsx. */
5771
GEN_HANDLER2(tlbsx_40x, "tlbsx", 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_TLB)
5772 5773
{
#if defined(CONFIG_USER_ONLY)
5774
    GEN_EXCP_PRIVOPC(ctx);
5775 5776
#else
    if (unlikely(!ctx->supervisor)) {
5777
        GEN_EXCP_PRIVOPC(ctx);
5778 5779
        return;
    }
5780
    gen_addr_reg_index(cpu_T[0], ctx);
5781
    gen_op_4xx_tlbsx();
5782
    if (Rc(ctx->opcode))
5783
        gen_op_4xx_tlbsx_check();
A
aurel32 已提交
5784
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
5785
#endif
B
bellard 已提交
5786 5787
}

5788
/* tlbwe */
5789
GEN_HANDLER2(tlbwe_40x, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_TLB)
B
bellard 已提交
5790
{
5791
#if defined(CONFIG_USER_ONLY)
5792
    GEN_EXCP_PRIVOPC(ctx);
5793 5794
#else
    if (unlikely(!ctx->supervisor)) {
5795
        GEN_EXCP_PRIVOPC(ctx);
5796 5797 5798 5799
        return;
    }
    switch (rB(ctx->opcode)) {
    case 0:
A
aurel32 已提交
5800 5801
        tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
        tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]);
5802 5803 5804
        gen_op_4xx_tlbwe_hi();
        break;
    case 1:
A
aurel32 已提交
5805 5806
        tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
        tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]);
5807 5808 5809
        gen_op_4xx_tlbwe_lo();
        break;
    default:
5810
        GEN_EXCP_INVAL(ctx);
5811
        break;
5812
    }
5813 5814 5815
#endif
}

5816
/* TLB management - PowerPC 440 implementation */
5817
/* tlbre */
5818
GEN_HANDLER2(tlbre_440, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE)
5819 5820
{
#if defined(CONFIG_USER_ONLY)
5821
    GEN_EXCP_PRIVOPC(ctx);
5822 5823
#else
    if (unlikely(!ctx->supervisor)) {
5824
        GEN_EXCP_PRIVOPC(ctx);
5825 5826 5827 5828 5829 5830
        return;
    }
    switch (rB(ctx->opcode)) {
    case 0:
    case 1:
    case 2:
A
aurel32 已提交
5831
        tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
5832
        gen_op_440_tlbre(rB(ctx->opcode));
A
aurel32 已提交
5833
        tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
5834 5835
        break;
    default:
5836
        GEN_EXCP_INVAL(ctx);
5837 5838 5839 5840 5841 5842
        break;
    }
#endif
}

/* tlbsx - tlbsx. */
5843
GEN_HANDLER2(tlbsx_440, "tlbsx", 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE)
5844 5845
{
#if defined(CONFIG_USER_ONLY)
5846
    GEN_EXCP_PRIVOPC(ctx);
5847 5848
#else
    if (unlikely(!ctx->supervisor)) {
5849
        GEN_EXCP_PRIVOPC(ctx);
5850 5851
        return;
    }
5852
    gen_addr_reg_index(cpu_T[0], ctx);
5853
    gen_op_440_tlbsx();
5854
    if (Rc(ctx->opcode))
5855
        gen_op_4xx_tlbsx_check();
A
aurel32 已提交
5856
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
5857 5858 5859 5860
#endif
}

/* tlbwe */
5861
GEN_HANDLER2(tlbwe_440, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE)
5862 5863
{
#if defined(CONFIG_USER_ONLY)
5864
    GEN_EXCP_PRIVOPC(ctx);
5865 5866
#else
    if (unlikely(!ctx->supervisor)) {
5867
        GEN_EXCP_PRIVOPC(ctx);
5868 5869 5870 5871 5872 5873
        return;
    }
    switch (rB(ctx->opcode)) {
    case 0:
    case 1:
    case 2:
A
aurel32 已提交
5874 5875
        tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
        tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]);
5876
        gen_op_440_tlbwe(rB(ctx->opcode));
5877 5878
        break;
    default:
5879
        GEN_EXCP_INVAL(ctx);
5880 5881 5882 5883 5884
        break;
    }
#endif
}

5885
/* wrtee */
5886
GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_WRTEE)
5887 5888
{
#if defined(CONFIG_USER_ONLY)
5889
    GEN_EXCP_PRIVOPC(ctx);
5890 5891
#else
    if (unlikely(!ctx->supervisor)) {
5892
        GEN_EXCP_PRIVOPC(ctx);
5893 5894
        return;
    }
A
aurel32 已提交
5895
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rD(ctx->opcode)]);
5896
    gen_op_wrte();
J
j_mayer 已提交
5897 5898 5899
    /* Stop translation to have a chance to raise an exception
     * if we just set msr_ee to 1
     */
5900
    GEN_STOP(ctx);
5901 5902 5903 5904
#endif
}

/* wrteei */
5905
GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000EFC01, PPC_WRTEE)
5906 5907
{
#if defined(CONFIG_USER_ONLY)
5908
    GEN_EXCP_PRIVOPC(ctx);
5909 5910
#else
    if (unlikely(!ctx->supervisor)) {
5911
        GEN_EXCP_PRIVOPC(ctx);
5912 5913
        return;
    }
5914
    tcg_gen_movi_tl(cpu_T[0], ctx->opcode & 0x00010000);
5915
    gen_op_wrte();
J
j_mayer 已提交
5916 5917 5918
    /* Stop translation to have a chance to raise an exception
     * if we just set msr_ee to 1
     */
5919
    GEN_STOP(ctx);
5920 5921 5922
#endif
}

J
j_mayer 已提交
5923
/* PowerPC 440 specific instructions */
5924 5925 5926
/* dlmzb */
GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC)
{
5927 5928 5929 5930
    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);
5931 5932 5933 5934 5935 5936 5937 5938 5939
}

/* mbar replaces eieio on 440 */
GEN_HANDLER(mbar, 0x1F, 0x16, 0x13, 0x001FF801, PPC_BOOKE)
{
    /* interpreted as no-op */
}

/* msync replaces sync on 440 */
5940
GEN_HANDLER(msync, 0x1F, 0x16, 0x12, 0x03FFF801, PPC_BOOKE)
5941 5942 5943 5944 5945
{
    /* interpreted as no-op */
}

/* icbt */
5946
GEN_HANDLER2(icbt_440, "icbt", 0x1F, 0x16, 0x00, 0x03E00001, PPC_BOOKE)
5947 5948 5949 5950 5951
{
    /* interpreted as no-op */
    /* XXX: specification say this is treated as a load by the MMU
     *      but does not generate any exception
     */
B
bellard 已提交
5952 5953
}

5954 5955 5956 5957
/***                      Altivec vector extension                         ***/
/* Altivec registers moves */

#define GEN_VR_LDX(name, opc2, opc3)                                          \
5958
GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC)                  \
5959
{                                                                             \
5960
    TCGv EA;                                                                  \
5961 5962 5963 5964
    if (unlikely(!ctx->altivec_enabled)) {                                    \
        GEN_EXCP_NO_VR(ctx);                                                  \
        return;                                                               \
    }                                                                         \
5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977
    EA = tcg_temp_new();                                                      \
    gen_addr_reg_index(EA, ctx);                                              \
    tcg_gen_andi_tl(EA, EA, ~0xf);                                            \
    if (ctx->mem_idx & 1) {                                                   \
        gen_qemu_ld64(cpu_avrl[rD(ctx->opcode)], EA, ctx->mem_idx);           \
        tcg_gen_addi_tl(EA, EA, 8);                                           \
        gen_qemu_ld64(cpu_avrh[rD(ctx->opcode)], EA, ctx->mem_idx);           \
    } else {                                                                  \
        gen_qemu_ld64(cpu_avrh[rD(ctx->opcode)], EA, ctx->mem_idx);           \
        tcg_gen_addi_tl(EA, EA, 8);                                           \
        gen_qemu_ld64(cpu_avrl[rD(ctx->opcode)], EA, ctx->mem_idx);           \
    }                                                                         \
    tcg_temp_free(EA);                                                        \
5978 5979 5980 5981 5982
}

#define GEN_VR_STX(name, opc2, opc3)                                          \
GEN_HANDLER(st##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC)              \
{                                                                             \
5983
    TCGv EA;                                                                  \
5984 5985 5986 5987
    if (unlikely(!ctx->altivec_enabled)) {                                    \
        GEN_EXCP_NO_VR(ctx);                                                  \
        return;                                                               \
    }                                                                         \
5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000
    EA = tcg_temp_new();                                                      \
    gen_addr_reg_index(EA, ctx);                                              \
    tcg_gen_andi_tl(EA, EA, ~0xf);                                            \
    if (ctx->mem_idx & 1) {                                                   \
        gen_qemu_st64(cpu_avrl[rD(ctx->opcode)], EA, ctx->mem_idx);           \
        tcg_gen_addi_tl(EA, EA, 8);                                           \
        gen_qemu_st64(cpu_avrh[rD(ctx->opcode)], EA, ctx->mem_idx);           \
    } else {                                                                  \
        gen_qemu_st64(cpu_avrh[rD(ctx->opcode)], EA, ctx->mem_idx);           \
        tcg_gen_addi_tl(EA, EA, 8);                                           \
        gen_qemu_st64(cpu_avrl[rD(ctx->opcode)], EA, ctx->mem_idx);           \
    }                                                                         \
    tcg_temp_free(EA);                                                        \
6001 6002
}

6003
GEN_VR_LDX(lvx, 0x07, 0x03);
6004
/* As we don't emulate the cache, lvxl is stricly equivalent to lvx */
6005
GEN_VR_LDX(lvxl, 0x07, 0x0B);
6006

6007
GEN_VR_STX(svx, 0x07, 0x07);
6008
/* As we don't emulate the cache, stvxl is stricly equivalent to stvx */
6009
GEN_VR_STX(svxl, 0x07, 0x0F);
6010

6011 6012
/***                           SPE extension                               ***/
/* Register moves */
6013

P
pbrook 已提交
6014
static always_inline void gen_load_gpr64(TCGv_i64 t, int reg) {
A
aurel32 已提交
6015 6016 6017
#if defined(TARGET_PPC64)
    tcg_gen_mov_i64(t, cpu_gpr[reg]);
#else
P
pbrook 已提交
6018
    tcg_gen_concat_i32_i64(t, cpu_gpr[reg], cpu_gprh[reg]);
6019
#endif
A
aurel32 已提交
6020
}
6021

P
pbrook 已提交
6022
static always_inline void gen_store_gpr64(int reg, TCGv_i64 t) {
A
aurel32 已提交
6023 6024 6025
#if defined(TARGET_PPC64)
    tcg_gen_mov_i64(cpu_gpr[reg], t);
#else
P
pbrook 已提交
6026
    TCGv_i64 tmp = tcg_temp_new_i64();
A
aurel32 已提交
6027 6028 6029
    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 已提交
6030
    tcg_temp_free_i64(tmp);
6031
#endif
A
aurel32 已提交
6032
}
6033

6034 6035 6036 6037 6038 6039 6040 6041 6042 6043
#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 */
6044
static always_inline void gen_speundef (DisasContext *ctx)
6045
{
6046
    GEN_EXCP_INVAL(ctx);
6047 6048
}

6049 6050 6051
/* SPE logic */
#if defined(TARGET_PPC64)
#define GEN_SPEOP_LOGIC2(name, tcg_op)                                        \
6052
static always_inline void gen_##name (DisasContext *ctx)                      \
6053 6054
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
6055
        GEN_EXCP_NO_AP(ctx);                                                  \
6056 6057
        return;                                                               \
    }                                                                         \
6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072
    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)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        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)]);                                        \
6073
}
6074 6075 6076 6077 6078 6079 6080 6081 6082 6083
#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);
6084

6085 6086 6087
/* SPE logic immediate */
#if defined(TARGET_PPC64)
#define GEN_SPEOP_TCG_LOGIC_IMM2(name, tcg_opi)                               \
6088 6089 6090 6091 6092 6093
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        return;                                                               \
    }                                                                         \
P
pbrook 已提交
6094 6095 6096
    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
    TCGv_i64 t2 = tcg_temp_local_new_i64();                                   \
6097 6098 6099 6100
    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 已提交
6101
    tcg_temp_free_i64(t2);                                                    \
6102 6103
    tcg_opi(t1, t1, rB(ctx->opcode));                                         \
    tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1);                 \
P
pbrook 已提交
6104 6105
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
6106
}
6107 6108
#else
#define GEN_SPEOP_TCG_LOGIC_IMM2(name, tcg_opi)                               \
6109
static always_inline void gen_##name (DisasContext *ctx)                      \
6110 6111
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
6112
        GEN_EXCP_NO_AP(ctx);                                                  \
6113 6114
        return;                                                               \
    }                                                                         \
6115 6116 6117 6118
    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));                                                 \
6119
}
6120 6121 6122 6123 6124
#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);
6125

6126 6127 6128
/* SPE arithmetic */
#if defined(TARGET_PPC64)
#define GEN_SPEOP_ARITH1(name, tcg_op)                                        \
6129
static always_inline void gen_##name (DisasContext *ctx)                      \
6130 6131
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
6132
        GEN_EXCP_NO_AP(ctx);                                                  \
6133 6134
        return;                                                               \
    }                                                                         \
P
pbrook 已提交
6135 6136 6137
    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
    TCGv_i64 t2 = tcg_temp_local_new_i64();                                   \
6138 6139 6140 6141
    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 已提交
6142
    tcg_temp_free_i64(t2);                                                    \
6143 6144
    tcg_op(t1, t1);                                                           \
    tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1);                 \
P
pbrook 已提交
6145 6146
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
6147
}
6148
#else
P
pbrook 已提交
6149
#define GEN_SPEOP_ARITH1(name, tcg_op)                                        \
6150 6151 6152 6153 6154 6155 6156 6157 6158 6159
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        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
6160

P
pbrook 已提交
6161
static always_inline void gen_op_evabs (TCGv_i32 ret, TCGv_i32 arg1)
6162 6163 6164
{
    int l1 = gen_new_label();
    int l2 = gen_new_label();
6165

6166 6167 6168 6169
    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 已提交
6170
    tcg_gen_mov_i32(ret, arg1);
6171 6172 6173 6174 6175 6176
    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 已提交
6177
static always_inline void gen_op_evrndw (TCGv_i32 ret, TCGv_i32 arg1)
6178
{
6179 6180 6181 6182
    tcg_gen_addi_i32(ret, arg1, 0x8000);
    tcg_gen_ext16u_i32(ret, ret);
}
GEN_SPEOP_ARITH1(evrndw, gen_op_evrndw);
P
pbrook 已提交
6183 6184
GEN_SPEOP_ARITH1(evcntlsw, gen_helper_cntlsw32);
GEN_SPEOP_ARITH1(evcntlzw, gen_helper_cntlzw32);
6185

6186 6187 6188
#if defined(TARGET_PPC64)
#define GEN_SPEOP_ARITH2(name, tcg_op)                                        \
static always_inline void gen_##name (DisasContext *ctx)                      \
6189 6190
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
6191
        GEN_EXCP_NO_AP(ctx);                                                  \
6192 6193
        return;                                                               \
    }                                                                         \
P
pbrook 已提交
6194 6195 6196 6197
    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t2 = tcg_temp_local_new_i32();                                   \
    TCGv_i64 t3 = tcg_temp_local_new(TCG_TYPE_I64);                           \
6198 6199 6200 6201 6202 6203 6204
    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 已提交
6205
    tcg_temp_free_i64(t3);                                                    \
6206
    tcg_op(t1, t1, t2);                                                       \
P
pbrook 已提交
6207
    tcg_temp_free_i32(t2);                                                    \
6208
    tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1);                 \
P
pbrook 已提交
6209 6210
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
6211
}
6212 6213 6214
#else
#define GEN_SPEOP_ARITH2(name, tcg_op)                                        \
static always_inline void gen_##name (DisasContext *ctx)                      \
6215 6216
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
6217
        GEN_EXCP_NO_AP(ctx);                                                  \
6218 6219
        return;                                                               \
    }                                                                         \
6220 6221 6222 6223
    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)]);                                        \
6224
}
6225
#endif
6226

P
pbrook 已提交
6227
static always_inline void gen_op_evsrwu (TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
6228
{
P
pbrook 已提交
6229
    TCGv_i32 t0;
6230
    int l1, l2;
6231

6232 6233
    l1 = gen_new_label();
    l2 = gen_new_label();
P
pbrook 已提交
6234
    t0 = tcg_temp_local_new_i32();
6235 6236 6237 6238 6239 6240 6241 6242
    /* 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 已提交
6243
    tcg_temp_free_i32(t0);
6244 6245
}
GEN_SPEOP_ARITH2(evsrwu, gen_op_evsrwu);
P
pbrook 已提交
6246
static always_inline void gen_op_evsrws (TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
6247
{
P
pbrook 已提交
6248
    TCGv_i32 t0;
6249 6250 6251 6252
    int l1, l2;

    l1 = gen_new_label();
    l2 = gen_new_label();
P
pbrook 已提交
6253
    t0 = tcg_temp_local_new_i32();
6254 6255 6256 6257 6258 6259 6260 6261
    /* 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 已提交
6262
    tcg_temp_free_i32(t0);
6263 6264
}
GEN_SPEOP_ARITH2(evsrws, gen_op_evsrws);
P
pbrook 已提交
6265
static always_inline void gen_op_evslw (TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
6266
{
P
pbrook 已提交
6267
    TCGv_i32 t0;
6268 6269 6270 6271
    int l1, l2;

    l1 = gen_new_label();
    l2 = gen_new_label();
P
pbrook 已提交
6272
    t0 = tcg_temp_local_new_i32();
6273 6274 6275 6276 6277 6278 6279 6280
    /* 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 已提交
6281
    tcg_temp_free_i32(t0);
6282 6283
}
GEN_SPEOP_ARITH2(evslw, gen_op_evslw);
P
pbrook 已提交
6284
static always_inline void gen_op_evrlw (TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
6285
{
P
pbrook 已提交
6286
    TCGv_i32 t0 = tcg_temp_new_i32();
6287 6288
    tcg_gen_andi_i32(t0, arg2, 0x1F);
    tcg_gen_rotl_i32(ret, arg1, t0);
P
pbrook 已提交
6289
    tcg_temp_free_i32(t0);
6290 6291 6292 6293 6294 6295 6296 6297 6298
}
GEN_SPEOP_ARITH2(evrlw, gen_op_evrlw);
static always_inline void gen_evmergehi (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
        GEN_EXCP_NO_AP(ctx);
        return;
    }
#if defined(TARGET_PPC64)
P
pbrook 已提交
6299 6300
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311
    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 已提交
6312
static always_inline void gen_op_evsubf (TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
6313
{
6314 6315 6316
    tcg_gen_sub_i32(ret, arg2, arg1);
}
GEN_SPEOP_ARITH2(evsubfw, gen_op_evsubf);
6317

6318 6319 6320 6321 6322 6323 6324 6325 6326
/* 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)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        return;                                                               \
    }                                                                         \
P
pbrook 已提交
6327 6328 6329
    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
    TCGv_i64 t2 = tcg_temp_local_new_i64();                                   \
6330 6331 6332 6333
    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);                                            \
P
pbrook 已提交
6334
    tcg_temp_free_i64(t2);                                                        \
6335 6336
    tcg_op(t1, t1, rA(ctx->opcode));                                          \
    tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1);                 \
P
pbrook 已提交
6337 6338
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369
}
#else
#define GEN_SPEOP_ARITH_IMM2(name, tcg_op)                                    \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        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)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        return;                                                               \
    }                                                                         \
    int l1 = gen_new_label();                                                 \
    int l2 = gen_new_label();                                                 \
    int l3 = gen_new_label();                                                 \
    int l4 = gen_new_label();                                                 \
P
pbrook 已提交
6370 6371 6372
    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
    TCGv_i64 t2 = tcg_temp_local_new_i64();                                   \
6373 6374 6375
    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 已提交
6376
    tcg_gen_movi_i32(cpu_crf[crfD(ctx->opcode)], 0);                          \
6377 6378 6379 6380 6381 6382 6383 6384 6385
    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 已提交
6386
    tcg_temp_free_i64(t2);                                                    \
6387 6388 6389 6390 6391 6392 6393 6394
    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 已提交
6395 6396
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439
}
#else
#define GEN_SPEOP_COMP(name, tcg_cond)                                        \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        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 已提交
6440 6441
    gen_helper_brinc(cpu_gpr[rD(ctx->opcode)],
                     cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
6442
}
6443 6444 6445 6446 6447 6448 6449
static always_inline void gen_evmergelo (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
        GEN_EXCP_NO_AP(ctx);
        return;
    }
#if defined(TARGET_PPC64)
P
pbrook 已提交
6450 6451
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468
    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)) {
        GEN_EXCP_NO_AP(ctx);
        return;
    }
#if defined(TARGET_PPC64)
P
pbrook 已提交
6469 6470
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487
    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)) {
        GEN_EXCP_NO_AP(ctx);
        return;
    }
#if defined(TARGET_PPC64)
P
pbrook 已提交
6488 6489
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501
    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)
{
6502
    uint64_t imm = ((int32_t)(rA(ctx->opcode) << 11)) >> 27;
6503

6504
#if defined(TARGET_PPC64)
6505
    tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], (imm << 32) | imm);
6506 6507 6508 6509 6510
#else
    tcg_gen_movi_i32(cpu_gpr[rD(ctx->opcode)], imm);
    tcg_gen_movi_i32(cpu_gprh[rD(ctx->opcode)], imm);
#endif
}
6511
static always_inline void gen_evsplatfi (DisasContext *ctx)
6512
{
6513
    uint64_t imm = rA(ctx->opcode) << 11;
6514

6515
#if defined(TARGET_PPC64)
6516
    tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], (imm << 32) | imm);
6517 6518 6519 6520
#else
    tcg_gen_movi_i32(cpu_gpr[rD(ctx->opcode)], imm);
    tcg_gen_movi_i32(cpu_gprh[rD(ctx->opcode)], imm);
#endif
6521 6522
}

6523 6524 6525 6526 6527 6528
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 已提交
6529
    TCGv_i32 t0 = tcg_temp_local_new_i32();
6530
#if defined(TARGET_PPC64)
P
pbrook 已提交
6531 6532
    TCGv t1 = tcg_temp_local_new();
    TCGv t2 = tcg_temp_local_new();
6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563
#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 已提交
6564
    tcg_temp_free_i32(t0);
6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 6580 6581 6582 6583 6584 6585 6586
#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);
}
6587 6588 6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604 6605 6606 6607 6608 6609 6610 6611 6612 6613

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

6614 6615 6616 6617 6618 6619 6620 6621 6622
/* SPE load and stores */
static always_inline void gen_addr_spe_imm_index (TCGv EA, DisasContext *ctx, int sh)
{
    target_ulong uimm = rB(ctx->opcode);

    if (rA(ctx->opcode) == 0)
        tcg_gen_movi_tl(EA, uimm << sh);
    else
        tcg_gen_addi_tl(EA, cpu_gpr[rA(ctx->opcode)], uimm << sh);
6623
}
6624 6625 6626 6627 6628 6629 6630 6631 6632 6633 6634 6635 6636

static always_inline void gen_op_evldd(DisasContext *ctx, TCGv addr)
{
#if defined(TARGET_PPC64)
    gen_qemu_ld64(cpu_gpr[rD(ctx->opcode)], addr, ctx->mem_idx);
#else
    TCGv_i64 t0 = tcg_temp_new_i64();
    gen_qemu_ld64(t0, addr, ctx->mem_idx);
    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
6637
}
6638 6639 6640

static always_inline void gen_op_evldw(DisasContext *ctx, TCGv addr)
{
6641
#if defined(TARGET_PPC64)
6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653
    TCGv t0 = tcg_temp_new();
    gen_qemu_ld32u(t0, addr, ctx->mem_idx);
    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 32);
    tcg_gen_addi_tl(addr, addr, 4);
    gen_qemu_ld32u(t0, addr, ctx->mem_idx);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
    tcg_temp_free(t0);
#else
    gen_qemu_ld32u(cpu_gprh[rD(ctx->opcode)], addr, ctx->mem_idx);
    tcg_gen_addi_tl(addr, addr, 4);
    gen_qemu_ld32u(cpu_gpr[rD(ctx->opcode)], addr, ctx->mem_idx);
#endif
6654
}
6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672

static always_inline void gen_op_evldh(DisasContext *ctx, TCGv addr)
{
    TCGv t0 = tcg_temp_new();
#if defined(TARGET_PPC64)
    gen_qemu_ld16u(t0, addr, ctx->mem_idx);
    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 48);
    tcg_gen_addi_tl(addr, addr, 2);
    gen_qemu_ld16u(t0, addr, ctx->mem_idx);
    tcg_gen_shli_tl(t0, t0, 32);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
    tcg_gen_addi_tl(addr, addr, 2);
    gen_qemu_ld16u(t0, addr, ctx->mem_idx);
    tcg_gen_shli_tl(t0, t0, 16);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
    tcg_gen_addi_tl(addr, addr, 2);
    gen_qemu_ld16u(t0, addr, ctx->mem_idx);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
6673
#else
6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684
    gen_qemu_ld16u(t0, addr, ctx->mem_idx);
    tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16);
    tcg_gen_addi_tl(addr, addr, 2);
    gen_qemu_ld16u(t0, addr, ctx->mem_idx);
    tcg_gen_or_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rD(ctx->opcode)], t0);
    tcg_gen_addi_tl(addr, addr, 2);
    gen_qemu_ld16u(t0, addr, ctx->mem_idx);
    tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16);
    tcg_gen_addi_tl(addr, addr, 2);
    gen_qemu_ld16u(t0, addr, ctx->mem_idx);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
6685
#endif
6686
    tcg_temp_free(t0);
6687 6688
}

6689 6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 6702
static always_inline void gen_op_evlhhesplat(DisasContext *ctx, TCGv addr)
{
    TCGv t0 = tcg_temp_new();
    gen_qemu_ld16u(t0, addr, ctx->mem_idx);
#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);
6703 6704
}

6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716
static always_inline void gen_op_evlhhousplat(DisasContext *ctx, TCGv addr)
{
    TCGv t0 = tcg_temp_new();
    gen_qemu_ld16u(t0, addr, ctx->mem_idx);
#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);
6717 6718
}

6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 6754 6755 6756 6757 6758 6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778 6779 6780 6781 6782 6783 6784 6785 6786 6787 6788 6789 6790 6791
static always_inline void gen_op_evlhhossplat(DisasContext *ctx, TCGv addr)
{
    TCGv t0 = tcg_temp_new();
    gen_qemu_ld16s(t0, addr, ctx->mem_idx);
#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)
    gen_qemu_ld16u(t0, addr, ctx->mem_idx);
    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 48);
    gen_qemu_ld16u(t0, addr, ctx->mem_idx);
    tcg_gen_shli_tl(t0, t0, 16);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
#else
    gen_qemu_ld16u(t0, addr, ctx->mem_idx);
    tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16);
    tcg_gen_addi_tl(addr, addr, 2);
    gen_qemu_ld16u(t0, addr, ctx->mem_idx);
    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();
    gen_qemu_ld16u(cpu_gpr[rD(ctx->opcode)], addr, ctx->mem_idx);
    tcg_gen_addi_tl(addr, addr, 2);
    gen_qemu_ld16u(t0, addr, ctx->mem_idx);
    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
    gen_qemu_ld16u(cpu_gprh[rD(ctx->opcode)], addr, ctx->mem_idx);
    tcg_gen_addi_tl(addr, addr, 2);
    gen_qemu_ld16u(cpu_gpr[rD(ctx->opcode)], addr, ctx->mem_idx);
#endif
}

static always_inline void gen_op_evlwhos(DisasContext *ctx, TCGv addr)
{
#if defined(TARGET_PPC64)
    TCGv t0 = tcg_temp_new();
    gen_qemu_ld16s(t0, addr, ctx->mem_idx);
    tcg_gen_ext32u_tl(cpu_gpr[rD(ctx->opcode)], t0);
    tcg_gen_addi_tl(addr, addr, 2);
    gen_qemu_ld16s(t0, addr, ctx->mem_idx);
    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
    gen_qemu_ld16s(cpu_gprh[rD(ctx->opcode)], addr, ctx->mem_idx);
    tcg_gen_addi_tl(addr, addr, 2);
    gen_qemu_ld16s(cpu_gpr[rD(ctx->opcode)], addr, ctx->mem_idx);
#endif
}

static always_inline void gen_op_evlwwsplat(DisasContext *ctx, TCGv addr)
{
    TCGv t0 = tcg_temp_new();
    gen_qemu_ld32u(t0, addr, ctx->mem_idx);
6792
#if defined(TARGET_PPC64)
6793 6794 6795 6796 6797 6798 6799 6800 6801 6802 6803 6804 6805 6806 6807 6808 6809 6810 6811 6812 6813 6814 6815 6816 6817 6818 6819 6820 6821 6822
    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)
    gen_qemu_ld16u(t0, addr, ctx->mem_idx);
    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);
    tcg_gen_addi_tl(addr, addr, 2);
    gen_qemu_ld16u(t0, addr, ctx->mem_idx);
    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
    gen_qemu_ld16u(t0, addr, ctx->mem_idx);
    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);
    tcg_gen_addi_tl(addr, addr, 2);
    gen_qemu_ld16u(t0, addr, ctx->mem_idx);
    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);
6823
#endif
6824 6825 6826 6827 6828 6829 6830
    tcg_temp_free(t0);
}

static always_inline void gen_op_evstdd(DisasContext *ctx, TCGv addr)
{
#if defined(TARGET_PPC64)
    gen_qemu_st64(cpu_gpr[rS(ctx->opcode)], addr, ctx->mem_idx);
6831
#else
6832 6833 6834 6835 6836 6837 6838 6839 6840
    TCGv_i64 t0 = tcg_temp_new_i64();
    tcg_gen_concat_i32_i64(t0, cpu_gpr[rS(ctx->opcode)], cpu_gprh[rS(ctx->opcode)]);
    gen_qemu_st64(t0, addr, ctx->mem_idx);
    tcg_temp_free_i64(t0);
#endif
}

static always_inline void gen_op_evstdw(DisasContext *ctx, TCGv addr)
{
6841
#if defined(TARGET_PPC64)
6842 6843 6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 6859 6860 6861 6862 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877 6878 6879 6880 6881 6882 6883 6884 6885 6886 6887 6888 6889 6890 6891 6892 6893 6894 6895 6896 6897 6898 6899 6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 6928 6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939 6940 6941 6942 6943 6944 6945 6946 6947 6948 6949 6950 6951 6952 6953 6954 6955 6956 6957 6958 6959
    TCGv t0 = tcg_temp_new();
    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 32);
    gen_qemu_st32(t0, addr, ctx->mem_idx);
    tcg_temp_free(t0);
#else
    gen_qemu_st32(cpu_gprh[rS(ctx->opcode)], addr, ctx->mem_idx);
#endif
    tcg_gen_addi_tl(addr, addr, 4);
    gen_qemu_st32(cpu_gpr[rS(ctx->opcode)], addr, ctx->mem_idx);
}

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
    gen_qemu_st16(t0, addr, ctx->mem_idx);
    tcg_gen_addi_tl(addr, addr, 2);
#if defined(TARGET_PPC64)
    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 32);
    gen_qemu_st16(t0, addr, ctx->mem_idx);
#else
    gen_qemu_st16(cpu_gprh[rS(ctx->opcode)], addr, ctx->mem_idx);
#endif
    tcg_gen_addi_tl(addr, addr, 2);
    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 16);
    gen_qemu_st16(t0, addr, ctx->mem_idx);
    tcg_temp_free(t0);
    tcg_gen_addi_tl(addr, addr, 2);
    gen_qemu_st16(cpu_gpr[rS(ctx->opcode)], addr, ctx->mem_idx);
}

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
    gen_qemu_st16(t0, addr, ctx->mem_idx);
    tcg_gen_addi_tl(addr, addr, 2);
    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 16);
    gen_qemu_st16(t0, addr, ctx->mem_idx);
    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);
    gen_qemu_st16(t0, addr, ctx->mem_idx);
    tcg_temp_free(t0);
#else
    gen_qemu_st16(cpu_gprh[rS(ctx->opcode)], addr, ctx->mem_idx);
#endif
    tcg_gen_addi_tl(addr, addr, 2);
    gen_qemu_st16(cpu_gpr[rS(ctx->opcode)], addr, ctx->mem_idx);
}

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);
    gen_qemu_st32(t0, addr, ctx->mem_idx);
    tcg_temp_free(t0);
#else
    gen_qemu_st32(cpu_gprh[rS(ctx->opcode)], addr, ctx->mem_idx);
#endif
}

static always_inline void gen_op_evstwwo(DisasContext *ctx, TCGv addr)
{
    gen_qemu_st32(cpu_gpr[rS(ctx->opcode)], addr, ctx->mem_idx);
}

#define GEN_SPEOP_LDST(name, opc2, sh)                                        \
GEN_HANDLER(gen_##name, 0x04, opc2, 0x0C, 0x00000000, PPC_SPE)                \
{                                                                             \
    TCGv t0;                                                                  \
    if (unlikely(!ctx->spe_enabled)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        return;                                                               \
    }                                                                         \
    t0 = tcg_temp_new();                                                      \
    if (Rc(ctx->opcode)) {                                                    \
        gen_addr_spe_imm_index(t0, ctx, sh);                                  \
    } else {                                                                  \
        gen_addr_reg_index(t0, ctx);                                          \
    }                                                                         \
    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);
6960 6961 6962 6963 6964 6965 6966 6967 6968 6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 6987 6988 6989 6990 6991 6992 6993 6994 6995 6996 6997 6998 6999 7000 7001 7002 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

/* 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 已提交
7038 7039
#if defined(TARGET_PPC64)
#define GEN_SPEFPUOP_CONV_32_32(name)                                         \
7040
static always_inline void gen_##name (DisasContext *ctx)                      \
7041
{                                                                             \
A
aurel32 已提交
7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053
    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);                                                        \
7054
}
A
aurel32 已提交
7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 7080 7081 7082 7083
#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)                                       \
7084 7085
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
A
aurel32 已提交
7086 7087
    TCGv_i32 t0, t1;                                                          \
    TCGv_i64 t2;                                                              \
7088 7089 7090 7091
    if (unlikely(!ctx->spe_enabled)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
7092 7093 7094 7095 7096 7097 7098 7099 7100 7101 7102 7103 7104
    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);                                                        \
7105
}
A
aurel32 已提交
7106
#define GEN_SPEFPUOP_ARITH2_64_64(name)                                       \
7107 7108 7109 7110 7111 7112
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
7113 7114
    gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],     \
                      cpu_gpr[rB(ctx->opcode)]);                              \
7115
}
A
aurel32 已提交
7116
#define GEN_SPEFPUOP_COMP_32(name)                                            \
7117 7118
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
A
aurel32 已提交
7119
    TCGv_i32 t0, t1;                                                          \
7120 7121 7122 7123
    if (unlikely(!ctx->spe_enabled)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
7124 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 7136 7137 7138 7139 7140 7141 7142 7143 7144 7145 7146
    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)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        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)]);    \
7147
}
A
aurel32 已提交
7148 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7160 7161 7162 7163 7164 7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 7182 7183 7184 7185 7186 7187 7188 7189 7190 7191 7192 7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212 7213 7214 7215 7216 7217 7218 7219 7220 7221 7222 7223 7224 7225 7226
#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)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        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)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        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)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        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)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        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
7227

7228 7229
/* Single precision floating-point vectors operations */
/* Arithmetic */
A
aurel32 已提交
7230 7231 7232 7233 7234 7235 7236 7237 7238 7239 7240 7241 7242 7243 7244 7245 7246 7247 7248 7249 7250 7251 7252 7253 7254 7255 7256 7257 7258 7259 7260 7261 7262 7263 7264 7265 7266 7267 7268 7269 7270 7271 7272 7273
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)) {
        GEN_EXCP_NO_AP(ctx);
        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)) {
        GEN_EXCP_NO_AP(ctx);
        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)) {
        GEN_EXCP_NO_AP(ctx);
        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
}

7274
/* Conversion */
A
aurel32 已提交
7275 7276 7277 7278 7279 7280 7281 7282 7283 7284 7285
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);

7286
/* Comparison */
A
aurel32 已提交
7287 7288 7289 7290 7291 7292
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);
7293 7294 7295 7296 7297 7298 7299 7300 7301 7302 7303 7304 7305 7306 7307 7308 7309 7310 7311

/* Opcodes definitions */
GEN_SPE(evfsadd,        evfssub,       0x00, 0x0A, 0x00000000, PPC_SPEFPU); //
GEN_SPE(evfsabs,        evfsnabs,      0x02, 0x0A, 0x0000F800, PPC_SPEFPU); //
GEN_SPE(evfsneg,        speundef,      0x03, 0x0A, 0x0000F800, PPC_SPEFPU); //
GEN_SPE(evfsmul,        evfsdiv,       0x04, 0x0A, 0x00000000, PPC_SPEFPU); //
GEN_SPE(evfscmpgt,      evfscmplt,     0x06, 0x0A, 0x00600000, PPC_SPEFPU); //
GEN_SPE(evfscmpeq,      speundef,      0x07, 0x0A, 0x00600000, PPC_SPEFPU); //
GEN_SPE(evfscfui,       evfscfsi,      0x08, 0x0A, 0x00180000, PPC_SPEFPU); //
GEN_SPE(evfscfuf,       evfscfsf,      0x09, 0x0A, 0x00180000, PPC_SPEFPU); //
GEN_SPE(evfsctui,       evfsctsi,      0x0A, 0x0A, 0x00180000, PPC_SPEFPU); //
GEN_SPE(evfsctuf,       evfsctsf,      0x0B, 0x0A, 0x00180000, PPC_SPEFPU); //
GEN_SPE(evfsctuiz,      speundef,      0x0C, 0x0A, 0x00180000, PPC_SPEFPU); //
GEN_SPE(evfsctsiz,      speundef,      0x0D, 0x0A, 0x00180000, PPC_SPEFPU); //
GEN_SPE(evfststgt,      evfststlt,     0x0E, 0x0A, 0x00600000, PPC_SPEFPU); //
GEN_SPE(evfststeq,      speundef,      0x0F, 0x0A, 0x00600000, PPC_SPEFPU); //

/* Single precision floating-point operations */
/* Arithmetic */
A
aurel32 已提交
7312 7313 7314 7315 7316 7317 7318 7319 7320 7321 7322 7323 7324 7325 7326 7327 7328 7329 7330 7331 7332 7333 7334 7335 7336 7337 7338 7339 7340
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)) {
        GEN_EXCP_NO_AP(ctx);
        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)) {
        GEN_EXCP_NO_AP(ctx);
        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)) {
        GEN_EXCP_NO_AP(ctx);
        return;
    }
    tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
}

7341
/* Conversion */
A
aurel32 已提交
7342 7343 7344 7345 7346 7347 7348 7349 7350 7351 7352 7353
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);

7354
/* Comparison */
A
aurel32 已提交
7355 7356 7357 7358 7359 7360
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);
7361 7362

/* Opcodes definitions */
7363
GEN_SPE(efsadd,         efssub,        0x00, 0x0B, 0x00000000, PPC_SPEFPU); //
7364 7365 7366 7367 7368 7369 7370 7371 7372
GEN_SPE(efsabs,         efsnabs,       0x02, 0x0B, 0x0000F800, PPC_SPEFPU); //
GEN_SPE(efsneg,         speundef,      0x03, 0x0B, 0x0000F800, PPC_SPEFPU); //
GEN_SPE(efsmul,         efsdiv,        0x04, 0x0B, 0x00000000, PPC_SPEFPU); //
GEN_SPE(efscmpgt,       efscmplt,      0x06, 0x0B, 0x00600000, PPC_SPEFPU); //
GEN_SPE(efscmpeq,       efscfd,        0x07, 0x0B, 0x00600000, PPC_SPEFPU); //
GEN_SPE(efscfui,        efscfsi,       0x08, 0x0B, 0x00180000, PPC_SPEFPU); //
GEN_SPE(efscfuf,        efscfsf,       0x09, 0x0B, 0x00180000, PPC_SPEFPU); //
GEN_SPE(efsctui,        efsctsi,       0x0A, 0x0B, 0x00180000, PPC_SPEFPU); //
GEN_SPE(efsctuf,        efsctsf,       0x0B, 0x0B, 0x00180000, PPC_SPEFPU); //
7373 7374
GEN_SPE(efsctuiz,       speundef,      0x0C, 0x0B, 0x00180000, PPC_SPEFPU); //
GEN_SPE(efsctsiz,       speundef,      0x0D, 0x0B, 0x00180000, PPC_SPEFPU); //
7375 7376 7377 7378 7379
GEN_SPE(efststgt,       efststlt,      0x0E, 0x0B, 0x00600000, PPC_SPEFPU); //
GEN_SPE(efststeq,       speundef,      0x0F, 0x0B, 0x00600000, PPC_SPEFPU); //

/* Double precision floating-point operations */
/* Arithmetic */
A
aurel32 已提交
7380 7381 7382 7383 7384 7385 7386 7387 7388 7389 7390 7391 7392 7393 7394 7395 7396 7397 7398 7399 7400 7401 7402 7403 7404 7405 7406 7407 7408 7409 7410 7411 7412 7413 7414 7415 7416 7417 7418 7419 7420
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)) {
        GEN_EXCP_NO_AP(ctx);
        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)) {
        GEN_EXCP_NO_AP(ctx);
        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)) {
        GEN_EXCP_NO_AP(ctx);
        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
}

7421
/* Conversion */
A
aurel32 已提交
7422 7423 7424 7425 7426 7427 7428 7429 7430 7431 7432 7433 7434 7435 7436
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);
7437 7438

/* Comparison */
A
aurel32 已提交
7439 7440 7441 7442 7443 7444
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);
7445 7446 7447 7448 7449 7450 7451 7452 7453 7454 7455 7456 7457 7458 7459 7460 7461 7462 7463

/* Opcodes definitions */
GEN_SPE(efdadd,         efdsub,        0x10, 0x0B, 0x00000000, PPC_SPEFPU); //
GEN_SPE(efdcfuid,       efdcfsid,      0x11, 0x0B, 0x00180000, PPC_SPEFPU); //
GEN_SPE(efdabs,         efdnabs,       0x12, 0x0B, 0x0000F800, PPC_SPEFPU); //
GEN_SPE(efdneg,         speundef,      0x13, 0x0B, 0x0000F800, PPC_SPEFPU); //
GEN_SPE(efdmul,         efddiv,        0x14, 0x0B, 0x00000000, PPC_SPEFPU); //
GEN_SPE(efdctuidz,      efdctsidz,     0x15, 0x0B, 0x00180000, PPC_SPEFPU); //
GEN_SPE(efdcmpgt,       efdcmplt,      0x16, 0x0B, 0x00600000, PPC_SPEFPU); //
GEN_SPE(efdcmpeq,       efdcfs,        0x17, 0x0B, 0x00600000, PPC_SPEFPU); //
GEN_SPE(efdcfui,        efdcfsi,       0x18, 0x0B, 0x00180000, PPC_SPEFPU); //
GEN_SPE(efdcfuf,        efdcfsf,       0x19, 0x0B, 0x00180000, PPC_SPEFPU); //
GEN_SPE(efdctui,        efdctsi,       0x1A, 0x0B, 0x00180000, PPC_SPEFPU); //
GEN_SPE(efdctuf,        efdctsf,       0x1B, 0x0B, 0x00180000, PPC_SPEFPU); //
GEN_SPE(efdctuiz,       speundef,      0x1C, 0x0B, 0x00180000, PPC_SPEFPU); //
GEN_SPE(efdctsiz,       speundef,      0x1D, 0x0B, 0x00180000, PPC_SPEFPU); //
GEN_SPE(efdtstgt,       efdtstlt,      0x1E, 0x0B, 0x00600000, PPC_SPEFPU); //
GEN_SPE(efdtsteq,       speundef,      0x1F, 0x0B, 0x00600000, PPC_SPEFPU); //

B
bellard 已提交
7464 7465 7466
/* End opcode list */
GEN_OPCODE_MARK(end);

7467
#include "translate_init.c"
7468
#include "helper_regs.h"
B
bellard 已提交
7469

7470
/*****************************************************************************/
7471
/* Misc PowerPC helpers */
7472 7473 7474
void cpu_dump_state (CPUState *env, FILE *f,
                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
                     int flags)
B
bellard 已提交
7475
{
7476 7477 7478
#define RGPL  4
#define RFPL  4

B
bellard 已提交
7479 7480
    int i;

J
j_mayer 已提交
7481
    cpu_fprintf(f, "NIP " ADDRX "   LR " ADDRX " CTR " ADDRX " XER %08x\n",
A
aurel32 已提交
7482
                env->nip, env->lr, env->ctr, env->xer);
7483 7484
    cpu_fprintf(f, "MSR " ADDRX " HID0 " ADDRX "  HF " ADDRX " idx %d\n",
                env->msr, env->spr[SPR_HID0], env->hflags, env->mmu_idx);
7485
#if !defined(NO_TIMER_DUMP)
J
j_mayer 已提交
7486
    cpu_fprintf(f, "TB %08x %08x "
7487 7488 7489 7490
#if !defined(CONFIG_USER_ONLY)
                "DECR %08x"
#endif
                "\n",
J
j_mayer 已提交
7491
                cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env)
7492 7493 7494 7495
#if !defined(CONFIG_USER_ONLY)
                , cpu_ppc_load_decr(env)
#endif
                );
J
j_mayer 已提交
7496
#endif
7497
    for (i = 0; i < 32; i++) {
7498 7499
        if ((i & (RGPL - 1)) == 0)
            cpu_fprintf(f, "GPR%02d", i);
7500
        cpu_fprintf(f, " " REGX, ppc_dump_gpr(env, i));
7501
        if ((i & (RGPL - 1)) == (RGPL - 1))
B
bellard 已提交
7502
            cpu_fprintf(f, "\n");
7503
    }
7504
    cpu_fprintf(f, "CR ");
7505
    for (i = 0; i < 8; i++)
B
bellard 已提交
7506 7507
        cpu_fprintf(f, "%01x", env->crf[i]);
    cpu_fprintf(f, "  [");
7508 7509 7510 7511 7512 7513 7514 7515
    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 已提交
7516
        cpu_fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' ');
7517
    }
7518
    cpu_fprintf(f, " ]             RES " ADDRX "\n", env->reserve);
7519 7520 7521
    for (i = 0; i < 32; i++) {
        if ((i & (RFPL - 1)) == 0)
            cpu_fprintf(f, "FPR%02d", i);
B
bellard 已提交
7522
        cpu_fprintf(f, " %016" PRIx64, *((uint64_t *)&env->fpr[i]));
7523
        if ((i & (RFPL - 1)) == (RFPL - 1))
B
bellard 已提交
7524
            cpu_fprintf(f, "\n");
B
bellard 已提交
7525
    }
7526
#if !defined(CONFIG_USER_ONLY)
7527
    cpu_fprintf(f, "SRR0 " ADDRX " SRR1 " ADDRX " SDR1 " ADDRX "\n",
7528
                env->spr[SPR_SRR0], env->spr[SPR_SRR1], env->sdr1);
7529
#endif
B
bellard 已提交
7530

7531 7532
#undef RGPL
#undef RFPL
B
bellard 已提交
7533 7534
}

7535 7536 7537 7538 7539 7540 7541 7542 7543 7544 7545 7546 7547 7548 7549 7550 7551 7552 7553 7554 7555 7556 7557 7558 7559 7560 7561 7562 7563 7564 7565 7566 7567 7568 7569 7570 7571 7572 7573 7574 7575 7576 7577 7578 7579 7580 7581
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
}

7582
/*****************************************************************************/
7583 7584 7585
static always_inline void gen_intermediate_code_internal (CPUState *env,
                                                          TranslationBlock *tb,
                                                          int search_pc)
B
bellard 已提交
7586
{
7587
    DisasContext ctx, *ctxp = &ctx;
B
bellard 已提交
7588
    opc_handler_t **table, *handler;
B
bellard 已提交
7589
    target_ulong pc_start;
B
bellard 已提交
7590
    uint16_t *gen_opc_end;
7591
    int supervisor, little_endian;
7592
    CPUBreakpoint *bp;
B
bellard 已提交
7593
    int j, lj = -1;
P
pbrook 已提交
7594 7595
    int num_insns;
    int max_insns;
B
bellard 已提交
7596 7597 7598

    pc_start = tb->pc;
    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
7599 7600 7601
#if defined(OPTIMIZE_FPRF_UPDATE)
    gen_fprf_ptr = gen_fprf_buf;
#endif
B
bellard 已提交
7602
    ctx.nip = pc_start;
B
bellard 已提交
7603
    ctx.tb = tb;
7604
    ctx.exception = POWERPC_EXCP_NONE;
7605
    ctx.spr_cb = env->spr_cb;
7606 7607
    supervisor = env->mmu_idx;
#if !defined(CONFIG_USER_ONLY)
7608
    ctx.supervisor = supervisor;
7609
#endif
7610
    little_endian = env->hflags & (1 << MSR_LE) ? 1 : 0;
7611 7612
#if defined(TARGET_PPC64)
    ctx.sf_mode = msr_sf;
7613
    ctx.mem_idx = (supervisor << 2) | (msr_sf << 1) | little_endian;
7614
#else
7615
    ctx.mem_idx = (supervisor << 1) | little_endian;
7616
#endif
B
bellard 已提交
7617
    ctx.fpu_enabled = msr_fp;
7618
    if ((env->flags & POWERPC_FLAG_SPE) && msr_spe)
7619 7620 7621
        ctx.spe_enabled = msr_spe;
    else
        ctx.spe_enabled = 0;
7622 7623 7624 7625
    if ((env->flags & POWERPC_FLAG_VRE) && msr_vr)
        ctx.altivec_enabled = msr_vr;
    else
        ctx.altivec_enabled = 0;
7626
    if ((env->flags & POWERPC_FLAG_SE) && msr_se)
7627
        ctx.singlestep_enabled = CPU_SINGLE_STEP;
7628
    else
7629
        ctx.singlestep_enabled = 0;
7630
    if ((env->flags & POWERPC_FLAG_BE) && msr_be)
7631 7632 7633
        ctx.singlestep_enabled |= CPU_BRANCH_STEP;
    if (unlikely(env->singlestep_enabled))
        ctx.singlestep_enabled |= GDBSTUB_SINGLE_STEP;
7634
#if defined (DO_SINGLE_STEP) && 0
7635 7636 7637
    /* Single step trace mode */
    msr_se = 1;
#endif
P
pbrook 已提交
7638 7639 7640 7641 7642 7643
    num_insns = 0;
    max_insns = tb->cflags & CF_COUNT_MASK;
    if (max_insns == 0)
        max_insns = CF_COUNT_MASK;

    gen_icount_start();
7644
    /* Set env in case of segfault during code fetch */
7645
    while (ctx.exception == POWERPC_EXCP_NONE && gen_opc_ptr < gen_opc_end) {
7646 7647
        if (unlikely(!TAILQ_EMPTY(&env->breakpoints))) {
            TAILQ_FOREACH(bp, &env->breakpoints, entry) {
7648
                if (bp->pc == ctx.nip) {
7649
                    gen_update_nip(&ctx, ctx.nip);
7650
                    gen_helper_raise_debug();
7651 7652 7653 7654
                    break;
                }
            }
        }
7655
        if (unlikely(search_pc)) {
B
bellard 已提交
7656 7657 7658 7659 7660
            j = gen_opc_ptr - gen_opc_buf;
            if (lj < j) {
                lj++;
                while (lj < j)
                    gen_opc_instr_start[lj++] = 0;
B
bellard 已提交
7661
                gen_opc_pc[lj] = ctx.nip;
B
bellard 已提交
7662
                gen_opc_instr_start[lj] = 1;
P
pbrook 已提交
7663
                gen_opc_icount[lj] = num_insns;
B
bellard 已提交
7664 7665
            }
        }
7666 7667
#if defined PPC_DEBUG_DISAS
        if (loglevel & CPU_LOG_TB_IN_ASM) {
B
bellard 已提交
7668
            fprintf(logfile, "----------------\n");
7669
            fprintf(logfile, "nip=" ADDRX " super=%d ir=%d\n",
7670
                    ctx.nip, supervisor, (int)msr_ir);
7671 7672
        }
#endif
P
pbrook 已提交
7673 7674
        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
            gen_io_start();
7675 7676 7677 7678
        if (unlikely(little_endian)) {
            ctx.opcode = bswap32(ldl_code(ctx.nip));
        } else {
            ctx.opcode = ldl_code(ctx.nip);
7679
        }
7680 7681
#if defined PPC_DEBUG_DISAS
        if (loglevel & CPU_LOG_TB_IN_ASM) {
7682
            fprintf(logfile, "translate opcode %08x (%02x %02x %02x) (%s)\n",
7683
                    ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode),
7684
                    opc3(ctx.opcode), little_endian ? "little" : "big");
B
bellard 已提交
7685 7686
        }
#endif
B
bellard 已提交
7687
        ctx.nip += 4;
7688
        table = env->opcodes;
P
pbrook 已提交
7689
        num_insns++;
B
bellard 已提交
7690 7691 7692 7693 7694 7695 7696 7697 7698 7699
        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 ? */
7700
        if (unlikely(handler->handler == &gen_invalid)) {
J
j_mayer 已提交
7701
            if (loglevel != 0) {
7702
                fprintf(logfile, "invalid/unsupported opcode: "
7703
                        "%02x - %02x - %02x (%08x) " ADDRX " %d\n",
7704
                        opc1(ctx.opcode), opc2(ctx.opcode),
7705
                        opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, (int)msr_ir);
B
bellard 已提交
7706 7707
            } else {
                printf("invalid/unsupported opcode: "
7708
                       "%02x - %02x - %02x (%08x) " ADDRX " %d\n",
B
bellard 已提交
7709
                       opc1(ctx.opcode), opc2(ctx.opcode),
7710
                       opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, (int)msr_ir);
B
bellard 已提交
7711
            }
7712 7713
        } else {
            if (unlikely((ctx.opcode & handler->inval) != 0)) {
J
j_mayer 已提交
7714
                if (loglevel != 0) {
B
bellard 已提交
7715
                    fprintf(logfile, "invalid bits: %08x for opcode: "
7716
                            "%02x - %02x - %02x (%08x) " ADDRX "\n",
B
bellard 已提交
7717 7718
                            ctx.opcode & handler->inval, opc1(ctx.opcode),
                            opc2(ctx.opcode), opc3(ctx.opcode),
B
bellard 已提交
7719
                            ctx.opcode, ctx.nip - 4);
7720 7721
                } else {
                    printf("invalid bits: %08x for opcode: "
7722
                           "%02x - %02x - %02x (%08x) " ADDRX "\n",
7723 7724
                           ctx.opcode & handler->inval, opc1(ctx.opcode),
                           opc2(ctx.opcode), opc3(ctx.opcode),
B
bellard 已提交
7725
                           ctx.opcode, ctx.nip - 4);
7726
                }
7727
                GEN_EXCP_INVAL(ctxp);
B
bellard 已提交
7728
                break;
B
bellard 已提交
7729 7730
            }
        }
B
bellard 已提交
7731
        (*(handler->handler))(&ctx);
7732 7733 7734
#if defined(DO_PPC_STATISTICS)
        handler->count++;
#endif
7735
        /* Check trace mode exceptions */
7736 7737 7738 7739 7740
        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)) {
7741
            GEN_EXCP(ctxp, POWERPC_EXCP_TRACE, 0);
7742
        } else if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) ||
P
pbrook 已提交
7743 7744
                            (env->singlestep_enabled) ||
                            num_insns >= max_insns)) {
7745 7746 7747
            /* if we reach a page boundary or are single stepping, stop
             * generation
             */
7748
            break;
7749
        }
7750 7751 7752 7753
#if defined (DO_SINGLE_STEP)
        break;
#endif
    }
P
pbrook 已提交
7754 7755
    if (tb->cflags & CF_LAST_IO)
        gen_io_end();
7756
    if (ctx.exception == POWERPC_EXCP_NONE) {
7757
        gen_goto_tb(&ctx, 0, ctx.nip);
7758
    } else if (ctx.exception != POWERPC_EXCP_BRANCH) {
7759 7760
        if (unlikely(env->singlestep_enabled)) {
            gen_update_nip(&ctx, ctx.nip);
7761
            gen_helper_raise_debug();
7762
        }
7763
        /* Generate the return instruction */
B
bellard 已提交
7764
        tcg_gen_exit_tb(0);
7765
    }
P
pbrook 已提交
7766
    gen_icount_end(tb, num_insns);
B
bellard 已提交
7767
    *gen_opc_ptr = INDEX_op_end;
7768
    if (unlikely(search_pc)) {
7769 7770 7771 7772 7773
        j = gen_opc_ptr - gen_opc_buf;
        lj++;
        while (lj <= j)
            gen_opc_instr_start[lj++] = 0;
    } else {
B
bellard 已提交
7774
        tb->size = ctx.nip - pc_start;
P
pbrook 已提交
7775
        tb->icount = num_insns;
7776
    }
7777
#if defined(DEBUG_DISAS)
7778
    if (loglevel & CPU_LOG_TB_CPU) {
7779
        fprintf(logfile, "---------------- excp: %04x\n", ctx.exception);
B
bellard 已提交
7780
        cpu_dump_state(env, logfile, fprintf, 0);
7781 7782
    }
    if (loglevel & CPU_LOG_TB_IN_ASM) {
7783
        int flags;
7784
        flags = env->bfd_mach;
7785
        flags |= little_endian << 16;
B
bellard 已提交
7786
        fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
7787
        target_disas(logfile, pc_start, ctx.nip - pc_start, flags);
B
bellard 已提交
7788
        fprintf(logfile, "\n");
7789
    }
B
bellard 已提交
7790 7791 7792
#endif
}

7793
void gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
B
bellard 已提交
7794
{
7795
    gen_intermediate_code_internal(env, tb, 0);
B
bellard 已提交
7796 7797
}

7798
void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
B
bellard 已提交
7799
{
7800
    gen_intermediate_code_internal(env, tb, 1);
B
bellard 已提交
7801
}
A
aurel32 已提交
7802 7803 7804 7805 7806 7807

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