translate.c 277.4 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
}

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

/* Invalid instruction */
695 696
GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE)
{
697
    GEN_EXCP_INVAL(ctx);
698 699
}

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

706 707
/***                           Integer comparison                          ***/

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

712 713
    tcg_gen_trunc_tl_i32(cpu_crf[crf], cpu_xer);
    tcg_gen_shri_i32(cpu_crf[crf], cpu_crf[crf], XER_SO);
714 715 716 717 718 719
    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) {
720 721
        tcg_gen_brcond_tl(TCG_COND_LT, arg0, arg1, l1);
        tcg_gen_brcond_tl(TCG_COND_GT, arg0, arg1, l2);
722
    } else {
723 724
        tcg_gen_brcond_tl(TCG_COND_LTU, arg0, arg1, l1);
        tcg_gen_brcond_tl(TCG_COND_GTU, arg0, arg1, l2);
725 726 727 728 729 730 731 732 733 734 735
    }
    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);
}

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

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

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

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

    mask = 1 << (3 - (bi & 0x03));
P
pbrook 已提交
843
    t0 = tcg_temp_new_i32();
844 845
    tcg_gen_andi_i32(t0, cpu_crf[bi >> 2], mask);
    tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l1);
846 847 848 849 850 851 852 853
    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 已提交
854
    tcg_temp_free_i32(t0);
855 856
}

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

859 860 861 862
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 已提交
863

864 865 866
    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 已提交
867
    t0 = tcg_temp_local_new();
868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888
    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 已提交
889 890
}

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

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

901 902 903 904
        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 已提交
905
        } else {
906 907
            tcg_gen_brcond_tl(TCG_COND_GEU, t0, t1, l1);
        }
908 909 910 911
        tcg_gen_ori_tl(cpu_xer, cpu_xer, 1 << XER_CA);
        gen_set_label(l1);
        tcg_temp_free(t0);
        tcg_temp_free(t1);
912 913
    } else
#endif
914 915 916 917 918 919 920 921
    {
        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);
922
    }
923 924
}

925 926 927 928 929
/* 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;
930

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

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

944 945 946 947 948 949 950 951 952 953
    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 已提交
954

955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971
    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 已提交
972
    if (!TCGV_EQUAL(t0, ret)) {
973 974 975
        tcg_gen_mov_tl(ret, t0);
        tcg_temp_free(t0);
    }
A
aurel32 已提交
976
}
977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013
/* 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)
1014
{
1015 1016 1017 1018 1019 1020 1021 1022
    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);
    }
1023
}
1024 1025 1026
/* addic  addic.*/
static always_inline void gen_op_addic (DisasContext *ctx, TCGv ret, TCGv arg1,
                                        int compute_Rc0)
1027
{
1028 1029 1030 1031 1032 1033
    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 已提交
1034
        TCGv t0 = tcg_temp_local_new();
1035 1036 1037 1038 1039 1040 1041 1042 1043 1044
        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);
    }
1045
}
1046
GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
1047
{
1048
    gen_op_addic(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0);
1049
}
1050
GEN_HANDLER2(addic_, "addic.", 0x0D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
1051
{
1052
    gen_op_addic(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 1);
1053
}
1054 1055
/* addis */
GEN_HANDLER(addis, 0x0F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
1056
{
1057 1058 1059 1060 1061 1062 1063 1064
    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);
    }
1065
}
1066 1067 1068

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

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

    tcg_gen_brcondi_i64(TCG_COND_EQ, arg2, 0, l1);
    if (sign) {
1130
        int l3 = gen_new_label();
1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153
        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);
1154
}
1155 1156 1157
#define GEN_INT_ARITH_DIVD(name, opc3, sign, compute_ov)                      \
GEN_HANDLER(name, 0x1F, 0x09, opc3, 0x00000000, PPC_64B)                      \
{                                                                             \
1158 1159 1160
    gen_op_arith_divd(ctx, cpu_gpr[rD(ctx->opcode)],                          \
                      cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],     \
                      sign, compute_ov);                                      \
1161 1162 1163 1164 1165 1166 1167
}
/* 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);
1168
#endif
1169 1170 1171

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

P
pbrook 已提交
1175 1176
    t0 = tcg_temp_new_i64();
    t1 = tcg_temp_new_i64();
1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188
#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 已提交
1189 1190
    tcg_temp_free_i64(t0);
    tcg_temp_free_i64(t1);
1191 1192
    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
1193
}
1194 1195
/* mulhwu  mulhwu.  */
GEN_HANDLER(mulhwu, 0x1F, 0x0B, 0x00, 0x00000400, PPC_INTEGER)
1196
{
P
pbrook 已提交
1197
    TCGv_i64 t0, t1;
1198

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

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

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

/* 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 已提交
1335
{
1336
    TCGv t0, t1;
1337

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

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

1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368
    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 已提交
1369
    } else {
1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381
        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 已提交
1382
    if (!TCGV_EQUAL(t0, ret)) {
1383 1384
        tcg_gen_mov_tl(ret, t0);
        tcg_temp_free(t0);
B
bellard 已提交
1385 1386
    }
}
1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420
/* 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 已提交
1421 1422 1423
/* subfic */
GEN_HANDLER(subfic, 0x08, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
1424 1425
    /* Start with XER CA and OV disabled, the most likely case */
    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
P
pbrook 已提交
1426
    TCGv t0 = tcg_temp_local_new();
1427 1428 1429 1430 1431 1432
    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 已提交
1433 1434 1435
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

J
j_mayer 已提交
1893 1894
    sh = SH(ctx->opcode) | (shn << 5);
    mb = MB(ctx->opcode) | (mbn << 5);
1895
    me = 63 - sh;
1896 1897 1898 1899 1900 1901
    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 已提交
1902
        t0 = tcg_temp_new();
1903
        tcg_gen_rotli_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
P
pbrook 已提交
1904
        t1 = tcg_temp_new();
1905 1906 1907 1908 1909 1910
        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 已提交
1911 1912
    }
    if (unlikely(Rc(ctx->opcode) != 0))
1913
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
1914
}
1915
GEN_PPC64_R4(rldimi, 0x1E, 0x06);
1916 1917
#endif

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

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

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

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

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

/***                       Floating-Point arithmetic                       ***/
2087
#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat, set_fprf, type)           \
2088
GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, type)                        \
2089
{                                                                             \
2090
    if (unlikely(!ctx->fpu_enabled)) {                                        \
2091
        GEN_EXCP_NO_FP(ctx);                                                  \
B
bellard 已提交
2092 2093
        return;                                                               \
    }                                                                         \
2094
    gen_reset_fpstatus();                                                     \
A
aurel32 已提交
2095 2096
    gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)],      \
                     cpu_fpr[rC(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);     \
2097
    if (isfloat) {                                                            \
A
aurel32 已提交
2098
        gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]);  \
2099
    }                                                                         \
A
aurel32 已提交
2100 2101
    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], set_fprf,                      \
                     Rc(ctx->opcode) != 0);                                   \
2102 2103
}

2104 2105 2106
#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);
2107

2108 2109
#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat, set_fprf, type)     \
GEN_HANDLER(f##name, op1, op2, 0xFF, inval, type)                             \
2110
{                                                                             \
2111
    if (unlikely(!ctx->fpu_enabled)) {                                        \
2112
        GEN_EXCP_NO_FP(ctx);                                                  \
B
bellard 已提交
2113 2114
        return;                                                               \
    }                                                                         \
2115
    gen_reset_fpstatus();                                                     \
A
aurel32 已提交
2116 2117
    gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)],      \
                     cpu_fpr[rB(ctx->opcode)]);                               \
2118
    if (isfloat) {                                                            \
A
aurel32 已提交
2119
        gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]);  \
2120
    }                                                                         \
A
aurel32 已提交
2121 2122
    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)],                                \
                     set_fprf, Rc(ctx->opcode) != 0);                         \
2123
}
2124 2125 2126
#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);
2127

2128 2129
#define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat, set_fprf, type)     \
GEN_HANDLER(f##name, op1, op2, 0xFF, inval, type)                             \
2130
{                                                                             \
2131
    if (unlikely(!ctx->fpu_enabled)) {                                        \
2132
        GEN_EXCP_NO_FP(ctx);                                                  \
B
bellard 已提交
2133 2134
        return;                                                               \
    }                                                                         \
2135
    gen_reset_fpstatus();                                                     \
A
aurel32 已提交
2136 2137
    gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)],      \
                       cpu_fpr[rC(ctx->opcode)]);                             \
2138
    if (isfloat) {                                                            \
A
aurel32 已提交
2139
        gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]);  \
2140
    }                                                                         \
A
aurel32 已提交
2141 2142
    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)],                                \
                     set_fprf, Rc(ctx->opcode) != 0);                         \
2143
}
2144 2145 2146
#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);
2147

2148
#define GEN_FLOAT_B(name, op2, op3, set_fprf, type)                           \
2149
GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, type)                        \
2150
{                                                                             \
2151
    if (unlikely(!ctx->fpu_enabled)) {                                        \
2152
        GEN_EXCP_NO_FP(ctx);                                                  \
B
bellard 已提交
2153 2154
        return;                                                               \
    }                                                                         \
2155
    gen_reset_fpstatus();                                                     \
A
aurel32 已提交
2156 2157 2158
    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 已提交
2159 2160
}

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

2174
/* fadd - fadds */
2175
GEN_FLOAT_AB(add, 0x15, 0x000007C0, 1, PPC_FLOAT);
2176
/* fdiv - fdivs */
2177
GEN_FLOAT_AB(div, 0x12, 0x000007C0, 1, PPC_FLOAT);
2178
/* fmul - fmuls */
2179
GEN_FLOAT_AC(mul, 0x19, 0x0000F800, 1, PPC_FLOAT);
B
bellard 已提交
2180

2181
/* fre */
2182
GEN_FLOAT_BS(re, 0x3F, 0x18, 1, PPC_FLOAT_EXT);
2183

2184
/* fres */
2185
GEN_FLOAT_BS(res, 0x3B, 0x18, 1, PPC_FLOAT_FRES);
B
bellard 已提交
2186

2187
/* frsqrte */
2188 2189 2190
GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, 1, PPC_FLOAT_FRSQRTE);

/* frsqrtes */
A
aurel32 已提交
2191
GEN_HANDLER(frsqrtes, 0x3B, 0x1A, 0xFF, 0x001F07C0, PPC_FLOAT_FRSQRTES)
2192
{
A
aurel32 已提交
2193 2194 2195 2196 2197 2198 2199 2200
    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);
2201
}
B
bellard 已提交
2202

2203
/* fsel */
2204
_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0, 0, PPC_FLOAT_FSEL);
2205
/* fsub - fsubs */
2206
GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT);
B
bellard 已提交
2207 2208
/* Optional: */
/* fsqrt */
2209
GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT)
2210
{
2211
    if (unlikely(!ctx->fpu_enabled)) {
2212
        GEN_EXCP_NO_FP(ctx);
2213 2214
        return;
    }
2215
    gen_reset_fpstatus();
A
aurel32 已提交
2216 2217
    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);
2218
}
B
bellard 已提交
2219

2220
GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT)
B
bellard 已提交
2221
{
2222
    if (unlikely(!ctx->fpu_enabled)) {
2223
        GEN_EXCP_NO_FP(ctx);
B
bellard 已提交
2224 2225
        return;
    }
2226
    gen_reset_fpstatus();
A
aurel32 已提交
2227 2228 2229
    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 已提交
2230 2231 2232
}

/***                     Floating-Point multiply-and-add                   ***/
2233
/* fmadd - fmadds */
2234
GEN_FLOAT_ACB(madd, 0x1D, 1, PPC_FLOAT);
2235
/* fmsub - fmsubs */
2236
GEN_FLOAT_ACB(msub, 0x1C, 1, PPC_FLOAT);
2237
/* fnmadd - fnmadds */
2238
GEN_FLOAT_ACB(nmadd, 0x1F, 1, PPC_FLOAT);
2239
/* fnmsub - fnmsubs */
2240
GEN_FLOAT_ACB(nmsub, 0x1E, 1, PPC_FLOAT);
B
bellard 已提交
2241 2242 2243

/***                     Floating-Point round & convert                    ***/
/* fctiw */
2244
GEN_FLOAT_B(ctiw, 0x0E, 0x00, 0, PPC_FLOAT);
B
bellard 已提交
2245
/* fctiwz */
2246
GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT);
B
bellard 已提交
2247
/* frsp */
2248
GEN_FLOAT_B(rsp, 0x0C, 0x00, 1, PPC_FLOAT);
J
j_mayer 已提交
2249 2250
#if defined(TARGET_PPC64)
/* fcfid */
2251
GEN_FLOAT_B(cfid, 0x0E, 0x1A, 1, PPC_64B);
J
j_mayer 已提交
2252
/* fctid */
2253
GEN_FLOAT_B(ctid, 0x0E, 0x19, 0, PPC_64B);
J
j_mayer 已提交
2254
/* fctidz */
2255
GEN_FLOAT_B(ctidz, 0x0F, 0x19, 0, PPC_64B);
J
j_mayer 已提交
2256
#endif
B
bellard 已提交
2257

2258
/* frin */
2259
GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT);
2260
/* friz */
2261
GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT);
2262
/* frip */
2263
GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT);
2264
/* frim */
2265
GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT);
2266

B
bellard 已提交
2267 2268
/***                         Floating-Point compare                        ***/
/* fcmpo */
2269
GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT)
B
bellard 已提交
2270
{
2271
    if (unlikely(!ctx->fpu_enabled)) {
2272
        GEN_EXCP_NO_FP(ctx);
B
bellard 已提交
2273 2274
        return;
    }
2275
    gen_reset_fpstatus();
A
aurel32 已提交
2276 2277 2278
    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 已提交
2279 2280 2281
}

/* fcmpu */
2282
GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT)
B
bellard 已提交
2283
{
2284
    if (unlikely(!ctx->fpu_enabled)) {
2285
        GEN_EXCP_NO_FP(ctx);
B
bellard 已提交
2286 2287
        return;
    }
2288
    gen_reset_fpstatus();
A
aurel32 已提交
2289 2290 2291
    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 已提交
2292 2293
}

2294 2295
/***                         Floating-point move                           ***/
/* fabs */
2296 2297
/* XXX: beware that fabs never checks for NaNs nor update FPSCR */
GEN_FLOAT_B(abs, 0x08, 0x08, 0, PPC_FLOAT);
2298 2299

/* fmr  - fmr. */
2300
/* XXX: beware that fmr never checks for NaNs nor update FPSCR */
2301 2302
GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT)
{
2303
    if (unlikely(!ctx->fpu_enabled)) {
2304
        GEN_EXCP_NO_FP(ctx);
B
bellard 已提交
2305 2306
        return;
    }
A
aurel32 已提交
2307 2308
    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);
2309 2310 2311
}

/* fnabs */
2312 2313
/* XXX: beware that fnabs never checks for NaNs nor update FPSCR */
GEN_FLOAT_B(nabs, 0x08, 0x04, 0, PPC_FLOAT);
2314
/* fneg */
2315 2316
/* XXX: beware that fneg never checks for NaNs nor update FPSCR */
GEN_FLOAT_B(neg, 0x08, 0x01, 0, PPC_FLOAT);
2317

B
bellard 已提交
2318 2319 2320 2321
/***                  Floating-Point status & ctrl register                ***/
/* mcrfs */
GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT)
{
2322 2323
    int bfa;

2324
    if (unlikely(!ctx->fpu_enabled)) {
2325
        GEN_EXCP_NO_FP(ctx);
B
bellard 已提交
2326 2327
        return;
    }
2328 2329
    gen_optimize_fprf();
    bfa = 4 * (7 - crfS(ctx->opcode));
2330 2331
    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 已提交
2332
    tcg_gen_andi_i32(cpu_fpscr, cpu_fpscr, ~(0xF << bfa));
B
bellard 已提交
2333 2334 2335 2336 2337
}

/* mffs */
GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT)
{
2338
    if (unlikely(!ctx->fpu_enabled)) {
2339
        GEN_EXCP_NO_FP(ctx);
B
bellard 已提交
2340 2341
        return;
    }
2342 2343
    gen_optimize_fprf();
    gen_reset_fpstatus();
A
aurel32 已提交
2344 2345
    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 已提交
2346 2347 2348 2349 2350
}

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

2353
    if (unlikely(!ctx->fpu_enabled)) {
2354
        GEN_EXCP_NO_FP(ctx);
B
bellard 已提交
2355 2356
        return;
    }
2357 2358 2359 2360
    crb = 32 - (crbD(ctx->opcode) >> 2);
    gen_optimize_fprf();
    gen_reset_fpstatus();
    if (likely(crb != 30 && crb != 29))
A
aurel32 已提交
2361
        tcg_gen_andi_i32(cpu_fpscr, cpu_fpscr, ~(1 << crb));
2362
    if (unlikely(Rc(ctx->opcode) != 0)) {
2363
        tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX);
2364
    }
B
bellard 已提交
2365 2366 2367 2368 2369
}

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

2372
    if (unlikely(!ctx->fpu_enabled)) {
2373
        GEN_EXCP_NO_FP(ctx);
B
bellard 已提交
2374 2375
        return;
    }
2376 2377 2378 2379
    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 已提交
2380
    if (likely(crb != FPSCR_FEX && crb != FPSCR_VX && crb != FPSCR_NI)) {
2381
        TCGv_i32 t0 = tcg_const_i32(crb);
A
aurel32 已提交
2382
        gen_helper_fpscr_setbit(t0);
2383
        tcg_temp_free_i32(t0);
A
aurel32 已提交
2384
    }
2385
    if (unlikely(Rc(ctx->opcode) != 0)) {
2386
        tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX);
2387 2388
    }
    /* We can raise a differed exception */
A
aurel32 已提交
2389
    gen_helper_float_check_status();
B
bellard 已提交
2390 2391 2392 2393 2394
}

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

2397
    if (unlikely(!ctx->fpu_enabled)) {
2398
        GEN_EXCP_NO_FP(ctx);
B
bellard 已提交
2399 2400
        return;
    }
2401 2402
    gen_optimize_fprf();
    gen_reset_fpstatus();
A
aurel32 已提交
2403 2404
    t0 = tcg_const_i32(FM(ctx->opcode));
    gen_helper_store_fpscr(cpu_fpr[rB(ctx->opcode)], t0);
2405
    tcg_temp_free_i32(t0);
2406
    if (unlikely(Rc(ctx->opcode) != 0)) {
2407
        tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX);
2408 2409
    }
    /* We can raise a differed exception */
A
aurel32 已提交
2410
    gen_helper_float_check_status();
B
bellard 已提交
2411 2412 2413 2414 2415
}

/* mtfsfi */
GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT)
{
2416
    int bf, sh;
2417 2418
    TCGv_i64 t0;
    TCGv_i32 t1;
2419

2420
    if (unlikely(!ctx->fpu_enabled)) {
2421
        GEN_EXCP_NO_FP(ctx);
B
bellard 已提交
2422 2423
        return;
    }
2424 2425 2426 2427
    bf = crbD(ctx->opcode) >> 2;
    sh = 7 - bf;
    gen_optimize_fprf();
    gen_reset_fpstatus();
2428
    t0 = tcg_const_i64(FPIMM(ctx->opcode) << (4 * sh));
A
aurel32 已提交
2429 2430
    t1 = tcg_const_i32(1 << sh);
    gen_helper_store_fpscr(t0, t1);
2431 2432
    tcg_temp_free_i64(t0);
    tcg_temp_free_i32(t1);
2433
    if (unlikely(Rc(ctx->opcode) != 0)) {
2434
        tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX);
2435 2436
    }
    /* We can raise a differed exception */
A
aurel32 已提交
2437
    gen_helper_float_check_status();
B
bellard 已提交
2438 2439
}

2440 2441
/***                           Addressing modes                            ***/
/* Register indirect with immediate index : EA = (rA|0) + SIMM */
2442 2443
static always_inline void gen_addr_imm_index (TCGv EA,
                                              DisasContext *ctx,
2444
                                              target_long maskl)
2445 2446 2447
{
    target_long simm = SIMM(ctx->opcode);

2448
    simm &= ~maskl;
2449 2450 2451 2452 2453 2454
    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)]);
2455 2456
}

2457 2458
static always_inline void gen_addr_reg_index (TCGv EA,
                                              DisasContext *ctx)
2459
{
2460 2461 2462 2463
    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)]);
2464 2465
}

2466 2467
static always_inline void gen_addr_register (TCGv EA,
                                             DisasContext *ctx)
2468
{
2469 2470 2471 2472
    if (rA(ctx->opcode) == 0)
        tcg_gen_movi_tl(EA, 0);
    else
        tcg_gen_mov_tl(EA, cpu_gpr[rA(ctx->opcode)]);
2473 2474
}

2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492
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);
}

2493
/***                             Integer load                              ***/
A
aurel32 已提交
2494 2495 2496 2497 2498 2499 2500
#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 已提交
2501
        TCGv addr = tcg_temp_new();                                   \
A
aurel32 已提交
2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520
        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 已提交
2521
        TCGv addr = tcg_temp_new();                                   \
A
aurel32 已提交
2522 2523 2524 2525 2526 2527 2528 2529 2530 2531
        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)

2532
static always_inline void gen_qemu_ld8u(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2533
{
2534
    gen_qemu_ld8u_ppc64(arg0, arg1, flags);
A
aurel32 已提交
2535 2536
}

2537
static always_inline void gen_qemu_ld8s(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2538
{
2539
    gen_qemu_ld8s_ppc64(arg0, arg1, flags);
A
aurel32 已提交
2540 2541
}

2542
static always_inline void gen_qemu_ld16u(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2543 2544
{
    if (unlikely(flags & 1)) {
P
pbrook 已提交
2545
        TCGv_i32 t0;
2546
        gen_qemu_ld16u_ppc64(arg0, arg1, flags);
P
pbrook 已提交
2547
        t0 = tcg_temp_new_i32();
2548 2549 2550
        tcg_gen_trunc_tl_i32(t0, arg0);
        tcg_gen_bswap16_i32(t0, t0);
        tcg_gen_extu_i32_tl(arg0, t0);
P
pbrook 已提交
2551
        tcg_temp_free_i32(t0);
A
aurel32 已提交
2552
    } else
2553
        gen_qemu_ld16u_ppc64(arg0, arg1, flags);
A
aurel32 已提交
2554 2555
}

2556
static always_inline void gen_qemu_ld16s(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2557 2558
{
    if (unlikely(flags & 1)) {
P
pbrook 已提交
2559
        TCGv_i32 t0;
2560
        gen_qemu_ld16u_ppc64(arg0, arg1, flags);
P
pbrook 已提交
2561
        t0 = tcg_temp_new_i32();
2562 2563 2564 2565
        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 已提交
2566
        tcg_temp_free_i32(t0);
A
aurel32 已提交
2567
    } else
2568
        gen_qemu_ld16s_ppc64(arg0, arg1, flags);
A
aurel32 已提交
2569 2570
}

2571
static always_inline void gen_qemu_ld32u(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2572 2573
{
    if (unlikely(flags & 1)) {
P
pbrook 已提交
2574
        TCGv_i32 t0;
2575
        gen_qemu_ld32u_ppc64(arg0, arg1, flags);
P
pbrook 已提交
2576
        t0 = tcg_temp_new_i32();
2577 2578 2579
        tcg_gen_trunc_tl_i32(t0, arg0);
        tcg_gen_bswap_i32(t0, t0);
        tcg_gen_extu_i32_tl(arg0, t0);
P
pbrook 已提交
2580
        tcg_temp_free_i32(t0);
A
aurel32 已提交
2581
    } else
2582
        gen_qemu_ld32u_ppc64(arg0, arg1, flags);
A
aurel32 已提交
2583 2584
}

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

2599
static always_inline void gen_qemu_ld64(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2600
{
2601
    gen_qemu_ld64_ppc64(arg0, arg1, flags);
A
aurel32 已提交
2602
    if (unlikely(flags & 1))
2603
        tcg_gen_bswap_i64(arg0, arg0);
A
aurel32 已提交
2604 2605
}

2606
static always_inline void gen_qemu_st8(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2607
{
2608
    gen_qemu_st8_ppc64(arg0, arg1, flags);
A
aurel32 已提交
2609 2610
}

2611
static always_inline void gen_qemu_st16(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2612 2613
{
    if (unlikely(flags & 1)) {
P
pbrook 已提交
2614 2615 2616
        TCGv_i32 t0;
        TCGv_i64 t1;
        t0 = tcg_temp_new_i32();
2617 2618 2619
        tcg_gen_trunc_tl_i32(t0, arg0);
        tcg_gen_ext16u_i32(t0, t0);
        tcg_gen_bswap16_i32(t0, t0);
P
pbrook 已提交
2620
        t1 = tcg_temp_new_i64();
2621
        tcg_gen_extu_i32_tl(t1, t0);
P
pbrook 已提交
2622
        tcg_temp_free_i32(t0);
2623
        gen_qemu_st16_ppc64(t1, arg1, flags);
P
pbrook 已提交
2624
        tcg_temp_free_i64(t1);
A
aurel32 已提交
2625
    } else
2626
        gen_qemu_st16_ppc64(arg0, arg1, flags);
A
aurel32 已提交
2627 2628
}

2629
static always_inline void gen_qemu_st32(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2630 2631
{
    if (unlikely(flags & 1)) {
P
pbrook 已提交
2632 2633 2634
        TCGv_i32 t0;
        TCGv_i64 t1;
        t0 = tcg_temp_new_i32();
2635 2636
        tcg_gen_trunc_tl_i32(t0, arg0);
        tcg_gen_bswap_i32(t0, t0);
P
pbrook 已提交
2637
        t1 = tcg_temp_new_i64();
2638
        tcg_gen_extu_i32_tl(t1, t0);
P
pbrook 已提交
2639
        tcg_temp_free_i32(t0);
2640
        gen_qemu_st32_ppc64(t1, arg1, flags);
P
pbrook 已提交
2641
        tcg_temp_free_i64(t1);
A
aurel32 已提交
2642
    } else
2643
        gen_qemu_st32_ppc64(arg0, arg1, flags);
A
aurel32 已提交
2644 2645
}

2646
static always_inline void gen_qemu_st64(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2647 2648
{
    if (unlikely(flags & 1)) {
P
pbrook 已提交
2649
        TCGv_i64 t0 = tcg_temp_new_i64();
2650 2651
        tcg_gen_bswap_i64(t0, arg0);
        gen_qemu_st64_ppc64(t0, arg1, flags);
P
pbrook 已提交
2652
        tcg_temp_free_i64(t0);
A
aurel32 已提交
2653
    } else
2654
        gen_qemu_st64_ppc64(arg0, arg1, flags);
A
aurel32 已提交
2655 2656 2657 2658
}


#else /* defined(TARGET_PPC64) */
2659 2660 2661 2662
#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 已提交
2663 2664 2665 2666 2667 2668 2669
}
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)
2670 2671 2672 2673
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 已提交
2674

2675 2676 2677 2678
#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 已提交
2679 2680 2681 2682
}
GEN_QEMU_ST_PPC32(8)
GEN_QEMU_ST_PPC32(16)
GEN_QEMU_ST_PPC32(32)
2683 2684 2685 2686
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 已提交
2687

2688
static always_inline void gen_qemu_ld8u(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2689
{
2690
    gen_qemu_ld8u_ppc32(arg0, arg1, flags >> 1);
A
aurel32 已提交
2691 2692
}

2693
static always_inline void gen_qemu_ld8s(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2694
{
2695
    gen_qemu_ld8s_ppc32(arg0, arg1, flags >> 1);
A
aurel32 已提交
2696 2697
}

2698
static always_inline void gen_qemu_ld16u(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2699
{
2700
    gen_qemu_ld16u_ppc32(arg0, arg1, flags >> 1);
A
aurel32 已提交
2701
    if (unlikely(flags & 1))
2702
        tcg_gen_bswap16_i32(arg0, arg0);
A
aurel32 已提交
2703 2704
}

2705
static always_inline void gen_qemu_ld16s(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2706 2707
{
    if (unlikely(flags & 1)) {
2708 2709 2710
        gen_qemu_ld16u_ppc32(arg0, arg1, flags);
        tcg_gen_bswap16_i32(arg0, arg0);
        tcg_gen_ext16s_i32(arg0, arg0);
A
aurel32 已提交
2711
    } else
2712
        gen_qemu_ld16s_ppc32(arg0, arg1, flags);
A
aurel32 已提交
2713 2714
}

2715
static always_inline void gen_qemu_ld32u(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2716
{
2717
    gen_qemu_ld32u_ppc32(arg0, arg1, flags);
A
aurel32 已提交
2718
    if (unlikely(flags & 1))
2719
        tcg_gen_bswap_i32(arg0, arg0);
A
aurel32 已提交
2720 2721
}

2722 2723 2724 2725 2726 2727 2728
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);
}

2729
static always_inline void gen_qemu_st8(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2730
{
2731
    gen_qemu_st8_ppc32(arg0, arg1, flags);
A
aurel32 已提交
2732 2733
}

2734
static always_inline void gen_qemu_st16(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2735 2736
{
    if (unlikely(flags & 1)) {
P
pbrook 已提交
2737
        TCGv_i32 temp = tcg_temp_new_i32();
2738
        tcg_gen_ext16u_i32(temp, arg0);
A
aurel32 已提交
2739
        tcg_gen_bswap16_i32(temp, temp);
2740
        gen_qemu_st16_ppc32(temp, arg1, flags);
P
pbrook 已提交
2741
        tcg_temp_free_i32(temp);
A
aurel32 已提交
2742
    } else
2743
        gen_qemu_st16_ppc32(arg0, arg1, flags);
A
aurel32 已提交
2744 2745
}

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

2757 2758 2759 2760 2761 2762 2763 2764 2765 2766
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 已提交
2767 2768
#endif

2769 2770
#define GEN_LD(name, ldop, opc, type)                                         \
GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type)                          \
B
bellard 已提交
2771
{                                                                             \
2772
    TCGv EA = tcg_temp_new();                                                 \
A
aurel32 已提交
2773
    gen_set_access_type(ACCESS_INT);                                          \
A
aurel32 已提交
2774
    gen_addr_imm_index(EA, ctx, 0);                                           \
2775
    gen_qemu_##ldop(cpu_gpr[rD(ctx->opcode)], EA, ctx->mem_idx);              \
A
aurel32 已提交
2776
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2777 2778
}

2779 2780
#define GEN_LDU(name, ldop, opc, type)                                        \
GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type)                       \
B
bellard 已提交
2781
{                                                                             \
A
aurel32 已提交
2782
    TCGv EA;                                                                  \
2783 2784
    if (unlikely(rA(ctx->opcode) == 0 ||                                      \
                 rA(ctx->opcode) == rD(ctx->opcode))) {                       \
2785
        GEN_EXCP_INVAL(ctx);                                                  \
2786
        return;                                                               \
2787
    }                                                                         \
2788
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
2789
    gen_set_access_type(ACCESS_INT);                                          \
J
j_mayer 已提交
2790
    if (type == PPC_64B)                                                      \
A
aurel32 已提交
2791
        gen_addr_imm_index(EA, ctx, 0x03);                                    \
J
j_mayer 已提交
2792
    else                                                                      \
A
aurel32 已提交
2793
        gen_addr_imm_index(EA, ctx, 0);                                       \
2794
    gen_qemu_##ldop(cpu_gpr[rD(ctx->opcode)], EA, ctx->mem_idx);              \
A
aurel32 已提交
2795 2796
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2797 2798
}

2799 2800
#define GEN_LDUX(name, ldop, opc2, opc3, type)                                \
GEN_HANDLER(name##ux, 0x1F, opc2, opc3, 0x00000001, type)                     \
B
bellard 已提交
2801
{                                                                             \
A
aurel32 已提交
2802
    TCGv EA;                                                                  \
2803 2804
    if (unlikely(rA(ctx->opcode) == 0 ||                                      \
                 rA(ctx->opcode) == rD(ctx->opcode))) {                       \
2805
        GEN_EXCP_INVAL(ctx);                                                  \
2806
        return;                                                               \
2807
    }                                                                         \
2808
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
2809
    gen_set_access_type(ACCESS_INT);                                          \
A
aurel32 已提交
2810
    gen_addr_reg_index(EA, ctx);                                              \
2811
    gen_qemu_##ldop(cpu_gpr[rD(ctx->opcode)], EA, ctx->mem_idx);              \
A
aurel32 已提交
2812 2813
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2814 2815
}

2816 2817
#define GEN_LDX(name, ldop, opc2, opc3, type)                                 \
GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type)                      \
B
bellard 已提交
2818
{                                                                             \
2819
    TCGv 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
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2824 2825
}

2826 2827 2828 2829 2830
#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 已提交
2831 2832

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

    /* 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 已提交
2898
    EA = tcg_temp_new();
A
aurel32 已提交
2899
    gen_set_access_type(ACCESS_INT);
A
aurel32 已提交
2900 2901 2902 2903 2904
    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);
2905 2906
#endif
}
2907
#endif
B
bellard 已提交
2908 2909

/***                              Integer store                            ***/
2910 2911
#define GEN_ST(name, stop, opc, type)                                         \
GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type)                          \
B
bellard 已提交
2912
{                                                                             \
2913
    TCGv EA = tcg_temp_new();                                                 \
A
aurel32 已提交
2914
    gen_set_access_type(ACCESS_INT);                                          \
A
aurel32 已提交
2915
    gen_addr_imm_index(EA, ctx, 0);                                           \
2916
    gen_qemu_##stop(cpu_gpr[rS(ctx->opcode)], EA, ctx->mem_idx);              \
A
aurel32 已提交
2917
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2918 2919
}

2920 2921
#define GEN_STU(name, stop, opc, type)                                        \
GEN_HANDLER(stop##u, opc, 0xFF, 0xFF, 0x00000000, type)                       \
B
bellard 已提交
2922
{                                                                             \
A
aurel32 已提交
2923
    TCGv EA;                                                                  \
2924
    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
2925
        GEN_EXCP_INVAL(ctx);                                                  \
2926
        return;                                                               \
2927
    }                                                                         \
2928
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
2929
    gen_set_access_type(ACCESS_INT);                                          \
J
j_mayer 已提交
2930
    if (type == PPC_64B)                                                      \
A
aurel32 已提交
2931
        gen_addr_imm_index(EA, ctx, 0x03);                                    \
J
j_mayer 已提交
2932
    else                                                                      \
A
aurel32 已提交
2933
        gen_addr_imm_index(EA, ctx, 0);                                       \
2934
    gen_qemu_##stop(cpu_gpr[rS(ctx->opcode)], EA, ctx->mem_idx);              \
A
aurel32 已提交
2935 2936
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2937 2938
}

2939 2940
#define GEN_STUX(name, stop, opc2, opc3, type)                                \
GEN_HANDLER(name##ux, 0x1F, opc2, opc3, 0x00000001, type)                     \
B
bellard 已提交
2941
{                                                                             \
A
aurel32 已提交
2942
    TCGv EA;                                                                  \
2943
    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
2944
        GEN_EXCP_INVAL(ctx);                                                  \
2945
        return;                                                               \
2946
    }                                                                         \
2947
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
2948
    gen_set_access_type(ACCESS_INT);                                          \
A
aurel32 已提交
2949
    gen_addr_reg_index(EA, ctx);                                              \
2950
    gen_qemu_##stop(cpu_gpr[rS(ctx->opcode)], EA, ctx->mem_idx);              \
A
aurel32 已提交
2951 2952
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2953 2954
}

2955 2956
#define GEN_STX(name, stop, opc2, opc3, type)                                 \
GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type)                      \
B
bellard 已提交
2957
{                                                                             \
2958
    TCGv 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
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2963 2964
}

2965 2966 2967 2968 2969
#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 已提交
2970 2971

/* stb stbu stbux stbx */
2972
GEN_STS(stb, st8, 0x06, PPC_INTEGER);
B
bellard 已提交
2973
/* sth sthu sthux sthx */
2974
GEN_STS(sth, st16, 0x0C, PPC_INTEGER);
B
bellard 已提交
2975
/* stw stwu stwux stwx */
2976
GEN_STS(stw, st32, 0x04, PPC_INTEGER);
2977
#if defined(TARGET_PPC64)
2978 2979
GEN_STUX(std, st64, 0x15, 0x05, PPC_64B);
GEN_STX(std, st64, 0x15, 0x04, PPC_64B);
2980
GEN_HANDLER(std, 0x3E, 0xFF, 0xFF, 0x00000000, PPC_64B)
2981
{
2982
    int rs;
A
aurel32 已提交
2983
    TCGv EA;
2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995

    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)) {
2996
            GEN_EXCP_INVAL(ctx);
2997 2998
            return;
        }
2999 3000 3001 3002 3003
        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 已提交
3004
        EA = tcg_temp_new();
A
aurel32 已提交
3005
        gen_set_access_type(ACCESS_INT);
A
aurel32 已提交
3006 3007 3008 3009 3010
        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);
3011 3012 3013 3014 3015 3016 3017 3018 3019
#endif
    } else {
        /* std / stdu */
        if (Rc(ctx->opcode)) {
            if (unlikely(rA(ctx->opcode) == 0)) {
                GEN_EXCP_INVAL(ctx);
                return;
            }
        }
P
pbrook 已提交
3020
        EA = tcg_temp_new();
A
aurel32 已提交
3021
        gen_set_access_type(ACCESS_INT);
A
aurel32 已提交
3022 3023
        gen_addr_imm_index(EA, ctx, 0x03);
        gen_qemu_st64(cpu_gpr[rs], EA, ctx->mem_idx);
3024
        if (Rc(ctx->opcode))
A
aurel32 已提交
3025 3026
            tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);
        tcg_temp_free(EA);
3027 3028 3029
    }
}
#endif
B
bellard 已提交
3030 3031
/***                Integer load and store with byte reverse               ***/
/* lhbrx */
A
aurel32 已提交
3032 3033
void always_inline gen_qemu_ld16ur(TCGv t0, TCGv t1, int flags)
{
P
pbrook 已提交
3034 3035 3036
    TCGv_i32 temp = tcg_temp_new_i32();
    gen_qemu_ld16u(t0, t1, flags);
    tcg_gen_trunc_tl_i32(temp, t0);
A
aurel32 已提交
3037 3038
    tcg_gen_bswap16_i32(temp, temp);
    tcg_gen_extu_i32_tl(t0, temp);
P
pbrook 已提交
3039
    tcg_temp_free_i32(temp);
A
aurel32 已提交
3040
}
3041
GEN_LDX(lhbr, ld16ur, 0x16, 0x18, PPC_INTEGER);
A
aurel32 已提交
3042

B
bellard 已提交
3043
/* lwbrx */
A
aurel32 已提交
3044 3045
void always_inline gen_qemu_ld32ur(TCGv t0, TCGv t1, int flags)
{
P
pbrook 已提交
3046 3047 3048
    TCGv_i32 temp = tcg_temp_new_i32();
    gen_qemu_ld32u(t0, t1, flags);
    tcg_gen_trunc_tl_i32(temp, t0);
A
aurel32 已提交
3049 3050
    tcg_gen_bswap_i32(temp, temp);
    tcg_gen_extu_i32_tl(t0, temp);
P
pbrook 已提交
3051
    tcg_temp_free_i32(temp);
A
aurel32 已提交
3052
}
3053
GEN_LDX(lwbr, ld32ur, 0x16, 0x10, PPC_INTEGER);
A
aurel32 已提交
3054

B
bellard 已提交
3055
/* sthbrx */
A
aurel32 已提交
3056 3057
void always_inline gen_qemu_st16r(TCGv t0, TCGv t1, int flags)
{
P
pbrook 已提交
3058 3059
    TCGv_i32 temp = tcg_temp_new_i32();
    TCGv t2 = tcg_temp_new();
A
aurel32 已提交
3060 3061 3062
    tcg_gen_trunc_tl_i32(temp, t0);
    tcg_gen_ext16u_i32(temp, temp);
    tcg_gen_bswap16_i32(temp, temp);
P
pbrook 已提交
3063 3064 3065 3066
    tcg_gen_extu_i32_tl(t2, temp);
    tcg_temp_free_i32(temp);
    gen_qemu_st16(t2, t1, flags);
    tcg_temp_free(t2);
A
aurel32 已提交
3067
}
3068
GEN_STX(sthbr, st16r, 0x16, 0x1C, PPC_INTEGER);
A
aurel32 已提交
3069

B
bellard 已提交
3070
/* stwbrx */
A
aurel32 已提交
3071 3072
void always_inline gen_qemu_st32r(TCGv t0, TCGv t1, int flags)
{
P
pbrook 已提交
3073 3074
    TCGv_i32 temp = tcg_temp_new_i32();
    TCGv t2 = tcg_temp_new();
A
aurel32 已提交
3075 3076
    tcg_gen_trunc_tl_i32(temp, t0);
    tcg_gen_bswap_i32(temp, temp);
P
pbrook 已提交
3077 3078
    tcg_gen_extu_i32_tl(t2, temp);
    tcg_temp_free_i32(temp);
3079
    gen_qemu_st32(t2, t1, flags);
P
pbrook 已提交
3080
    tcg_temp_free(t2);
A
aurel32 已提交
3081
}
3082
GEN_STX(stwbr, st32r, 0x16, 0x14, PPC_INTEGER);
B
bellard 已提交
3083 3084 3085 3086 3087

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

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

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

    if (nb == 0)
        nb = 32;
    nr = nb / 4;
3130 3131 3132
    if (unlikely(((start + nr) > 32  &&
                  start <= ra && (start + nr - 32) > ra) ||
                 ((start + nr) <= 32 && start <= ra && (start + nr) > ra))) {
3133 3134
        GEN_EXCP(ctx, POWERPC_EXCP_PROGRAM,
                 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_LSWX);
3135
        return;
B
bellard 已提交
3136
    }
3137
    /* NIP cannot be restored if the memory exception comes from an helper */
3138
    gen_update_nip(ctx, ctx->nip - 4);
3139 3140 3141 3142 3143 3144 3145 3146
    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 已提交
3147 3148 3149
}

/* lswx */
3150
GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001, PPC_STRING)
B
bellard 已提交
3151
{
3152 3153 3154 3155
    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));
3156
    /* NIP cannot be restored if the memory exception comes from an helper */
3157
    gen_update_nip(ctx, ctx->nip - 4);
3158 3159 3160 3161 3162 3163
    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 已提交
3164 3165 3166
}

/* stswi */
3167
GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_STRING)
B
bellard 已提交
3168
{
B
bellard 已提交
3169
    int nb = NB(ctx->opcode);
3170 3171 3172
    TCGv t0 = tcg_temp_new();
    TCGv_i32 t1;
    TCGv_i32 t2 = tcg_const_i32(rS(ctx->opcode));
3173
    /* NIP cannot be restored if the memory exception comes from an helper */
3174
    gen_update_nip(ctx, ctx->nip - 4);
3175
    gen_addr_register(t0, ctx);
B
bellard 已提交
3176 3177
    if (nb == 0)
        nb = 32;
3178 3179 3180 3181 3182
    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 已提交
3183 3184 3185
}

/* stswx */
3186
GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_STRING)
B
bellard 已提交
3187
{
3188 3189 3190
    TCGv t0 = tcg_temp_new();
    TCGv_i32 t1 = tcg_temp_new_i32();
    TCGv_i32 t2 = tcg_const_i32(rS(ctx->opcode));
3191
    /* NIP cannot be restored if the memory exception comes from an helper */
3192
    gen_update_nip(ctx, ctx->nip - 4);
3193 3194 3195 3196 3197 3198 3199
    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 已提交
3200 3201 3202 3203
}

/***                        Memory synchronisation                         ***/
/* eieio */
3204
GEN_HANDLER(eieio, 0x1F, 0x16, 0x1A, 0x03FFF801, PPC_MEM_EIEIO)
B
bellard 已提交
3205 3206 3207 3208
{
}

/* isync */
3209
GEN_HANDLER(isync, 0x13, 0x16, 0x04, 0x03FFF801, PPC_MEM)
B
bellard 已提交
3210
{
3211
    GEN_STOP(ctx);
B
bellard 已提交
3212 3213
}

3214
/* lwarx */
3215
GEN_HANDLER(lwarx, 0x1F, 0x14, 0x00, 0x00000001, PPC_RES)
B
bellard 已提交
3216
{
3217
    TCGv t0 = tcg_temp_local_new();
A
aurel32 已提交
3218
    gen_set_access_type(ACCESS_RES);
3219 3220 3221 3222 3223 3224 3225 3226 3227
    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 已提交
3228 3229 3230
}

/* stwcx. */
3231
GEN_HANDLER2(stwcx_, "stwcx.", 0x1F, 0x16, 0x04, 0x00000000, PPC_RES)
B
bellard 已提交
3232
{
3233 3234
    int l1 = gen_new_label();
    TCGv t0 = tcg_temp_local_new();
A
aurel32 已提交
3235
    gen_set_access_type(ACCESS_RES);
3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250
    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 已提交
3251 3252
}

J
j_mayer 已提交
3253 3254
#if defined(TARGET_PPC64)
/* ldarx */
3255
GEN_HANDLER(ldarx, 0x1F, 0x14, 0x02, 0x00000001, PPC_64B)
J
j_mayer 已提交
3256
{
3257
    TCGv t0 = tcg_temp_local_new();
A
aurel32 已提交
3258
    gen_set_access_type(ACCESS_RES);
3259 3260 3261 3262 3263 3264 3265
    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 已提交
3266 3267 3268
}

/* stdcx. */
3269
GEN_HANDLER2(stdcx_, "stdcx.", 0x1F, 0x16, 0x06, 0x00000000, PPC_64B)
J
j_mayer 已提交
3270
{
3271 3272
    int l1 = gen_new_label();
    TCGv t0 = tcg_temp_local_new();
A
aurel32 已提交
3273
    gen_set_access_type(ACCESS_RES);
3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286
    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 已提交
3287 3288 3289
}
#endif /* defined(TARGET_PPC64) */

B
bellard 已提交
3290
/* sync */
3291
GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x039FF801, PPC_MEM_SYNC)
B
bellard 已提交
3292 3293 3294
{
}

3295 3296 3297
/* wait */
GEN_HANDLER(wait, 0x1F, 0x1E, 0x01, 0x03FFF801, PPC_WAIT)
{
3298 3299 3300
    TCGv_i32 t0 = tcg_temp_new_i32();
    tcg_gen_st_i32(t0, cpu_env, offsetof(CPUState, halted));
    tcg_temp_free_i32(t0);
3301
    /* Stop translation, as the CPU is supposed to sleep from now */
3302
    GEN_EXCP(ctx, EXCP_HLT, 1);
3303 3304
}

B
bellard 已提交
3305
/***                         Floating-point load                           ***/
3306 3307
#define GEN_LDF(name, ldop, opc, type)                                        \
GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type)                          \
B
bellard 已提交
3308
{                                                                             \
3309
    TCGv EA;                                                                  \
3310
    if (unlikely(!ctx->fpu_enabled)) {                                        \
3311
        GEN_EXCP_NO_FP(ctx);                                                  \
3312 3313
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
3314
    gen_set_access_type(ACCESS_FLOAT);                                        \
3315 3316 3317 3318
    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 已提交
3319 3320
}

3321 3322
#define GEN_LDUF(name, ldop, opc, type)                                       \
GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type)                       \
B
bellard 已提交
3323
{                                                                             \
3324
    TCGv EA;                                                                  \
3325
    if (unlikely(!ctx->fpu_enabled)) {                                        \
3326
        GEN_EXCP_NO_FP(ctx);                                                  \
3327 3328
        return;                                                               \
    }                                                                         \
3329
    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
3330
        GEN_EXCP_INVAL(ctx);                                                  \
3331
        return;                                                               \
3332
    }                                                                         \
A
aurel32 已提交
3333
    gen_set_access_type(ACCESS_FLOAT);                                        \
3334 3335 3336 3337 3338
    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 已提交
3339 3340
}

3341 3342
#define GEN_LDUXF(name, ldop, opc, type)                                      \
GEN_HANDLER(name##ux, 0x1F, 0x17, opc, 0x00000001, type)                      \
B
bellard 已提交
3343
{                                                                             \
3344
    TCGv EA;                                                                  \
3345
    if (unlikely(!ctx->fpu_enabled)) {                                        \
3346
        GEN_EXCP_NO_FP(ctx);                                                  \
3347 3348
        return;                                                               \
    }                                                                         \
3349
    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
3350
        GEN_EXCP_INVAL(ctx);                                                  \
3351
        return;                                                               \
3352
    }                                                                         \
A
aurel32 已提交
3353
    gen_set_access_type(ACCESS_FLOAT);                                        \
3354 3355 3356 3357 3358
    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 已提交
3359 3360
}

3361 3362
#define GEN_LDXF(name, ldop, opc2, opc3, type)                                \
GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type)                      \
B
bellard 已提交
3363
{                                                                             \
3364
    TCGv EA;                                                                  \
3365
    if (unlikely(!ctx->fpu_enabled)) {                                        \
3366
        GEN_EXCP_NO_FP(ctx);                                                  \
3367 3368
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
3369
    gen_set_access_type(ACCESS_FLOAT);                                        \
3370 3371 3372 3373
    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 已提交
3374 3375
}

3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391
#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 已提交
3392

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

/***                         Floating-point store                          ***/
3399 3400
#define GEN_STF(name, stop, opc, type)                                        \
GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type)                          \
B
bellard 已提交
3401
{                                                                             \
3402
    TCGv EA;                                                                  \
3403
    if (unlikely(!ctx->fpu_enabled)) {                                        \
3404
        GEN_EXCP_NO_FP(ctx);                                                  \
3405 3406
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
3407
    gen_set_access_type(ACCESS_FLOAT);                                        \
3408 3409 3410 3411
    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 已提交
3412 3413
}

3414 3415
#define GEN_STUF(name, stop, opc, type)                                       \
GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type)                       \
B
bellard 已提交
3416
{                                                                             \
3417
    TCGv EA;                                                                  \
3418
    if (unlikely(!ctx->fpu_enabled)) {                                        \
3419
        GEN_EXCP_NO_FP(ctx);                                                  \
3420 3421
        return;                                                               \
    }                                                                         \
3422
    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
3423
        GEN_EXCP_INVAL(ctx);                                                  \
3424
        return;                                                               \
3425
    }                                                                         \
A
aurel32 已提交
3426
    gen_set_access_type(ACCESS_FLOAT);                                        \
3427 3428 3429 3430 3431
    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 已提交
3432 3433
}

3434 3435
#define GEN_STUXF(name, stop, opc, type)                                      \
GEN_HANDLER(name##ux, 0x1F, 0x17, opc, 0x00000001, type)                      \
B
bellard 已提交
3436
{                                                                             \
3437
    TCGv EA;                                                                  \
3438
    if (unlikely(!ctx->fpu_enabled)) {                                        \
3439
        GEN_EXCP_NO_FP(ctx);                                                  \
3440 3441
        return;                                                               \
    }                                                                         \
3442
    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
3443
        GEN_EXCP_INVAL(ctx);                                                  \
3444
        return;                                                               \
3445
    }                                                                         \
A
aurel32 已提交
3446
    gen_set_access_type(ACCESS_FLOAT);                                        \
3447 3448 3449 3450 3451
    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 已提交
3452 3453
}

3454 3455
#define GEN_STXF(name, stop, opc2, opc3, type)                                \
GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type)                      \
B
bellard 已提交
3456
{                                                                             \
3457
    TCGv EA;                                                                  \
3458
    if (unlikely(!ctx->fpu_enabled)) {                                        \
3459
        GEN_EXCP_NO_FP(ctx);                                                  \
3460 3461
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
3462
    gen_set_access_type(ACCESS_FLOAT);                                        \
3463 3464 3465 3466
    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 已提交
3467 3468
}

3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484
#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 已提交
3485 3486

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

/* Optional: */
3492 3493 3494 3495 3496 3497 3498
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 已提交
3499
/* stfiwx */
3500
GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX);
B
bellard 已提交
3501 3502

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

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

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

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

3569 3570 3571 3572
#define BCOND_IM  0
#define BCOND_LR  1
#define BCOND_CTR 2

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

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

3617
        if (bo & 0x8) {
3618 3619
            tcg_gen_andi_i32(temp, cpu_crf[bi >> 2], mask);
            tcg_gen_brcondi_i32(TCG_COND_EQ, temp, 0, l1);
3620
        } else {
3621 3622
            tcg_gen_andi_i32(temp, cpu_crf[bi >> 2], mask);
            tcg_gen_brcondi_i32(TCG_COND_NE, temp, 0, l1);
3623
        }
P
pbrook 已提交
3624
        tcg_temp_free_i32(temp);
3625
    }
3626
    if (type == BCOND_IM) {
3627 3628 3629 3630 3631 3632
        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 已提交
3633
        gen_set_label(l1);
3634
        gen_goto_tb(ctx, 1, ctx->nip);
3635
    } else {
3636
#if defined(TARGET_PPC64)
3637 3638 3639 3640 3641 3642 3643 3644 3645 3646
        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);
3647 3648
        else
#endif
3649
            tcg_gen_movi_tl(cpu_nip, ctx->nip);
B
bellard 已提交
3650
        tcg_gen_exit_tb(0);
J
j_mayer 已提交
3651
    }
3652 3653 3654
}

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

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

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

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

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

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

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

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

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

    lev = (ctx->opcode >> 5) & 0x7F;
3783
    GEN_EXCP(ctx, POWERPC_SYSCALL, lev);
B
bellard 已提交
3784 3785 3786 3787
}

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

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

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

/* tdi */
GEN_HANDLER(tdi, 0x02, 0xFF, 0xFF, 0x00000000, PPC_64B)
{
3823 3824
    TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
    TCGv_i32 t1 = 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 3829
    gen_helper_td(cpu_gpr[rA(ctx->opcode)], t0, t1);
    tcg_temp_free(t0);
    tcg_temp_free_i32(t1);
3830 3831 3832
}
#endif

B
bellard 已提交
3833 3834 3835 3836
/***                          Processor control                            ***/
/* mcrxr */
GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC)
{
A
aurel32 已提交
3837 3838
    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);
3839
    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_SO | 1 << XER_OV | 1 << XER_CA));
B
bellard 已提交
3840 3841 3842
}

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

3847 3848 3849 3850
    if (likely(ctx->opcode & 0x00100000)) {
        crm = CRM(ctx->opcode);
        if (likely((crm ^ (crm - 1)) == 0)) {
            crn = ffs(crm);
3851
            tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], cpu_crf[7 - crn]);
3852
        }
3853
    } else {
P
pbrook 已提交
3854
        gen_helper_load_cr(cpu_gpr[rD(ctx->opcode)]);
3855
    }
B
bellard 已提交
3856 3857 3858 3859 3860
}

/* mfmsr */
GEN_HANDLER(mfmsr, 0x1F, 0x13, 0x02, 0x001FF801, PPC_MISC)
{
3861
#if defined(CONFIG_USER_ONLY)
3862
    GEN_EXCP_PRIVREG(ctx);
3863
#else
3864
    if (unlikely(!ctx->supervisor)) {
3865
        GEN_EXCP_PRIVREG(ctx);
3866
        return;
3867
    }
A
aurel32 已提交
3868
    gen_op_load_msr();
A
aurel32 已提交
3869
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
3870
#endif
B
bellard 已提交
3871 3872
}

J
j_mayer 已提交
3873
#if 1
3874
#define SPR_NOACCESS ((void *)(-1UL))
3875 3876 3877 3878 3879 3880 3881 3882 3883
#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 已提交
3884
/* mfspr */
3885
static always_inline void gen_op_mfspr (DisasContext *ctx)
B
bellard 已提交
3886
{
3887
    void (*read_cb)(void *opaque, int sprn);
B
bellard 已提交
3888 3889
    uint32_t sprn = SPR(ctx->opcode);

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

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

/* mftb */
3937
GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_MFTB)
3938 3939
{
    gen_op_mfspr(ctx);
B
bellard 已提交
3940 3941 3942
}

/* mtcrf */
3943
GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00000801, PPC_MISC)
B
bellard 已提交
3944
{
3945
    uint32_t crm, crn;
3946

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

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

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

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

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

/***                         Cache management                              ***/
/* dcbf */
4067
GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03C00001, PPC_CACHE)
B
bellard 已提交
4068
{
J
j_mayer 已提交
4069
    /* XXX: specification says this is treated as a load by the MMU */
P
pbrook 已提交
4070
    TCGv t0 = tcg_temp_new();
A
aurel32 已提交
4071
    gen_set_access_type(ACCESS_CACHE);
4072 4073 4074
    gen_addr_reg_index(t0, ctx);
    gen_qemu_ld8u(t0, t0, ctx->mem_idx);
    tcg_temp_free(t0);
B
bellard 已提交
4075 4076 4077
}

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

/* dcdst */
4101
GEN_HANDLER(dcbst, 0x1F, 0x16, 0x01, 0x03E00001, PPC_CACHE)
B
bellard 已提交
4102
{
4103
    /* XXX: specification say this is treated as a load by the MMU */
P
pbrook 已提交
4104
    TCGv t0 = tcg_temp_new();
A
aurel32 已提交
4105
    gen_set_access_type(ACCESS_CACHE);
4106 4107 4108
    gen_addr_reg_index(t0, ctx);
    gen_qemu_ld8u(t0, t0, ctx->mem_idx);
    tcg_temp_free(t0);
B
bellard 已提交
4109 4110 4111
}

/* dcbt */
4112
GEN_HANDLER(dcbt, 0x1F, 0x16, 0x08, 0x02000001, PPC_CACHE)
B
bellard 已提交
4113
{
4114
    /* interpreted as no-op */
4115 4116 4117
    /* XXX: specification say this is treated as a load by the MMU
     *      but does not generate any exception
     */
B
bellard 已提交
4118 4119 4120
}

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

/* dcbz */
4130
GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE_DCBZ)
B
bellard 已提交
4131
{
4132 4133 4134 4135 4136 4137
    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);
4138 4139
}

4140
GEN_HANDLER2(dcbz_970, "dcbz", 0x1F, 0x16, 0x1F, 0x03C00001, PPC_CACHE_DCBZT)
4141
{
4142 4143 4144 4145
    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);
4146
    if (ctx->opcode & 0x00200000)
4147
        gen_helper_dcbz(t0);
4148
    else
4149 4150
        gen_helper_dcbz_970(t0);
    tcg_temp_free(t0);
B
bellard 已提交
4151 4152 4153
}

/* icbi */
4154
GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_CACHE_ICBI)
B
bellard 已提交
4155
{
4156
    TCGv t0 = tcg_temp_new();
4157 4158
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
4159 4160 4161
    gen_addr_reg_index(t0, ctx);
    gen_helper_icbi(t0);
    tcg_temp_free(t0);
B
bellard 已提交
4162 4163 4164 4165
}

/* Optional: */
/* dcba */
4166
GEN_HANDLER(dcba, 0x1F, 0x16, 0x17, 0x03E00001, PPC_CACHE_DCBA)
B
bellard 已提交
4167
{
4168 4169 4170 4171
    /* interpreted as no-op */
    /* XXX: specification say this is treated as a store by the MMU
     *      but does not generate any exception
     */
B
bellard 已提交
4172 4173 4174 4175 4176 4177 4178
}

/***                    Segment register manipulation                      ***/
/* Supervisor only: */
/* mfsr */
GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT)
{
4179
#if defined(CONFIG_USER_ONLY)
4180
    GEN_EXCP_PRIVREG(ctx);
4181
#else
4182
    if (unlikely(!ctx->supervisor)) {
4183
        GEN_EXCP_PRIVREG(ctx);
4184
        return;
4185
    }
4186
    tcg_gen_movi_tl(cpu_T[1], SR(ctx->opcode));
4187
    gen_op_load_sr();
A
aurel32 已提交
4188
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4189
#endif
B
bellard 已提交
4190 4191 4192
}

/* mfsrin */
4193
GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT)
B
bellard 已提交
4194
{
4195
#if defined(CONFIG_USER_ONLY)
4196
    GEN_EXCP_PRIVREG(ctx);
4197
#else
4198
    if (unlikely(!ctx->supervisor)) {
4199
        GEN_EXCP_PRIVREG(ctx);
4200
        return;
4201
    }
A
aurel32 已提交
4202
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4203 4204
    gen_op_srli_T1(28);
    gen_op_load_sr();
A
aurel32 已提交
4205
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4206
#endif
B
bellard 已提交
4207 4208 4209
}

/* mtsr */
B
bellard 已提交
4210
GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT)
B
bellard 已提交
4211
{
4212
#if defined(CONFIG_USER_ONLY)
4213
    GEN_EXCP_PRIVREG(ctx);
4214
#else
4215
    if (unlikely(!ctx->supervisor)) {
4216
        GEN_EXCP_PRIVREG(ctx);
4217
        return;
4218
    }
A
aurel32 已提交
4219
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
4220
    tcg_gen_movi_tl(cpu_T[1], SR(ctx->opcode));
4221
    gen_op_store_sr();
4222
#endif
B
bellard 已提交
4223 4224 4225
}

/* mtsrin */
4226
GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT)
B
bellard 已提交
4227
{
4228
#if defined(CONFIG_USER_ONLY)
4229
    GEN_EXCP_PRIVREG(ctx);
4230
#else
4231
    if (unlikely(!ctx->supervisor)) {
4232
        GEN_EXCP_PRIVREG(ctx);
4233
        return;
4234
    }
A
aurel32 已提交
4235 4236
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4237 4238
    gen_op_srli_T1(28);
    gen_op_store_sr();
4239
#endif
B
bellard 已提交
4240 4241
}

4242 4243 4244
#if defined(TARGET_PPC64)
/* Specific implementation for PowerPC 64 "bridge" emulation using SLB */
/* mfsr */
4245
GEN_HANDLER2(mfsr_64b, "mfsr", 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT_64B)
4246 4247 4248 4249 4250 4251 4252 4253
{
#if defined(CONFIG_USER_ONLY)
    GEN_EXCP_PRIVREG(ctx);
#else
    if (unlikely(!ctx->supervisor)) {
        GEN_EXCP_PRIVREG(ctx);
        return;
    }
4254
    tcg_gen_movi_tl(cpu_T[1], SR(ctx->opcode));
4255
    gen_op_load_slb();
A
aurel32 已提交
4256
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4257 4258 4259 4260
#endif
}

/* mfsrin */
4261 4262
GEN_HANDLER2(mfsrin_64b, "mfsrin", 0x1F, 0x13, 0x14, 0x001F0001,
             PPC_SEGMENT_64B)
4263 4264 4265 4266 4267 4268 4269 4270
{
#if defined(CONFIG_USER_ONLY)
    GEN_EXCP_PRIVREG(ctx);
#else
    if (unlikely(!ctx->supervisor)) {
        GEN_EXCP_PRIVREG(ctx);
        return;
    }
A
aurel32 已提交
4271
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4272 4273
    gen_op_srli_T1(28);
    gen_op_load_slb();
A
aurel32 已提交
4274
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4275 4276 4277 4278
#endif
}

/* mtsr */
4279
GEN_HANDLER2(mtsr_64b, "mtsr", 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT_64B)
4280 4281 4282 4283 4284 4285 4286 4287
{
#if defined(CONFIG_USER_ONLY)
    GEN_EXCP_PRIVREG(ctx);
#else
    if (unlikely(!ctx->supervisor)) {
        GEN_EXCP_PRIVREG(ctx);
        return;
    }
A
aurel32 已提交
4288
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
4289
    tcg_gen_movi_tl(cpu_T[1], SR(ctx->opcode));
4290 4291 4292 4293 4294
    gen_op_store_slb();
#endif
}

/* mtsrin */
4295 4296
GEN_HANDLER2(mtsrin_64b, "mtsrin", 0x1F, 0x12, 0x07, 0x001F0001,
             PPC_SEGMENT_64B)
4297 4298 4299 4300 4301 4302 4303 4304
{
#if defined(CONFIG_USER_ONLY)
    GEN_EXCP_PRIVREG(ctx);
#else
    if (unlikely(!ctx->supervisor)) {
        GEN_EXCP_PRIVREG(ctx);
        return;
    }
A
aurel32 已提交
4305 4306
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4307 4308 4309 4310 4311 4312
    gen_op_srli_T1(28);
    gen_op_store_slb();
#endif
}
#endif /* defined(TARGET_PPC64) */

B
bellard 已提交
4313 4314 4315
/***                      Lookaside buffer management                      ***/
/* Optional & supervisor only: */
/* tlbia */
4316
GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA)
B
bellard 已提交
4317
{
4318
#if defined(CONFIG_USER_ONLY)
4319
    GEN_EXCP_PRIVOPC(ctx);
4320
#else
4321
    if (unlikely(!ctx->supervisor)) {
4322
        GEN_EXCP_PRIVOPC(ctx);
4323
        return;
4324 4325 4326
    }
    gen_op_tlbia();
#endif
B
bellard 已提交
4327 4328 4329
}

/* tlbie */
4330
GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM_TLBIE)
B
bellard 已提交
4331
{
4332
#if defined(CONFIG_USER_ONLY)
4333
    GEN_EXCP_PRIVOPC(ctx);
4334
#else
4335
    if (unlikely(!ctx->supervisor)) {
4336
        GEN_EXCP_PRIVOPC(ctx);
4337
        return;
4338
    }
A
aurel32 已提交
4339
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rB(ctx->opcode)]);
4340 4341 4342 4343 4344 4345
#if defined(TARGET_PPC64)
    if (ctx->sf_mode)
        gen_op_tlbie_64();
    else
#endif
        gen_op_tlbie();
4346
#endif
B
bellard 已提交
4347 4348 4349
}

/* tlbsync */
4350
GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM_TLBSYNC)
B
bellard 已提交
4351
{
4352
#if defined(CONFIG_USER_ONLY)
4353
    GEN_EXCP_PRIVOPC(ctx);
4354
#else
4355
    if (unlikely(!ctx->supervisor)) {
4356
        GEN_EXCP_PRIVOPC(ctx);
4357
        return;
4358 4359 4360 4361
    }
    /* This has no effect: it should ensure that all previous
     * tlbie have completed
     */
4362
    GEN_STOP(ctx);
4363
#endif
B
bellard 已提交
4364 4365
}

J
j_mayer 已提交
4366 4367 4368 4369 4370
#if defined(TARGET_PPC64)
/* slbia */
GEN_HANDLER(slbia, 0x1F, 0x12, 0x0F, 0x03FFFC01, PPC_SLBI)
{
#if defined(CONFIG_USER_ONLY)
4371
    GEN_EXCP_PRIVOPC(ctx);
J
j_mayer 已提交
4372 4373
#else
    if (unlikely(!ctx->supervisor)) {
4374
        GEN_EXCP_PRIVOPC(ctx);
J
j_mayer 已提交
4375 4376 4377 4378 4379 4380 4381 4382 4383 4384
        return;
    }
    gen_op_slbia();
#endif
}

/* slbie */
GEN_HANDLER(slbie, 0x1F, 0x12, 0x0D, 0x03FF0001, PPC_SLBI)
{
#if defined(CONFIG_USER_ONLY)
4385
    GEN_EXCP_PRIVOPC(ctx);
J
j_mayer 已提交
4386 4387
#else
    if (unlikely(!ctx->supervisor)) {
4388
        GEN_EXCP_PRIVOPC(ctx);
J
j_mayer 已提交
4389 4390
        return;
    }
A
aurel32 已提交
4391
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rB(ctx->opcode)]);
J
j_mayer 已提交
4392 4393 4394 4395 4396
    gen_op_slbie();
#endif
}
#endif

B
bellard 已提交
4397 4398
/***                              External control                         ***/
/* Optional: */
4399
/* eciwx */
B
bellard 已提交
4400 4401
GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN)
{
4402 4403
    /* Should check EAR[E] ! */
    TCGv t0 = tcg_temp_new();
A
aurel32 已提交
4404
    gen_set_access_type(ACCESS_RES);
4405 4406 4407 4408
    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);
4409 4410 4411 4412 4413
}

/* ecowx */
GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN)
{
4414 4415 4416 4417 4418 4419 4420
    /* 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);
4421 4422 4423 4424 4425 4426
}

/* PowerPC 601 specific instructions */
/* abs - abs. */
GEN_HANDLER(abs, 0x1F, 0x08, 0x0B, 0x0000F800, PPC_POWER_BR)
{
A
aurel32 已提交
4427
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
4428
    gen_op_POWER_abs();
A
aurel32 已提交
4429
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4430
    if (unlikely(Rc(ctx->opcode) != 0))
4431
        gen_set_Rc0(ctx, cpu_T[0]);
4432 4433 4434 4435 4436
}

/* abso - abso. */
GEN_HANDLER(abso, 0x1F, 0x08, 0x1B, 0x0000F800, PPC_POWER_BR)
{
A
aurel32 已提交
4437
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
4438
    gen_op_POWER_abso();
A
aurel32 已提交
4439
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4440
    if (unlikely(Rc(ctx->opcode) != 0))
4441
        gen_set_Rc0(ctx, cpu_T[0]);
4442 4443 4444
}

/* clcs */
4445
GEN_HANDLER(clcs, 0x1F, 0x10, 0x13, 0x0000F800, PPC_POWER_BR)
4446
{
A
aurel32 已提交
4447
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
4448
    gen_op_POWER_clcs();
4449
    /* Rc=1 sets CR0 to an undefined state */
A
aurel32 已提交
4450
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4451 4452 4453 4454 4455
}

/* div - div. */
GEN_HANDLER(div, 0x1F, 0x0B, 0x0A, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4456 4457
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4458
    gen_op_POWER_div();
A
aurel32 已提交
4459
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4460
    if (unlikely(Rc(ctx->opcode) != 0))
4461
        gen_set_Rc0(ctx, cpu_T[0]);
4462 4463 4464 4465 4466
}

/* divo - divo. */
GEN_HANDLER(divo, 0x1F, 0x0B, 0x1A, 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_divo();
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
}

/* divs - divs. */
GEN_HANDLER(divs, 0x1F, 0x0B, 0x0B, 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_divs();
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
}

/* divso - divso. */
GEN_HANDLER(divso, 0x1F, 0x0B, 0x1B, 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_divso();
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
}

/* doz - doz. */
GEN_HANDLER(doz, 0x1F, 0x08, 0x08, 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_doz();
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
}

/* dozo - dozo. */
GEN_HANDLER(dozo, 0x1F, 0x08, 0x18, 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_dozo();
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
}

/* dozi */
GEN_HANDLER(dozi, 0x09, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4522
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
4523
    tcg_gen_movi_tl(cpu_T[1], SIMM(ctx->opcode));
4524
    gen_op_POWER_doz();
A
aurel32 已提交
4525
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4526 4527 4528 4529 4530
}

/* lscbx - lscbx. */
GEN_HANDLER(lscbx, 0x1F, 0x15, 0x08, 0x00000000, PPC_POWER_BR)
{
4531 4532 4533 4534
    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));
4535

4536
    gen_addr_reg_index(t0, ctx);
4537
    /* NIP cannot be restored if the memory exception comes from an helper */
4538
    gen_update_nip(ctx, ctx->nip - 4);
4539 4540 4541 4542
    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 已提交
4543
    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~0x7F);
4544
    tcg_gen_or_tl(cpu_xer, cpu_xer, t0);
4545
    if (unlikely(Rc(ctx->opcode) != 0))
4546 4547
        gen_set_Rc0(ctx, t0);
    tcg_temp_free(t0);
4548 4549 4550 4551 4552
}

/* maskg - maskg. */
GEN_HANDLER(maskg, 0x1F, 0x1D, 0x00, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4553 4554
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4555
    gen_op_POWER_maskg();
A
aurel32 已提交
4556
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4557
    if (unlikely(Rc(ctx->opcode) != 0))
4558
        gen_set_Rc0(ctx, cpu_T[0]);
4559 4560 4561 4562 4563
}

/* maskir - maskir. */
GEN_HANDLER(maskir, 0x1F, 0x1D, 0x10, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4564 4565 4566
    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)]);
4567
    gen_op_POWER_maskir();
A
aurel32 已提交
4568
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4569
    if (unlikely(Rc(ctx->opcode) != 0))
4570
        gen_set_Rc0(ctx, cpu_T[0]);
4571 4572 4573 4574 4575
}

/* mul - mul. */
GEN_HANDLER(mul, 0x1F, 0x0B, 0x03, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4576 4577
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4578
    gen_op_POWER_mul();
A
aurel32 已提交
4579
    tcg_gen_mov_tl(cpu_gpr[rD(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
}

/* mulo - mulo. */
GEN_HANDLER(mulo, 0x1F, 0x0B, 0x13, 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_mulo();
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
}

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

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

/* rlmi - rlmi. */
GEN_HANDLER(rlmi, 0x16, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR)
{
    uint32_t mb, me;

    mb = MB(ctx->opcode);
    me = ME(ctx->opcode);
A
aurel32 已提交
4622 4623 4624
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[2], cpu_gpr[rB(ctx->opcode)]);
4625
    gen_op_POWER_rlmi(MASK(mb, me), ~MASK(mb, me));
A
aurel32 已提交
4626
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4627
    if (unlikely(Rc(ctx->opcode) != 0))
4628
        gen_set_Rc0(ctx, cpu_T[0]);
4629 4630 4631 4632 4633
}

/* rrib - rrib. */
GEN_HANDLER(rrib, 0x1F, 0x19, 0x10, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4634 4635 4636
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[2], cpu_gpr[rB(ctx->opcode)]);
4637
    gen_op_POWER_rrib();
A
aurel32 已提交
4638
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4639
    if (unlikely(Rc(ctx->opcode) != 0))
4640
        gen_set_Rc0(ctx, cpu_T[0]);
4641 4642 4643 4644 4645
}

/* sle - sle. */
GEN_HANDLER(sle, 0x1F, 0x19, 0x04, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4646 4647
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4648
    gen_op_POWER_sle();
A
aurel32 已提交
4649
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4650
    if (unlikely(Rc(ctx->opcode) != 0))
4651
        gen_set_Rc0(ctx, cpu_T[0]);
4652 4653 4654 4655 4656
}

/* sleq - sleq. */
GEN_HANDLER(sleq, 0x1F, 0x19, 0x06, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4657 4658
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4659
    gen_op_POWER_sleq();
A
aurel32 已提交
4660
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4661
    if (unlikely(Rc(ctx->opcode) != 0))
4662
        gen_set_Rc0(ctx, cpu_T[0]);
4663 4664 4665 4666 4667
}

/* sliq - sliq. */
GEN_HANDLER(sliq, 0x1F, 0x18, 0x05, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4668
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
4669
    tcg_gen_movi_tl(cpu_T[1], SH(ctx->opcode));
4670
    gen_op_POWER_sle();
A
aurel32 已提交
4671
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4672
    if (unlikely(Rc(ctx->opcode) != 0))
4673
        gen_set_Rc0(ctx, cpu_T[0]);
4674 4675 4676 4677 4678
}

/* slliq - slliq. */
GEN_HANDLER(slliq, 0x1F, 0x18, 0x07, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4679
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
4680
    tcg_gen_movi_tl(cpu_T[1], SH(ctx->opcode));
4681
    gen_op_POWER_sleq();
A
aurel32 已提交
4682
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4683
    if (unlikely(Rc(ctx->opcode) != 0))
4684
        gen_set_Rc0(ctx, cpu_T[0]);
4685 4686 4687 4688 4689
}

/* sllq - sllq. */
GEN_HANDLER(sllq, 0x1F, 0x18, 0x06, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4690 4691
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4692
    gen_op_POWER_sllq();
A
aurel32 已提交
4693
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4694
    if (unlikely(Rc(ctx->opcode) != 0))
4695
        gen_set_Rc0(ctx, cpu_T[0]);
4696 4697 4698 4699 4700
}

/* slq - slq. */
GEN_HANDLER(slq, 0x1F, 0x18, 0x04, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4701 4702
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4703
    gen_op_POWER_slq();
A
aurel32 已提交
4704
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4705
    if (unlikely(Rc(ctx->opcode) != 0))
4706
        gen_set_Rc0(ctx, cpu_T[0]);
4707 4708
}

4709
/* sraiq - sraiq. */
4710 4711
GEN_HANDLER(sraiq, 0x1F, 0x18, 0x1D, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4712
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
4713
    tcg_gen_movi_tl(cpu_T[1], SH(ctx->opcode));
4714
    gen_op_POWER_sraq();
A
aurel32 已提交
4715
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4716
    if (unlikely(Rc(ctx->opcode) != 0))
4717
        gen_set_Rc0(ctx, cpu_T[0]);
4718 4719 4720 4721 4722
}

/* sraq - sraq. */
GEN_HANDLER(sraq, 0x1F, 0x18, 0x1C, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4723 4724
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4725
    gen_op_POWER_sraq();
A
aurel32 已提交
4726
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4727
    if (unlikely(Rc(ctx->opcode) != 0))
4728
        gen_set_Rc0(ctx, cpu_T[0]);
4729 4730 4731 4732 4733
}

/* sre - sre. */
GEN_HANDLER(sre, 0x1F, 0x19, 0x14, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4734 4735
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4736
    gen_op_POWER_sre();
A
aurel32 已提交
4737
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4738
    if (unlikely(Rc(ctx->opcode) != 0))
4739
        gen_set_Rc0(ctx, cpu_T[0]);
4740 4741 4742 4743 4744
}

/* srea - srea. */
GEN_HANDLER(srea, 0x1F, 0x19, 0x1C, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4745 4746
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4747
    gen_op_POWER_srea();
A
aurel32 已提交
4748
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4749
    if (unlikely(Rc(ctx->opcode) != 0))
4750
        gen_set_Rc0(ctx, cpu_T[0]);
4751 4752 4753 4754 4755
}

/* sreq */
GEN_HANDLER(sreq, 0x1F, 0x19, 0x16, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4756 4757
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4758
    gen_op_POWER_sreq();
A
aurel32 已提交
4759
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4760
    if (unlikely(Rc(ctx->opcode) != 0))
4761
        gen_set_Rc0(ctx, cpu_T[0]);
4762 4763 4764 4765 4766
}

/* sriq */
GEN_HANDLER(sriq, 0x1F, 0x18, 0x15, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4767
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
4768
    tcg_gen_movi_tl(cpu_T[1], SH(ctx->opcode));
4769
    gen_op_POWER_srq();
A
aurel32 已提交
4770
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4771
    if (unlikely(Rc(ctx->opcode) != 0))
4772
        gen_set_Rc0(ctx, cpu_T[0]);
4773 4774 4775 4776 4777
}

/* srliq */
GEN_HANDLER(srliq, 0x1F, 0x18, 0x17, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4778 4779
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4780
    tcg_gen_movi_tl(cpu_T[1], SH(ctx->opcode));
4781
    gen_op_POWER_srlq();
A
aurel32 已提交
4782
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4783
    if (unlikely(Rc(ctx->opcode) != 0))
4784
        gen_set_Rc0(ctx, cpu_T[0]);
4785 4786 4787 4788 4789
}

/* srlq */
GEN_HANDLER(srlq, 0x1F, 0x18, 0x16, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4790 4791
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4792
    gen_op_POWER_srlq();
A
aurel32 已提交
4793
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4794
    if (unlikely(Rc(ctx->opcode) != 0))
4795
        gen_set_Rc0(ctx, cpu_T[0]);
4796 4797 4798 4799 4800
}

/* srq */
GEN_HANDLER(srq, 0x1F, 0x18, 0x14, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4801 4802
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4803
    gen_op_POWER_srq();
A
aurel32 已提交
4804
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4805
    if (unlikely(Rc(ctx->opcode) != 0))
4806
        gen_set_Rc0(ctx, cpu_T[0]);
4807 4808 4809 4810 4811 4812 4813
}

/* PowerPC 602 specific instructions */
/* dsa  */
GEN_HANDLER(dsa, 0x1F, 0x14, 0x13, 0x03FFF801, PPC_602_SPEC)
{
    /* XXX: TODO */
4814
    GEN_EXCP_INVAL(ctx);
4815 4816 4817 4818 4819 4820
}

/* esa */
GEN_HANDLER(esa, 0x1F, 0x14, 0x12, 0x03FFF801, PPC_602_SPEC)
{
    /* XXX: TODO */
4821
    GEN_EXCP_INVAL(ctx);
4822 4823 4824 4825 4826 4827
}

/* mfrom */
GEN_HANDLER(mfrom, 0x1F, 0x09, 0x08, 0x03E0F801, PPC_602_SPEC)
{
#if defined(CONFIG_USER_ONLY)
4828
    GEN_EXCP_PRIVOPC(ctx);
4829 4830
#else
    if (unlikely(!ctx->supervisor)) {
4831
        GEN_EXCP_PRIVOPC(ctx);
4832 4833
        return;
    }
4834
    gen_helper_602_mfrom(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
4835 4836 4837 4838 4839
#endif
}

/* 602 - 603 - G2 TLB management */
/* tlbld */
4840
GEN_HANDLER2(tlbld_6xx, "tlbld", 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB)
4841 4842
{
#if defined(CONFIG_USER_ONLY)
4843
    GEN_EXCP_PRIVOPC(ctx);
4844 4845
#else
    if (unlikely(!ctx->supervisor)) {
4846
        GEN_EXCP_PRIVOPC(ctx);
4847 4848
        return;
    }
4849
    gen_helper_load_6xx_tlbd(cpu_gpr[rB(ctx->opcode)]);
4850 4851 4852 4853
#endif
}

/* tlbli */
4854
GEN_HANDLER2(tlbli_6xx, "tlbli", 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB)
4855 4856
{
#if defined(CONFIG_USER_ONLY)
4857
    GEN_EXCP_PRIVOPC(ctx);
4858 4859
#else
    if (unlikely(!ctx->supervisor)) {
4860
        GEN_EXCP_PRIVOPC(ctx);
4861 4862
        return;
    }
4863
    gen_helper_load_6xx_tlbi(cpu_gpr[rB(ctx->opcode)]);
4864 4865 4866
#endif
}

4867 4868
/* 74xx TLB management */
/* tlbld */
4869
GEN_HANDLER2(tlbld_74xx, "tlbld", 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_74xx_TLB)
4870 4871 4872 4873 4874 4875 4876 4877
{
#if defined(CONFIG_USER_ONLY)
    GEN_EXCP_PRIVOPC(ctx);
#else
    if (unlikely(!ctx->supervisor)) {
        GEN_EXCP_PRIVOPC(ctx);
        return;
    }
4878
    gen_helper_load_74xx_tlbd(cpu_gpr[rB(ctx->opcode)]);
4879 4880 4881 4882
#endif
}

/* tlbli */
4883
GEN_HANDLER2(tlbli_74xx, "tlbli", 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_74xx_TLB)
4884 4885 4886 4887 4888 4889 4890 4891
{
#if defined(CONFIG_USER_ONLY)
    GEN_EXCP_PRIVOPC(ctx);
#else
    if (unlikely(!ctx->supervisor)) {
        GEN_EXCP_PRIVOPC(ctx);
        return;
    }
4892
    gen_helper_load_74xx_tlbi(cpu_gpr[rB(ctx->opcode)]);
4893 4894 4895
#endif
}

4896 4897 4898 4899 4900 4901 4902 4903 4904 4905
/* 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 已提交
4906
    /* Cache line invalidate: privileged and treated as no-op */
4907
#if defined(CONFIG_USER_ONLY)
4908
    GEN_EXCP_PRIVOPC(ctx);
4909 4910
#else
    if (unlikely(!ctx->supervisor)) {
4911
        GEN_EXCP_PRIVOPC(ctx);
4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925
        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)
4926
    GEN_EXCP_PRIVOPC(ctx);
4927 4928
#else
    if (unlikely(!ctx->supervisor)) {
4929
        GEN_EXCP_PRIVOPC(ctx);
4930 4931 4932 4933 4934
        return;
    }
    int ra = rA(ctx->opcode);
    int rd = rD(ctx->opcode);

4935
    gen_addr_reg_index(cpu_T[0], ctx);
4936
    gen_op_POWER_mfsri();
A
aurel32 已提交
4937
    tcg_gen_mov_tl(cpu_gpr[rd], cpu_T[0]);
4938
    if (ra != 0 && ra != rd)
A
aurel32 已提交
4939
        tcg_gen_mov_tl(cpu_gpr[ra], cpu_T[1]);
4940 4941 4942 4943 4944 4945
#endif
}

GEN_HANDLER(rac, 0x1F, 0x12, 0x19, 0x00000001, PPC_POWER)
{
#if defined(CONFIG_USER_ONLY)
4946
    GEN_EXCP_PRIVOPC(ctx);
4947 4948
#else
    if (unlikely(!ctx->supervisor)) {
4949
        GEN_EXCP_PRIVOPC(ctx);
4950 4951
        return;
    }
4952
    gen_addr_reg_index(cpu_T[0], ctx);
4953
    gen_op_POWER_rac();
A
aurel32 已提交
4954
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4955 4956 4957 4958 4959 4960
#endif
}

GEN_HANDLER(rfsvc, 0x13, 0x12, 0x02, 0x03FFF0001, PPC_POWER)
{
#if defined(CONFIG_USER_ONLY)
4961
    GEN_EXCP_PRIVOPC(ctx);
4962 4963
#else
    if (unlikely(!ctx->supervisor)) {
4964
        GEN_EXCP_PRIVOPC(ctx);
4965 4966
        return;
    }
4967
    gen_helper_rfsvc();
4968
    GEN_SYNC(ctx);
4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979
#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)
{
4980 4981 4982 4983 4984 4985 4986
    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);
4987 4988 4989 4990 4991 4992
}

/* lfqu */
GEN_HANDLER(lfqu, 0x39, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
{
    int ra = rA(ctx->opcode);
4993 4994 4995 4996 4997 4998 4999
    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);
5000
    if (ra != 0)
5001 5002 5003
        tcg_gen_mov_tl(cpu_gpr[ra], t0);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
5004 5005 5006 5007 5008 5009
}

/* lfqux */
GEN_HANDLER(lfqux, 0x1F, 0x17, 0x19, 0x00000001, PPC_POWER2)
{
    int ra = rA(ctx->opcode);
5010 5011 5012 5013 5014 5015 5016
    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);
5017
    if (ra != 0)
5018 5019 5020
        tcg_gen_mov_tl(cpu_gpr[ra], t0);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
5021 5022 5023 5024 5025
}

/* lfqx */
GEN_HANDLER(lfqx, 0x1F, 0x17, 0x18, 0x00000001, PPC_POWER2)
{
5026 5027 5028 5029 5030 5031 5032
    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);
5033 5034 5035 5036 5037
}

/* stfq */
GEN_HANDLER(stfq, 0x3C, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
{
5038 5039 5040 5041 5042 5043 5044
    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);
5045 5046 5047 5048 5049 5050
}

/* stfqu */
GEN_HANDLER(stfqu, 0x3D, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
{
    int ra = rA(ctx->opcode);
5051 5052 5053 5054 5055 5056 5057
    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);
5058
    if (ra != 0)
5059 5060 5061
        tcg_gen_mov_tl(cpu_gpr[ra], t0);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
5062 5063 5064 5065 5066 5067
}

/* stfqux */
GEN_HANDLER(stfqux, 0x1F, 0x17, 0x1D, 0x00000001, PPC_POWER2)
{
    int ra = rA(ctx->opcode);
5068 5069 5070 5071 5072 5073 5074
    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);
5075
    if (ra != 0)
5076 5077 5078
        tcg_gen_mov_tl(cpu_gpr[ra], t0);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
5079 5080 5081 5082 5083
}

/* stfqx */
GEN_HANDLER(stfqx, 0x1F, 0x17, 0x1C, 0x00000001, PPC_POWER2)
{
5084 5085 5086 5087 5088 5089 5090
    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);
5091 5092 5093
}

/* BookE specific instructions */
5094
/* XXX: not implemented on 440 ? */
5095
GEN_HANDLER(mfapidi, 0x1F, 0x13, 0x08, 0x0000F801, PPC_MFAPIDI)
5096 5097
{
    /* XXX: TODO */
5098
    GEN_EXCP_INVAL(ctx);
5099 5100
}

5101
/* XXX: not implemented on 440 ? */
5102
GEN_HANDLER(tlbiva, 0x1F, 0x12, 0x18, 0x03FFF801, PPC_TLBIVA)
5103 5104
{
#if defined(CONFIG_USER_ONLY)
5105
    GEN_EXCP_PRIVOPC(ctx);
5106 5107
#else
    if (unlikely(!ctx->supervisor)) {
5108
        GEN_EXCP_PRIVOPC(ctx);
5109 5110
        return;
    }
5111
    gen_addr_reg_index(cpu_T[0], ctx);
5112
    /* Use the same micro-ops as for tlbie */
5113 5114 5115 5116 5117 5118
#if defined(TARGET_PPC64)
    if (ctx->sf_mode)
        gen_op_tlbie_64();
    else
#endif
        gen_op_tlbie();
5119 5120 5121 5122
#endif
}

/* All 405 MAC instructions are translated here */
5123 5124 5125
static always_inline void gen_405_mulladd_insn (DisasContext *ctx,
                                                int opc2, int opc3,
                                                int ra, int rb, int rt, int Rc)
5126
{
5127 5128
    TCGv t0, t1;

P
pbrook 已提交
5129 5130
    t0 = tcg_temp_local_new();
    t1 = tcg_temp_local_new();
5131

5132 5133 5134 5135 5136 5137 5138
    switch (opc3 & 0x0D) {
    case 0x05:
        /* macchw    - macchw.    - macchwo   - macchwo.   */
        /* macchws   - macchws.   - macchwso  - macchwso.  */
        /* nmacchw   - nmacchw.   - nmacchwo  - nmacchwo.  */
        /* nmacchws  - nmacchws.  - nmacchwso - nmacchwso. */
        /* mulchw - mulchw. */
5139 5140 5141
        tcg_gen_ext16s_tl(t0, cpu_gpr[ra]);
        tcg_gen_sari_tl(t1, cpu_gpr[rb], 16);
        tcg_gen_ext16s_tl(t1, t1);
5142 5143 5144 5145 5146
        break;
    case 0x04:
        /* macchwu   - macchwu.   - macchwuo  - macchwuo.  */
        /* macchwsu  - macchwsu.  - macchwsuo - macchwsuo. */
        /* mulchwu - mulchwu. */
5147 5148 5149
        tcg_gen_ext16u_tl(t0, cpu_gpr[ra]);
        tcg_gen_shri_tl(t1, cpu_gpr[rb], 16);
        tcg_gen_ext16u_tl(t1, t1);
5150 5151 5152 5153 5154 5155 5156
        break;
    case 0x01:
        /* machhw    - machhw.    - machhwo   - machhwo.   */
        /* machhws   - machhws.   - machhwso  - machhwso.  */
        /* nmachhw   - nmachhw.   - nmachhwo  - nmachhwo.  */
        /* nmachhws  - nmachhws.  - nmachhwso - nmachhwso. */
        /* mulhhw - mulhhw. */
5157 5158 5159 5160
        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);
5161 5162 5163 5164 5165
        break;
    case 0x00:
        /* machhwu   - machhwu.   - machhwuo  - machhwuo.  */
        /* machhwsu  - machhwsu.  - machhwsuo - machhwsuo. */
        /* mulhhwu - mulhhwu. */
5166 5167 5168 5169
        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);
5170 5171 5172 5173 5174 5175 5176
        break;
    case 0x0D:
        /* maclhw    - maclhw.    - maclhwo   - maclhwo.   */
        /* maclhws   - maclhws.   - maclhwso  - maclhwso.  */
        /* nmaclhw   - nmaclhw.   - nmaclhwo  - nmaclhwo.  */
        /* nmaclhws  - nmaclhws.  - nmaclhwso - nmaclhwso. */
        /* mullhw - mullhw. */
5177 5178
        tcg_gen_ext16s_tl(t0, cpu_gpr[ra]);
        tcg_gen_ext16s_tl(t1, cpu_gpr[rb]);
5179 5180 5181 5182 5183
        break;
    case 0x0C:
        /* maclhwu   - maclhwu.   - maclhwuo  - maclhwuo.  */
        /* maclhwsu  - maclhwsu.  - maclhwsuo - maclhwsuo. */
        /* mullhwu - mullhwu. */
5184 5185
        tcg_gen_ext16u_tl(t0, cpu_gpr[ra]);
        tcg_gen_ext16u_tl(t1, cpu_gpr[rb]);
5186 5187 5188
        break;
    }
    if (opc2 & 0x04) {
5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212
        /* (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 已提交
5213
                if (opc3 & 0x02) {
5214 5215 5216 5217 5218 5219 5220
                    /* 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 已提交
5221
                if (opc3 & 0x02) {
5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234
                    /* 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);
5235
    }
5236 5237
    tcg_temp_free(t0);
    tcg_temp_free(t1);
5238 5239
    if (unlikely(Rc) != 0) {
        /* Update Rc0 */
5240
        gen_set_Rc0(ctx, cpu_gpr[rt]);
5241 5242 5243
    }
}

5244 5245
#define GEN_MAC_HANDLER(name, opc2, opc3)                                     \
GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_405_MAC)                  \
5246 5247 5248 5249 5250 5251
{                                                                             \
    gen_405_mulladd_insn(ctx, opc2, opc3, rA(ctx->opcode), rB(ctx->opcode),   \
                         rD(ctx->opcode), Rc(ctx->opcode));                   \
}

/* macchw    - macchw.    */
5252
GEN_MAC_HANDLER(macchw, 0x0C, 0x05);
5253
/* macchwo   - macchwo.   */
5254
GEN_MAC_HANDLER(macchwo, 0x0C, 0x15);
5255
/* macchws   - macchws.   */
5256
GEN_MAC_HANDLER(macchws, 0x0C, 0x07);
5257
/* macchwso  - macchwso.  */
5258
GEN_MAC_HANDLER(macchwso, 0x0C, 0x17);
5259
/* macchwsu  - macchwsu.  */
5260
GEN_MAC_HANDLER(macchwsu, 0x0C, 0x06);
5261
/* macchwsuo - macchwsuo. */
5262
GEN_MAC_HANDLER(macchwsuo, 0x0C, 0x16);
5263
/* macchwu   - macchwu.   */
5264
GEN_MAC_HANDLER(macchwu, 0x0C, 0x04);
5265
/* macchwuo  - macchwuo.  */
5266
GEN_MAC_HANDLER(macchwuo, 0x0C, 0x14);
5267
/* machhw    - machhw.    */
5268
GEN_MAC_HANDLER(machhw, 0x0C, 0x01);
5269
/* machhwo   - machhwo.   */
5270
GEN_MAC_HANDLER(machhwo, 0x0C, 0x11);
5271
/* machhws   - machhws.   */
5272
GEN_MAC_HANDLER(machhws, 0x0C, 0x03);
5273
/* machhwso  - machhwso.  */
5274
GEN_MAC_HANDLER(machhwso, 0x0C, 0x13);
5275
/* machhwsu  - machhwsu.  */
5276
GEN_MAC_HANDLER(machhwsu, 0x0C, 0x02);
5277
/* machhwsuo - machhwsuo. */
5278
GEN_MAC_HANDLER(machhwsuo, 0x0C, 0x12);
5279
/* machhwu   - machhwu.   */
5280
GEN_MAC_HANDLER(machhwu, 0x0C, 0x00);
5281
/* machhwuo  - machhwuo.  */
5282
GEN_MAC_HANDLER(machhwuo, 0x0C, 0x10);
5283
/* maclhw    - maclhw.    */
5284
GEN_MAC_HANDLER(maclhw, 0x0C, 0x0D);
5285
/* maclhwo   - maclhwo.   */
5286
GEN_MAC_HANDLER(maclhwo, 0x0C, 0x1D);
5287
/* maclhws   - maclhws.   */
5288
GEN_MAC_HANDLER(maclhws, 0x0C, 0x0F);
5289
/* maclhwso  - maclhwso.  */
5290
GEN_MAC_HANDLER(maclhwso, 0x0C, 0x1F);
5291
/* maclhwu   - maclhwu.   */
5292
GEN_MAC_HANDLER(maclhwu, 0x0C, 0x0C);
5293
/* maclhwuo  - maclhwuo.  */
5294
GEN_MAC_HANDLER(maclhwuo, 0x0C, 0x1C);
5295
/* maclhwsu  - maclhwsu.  */
5296
GEN_MAC_HANDLER(maclhwsu, 0x0C, 0x0E);
5297
/* maclhwsuo - maclhwsuo. */
5298
GEN_MAC_HANDLER(maclhwsuo, 0x0C, 0x1E);
5299
/* nmacchw   - nmacchw.   */
5300
GEN_MAC_HANDLER(nmacchw, 0x0E, 0x05);
5301
/* nmacchwo  - nmacchwo.  */
5302
GEN_MAC_HANDLER(nmacchwo, 0x0E, 0x15);
5303
/* nmacchws  - nmacchws.  */
5304
GEN_MAC_HANDLER(nmacchws, 0x0E, 0x07);
5305
/* nmacchwso - nmacchwso. */
5306
GEN_MAC_HANDLER(nmacchwso, 0x0E, 0x17);
5307
/* nmachhw   - nmachhw.   */
5308
GEN_MAC_HANDLER(nmachhw, 0x0E, 0x01);
5309
/* nmachhwo  - nmachhwo.  */
5310
GEN_MAC_HANDLER(nmachhwo, 0x0E, 0x11);
5311
/* nmachhws  - nmachhws.  */
5312
GEN_MAC_HANDLER(nmachhws, 0x0E, 0x03);
5313
/* nmachhwso - nmachhwso. */
5314
GEN_MAC_HANDLER(nmachhwso, 0x0E, 0x13);
5315
/* nmaclhw   - nmaclhw.   */
5316
GEN_MAC_HANDLER(nmaclhw, 0x0E, 0x0D);
5317
/* nmaclhwo  - nmaclhwo.  */
5318
GEN_MAC_HANDLER(nmaclhwo, 0x0E, 0x1D);
5319
/* nmaclhws  - nmaclhws.  */
5320
GEN_MAC_HANDLER(nmaclhws, 0x0E, 0x0F);
5321
/* nmaclhwso - nmaclhwso. */
5322
GEN_MAC_HANDLER(nmaclhwso, 0x0E, 0x1F);
5323 5324

/* mulchw  - mulchw.  */
5325
GEN_MAC_HANDLER(mulchw, 0x08, 0x05);
5326
/* mulchwu - mulchwu. */
5327
GEN_MAC_HANDLER(mulchwu, 0x08, 0x04);
5328
/* mulhhw  - mulhhw.  */
5329
GEN_MAC_HANDLER(mulhhw, 0x08, 0x01);
5330
/* mulhhwu - mulhhwu. */
5331
GEN_MAC_HANDLER(mulhhwu, 0x08, 0x00);
5332
/* mullhw  - mullhw.  */
5333
GEN_MAC_HANDLER(mullhw, 0x08, 0x0D);
5334
/* mullhwu - mullhwu. */
5335
GEN_MAC_HANDLER(mullhwu, 0x08, 0x0C);
5336 5337

/* mfdcr */
5338
GEN_HANDLER(mfdcr, 0x1F, 0x03, 0x0A, 0x00000001, PPC_DCR)
5339 5340
{
#if defined(CONFIG_USER_ONLY)
5341
    GEN_EXCP_PRIVREG(ctx);
5342 5343 5344 5345
#else
    uint32_t dcrn = SPR(ctx->opcode);

    if (unlikely(!ctx->supervisor)) {
5346
        GEN_EXCP_PRIVREG(ctx);
5347 5348
        return;
    }
5349
    tcg_gen_movi_tl(cpu_T[0], dcrn);
5350
    gen_op_load_dcr();
A
aurel32 已提交
5351
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
5352 5353 5354 5355
#endif
}

/* mtdcr */
5356
GEN_HANDLER(mtdcr, 0x1F, 0x03, 0x0E, 0x00000001, PPC_DCR)
5357 5358
{
#if defined(CONFIG_USER_ONLY)
5359
    GEN_EXCP_PRIVREG(ctx);
5360 5361 5362 5363
#else
    uint32_t dcrn = SPR(ctx->opcode);

    if (unlikely(!ctx->supervisor)) {
5364
        GEN_EXCP_PRIVREG(ctx);
5365 5366
        return;
    }
5367
    tcg_gen_movi_tl(cpu_T[0], dcrn);
A
aurel32 已提交
5368
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]);
5369 5370 5371 5372 5373
    gen_op_store_dcr();
#endif
}

/* mfdcrx */
5374
/* XXX: not implemented on 440 ? */
5375
GEN_HANDLER(mfdcrx, 0x1F, 0x03, 0x08, 0x00000000, PPC_DCRX)
5376 5377
{
#if defined(CONFIG_USER_ONLY)
5378
    GEN_EXCP_PRIVREG(ctx);
5379 5380
#else
    if (unlikely(!ctx->supervisor)) {
5381
        GEN_EXCP_PRIVREG(ctx);
5382 5383
        return;
    }
A
aurel32 已提交
5384
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
5385
    gen_op_load_dcr();
A
aurel32 已提交
5386
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
5387
    /* Note: Rc update flag set leads to undefined state of Rc0 */
5388 5389 5390 5391
#endif
}

/* mtdcrx */
5392
/* XXX: not implemented on 440 ? */
5393
GEN_HANDLER(mtdcrx, 0x1F, 0x03, 0x0C, 0x00000000, PPC_DCRX)
5394 5395
{
#if defined(CONFIG_USER_ONLY)
5396
    GEN_EXCP_PRIVREG(ctx);
5397 5398
#else
    if (unlikely(!ctx->supervisor)) {
5399
        GEN_EXCP_PRIVREG(ctx);
5400 5401
        return;
    }
A
aurel32 已提交
5402 5403
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]);
5404
    gen_op_store_dcr();
5405
    /* Note: Rc update flag set leads to undefined state of Rc0 */
5406 5407 5408
#endif
}

5409 5410 5411
/* mfdcrux (PPC 460) : user-mode access to DCR */
GEN_HANDLER(mfdcrux, 0x1F, 0x03, 0x09, 0x00000000, PPC_DCRUX)
{
A
aurel32 已提交
5412
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
5413
    gen_op_load_dcr();
A
aurel32 已提交
5414
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
5415 5416 5417 5418 5419 5420
    /* 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 已提交
5421 5422
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]);
5423 5424 5425 5426
    gen_op_store_dcr();
    /* Note: Rc update flag set leads to undefined state of Rc0 */
}

5427 5428 5429 5430
/* dccci */
GEN_HANDLER(dccci, 0x1F, 0x06, 0x0E, 0x03E00001, PPC_4xx_COMMON)
{
#if defined(CONFIG_USER_ONLY)
5431
    GEN_EXCP_PRIVOPC(ctx);
5432 5433
#else
    if (unlikely(!ctx->supervisor)) {
5434
        GEN_EXCP_PRIVOPC(ctx);
5435 5436 5437 5438 5439 5440 5441 5442 5443 5444
        return;
    }
    /* interpreted as no-op */
#endif
}

/* dcread */
GEN_HANDLER(dcread, 0x1F, 0x06, 0x0F, 0x00000001, PPC_4xx_COMMON)
{
#if defined(CONFIG_USER_ONLY)
5445
    GEN_EXCP_PRIVOPC(ctx);
5446
#else
A
aurel32 已提交
5447
    TCGv EA, val;
5448
    if (unlikely(!ctx->supervisor)) {
5449
        GEN_EXCP_PRIVOPC(ctx);
5450 5451
        return;
    }
P
pbrook 已提交
5452
    EA = tcg_temp_new();
A
aurel32 已提交
5453
    gen_set_access_type(ACCESS_CACHE);
A
aurel32 已提交
5454
    gen_addr_reg_index(EA, ctx);
P
pbrook 已提交
5455
    val = tcg_temp_new();
A
aurel32 已提交
5456 5457 5458 5459
    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);
5460 5461 5462 5463
#endif
}

/* icbt */
5464
GEN_HANDLER2(icbt_40x, "icbt", 0x1F, 0x06, 0x08, 0x03E00001, PPC_40x_ICBT)
5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475
{
    /* 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)
5476
    GEN_EXCP_PRIVOPC(ctx);
5477 5478
#else
    if (unlikely(!ctx->supervisor)) {
5479
        GEN_EXCP_PRIVOPC(ctx);
5480 5481 5482 5483 5484 5485 5486 5487 5488 5489
        return;
    }
    /* interpreted as no-op */
#endif
}

/* icread */
GEN_HANDLER(icread, 0x1F, 0x06, 0x1F, 0x03E00001, PPC_4xx_COMMON)
{
#if defined(CONFIG_USER_ONLY)
5490
    GEN_EXCP_PRIVOPC(ctx);
5491 5492
#else
    if (unlikely(!ctx->supervisor)) {
5493
        GEN_EXCP_PRIVOPC(ctx);
5494 5495 5496 5497 5498 5499 5500
        return;
    }
    /* interpreted as no-op */
#endif
}

/* rfci (supervisor only) */
5501
GEN_HANDLER2(rfci_40x, "rfci", 0x13, 0x13, 0x01, 0x03FF8001, PPC_40x_EXCP)
5502 5503
{
#if defined(CONFIG_USER_ONLY)
5504
    GEN_EXCP_PRIVOPC(ctx);
5505 5506
#else
    if (unlikely(!ctx->supervisor)) {
5507
        GEN_EXCP_PRIVOPC(ctx);
5508 5509 5510
        return;
    }
    /* Restore CPU state */
5511
    gen_helper_40x_rfci();
5512
    GEN_SYNC(ctx);
5513 5514 5515 5516 5517 5518
#endif
}

GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE)
{
#if defined(CONFIG_USER_ONLY)
5519
    GEN_EXCP_PRIVOPC(ctx);
5520 5521
#else
    if (unlikely(!ctx->supervisor)) {
5522
        GEN_EXCP_PRIVOPC(ctx);
5523 5524 5525
        return;
    }
    /* Restore CPU state */
5526
    gen_helper_rfci();
5527
    GEN_SYNC(ctx);
5528 5529 5530 5531
#endif
}

/* BookE specific */
5532
/* XXX: not implemented on 440 ? */
5533
GEN_HANDLER(rfdi, 0x13, 0x07, 0x01, 0x03FF8001, PPC_RFDI)
5534 5535
{
#if defined(CONFIG_USER_ONLY)
5536
    GEN_EXCP_PRIVOPC(ctx);
5537 5538
#else
    if (unlikely(!ctx->supervisor)) {
5539
        GEN_EXCP_PRIVOPC(ctx);
5540 5541 5542
        return;
    }
    /* Restore CPU state */
5543
    gen_helper_rfdi();
5544
    GEN_SYNC(ctx);
5545 5546 5547
#endif
}

5548
/* XXX: not implemented on 440 ? */
5549
GEN_HANDLER(rfmci, 0x13, 0x06, 0x01, 0x03FF8001, PPC_RFMCI)
5550 5551
{
#if defined(CONFIG_USER_ONLY)
5552
    GEN_EXCP_PRIVOPC(ctx);
5553 5554
#else
    if (unlikely(!ctx->supervisor)) {
5555
        GEN_EXCP_PRIVOPC(ctx);
5556 5557 5558
        return;
    }
    /* Restore CPU state */
5559
    gen_helper_rfmci();
5560
    GEN_SYNC(ctx);
5561 5562
#endif
}
5563

5564
/* TLB management - PowerPC 405 implementation */
5565
/* tlbre */
5566
GEN_HANDLER2(tlbre_40x, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_TLB)
5567 5568
{
#if defined(CONFIG_USER_ONLY)
5569
    GEN_EXCP_PRIVOPC(ctx);
5570 5571
#else
    if (unlikely(!ctx->supervisor)) {
5572
        GEN_EXCP_PRIVOPC(ctx);
5573 5574 5575 5576
        return;
    }
    switch (rB(ctx->opcode)) {
    case 0:
A
aurel32 已提交
5577
        tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
5578
        gen_op_4xx_tlbre_hi();
A
aurel32 已提交
5579
        tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
5580 5581
        break;
    case 1:
A
aurel32 已提交
5582
        tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
5583
        gen_op_4xx_tlbre_lo();
A
aurel32 已提交
5584
        tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
5585 5586
        break;
    default:
5587
        GEN_EXCP_INVAL(ctx);
5588
        break;
5589
    }
5590 5591 5592
#endif
}

5593
/* tlbsx - tlbsx. */
5594
GEN_HANDLER2(tlbsx_40x, "tlbsx", 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_TLB)
5595 5596
{
#if defined(CONFIG_USER_ONLY)
5597
    GEN_EXCP_PRIVOPC(ctx);
5598 5599
#else
    if (unlikely(!ctx->supervisor)) {
5600
        GEN_EXCP_PRIVOPC(ctx);
5601 5602
        return;
    }
5603
    gen_addr_reg_index(cpu_T[0], ctx);
5604
    gen_op_4xx_tlbsx();
5605
    if (Rc(ctx->opcode))
5606
        gen_op_4xx_tlbsx_check();
A
aurel32 已提交
5607
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
5608
#endif
B
bellard 已提交
5609 5610
}

5611
/* tlbwe */
5612
GEN_HANDLER2(tlbwe_40x, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_TLB)
B
bellard 已提交
5613
{
5614
#if defined(CONFIG_USER_ONLY)
5615
    GEN_EXCP_PRIVOPC(ctx);
5616 5617
#else
    if (unlikely(!ctx->supervisor)) {
5618
        GEN_EXCP_PRIVOPC(ctx);
5619 5620 5621 5622
        return;
    }
    switch (rB(ctx->opcode)) {
    case 0:
A
aurel32 已提交
5623 5624
        tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
        tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]);
5625 5626 5627
        gen_op_4xx_tlbwe_hi();
        break;
    case 1:
A
aurel32 已提交
5628 5629
        tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
        tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]);
5630 5631 5632
        gen_op_4xx_tlbwe_lo();
        break;
    default:
5633
        GEN_EXCP_INVAL(ctx);
5634
        break;
5635
    }
5636 5637 5638
#endif
}

5639
/* TLB management - PowerPC 440 implementation */
5640
/* tlbre */
5641
GEN_HANDLER2(tlbre_440, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE)
5642 5643
{
#if defined(CONFIG_USER_ONLY)
5644
    GEN_EXCP_PRIVOPC(ctx);
5645 5646
#else
    if (unlikely(!ctx->supervisor)) {
5647
        GEN_EXCP_PRIVOPC(ctx);
5648 5649 5650 5651 5652 5653
        return;
    }
    switch (rB(ctx->opcode)) {
    case 0:
    case 1:
    case 2:
A
aurel32 已提交
5654
        tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
5655
        gen_op_440_tlbre(rB(ctx->opcode));
A
aurel32 已提交
5656
        tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
5657 5658
        break;
    default:
5659
        GEN_EXCP_INVAL(ctx);
5660 5661 5662 5663 5664 5665
        break;
    }
#endif
}

/* tlbsx - tlbsx. */
5666
GEN_HANDLER2(tlbsx_440, "tlbsx", 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE)
5667 5668
{
#if defined(CONFIG_USER_ONLY)
5669
    GEN_EXCP_PRIVOPC(ctx);
5670 5671
#else
    if (unlikely(!ctx->supervisor)) {
5672
        GEN_EXCP_PRIVOPC(ctx);
5673 5674
        return;
    }
5675
    gen_addr_reg_index(cpu_T[0], ctx);
5676
    gen_op_440_tlbsx();
5677
    if (Rc(ctx->opcode))
5678
        gen_op_4xx_tlbsx_check();
A
aurel32 已提交
5679
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
5680 5681 5682 5683
#endif
}

/* tlbwe */
5684
GEN_HANDLER2(tlbwe_440, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE)
5685 5686
{
#if defined(CONFIG_USER_ONLY)
5687
    GEN_EXCP_PRIVOPC(ctx);
5688 5689
#else
    if (unlikely(!ctx->supervisor)) {
5690
        GEN_EXCP_PRIVOPC(ctx);
5691 5692 5693 5694 5695 5696
        return;
    }
    switch (rB(ctx->opcode)) {
    case 0:
    case 1:
    case 2:
A
aurel32 已提交
5697 5698
        tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
        tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]);
5699
        gen_op_440_tlbwe(rB(ctx->opcode));
5700 5701
        break;
    default:
5702
        GEN_EXCP_INVAL(ctx);
5703 5704 5705 5706 5707
        break;
    }
#endif
}

5708
/* wrtee */
5709
GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_WRTEE)
5710 5711
{
#if defined(CONFIG_USER_ONLY)
5712
    GEN_EXCP_PRIVOPC(ctx);
5713 5714
#else
    if (unlikely(!ctx->supervisor)) {
5715
        GEN_EXCP_PRIVOPC(ctx);
5716 5717
        return;
    }
A
aurel32 已提交
5718
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rD(ctx->opcode)]);
5719
    gen_op_wrte();
J
j_mayer 已提交
5720 5721 5722
    /* Stop translation to have a chance to raise an exception
     * if we just set msr_ee to 1
     */
5723
    GEN_STOP(ctx);
5724 5725 5726 5727
#endif
}

/* wrteei */
5728
GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000EFC01, PPC_WRTEE)
5729 5730
{
#if defined(CONFIG_USER_ONLY)
5731
    GEN_EXCP_PRIVOPC(ctx);
5732 5733
#else
    if (unlikely(!ctx->supervisor)) {
5734
        GEN_EXCP_PRIVOPC(ctx);
5735 5736
        return;
    }
5737
    tcg_gen_movi_tl(cpu_T[0], ctx->opcode & 0x00010000);
5738
    gen_op_wrte();
J
j_mayer 已提交
5739 5740 5741
    /* Stop translation to have a chance to raise an exception
     * if we just set msr_ee to 1
     */
5742
    GEN_STOP(ctx);
5743 5744 5745
#endif
}

J
j_mayer 已提交
5746
/* PowerPC 440 specific instructions */
5747 5748 5749
/* dlmzb */
GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC)
{
A
aurel32 已提交
5750 5751
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
5752
    gen_op_440_dlmzb();
A
aurel32 已提交
5753
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
A
aurel32 已提交
5754 5755
    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~0x7F);
    tcg_gen_or_tl(cpu_xer, cpu_xer, cpu_T[0]);
5756 5757
    if (Rc(ctx->opcode)) {
        gen_op_440_dlmzb_update_Rc();
P
pbrook 已提交
5758 5759
        tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_T[0]);
        tcg_gen_andi_i32(cpu_crf[0], cpu_crf[0], 0xf);
5760 5761 5762 5763 5764 5765 5766 5767 5768 5769
    }
}

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

/* msync replaces sync on 440 */
5770
GEN_HANDLER(msync, 0x1F, 0x16, 0x12, 0x03FFF801, PPC_BOOKE)
5771 5772 5773 5774 5775
{
    /* interpreted as no-op */
}

/* icbt */
5776
GEN_HANDLER2(icbt_440, "icbt", 0x1F, 0x16, 0x00, 0x03E00001, PPC_BOOKE)
5777 5778 5779 5780 5781
{
    /* interpreted as no-op */
    /* XXX: specification say this is treated as a load by the MMU
     *      but does not generate any exception
     */
B
bellard 已提交
5782 5783
}

5784 5785 5786 5787
/***                      Altivec vector extension                         ***/
/* Altivec registers moves */

#define GEN_VR_LDX(name, opc2, opc3)                                          \
5788
GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC)                  \
5789
{                                                                             \
5790
    TCGv EA;                                                                  \
5791 5792 5793 5794
    if (unlikely(!ctx->altivec_enabled)) {                                    \
        GEN_EXCP_NO_VR(ctx);                                                  \
        return;                                                               \
    }                                                                         \
5795 5796 5797 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807
    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);                                                        \
5808 5809 5810 5811 5812
}

#define GEN_VR_STX(name, opc2, opc3)                                          \
GEN_HANDLER(st##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC)              \
{                                                                             \
5813
    TCGv EA;                                                                  \
5814 5815 5816 5817
    if (unlikely(!ctx->altivec_enabled)) {                                    \
        GEN_EXCP_NO_VR(ctx);                                                  \
        return;                                                               \
    }                                                                         \
5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830
    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);                                                        \
5831 5832
}

5833
GEN_VR_LDX(lvx, 0x07, 0x03);
5834
/* As we don't emulate the cache, lvxl is stricly equivalent to lvx */
5835
GEN_VR_LDX(lvxl, 0x07, 0x0B);
5836

5837
GEN_VR_STX(svx, 0x07, 0x07);
5838
/* As we don't emulate the cache, stvxl is stricly equivalent to stvx */
5839
GEN_VR_STX(svxl, 0x07, 0x0F);
5840

5841 5842
/***                           SPE extension                               ***/
/* Register moves */
5843

P
pbrook 已提交
5844
static always_inline void gen_load_gpr64(TCGv_i64 t, int reg) {
A
aurel32 已提交
5845 5846 5847
#if defined(TARGET_PPC64)
    tcg_gen_mov_i64(t, cpu_gpr[reg]);
#else
P
pbrook 已提交
5848
    tcg_gen_concat_i32_i64(t, cpu_gpr[reg], cpu_gprh[reg]);
5849
#endif
A
aurel32 已提交
5850
}
5851

P
pbrook 已提交
5852
static always_inline void gen_store_gpr64(int reg, TCGv_i64 t) {
A
aurel32 已提交
5853 5854 5855
#if defined(TARGET_PPC64)
    tcg_gen_mov_i64(cpu_gpr[reg], t);
#else
P
pbrook 已提交
5856
    TCGv_i64 tmp = tcg_temp_new_i64();
A
aurel32 已提交
5857 5858 5859
    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 已提交
5860
    tcg_temp_free_i64(tmp);
5861
#endif
A
aurel32 已提交
5862
}
5863

5864 5865 5866 5867 5868 5869 5870 5871 5872 5873
#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 */
5874
static always_inline void gen_speundef (DisasContext *ctx)
5875
{
5876
    GEN_EXCP_INVAL(ctx);
5877 5878
}

5879 5880 5881
/* SPE logic */
#if defined(TARGET_PPC64)
#define GEN_SPEOP_LOGIC2(name, tcg_op)                                        \
5882
static always_inline void gen_##name (DisasContext *ctx)                      \
5883 5884
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
5885
        GEN_EXCP_NO_AP(ctx);                                                  \
5886 5887
        return;                                                               \
    }                                                                         \
5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901 5902
    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)]);                                        \
5903
}
5904 5905 5906 5907 5908 5909 5910 5911 5912 5913
#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);
5914

5915 5916 5917
/* SPE logic immediate */
#if defined(TARGET_PPC64)
#define GEN_SPEOP_TCG_LOGIC_IMM2(name, tcg_opi)                               \
5918 5919 5920 5921 5922 5923
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        return;                                                               \
    }                                                                         \
P
pbrook 已提交
5924 5925 5926
    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
    TCGv_i64 t2 = tcg_temp_local_new_i64();                                   \
5927 5928 5929 5930
    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 已提交
5931
    tcg_temp_free_i64(t2);                                                    \
5932 5933
    tcg_opi(t1, t1, rB(ctx->opcode));                                         \
    tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1);                 \
P
pbrook 已提交
5934 5935
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
5936
}
5937 5938
#else
#define GEN_SPEOP_TCG_LOGIC_IMM2(name, tcg_opi)                               \
5939
static always_inline void gen_##name (DisasContext *ctx)                      \
5940 5941
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
5942
        GEN_EXCP_NO_AP(ctx);                                                  \
5943 5944
        return;                                                               \
    }                                                                         \
5945 5946 5947 5948
    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));                                                 \
5949
}
5950 5951 5952 5953 5954
#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);
5955

5956 5957 5958
/* SPE arithmetic */
#if defined(TARGET_PPC64)
#define GEN_SPEOP_ARITH1(name, tcg_op)                                        \
5959
static always_inline void gen_##name (DisasContext *ctx)                      \
5960 5961
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
5962
        GEN_EXCP_NO_AP(ctx);                                                  \
5963 5964
        return;                                                               \
    }                                                                         \
P
pbrook 已提交
5965 5966 5967
    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
    TCGv_i64 t2 = tcg_temp_local_new_i64();                                   \
5968 5969 5970 5971
    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 已提交
5972
    tcg_temp_free_i64(t2);                                                    \
5973 5974
    tcg_op(t1, t1);                                                           \
    tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1);                 \
P
pbrook 已提交
5975 5976
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
5977
}
5978
#else
P
pbrook 已提交
5979
#define GEN_SPEOP_ARITH1(name, tcg_op)                                        \
5980 5981 5982 5983 5984 5985 5986 5987 5988 5989
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
5990

P
pbrook 已提交
5991
static always_inline void gen_op_evabs (TCGv_i32 ret, TCGv_i32 arg1)
5992 5993 5994
{
    int l1 = gen_new_label();
    int l2 = gen_new_label();
5995

5996 5997 5998 5999
    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 已提交
6000
    tcg_gen_mov_i32(ret, arg1);
6001 6002 6003 6004 6005 6006
    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 已提交
6007
static always_inline void gen_op_evrndw (TCGv_i32 ret, TCGv_i32 arg1)
6008
{
6009 6010 6011 6012
    tcg_gen_addi_i32(ret, arg1, 0x8000);
    tcg_gen_ext16u_i32(ret, ret);
}
GEN_SPEOP_ARITH1(evrndw, gen_op_evrndw);
P
pbrook 已提交
6013 6014
GEN_SPEOP_ARITH1(evcntlsw, gen_helper_cntlsw32);
GEN_SPEOP_ARITH1(evcntlzw, gen_helper_cntlzw32);
6015

6016 6017 6018
#if defined(TARGET_PPC64)
#define GEN_SPEOP_ARITH2(name, tcg_op)                                        \
static always_inline void gen_##name (DisasContext *ctx)                      \
6019 6020
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
6021
        GEN_EXCP_NO_AP(ctx);                                                  \
6022 6023
        return;                                                               \
    }                                                                         \
P
pbrook 已提交
6024 6025 6026 6027
    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);                           \
6028 6029 6030 6031 6032 6033 6034
    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 已提交
6035
    tcg_temp_free_i64(t3);                                                    \
6036
    tcg_op(t1, t1, t2);                                                       \
P
pbrook 已提交
6037
    tcg_temp_free_i32(t2);                                                    \
6038
    tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1);                 \
P
pbrook 已提交
6039 6040
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
6041
}
6042 6043 6044
#else
#define GEN_SPEOP_ARITH2(name, tcg_op)                                        \
static always_inline void gen_##name (DisasContext *ctx)                      \
6045 6046
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
6047
        GEN_EXCP_NO_AP(ctx);                                                  \
6048 6049
        return;                                                               \
    }                                                                         \
6050 6051 6052 6053
    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)]);                                        \
6054
}
6055
#endif
6056

P
pbrook 已提交
6057
static always_inline void gen_op_evsrwu (TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
6058
{
P
pbrook 已提交
6059
    TCGv_i32 t0;
6060
    int l1, l2;
6061

6062 6063
    l1 = gen_new_label();
    l2 = gen_new_label();
P
pbrook 已提交
6064
    t0 = tcg_temp_local_new_i32();
6065 6066 6067 6068 6069 6070 6071 6072
    /* 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 已提交
6073
    tcg_temp_free_i32(t0);
6074 6075
}
GEN_SPEOP_ARITH2(evsrwu, gen_op_evsrwu);
P
pbrook 已提交
6076
static always_inline void gen_op_evsrws (TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
6077
{
P
pbrook 已提交
6078
    TCGv_i32 t0;
6079 6080 6081 6082
    int l1, l2;

    l1 = gen_new_label();
    l2 = gen_new_label();
P
pbrook 已提交
6083
    t0 = tcg_temp_local_new_i32();
6084 6085 6086 6087 6088 6089 6090 6091
    /* 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 已提交
6092
    tcg_temp_free_i32(t0);
6093 6094
}
GEN_SPEOP_ARITH2(evsrws, gen_op_evsrws);
P
pbrook 已提交
6095
static always_inline void gen_op_evslw (TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
6096
{
P
pbrook 已提交
6097
    TCGv_i32 t0;
6098 6099 6100 6101
    int l1, l2;

    l1 = gen_new_label();
    l2 = gen_new_label();
P
pbrook 已提交
6102
    t0 = tcg_temp_local_new_i32();
6103 6104 6105 6106 6107 6108 6109 6110
    /* 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 已提交
6111
    tcg_temp_free_i32(t0);
6112 6113
}
GEN_SPEOP_ARITH2(evslw, gen_op_evslw);
P
pbrook 已提交
6114
static always_inline void gen_op_evrlw (TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
6115
{
P
pbrook 已提交
6116
    TCGv_i32 t0 = tcg_temp_new_i32();
6117 6118
    tcg_gen_andi_i32(t0, arg2, 0x1F);
    tcg_gen_rotl_i32(ret, arg1, t0);
P
pbrook 已提交
6119
    tcg_temp_free_i32(t0);
6120 6121 6122 6123 6124 6125 6126 6127 6128
}
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 已提交
6129 6130
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141
    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 已提交
6142
static always_inline void gen_op_evsubf (TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
6143
{
6144 6145 6146
    tcg_gen_sub_i32(ret, arg2, arg1);
}
GEN_SPEOP_ARITH2(evsubfw, gen_op_evsubf);
6147

6148 6149 6150 6151 6152 6153 6154 6155 6156
/* 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 已提交
6157 6158 6159
    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
    TCGv_i64 t2 = tcg_temp_local_new_i64();                                   \
6160 6161 6162 6163
    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 已提交
6164
    tcg_temp_free_i64(t2);                                                        \
6165 6166
    tcg_op(t1, t1, rA(ctx->opcode));                                          \
    tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1);                 \
P
pbrook 已提交
6167 6168
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199
}
#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 已提交
6200 6201 6202
    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
    TCGv_i64 t2 = tcg_temp_local_new_i64();                                   \
6203 6204 6205
    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 已提交
6206
    tcg_gen_movi_i32(cpu_crf[crfD(ctx->opcode)], 0);                          \
6207 6208 6209 6210 6211 6212 6213 6214 6215
    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 已提交
6216
    tcg_temp_free_i64(t2);                                                    \
6217 6218 6219 6220 6221 6222 6223 6224
    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 已提交
6225 6226
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269
}
#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 已提交
6270 6271
    gen_helper_brinc(cpu_gpr[rD(ctx->opcode)],
                     cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
6272
}
6273 6274 6275 6276 6277 6278 6279
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 已提交
6280 6281
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298
    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 已提交
6299 6300
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317
    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 已提交
6318 6319
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331
    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)
{
6332
    uint64_t imm = ((int32_t)(rA(ctx->opcode) << 11)) >> 27;
6333

6334
#if defined(TARGET_PPC64)
6335
    tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], (imm << 32) | imm);
6336 6337 6338 6339 6340
#else
    tcg_gen_movi_i32(cpu_gpr[rD(ctx->opcode)], imm);
    tcg_gen_movi_i32(cpu_gprh[rD(ctx->opcode)], imm);
#endif
}
6341
static always_inline void gen_evsplatfi (DisasContext *ctx)
6342
{
6343
    uint64_t imm = rA(ctx->opcode) << 11;
6344

6345
#if defined(TARGET_PPC64)
6346
    tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], (imm << 32) | imm);
6347 6348 6349 6350
#else
    tcg_gen_movi_i32(cpu_gpr[rD(ctx->opcode)], imm);
    tcg_gen_movi_i32(cpu_gprh[rD(ctx->opcode)], imm);
#endif
6351 6352
}

6353 6354 6355 6356 6357 6358
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 已提交
6359
    TCGv_i32 t0 = tcg_temp_local_new_i32();
6360
#if defined(TARGET_PPC64)
P
pbrook 已提交
6361 6362
    TCGv t1 = tcg_temp_local_new();
    TCGv t2 = tcg_temp_local_new();
6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393
#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 已提交
6394
    tcg_temp_free_i32(t0);
6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415 6416
#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);
}
6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443

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

6444 6445 6446 6447 6448 6449 6450 6451 6452
/* 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);
6453
}
6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466

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
6467
}
6468 6469 6470

static always_inline void gen_op_evldw(DisasContext *ctx, TCGv addr)
{
6471
#if defined(TARGET_PPC64)
6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483
    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
6484
}
6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502

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);
6503
#else
6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514
    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);
6515
#endif
6516
    tcg_temp_free(t0);
6517 6518
}

6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532
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);
6533 6534
}

6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546
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);
6547 6548
}

6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 6580 6581 6582 6583 6584 6585 6586 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 6614 6615 6616 6617 6618 6619 6620 6621
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);
6622
#if defined(TARGET_PPC64)
6623 6624 6625 6626 6627 6628 6629 6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652
    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);
6653
#endif
6654 6655 6656 6657 6658 6659 6660
    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);
6661
#else
6662 6663 6664 6665 6666 6667 6668 6669 6670
    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)
{
6671
#if defined(TARGET_PPC64)
6672 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 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
    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);
6790 6791 6792 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 6823 6824 6825 6826 6827 6828 6829 6830 6831 6832 6833 6834 6835 6836 6837 6838 6839 6840 6841 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

/* 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 已提交
6868 6869
#if defined(TARGET_PPC64)
#define GEN_SPEFPUOP_CONV_32_32(name)                                         \
6870
static always_inline void gen_##name (DisasContext *ctx)                      \
6871
{                                                                             \
A
aurel32 已提交
6872 6873 6874 6875 6876 6877 6878 6879 6880 6881 6882 6883
    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);                                                        \
6884
}
A
aurel32 已提交
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
#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)                                       \
6914 6915
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
A
aurel32 已提交
6916 6917
    TCGv_i32 t0, t1;                                                          \
    TCGv_i64 t2;                                                              \
6918 6919 6920 6921
    if (unlikely(!ctx->spe_enabled)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
6922 6923 6924 6925 6926 6927 6928 6929 6930 6931 6932 6933 6934
    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);                                                        \
6935
}
A
aurel32 已提交
6936
#define GEN_SPEFPUOP_ARITH2_64_64(name)                                       \
6937 6938 6939 6940 6941 6942
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
6943 6944
    gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],     \
                      cpu_gpr[rB(ctx->opcode)]);                              \
6945
}
A
aurel32 已提交
6946
#define GEN_SPEFPUOP_COMP_32(name)                                            \
6947 6948
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
A
aurel32 已提交
6949
    TCGv_i32 t0, t1;                                                          \
6950 6951 6952 6953
    if (unlikely(!ctx->spe_enabled)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
6954 6955 6956 6957 6958 6959 6960 6961 6962 6963 6964 6965 6966 6967 6968 6969 6970 6971 6972 6973 6974 6975 6976
    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)]);    \
6977
}
A
aurel32 已提交
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 7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056
#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
7057

7058 7059
/* Single precision floating-point vectors operations */
/* Arithmetic */
A
aurel32 已提交
7060 7061 7062 7063 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 7080 7081 7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 7093 7094 7095 7096 7097 7098 7099 7100 7101 7102 7103
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
}

7104
/* Conversion */
A
aurel32 已提交
7105 7106 7107 7108 7109 7110 7111 7112 7113 7114 7115
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);

7116
/* Comparison */
A
aurel32 已提交
7117 7118 7119 7120 7121 7122
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);
7123 7124 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 7136 7137 7138 7139 7140 7141

/* 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 已提交
7142 7143 7144 7145 7146 7147 7148 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7160 7161 7162 7163 7164 7165 7166 7167 7168 7169 7170
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);
}

7171
/* Conversion */
A
aurel32 已提交
7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 7182 7183
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);

7184
/* Comparison */
A
aurel32 已提交
7185 7186 7187 7188 7189 7190
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);
7191 7192

/* Opcodes definitions */
7193
GEN_SPE(efsadd,         efssub,        0x00, 0x0B, 0x00000000, PPC_SPEFPU); //
7194 7195 7196 7197 7198 7199 7200 7201 7202
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); //
7203 7204
GEN_SPE(efsctuiz,       speundef,      0x0C, 0x0B, 0x00180000, PPC_SPEFPU); //
GEN_SPE(efsctsiz,       speundef,      0x0D, 0x0B, 0x00180000, PPC_SPEFPU); //
7205 7206 7207 7208 7209
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 已提交
7210 7211 7212 7213 7214 7215 7216 7217 7218 7219 7220 7221 7222 7223 7224 7225 7226 7227 7228 7229 7230 7231 7232 7233 7234 7235 7236 7237 7238 7239 7240 7241 7242 7243 7244 7245 7246 7247 7248 7249 7250
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
}

7251
/* Conversion */
A
aurel32 已提交
7252 7253 7254 7255 7256 7257 7258 7259 7260 7261 7262 7263 7264 7265 7266
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);
7267 7268

/* Comparison */
A
aurel32 已提交
7269 7270 7271 7272 7273 7274
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);
7275 7276 7277 7278 7279 7280 7281 7282 7283 7284 7285 7286 7287 7288 7289 7290 7291 7292 7293

/* 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 已提交
7294 7295 7296
/* End opcode list */
GEN_OPCODE_MARK(end);

7297
#include "translate_init.c"
7298
#include "helper_regs.h"
B
bellard 已提交
7299

7300
/*****************************************************************************/
7301
/* Misc PowerPC helpers */
7302 7303 7304
void cpu_dump_state (CPUState *env, FILE *f,
                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
                     int flags)
B
bellard 已提交
7305
{
7306 7307 7308
#define RGPL  4
#define RFPL  4

B
bellard 已提交
7309 7310
    int i;

J
j_mayer 已提交
7311
    cpu_fprintf(f, "NIP " ADDRX "   LR " ADDRX " CTR " ADDRX " XER %08x\n",
A
aurel32 已提交
7312
                env->nip, env->lr, env->ctr, env->xer);
7313 7314
    cpu_fprintf(f, "MSR " ADDRX " HID0 " ADDRX "  HF " ADDRX " idx %d\n",
                env->msr, env->spr[SPR_HID0], env->hflags, env->mmu_idx);
7315
#if !defined(NO_TIMER_DUMP)
J
j_mayer 已提交
7316
    cpu_fprintf(f, "TB %08x %08x "
7317 7318 7319 7320
#if !defined(CONFIG_USER_ONLY)
                "DECR %08x"
#endif
                "\n",
J
j_mayer 已提交
7321
                cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env)
7322 7323 7324 7325
#if !defined(CONFIG_USER_ONLY)
                , cpu_ppc_load_decr(env)
#endif
                );
J
j_mayer 已提交
7326
#endif
7327
    for (i = 0; i < 32; i++) {
7328 7329
        if ((i & (RGPL - 1)) == 0)
            cpu_fprintf(f, "GPR%02d", i);
7330
        cpu_fprintf(f, " " REGX, ppc_dump_gpr(env, i));
7331
        if ((i & (RGPL - 1)) == (RGPL - 1))
B
bellard 已提交
7332
            cpu_fprintf(f, "\n");
7333
    }
7334
    cpu_fprintf(f, "CR ");
7335
    for (i = 0; i < 8; i++)
B
bellard 已提交
7336 7337
        cpu_fprintf(f, "%01x", env->crf[i]);
    cpu_fprintf(f, "  [");
7338 7339 7340 7341 7342 7343 7344 7345
    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 已提交
7346
        cpu_fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' ');
7347
    }
7348
    cpu_fprintf(f, " ]             RES " ADDRX "\n", env->reserve);
7349 7350 7351
    for (i = 0; i < 32; i++) {
        if ((i & (RFPL - 1)) == 0)
            cpu_fprintf(f, "FPR%02d", i);
B
bellard 已提交
7352
        cpu_fprintf(f, " %016" PRIx64, *((uint64_t *)&env->fpr[i]));
7353
        if ((i & (RFPL - 1)) == (RFPL - 1))
B
bellard 已提交
7354
            cpu_fprintf(f, "\n");
B
bellard 已提交
7355
    }
7356
#if !defined(CONFIG_USER_ONLY)
7357
    cpu_fprintf(f, "SRR0 " ADDRX " SRR1 " ADDRX " SDR1 " ADDRX "\n",
7358
                env->spr[SPR_SRR0], env->spr[SPR_SRR1], env->sdr1);
7359
#endif
B
bellard 已提交
7360

7361 7362
#undef RGPL
#undef RFPL
B
bellard 已提交
7363 7364
}

7365 7366 7367 7368 7369 7370 7371 7372 7373 7374 7375 7376 7377 7378 7379 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
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
}

7412
/*****************************************************************************/
7413 7414 7415
static always_inline void gen_intermediate_code_internal (CPUState *env,
                                                          TranslationBlock *tb,
                                                          int search_pc)
B
bellard 已提交
7416
{
7417
    DisasContext ctx, *ctxp = &ctx;
B
bellard 已提交
7418
    opc_handler_t **table, *handler;
B
bellard 已提交
7419
    target_ulong pc_start;
B
bellard 已提交
7420
    uint16_t *gen_opc_end;
7421
    int supervisor, little_endian;
7422
    CPUBreakpoint *bp;
B
bellard 已提交
7423
    int j, lj = -1;
P
pbrook 已提交
7424 7425
    int num_insns;
    int max_insns;
B
bellard 已提交
7426 7427 7428

    pc_start = tb->pc;
    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
7429 7430 7431
#if defined(OPTIMIZE_FPRF_UPDATE)
    gen_fprf_ptr = gen_fprf_buf;
#endif
B
bellard 已提交
7432
    ctx.nip = pc_start;
B
bellard 已提交
7433
    ctx.tb = tb;
7434
    ctx.exception = POWERPC_EXCP_NONE;
7435
    ctx.spr_cb = env->spr_cb;
7436 7437
    supervisor = env->mmu_idx;
#if !defined(CONFIG_USER_ONLY)
7438
    ctx.supervisor = supervisor;
7439
#endif
7440
    little_endian = env->hflags & (1 << MSR_LE) ? 1 : 0;
7441 7442
#if defined(TARGET_PPC64)
    ctx.sf_mode = msr_sf;
7443
    ctx.mem_idx = (supervisor << 2) | (msr_sf << 1) | little_endian;
7444
#else
7445
    ctx.mem_idx = (supervisor << 1) | little_endian;
7446
#endif
B
bellard 已提交
7447
    ctx.fpu_enabled = msr_fp;
7448
    if ((env->flags & POWERPC_FLAG_SPE) && msr_spe)
7449 7450 7451
        ctx.spe_enabled = msr_spe;
    else
        ctx.spe_enabled = 0;
7452 7453 7454 7455
    if ((env->flags & POWERPC_FLAG_VRE) && msr_vr)
        ctx.altivec_enabled = msr_vr;
    else
        ctx.altivec_enabled = 0;
7456
    if ((env->flags & POWERPC_FLAG_SE) && msr_se)
7457
        ctx.singlestep_enabled = CPU_SINGLE_STEP;
7458
    else
7459
        ctx.singlestep_enabled = 0;
7460
    if ((env->flags & POWERPC_FLAG_BE) && msr_be)
7461 7462 7463
        ctx.singlestep_enabled |= CPU_BRANCH_STEP;
    if (unlikely(env->singlestep_enabled))
        ctx.singlestep_enabled |= GDBSTUB_SINGLE_STEP;
7464
#if defined (DO_SINGLE_STEP) && 0
7465 7466 7467
    /* Single step trace mode */
    msr_se = 1;
#endif
P
pbrook 已提交
7468 7469 7470 7471 7472 7473
    num_insns = 0;
    max_insns = tb->cflags & CF_COUNT_MASK;
    if (max_insns == 0)
        max_insns = CF_COUNT_MASK;

    gen_icount_start();
7474
    /* Set env in case of segfault during code fetch */
7475
    while (ctx.exception == POWERPC_EXCP_NONE && gen_opc_ptr < gen_opc_end) {
7476 7477
        if (unlikely(!TAILQ_EMPTY(&env->breakpoints))) {
            TAILQ_FOREACH(bp, &env->breakpoints, entry) {
7478
                if (bp->pc == ctx.nip) {
7479
                    gen_update_nip(&ctx, ctx.nip);
7480
                    gen_helper_raise_debug();
7481 7482 7483 7484
                    break;
                }
            }
        }
7485
        if (unlikely(search_pc)) {
B
bellard 已提交
7486 7487 7488 7489 7490
            j = gen_opc_ptr - gen_opc_buf;
            if (lj < j) {
                lj++;
                while (lj < j)
                    gen_opc_instr_start[lj++] = 0;
B
bellard 已提交
7491
                gen_opc_pc[lj] = ctx.nip;
B
bellard 已提交
7492
                gen_opc_instr_start[lj] = 1;
P
pbrook 已提交
7493
                gen_opc_icount[lj] = num_insns;
B
bellard 已提交
7494 7495
            }
        }
7496 7497
#if defined PPC_DEBUG_DISAS
        if (loglevel & CPU_LOG_TB_IN_ASM) {
B
bellard 已提交
7498
            fprintf(logfile, "----------------\n");
7499
            fprintf(logfile, "nip=" ADDRX " super=%d ir=%d\n",
7500
                    ctx.nip, supervisor, (int)msr_ir);
7501 7502
        }
#endif
P
pbrook 已提交
7503 7504
        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
            gen_io_start();
7505 7506 7507 7508
        if (unlikely(little_endian)) {
            ctx.opcode = bswap32(ldl_code(ctx.nip));
        } else {
            ctx.opcode = ldl_code(ctx.nip);
7509
        }
7510 7511
#if defined PPC_DEBUG_DISAS
        if (loglevel & CPU_LOG_TB_IN_ASM) {
7512
            fprintf(logfile, "translate opcode %08x (%02x %02x %02x) (%s)\n",
7513
                    ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode),
7514
                    opc3(ctx.opcode), little_endian ? "little" : "big");
B
bellard 已提交
7515 7516
        }
#endif
B
bellard 已提交
7517
        ctx.nip += 4;
7518
        table = env->opcodes;
P
pbrook 已提交
7519
        num_insns++;
B
bellard 已提交
7520 7521 7522 7523 7524 7525 7526 7527 7528 7529
        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 ? */
7530
        if (unlikely(handler->handler == &gen_invalid)) {
J
j_mayer 已提交
7531
            if (loglevel != 0) {
7532
                fprintf(logfile, "invalid/unsupported opcode: "
7533
                        "%02x - %02x - %02x (%08x) " ADDRX " %d\n",
7534
                        opc1(ctx.opcode), opc2(ctx.opcode),
7535
                        opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, (int)msr_ir);
B
bellard 已提交
7536 7537
            } else {
                printf("invalid/unsupported opcode: "
7538
                       "%02x - %02x - %02x (%08x) " ADDRX " %d\n",
B
bellard 已提交
7539
                       opc1(ctx.opcode), opc2(ctx.opcode),
7540
                       opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, (int)msr_ir);
B
bellard 已提交
7541
            }
7542 7543
        } else {
            if (unlikely((ctx.opcode & handler->inval) != 0)) {
J
j_mayer 已提交
7544
                if (loglevel != 0) {
B
bellard 已提交
7545
                    fprintf(logfile, "invalid bits: %08x for opcode: "
7546
                            "%02x - %02x - %02x (%08x) " ADDRX "\n",
B
bellard 已提交
7547 7548
                            ctx.opcode & handler->inval, opc1(ctx.opcode),
                            opc2(ctx.opcode), opc3(ctx.opcode),
B
bellard 已提交
7549
                            ctx.opcode, ctx.nip - 4);
7550 7551
                } else {
                    printf("invalid bits: %08x for opcode: "
7552
                           "%02x - %02x - %02x (%08x) " ADDRX "\n",
7553 7554
                           ctx.opcode & handler->inval, opc1(ctx.opcode),
                           opc2(ctx.opcode), opc3(ctx.opcode),
B
bellard 已提交
7555
                           ctx.opcode, ctx.nip - 4);
7556
                }
7557
                GEN_EXCP_INVAL(ctxp);
B
bellard 已提交
7558
                break;
B
bellard 已提交
7559 7560
            }
        }
B
bellard 已提交
7561
        (*(handler->handler))(&ctx);
7562 7563 7564
#if defined(DO_PPC_STATISTICS)
        handler->count++;
#endif
7565
        /* Check trace mode exceptions */
7566 7567 7568 7569 7570
        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)) {
7571
            GEN_EXCP(ctxp, POWERPC_EXCP_TRACE, 0);
7572
        } else if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) ||
P
pbrook 已提交
7573 7574
                            (env->singlestep_enabled) ||
                            num_insns >= max_insns)) {
7575 7576 7577
            /* if we reach a page boundary or are single stepping, stop
             * generation
             */
7578
            break;
7579
        }
7580 7581 7582 7583
#if defined (DO_SINGLE_STEP)
        break;
#endif
    }
P
pbrook 已提交
7584 7585
    if (tb->cflags & CF_LAST_IO)
        gen_io_end();
7586
    if (ctx.exception == POWERPC_EXCP_NONE) {
7587
        gen_goto_tb(&ctx, 0, ctx.nip);
7588
    } else if (ctx.exception != POWERPC_EXCP_BRANCH) {
7589 7590
        if (unlikely(env->singlestep_enabled)) {
            gen_update_nip(&ctx, ctx.nip);
7591
            gen_helper_raise_debug();
7592
        }
7593
        /* Generate the return instruction */
B
bellard 已提交
7594
        tcg_gen_exit_tb(0);
7595
    }
P
pbrook 已提交
7596
    gen_icount_end(tb, num_insns);
B
bellard 已提交
7597
    *gen_opc_ptr = INDEX_op_end;
7598
    if (unlikely(search_pc)) {
7599 7600 7601 7602 7603
        j = gen_opc_ptr - gen_opc_buf;
        lj++;
        while (lj <= j)
            gen_opc_instr_start[lj++] = 0;
    } else {
B
bellard 已提交
7604
        tb->size = ctx.nip - pc_start;
P
pbrook 已提交
7605
        tb->icount = num_insns;
7606
    }
7607
#if defined(DEBUG_DISAS)
7608
    if (loglevel & CPU_LOG_TB_CPU) {
7609
        fprintf(logfile, "---------------- excp: %04x\n", ctx.exception);
B
bellard 已提交
7610
        cpu_dump_state(env, logfile, fprintf, 0);
7611 7612
    }
    if (loglevel & CPU_LOG_TB_IN_ASM) {
7613
        int flags;
7614
        flags = env->bfd_mach;
7615
        flags |= little_endian << 16;
B
bellard 已提交
7616
        fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
7617
        target_disas(logfile, pc_start, ctx.nip - pc_start, flags);
B
bellard 已提交
7618
        fprintf(logfile, "\n");
7619
    }
B
bellard 已提交
7620 7621 7622
#endif
}

7623
void gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
B
bellard 已提交
7624
{
7625
    gen_intermediate_code_internal(env, tb, 0);
B
bellard 已提交
7626 7627
}

7628
void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
B
bellard 已提交
7629
{
7630
    gen_intermediate_code_internal(env, tb, 1);
B
bellard 已提交
7631
}
A
aurel32 已提交
7632 7633 7634 7635 7636 7637

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