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

B
bellard 已提交
26
#include "cpu.h"
B
bellard 已提交
27
#include "exec-all.h"
B
bellard 已提交
28
#include "disas.h"
B
bellard 已提交
29
#include "tcg-op.h"
30
#include "qemu-common.h"
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 */
A
aurel32 已提交
41
//#define DO_SINGLE_STEP
42
//#define PPC_DEBUG_DISAS
43
//#define DO_PPC_STATISTICS
B
bellard 已提交
44

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

A
aurel32 已提交
48
/* global register indexes */
P
pbrook 已提交
49
static TCGv_ptr cpu_env;
50
static char cpu_reg_names[10*3 + 22*4 /* GPR */
A
aurel32 已提交
51
#if !defined(TARGET_PPC64)
52
    + 10*4 + 22*5 /* SPE GPRh */
A
aurel32 已提交
53
#endif
A
aurel32 已提交
54
    + 10*4 + 22*5 /* FPR */
A
aurel32 已提交
55 56
    + 2*(10*6 + 22*7) /* AVRh, AVRl */
    + 8*5 /* CRF */];
A
aurel32 已提交
57 58 59 60
static TCGv cpu_gpr[32];
#if !defined(TARGET_PPC64)
static TCGv cpu_gprh[32];
#endif
P
pbrook 已提交
61 62 63
static TCGv_i64 cpu_fpr[32];
static TCGv_i64 cpu_avrh[32], cpu_avrl[32];
static TCGv_i32 cpu_crf[8];
A
aurel32 已提交
64
static TCGv cpu_nip;
65
static TCGv cpu_msr;
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

P
pbrook 已提交
73 74 75 76
#include "gen-icount.h"

void ppc_translate_init(void)
{
A
aurel32 已提交
77 78
    int i;
    char* p;
P
pbrook 已提交
79
    static int done_init = 0;
A
aurel32 已提交
80

P
pbrook 已提交
81 82
    if (done_init)
        return;
A
aurel32 已提交
83

P
pbrook 已提交
84 85
    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");

A
aurel32 已提交
86
    p = cpu_reg_names;
A
aurel32 已提交
87 88 89

    for (i = 0; i < 8; i++) {
        sprintf(p, "crf%d", i);
P
pbrook 已提交
90 91
        cpu_crf[i] = tcg_global_mem_new_i32(TCG_AREG0,
                                            offsetof(CPUState, crf[i]), p);
A
aurel32 已提交
92 93 94
        p += 5;
    }

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

A
aurel32 已提交
107
        sprintf(p, "fp%d", i);
P
pbrook 已提交
108 109
        cpu_fpr[i] = tcg_global_mem_new_i64(TCG_AREG0,
                                            offsetof(CPUState, fpr[i]), p);
A
aurel32 已提交
110
        p += (i < 10) ? 4 : 5;
A
aurel32 已提交
111

112
        sprintf(p, "avr%dH", i);
113 114 115 116
#ifdef WORDS_BIGENDIAN
        cpu_avrh[i] = tcg_global_mem_new_i64(TCG_AREG0,
                                             offsetof(CPUState, avr[i].u64[0]), p);
#else
P
pbrook 已提交
117
        cpu_avrh[i] = tcg_global_mem_new_i64(TCG_AREG0,
118 119
                                             offsetof(CPUState, avr[i].u64[1]), p);
#endif
120
        p += (i < 10) ? 6 : 7;
A
aurel32 已提交
121

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

P
pbrook 已提交
133
    cpu_nip = tcg_global_mem_new(TCG_AREG0,
A
aurel32 已提交
134 135
                                 offsetof(CPUState, nip), "nip");

136 137 138
    cpu_msr = tcg_global_mem_new(TCG_AREG0,
                                 offsetof(CPUState, msr), "msr");

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

P
pbrook 已提交
142
    cpu_lr = tcg_global_mem_new(TCG_AREG0,
A
aurel32 已提交
143 144
                                offsetof(CPUState, lr), "lr");

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

148 149 150
    cpu_reserve = tcg_global_mem_new(TCG_AREG0,
                                     offsetof(CPUState, reserve), "reserve");

P
pbrook 已提交
151 152
    cpu_fpscr = tcg_global_mem_new_i32(TCG_AREG0,
                                       offsetof(CPUState, fpscr), "fpscr");
153

A
aurel32 已提交
154 155 156
    cpu_access_type = tcg_global_mem_new_i32(TCG_AREG0,
                                             offsetof(CPUState, access_type), "access_type");

A
aurel32 已提交
157
    /* register helpers */
P
pbrook 已提交
158
#define GEN_HELPER 2
A
aurel32 已提交
159 160
#include "helper.h"

P
pbrook 已提交
161 162 163
    done_init = 1;
}

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

185
struct opc_handler_t {
B
bellard 已提交
186 187
    /* invalid bits */
    uint32_t inval;
188
    /* instruction type */
189
    uint64_t type;
B
bellard 已提交
190 191
    /* handler */
    void (*handler)(DisasContext *ctx);
192
#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU)
193
    const char *oname;
194 195
#endif
#if defined(DO_PPC_STATISTICS)
196 197
    uint64_t count;
#endif
198
};
B
bellard 已提交
199

200 201 202
static always_inline void gen_reset_fpstatus (void)
{
#ifdef CONFIG_SOFTFLOAT
203
    gen_helper_reset_fpstatus();
204 205 206
#endif
}

207
static always_inline void gen_compute_fprf (TCGv_i64 arg, int set_fprf, int set_rc)
208
{
209
    TCGv_i32 t0 = tcg_temp_new_i32();
A
aurel32 已提交
210

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

226
    tcg_temp_free_i32(t0);
227 228
}

A
aurel32 已提交
229
static always_inline void gen_set_access_type (DisasContext *ctx, int access_type)
A
aurel32 已提交
230
{
A
aurel32 已提交
231 232 233 234
    if (ctx->access_type != access_type) {
        tcg_gen_movi_i32(cpu_access_type, access_type);
        ctx->access_type = access_type;
    }
A
aurel32 已提交
235 236
}

237
static always_inline void gen_update_nip (DisasContext *ctx, target_ulong nip)
238 239 240
{
#if defined(TARGET_PPC64)
    if (ctx->sf_mode)
A
aurel32 已提交
241
        tcg_gen_movi_tl(cpu_nip, nip);
242 243
    else
#endif
A
aurel32 已提交
244
        tcg_gen_movi_tl(cpu_nip, (uint32_t)nip);
245 246
}

A
aurel32 已提交
247 248 249 250 251 252 253 254 255 256 257 258 259
static always_inline void gen_exception_err (DisasContext *ctx, uint32_t excp, uint32_t error)
{
    TCGv_i32 t0, t1;
    if (ctx->exception == POWERPC_EXCP_NONE) {
        gen_update_nip(ctx, ctx->nip);
    }
    t0 = tcg_const_i32(excp);
    t1 = tcg_const_i32(error);
    gen_helper_raise_exception_err(t0, t1);
    tcg_temp_free_i32(t0);
    tcg_temp_free_i32(t1);
    ctx->exception = (excp);
}
260

A
aurel32 已提交
261 262 263 264 265 266 267 268 269 270 271
static always_inline void gen_exception (DisasContext *ctx, uint32_t excp)
{
    TCGv_i32 t0;
    if (ctx->exception == POWERPC_EXCP_NONE) {
        gen_update_nip(ctx, ctx->nip);
    }
    t0 = tcg_const_i32(excp);
    gen_helper_raise_exception(t0);
    tcg_temp_free_i32(t0);
    ctx->exception = (excp);
}
272

A
aurel32 已提交
273 274 275 276 277 278 279 280
static always_inline void gen_debug_exception (DisasContext *ctx)
{
    TCGv_i32 t0;
    gen_update_nip(ctx, ctx->nip);
    t0 = tcg_const_i32(EXCP_DEBUG);
    gen_helper_raise_exception(t0);
    tcg_temp_free_i32(t0);
}
281

A
aurel32 已提交
282 283 284 285
static always_inline void gen_inval_exception (DisasContext *ctx, uint32_t error)
{
    gen_exception_err(ctx, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL | error);
}
286

287
/* Stop translation */
A
aurel32 已提交
288
static always_inline void gen_stop_exception (DisasContext *ctx)
289
{
290
    gen_update_nip(ctx, ctx->nip);
291
    ctx->exception = POWERPC_EXCP_STOP;
292 293
}

294
/* No need to update nip here, as execution flow will change */
A
aurel32 已提交
295
static always_inline void gen_sync_exception (DisasContext *ctx)
296
{
297
    ctx->exception = POWERPC_EXCP_SYNC;
298 299
}

B
bellard 已提交
300 301 302 303 304
#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)

305 306 307 308 309
#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 已提交
310 311
typedef struct opcode_t {
    unsigned char opc1, opc2, opc3;
T
ths 已提交
312
#if HOST_LONG_BITS == 64 /* Explicitly align to 64 bits */
313 314 315 316
    unsigned char pad[5];
#else
    unsigned char pad[1];
#endif
B
bellard 已提交
317
    opc_handler_t handler;
318
    const char *oname;
B
bellard 已提交
319 320
} opcode_t;

321
/*****************************************************************************/
B
bellard 已提交
322 323
/***                           Instruction decoding                        ***/
#define EXTRACT_HELPER(name, shift, nb)                                       \
324
static always_inline uint32_t name (uint32_t opcode)                          \
B
bellard 已提交
325 326 327 328 329
{                                                                             \
    return (opcode >> (shift)) & ((1 << (nb)) - 1);                           \
}

#define EXTRACT_SHELPER(name, shift, nb)                                      \
330
static always_inline int32_t name (uint32_t opcode)                           \
B
bellard 已提交
331
{                                                                             \
332
    return (int16_t)((opcode >> (shift)) & ((1 << (nb)) - 1));                \
B
bellard 已提交
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
}

/* 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 */
360
EXTRACT_HELPER(_SPR, 11, 10);
361
static always_inline uint32_t SPR (uint32_t opcode)
362 363 364 365 366
{
    uint32_t sprn = _SPR(opcode);

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

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

B
bellard 已提交
395 396 397 398
/***                            Jump target decoding                       ***/
/* Displacement */
EXTRACT_SHELPER(d, 0, 16);
/* Immediate address */
399
static always_inline target_ulong LI (uint32_t opcode)
B
bellard 已提交
400 401 402 403
{
    return (opcode >> 0) & 0x03FFFFFC;
}

404
static always_inline uint32_t BD (uint32_t opcode)
B
bellard 已提交
405 406 407 408 409 410 411 412 413 414 415 416
{
    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 */
417
static always_inline target_ulong MASK (uint32_t start, uint32_t end)
B
bellard 已提交
418
{
419
    target_ulong ret;
B
bellard 已提交
420

421 422
#if defined(TARGET_PPC64)
    if (likely(start == 0)) {
423
        ret = UINT64_MAX << (63 - end);
424
    } else if (likely(end == 63)) {
425
        ret = UINT64_MAX >> start;
426 427 428
    }
#else
    if (likely(start == 0)) {
429
        ret = UINT32_MAX << (31  - end);
430
    } else if (likely(end == 31)) {
431
        ret = UINT32_MAX >> start;
432 433 434 435 436 437 438 439
    }
#endif
    else {
        ret = (((target_ulong)(-1ULL)) >> (start)) ^
            (((target_ulong)(-1ULL) >> (end)) >> 1);
        if (unlikely(start > end))
            return ~ret;
    }
B
bellard 已提交
440 441 442 443

    return ret;
}

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

    /* Fixed-point unit extensions                                           */
    /*   PowerPC 602 specific                                                */
482
    PPC_602_SPEC       = 0x0000000000000400ULL,
483 484 485 486 487 488
    /*   isel instruction                                                    */
    PPC_ISEL           = 0x0000000000000800ULL,
    /*   popcntb instruction                                                 */
    PPC_POPCNTB        = 0x0000000000001000ULL,
    /*   string load / store                                                 */
    PPC_STRING         = 0x0000000000002000ULL,
489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505

    /* 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                                          */
506
    PPC_SPE            = 0x0000000002000000ULL,
507
    /*   PowerPC 2.03 SPE floating-point extension                           */
508
    PPC_SPEFPU         = 0x0000000004000000ULL,
509

510
    /* Optional memory control instructions                                  */
511 512 513 514 515 516 517 518 519
    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                                            */
520
    PPC_CACHE          = 0x0000000200000000ULL,
521
    /*   icbi instruction                                                    */
522
    PPC_CACHE_ICBI     = 0x0000000400000000ULL,
523
    /*   dcbz instruction with fixed cache line size                         */
524
    PPC_CACHE_DCBZ     = 0x0000000800000000ULL,
525
    /*   dcbz instruction with tunable cache line size                       */
526
    PPC_CACHE_DCBZT    = 0x0000001000000000ULL,
527
    /*   dcba instruction                                                    */
528 529 530
    PPC_CACHE_DCBA     = 0x0000002000000000ULL,
    /*   Freescale cache locking instructions                                */
    PPC_CACHE_LOCK     = 0x0000004000000000ULL,
531 532 533

    /* MMU related extensions                                                */
    /*   external control instructions                                       */
534
    PPC_EXTERN         = 0x0000010000000000ULL,
535
    /*   segment register access instructions                                */
536
    PPC_SEGMENT        = 0x0000020000000000ULL,
537
    /*   PowerPC 6xx TLB management instructions                             */
538
    PPC_6xx_TLB        = 0x0000040000000000ULL,
539
    /* PowerPC 74xx TLB management instructions                              */
540
    PPC_74xx_TLB       = 0x0000080000000000ULL,
541
    /*   PowerPC 40x TLB management instructions                             */
542
    PPC_40x_TLB        = 0x0000100000000000ULL,
543
    /*   segment register access instructions for PowerPC 64 "bridge"        */
544
    PPC_SEGMENT_64B    = 0x0000200000000000ULL,
545
    /*   SLB management                                                      */
546
    PPC_SLBI           = 0x0000400000000000ULL,
547

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

/*****************************************************************************/
/* PowerPC instructions table                                                */
582 583 584 585 586
#if HOST_LONG_BITS == 64
#define OPC_ALIGN 8
#else
#define OPC_ALIGN 4
#endif
B
bellard 已提交
587
#if defined(__APPLE__)
588
#define OPCODES_SECTION                                                       \
589
    __attribute__ ((section("__TEXT,__opcodes"), unused, aligned (OPC_ALIGN) ))
B
bellard 已提交
590
#else
591
#define OPCODES_SECTION                                                       \
592
    __attribute__ ((section(".opcodes"), unused, aligned (OPC_ALIGN) ))
B
bellard 已提交
593 594
#endif

595
#if defined(DO_PPC_STATISTICS)
B
bellard 已提交
596
#define GEN_OPCODE(name, op1, op2, op3, invl, _typ)                           \
597
OPCODES_SECTION opcode_t opc_##name = {                                       \
B
bellard 已提交
598 599 600
    .opc1 = op1,                                                              \
    .opc2 = op2,                                                              \
    .opc3 = op3,                                                              \
601
    .pad  = { 0, },                                                           \
B
bellard 已提交
602 603
    .handler = {                                                              \
        .inval   = invl,                                                      \
604
        .type = _typ,                                                         \
B
bellard 已提交
605
        .handler = &gen_##name,                                               \
606
        .oname = stringify(name),                                             \
B
bellard 已提交
607
    },                                                                        \
608
    .oname = stringify(name),                                                 \
B
bellard 已提交
609
}
610 611 612 613 614 615 616 617 618 619 620 621 622 623
#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,                                                            \
}
624 625 626 627 628 629 630 631 632 633 634 635 636 637
#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),                                                 \
}
638 639 640 641 642 643 644 645 646 647 648 649 650
#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,                                                            \
}
651
#endif
B
bellard 已提交
652 653

#define GEN_OPCODE_MARK(name)                                                 \
654
OPCODES_SECTION opcode_t opc_##name = {                                       \
B
bellard 已提交
655 656 657
    .opc1 = 0xFF,                                                             \
    .opc2 = 0xFF,                                                             \
    .opc3 = 0xFF,                                                             \
658
    .pad  = { 0, },                                                           \
B
bellard 已提交
659 660
    .handler = {                                                              \
        .inval   = 0x00000000,                                                \
661
        .type = 0x00,                                                         \
B
bellard 已提交
662 663
        .handler = NULL,                                                      \
    },                                                                        \
664
    .oname = stringify(name),                                                 \
B
bellard 已提交
665 666
}

667 668 669 670 671 672 673 674 675 676 677
/* SPR load/store helpers */
static always_inline void gen_load_spr(TCGv t, int reg)
{
    tcg_gen_ld_tl(t, cpu_env, offsetof(CPUState, spr[reg]));
}

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

B
bellard 已提交
678 679 680 681
/* Start opcode list */
GEN_OPCODE_MARK(start);

/* Invalid instruction */
682 683
GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE)
{
A
aurel32 已提交
684
    gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
685 686
}

B
bellard 已提交
687 688
static opc_handler_t invalid_handler = {
    .inval   = 0xFFFFFFFF,
689
    .type    = PPC_NONE,
B
bellard 已提交
690 691 692
    .handler = gen_invalid,
};

693 694
/***                           Integer comparison                          ***/

695
static always_inline void gen_op_cmp(TCGv arg0, TCGv arg1, int s, int crf)
696 697 698
{
    int l1, l2, l3;

699 700
    tcg_gen_trunc_tl_i32(cpu_crf[crf], cpu_xer);
    tcg_gen_shri_i32(cpu_crf[crf], cpu_crf[crf], XER_SO);
701 702 703 704 705 706
    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) {
707 708
        tcg_gen_brcond_tl(TCG_COND_LT, arg0, arg1, l1);
        tcg_gen_brcond_tl(TCG_COND_GT, arg0, arg1, l2);
709
    } else {
710 711
        tcg_gen_brcond_tl(TCG_COND_LTU, arg0, arg1, l1);
        tcg_gen_brcond_tl(TCG_COND_GTU, arg0, arg1, l2);
712 713 714 715 716 717 718 719 720 721 722
    }
    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);
}

723
static always_inline void gen_op_cmpi(TCGv arg0, target_ulong arg1, int s, int crf)
724
{
725 726 727
    TCGv t0 = tcg_const_local_tl(arg1);
    gen_op_cmp(arg0, t0, s, crf);
    tcg_temp_free(t0);
728 729 730
}

#if defined(TARGET_PPC64)
731
static always_inline void gen_op_cmp32(TCGv arg0, TCGv arg1, int s, int crf)
732
{
733
    TCGv t0, t1;
P
pbrook 已提交
734 735
    t0 = tcg_temp_local_new();
    t1 = tcg_temp_local_new();
736
    if (s) {
737 738
        tcg_gen_ext32s_tl(t0, arg0);
        tcg_gen_ext32s_tl(t1, arg1);
739
    } else {
740 741
        tcg_gen_ext32u_tl(t0, arg0);
        tcg_gen_ext32u_tl(t1, arg1);
742
    }
743 744 745
    gen_op_cmp(t0, t1, s, crf);
    tcg_temp_free(t1);
    tcg_temp_free(t0);
746 747
}

748
static always_inline void gen_op_cmpi32(TCGv arg0, target_ulong arg1, int s, int crf)
749
{
750 751 752
    TCGv t0 = tcg_const_local_tl(arg1);
    gen_op_cmp32(arg0, t0, s, crf);
    tcg_temp_free(t0);
753 754 755 756 757 758 759 760 761 762 763 764 765 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
}
#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 已提交
824
    TCGv_i32 t0;
825 826 827 828 829

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

    mask = 1 << (3 - (bi & 0x03));
P
pbrook 已提交
830
    t0 = tcg_temp_new_i32();
831 832
    tcg_gen_andi_i32(t0, cpu_crf[bi >> 2], mask);
    tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, l1);
833 834 835 836 837 838 839 840
    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 已提交
841
    tcg_temp_free_i32(t0);
842 843
}

B
bellard 已提交
844 845
/***                           Integer arithmetic                          ***/

846 847 848 849
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 已提交
850

851 852 853
    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 已提交
854
    t0 = tcg_temp_local_new();
855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875
    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 已提交
876 877
}

878 879 880
static always_inline void gen_op_arith_compute_ca(DisasContext *ctx, TCGv arg1, TCGv arg2, int sub)
{
    int l1 = gen_new_label();
881 882

#if defined(TARGET_PPC64)
883 884
    if (!(ctx->sf_mode)) {
        TCGv t0, t1;
P
pbrook 已提交
885 886
        t0 = tcg_temp_new();
        t1 = tcg_temp_new();
887

888 889 890 891
        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 已提交
892
        } else {
893 894
            tcg_gen_brcond_tl(TCG_COND_GEU, t0, t1, l1);
        }
895 896 897 898
        tcg_gen_ori_tl(cpu_xer, cpu_xer, 1 << XER_CA);
        gen_set_label(l1);
        tcg_temp_free(t0);
        tcg_temp_free(t1);
899 900
    } else
#endif
901 902 903 904 905 906 907 908
    {
        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);
909
    }
910 911
}

912 913 914 915 916
/* 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;
917

918
    if ((!compute_ca && !compute_ov) ||
P
pbrook 已提交
919
        (!TCGV_EQUAL(ret,arg1) && !TCGV_EQUAL(ret, arg2)))  {
920 921
        t0 = ret;
    } else {
P
pbrook 已提交
922
        t0 = tcg_temp_local_new();
923
    }
B
bellard 已提交
924

925
    if (add_ca) {
P
pbrook 已提交
926
        t1 = tcg_temp_local_new();
927 928 929
        tcg_gen_andi_tl(t1, cpu_xer, (1 << XER_CA));
        tcg_gen_shri_tl(t1, t1, XER_CA);
    }
B
bellard 已提交
930

931 932 933 934 935 936 937 938 939 940
    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 已提交
941

942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958
    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 已提交
959
    if (!TCGV_EQUAL(t0, ret)) {
960 961 962
        tcg_gen_mov_tl(ret, t0);
        tcg_temp_free(t0);
    }
A
aurel32 已提交
963
}
964 965 966 967 968 969 970 971 972 973 974 975 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
/* 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)
1001
{
1002 1003 1004 1005 1006 1007 1008 1009
    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);
    }
1010
}
1011 1012 1013
/* addic  addic.*/
static always_inline void gen_op_addic (DisasContext *ctx, TCGv ret, TCGv arg1,
                                        int compute_Rc0)
1014
{
1015 1016 1017 1018 1019 1020
    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 已提交
1021
        TCGv t0 = tcg_temp_local_new();
1022 1023 1024 1025 1026 1027 1028 1029 1030 1031
        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);
    }
1032
}
1033
GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
1034
{
1035
    gen_op_addic(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0);
1036
}
1037
GEN_HANDLER2(addic_, "addic.", 0x0D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
1038
{
1039
    gen_op_addic(ctx, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 1);
1040
}
1041 1042
/* addis */
GEN_HANDLER(addis, 0x0F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
1043
{
1044 1045 1046 1047 1048 1049 1050 1051
    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);
    }
1052
}
1053 1054 1055

static always_inline void gen_op_arith_divw (DisasContext *ctx, TCGv ret, TCGv arg1, TCGv arg2,
                                             int sign, int compute_ov)
1056
{
1057 1058
    int l1 = gen_new_label();
    int l2 = gen_new_label();
P
pbrook 已提交
1059 1060
    TCGv_i32 t0 = tcg_temp_local_new_i32();
    TCGv_i32 t1 = tcg_temp_local_new_i32();
1061

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

    tcg_gen_brcondi_i64(TCG_COND_EQ, arg2, 0, l1);
    if (sign) {
1117
        int l3 = gen_new_label();
1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140
        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);
1141
}
1142 1143 1144
#define GEN_INT_ARITH_DIVD(name, opc3, sign, compute_ov)                      \
GEN_HANDLER(name, 0x1F, 0x09, opc3, 0x00000000, PPC_64B)                      \
{                                                                             \
1145 1146 1147
    gen_op_arith_divd(ctx, cpu_gpr[rD(ctx->opcode)],                          \
                      cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],     \
                      sign, compute_ov);                                      \
1148 1149 1150 1151 1152 1153 1154
}
/* 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);
1155
#endif
1156 1157 1158

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

P
pbrook 已提交
1162 1163
    t0 = tcg_temp_new_i64();
    t1 = tcg_temp_new_i64();
1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175
#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 已提交
1176 1177
    tcg_temp_free_i64(t0);
    tcg_temp_free_i64(t1);
1178 1179
    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
1180
}
1181 1182
/* mulhwu  mulhwu.  */
GEN_HANDLER(mulhwu, 0x1F, 0x0B, 0x00, 0x00000400, PPC_INTEGER)
1183
{
P
pbrook 已提交
1184
    TCGv_i64 t0, t1;
1185

P
pbrook 已提交
1186 1187
    t0 = tcg_temp_new_i64();
    t1 = tcg_temp_new_i64();
1188
#if defined(TARGET_PPC64)
1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199
    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 已提交
1200 1201
    tcg_temp_free_i64(t0);
    tcg_temp_free_i64(t1);
1202 1203
    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
1204
}
1205 1206
/* mullw  mullw. */
GEN_HANDLER(mullw, 0x1F, 0x0B, 0x07, 0x00000000, PPC_INTEGER)
1207
{
1208 1209
    tcg_gen_mul_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],
                   cpu_gpr[rB(ctx->opcode)]);
1210
    tcg_gen_ext32s_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)]);
1211 1212
    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
1213
}
1214 1215
/* mullwo  mullwo. */
GEN_HANDLER(mullwo, 0x1F, 0x0B, 0x17, 0x00000000, PPC_INTEGER)
1216
{
1217
    int l1;
P
pbrook 已提交
1218
    TCGv_i64 t0, t1;
1219

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

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

/* 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 已提交
1322
{
1323
    TCGv t0, t1;
1324

1325
    if ((!compute_ca && !compute_ov) ||
P
pbrook 已提交
1326
        (!TCGV_EQUAL(ret, arg1) && !TCGV_EQUAL(ret, arg2)))  {
1327
        t0 = ret;
J
j_mayer 已提交
1328
    } else {
P
pbrook 已提交
1329
        t0 = tcg_temp_local_new();
1330
    }
1331

1332
    if (add_ca) {
P
pbrook 已提交
1333
        t1 = tcg_temp_local_new();
1334 1335
        tcg_gen_andi_tl(t1, cpu_xer, (1 << XER_CA));
        tcg_gen_shri_tl(t1, t1, XER_CA);
1336
    }
B
bellard 已提交
1337

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

/***                            Integer logical                            ***/
1423 1424
#define GEN_LOGICAL2(name, tcg_op, opc, type)                                 \
GEN_HANDLER(name, 0x1F, 0x1C, opc, 0x00000000, type)                          \
B
bellard 已提交
1425
{                                                                             \
1426 1427
    tcg_op(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)],                \
       cpu_gpr[rB(ctx->opcode)]);                                             \
1428
    if (unlikely(Rc(ctx->opcode) != 0))                                       \
1429
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);                           \
B
bellard 已提交
1430 1431
}

1432
#define GEN_LOGICAL1(name, tcg_op, opc, type)                                 \
1433
GEN_HANDLER(name, 0x1F, 0x1A, opc, 0x00000000, type)                          \
B
bellard 已提交
1434
{                                                                             \
1435
    tcg_op(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);               \
1436
    if (unlikely(Rc(ctx->opcode) != 0))                                       \
1437
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);                           \
B
bellard 已提交
1438 1439 1440
}

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

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

1567 1568
    if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
        /* NOP */
1569
        /* XXX: should handle special NOPs for POWER series */
1570
        return;
1571
    }
1572
    tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], uimm);
B
bellard 已提交
1573 1574 1575 1576
}
/* oris */
GEN_HANDLER(oris, 0x19, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
1577
    target_ulong uimm = UIMM(ctx->opcode);
B
bellard 已提交
1578

1579 1580 1581
    if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
        /* NOP */
        return;
1582
    }
1583
    tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], uimm << 16);
B
bellard 已提交
1584 1585 1586 1587
}
/* xori */
GEN_HANDLER(xori, 0x1A, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
1588
    target_ulong uimm = UIMM(ctx->opcode);
1589 1590 1591 1592 1593

    if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
        /* NOP */
        return;
    }
1594
    tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], uimm);
B
bellard 已提交
1595 1596 1597 1598
}
/* xoris */
GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
1599
    target_ulong uimm = UIMM(ctx->opcode);
1600 1601 1602 1603 1604

    if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
        /* NOP */
        return;
    }
1605
    tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], uimm << 16);
B
bellard 已提交
1606
}
1607
/* popcntb : PowerPC 2.03 specification */
1608
GEN_HANDLER(popcntb, 0x1F, 0x03, 0x03, 0x0000F801, PPC_POPCNTB)
1609 1610 1611
{
#if defined(TARGET_PPC64)
    if (ctx->sf_mode)
P
pbrook 已提交
1612
        gen_helper_popcntb_64(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
1613 1614
    else
#endif
P
pbrook 已提交
1615
        gen_helper_popcntb(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
1616 1617 1618 1619
}

#if defined(TARGET_PPC64)
/* extsw & extsw. */
1620
GEN_LOGICAL1(extsw, tcg_gen_ext32s_tl, 0x1E, PPC_64B);
1621
/* cntlzd */
1622 1623
GEN_HANDLER(cntlzd, 0x1F, 0x1A, 0x01, 0x00000000, PPC_64B)
{
P
pbrook 已提交
1624
    gen_helper_cntlzd(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
1625 1626 1627
    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
}
1628 1629
#endif

B
bellard 已提交
1630 1631 1632 1633
/***                             Integer rotate                            ***/
/* rlwimi & rlwimi. */
GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
1634
    uint32_t mb, me, sh;
B
bellard 已提交
1635 1636 1637

    mb = MB(ctx->opcode);
    me = ME(ctx->opcode);
1638
    sh = SH(ctx->opcode);
1639 1640 1641 1642
    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 已提交
1643 1644
        TCGv t1;
        TCGv t0 = tcg_temp_new();
1645
#if defined(TARGET_PPC64)
P
pbrook 已提交
1646 1647 1648 1649 1650
        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);
1651 1652 1653
#else
        tcg_gen_rotli_i32(t0, cpu_gpr[rS(ctx->opcode)], sh);
#endif
1654
#if defined(TARGET_PPC64)
1655 1656
        mb += 32;
        me += 32;
1657
#endif
1658
        mask = MASK(mb, me);
P
pbrook 已提交
1659
        t1 = tcg_temp_new();
1660 1661 1662 1663 1664 1665
        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);
    }
1666
    if (unlikely(Rc(ctx->opcode) != 0))
1667
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
B
bellard 已提交
1668 1669 1670 1671 1672
}
/* rlwinm & rlwinm. */
GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
    uint32_t mb, me, sh;
1673

B
bellard 已提交
1674 1675 1676
    sh = SH(ctx->opcode);
    mb = MB(ctx->opcode);
    me = ME(ctx->opcode);
1677 1678 1679 1680 1681

    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 已提交
1682
            TCGv t0 = tcg_temp_new();
1683 1684 1685 1686
            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 已提交
1687
        }
1688
    } else if (likely(sh != 0 && me == 31 && sh == (32 - mb))) {
P
pbrook 已提交
1689
        TCGv t0 = tcg_temp_new();
1690 1691 1692 1693 1694
        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 已提交
1695
        TCGv t0 = tcg_temp_new();
1696
#if defined(TARGET_PPC64)
P
pbrook 已提交
1697
        TCGv_i32 t1 = tcg_temp_new_i32();
1698 1699 1700
        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 已提交
1701
        tcg_temp_free_i32(t1);
1702 1703 1704
#else
        tcg_gen_rotli_i32(t0, cpu_gpr[rS(ctx->opcode)], sh);
#endif
1705
#if defined(TARGET_PPC64)
1706 1707
        mb += 32;
        me += 32;
1708
#endif
1709 1710 1711
        tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], t0, MASK(mb, me));
        tcg_temp_free(t0);
    }
1712
    if (unlikely(Rc(ctx->opcode) != 0))
1713
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
B
bellard 已提交
1714 1715 1716 1717 1718
}
/* rlwnm & rlwnm. */
GEN_HANDLER(rlwnm, 0x17, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
    uint32_t mb, me;
1719 1720
    TCGv t0;
#if defined(TARGET_PPC64)
P
pbrook 已提交
1721
    TCGv_i32 t1, t2;
1722
#endif
B
bellard 已提交
1723 1724 1725

    mb = MB(ctx->opcode);
    me = ME(ctx->opcode);
P
pbrook 已提交
1726
    t0 = tcg_temp_new();
1727
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1f);
1728
#if defined(TARGET_PPC64)
P
pbrook 已提交
1729 1730
    t1 = tcg_temp_new_i32();
    t2 = tcg_temp_new_i32();
1731 1732 1733 1734
    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 已提交
1735 1736
    tcg_temp_free_i32(t1);
    tcg_temp_free_i32(t2);
1737 1738 1739
#else
    tcg_gen_rotl_i32(t0, cpu_gpr[rS(ctx->opcode)], t0);
#endif
1740 1741 1742 1743 1744
    if (unlikely(mb != 0 || me != 31)) {
#if defined(TARGET_PPC64)
        mb += 32;
        me += 32;
#endif
1745
        tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], t0, MASK(mb, me));
1746
    } else {
1747
        tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
B
bellard 已提交
1748
    }
1749
    tcg_temp_free(t0);
1750
    if (unlikely(Rc(ctx->opcode) != 0))
1751
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
B
bellard 已提交
1752 1753
}

1754 1755
#if defined(TARGET_PPC64)
#define GEN_PPC64_R2(name, opc1, opc2)                                        \
1756
GEN_HANDLER2(name##0, stringify(name), opc1, opc2, 0xFF, 0x00000000, PPC_64B) \
1757 1758 1759
{                                                                             \
    gen_##name(ctx, 0);                                                       \
}                                                                             \
1760 1761
GEN_HANDLER2(name##1, stringify(name), opc1, opc2 | 0x10, 0xFF, 0x00000000,   \
             PPC_64B)                                                         \
1762 1763 1764 1765
{                                                                             \
    gen_##name(ctx, 1);                                                       \
}
#define GEN_PPC64_R4(name, opc1, opc2)                                        \
1766
GEN_HANDLER2(name##0, stringify(name), opc1, opc2, 0xFF, 0x00000000, PPC_64B) \
1767 1768 1769
{                                                                             \
    gen_##name(ctx, 0, 0);                                                    \
}                                                                             \
1770 1771
GEN_HANDLER2(name##1, stringify(name), opc1, opc2 | 0x01, 0xFF, 0x00000000,   \
             PPC_64B)                                                         \
1772 1773 1774
{                                                                             \
    gen_##name(ctx, 0, 1);                                                    \
}                                                                             \
1775 1776
GEN_HANDLER2(name##2, stringify(name), opc1, opc2 | 0x10, 0xFF, 0x00000000,   \
             PPC_64B)                                                         \
1777 1778 1779
{                                                                             \
    gen_##name(ctx, 1, 0);                                                    \
}                                                                             \
1780 1781
GEN_HANDLER2(name##3, stringify(name), opc1, opc2 | 0x11, 0xFF, 0x00000000,   \
             PPC_64B)                                                         \
1782 1783 1784
{                                                                             \
    gen_##name(ctx, 1, 1);                                                    \
}
J
j_mayer 已提交
1785

1786 1787
static always_inline void gen_rldinm (DisasContext *ctx, uint32_t mb,
                                      uint32_t me, uint32_t sh)
J
j_mayer 已提交
1788
{
1789 1790 1791 1792 1793
    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 已提交
1794
        TCGv t0 = tcg_temp_new();
1795
        tcg_gen_rotli_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
1796
        if (likely(mb == 0 && me == 63)) {
1797
            tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
1798 1799
        } else {
            tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], t0, MASK(mb, me));
J
j_mayer 已提交
1800
        }
1801
        tcg_temp_free(t0);
J
j_mayer 已提交
1802 1803
    }
    if (unlikely(Rc(ctx->opcode) != 0))
1804
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
J
j_mayer 已提交
1805
}
1806
/* rldicl - rldicl. */
1807
static always_inline void gen_rldicl (DisasContext *ctx, int mbn, int shn)
1808
{
J
j_mayer 已提交
1809
    uint32_t sh, mb;
1810

J
j_mayer 已提交
1811 1812
    sh = SH(ctx->opcode) | (shn << 5);
    mb = MB(ctx->opcode) | (mbn << 5);
J
j_mayer 已提交
1813
    gen_rldinm(ctx, mb, 63, sh);
1814
}
J
j_mayer 已提交
1815
GEN_PPC64_R4(rldicl, 0x1E, 0x00);
1816
/* rldicr - rldicr. */
1817
static always_inline void gen_rldicr (DisasContext *ctx, int men, int shn)
1818
{
J
j_mayer 已提交
1819
    uint32_t sh, me;
1820

J
j_mayer 已提交
1821 1822
    sh = SH(ctx->opcode) | (shn << 5);
    me = MB(ctx->opcode) | (men << 5);
J
j_mayer 已提交
1823
    gen_rldinm(ctx, 0, me, sh);
1824
}
J
j_mayer 已提交
1825
GEN_PPC64_R4(rldicr, 0x1E, 0x02);
1826
/* rldic - rldic. */
1827
static always_inline void gen_rldic (DisasContext *ctx, int mbn, int shn)
1828
{
J
j_mayer 已提交
1829
    uint32_t sh, mb;
1830

J
j_mayer 已提交
1831 1832
    sh = SH(ctx->opcode) | (shn << 5);
    mb = MB(ctx->opcode) | (mbn << 5);
J
j_mayer 已提交
1833 1834 1835 1836
    gen_rldinm(ctx, mb, 63 - sh, sh);
}
GEN_PPC64_R4(rldic, 0x1E, 0x04);

1837 1838
static always_inline void gen_rldnm (DisasContext *ctx, uint32_t mb,
                                     uint32_t me)
J
j_mayer 已提交
1839
{
1840
    TCGv t0;
1841 1842 1843

    mb = MB(ctx->opcode);
    me = ME(ctx->opcode);
P
pbrook 已提交
1844
    t0 = tcg_temp_new();
1845
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x3f);
1846
    tcg_gen_rotl_tl(t0, cpu_gpr[rS(ctx->opcode)], t0);
J
j_mayer 已提交
1847
    if (unlikely(mb != 0 || me != 63)) {
1848 1849 1850 1851 1852
        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 已提交
1853
    if (unlikely(Rc(ctx->opcode) != 0))
1854
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
1855
}
J
j_mayer 已提交
1856

1857
/* rldcl - rldcl. */
1858
static always_inline void gen_rldcl (DisasContext *ctx, int mbn)
1859
{
J
j_mayer 已提交
1860
    uint32_t mb;
1861

J
j_mayer 已提交
1862
    mb = MB(ctx->opcode) | (mbn << 5);
J
j_mayer 已提交
1863
    gen_rldnm(ctx, mb, 63);
1864
}
1865
GEN_PPC64_R2(rldcl, 0x1E, 0x08);
1866
/* rldcr - rldcr. */
1867
static always_inline void gen_rldcr (DisasContext *ctx, int men)
1868
{
J
j_mayer 已提交
1869
    uint32_t me;
1870

J
j_mayer 已提交
1871
    me = MB(ctx->opcode) | (men << 5);
J
j_mayer 已提交
1872
    gen_rldnm(ctx, 0, me);
1873
}
1874
GEN_PPC64_R2(rldcr, 0x1E, 0x09);
1875
/* rldimi - rldimi. */
1876
static always_inline void gen_rldimi (DisasContext *ctx, int mbn, int shn)
1877
{
1878
    uint32_t sh, mb, me;
1879

J
j_mayer 已提交
1880 1881
    sh = SH(ctx->opcode) | (shn << 5);
    mb = MB(ctx->opcode) | (mbn << 5);
1882
    me = 63 - sh;
1883 1884 1885 1886 1887 1888
    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 已提交
1889
        t0 = tcg_temp_new();
1890
        tcg_gen_rotli_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
P
pbrook 已提交
1891
        t1 = tcg_temp_new();
1892 1893 1894 1895 1896 1897
        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 已提交
1898 1899
    }
    if (unlikely(Rc(ctx->opcode) != 0))
1900
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
1901
}
1902
GEN_PPC64_R4(rldimi, 0x1E, 0x06);
1903 1904
#endif

B
bellard 已提交
1905 1906
/***                             Integer shift                             ***/
/* slw & slw. */
1907 1908
GEN_HANDLER(slw, 0x1F, 0x18, 0x00, 0x00000000, PPC_INTEGER)
{
1909
    TCGv t0;
1910 1911 1912 1913
    int l1, l2;
    l1 = gen_new_label();
    l2 = gen_new_label();

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

P
pbrook 已提交
1972
    t0 = tcg_temp_local_new();
A
aurel32 已提交
1973 1974
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x3f);
    tcg_gen_brcondi_tl(TCG_COND_LT, t0, 0x20, l1);
1975 1976 1977
    tcg_gen_movi_tl(cpu_gpr[rA(ctx->opcode)], 0);
    tcg_gen_br(l2);
    gen_set_label(l1);
P
pbrook 已提交
1978
    t1 = tcg_temp_new();
1979 1980 1981
    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);
1982
    gen_set_label(l2);
1983
    tcg_temp_free(t0);
1984 1985 1986
    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
}
1987 1988
#if defined(TARGET_PPC64)
/* sld & sld. */
1989 1990
GEN_HANDLER(sld, 0x1F, 0x1B, 0x00, 0x00000000, PPC_64B)
{
1991
    TCGv t0;
1992 1993 1994 1995
    int l1, l2;
    l1 = gen_new_label();
    l2 = gen_new_label();

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

P
pbrook 已提交
2059
    t0 = tcg_temp_local_new();
A
aurel32 已提交
2060 2061
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x7f);
    tcg_gen_brcondi_tl(TCG_COND_LT, t0, 0x40, l1);
2062 2063 2064
    tcg_gen_movi_tl(cpu_gpr[rA(ctx->opcode)], 0);
    tcg_gen_br(l2);
    gen_set_label(l1);
2065
    tcg_gen_shr_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], t0);
2066
    gen_set_label(l2);
2067
    tcg_temp_free(t0);
2068 2069 2070
    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
}
2071
#endif
B
bellard 已提交
2072 2073

/***                       Floating-Point arithmetic                       ***/
2074
#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat, set_fprf, type)           \
2075
GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, type)                        \
2076
{                                                                             \
2077
    if (unlikely(!ctx->fpu_enabled)) {                                        \
A
aurel32 已提交
2078
        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
B
bellard 已提交
2079 2080
        return;                                                               \
    }                                                                         \
2081 2082
    /* NIP cannot be restored if the memory exception comes from an helper */ \
    gen_update_nip(ctx, ctx->nip - 4);                                        \
2083
    gen_reset_fpstatus();                                                     \
A
aurel32 已提交
2084 2085
    gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)],      \
                     cpu_fpr[rC(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);     \
2086
    if (isfloat) {                                                            \
A
aurel32 已提交
2087
        gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]);  \
2088
    }                                                                         \
A
aurel32 已提交
2089 2090
    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], set_fprf,                      \
                     Rc(ctx->opcode) != 0);                                   \
2091 2092
}

2093 2094 2095
#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);
2096

2097 2098
#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat, set_fprf, type)     \
GEN_HANDLER(f##name, op1, op2, 0xFF, inval, type)                             \
2099
{                                                                             \
2100
    if (unlikely(!ctx->fpu_enabled)) {                                        \
A
aurel32 已提交
2101
        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
B
bellard 已提交
2102 2103
        return;                                                               \
    }                                                                         \
2104 2105
    /* NIP cannot be restored if the memory exception comes from an helper */ \
    gen_update_nip(ctx, ctx->nip - 4);                                        \
2106
    gen_reset_fpstatus();                                                     \
A
aurel32 已提交
2107 2108
    gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)],      \
                     cpu_fpr[rB(ctx->opcode)]);                               \
2109
    if (isfloat) {                                                            \
A
aurel32 已提交
2110
        gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]);  \
2111
    }                                                                         \
A
aurel32 已提交
2112 2113
    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)],                                \
                     set_fprf, Rc(ctx->opcode) != 0);                         \
2114
}
2115 2116 2117
#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);
2118

2119 2120
#define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat, set_fprf, type)     \
GEN_HANDLER(f##name, op1, op2, 0xFF, inval, type)                             \
2121
{                                                                             \
2122
    if (unlikely(!ctx->fpu_enabled)) {                                        \
A
aurel32 已提交
2123
        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
B
bellard 已提交
2124 2125
        return;                                                               \
    }                                                                         \
2126 2127
    /* NIP cannot be restored if the memory exception comes from an helper */ \
    gen_update_nip(ctx, ctx->nip - 4);                                        \
2128
    gen_reset_fpstatus();                                                     \
A
aurel32 已提交
2129 2130
    gen_helper_f##op(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)],      \
                       cpu_fpr[rC(ctx->opcode)]);                             \
2131
    if (isfloat) {                                                            \
A
aurel32 已提交
2132
        gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]);  \
2133
    }                                                                         \
A
aurel32 已提交
2134 2135
    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)],                                \
                     set_fprf, Rc(ctx->opcode) != 0);                         \
2136
}
2137 2138 2139
#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);
2140

2141
#define GEN_FLOAT_B(name, op2, op3, set_fprf, type)                           \
2142
GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, type)                        \
2143
{                                                                             \
2144
    if (unlikely(!ctx->fpu_enabled)) {                                        \
A
aurel32 已提交
2145
        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
B
bellard 已提交
2146 2147
        return;                                                               \
    }                                                                         \
2148 2149
    /* NIP cannot be restored if the memory exception comes from an helper */ \
    gen_update_nip(ctx, ctx->nip - 4);                                        \
2150
    gen_reset_fpstatus();                                                     \
A
aurel32 已提交
2151 2152 2153
    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 已提交
2154 2155
}

2156
#define GEN_FLOAT_BS(name, op1, op2, set_fprf, type)                          \
2157
GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, type)                        \
2158
{                                                                             \
2159
    if (unlikely(!ctx->fpu_enabled)) {                                        \
A
aurel32 已提交
2160
        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
B
bellard 已提交
2161 2162
        return;                                                               \
    }                                                                         \
2163 2164
    /* NIP cannot be restored if the memory exception comes from an helper */ \
    gen_update_nip(ctx, ctx->nip - 4);                                        \
2165
    gen_reset_fpstatus();                                                     \
A
aurel32 已提交
2166 2167 2168
    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 已提交
2169 2170
}

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

2178
/* fre */
2179
GEN_FLOAT_BS(re, 0x3F, 0x18, 1, PPC_FLOAT_EXT);
2180

2181
/* fres */
2182
GEN_FLOAT_BS(res, 0x3B, 0x18, 1, PPC_FLOAT_FRES);
B
bellard 已提交
2183

2184
/* frsqrte */
2185 2186 2187
GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, 1, PPC_FLOAT_FRSQRTE);

/* frsqrtes */
A
aurel32 已提交
2188
GEN_HANDLER(frsqrtes, 0x3B, 0x1A, 0xFF, 0x001F07C0, PPC_FLOAT_FRSQRTES)
2189
{
A
aurel32 已提交
2190
    if (unlikely(!ctx->fpu_enabled)) {
A
aurel32 已提交
2191
        gen_exception(ctx, POWERPC_EXCP_FPU);
A
aurel32 已提交
2192 2193
        return;
    }
2194 2195
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
A
aurel32 已提交
2196 2197 2198 2199
    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);
2200
}
B
bellard 已提交
2201

2202
/* fsel */
2203
_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0, 0, PPC_FLOAT_FSEL);
2204
/* fsub - fsubs */
2205
GEN_FLOAT_AB(sub, 0x14, 0x000007C0, 1, PPC_FLOAT);
B
bellard 已提交
2206 2207
/* Optional: */
/* fsqrt */
2208
GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT)
2209
{
2210
    if (unlikely(!ctx->fpu_enabled)) {
A
aurel32 已提交
2211
        gen_exception(ctx, POWERPC_EXCP_FPU);
2212 2213
        return;
    }
2214 2215
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
2216
    gen_reset_fpstatus();
A
aurel32 已提交
2217 2218
    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);
2219
}
B
bellard 已提交
2220

2221
GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT)
B
bellard 已提交
2222
{
2223
    if (unlikely(!ctx->fpu_enabled)) {
A
aurel32 已提交
2224
        gen_exception(ctx, POWERPC_EXCP_FPU);
B
bellard 已提交
2225 2226
        return;
    }
2227 2228
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
2229
    gen_reset_fpstatus();
A
aurel32 已提交
2230 2231 2232
    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 已提交
2233 2234 2235
}

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

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

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

B
bellard 已提交
2270 2271
/***                         Floating-Point compare                        ***/
/* fcmpo */
2272
GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT)
B
bellard 已提交
2273
{
A
aurel32 已提交
2274
    TCGv_i32 crf;
2275
    if (unlikely(!ctx->fpu_enabled)) {
A
aurel32 已提交
2276
        gen_exception(ctx, POWERPC_EXCP_FPU);
B
bellard 已提交
2277 2278
        return;
    }
2279 2280
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
2281
    gen_reset_fpstatus();
A
aurel32 已提交
2282 2283
    crf = tcg_const_i32(crfD(ctx->opcode));
    gen_helper_fcmpo(cpu_fpr[rA(ctx->opcode)], cpu_fpr[rB(ctx->opcode)], crf);
A
aurel32 已提交
2284
    tcg_temp_free_i32(crf);
A
aurel32 已提交
2285
    gen_helper_float_check_status();
B
bellard 已提交
2286 2287 2288
}

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

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

/* fmr  - fmr. */
2311
/* XXX: beware that fmr never checks for NaNs nor update FPSCR */
2312 2313
GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT)
{
2314
    if (unlikely(!ctx->fpu_enabled)) {
A
aurel32 已提交
2315
        gen_exception(ctx, POWERPC_EXCP_FPU);
B
bellard 已提交
2316 2317
        return;
    }
A
aurel32 已提交
2318 2319
    tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);
    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 0, Rc(ctx->opcode) != 0);
2320 2321 2322
}

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

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

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

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

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

2362
    if (unlikely(!ctx->fpu_enabled)) {
A
aurel32 已提交
2363
        gen_exception(ctx, POWERPC_EXCP_FPU);
B
bellard 已提交
2364 2365
        return;
    }
A
aurel32 已提交
2366
    crb = 31 - crbD(ctx->opcode);
2367
    gen_reset_fpstatus();
A
aurel32 已提交
2368
    if (likely(crb != FPSCR_FEX && crb != FPSCR_VX)) {
2369 2370 2371 2372
        TCGv_i32 t0;
        /* NIP cannot be restored if the memory exception comes from an helper */
        gen_update_nip(ctx, ctx->nip - 4);
        t0 = tcg_const_i32(crb);
A
aurel32 已提交
2373 2374 2375
        gen_helper_fpscr_clrbit(t0);
        tcg_temp_free_i32(t0);
    }
2376
    if (unlikely(Rc(ctx->opcode) != 0)) {
2377
        tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX);
2378
    }
B
bellard 已提交
2379 2380 2381 2382 2383
}

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

2386
    if (unlikely(!ctx->fpu_enabled)) {
A
aurel32 已提交
2387
        gen_exception(ctx, POWERPC_EXCP_FPU);
B
bellard 已提交
2388 2389
        return;
    }
A
aurel32 已提交
2390
    crb = 31 - crbD(ctx->opcode);
2391 2392
    gen_reset_fpstatus();
    /* XXX: we pretend we can only do IEEE floating-point computations */
A
aurel32 已提交
2393
    if (likely(crb != FPSCR_FEX && crb != FPSCR_VX && crb != FPSCR_NI)) {
2394 2395 2396 2397
        TCGv_i32 t0;
        /* NIP cannot be restored if the memory exception comes from an helper */
        gen_update_nip(ctx, ctx->nip - 4);
        t0 = tcg_const_i32(crb);
A
aurel32 已提交
2398
        gen_helper_fpscr_setbit(t0);
2399
        tcg_temp_free_i32(t0);
A
aurel32 已提交
2400
    }
2401
    if (unlikely(Rc(ctx->opcode) != 0)) {
2402
        tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX);
2403 2404
    }
    /* We can raise a differed exception */
A
aurel32 已提交
2405
    gen_helper_float_check_status();
B
bellard 已提交
2406 2407 2408 2409 2410
}

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

2413
    if (unlikely(!ctx->fpu_enabled)) {
A
aurel32 已提交
2414
        gen_exception(ctx, POWERPC_EXCP_FPU);
B
bellard 已提交
2415 2416
        return;
    }
2417 2418
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
2419
    gen_reset_fpstatus();
A
aurel32 已提交
2420 2421
    t0 = tcg_const_i32(FM(ctx->opcode));
    gen_helper_store_fpscr(cpu_fpr[rB(ctx->opcode)], t0);
2422
    tcg_temp_free_i32(t0);
2423
    if (unlikely(Rc(ctx->opcode) != 0)) {
2424
        tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX);
2425 2426
    }
    /* We can raise a differed exception */
A
aurel32 已提交
2427
    gen_helper_float_check_status();
B
bellard 已提交
2428 2429 2430 2431 2432
}

/* mtfsfi */
GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT)
{
2433
    int bf, sh;
2434 2435
    TCGv_i64 t0;
    TCGv_i32 t1;
2436

2437
    if (unlikely(!ctx->fpu_enabled)) {
A
aurel32 已提交
2438
        gen_exception(ctx, POWERPC_EXCP_FPU);
B
bellard 已提交
2439 2440
        return;
    }
2441 2442
    bf = crbD(ctx->opcode) >> 2;
    sh = 7 - bf;
2443 2444
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
2445
    gen_reset_fpstatus();
2446
    t0 = tcg_const_i64(FPIMM(ctx->opcode) << (4 * sh));
A
aurel32 已提交
2447 2448
    t1 = tcg_const_i32(1 << sh);
    gen_helper_store_fpscr(t0, t1);
2449 2450
    tcg_temp_free_i64(t0);
    tcg_temp_free_i32(t1);
2451
    if (unlikely(Rc(ctx->opcode) != 0)) {
2452
        tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX);
2453 2454
    }
    /* We can raise a differed exception */
A
aurel32 已提交
2455
    gen_helper_float_check_status();
B
bellard 已提交
2456 2457
}

2458 2459
/***                           Addressing modes                            ***/
/* Register indirect with immediate index : EA = (rA|0) + SIMM */
A
aurel32 已提交
2460
static always_inline void gen_addr_imm_index (DisasContext *ctx, TCGv EA, target_long maskl)
2461 2462 2463
{
    target_long simm = SIMM(ctx->opcode);

2464
    simm &= ~maskl;
A
aurel32 已提交
2465 2466 2467 2468 2469 2470
    if (rA(ctx->opcode) == 0) {
#if defined(TARGET_PPC64)
        if (!ctx->sf_mode) {
            tcg_gen_movi_tl(EA, (uint32_t)simm);
        } else
#endif
2471
        tcg_gen_movi_tl(EA, simm);
A
aurel32 已提交
2472
    } else if (likely(simm != 0)) {
2473
        tcg_gen_addi_tl(EA, cpu_gpr[rA(ctx->opcode)], simm);
A
aurel32 已提交
2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484
#if defined(TARGET_PPC64)
        if (!ctx->sf_mode) {
            tcg_gen_ext32u_tl(EA, EA);
        }
#endif
    } else {
#if defined(TARGET_PPC64)
        if (!ctx->sf_mode) {
            tcg_gen_ext32u_tl(EA, cpu_gpr[rA(ctx->opcode)]);
        } else
#endif
2485
        tcg_gen_mov_tl(EA, cpu_gpr[rA(ctx->opcode)]);
A
aurel32 已提交
2486
    }
2487 2488
}

A
aurel32 已提交
2489
static always_inline void gen_addr_reg_index (DisasContext *ctx, TCGv EA)
2490
{
A
aurel32 已提交
2491 2492 2493 2494 2495 2496
    if (rA(ctx->opcode) == 0) {
#if defined(TARGET_PPC64)
        if (!ctx->sf_mode) {
            tcg_gen_ext32u_tl(EA, cpu_gpr[rB(ctx->opcode)]);
        } else
#endif
2497
        tcg_gen_mov_tl(EA, cpu_gpr[rB(ctx->opcode)]);
A
aurel32 已提交
2498
    } else {
2499
        tcg_gen_add_tl(EA, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
A
aurel32 已提交
2500 2501 2502 2503 2504 2505
#if defined(TARGET_PPC64)
        if (!ctx->sf_mode) {
            tcg_gen_ext32u_tl(EA, EA);
        }
#endif
    }
2506 2507
}

A
aurel32 已提交
2508
static always_inline void gen_addr_register (DisasContext *ctx, TCGv EA)
2509
{
A
aurel32 已提交
2510
    if (rA(ctx->opcode) == 0) {
2511
        tcg_gen_movi_tl(EA, 0);
A
aurel32 已提交
2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529
    } else {
#if defined(TARGET_PPC64)
        if (!ctx->sf_mode) {
            tcg_gen_ext32u_tl(EA, cpu_gpr[rA(ctx->opcode)]);
        } else
#endif
            tcg_gen_mov_tl(EA, cpu_gpr[rA(ctx->opcode)]);
    }
}

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

2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549
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);
}

2550
/***                             Integer load                              ***/
A
aurel32 已提交
2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564
static always_inline void gen_qemu_ld8u(DisasContext *ctx, TCGv arg1, TCGv arg2)
{
    tcg_gen_qemu_ld8u(arg1, arg2, ctx->mem_idx);
}

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

static always_inline void gen_qemu_ld16u(DisasContext *ctx, TCGv arg1, TCGv arg2)
{
    tcg_gen_qemu_ld16u(arg1, arg2, ctx->mem_idx);
    if (unlikely(ctx->le_mode)) {
A
aurel32 已提交
2565
#if defined(TARGET_PPC64)
A
aurel32 已提交
2566 2567
        TCGv_i32 t0 = tcg_temp_new_i32();
        tcg_gen_trunc_tl_i32(t0, arg1);
2568
        tcg_gen_bswap16_i32(t0, t0);
A
aurel32 已提交
2569
        tcg_gen_extu_i32_tl(arg1, t0);
P
pbrook 已提交
2570
        tcg_temp_free_i32(t0);
A
aurel32 已提交
2571 2572 2573 2574
#else
        tcg_gen_bswap16_i32(arg1, arg1);
#endif
    }
A
aurel32 已提交
2575 2576
}

A
aurel32 已提交
2577
static always_inline void gen_qemu_ld16s(DisasContext *ctx, TCGv arg1, TCGv arg2)
A
aurel32 已提交
2578
{
A
aurel32 已提交
2579 2580
    if (unlikely(ctx->le_mode)) {
#if defined(TARGET_PPC64)
P
pbrook 已提交
2581
        TCGv_i32 t0;
A
aurel32 已提交
2582
        tcg_gen_qemu_ld16u(arg1, arg2, ctx->mem_idx);
P
pbrook 已提交
2583
        t0 = tcg_temp_new_i32();
A
aurel32 已提交
2584
        tcg_gen_trunc_tl_i32(t0, arg1);
2585
        tcg_gen_bswap16_i32(t0, t0);
A
aurel32 已提交
2586 2587
        tcg_gen_extu_i32_tl(arg1, t0);
        tcg_gen_ext16s_tl(arg1, arg1);
P
pbrook 已提交
2588
        tcg_temp_free_i32(t0);
A
aurel32 已提交
2589 2590 2591 2592 2593 2594 2595 2596
#else
        tcg_gen_qemu_ld16u(arg1, arg2, ctx->mem_idx);
        tcg_gen_bswap16_i32(arg1, arg1);
        tcg_gen_ext16s_i32(arg1, arg1);
#endif
    } else {
        tcg_gen_qemu_ld16s(arg1, arg2, ctx->mem_idx);
    }
A
aurel32 已提交
2597 2598
}

A
aurel32 已提交
2599
static always_inline void gen_qemu_ld32u(DisasContext *ctx, TCGv arg1, TCGv arg2)
A
aurel32 已提交
2600
{
A
aurel32 已提交
2601 2602 2603 2604 2605
    tcg_gen_qemu_ld32u(arg1, arg2, ctx->mem_idx);
    if (unlikely(ctx->le_mode)) {
#if defined(TARGET_PPC64)
        TCGv_i32 t0 = tcg_temp_new_i32();
        tcg_gen_trunc_tl_i32(t0, arg1);
2606
        tcg_gen_bswap_i32(t0, t0);
A
aurel32 已提交
2607
        tcg_gen_extu_i32_tl(arg1, t0);
P
pbrook 已提交
2608
        tcg_temp_free_i32(t0);
A
aurel32 已提交
2609 2610 2611 2612
#else
        tcg_gen_bswap_i32(arg1, arg1);
#endif
    }
A
aurel32 已提交
2613 2614
}

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

A
aurel32 已提交
2631
static always_inline void gen_qemu_ld64(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
A
aurel32 已提交
2632
{
A
aurel32 已提交
2633 2634 2635 2636
    tcg_gen_qemu_ld64(arg1, arg2, ctx->mem_idx);
    if (unlikely(ctx->le_mode)) {
        tcg_gen_bswap_i64(arg1, arg1);
    }
A
aurel32 已提交
2637 2638
}

A
aurel32 已提交
2639
static always_inline void gen_qemu_st8(DisasContext *ctx, TCGv arg1, TCGv arg2)
A
aurel32 已提交
2640
{
A
aurel32 已提交
2641
    tcg_gen_qemu_st8(arg1, arg2, ctx->mem_idx);
A
aurel32 已提交
2642 2643
}

A
aurel32 已提交
2644
static always_inline void gen_qemu_st16(DisasContext *ctx, TCGv arg1, TCGv arg2)
A
aurel32 已提交
2645
{
A
aurel32 已提交
2646 2647
    if (unlikely(ctx->le_mode)) {
#if defined(TARGET_PPC64)
P
pbrook 已提交
2648
        TCGv_i32 t0;
A
aurel32 已提交
2649
        TCGv t1;
P
pbrook 已提交
2650
        t0 = tcg_temp_new_i32();
A
aurel32 已提交
2651
        tcg_gen_trunc_tl_i32(t0, arg1);
2652 2653
        tcg_gen_ext16u_i32(t0, t0);
        tcg_gen_bswap16_i32(t0, t0);
A
aurel32 已提交
2654
        t1 = tcg_temp_new();
2655
        tcg_gen_extu_i32_tl(t1, t0);
P
pbrook 已提交
2656
        tcg_temp_free_i32(t0);
A
aurel32 已提交
2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668
        tcg_gen_qemu_st16(t1, arg2, ctx->mem_idx);
        tcg_temp_free(t1);
#else
        TCGv t0 = tcg_temp_new();
        tcg_gen_ext16u_tl(t0, arg1);
        tcg_gen_bswap16_i32(t0, t0);
        tcg_gen_qemu_st16(t0, arg2, ctx->mem_idx);
        tcg_temp_free(t0);
#endif
    } else {
        tcg_gen_qemu_st16(arg1, arg2, ctx->mem_idx);
    }
A
aurel32 已提交
2669 2670
}

A
aurel32 已提交
2671
static always_inline void gen_qemu_st32(DisasContext *ctx, TCGv arg1, TCGv arg2)
A
aurel32 已提交
2672
{
A
aurel32 已提交
2673 2674
    if (unlikely(ctx->le_mode)) {
#if defined(TARGET_PPC64)
P
pbrook 已提交
2675
        TCGv_i32 t0;
A
aurel32 已提交
2676
        TCGv t1;
P
pbrook 已提交
2677
        t0 = tcg_temp_new_i32();
A
aurel32 已提交
2678
        tcg_gen_trunc_tl_i32(t0, arg1);
2679
        tcg_gen_bswap_i32(t0, t0);
A
aurel32 已提交
2680
        t1 = tcg_temp_new();
2681
        tcg_gen_extu_i32_tl(t1, t0);
P
pbrook 已提交
2682
        tcg_temp_free_i32(t0);
A
aurel32 已提交
2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693
        tcg_gen_qemu_st32(t1, arg2, ctx->mem_idx);
        tcg_temp_free(t1);
#else
        TCGv t0 = tcg_temp_new_i32();
        tcg_gen_bswap_i32(t0, arg1);
        tcg_gen_qemu_st32(t0, arg2, ctx->mem_idx);
        tcg_temp_free(t0);
#endif
    } else {
        tcg_gen_qemu_st32(arg1, arg2, ctx->mem_idx);
    }
A
aurel32 已提交
2694 2695
}

A
aurel32 已提交
2696
static always_inline void gen_qemu_st64(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
A
aurel32 已提交
2697
{
A
aurel32 已提交
2698
    if (unlikely(ctx->le_mode)) {
P
pbrook 已提交
2699
        TCGv_i64 t0 = tcg_temp_new_i64();
A
aurel32 已提交
2700 2701
        tcg_gen_bswap_i64(t0, arg1);
        tcg_gen_qemu_st64(t0, arg2, ctx->mem_idx);
P
pbrook 已提交
2702
        tcg_temp_free_i64(t0);
A
aurel32 已提交
2703
    } else
A
aurel32 已提交
2704
        tcg_gen_qemu_st64(arg1, arg2, ctx->mem_idx);
A
aurel32 已提交
2705 2706
}

2707 2708
#define GEN_LD(name, ldop, opc, type)                                         \
GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type)                          \
B
bellard 已提交
2709
{                                                                             \
A
aurel32 已提交
2710 2711 2712 2713 2714
    TCGv EA;                                                                  \
    gen_set_access_type(ctx, ACCESS_INT);                                     \
    EA = tcg_temp_new();                                                      \
    gen_addr_imm_index(ctx, EA, 0);                                           \
    gen_qemu_##ldop(ctx, cpu_gpr[rD(ctx->opcode)], EA);                       \
A
aurel32 已提交
2715
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2716 2717
}

2718 2719
#define GEN_LDU(name, ldop, opc, type)                                        \
GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type)                       \
B
bellard 已提交
2720
{                                                                             \
A
aurel32 已提交
2721
    TCGv EA;                                                                  \
2722 2723
    if (unlikely(rA(ctx->opcode) == 0 ||                                      \
                 rA(ctx->opcode) == rD(ctx->opcode))) {                       \
A
aurel32 已提交
2724
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);                   \
2725
        return;                                                               \
2726
    }                                                                         \
A
aurel32 已提交
2727
    gen_set_access_type(ctx, ACCESS_INT);                                     \
2728
    EA = tcg_temp_new();                                                      \
J
j_mayer 已提交
2729
    if (type == PPC_64B)                                                      \
A
aurel32 已提交
2730
        gen_addr_imm_index(ctx, EA, 0x03);                                    \
J
j_mayer 已提交
2731
    else                                                                      \
A
aurel32 已提交
2732 2733
        gen_addr_imm_index(ctx, EA, 0);                                       \
    gen_qemu_##ldop(ctx, cpu_gpr[rD(ctx->opcode)], EA);                       \
A
aurel32 已提交
2734 2735
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2736 2737
}

2738 2739
#define GEN_LDUX(name, ldop, opc2, opc3, type)                                \
GEN_HANDLER(name##ux, 0x1F, opc2, opc3, 0x00000001, type)                     \
B
bellard 已提交
2740
{                                                                             \
A
aurel32 已提交
2741
    TCGv EA;                                                                  \
2742 2743
    if (unlikely(rA(ctx->opcode) == 0 ||                                      \
                 rA(ctx->opcode) == rD(ctx->opcode))) {                       \
A
aurel32 已提交
2744
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);                   \
2745
        return;                                                               \
2746
    }                                                                         \
A
aurel32 已提交
2747
    gen_set_access_type(ctx, ACCESS_INT);                                     \
2748
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
2749 2750
    gen_addr_reg_index(ctx, EA);                                              \
    gen_qemu_##ldop(ctx, cpu_gpr[rD(ctx->opcode)], EA);                       \
A
aurel32 已提交
2751 2752
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2753 2754
}

2755 2756
#define GEN_LDX(name, ldop, opc2, opc3, type)                                 \
GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type)                      \
B
bellard 已提交
2757
{                                                                             \
A
aurel32 已提交
2758 2759 2760 2761 2762
    TCGv EA;                                                                  \
    gen_set_access_type(ctx, ACCESS_INT);                                     \
    EA = tcg_temp_new();                                                      \
    gen_addr_reg_index(ctx, EA);                                              \
    gen_qemu_##ldop(ctx, cpu_gpr[rD(ctx->opcode)], EA);                       \
A
aurel32 已提交
2763
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2764 2765
}

2766 2767 2768 2769 2770
#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 已提交
2771 2772

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

    /* Restore CPU state */
A
aurel32 已提交
2823
    if (unlikely(ctx->mem_idx == 0)) {
A
aurel32 已提交
2824
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
2825 2826 2827 2828 2829
        return;
    }
    ra = rA(ctx->opcode);
    rd = rD(ctx->opcode);
    if (unlikely((rd & 1) || rd == ra)) {
A
aurel32 已提交
2830
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
2831 2832
        return;
    }
A
aurel32 已提交
2833
    if (unlikely(ctx->le_mode)) {
2834
        /* Little-endian mode is not handled */
A
aurel32 已提交
2835
        gen_exception_err(ctx, POWERPC_EXCP_ALIGN, POWERPC_EXCP_ALIGN_LE);
2836 2837
        return;
    }
A
aurel32 已提交
2838
    gen_set_access_type(ctx, ACCESS_INT);
P
pbrook 已提交
2839
    EA = tcg_temp_new();
A
aurel32 已提交
2840 2841 2842 2843
    gen_addr_imm_index(ctx, EA, 0x0F);
    gen_qemu_ld64(ctx, cpu_gpr[rd], EA);
    gen_addr_add(ctx, EA, EA, 8);
    gen_qemu_ld64(ctx, cpu_gpr[rd+1], EA);
A
aurel32 已提交
2844
    tcg_temp_free(EA);
2845 2846
#endif
}
2847
#endif
B
bellard 已提交
2848 2849

/***                              Integer store                            ***/
2850 2851
#define GEN_ST(name, stop, opc, type)                                         \
GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type)                          \
B
bellard 已提交
2852
{                                                                             \
A
aurel32 已提交
2853 2854 2855 2856 2857
    TCGv EA;                                                                  \
    gen_set_access_type(ctx, ACCESS_INT);                                     \
    EA = tcg_temp_new();                                                      \
    gen_addr_imm_index(ctx, EA, 0);                                           \
    gen_qemu_##stop(ctx, cpu_gpr[rS(ctx->opcode)], EA);                       \
A
aurel32 已提交
2858
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2859 2860
}

2861 2862
#define GEN_STU(name, stop, opc, type)                                        \
GEN_HANDLER(stop##u, opc, 0xFF, 0xFF, 0x00000000, type)                       \
B
bellard 已提交
2863
{                                                                             \
A
aurel32 已提交
2864
    TCGv EA;                                                                  \
2865
    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
A
aurel32 已提交
2866
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);                   \
2867
        return;                                                               \
2868
    }                                                                         \
A
aurel32 已提交
2869
    gen_set_access_type(ctx, ACCESS_INT);                                     \
2870
    EA = tcg_temp_new();                                                      \
J
j_mayer 已提交
2871
    if (type == PPC_64B)                                                      \
A
aurel32 已提交
2872
        gen_addr_imm_index(ctx, EA, 0x03);                                    \
J
j_mayer 已提交
2873
    else                                                                      \
A
aurel32 已提交
2874 2875
        gen_addr_imm_index(ctx, EA, 0);                                       \
    gen_qemu_##stop(ctx, cpu_gpr[rS(ctx->opcode)], EA);                       \
A
aurel32 已提交
2876 2877
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2878 2879
}

2880 2881
#define GEN_STUX(name, stop, opc2, opc3, type)                                \
GEN_HANDLER(name##ux, 0x1F, opc2, opc3, 0x00000001, type)                     \
B
bellard 已提交
2882
{                                                                             \
A
aurel32 已提交
2883
    TCGv EA;                                                                  \
2884
    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
A
aurel32 已提交
2885
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);                   \
2886
        return;                                                               \
2887
    }                                                                         \
A
aurel32 已提交
2888
    gen_set_access_type(ctx, ACCESS_INT);                                     \
2889
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
2890 2891
    gen_addr_reg_index(ctx, EA);                                              \
    gen_qemu_##stop(ctx, cpu_gpr[rS(ctx->opcode)], EA);                       \
A
aurel32 已提交
2892 2893
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2894 2895
}

2896 2897
#define GEN_STX(name, stop, opc2, opc3, type)                                 \
GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type)                      \
B
bellard 已提交
2898
{                                                                             \
A
aurel32 已提交
2899 2900 2901 2902 2903
    TCGv EA;                                                                  \
    gen_set_access_type(ctx, ACCESS_INT);                                     \
    EA = tcg_temp_new();                                                      \
    gen_addr_reg_index(ctx, EA);                                              \
    gen_qemu_##stop(ctx, cpu_gpr[rS(ctx->opcode)], EA);                       \
A
aurel32 已提交
2904
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2905 2906
}

2907 2908 2909 2910 2911
#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 已提交
2912 2913

/* stb stbu stbux stbx */
2914
GEN_STS(stb, st8, 0x06, PPC_INTEGER);
B
bellard 已提交
2915
/* sth sthu sthux sthx */
2916
GEN_STS(sth, st16, 0x0C, PPC_INTEGER);
B
bellard 已提交
2917
/* stw stwu stwux stwx */
2918
GEN_STS(stw, st32, 0x04, PPC_INTEGER);
2919
#if defined(TARGET_PPC64)
2920 2921
GEN_STUX(std, st64, 0x15, 0x05, PPC_64B);
GEN_STX(std, st64, 0x15, 0x04, PPC_64B);
2922
GEN_HANDLER(std, 0x3E, 0xFF, 0xFF, 0x00000000, PPC_64B)
2923
{
2924
    int rs;
A
aurel32 已提交
2925
    TCGv EA;
2926 2927 2928 2929

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

B
bellard 已提交
2991
/* lwbrx */
A
aurel32 已提交
2992
static void always_inline gen_qemu_ld32ur(DisasContext *ctx, TCGv arg1, TCGv arg2)
A
aurel32 已提交
2993
{
A
aurel32 已提交
2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005
    tcg_gen_qemu_ld32u(arg1, arg2, ctx->mem_idx);
    if (likely(!ctx->le_mode)) {
#if defined(TARGET_PPC64)
        TCGv_i32 t0 = tcg_temp_new_i32();
        tcg_gen_trunc_tl_i32(t0, arg1);
        tcg_gen_bswap_i32(t0, t0);
        tcg_gen_extu_i32_tl(arg1, t0);
        tcg_temp_free_i32(t0);
#else
        tcg_gen_bswap_i32(arg1, arg1);
#endif
    }
A
aurel32 已提交
3006
}
3007
GEN_LDX(lwbr, ld32ur, 0x16, 0x10, PPC_INTEGER);
A
aurel32 已提交
3008

B
bellard 已提交
3009
/* sthbrx */
A
aurel32 已提交
3010
static void always_inline gen_qemu_st16r(DisasContext *ctx, TCGv arg1, TCGv arg2)
A
aurel32 已提交
3011
{
A
aurel32 已提交
3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034
    if (likely(!ctx->le_mode)) {
#if defined(TARGET_PPC64)
        TCGv_i32 t0;
        TCGv t1;
        t0 = tcg_temp_new_i32();
        tcg_gen_trunc_tl_i32(t0, arg1);
        tcg_gen_ext16u_i32(t0, t0);
        tcg_gen_bswap16_i32(t0, t0);
        t1 = tcg_temp_new();
        tcg_gen_extu_i32_tl(t1, t0);
        tcg_temp_free_i32(t0);
        tcg_gen_qemu_st16(t1, arg2, ctx->mem_idx);
        tcg_temp_free(t1);
#else
        TCGv t0 = tcg_temp_new();
        tcg_gen_ext16u_tl(t0, arg1);
        tcg_gen_bswap16_i32(t0, t0);
        tcg_gen_qemu_st16(t0, arg2, ctx->mem_idx);
        tcg_temp_free(t0);
#endif
    } else {
        tcg_gen_qemu_st16(arg1, arg2, ctx->mem_idx);
    }
A
aurel32 已提交
3035
}
3036
GEN_STX(sthbr, st16r, 0x16, 0x1C, PPC_INTEGER);
A
aurel32 已提交
3037

B
bellard 已提交
3038
/* stwbrx */
A
aurel32 已提交
3039
static void always_inline gen_qemu_st32r(DisasContext *ctx, TCGv arg1, TCGv arg2)
A
aurel32 已提交
3040
{
A
aurel32 已提交
3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061
    if (likely(!ctx->le_mode)) {
#if defined(TARGET_PPC64)
        TCGv_i32 t0;
        TCGv t1;
        t0 = tcg_temp_new_i32();
        tcg_gen_trunc_tl_i32(t0, arg1);
        tcg_gen_bswap_i32(t0, t0);
        t1 = tcg_temp_new();
        tcg_gen_extu_i32_tl(t1, t0);
        tcg_temp_free_i32(t0);
        tcg_gen_qemu_st32(t1, arg2, ctx->mem_idx);
        tcg_temp_free(t1);
#else
        TCGv t0 = tcg_temp_new_i32();
        tcg_gen_bswap_i32(t0, arg1);
        tcg_gen_qemu_st32(t0, arg2, ctx->mem_idx);
        tcg_temp_free(t0);
#endif
    } else {
        tcg_gen_qemu_st32(arg1, arg2, ctx->mem_idx);
    }
A
aurel32 已提交
3062
}
3063
GEN_STX(stwbr, st32r, 0x16, 0x14, PPC_INTEGER);
B
bellard 已提交
3064 3065 3066 3067 3068

/***                    Integer load and store multiple                    ***/
/* lmw */
GEN_HANDLER(lmw, 0x2E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
A
aurel32 已提交
3069 3070 3071
    TCGv t0;
    TCGv_i32 t1;
    gen_set_access_type(ctx, ACCESS_INT);
3072
    /* NIP cannot be restored if the memory exception comes from an helper */
3073
    gen_update_nip(ctx, ctx->nip - 4);
A
aurel32 已提交
3074 3075 3076
    t0 = tcg_temp_new();
    t1 = tcg_const_i32(rD(ctx->opcode));
    gen_addr_imm_index(ctx, t0, 0);
3077 3078 3079
    gen_helper_lmw(t0, t1);
    tcg_temp_free(t0);
    tcg_temp_free_i32(t1);
B
bellard 已提交
3080 3081 3082 3083 3084
}

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

/***                    Integer load and store strings                     ***/
/* lswi */
3100
/* PowerPC32 specification says we must generate an exception if
3101 3102 3103 3104
 * 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...
 */
3105
GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_STRING)
B
bellard 已提交
3106
{
3107 3108
    TCGv t0;
    TCGv_i32 t1, t2;
B
bellard 已提交
3109 3110
    int nb = NB(ctx->opcode);
    int start = rD(ctx->opcode);
3111
    int ra = rA(ctx->opcode);
B
bellard 已提交
3112 3113 3114 3115 3116
    int nr;

    if (nb == 0)
        nb = 32;
    nr = nb / 4;
3117 3118 3119
    if (unlikely(((start + nr) > 32  &&
                  start <= ra && (start + nr - 32) > ra) ||
                 ((start + nr) <= 32 && start <= ra && (start + nr) > ra))) {
A
aurel32 已提交
3120
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_LSWX);
3121
        return;
B
bellard 已提交
3122
    }
A
aurel32 已提交
3123
    gen_set_access_type(ctx, ACCESS_INT);
3124
    /* NIP cannot be restored if the memory exception comes from an helper */
3125
    gen_update_nip(ctx, ctx->nip - 4);
3126
    t0 = tcg_temp_new();
A
aurel32 已提交
3127
    gen_addr_register(ctx, t0);
3128 3129 3130 3131 3132 3133
    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 已提交
3134 3135 3136
}

/* lswx */
3137
GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001, PPC_STRING)
B
bellard 已提交
3138
{
A
aurel32 已提交
3139 3140 3141
    TCGv t0;
    TCGv_i32 t1, t2, t3;
    gen_set_access_type(ctx, ACCESS_INT);
3142
    /* NIP cannot be restored if the memory exception comes from an helper */
3143
    gen_update_nip(ctx, ctx->nip - 4);
A
aurel32 已提交
3144 3145 3146 3147 3148
    t0 = tcg_temp_new();
    gen_addr_reg_index(ctx, t0);
    t1 = tcg_const_i32(rD(ctx->opcode));
    t2 = tcg_const_i32(rA(ctx->opcode));
    t3 = tcg_const_i32(rB(ctx->opcode));
3149 3150 3151 3152 3153
    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 已提交
3154 3155 3156
}

/* stswi */
3157
GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_STRING)
B
bellard 已提交
3158
{
A
aurel32 已提交
3159 3160
    TCGv t0;
    TCGv_i32 t1, t2;
B
bellard 已提交
3161
    int nb = NB(ctx->opcode);
A
aurel32 已提交
3162
    gen_set_access_type(ctx, ACCESS_INT);
3163
    /* NIP cannot be restored if the memory exception comes from an helper */
3164
    gen_update_nip(ctx, ctx->nip - 4);
A
aurel32 已提交
3165 3166
    t0 = tcg_temp_new();
    gen_addr_register(ctx, t0);
B
bellard 已提交
3167 3168
    if (nb == 0)
        nb = 32;
3169
    t1 = tcg_const_i32(nb);
A
aurel32 已提交
3170
    t2 = tcg_const_i32(rS(ctx->opcode));
3171 3172 3173 3174
    gen_helper_stsw(t0, t1, t2);
    tcg_temp_free(t0);
    tcg_temp_free_i32(t1);
    tcg_temp_free_i32(t2);
B
bellard 已提交
3175 3176 3177
}

/* stswx */
3178
GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_STRING)
B
bellard 已提交
3179
{
A
aurel32 已提交
3180 3181 3182
    TCGv t0;
    TCGv_i32 t1, t2;
    gen_set_access_type(ctx, ACCESS_INT);
3183
    /* NIP cannot be restored if the memory exception comes from an helper */
3184
    gen_update_nip(ctx, ctx->nip - 4);
A
aurel32 已提交
3185 3186 3187
    t0 = tcg_temp_new();
    gen_addr_reg_index(ctx, t0);
    t1 = tcg_temp_new_i32();
3188 3189
    tcg_gen_trunc_tl_i32(t1, cpu_xer);
    tcg_gen_andi_i32(t1, t1, 0x7F);
A
aurel32 已提交
3190
    t2 = tcg_const_i32(rS(ctx->opcode));
3191 3192 3193 3194
    gen_helper_stsw(t0, t1, t2);
    tcg_temp_free(t0);
    tcg_temp_free_i32(t1);
    tcg_temp_free_i32(t2);
B
bellard 已提交
3195 3196 3197 3198
}

/***                        Memory synchronisation                         ***/
/* eieio */
3199
GEN_HANDLER(eieio, 0x1F, 0x16, 0x1A, 0x03FFF801, PPC_MEM_EIEIO)
B
bellard 已提交
3200 3201 3202 3203
{
}

/* isync */
3204
GEN_HANDLER(isync, 0x13, 0x16, 0x04, 0x03FFF801, PPC_MEM)
B
bellard 已提交
3205
{
A
aurel32 已提交
3206
    gen_stop_exception(ctx);
B
bellard 已提交
3207 3208
}

3209
/* lwarx */
3210
GEN_HANDLER(lwarx, 0x1F, 0x14, 0x00, 0x00000001, PPC_RES)
B
bellard 已提交
3211
{
A
aurel32 已提交
3212 3213 3214 3215
    TCGv t0;
    gen_set_access_type(ctx, ACCESS_RES);
    t0 = tcg_temp_local_new();
    gen_addr_reg_index(ctx, t0);
3216
    gen_check_align(ctx, t0, 0x03);
A
aurel32 已提交
3217
    gen_qemu_ld32u(ctx, cpu_gpr[rD(ctx->opcode)], t0);
3218 3219
    tcg_gen_mov_tl(cpu_reserve, t0);
    tcg_temp_free(t0);
B
bellard 已提交
3220 3221 3222
}

/* stwcx. */
3223
GEN_HANDLER2(stwcx_, "stwcx.", 0x1F, 0x16, 0x04, 0x00000000, PPC_RES)
B
bellard 已提交
3224
{
A
aurel32 已提交
3225 3226 3227 3228 3229
    int l1;
    TCGv t0;
    gen_set_access_type(ctx, ACCESS_RES);
    t0 = tcg_temp_local_new();
    gen_addr_reg_index(ctx, t0);
3230 3231 3232 3233
    gen_check_align(ctx, t0, 0x03);
    tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_xer);
    tcg_gen_shri_i32(cpu_crf[0], cpu_crf[0], XER_SO);
    tcg_gen_andi_i32(cpu_crf[0], cpu_crf[0], 1);
A
aurel32 已提交
3234
    l1 = gen_new_label();
3235 3236
    tcg_gen_brcond_tl(TCG_COND_NE, t0, cpu_reserve, l1);
    tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 1 << CRF_EQ);
A
aurel32 已提交
3237
    gen_qemu_st32(ctx, cpu_gpr[rS(ctx->opcode)], t0);
3238 3239 3240
    gen_set_label(l1);
    tcg_gen_movi_tl(cpu_reserve, -1);
    tcg_temp_free(t0);
B
bellard 已提交
3241 3242
}

J
j_mayer 已提交
3243 3244
#if defined(TARGET_PPC64)
/* ldarx */
3245
GEN_HANDLER(ldarx, 0x1F, 0x14, 0x02, 0x00000001, PPC_64B)
J
j_mayer 已提交
3246
{
A
aurel32 已提交
3247 3248 3249 3250
    TCGv t0;
    gen_set_access_type(ctx, ACCESS_RES);
    t0 = tcg_temp_local_new();
    gen_addr_reg_index(ctx, t0);
3251
    gen_check_align(ctx, t0, 0x07);
A
aurel32 已提交
3252
    gen_qemu_ld64(ctx, cpu_gpr[rD(ctx->opcode)], t0);
3253 3254
    tcg_gen_mov_tl(cpu_reserve, t0);
    tcg_temp_free(t0);
J
j_mayer 已提交
3255 3256 3257
}

/* stdcx. */
3258
GEN_HANDLER2(stdcx_, "stdcx.", 0x1F, 0x16, 0x06, 0x00000000, PPC_64B)
J
j_mayer 已提交
3259
{
A
aurel32 已提交
3260 3261 3262 3263 3264
    int l1;
    TCGv t0;
    gen_set_access_type(ctx, ACCESS_RES);
    t0 = tcg_temp_local_new();
    gen_addr_reg_index(ctx, t0);
3265 3266 3267 3268
    gen_check_align(ctx, t0, 0x07);
    tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_xer);
    tcg_gen_shri_i32(cpu_crf[0], cpu_crf[0], XER_SO);
    tcg_gen_andi_i32(cpu_crf[0], cpu_crf[0], 1);
A
aurel32 已提交
3269
    l1 = gen_new_label();
3270 3271
    tcg_gen_brcond_tl(TCG_COND_NE, t0, cpu_reserve, l1);
    tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 1 << CRF_EQ);
A
aurel32 已提交
3272
    gen_qemu_st64(ctx, cpu_gpr[rS(ctx->opcode)], t0);
3273 3274 3275
    gen_set_label(l1);
    tcg_gen_movi_tl(cpu_reserve, -1);
    tcg_temp_free(t0);
J
j_mayer 已提交
3276 3277 3278
}
#endif /* defined(TARGET_PPC64) */

B
bellard 已提交
3279
/* sync */
3280
GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x039FF801, PPC_MEM_SYNC)
B
bellard 已提交
3281 3282 3283
{
}

3284 3285 3286
/* wait */
GEN_HANDLER(wait, 0x1F, 0x1E, 0x01, 0x03FFF801, PPC_WAIT)
{
3287 3288 3289
    TCGv_i32 t0 = tcg_temp_new_i32();
    tcg_gen_st_i32(t0, cpu_env, offsetof(CPUState, halted));
    tcg_temp_free_i32(t0);
3290
    /* Stop translation, as the CPU is supposed to sleep from now */
A
aurel32 已提交
3291
    gen_exception_err(ctx, EXCP_HLT, 1);
3292 3293
}

B
bellard 已提交
3294
/***                         Floating-point load                           ***/
3295 3296
#define GEN_LDF(name, ldop, opc, type)                                        \
GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type)                          \
B
bellard 已提交
3297
{                                                                             \
3298
    TCGv EA;                                                                  \
3299
    if (unlikely(!ctx->fpu_enabled)) {                                        \
A
aurel32 已提交
3300
        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
3301 3302
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
3303
    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
3304
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
3305 3306
    gen_addr_imm_index(ctx, EA, 0);                                           \
    gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA);                       \
3307
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
3308 3309
}

3310 3311
#define GEN_LDUF(name, ldop, opc, type)                                       \
GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type)                       \
B
bellard 已提交
3312
{                                                                             \
3313
    TCGv EA;                                                                  \
3314
    if (unlikely(!ctx->fpu_enabled)) {                                        \
A
aurel32 已提交
3315
        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
3316 3317
        return;                                                               \
    }                                                                         \
3318
    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
A
aurel32 已提交
3319
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);                   \
3320
        return;                                                               \
3321
    }                                                                         \
A
aurel32 已提交
3322
    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
3323
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
3324 3325
    gen_addr_imm_index(ctx, EA, 0);                                           \
    gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA);                       \
3326 3327
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
3328 3329
}

3330 3331
#define GEN_LDUXF(name, ldop, opc, type)                                      \
GEN_HANDLER(name##ux, 0x1F, 0x17, opc, 0x00000001, type)                      \
B
bellard 已提交
3332
{                                                                             \
3333
    TCGv EA;                                                                  \
3334
    if (unlikely(!ctx->fpu_enabled)) {                                        \
A
aurel32 已提交
3335
        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
3336 3337
        return;                                                               \
    }                                                                         \
3338
    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
A
aurel32 已提交
3339
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);                   \
3340
        return;                                                               \
3341
    }                                                                         \
A
aurel32 已提交
3342
    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
3343
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
3344 3345
    gen_addr_reg_index(ctx, EA);                                              \
    gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA);                       \
3346 3347
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
3348 3349
}

3350 3351
#define GEN_LDXF(name, ldop, opc2, opc3, type)                                \
GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type)                      \
B
bellard 已提交
3352
{                                                                             \
3353
    TCGv EA;                                                                  \
3354
    if (unlikely(!ctx->fpu_enabled)) {                                        \
A
aurel32 已提交
3355
        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
3356 3357
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
3358
    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
3359
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
3360 3361
    gen_addr_reg_index(ctx, EA);                                              \
    gen_qemu_##ldop(ctx, cpu_fpr[rD(ctx->opcode)], EA);                       \
3362
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
3363 3364
}

3365 3366 3367 3368 3369 3370
#define GEN_LDFS(name, ldop, op, type)                                        \
GEN_LDF(name, ldop, op | 0x20, type);                                         \
GEN_LDUF(name, ldop, op | 0x21, type);                                        \
GEN_LDUXF(name, ldop, op | 0x01, type);                                       \
GEN_LDXF(name, ldop, 0x17, op | 0x00, type)

A
aurel32 已提交
3371
static always_inline void gen_qemu_ld32fs(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
3372 3373 3374
{
    TCGv t0 = tcg_temp_new();
    TCGv_i32 t1 = tcg_temp_new_i32();
A
aurel32 已提交
3375
    gen_qemu_ld32u(ctx, t0, arg2);
3376 3377 3378 3379 3380
    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 已提交
3381

3382 3383 3384 3385
 /* lfd lfdu lfdux lfdx */
GEN_LDFS(lfd, ld64, 0x12, PPC_FLOAT);
 /* lfs lfsu lfsux lfsx */
GEN_LDFS(lfs, ld32fs, 0x10, PPC_FLOAT);
B
bellard 已提交
3386 3387

/***                         Floating-point store                          ***/
3388 3389
#define GEN_STF(name, stop, opc, type)                                        \
GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type)                          \
B
bellard 已提交
3390
{                                                                             \
3391
    TCGv EA;                                                                  \
3392
    if (unlikely(!ctx->fpu_enabled)) {                                        \
A
aurel32 已提交
3393
        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
3394 3395
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
3396
    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
3397
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
3398 3399
    gen_addr_imm_index(ctx, EA, 0);                                           \
    gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA);                       \
3400
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
3401 3402
}

3403 3404
#define GEN_STUF(name, stop, opc, type)                                       \
GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type)                       \
B
bellard 已提交
3405
{                                                                             \
3406
    TCGv EA;                                                                  \
3407
    if (unlikely(!ctx->fpu_enabled)) {                                        \
A
aurel32 已提交
3408
        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
3409 3410
        return;                                                               \
    }                                                                         \
3411
    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
A
aurel32 已提交
3412
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);                   \
3413
        return;                                                               \
3414
    }                                                                         \
A
aurel32 已提交
3415
    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
3416
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
3417 3418
    gen_addr_imm_index(ctx, EA, 0);                                           \
    gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA);                       \
3419 3420
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
3421 3422
}

3423 3424
#define GEN_STUXF(name, stop, opc, type)                                      \
GEN_HANDLER(name##ux, 0x1F, 0x17, opc, 0x00000001, type)                      \
B
bellard 已提交
3425
{                                                                             \
3426
    TCGv EA;                                                                  \
3427
    if (unlikely(!ctx->fpu_enabled)) {                                        \
A
aurel32 已提交
3428
        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
3429 3430
        return;                                                               \
    }                                                                         \
3431
    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
A
aurel32 已提交
3432
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);                   \
3433
        return;                                                               \
3434
    }                                                                         \
A
aurel32 已提交
3435
    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
3436
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
3437 3438
    gen_addr_reg_index(ctx, EA);                                              \
    gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA);                       \
3439 3440
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
3441 3442
}

3443 3444
#define GEN_STXF(name, stop, opc2, opc3, type)                                \
GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type)                      \
B
bellard 已提交
3445
{                                                                             \
3446
    TCGv EA;                                                                  \
3447
    if (unlikely(!ctx->fpu_enabled)) {                                        \
A
aurel32 已提交
3448
        gen_exception(ctx, POWERPC_EXCP_FPU);                                 \
3449 3450
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
3451
    gen_set_access_type(ctx, ACCESS_FLOAT);                                   \
3452
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
3453 3454
    gen_addr_reg_index(ctx, EA);                                              \
    gen_qemu_##stop(ctx, cpu_fpr[rS(ctx->opcode)], EA);                       \
3455
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
3456 3457
}

3458 3459 3460 3461 3462 3463
#define GEN_STFS(name, stop, op, type)                                        \
GEN_STF(name, stop, op | 0x20, type);                                         \
GEN_STUF(name, stop, op | 0x21, type);                                        \
GEN_STUXF(name, stop, op | 0x01, type);                                       \
GEN_STXF(name, stop, 0x17, op | 0x00, type)

A
aurel32 已提交
3464
static always_inline void gen_qemu_st32fs(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
3465 3466 3467 3468 3469 3470
{
    TCGv_i32 t0 = tcg_temp_new_i32();
    TCGv t1 = tcg_temp_new();
    gen_helper_float64_to_float32(t0, arg1);
    tcg_gen_extu_i32_tl(t1, t0);
    tcg_temp_free_i32(t0);
A
aurel32 已提交
3471
    gen_qemu_st32(ctx, t1, arg2);
3472 3473
    tcg_temp_free(t1);
}
B
bellard 已提交
3474 3475

/* stfd stfdu stfdux stfdx */
3476
GEN_STFS(stfd, st64, 0x16, PPC_FLOAT);
B
bellard 已提交
3477
/* stfs stfsu stfsux stfsx */
3478
GEN_STFS(stfs, st32fs, 0x14, PPC_FLOAT);
B
bellard 已提交
3479 3480

/* Optional: */
A
aurel32 已提交
3481
static always_inline void gen_qemu_st32fiw(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
3482 3483 3484
{
    TCGv t0 = tcg_temp_new();
    tcg_gen_trunc_i64_tl(t0, arg1),
A
aurel32 已提交
3485
    gen_qemu_st32(ctx, t0, arg2);
3486 3487
    tcg_temp_free(t0);
}
B
bellard 已提交
3488
/* stfiwx */
3489
GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX);
B
bellard 已提交
3490 3491

/***                                Branch                                 ***/
3492 3493
static always_inline void gen_goto_tb (DisasContext *ctx, int n,
                                       target_ulong dest)
3494 3495 3496
{
    TranslationBlock *tb;
    tb = ctx->tb;
3497 3498 3499 3500
#if defined(TARGET_PPC64)
    if (!ctx->sf_mode)
        dest = (uint32_t) dest;
#endif
B
bellard 已提交
3501
    if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) &&
3502
        likely(!ctx->singlestep_enabled)) {
B
bellard 已提交
3503
        tcg_gen_goto_tb(n);
3504
        tcg_gen_movi_tl(cpu_nip, dest & ~3);
B
bellard 已提交
3505
        tcg_gen_exit_tb((long)tb + n);
3506
    } else {
3507
        tcg_gen_movi_tl(cpu_nip, dest & ~3);
3508 3509
        if (unlikely(ctx->singlestep_enabled)) {
            if ((ctx->singlestep_enabled &
A
aurel32 已提交
3510
                (CPU_BRANCH_STEP | CPU_SINGLE_STEP)) &&
3511 3512 3513
                ctx->exception == POWERPC_EXCP_BRANCH) {
                target_ulong tmp = ctx->nip;
                ctx->nip = dest;
A
aurel32 已提交
3514
                gen_exception(ctx, POWERPC_EXCP_TRACE);
3515 3516 3517
                ctx->nip = tmp;
            }
            if (ctx->singlestep_enabled & GDBSTUB_SINGLE_STEP) {
A
aurel32 已提交
3518
                gen_debug_exception(ctx);
3519 3520
            }
        }
B
bellard 已提交
3521
        tcg_gen_exit_tb(0);
3522
    }
B
bellard 已提交
3523 3524
}

3525
static always_inline void gen_setlr (DisasContext *ctx, target_ulong nip)
3526 3527
{
#if defined(TARGET_PPC64)
3528 3529
    if (ctx->sf_mode == 0)
        tcg_gen_movi_tl(cpu_lr, (uint32_t)nip);
3530 3531
    else
#endif
3532
        tcg_gen_movi_tl(cpu_lr, nip);
3533 3534
}

B
bellard 已提交
3535 3536 3537
/* b ba bl bla */
GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
{
3538
    target_ulong li, target;
B
bellard 已提交
3539

3540
    ctx->exception = POWERPC_EXCP_BRANCH;
B
bellard 已提交
3541
    /* sign extend LI */
3542
#if defined(TARGET_PPC64)
3543 3544 3545
    if (ctx->sf_mode)
        li = ((int64_t)LI(ctx->opcode) << 38) >> 38;
    else
3546
#endif
3547
        li = ((int32_t)LI(ctx->opcode) << 6) >> 6;
3548
    if (likely(AA(ctx->opcode) == 0))
B
bellard 已提交
3549
        target = ctx->nip + li - 4;
B
bellard 已提交
3550
    else
3551
        target = li;
3552 3553
    if (LK(ctx->opcode))
        gen_setlr(ctx, ctx->nip);
3554
    gen_goto_tb(ctx, 0, target);
B
bellard 已提交
3555 3556
}

3557 3558 3559 3560
#define BCOND_IM  0
#define BCOND_LR  1
#define BCOND_CTR 2

3561
static always_inline void gen_bcond (DisasContext *ctx, int type)
3562 3563
{
    uint32_t bo = BO(ctx->opcode);
3564 3565
    int l1 = gen_new_label();
    TCGv target;
3566

3567
    ctx->exception = POWERPC_EXCP_BRANCH;
3568
    if (type == BCOND_LR || type == BCOND_CTR) {
P
pbrook 已提交
3569
        target = tcg_temp_local_new();
3570 3571 3572 3573
        if (type == BCOND_CTR)
            tcg_gen_mov_tl(target, cpu_ctr);
        else
            tcg_gen_mov_tl(target, cpu_lr);
3574
    }
3575 3576
    if (LK(ctx->opcode))
        gen_setlr(ctx, ctx->nip);
3577 3578 3579
    l1 = gen_new_label();
    if ((bo & 0x4) == 0) {
        /* Decrement and test CTR */
P
pbrook 已提交
3580
        TCGv temp = tcg_temp_new();
3581
        if (unlikely(type == BCOND_CTR)) {
A
aurel32 已提交
3582
            gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
3583 3584 3585
            return;
        }
        tcg_gen_subi_tl(cpu_ctr, cpu_ctr, 1);
3586
#if defined(TARGET_PPC64)
3587 3588 3589
        if (!ctx->sf_mode)
            tcg_gen_ext32u_tl(temp, cpu_ctr);
        else
3590
#endif
3591 3592 3593 3594 3595
            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);
3596
        }
P
pbrook 已提交
3597
        tcg_temp_free(temp);
3598 3599 3600 3601 3602
    }
    if ((bo & 0x10) == 0) {
        /* Test CR */
        uint32_t bi = BI(ctx->opcode);
        uint32_t mask = 1 << (3 - (bi & 0x03));
P
pbrook 已提交
3603
        TCGv_i32 temp = tcg_temp_new_i32();
3604

3605
        if (bo & 0x8) {
3606 3607
            tcg_gen_andi_i32(temp, cpu_crf[bi >> 2], mask);
            tcg_gen_brcondi_i32(TCG_COND_EQ, temp, 0, l1);
3608
        } else {
3609 3610
            tcg_gen_andi_i32(temp, cpu_crf[bi >> 2], mask);
            tcg_gen_brcondi_i32(TCG_COND_NE, temp, 0, l1);
3611
        }
P
pbrook 已提交
3612
        tcg_temp_free_i32(temp);
3613
    }
3614
    if (type == BCOND_IM) {
3615 3616 3617 3618 3619 3620
        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 已提交
3621
        gen_set_label(l1);
3622
        gen_goto_tb(ctx, 1, ctx->nip);
3623
    } else {
3624
#if defined(TARGET_PPC64)
3625 3626 3627 3628 3629 3630 3631 3632 3633 3634
        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);
3635 3636
        else
#endif
3637
            tcg_gen_movi_tl(cpu_nip, ctx->nip);
B
bellard 已提交
3638
        tcg_gen_exit_tb(0);
J
j_mayer 已提交
3639
    }
3640 3641 3642
}

GEN_HANDLER(bc, 0x10, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
3643
{
3644 3645 3646 3647
    gen_bcond(ctx, BCOND_IM);
}

GEN_HANDLER(bcctr, 0x13, 0x10, 0x10, 0x00000000, PPC_FLOW)
3648
{
3649 3650 3651 3652
    gen_bcond(ctx, BCOND_CTR);
}

GEN_HANDLER(bclr, 0x13, 0x10, 0x00, 0x00000000, PPC_FLOW)
3653
{
3654 3655
    gen_bcond(ctx, BCOND_LR);
}
B
bellard 已提交
3656 3657

/***                      Condition register logical                       ***/
3658 3659
#define GEN_CRLOGIC(name, tcg_op, opc)                                        \
GEN_HANDLER(name, 0x13, 0x01, opc, 0x00000001, PPC_INTEGER)                   \
B
bellard 已提交
3660
{                                                                             \
3661 3662
    uint8_t bitmask;                                                          \
    int sh;                                                                   \
P
pbrook 已提交
3663
    TCGv_i32 t0, t1;                                                          \
3664
    sh = (crbD(ctx->opcode) & 0x03) - (crbA(ctx->opcode) & 0x03);             \
P
pbrook 已提交
3665
    t0 = tcg_temp_new_i32();                                                  \
3666
    if (sh > 0)                                                               \
3667
        tcg_gen_shri_i32(t0, cpu_crf[crbA(ctx->opcode) >> 2], sh);            \
3668
    else if (sh < 0)                                                          \
3669
        tcg_gen_shli_i32(t0, cpu_crf[crbA(ctx->opcode) >> 2], -sh);           \
3670
    else                                                                      \
3671
        tcg_gen_mov_i32(t0, cpu_crf[crbA(ctx->opcode) >> 2]);                 \
P
pbrook 已提交
3672
    t1 = tcg_temp_new_i32();                                                  \
3673 3674
    sh = (crbD(ctx->opcode) & 0x03) - (crbB(ctx->opcode) & 0x03);             \
    if (sh > 0)                                                               \
3675
        tcg_gen_shri_i32(t1, cpu_crf[crbB(ctx->opcode) >> 2], sh);            \
3676
    else if (sh < 0)                                                          \
3677
        tcg_gen_shli_i32(t1, cpu_crf[crbB(ctx->opcode) >> 2], -sh);           \
3678
    else                                                                      \
3679 3680
        tcg_gen_mov_i32(t1, cpu_crf[crbB(ctx->opcode) >> 2]);                 \
    tcg_op(t0, t0, t1);                                                       \
3681
    bitmask = 1 << (3 - (crbD(ctx->opcode) & 0x03));                          \
3682 3683 3684
    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 已提交
3685 3686
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
B
bellard 已提交
3687 3688 3689
}

/* crand */
3690
GEN_CRLOGIC(crand, tcg_gen_and_i32, 0x08);
B
bellard 已提交
3691
/* crandc */
3692
GEN_CRLOGIC(crandc, tcg_gen_andc_i32, 0x04);
B
bellard 已提交
3693
/* creqv */
3694
GEN_CRLOGIC(creqv, tcg_gen_eqv_i32, 0x09);
B
bellard 已提交
3695
/* crnand */
3696
GEN_CRLOGIC(crnand, tcg_gen_nand_i32, 0x07);
B
bellard 已提交
3697
/* crnor */
3698
GEN_CRLOGIC(crnor, tcg_gen_nor_i32, 0x01);
B
bellard 已提交
3699
/* cror */
3700
GEN_CRLOGIC(cror, tcg_gen_or_i32, 0x0E);
B
bellard 已提交
3701
/* crorc */
3702
GEN_CRLOGIC(crorc, tcg_gen_orc_i32, 0x0D);
B
bellard 已提交
3703
/* crxor */
3704
GEN_CRLOGIC(crxor, tcg_gen_xor_i32, 0x06);
B
bellard 已提交
3705 3706 3707
/* mcrf */
GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER)
{
A
aurel32 已提交
3708
    tcg_gen_mov_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfS(ctx->opcode)]);
B
bellard 已提交
3709 3710 3711
}

/***                           System linkage                              ***/
A
aurel32 已提交
3712
/* rfi (mem_idx only) */
3713
GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW)
B
bellard 已提交
3714
{
3715
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
3716
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
3717 3718
#else
    /* Restore CPU state */
A
aurel32 已提交
3719
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
3720
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
3721
        return;
3722
    }
3723
    gen_helper_rfi();
A
aurel32 已提交
3724
    gen_sync_exception(ctx);
3725
#endif
B
bellard 已提交
3726 3727
}

J
j_mayer 已提交
3728
#if defined(TARGET_PPC64)
3729
GEN_HANDLER(rfid, 0x13, 0x12, 0x00, 0x03FF8001, PPC_64B)
J
j_mayer 已提交
3730 3731
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
3732
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
J
j_mayer 已提交
3733 3734
#else
    /* Restore CPU state */
A
aurel32 已提交
3735
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
3736
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
J
j_mayer 已提交
3737 3738
        return;
    }
3739
    gen_helper_rfid();
A
aurel32 已提交
3740
    gen_sync_exception(ctx);
J
j_mayer 已提交
3741 3742 3743
#endif
}

J
j_mayer 已提交
3744
GEN_HANDLER(hrfid, 0x13, 0x12, 0x08, 0x03FF8001, PPC_64H)
3745 3746
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
3747
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
3748 3749
#else
    /* Restore CPU state */
A
aurel32 已提交
3750
    if (unlikely(ctx->mem_idx <= 1)) {
A
aurel32 已提交
3751
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
3752 3753
        return;
    }
3754
    gen_helper_hrfid();
A
aurel32 已提交
3755
    gen_sync_exception(ctx);
3756 3757 3758 3759
#endif
}
#endif

B
bellard 已提交
3760
/* sc */
3761 3762 3763 3764 3765
#if defined(CONFIG_USER_ONLY)
#define POWERPC_SYSCALL POWERPC_EXCP_SYSCALL_USER
#else
#define POWERPC_SYSCALL POWERPC_EXCP_SYSCALL
#endif
3766
GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFF01D, PPC_FLOW)
B
bellard 已提交
3767
{
3768 3769 3770
    uint32_t lev;

    lev = (ctx->opcode >> 5) & 0x7F;
A
aurel32 已提交
3771
    gen_exception_err(ctx, POWERPC_SYSCALL, lev);
B
bellard 已提交
3772 3773 3774 3775
}

/***                                Trap                                   ***/
/* tw */
3776
GEN_HANDLER(tw, 0x1F, 0x04, 0x00, 0x00000001, PPC_FLOW)
B
bellard 已提交
3777
{
3778
    TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
3779
    /* Update the nip since this might generate a trap exception */
3780
    gen_update_nip(ctx, ctx->nip);
3781 3782
    gen_helper_tw(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], t0);
    tcg_temp_free_i32(t0);
B
bellard 已提交
3783 3784 3785 3786 3787
}

/* twi */
GEN_HANDLER(twi, 0x03, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
{
3788 3789
    TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
    TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
3790 3791
    /* Update the nip since this might generate a trap exception */
    gen_update_nip(ctx, ctx->nip);
3792 3793 3794
    gen_helper_tw(cpu_gpr[rA(ctx->opcode)], t0, t1);
    tcg_temp_free(t0);
    tcg_temp_free_i32(t1);
B
bellard 已提交
3795 3796
}

3797 3798 3799 3800
#if defined(TARGET_PPC64)
/* td */
GEN_HANDLER(td, 0x1F, 0x04, 0x02, 0x00000001, PPC_64B)
{
3801
    TCGv_i32 t0 = 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
    gen_helper_td(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], t0);
    tcg_temp_free_i32(t0);
3806 3807 3808 3809 3810
}

/* tdi */
GEN_HANDLER(tdi, 0x02, 0xFF, 0xFF, 0x00000000, PPC_64B)
{
3811 3812
    TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
    TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
3813 3814
    /* Update the nip since this might generate a trap exception */
    gen_update_nip(ctx, ctx->nip);
3815 3816 3817
    gen_helper_td(cpu_gpr[rA(ctx->opcode)], t0, t1);
    tcg_temp_free(t0);
    tcg_temp_free_i32(t1);
3818 3819 3820
}
#endif

B
bellard 已提交
3821 3822 3823 3824
/***                          Processor control                            ***/
/* mcrxr */
GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC)
{
A
aurel32 已提交
3825 3826
    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);
3827
    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_SO | 1 << XER_OV | 1 << XER_CA));
B
bellard 已提交
3828 3829 3830
}

/* mfcr */
3831
GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x00000801, PPC_MISC)
B
bellard 已提交
3832
{
3833
    uint32_t crm, crn;
3834

3835 3836 3837 3838
    if (likely(ctx->opcode & 0x00100000)) {
        crm = CRM(ctx->opcode);
        if (likely((crm ^ (crm - 1)) == 0)) {
            crn = ffs(crm);
3839
            tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], cpu_crf[7 - crn]);
3840
        }
3841
    } else {
P
pbrook 已提交
3842
        gen_helper_load_cr(cpu_gpr[rD(ctx->opcode)]);
3843
    }
B
bellard 已提交
3844 3845 3846 3847 3848
}

/* mfmsr */
GEN_HANDLER(mfmsr, 0x1F, 0x13, 0x02, 0x001FF801, PPC_MISC)
{
3849
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
3850
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
3851
#else
A
aurel32 已提交
3852
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
3853
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
3854
        return;
3855
    }
3856
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_msr);
3857
#endif
B
bellard 已提交
3858 3859
}

J
j_mayer 已提交
3860
#if 1
3861
#define SPR_NOACCESS ((void *)(-1UL))
3862 3863 3864 3865 3866 3867 3868 3869 3870
#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 已提交
3871
/* mfspr */
3872
static always_inline void gen_op_mfspr (DisasContext *ctx)
B
bellard 已提交
3873
{
A
aurel32 已提交
3874
    void (*read_cb)(void *opaque, int gprn, int sprn);
B
bellard 已提交
3875 3876
    uint32_t sprn = SPR(ctx->opcode);

3877
#if !defined(CONFIG_USER_ONLY)
A
aurel32 已提交
3878
    if (ctx->mem_idx == 2)
3879
        read_cb = ctx->spr_cb[sprn].hea_read;
A
aurel32 已提交
3880
    else if (ctx->mem_idx)
3881 3882
        read_cb = ctx->spr_cb[sprn].oea_read;
    else
3883
#endif
3884
        read_cb = ctx->spr_cb[sprn].uea_read;
3885 3886
    if (likely(read_cb != NULL)) {
        if (likely(read_cb != SPR_NOACCESS)) {
A
aurel32 已提交
3887
            (*read_cb)(ctx, rD(ctx->opcode), sprn);
3888 3889
        } else {
            /* Privilege exception */
3890 3891 3892 3893 3894 3895
            /* 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) {
3896
                    fprintf(logfile, "Trying to read privileged spr %d %03x at "
J
j_mayer 已提交
3897
                            ADDRX "\n", sprn, sprn, ctx->nip);
3898
                }
J
j_mayer 已提交
3899 3900
                printf("Trying to read privileged spr %d %03x at " ADDRX "\n",
                       sprn, sprn, ctx->nip);
3901
            }
A
aurel32 已提交
3902
            gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
B
bellard 已提交
3903
        }
3904 3905
    } else {
        /* Not defined */
J
j_mayer 已提交
3906
        if (loglevel != 0) {
J
j_mayer 已提交
3907 3908
            fprintf(logfile, "Trying to read invalid spr %d %03x at "
                    ADDRX "\n", sprn, sprn, ctx->nip);
3909
        }
J
j_mayer 已提交
3910 3911
        printf("Trying to read invalid spr %d %03x at " ADDRX "\n",
               sprn, sprn, ctx->nip);
A
aurel32 已提交
3912
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_SPR);
B
bellard 已提交
3913 3914 3915
    }
}

3916
GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC)
B
bellard 已提交
3917
{
3918
    gen_op_mfspr(ctx);
3919
}
3920 3921

/* mftb */
3922
GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_MFTB)
3923 3924
{
    gen_op_mfspr(ctx);
B
bellard 已提交
3925 3926 3927
}

/* mtcrf */
3928
GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00000801, PPC_MISC)
B
bellard 已提交
3929
{
3930
    uint32_t crm, crn;
3931

3932 3933
    crm = CRM(ctx->opcode);
    if (likely((ctx->opcode & 0x00100000) || (crm ^ (crm - 1)) == 0)) {
P
pbrook 已提交
3934
        TCGv_i32 temp = tcg_temp_new_i32();
3935
        crn = ffs(crm);
P
pbrook 已提交
3936 3937
        tcg_gen_trunc_tl_i32(temp, cpu_gpr[rS(ctx->opcode)]);
        tcg_gen_shri_i32(cpu_crf[7 - crn], temp, crn * 4);
3938
        tcg_gen_andi_i32(cpu_crf[7 - crn], cpu_crf[7 - crn], 0xf);
P
pbrook 已提交
3939
        tcg_temp_free_i32(temp);
3940
    } else {
P
pbrook 已提交
3941 3942 3943
        TCGv_i32 temp = tcg_const_i32(crm);
        gen_helper_store_cr(cpu_gpr[rS(ctx->opcode)], temp);
        tcg_temp_free_i32(temp);
3944
    }
B
bellard 已提交
3945 3946 3947
}

/* mtmsr */
J
j_mayer 已提交
3948
#if defined(TARGET_PPC64)
3949
GEN_HANDLER(mtmsrd, 0x1F, 0x12, 0x05, 0x001EF801, PPC_64B)
J
j_mayer 已提交
3950 3951
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
3952
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
J
j_mayer 已提交
3953
#else
A
aurel32 已提交
3954
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
3955
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
J
j_mayer 已提交
3956 3957
        return;
    }
3958 3959
    if (ctx->opcode & 0x00010000) {
        /* Special form that does not need any synchronisation */
3960 3961 3962 3963 3964
        TCGv t0 = tcg_temp_new();
        tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)], (1 << MSR_RI) | (1 << MSR_EE));
        tcg_gen_andi_tl(cpu_msr, cpu_msr, ~((1 << MSR_RI) | (1 << MSR_EE)));
        tcg_gen_or_tl(cpu_msr, cpu_msr, t0);
        tcg_temp_free(t0);
3965
    } else {
3966 3967 3968 3969
        /* 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
         */
3970
        gen_update_nip(ctx, ctx->nip);
3971
        gen_helper_store_msr(cpu_gpr[rS(ctx->opcode)]);
3972 3973
        /* Must stop the translation as machine state (may have) changed */
        /* Note that mtmsr is not always defined as context-synchronizing */
A
aurel32 已提交
3974
        gen_stop_exception(ctx);
3975
    }
J
j_mayer 已提交
3976 3977 3978 3979
#endif
}
#endif

B
bellard 已提交
3980 3981
GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC)
{
3982
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
3983
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
3984
#else
A
aurel32 已提交
3985
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
3986
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
3987
        return;
3988
    }
3989 3990
    if (ctx->opcode & 0x00010000) {
        /* Special form that does not need any synchronisation */
3991 3992 3993 3994 3995
        TCGv t0 = tcg_temp_new();
        tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)], (1 << MSR_RI) | (1 << MSR_EE));
        tcg_gen_andi_tl(cpu_msr, cpu_msr, ~((1 << MSR_RI) | (1 << MSR_EE)));
        tcg_gen_or_tl(cpu_msr, cpu_msr, t0);
        tcg_temp_free(t0);
3996
    } else {
3997 3998 3999 4000
        /* 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
         */
4001
        gen_update_nip(ctx, ctx->nip);
4002
#if defined(TARGET_PPC64)
4003 4004 4005 4006 4007 4008 4009 4010 4011 4012
        if (!ctx->sf_mode) {
            TCGv t0 = tcg_temp_new();
            TCGv t1 = tcg_temp_new();
            tcg_gen_andi_tl(t0, cpu_msr, 0xFFFFFFFF00000000ULL);
            tcg_gen_ext32u_tl(t1, cpu_gpr[rS(ctx->opcode)]);
            tcg_gen_or_tl(t0, t0, t1);
            tcg_temp_free(t1);
            gen_helper_store_msr(t0);
            tcg_temp_free(t0);
        } else
4013
#endif
4014
            gen_helper_store_msr(cpu_gpr[rS(ctx->opcode)]);
4015
        /* Must stop the translation as machine state (may have) changed */
4016
        /* Note that mtmsr is not always defined as context-synchronizing */
A
aurel32 已提交
4017
        gen_stop_exception(ctx);
4018
    }
4019
#endif
B
bellard 已提交
4020 4021 4022 4023 4024
}

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

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

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

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

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

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

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

/* dcbz */
4128
GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE_DCBZ)
B
bellard 已提交
4129
{
A
aurel32 已提交
4130 4131
    TCGv t0;
    gen_set_access_type(ctx, ACCESS_CACHE);
4132 4133
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
A
aurel32 已提交
4134 4135
    t0 = tcg_temp_new();
    gen_addr_reg_index(ctx, t0);
4136 4137
    gen_helper_dcbz(t0);
    tcg_temp_free(t0);
4138 4139
}

4140
GEN_HANDLER2(dcbz_970, "dcbz", 0x1F, 0x16, 0x1F, 0x03C00001, PPC_CACHE_DCBZT)
4141
{
A
aurel32 已提交
4142 4143
    TCGv t0;
    gen_set_access_type(ctx, ACCESS_CACHE);
4144 4145
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
A
aurel32 已提交
4146 4147
    t0 = tcg_temp_new();
    gen_addr_reg_index(ctx, t0);
4148
    if (ctx->opcode & 0x00200000)
4149
        gen_helper_dcbz(t0);
4150
    else
4151 4152
        gen_helper_dcbz_970(t0);
    tcg_temp_free(t0);
B
bellard 已提交
4153 4154 4155
}

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

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

/***                    Segment register manipulation                      ***/
/* Supervisor only: */
/* mfsr */
GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT)
{
4183
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
4184
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
4185
#else
4186
    TCGv t0;
A
aurel32 已提交
4187
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
4188
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
4189
        return;
4190
    }
4191 4192 4193
    t0 = tcg_const_tl(SR(ctx->opcode));
    gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], t0);
    tcg_temp_free(t0);
4194
#endif
B
bellard 已提交
4195 4196 4197
}

/* mfsrin */
4198
GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT)
B
bellard 已提交
4199
{
4200
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
4201
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
4202
#else
4203
    TCGv t0;
A
aurel32 已提交
4204
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
4205
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
4206
        return;
4207
    }
4208 4209 4210 4211 4212
    t0 = tcg_temp_new();
    tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 28);
    tcg_gen_andi_tl(t0, t0, 0xF);
    gen_helper_load_sr(cpu_gpr[rD(ctx->opcode)], t0);
    tcg_temp_free(t0);
4213
#endif
B
bellard 已提交
4214 4215 4216
}

/* mtsr */
B
bellard 已提交
4217
GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT)
B
bellard 已提交
4218
{
4219
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
4220
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
4221
#else
4222
    TCGv t0;
A
aurel32 已提交
4223
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
4224
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
4225
        return;
4226
    }
4227 4228 4229
    t0 = tcg_const_tl(SR(ctx->opcode));
    gen_helper_store_sr(t0, cpu_gpr[rS(ctx->opcode)]);
    tcg_temp_free(t0);
4230
#endif
B
bellard 已提交
4231 4232 4233
}

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

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

/* mfsrin */
4272 4273
GEN_HANDLER2(mfsrin_64b, "mfsrin", 0x1F, 0x13, 0x14, 0x001F0001,
             PPC_SEGMENT_64B)
4274 4275
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
4276
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
4277
#else
4278
    TCGv t0;
A
aurel32 已提交
4279
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
4280
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
4281 4282
        return;
    }
4283 4284 4285 4286 4287
    t0 = tcg_temp_new();
    tcg_gen_shri_tl(t0, cpu_gpr[rB(ctx->opcode)], 28);
    tcg_gen_andi_tl(t0, t0, 0xF);
    gen_helper_load_slb(cpu_gpr[rD(ctx->opcode)], t0);
    tcg_temp_free(t0);
4288 4289 4290 4291
#endif
}

/* mtsr */
4292
GEN_HANDLER2(mtsr_64b, "mtsr", 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT_64B)
4293 4294
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
4295
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
4296
#else
4297
    TCGv t0;
A
aurel32 已提交
4298
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
4299
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
4300 4301
        return;
    }
4302 4303 4304
    t0 = tcg_const_tl(SR(ctx->opcode));
    gen_helper_store_slb(t0, cpu_gpr[rS(ctx->opcode)]);
    tcg_temp_free(t0);
4305 4306 4307 4308
#endif
}

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

B
bellard 已提交
4329
/***                      Lookaside buffer management                      ***/
A
aurel32 已提交
4330
/* Optional & mem_idx only: */
B
bellard 已提交
4331
/* tlbia */
4332
GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA)
B
bellard 已提交
4333
{
4334
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
4335
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
4336
#else
A
aurel32 已提交
4337
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
4338
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
4339
        return;
4340
    }
4341
    gen_helper_tlbia();
4342
#endif
B
bellard 已提交
4343 4344 4345
}

/* tlbie */
4346
GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM_TLBIE)
B
bellard 已提交
4347
{
4348
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
4349
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
4350
#else
A
aurel32 已提交
4351
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
4352
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
4353
        return;
4354
    }
4355
#if defined(TARGET_PPC64)
4356 4357 4358 4359 4360 4361
    if (!ctx->sf_mode) {
        TCGv t0 = tcg_temp_new();
        tcg_gen_ext32u_tl(t0, cpu_gpr[rB(ctx->opcode)]);
        gen_helper_tlbie(t0);
        tcg_temp_free(t0);
    } else
4362
#endif
4363
        gen_helper_tlbie(cpu_gpr[rB(ctx->opcode)]);
4364
#endif
B
bellard 已提交
4365 4366 4367
}

/* tlbsync */
4368
GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM_TLBSYNC)
B
bellard 已提交
4369
{
4370
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
4371
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
4372
#else
A
aurel32 已提交
4373
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
4374
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
4375
        return;
4376 4377 4378 4379
    }
    /* This has no effect: it should ensure that all previous
     * tlbie have completed
     */
A
aurel32 已提交
4380
    gen_stop_exception(ctx);
4381
#endif
B
bellard 已提交
4382 4383
}

J
j_mayer 已提交
4384 4385 4386 4387 4388
#if defined(TARGET_PPC64)
/* slbia */
GEN_HANDLER(slbia, 0x1F, 0x12, 0x0F, 0x03FFFC01, PPC_SLBI)
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
4389
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
J
j_mayer 已提交
4390
#else
A
aurel32 已提交
4391
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
4392
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
J
j_mayer 已提交
4393 4394
        return;
    }
4395
    gen_helper_slbia();
J
j_mayer 已提交
4396 4397 4398 4399 4400 4401 4402
#endif
}

/* slbie */
GEN_HANDLER(slbie, 0x1F, 0x12, 0x0D, 0x03FF0001, PPC_SLBI)
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
4403
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
J
j_mayer 已提交
4404
#else
A
aurel32 已提交
4405
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
4406
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
J
j_mayer 已提交
4407 4408
        return;
    }
4409
    gen_helper_slbie(cpu_gpr[rB(ctx->opcode)]);
J
j_mayer 已提交
4410 4411 4412 4413
#endif
}
#endif

B
bellard 已提交
4414 4415
/***                              External control                         ***/
/* Optional: */
4416
/* eciwx */
B
bellard 已提交
4417 4418
GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN)
{
A
aurel32 已提交
4419
    TCGv t0;
4420
    /* Should check EAR[E] ! */
A
aurel32 已提交
4421 4422 4423
    gen_set_access_type(ctx, ACCESS_EXT);
    t0 = tcg_temp_new();
    gen_addr_reg_index(ctx, t0);
4424
    gen_check_align(ctx, t0, 0x03);
A
aurel32 已提交
4425
    gen_qemu_ld32u(ctx, cpu_gpr[rD(ctx->opcode)], t0);
4426
    tcg_temp_free(t0);
4427 4428 4429 4430 4431
}

/* ecowx */
GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN)
{
A
aurel32 已提交
4432
    TCGv t0;
4433
    /* Should check EAR[E] ! */
A
aurel32 已提交
4434 4435 4436
    gen_set_access_type(ctx, ACCESS_EXT);
    t0 = tcg_temp_new();
    gen_addr_reg_index(ctx, t0);
4437
    gen_check_align(ctx, t0, 0x03);
A
aurel32 已提交
4438
    gen_qemu_st32(ctx, cpu_gpr[rD(ctx->opcode)], t0);
4439
    tcg_temp_free(t0);
4440 4441 4442 4443 4444 4445
}

/* PowerPC 601 specific instructions */
/* abs - abs. */
GEN_HANDLER(abs, 0x1F, 0x08, 0x0B, 0x0000F800, PPC_POWER_BR)
{
4446 4447 4448 4449 4450 4451 4452 4453
    int l1 = gen_new_label();
    int l2 = gen_new_label();
    tcg_gen_brcondi_tl(TCG_COND_GE, cpu_gpr[rA(ctx->opcode)], 0, l1);
    tcg_gen_neg_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_br(l2);
    gen_set_label(l1);
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
    gen_set_label(l2);
4454
    if (unlikely(Rc(ctx->opcode) != 0))
4455
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4456 4457 4458 4459 4460
}

/* abso - abso. */
GEN_HANDLER(abso, 0x1F, 0x08, 0x1B, 0x0000F800, PPC_POWER_BR)
{
4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475
    int l1 = gen_new_label();
    int l2 = gen_new_label();
    int l3 = gen_new_label();
    /* Start with XER OV disabled, the most likely case */
    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
    tcg_gen_brcondi_tl(TCG_COND_GE, cpu_gpr[rA(ctx->opcode)], 0, l2);
    tcg_gen_brcondi_tl(TCG_COND_NE, cpu_gpr[rA(ctx->opcode)], 0x80000000, l1);
    tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
    tcg_gen_br(l2);
    gen_set_label(l1);
    tcg_gen_neg_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_br(l3);
    gen_set_label(l2);
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
    gen_set_label(l3);
4476
    if (unlikely(Rc(ctx->opcode) != 0))
4477
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4478 4479 4480
}

/* clcs */
4481
GEN_HANDLER(clcs, 0x1F, 0x10, 0x13, 0x0000F800, PPC_POWER_BR)
4482
{
4483 4484 4485
    TCGv_i32 t0 = tcg_const_i32(rA(ctx->opcode));
    gen_helper_clcs(cpu_gpr[rD(ctx->opcode)], t0);
    tcg_temp_free_i32(t0);
4486
    /* Rc=1 sets CR0 to an undefined state */
4487 4488 4489 4490 4491
}

/* div - div. */
GEN_HANDLER(div, 0x1F, 0x0B, 0x0A, 0x00000000, PPC_POWER_BR)
{
4492
    gen_helper_div(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
4493
    if (unlikely(Rc(ctx->opcode) != 0))
4494
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4495 4496 4497 4498 4499
}

/* divo - divo. */
GEN_HANDLER(divo, 0x1F, 0x0B, 0x1A, 0x00000000, PPC_POWER_BR)
{
4500
    gen_helper_divo(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
4501
    if (unlikely(Rc(ctx->opcode) != 0))
4502
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4503 4504 4505 4506 4507
}

/* divs - divs. */
GEN_HANDLER(divs, 0x1F, 0x0B, 0x0B, 0x00000000, PPC_POWER_BR)
{
4508
    gen_helper_divs(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
4509
    if (unlikely(Rc(ctx->opcode) != 0))
4510
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4511 4512 4513 4514 4515
}

/* divso - divso. */
GEN_HANDLER(divso, 0x1F, 0x0B, 0x1B, 0x00000000, PPC_POWER_BR)
{
4516
    gen_helper_divso(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
4517
    if (unlikely(Rc(ctx->opcode) != 0))
4518
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4519 4520 4521 4522 4523
}

/* doz - doz. */
GEN_HANDLER(doz, 0x1F, 0x08, 0x08, 0x00000000, PPC_POWER_BR)
{
4524 4525 4526 4527 4528 4529 4530 4531
    int l1 = gen_new_label();
    int l2 = gen_new_label();
    tcg_gen_brcond_tl(TCG_COND_GE, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], l1);
    tcg_gen_sub_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_br(l2);
    gen_set_label(l1);
    tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], 0);
    gen_set_label(l2);
4532
    if (unlikely(Rc(ctx->opcode) != 0))
4533
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4534 4535 4536 4537 4538
}

/* dozo - dozo. */
GEN_HANDLER(dozo, 0x1F, 0x08, 0x18, 0x00000000, PPC_POWER_BR)
{
4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560
    int l1 = gen_new_label();
    int l2 = gen_new_label();
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    TCGv t2 = tcg_temp_new();
    /* Start with XER OV disabled, the most likely case */
    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
    tcg_gen_brcond_tl(TCG_COND_GE, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], l1);
    tcg_gen_sub_tl(t0, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_xor_tl(t1, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_xor_tl(t2, cpu_gpr[rA(ctx->opcode)], t0);
    tcg_gen_andc_tl(t1, t1, t2);
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0);
    tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l2);
    tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
    tcg_gen_br(l2);
    gen_set_label(l1);
    tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], 0);
    gen_set_label(l2);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
    tcg_temp_free(t2);
4561
    if (unlikely(Rc(ctx->opcode) != 0))
4562
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4563 4564 4565 4566 4567
}

/* dozi */
GEN_HANDLER(dozi, 0x09, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR)
{
4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578
    target_long simm = SIMM(ctx->opcode);
    int l1 = gen_new_label();
    int l2 = gen_new_label();
    tcg_gen_brcondi_tl(TCG_COND_LT, cpu_gpr[rA(ctx->opcode)], simm, l1);
    tcg_gen_subfi_tl(cpu_gpr[rD(ctx->opcode)], simm, cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_br(l2);
    gen_set_label(l1);
    tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], 0);
    gen_set_label(l2);
    if (unlikely(Rc(ctx->opcode) != 0))
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4579 4580 4581 4582 4583
}

/* lscbx - lscbx. */
GEN_HANDLER(lscbx, 0x1F, 0x15, 0x08, 0x00000000, PPC_POWER_BR)
{
4584 4585 4586 4587
    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));
4588

A
aurel32 已提交
4589
    gen_addr_reg_index(ctx, t0);
4590
    /* NIP cannot be restored if the memory exception comes from an helper */
4591
    gen_update_nip(ctx, ctx->nip - 4);
4592 4593 4594 4595
    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 已提交
4596
    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~0x7F);
4597
    tcg_gen_or_tl(cpu_xer, cpu_xer, t0);
4598
    if (unlikely(Rc(ctx->opcode) != 0))
4599 4600
        gen_set_Rc0(ctx, t0);
    tcg_temp_free(t0);
4601 4602 4603 4604 4605
}

/* maskg - maskg. */
GEN_HANDLER(maskg, 0x1F, 0x1D, 0x00, 0x00000000, PPC_POWER_BR)
{
4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624
    int l1 = gen_new_label();
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    TCGv t2 = tcg_temp_new();
    TCGv t3 = tcg_temp_new();
    tcg_gen_movi_tl(t3, 0xFFFFFFFF);
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1F);
    tcg_gen_andi_tl(t1, cpu_gpr[rS(ctx->opcode)], 0x1F);
    tcg_gen_addi_tl(t2, t0, 1);
    tcg_gen_shr_tl(t2, t3, t2);
    tcg_gen_shr_tl(t3, t3, t1);
    tcg_gen_xor_tl(cpu_gpr[rA(ctx->opcode)], t2, t3);
    tcg_gen_brcond_tl(TCG_COND_GE, t0, t1, l1);
    tcg_gen_neg_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
    gen_set_label(l1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
    tcg_temp_free(t2);
    tcg_temp_free(t3);
4625
    if (unlikely(Rc(ctx->opcode) != 0))
4626
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4627 4628 4629 4630 4631
}

/* maskir - maskir. */
GEN_HANDLER(maskir, 0x1F, 0x1D, 0x10, 0x00000000, PPC_POWER_BR)
{
4632 4633 4634 4635 4636 4637 4638
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    tcg_gen_and_tl(t0, cpu_gpr[rS(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
    tcg_gen_andc_tl(t1, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
    tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
4639
    if (unlikely(Rc(ctx->opcode) != 0))
4640
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4641 4642 4643 4644 4645
}

/* mul - mul. */
GEN_HANDLER(mul, 0x1F, 0x0B, 0x03, 0x00000000, PPC_POWER_BR)
{
4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658
    TCGv_i64 t0 = tcg_temp_new_i64();
    TCGv_i64 t1 = tcg_temp_new_i64();
    TCGv t2 = tcg_temp_new();
    tcg_gen_extu_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_extu_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]);
    tcg_gen_mul_i64(t0, t0, t1);
    tcg_gen_trunc_i64_tl(t2, t0);
    gen_store_spr(SPR_MQ, t2);
    tcg_gen_shri_i64(t1, t0, 32);
    tcg_gen_trunc_i64_tl(cpu_gpr[rD(ctx->opcode)], t1);
    tcg_temp_free_i64(t0);
    tcg_temp_free_i64(t1);
    tcg_temp_free(t2);
4659
    if (unlikely(Rc(ctx->opcode) != 0))
4660
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4661 4662 4663 4664 4665
}

/* mulo - mulo. */
GEN_HANDLER(mulo, 0x1F, 0x0B, 0x13, 0x00000000, PPC_POWER_BR)
{
4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685
    int l1 = gen_new_label();
    TCGv_i64 t0 = tcg_temp_new_i64();
    TCGv_i64 t1 = tcg_temp_new_i64();
    TCGv t2 = tcg_temp_new();
    /* Start with XER OV disabled, the most likely case */
    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
    tcg_gen_extu_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_extu_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]);
    tcg_gen_mul_i64(t0, t0, t1);
    tcg_gen_trunc_i64_tl(t2, t0);
    gen_store_spr(SPR_MQ, t2);
    tcg_gen_shri_i64(t1, t0, 32);
    tcg_gen_trunc_i64_tl(cpu_gpr[rD(ctx->opcode)], t1);
    tcg_gen_ext32s_i64(t1, t0);
    tcg_gen_brcond_i64(TCG_COND_EQ, t0, t1, l1);
    tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_OV) | (1 << XER_SO));
    gen_set_label(l1);
    tcg_temp_free_i64(t0);
    tcg_temp_free_i64(t1);
    tcg_temp_free(t2);
4686
    if (unlikely(Rc(ctx->opcode) != 0))
4687
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4688 4689 4690 4691 4692
}

/* nabs - nabs. */
GEN_HANDLER(nabs, 0x1F, 0x08, 0x0F, 0x00000000, PPC_POWER_BR)
{
4693 4694 4695 4696 4697 4698 4699 4700
    int l1 = gen_new_label();
    int l2 = gen_new_label();
    tcg_gen_brcondi_tl(TCG_COND_GT, cpu_gpr[rA(ctx->opcode)], 0, l1);
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_br(l2);
    gen_set_label(l1);
    tcg_gen_neg_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
    gen_set_label(l2);
4701
    if (unlikely(Rc(ctx->opcode) != 0))
4702
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4703 4704 4705 4706 4707
}

/* nabso - nabso. */
GEN_HANDLER(nabso, 0x1F, 0x08, 0x1F, 0x00000000, PPC_POWER_BR)
{
4708 4709 4710 4711 4712 4713 4714 4715 4716 4717
    int l1 = gen_new_label();
    int l2 = gen_new_label();
    tcg_gen_brcondi_tl(TCG_COND_GT, cpu_gpr[rA(ctx->opcode)], 0, l1);
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_br(l2);
    gen_set_label(l1);
    tcg_gen_neg_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
    gen_set_label(l2);
    /* nabs never overflows */
    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_OV));
4718
    if (unlikely(Rc(ctx->opcode) != 0))
4719
        gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
4720 4721 4722 4723 4724
}

/* rlmi - rlmi. */
GEN_HANDLER(rlmi, 0x16, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR)
{
4725 4726 4727 4728 4729 4730 4731 4732 4733
    uint32_t mb = MB(ctx->opcode);
    uint32_t me = ME(ctx->opcode);
    TCGv t0 = tcg_temp_new();
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1F);
    tcg_gen_rotl_tl(t0, cpu_gpr[rS(ctx->opcode)], t0);
    tcg_gen_andi_tl(t0, t0, MASK(mb, me));
    tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~MASK(mb, me));
    tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], t0);
    tcg_temp_free(t0);
4734
    if (unlikely(Rc(ctx->opcode) != 0))
4735
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4736 4737 4738 4739 4740
}

/* rrib - rrib. */
GEN_HANDLER(rrib, 0x1F, 0x19, 0x10, 0x00000000, PPC_POWER_BR)
{
4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1F);
    tcg_gen_movi_tl(t1, 0x80000000);
    tcg_gen_shr_tl(t1, t1, t0);
    tcg_gen_shr_tl(t0, cpu_gpr[rS(ctx->opcode)], t0);
    tcg_gen_and_tl(t0, t0, t1);
    tcg_gen_andc_tl(t1, cpu_gpr[rA(ctx->opcode)], t1);
    tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
4752
    if (unlikely(Rc(ctx->opcode) != 0))
4753
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4754 4755 4756 4757 4758
}

/* sle - sle. */
GEN_HANDLER(sle, 0x1F, 0x19, 0x04, 0x00000000, PPC_POWER_BR)
{
4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x1F);
    tcg_gen_shl_tl(t0, cpu_gpr[rS(ctx->opcode)], t1);
    tcg_gen_subfi_tl(t1, 32, t1);
    tcg_gen_shr_tl(t1, cpu_gpr[rS(ctx->opcode)], t1);
    tcg_gen_or_tl(t1, t0, t1);
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
    gen_store_spr(SPR_MQ, t1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
4770
    if (unlikely(Rc(ctx->opcode) != 0))
4771
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4772 4773 4774 4775 4776
}

/* sleq - sleq. */
GEN_HANDLER(sleq, 0x1F, 0x19, 0x06, 0x00000000, PPC_POWER_BR)
{
4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    TCGv t2 = tcg_temp_new();
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1F);
    tcg_gen_movi_tl(t2, 0xFFFFFFFF);
    tcg_gen_shl_tl(t2, t2, t0);
    tcg_gen_rotl_tl(t0, cpu_gpr[rS(ctx->opcode)], t0);
    gen_load_spr(t1, SPR_MQ);
    gen_store_spr(SPR_MQ, t0);
    tcg_gen_and_tl(t0, t0, t2);
    tcg_gen_andc_tl(t1, t1, t2);
    tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
    tcg_temp_free(t2);
4792
    if (unlikely(Rc(ctx->opcode) != 0))
4793
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4794 4795 4796 4797 4798
}

/* sliq - sliq. */
GEN_HANDLER(sliq, 0x1F, 0x18, 0x05, 0x00000000, PPC_POWER_BR)
{
4799 4800 4801 4802 4803 4804 4805 4806 4807 4808
    int sh = SH(ctx->opcode);
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    tcg_gen_shli_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
    tcg_gen_shri_tl(t1, cpu_gpr[rS(ctx->opcode)], 32 - sh);
    tcg_gen_or_tl(t1, t0, t1);
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
    gen_store_spr(SPR_MQ, t1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
4809
    if (unlikely(Rc(ctx->opcode) != 0))
4810
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4811 4812 4813 4814 4815
}

/* slliq - slliq. */
GEN_HANDLER(slliq, 0x1F, 0x18, 0x07, 0x00000000, PPC_POWER_BR)
{
4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826
    int sh = SH(ctx->opcode);
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    tcg_gen_rotli_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
    gen_load_spr(t1, SPR_MQ);
    gen_store_spr(SPR_MQ, t0);
    tcg_gen_andi_tl(t0, t0,  (0xFFFFFFFFU << sh));
    tcg_gen_andi_tl(t1, t1, ~(0xFFFFFFFFU << sh));
    tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
4827
    if (unlikely(Rc(ctx->opcode) != 0))
4828
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4829 4830 4831 4832 4833
}

/* sllq - sllq. */
GEN_HANDLER(sllq, 0x1F, 0x18, 0x06, 0x00000000, PPC_POWER_BR)
{
4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855
    int l1 = gen_new_label();
    int l2 = gen_new_label();
    TCGv t0 = tcg_temp_local_new();
    TCGv t1 = tcg_temp_local_new();
    TCGv t2 = tcg_temp_local_new();
    tcg_gen_andi_tl(t2, cpu_gpr[rB(ctx->opcode)], 0x1F);
    tcg_gen_movi_tl(t1, 0xFFFFFFFF);
    tcg_gen_shl_tl(t1, t1, t2);
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x20);
    tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
    gen_load_spr(t0, SPR_MQ);
    tcg_gen_and_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
    tcg_gen_br(l2);
    gen_set_label(l1);
    tcg_gen_shl_tl(t0, cpu_gpr[rS(ctx->opcode)], t2);
    gen_load_spr(t2, SPR_MQ);
    tcg_gen_andc_tl(t1, t2, t1);
    tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
    gen_set_label(l2);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
    tcg_temp_free(t2);
4856
    if (unlikely(Rc(ctx->opcode) != 0))
4857
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4858 4859 4860 4861 4862
}

/* slq - slq. */
GEN_HANDLER(slq, 0x1F, 0x18, 0x04, 0x00000000, PPC_POWER_BR)
{
4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878
    int l1 = gen_new_label();
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x1F);
    tcg_gen_shl_tl(t0, cpu_gpr[rS(ctx->opcode)], t1);
    tcg_gen_subfi_tl(t1, 32, t1);
    tcg_gen_shr_tl(t1, cpu_gpr[rS(ctx->opcode)], t1);
    tcg_gen_or_tl(t1, t0, t1);
    gen_store_spr(SPR_MQ, t1);
    tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x20);
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
    tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1);
    tcg_gen_movi_tl(cpu_gpr[rA(ctx->opcode)], 0);
    gen_set_label(l1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
4879
    if (unlikely(Rc(ctx->opcode) != 0))
4880
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4881 4882
}

4883
/* sraiq - sraiq. */
4884 4885
GEN_HANDLER(sraiq, 0x1F, 0x18, 0x1D, 0x00000000, PPC_POWER_BR)
{
4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901
    int sh = SH(ctx->opcode);
    int l1 = gen_new_label();
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
    tcg_gen_shli_tl(t1, cpu_gpr[rS(ctx->opcode)], 32 - sh);
    tcg_gen_or_tl(t0, t0, t1);
    gen_store_spr(SPR_MQ, t0);
    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
    tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1);
    tcg_gen_brcondi_tl(TCG_COND_GE, cpu_gpr[rS(ctx->opcode)], 0, l1);
    tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_CA));
    gen_set_label(l1);
    tcg_gen_sari_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], sh);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
4902
    if (unlikely(Rc(ctx->opcode) != 0))
4903
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4904 4905 4906 4907 4908
}

/* sraq - sraq. */
GEN_HANDLER(sraq, 0x1F, 0x18, 0x1C, 0x00000000, PPC_POWER_BR)
{
4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934
    int l1 = gen_new_label();
    int l2 = gen_new_label();
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_local_new();
    TCGv t2 = tcg_temp_local_new();
    tcg_gen_andi_tl(t2, cpu_gpr[rB(ctx->opcode)], 0x1F);
    tcg_gen_shr_tl(t0, cpu_gpr[rS(ctx->opcode)], t2);
    tcg_gen_sar_tl(t1, cpu_gpr[rS(ctx->opcode)], t2);
    tcg_gen_subfi_tl(t2, 32, t2);
    tcg_gen_shl_tl(t2, cpu_gpr[rS(ctx->opcode)], t2);
    tcg_gen_or_tl(t0, t0, t2);
    gen_store_spr(SPR_MQ, t0);
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x20);
    tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, l1);
    tcg_gen_mov_tl(t2, cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_sari_tl(t1, cpu_gpr[rS(ctx->opcode)], 31);
    gen_set_label(l1);
    tcg_temp_free(t0);
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t1);
    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
    tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l2);
    tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, l2);
    tcg_gen_ori_tl(cpu_xer, cpu_xer, (1 << XER_CA));
    gen_set_label(l2);
    tcg_temp_free(t1);
    tcg_temp_free(t2);
4935
    if (unlikely(Rc(ctx->opcode) != 0))
4936
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4937 4938 4939 4940 4941
}

/* sre - sre. */
GEN_HANDLER(sre, 0x1F, 0x19, 0x14, 0x00000000, PPC_POWER_BR)
{
4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x1F);
    tcg_gen_shr_tl(t0, cpu_gpr[rS(ctx->opcode)], t1);
    tcg_gen_subfi_tl(t1, 32, t1);
    tcg_gen_shl_tl(t1, cpu_gpr[rS(ctx->opcode)], t1);
    tcg_gen_or_tl(t1, t0, t1);
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
    gen_store_spr(SPR_MQ, t1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
4953
    if (unlikely(Rc(ctx->opcode) != 0))
4954
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4955 4956 4957 4958 4959
}

/* srea - srea. */
GEN_HANDLER(srea, 0x1F, 0x19, 0x1C, 0x00000000, PPC_POWER_BR)
{
4960 4961 4962 4963 4964 4965 4966 4967
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x1F);
    tcg_gen_rotr_tl(t0, cpu_gpr[rS(ctx->opcode)], t1);
    gen_store_spr(SPR_MQ, t0);
    tcg_gen_sar_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], t1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
4968
    if (unlikely(Rc(ctx->opcode) != 0))
4969
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4970 4971 4972 4973 4974
}

/* sreq */
GEN_HANDLER(sreq, 0x1F, 0x19, 0x16, 0x00000000, PPC_POWER_BR)
{
4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    TCGv t2 = tcg_temp_new();
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1F);
    tcg_gen_movi_tl(t1, 0xFFFFFFFF);
    tcg_gen_shr_tl(t1, t1, t0);
    tcg_gen_rotr_tl(t0, cpu_gpr[rS(ctx->opcode)], t0);
    gen_load_spr(t2, SPR_MQ);
    gen_store_spr(SPR_MQ, t0);
    tcg_gen_and_tl(t0, t0, t1);
    tcg_gen_andc_tl(t2, t2, t1);
    tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t2);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
    tcg_temp_free(t2);
4990
    if (unlikely(Rc(ctx->opcode) != 0))
4991
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
4992 4993 4994 4995 4996
}

/* sriq */
GEN_HANDLER(sriq, 0x1F, 0x18, 0x15, 0x00000000, PPC_POWER_BR)
{
4997 4998 4999 5000 5001 5002 5003 5004 5005 5006
    int sh = SH(ctx->opcode);
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
    tcg_gen_shli_tl(t1, cpu_gpr[rS(ctx->opcode)], 32 - sh);
    tcg_gen_or_tl(t1, t0, t1);
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
    gen_store_spr(SPR_MQ, t1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
5007
    if (unlikely(Rc(ctx->opcode) != 0))
5008
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
5009 5010 5011 5012 5013
}

/* srliq */
GEN_HANDLER(srliq, 0x1F, 0x18, 0x17, 0x00000000, PPC_POWER_BR)
{
5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024
    int sh = SH(ctx->opcode);
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    tcg_gen_rotri_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
    gen_load_spr(t1, SPR_MQ);
    gen_store_spr(SPR_MQ, t0);
    tcg_gen_andi_tl(t0, t0,  (0xFFFFFFFFU >> sh));
    tcg_gen_andi_tl(t1, t1, ~(0xFFFFFFFFU >> sh));
    tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
5025
    if (unlikely(Rc(ctx->opcode) != 0))
5026
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
5027 5028 5029 5030 5031
}

/* srlq */
GEN_HANDLER(srlq, 0x1F, 0x18, 0x16, 0x00000000, PPC_POWER_BR)
{
5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054
    int l1 = gen_new_label();
    int l2 = gen_new_label();
    TCGv t0 = tcg_temp_local_new();
    TCGv t1 = tcg_temp_local_new();
    TCGv t2 = tcg_temp_local_new();
    tcg_gen_andi_tl(t2, cpu_gpr[rB(ctx->opcode)], 0x1F);
    tcg_gen_movi_tl(t1, 0xFFFFFFFF);
    tcg_gen_shr_tl(t2, t1, t2);
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x20);
    tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
    gen_load_spr(t0, SPR_MQ);
    tcg_gen_and_tl(cpu_gpr[rA(ctx->opcode)], t0, t2);
    tcg_gen_br(l2);
    gen_set_label(l1);
    tcg_gen_shr_tl(t0, cpu_gpr[rS(ctx->opcode)], t2);
    tcg_gen_and_tl(t0, t0, t2);
    gen_load_spr(t1, SPR_MQ);
    tcg_gen_andc_tl(t1, t1, t2);
    tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
    gen_set_label(l2);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
    tcg_temp_free(t2);
5055
    if (unlikely(Rc(ctx->opcode) != 0))
5056
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
5057 5058 5059 5060 5061
}

/* srq */
GEN_HANDLER(srq, 0x1F, 0x18, 0x14, 0x00000000, PPC_POWER_BR)
{
5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077
    int l1 = gen_new_label();
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
    tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x1F);
    tcg_gen_shr_tl(t0, cpu_gpr[rS(ctx->opcode)], t1);
    tcg_gen_subfi_tl(t1, 32, t1);
    tcg_gen_shl_tl(t1, cpu_gpr[rS(ctx->opcode)], t1);
    tcg_gen_or_tl(t1, t0, t1);
    gen_store_spr(SPR_MQ, t1);
    tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x20);
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
    tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
    tcg_gen_movi_tl(cpu_gpr[rA(ctx->opcode)], 0);
    gen_set_label(l1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
5078
    if (unlikely(Rc(ctx->opcode) != 0))
5079
        gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
5080 5081 5082 5083 5084 5085 5086
}

/* PowerPC 602 specific instructions */
/* dsa  */
GEN_HANDLER(dsa, 0x1F, 0x14, 0x13, 0x03FFF801, PPC_602_SPEC)
{
    /* XXX: TODO */
A
aurel32 已提交
5087
    gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
5088 5089 5090 5091 5092 5093
}

/* esa */
GEN_HANDLER(esa, 0x1F, 0x14, 0x12, 0x03FFF801, PPC_602_SPEC)
{
    /* XXX: TODO */
A
aurel32 已提交
5094
    gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
5095 5096 5097 5098 5099 5100
}

/* mfrom */
GEN_HANDLER(mfrom, 0x1F, 0x09, 0x08, 0x03E0F801, PPC_602_SPEC)
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5101
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5102
#else
A
aurel32 已提交
5103
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5104
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5105 5106
        return;
    }
5107
    gen_helper_602_mfrom(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
5108 5109 5110 5111 5112
#endif
}

/* 602 - 603 - G2 TLB management */
/* tlbld */
5113
GEN_HANDLER2(tlbld_6xx, "tlbld", 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB)
5114 5115
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5116
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5117
#else
A
aurel32 已提交
5118
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5119
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5120 5121
        return;
    }
5122
    gen_helper_6xx_tlbd(cpu_gpr[rB(ctx->opcode)]);
5123 5124 5125 5126
#endif
}

/* tlbli */
5127
GEN_HANDLER2(tlbli_6xx, "tlbli", 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB)
5128 5129
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5130
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5131
#else
A
aurel32 已提交
5132
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5133
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5134 5135
        return;
    }
5136
    gen_helper_6xx_tlbi(cpu_gpr[rB(ctx->opcode)]);
5137 5138 5139
#endif
}

5140 5141
/* 74xx TLB management */
/* tlbld */
5142
GEN_HANDLER2(tlbld_74xx, "tlbld", 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_74xx_TLB)
5143 5144
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5145
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5146
#else
A
aurel32 已提交
5147
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5148
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5149 5150
        return;
    }
5151
    gen_helper_74xx_tlbd(cpu_gpr[rB(ctx->opcode)]);
5152 5153 5154 5155
#endif
}

/* tlbli */
5156
GEN_HANDLER2(tlbli_74xx, "tlbli", 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_74xx_TLB)
5157 5158
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5159
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5160
#else
A
aurel32 已提交
5161
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5162
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5163 5164
        return;
    }
5165
    gen_helper_74xx_tlbi(cpu_gpr[rB(ctx->opcode)]);
5166 5167 5168
#endif
}

5169 5170 5171 5172 5173 5174 5175 5176 5177 5178
/* 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 已提交
5179
    /* Cache line invalidate: privileged and treated as no-op */
5180
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5181
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5182
#else
A
aurel32 已提交
5183
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5184
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198
        return;
    }
#endif
}

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

GEN_HANDLER(mfsri, 0x1F, 0x13, 0x13, 0x00000001, PPC_POWER)
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5199
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5200
#else
5201 5202 5203
    int ra = rA(ctx->opcode);
    int rd = rD(ctx->opcode);
    TCGv t0;
A
aurel32 已提交
5204
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5205
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5206 5207
        return;
    }
5208
    t0 = tcg_temp_new();
A
aurel32 已提交
5209
    gen_addr_reg_index(ctx, t0);
5210 5211 5212 5213
    tcg_gen_shri_tl(t0, t0, 28);
    tcg_gen_andi_tl(t0, t0, 0xF);
    gen_helper_load_sr(cpu_gpr[rd], t0);
    tcg_temp_free(t0);
5214
    if (ra != 0 && ra != rd)
5215
        tcg_gen_mov_tl(cpu_gpr[ra], cpu_gpr[rd]);
5216 5217 5218 5219 5220 5221
#endif
}

GEN_HANDLER(rac, 0x1F, 0x12, 0x19, 0x00000001, PPC_POWER)
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5222
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5223
#else
5224
    TCGv t0;
A
aurel32 已提交
5225
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5226
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5227 5228
        return;
    }
5229
    t0 = tcg_temp_new();
A
aurel32 已提交
5230
    gen_addr_reg_index(ctx, t0);
5231 5232
    gen_helper_rac(cpu_gpr[rD(ctx->opcode)], t0);
    tcg_temp_free(t0);
5233 5234 5235 5236 5237 5238
#endif
}

GEN_HANDLER(rfsvc, 0x13, 0x12, 0x02, 0x03FFF0001, PPC_POWER)
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5239
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5240
#else
A
aurel32 已提交
5241
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5242
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5243 5244
        return;
    }
5245
    gen_helper_rfsvc();
A
aurel32 已提交
5246
    gen_sync_exception(ctx);
5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257
#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)
{
5258
    int rd = rD(ctx->opcode);
A
aurel32 已提交
5259 5260 5261 5262 5263 5264 5265
    TCGv t0;
    gen_set_access_type(ctx, ACCESS_FLOAT);
    t0 = tcg_temp_new();
    gen_addr_imm_index(ctx, t0, 0);
    gen_qemu_ld64(ctx, cpu_fpr[rd], t0);
    gen_addr_add(ctx, t0, t0, 8);
    gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t0);
5266
    tcg_temp_free(t0);
5267 5268 5269 5270 5271 5272
}

/* lfqu */
GEN_HANDLER(lfqu, 0x39, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
{
    int ra = rA(ctx->opcode);
5273
    int rd = rD(ctx->opcode);
A
aurel32 已提交
5274 5275 5276 5277 5278 5279 5280 5281
    TCGv t0, t1;
    gen_set_access_type(ctx, ACCESS_FLOAT);
    t0 = tcg_temp_new();
    t1 = tcg_temp_new();
    gen_addr_imm_index(ctx, t0, 0);
    gen_qemu_ld64(ctx, cpu_fpr[rd], t0);
    gen_addr_add(ctx, t1, t0, 8);
    gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t1);
5282
    if (ra != 0)
5283 5284 5285
        tcg_gen_mov_tl(cpu_gpr[ra], t0);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
5286 5287 5288 5289 5290 5291
}

/* lfqux */
GEN_HANDLER(lfqux, 0x1F, 0x17, 0x19, 0x00000001, PPC_POWER2)
{
    int ra = rA(ctx->opcode);
5292
    int rd = rD(ctx->opcode);
A
aurel32 已提交
5293 5294 5295 5296 5297 5298 5299 5300 5301
    gen_set_access_type(ctx, ACCESS_FLOAT);
    TCGv t0, t1;
    t0 = tcg_temp_new();
    gen_addr_reg_index(ctx, t0);
    gen_qemu_ld64(ctx, cpu_fpr[rd], t0);
    t1 = tcg_temp_new();
    gen_addr_add(ctx, t1, t0, 8);
    gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t1);
    tcg_temp_free(t1);
5302
    if (ra != 0)
5303 5304
        tcg_gen_mov_tl(cpu_gpr[ra], t0);
    tcg_temp_free(t0);
5305 5306 5307 5308 5309
}

/* lfqx */
GEN_HANDLER(lfqx, 0x1F, 0x17, 0x18, 0x00000001, PPC_POWER2)
{
5310
    int rd = rD(ctx->opcode);
A
aurel32 已提交
5311 5312 5313 5314 5315 5316 5317
    TCGv t0;
    gen_set_access_type(ctx, ACCESS_FLOAT);
    t0 = tcg_temp_new();
    gen_addr_reg_index(ctx, t0);
    gen_qemu_ld64(ctx, cpu_fpr[rd], t0);
    gen_addr_add(ctx, t0, t0, 8);
    gen_qemu_ld64(ctx, cpu_fpr[(rd + 1) % 32], t0);
5318
    tcg_temp_free(t0);
5319 5320 5321 5322 5323
}

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

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

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

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

/* BookE specific instructions */
5388
/* XXX: not implemented on 440 ? */
5389
GEN_HANDLER(mfapidi, 0x1F, 0x13, 0x08, 0x0000F801, PPC_MFAPIDI)
5390 5391
{
    /* XXX: TODO */
A
aurel32 已提交
5392
    gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
5393 5394
}

5395
/* XXX: not implemented on 440 ? */
5396
GEN_HANDLER(tlbiva, 0x1F, 0x12, 0x18, 0x03FFF801, PPC_TLBIVA)
5397 5398
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5399
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5400
#else
5401
    TCGv t0;
A
aurel32 已提交
5402
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5403
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5404 5405
        return;
    }
5406
    t0 = tcg_temp_new();
A
aurel32 已提交
5407
    gen_addr_reg_index(ctx, t0);
5408 5409
    gen_helper_tlbie(cpu_gpr[rB(ctx->opcode)]);
    tcg_temp_free(t0);
5410 5411 5412 5413
#endif
}

/* All 405 MAC instructions are translated here */
5414 5415 5416
static always_inline void gen_405_mulladd_insn (DisasContext *ctx,
                                                int opc2, int opc3,
                                                int ra, int rb, int rt, int Rc)
5417
{
5418 5419
    TCGv t0, t1;

P
pbrook 已提交
5420 5421
    t0 = tcg_temp_local_new();
    t1 = tcg_temp_local_new();
5422

5423 5424 5425 5426 5427 5428 5429
    switch (opc3 & 0x0D) {
    case 0x05:
        /* macchw    - macchw.    - macchwo   - macchwo.   */
        /* macchws   - macchws.   - macchwso  - macchwso.  */
        /* nmacchw   - nmacchw.   - nmacchwo  - nmacchwo.  */
        /* nmacchws  - nmacchws.  - nmacchwso - nmacchwso. */
        /* mulchw - mulchw. */
5430 5431 5432
        tcg_gen_ext16s_tl(t0, cpu_gpr[ra]);
        tcg_gen_sari_tl(t1, cpu_gpr[rb], 16);
        tcg_gen_ext16s_tl(t1, t1);
5433 5434 5435 5436 5437
        break;
    case 0x04:
        /* macchwu   - macchwu.   - macchwuo  - macchwuo.  */
        /* macchwsu  - macchwsu.  - macchwsuo - macchwsuo. */
        /* mulchwu - mulchwu. */
5438 5439 5440
        tcg_gen_ext16u_tl(t0, cpu_gpr[ra]);
        tcg_gen_shri_tl(t1, cpu_gpr[rb], 16);
        tcg_gen_ext16u_tl(t1, t1);
5441 5442 5443 5444 5445 5446 5447
        break;
    case 0x01:
        /* machhw    - machhw.    - machhwo   - machhwo.   */
        /* machhws   - machhws.   - machhwso  - machhwso.  */
        /* nmachhw   - nmachhw.   - nmachhwo  - nmachhwo.  */
        /* nmachhws  - nmachhws.  - nmachhwso - nmachhwso. */
        /* mulhhw - mulhhw. */
5448 5449 5450 5451
        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);
5452 5453 5454 5455 5456
        break;
    case 0x00:
        /* machhwu   - machhwu.   - machhwuo  - machhwuo.  */
        /* machhwsu  - machhwsu.  - machhwsuo - machhwsuo. */
        /* mulhhwu - mulhhwu. */
5457 5458 5459 5460
        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);
5461 5462 5463 5464 5465 5466 5467
        break;
    case 0x0D:
        /* maclhw    - maclhw.    - maclhwo   - maclhwo.   */
        /* maclhws   - maclhws.   - maclhwso  - maclhwso.  */
        /* nmaclhw   - nmaclhw.   - nmaclhwo  - nmaclhwo.  */
        /* nmaclhws  - nmaclhws.  - nmaclhwso - nmaclhwso. */
        /* mullhw - mullhw. */
5468 5469
        tcg_gen_ext16s_tl(t0, cpu_gpr[ra]);
        tcg_gen_ext16s_tl(t1, cpu_gpr[rb]);
5470 5471 5472 5473 5474
        break;
    case 0x0C:
        /* maclhwu   - maclhwu.   - maclhwuo  - maclhwuo.  */
        /* maclhwsu  - maclhwsu.  - maclhwsuo - maclhwsuo. */
        /* mullhwu - mullhwu. */
5475 5476
        tcg_gen_ext16u_tl(t0, cpu_gpr[ra]);
        tcg_gen_ext16u_tl(t1, cpu_gpr[rb]);
5477 5478 5479
        break;
    }
    if (opc2 & 0x04) {
5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503
        /* (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 已提交
5504
                if (opc3 & 0x02) {
5505 5506 5507 5508 5509 5510 5511
                    /* 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 已提交
5512
                if (opc3 & 0x02) {
5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525
                    /* 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);
5526
    }
5527 5528
    tcg_temp_free(t0);
    tcg_temp_free(t1);
5529 5530
    if (unlikely(Rc) != 0) {
        /* Update Rc0 */
5531
        gen_set_Rc0(ctx, cpu_gpr[rt]);
5532 5533 5534
    }
}

5535 5536
#define GEN_MAC_HANDLER(name, opc2, opc3)                                     \
GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_405_MAC)                  \
5537 5538 5539 5540 5541 5542
{                                                                             \
    gen_405_mulladd_insn(ctx, opc2, opc3, rA(ctx->opcode), rB(ctx->opcode),   \
                         rD(ctx->opcode), Rc(ctx->opcode));                   \
}

/* macchw    - macchw.    */
5543
GEN_MAC_HANDLER(macchw, 0x0C, 0x05);
5544
/* macchwo   - macchwo.   */
5545
GEN_MAC_HANDLER(macchwo, 0x0C, 0x15);
5546
/* macchws   - macchws.   */
5547
GEN_MAC_HANDLER(macchws, 0x0C, 0x07);
5548
/* macchwso  - macchwso.  */
5549
GEN_MAC_HANDLER(macchwso, 0x0C, 0x17);
5550
/* macchwsu  - macchwsu.  */
5551
GEN_MAC_HANDLER(macchwsu, 0x0C, 0x06);
5552
/* macchwsuo - macchwsuo. */
5553
GEN_MAC_HANDLER(macchwsuo, 0x0C, 0x16);
5554
/* macchwu   - macchwu.   */
5555
GEN_MAC_HANDLER(macchwu, 0x0C, 0x04);
5556
/* macchwuo  - macchwuo.  */
5557
GEN_MAC_HANDLER(macchwuo, 0x0C, 0x14);
5558
/* machhw    - machhw.    */
5559
GEN_MAC_HANDLER(machhw, 0x0C, 0x01);
5560
/* machhwo   - machhwo.   */
5561
GEN_MAC_HANDLER(machhwo, 0x0C, 0x11);
5562
/* machhws   - machhws.   */
5563
GEN_MAC_HANDLER(machhws, 0x0C, 0x03);
5564
/* machhwso  - machhwso.  */
5565
GEN_MAC_HANDLER(machhwso, 0x0C, 0x13);
5566
/* machhwsu  - machhwsu.  */
5567
GEN_MAC_HANDLER(machhwsu, 0x0C, 0x02);
5568
/* machhwsuo - machhwsuo. */
5569
GEN_MAC_HANDLER(machhwsuo, 0x0C, 0x12);
5570
/* machhwu   - machhwu.   */
5571
GEN_MAC_HANDLER(machhwu, 0x0C, 0x00);
5572
/* machhwuo  - machhwuo.  */
5573
GEN_MAC_HANDLER(machhwuo, 0x0C, 0x10);
5574
/* maclhw    - maclhw.    */
5575
GEN_MAC_HANDLER(maclhw, 0x0C, 0x0D);
5576
/* maclhwo   - maclhwo.   */
5577
GEN_MAC_HANDLER(maclhwo, 0x0C, 0x1D);
5578
/* maclhws   - maclhws.   */
5579
GEN_MAC_HANDLER(maclhws, 0x0C, 0x0F);
5580
/* maclhwso  - maclhwso.  */
5581
GEN_MAC_HANDLER(maclhwso, 0x0C, 0x1F);
5582
/* maclhwu   - maclhwu.   */
5583
GEN_MAC_HANDLER(maclhwu, 0x0C, 0x0C);
5584
/* maclhwuo  - maclhwuo.  */
5585
GEN_MAC_HANDLER(maclhwuo, 0x0C, 0x1C);
5586
/* maclhwsu  - maclhwsu.  */
5587
GEN_MAC_HANDLER(maclhwsu, 0x0C, 0x0E);
5588
/* maclhwsuo - maclhwsuo. */
5589
GEN_MAC_HANDLER(maclhwsuo, 0x0C, 0x1E);
5590
/* nmacchw   - nmacchw.   */
5591
GEN_MAC_HANDLER(nmacchw, 0x0E, 0x05);
5592
/* nmacchwo  - nmacchwo.  */
5593
GEN_MAC_HANDLER(nmacchwo, 0x0E, 0x15);
5594
/* nmacchws  - nmacchws.  */
5595
GEN_MAC_HANDLER(nmacchws, 0x0E, 0x07);
5596
/* nmacchwso - nmacchwso. */
5597
GEN_MAC_HANDLER(nmacchwso, 0x0E, 0x17);
5598
/* nmachhw   - nmachhw.   */
5599
GEN_MAC_HANDLER(nmachhw, 0x0E, 0x01);
5600
/* nmachhwo  - nmachhwo.  */
5601
GEN_MAC_HANDLER(nmachhwo, 0x0E, 0x11);
5602
/* nmachhws  - nmachhws.  */
5603
GEN_MAC_HANDLER(nmachhws, 0x0E, 0x03);
5604
/* nmachhwso - nmachhwso. */
5605
GEN_MAC_HANDLER(nmachhwso, 0x0E, 0x13);
5606
/* nmaclhw   - nmaclhw.   */
5607
GEN_MAC_HANDLER(nmaclhw, 0x0E, 0x0D);
5608
/* nmaclhwo  - nmaclhwo.  */
5609
GEN_MAC_HANDLER(nmaclhwo, 0x0E, 0x1D);
5610
/* nmaclhws  - nmaclhws.  */
5611
GEN_MAC_HANDLER(nmaclhws, 0x0E, 0x0F);
5612
/* nmaclhwso - nmaclhwso. */
5613
GEN_MAC_HANDLER(nmaclhwso, 0x0E, 0x1F);
5614 5615

/* mulchw  - mulchw.  */
5616
GEN_MAC_HANDLER(mulchw, 0x08, 0x05);
5617
/* mulchwu - mulchwu. */
5618
GEN_MAC_HANDLER(mulchwu, 0x08, 0x04);
5619
/* mulhhw  - mulhhw.  */
5620
GEN_MAC_HANDLER(mulhhw, 0x08, 0x01);
5621
/* mulhhwu - mulhhwu. */
5622
GEN_MAC_HANDLER(mulhhwu, 0x08, 0x00);
5623
/* mullhw  - mullhw.  */
5624
GEN_MAC_HANDLER(mullhw, 0x08, 0x0D);
5625
/* mullhwu - mullhwu. */
5626
GEN_MAC_HANDLER(mullhwu, 0x08, 0x0C);
5627 5628

/* mfdcr */
5629
GEN_HANDLER(mfdcr, 0x1F, 0x03, 0x0A, 0x00000001, PPC_DCR)
5630 5631
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5632
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
5633
#else
5634
    TCGv dcrn;
A
aurel32 已提交
5635
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5636
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
5637 5638
        return;
    }
5639 5640 5641 5642 5643
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
    dcrn = tcg_const_tl(SPR(ctx->opcode));
    gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], dcrn);
    tcg_temp_free(dcrn);
5644 5645 5646 5647
#endif
}

/* mtdcr */
5648
GEN_HANDLER(mtdcr, 0x1F, 0x03, 0x0E, 0x00000001, PPC_DCR)
5649 5650
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5651
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
5652
#else
5653
    TCGv dcrn;
A
aurel32 已提交
5654
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5655
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
5656 5657
        return;
    }
5658 5659 5660 5661 5662
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
    dcrn = tcg_const_tl(SPR(ctx->opcode));
    gen_helper_store_dcr(dcrn, cpu_gpr[rS(ctx->opcode)]);
    tcg_temp_free(dcrn);
5663 5664 5665 5666
#endif
}

/* mfdcrx */
5667
/* XXX: not implemented on 440 ? */
5668
GEN_HANDLER(mfdcrx, 0x1F, 0x03, 0x08, 0x00000000, PPC_DCRX)
5669 5670
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5671
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
5672
#else
A
aurel32 已提交
5673
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5674
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
5675 5676
        return;
    }
5677 5678 5679
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
    gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
5680
    /* Note: Rc update flag set leads to undefined state of Rc0 */
5681 5682 5683 5684
#endif
}

/* mtdcrx */
5685
/* XXX: not implemented on 440 ? */
5686
GEN_HANDLER(mtdcrx, 0x1F, 0x03, 0x0C, 0x00000000, PPC_DCRX)
5687 5688
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5689
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
5690
#else
A
aurel32 已提交
5691
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5692
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
5693 5694
        return;
    }
5695 5696 5697
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
    gen_helper_store_dcr(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
5698
    /* Note: Rc update flag set leads to undefined state of Rc0 */
5699 5700 5701
#endif
}

5702 5703 5704
/* mfdcrux (PPC 460) : user-mode access to DCR */
GEN_HANDLER(mfdcrux, 0x1F, 0x03, 0x09, 0x00000000, PPC_DCRUX)
{
5705 5706 5707
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
    gen_helper_load_dcr(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
5708 5709 5710 5711 5712 5713
    /* 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)
{
5714 5715 5716
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
    gen_helper_store_dcr(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
5717 5718 5719
    /* Note: Rc update flag set leads to undefined state of Rc0 */
}

5720 5721 5722 5723
/* dccci */
GEN_HANDLER(dccci, 0x1F, 0x06, 0x0E, 0x03E00001, PPC_4xx_COMMON)
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5724
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5725
#else
A
aurel32 已提交
5726
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5727
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5728 5729 5730 5731 5732 5733 5734 5735 5736 5737
        return;
    }
    /* interpreted as no-op */
#endif
}

/* dcread */
GEN_HANDLER(dcread, 0x1F, 0x06, 0x0F, 0x00000001, PPC_4xx_COMMON)
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5738
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5739
#else
A
aurel32 已提交
5740
    TCGv EA, val;
A
aurel32 已提交
5741
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5742
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5743 5744
        return;
    }
A
aurel32 已提交
5745
    gen_set_access_type(ctx, ACCESS_CACHE);
P
pbrook 已提交
5746
    EA = tcg_temp_new();
A
aurel32 已提交
5747
    gen_addr_reg_index(ctx, EA);
P
pbrook 已提交
5748
    val = tcg_temp_new();
A
aurel32 已提交
5749
    gen_qemu_ld32u(ctx, val, EA);
A
aurel32 已提交
5750 5751 5752
    tcg_temp_free(val);
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], EA);
    tcg_temp_free(EA);
5753 5754 5755 5756
#endif
}

/* icbt */
5757
GEN_HANDLER2(icbt_40x, "icbt", 0x1F, 0x06, 0x08, 0x03E00001, PPC_40x_ICBT)
5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768
{
    /* interpreted as no-op */
    /* XXX: specification say this is treated as a load by the MMU
     *      but does not generate any exception
     */
}

/* iccci */
GEN_HANDLER(iccci, 0x1F, 0x06, 0x1E, 0x00000001, PPC_4xx_COMMON)
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5769
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5770
#else
A
aurel32 已提交
5771
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5772
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5773 5774 5775 5776 5777 5778 5779 5780 5781 5782
        return;
    }
    /* interpreted as no-op */
#endif
}

/* icread */
GEN_HANDLER(icread, 0x1F, 0x06, 0x1F, 0x03E00001, PPC_4xx_COMMON)
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5783
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5784
#else
A
aurel32 已提交
5785
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5786
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5787 5788 5789 5790 5791 5792
        return;
    }
    /* interpreted as no-op */
#endif
}

A
aurel32 已提交
5793
/* rfci (mem_idx only) */
5794
GEN_HANDLER2(rfci_40x, "rfci", 0x13, 0x13, 0x01, 0x03FF8001, PPC_40x_EXCP)
5795 5796
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5797
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5798
#else
A
aurel32 已提交
5799
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5800
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5801 5802 5803
        return;
    }
    /* Restore CPU state */
5804
    gen_helper_40x_rfci();
A
aurel32 已提交
5805
    gen_sync_exception(ctx);
5806 5807 5808 5809 5810 5811
#endif
}

GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE)
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5812
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5813
#else
A
aurel32 已提交
5814
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5815
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5816 5817 5818
        return;
    }
    /* Restore CPU state */
5819
    gen_helper_rfci();
A
aurel32 已提交
5820
    gen_sync_exception(ctx);
5821 5822 5823 5824
#endif
}

/* BookE specific */
5825
/* XXX: not implemented on 440 ? */
5826
GEN_HANDLER(rfdi, 0x13, 0x07, 0x01, 0x03FF8001, PPC_RFDI)
5827 5828
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5829
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5830
#else
A
aurel32 已提交
5831
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5832
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5833 5834 5835
        return;
    }
    /* Restore CPU state */
5836
    gen_helper_rfdi();
A
aurel32 已提交
5837
    gen_sync_exception(ctx);
5838 5839 5840
#endif
}

5841
/* XXX: not implemented on 440 ? */
5842
GEN_HANDLER(rfmci, 0x13, 0x06, 0x01, 0x03FF8001, PPC_RFMCI)
5843 5844
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5845
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5846
#else
A
aurel32 已提交
5847
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5848
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5849 5850 5851
        return;
    }
    /* Restore CPU state */
5852
    gen_helper_rfmci();
A
aurel32 已提交
5853
    gen_sync_exception(ctx);
5854 5855
#endif
}
5856

5857
/* TLB management - PowerPC 405 implementation */
5858
/* tlbre */
5859
GEN_HANDLER2(tlbre_40x, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_TLB)
5860 5861
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5862
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5863
#else
A
aurel32 已提交
5864
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5865
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5866 5867 5868 5869
        return;
    }
    switch (rB(ctx->opcode)) {
    case 0:
5870
        gen_helper_4xx_tlbre_hi(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
5871 5872
        break;
    case 1:
5873
        gen_helper_4xx_tlbre_lo(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
5874 5875
        break;
    default:
A
aurel32 已提交
5876
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
5877
        break;
5878
    }
5879 5880 5881
#endif
}

5882
/* tlbsx - tlbsx. */
5883
GEN_HANDLER2(tlbsx_40x, "tlbsx", 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_TLB)
5884 5885
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5886
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5887
#else
5888
    TCGv t0;
A
aurel32 已提交
5889
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5890
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5891 5892
        return;
    }
5893
    t0 = tcg_temp_new();
A
aurel32 已提交
5894
    gen_addr_reg_index(ctx, t0);
5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905
    gen_helper_4xx_tlbsx(cpu_gpr[rD(ctx->opcode)], t0);
    tcg_temp_free(t0);
    if (Rc(ctx->opcode)) {
        int l1 = gen_new_label();
        tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_xer);
        tcg_gen_shri_i32(cpu_crf[0], cpu_crf[0], XER_SO);
        tcg_gen_andi_i32(cpu_crf[0], cpu_crf[0], 1);
        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[rD(ctx->opcode)], -1, l1);
        tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 0x02);
        gen_set_label(l1);
    }
5906
#endif
B
bellard 已提交
5907 5908
}

5909
/* tlbwe */
5910
GEN_HANDLER2(tlbwe_40x, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_TLB)
B
bellard 已提交
5911
{
5912
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5913
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5914
#else
A
aurel32 已提交
5915
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5916
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5917 5918 5919 5920
        return;
    }
    switch (rB(ctx->opcode)) {
    case 0:
5921
        gen_helper_4xx_tlbwe_hi(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
5922 5923
        break;
    case 1:
5924
        gen_helper_4xx_tlbwe_lo(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
5925 5926
        break;
    default:
A
aurel32 已提交
5927
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
5928
        break;
5929
    }
5930 5931 5932
#endif
}

5933
/* TLB management - PowerPC 440 implementation */
5934
/* tlbre */
5935
GEN_HANDLER2(tlbre_440, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE)
5936 5937
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5938
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5939
#else
A
aurel32 已提交
5940
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5941
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5942 5943 5944 5945 5946 5947
        return;
    }
    switch (rB(ctx->opcode)) {
    case 0:
    case 1:
    case 2:
5948 5949 5950 5951 5952
        {
            TCGv_i32 t0 = tcg_const_i32(rB(ctx->opcode));
            gen_helper_440_tlbwe(t0, cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
            tcg_temp_free_i32(t0);
        }
5953 5954
        break;
    default:
A
aurel32 已提交
5955
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
5956 5957 5958 5959 5960 5961
        break;
    }
#endif
}

/* tlbsx - tlbsx. */
5962
GEN_HANDLER2(tlbsx_440, "tlbsx", 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE)
5963 5964
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5965
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5966
#else
5967
    TCGv t0;
A
aurel32 已提交
5968
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5969
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5970 5971
        return;
    }
5972
    t0 = tcg_temp_new();
A
aurel32 已提交
5973
    gen_addr_reg_index(ctx, t0);
5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984
    gen_helper_440_tlbsx(cpu_gpr[rD(ctx->opcode)], t0);
    tcg_temp_free(t0);
    if (Rc(ctx->opcode)) {
        int l1 = gen_new_label();
        tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_xer);
        tcg_gen_shri_i32(cpu_crf[0], cpu_crf[0], XER_SO);
        tcg_gen_andi_i32(cpu_crf[0], cpu_crf[0], 1);
        tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[rD(ctx->opcode)], -1, l1);
        tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 0x02);
        gen_set_label(l1);
    }
5985 5986 5987 5988
#endif
}

/* tlbwe */
5989
GEN_HANDLER2(tlbwe_440, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE)
5990 5991
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
5992
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5993
#else
A
aurel32 已提交
5994
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
5995
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
5996 5997 5998 5999 6000 6001
        return;
    }
    switch (rB(ctx->opcode)) {
    case 0:
    case 1:
    case 2:
6002 6003 6004 6005 6006
        {
            TCGv_i32 t0 = tcg_const_i32(rB(ctx->opcode));
            gen_helper_440_tlbwe(t0, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
            tcg_temp_free_i32(t0);
        }
6007 6008
        break;
    default:
A
aurel32 已提交
6009
        gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
6010 6011 6012 6013 6014
        break;
    }
#endif
}

6015
/* wrtee */
6016
GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_WRTEE)
6017 6018
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
6019
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
6020
#else
6021
    TCGv t0;
A
aurel32 已提交
6022
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
6023
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
6024 6025
        return;
    }
6026 6027 6028 6029 6030
    t0 = tcg_temp_new();
    tcg_gen_andi_tl(t0, cpu_gpr[rD(ctx->opcode)], (1 << MSR_EE));
    tcg_gen_andi_tl(cpu_msr, cpu_msr, ~(1 << MSR_EE));
    tcg_gen_or_tl(cpu_msr, cpu_msr, t0);
    tcg_temp_free(t0);
J
j_mayer 已提交
6031 6032 6033
    /* Stop translation to have a chance to raise an exception
     * if we just set msr_ee to 1
     */
A
aurel32 已提交
6034
    gen_stop_exception(ctx);
6035 6036 6037 6038
#endif
}

/* wrteei */
6039
GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000EFC01, PPC_WRTEE)
6040 6041
{
#if defined(CONFIG_USER_ONLY)
A
aurel32 已提交
6042
    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
6043
#else
A
aurel32 已提交
6044
    if (unlikely(!ctx->mem_idx)) {
A
aurel32 已提交
6045
        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
6046 6047
        return;
    }
6048 6049 6050
    if (ctx->opcode & 0x00010000) {
        tcg_gen_ori_tl(cpu_msr, cpu_msr, (1 << MSR_EE));
        /* Stop translation to have a chance to raise an exception */
A
aurel32 已提交
6051
        gen_stop_exception(ctx);
6052 6053 6054
    } else {
        tcg_gen_andi_tl(cpu_msr, cpu_msr, (1 << MSR_EE));
    }
6055 6056 6057
#endif
}

J
j_mayer 已提交
6058
/* PowerPC 440 specific instructions */
6059 6060 6061
/* dlmzb */
GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC)
{
6062 6063 6064 6065
    TCGv_i32 t0 = tcg_const_i32(Rc(ctx->opcode));
    gen_helper_dlmzb(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)],
                     cpu_gpr[rB(ctx->opcode)], t0);
    tcg_temp_free_i32(t0);
6066 6067 6068
}

/* mbar replaces eieio on 440 */
A
aurel32 已提交
6069
GEN_HANDLER(mbar, 0x1F, 0x16, 0x1a, 0x001FF801, PPC_BOOKE)
6070 6071 6072 6073 6074
{
    /* interpreted as no-op */
}

/* msync replaces sync on 440 */
6075
GEN_HANDLER(msync, 0x1F, 0x16, 0x12, 0x03FFF801, PPC_BOOKE)
6076 6077 6078 6079 6080
{
    /* interpreted as no-op */
}

/* icbt */
6081
GEN_HANDLER2(icbt_440, "icbt", 0x1F, 0x16, 0x00, 0x03E00001, PPC_BOOKE)
6082 6083 6084 6085 6086
{
    /* interpreted as no-op */
    /* XXX: specification say this is treated as a load by the MMU
     *      but does not generate any exception
     */
B
bellard 已提交
6087 6088
}

6089 6090 6091
/***                      Altivec vector extension                         ***/
/* Altivec registers moves */

A
aurel32 已提交
6092 6093
static always_inline TCGv_ptr gen_avr_ptr(int reg)
{
A
aurel32 已提交
6094
    TCGv_ptr r = tcg_temp_new_ptr();
A
aurel32 已提交
6095 6096 6097 6098
    tcg_gen_addi_ptr(r, cpu_env, offsetof(CPUPPCState, avr[reg]));
    return r;
}

6099
#define GEN_VR_LDX(name, opc2, opc3)                                          \
6100
GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC)                  \
6101
{                                                                             \
6102
    TCGv EA;                                                                  \
6103
    if (unlikely(!ctx->altivec_enabled)) {                                    \
A
aurel32 已提交
6104
        gen_exception(ctx, POWERPC_EXCP_VPU);                                 \
6105 6106
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
6107
    gen_set_access_type(ctx, ACCESS_INT);                                     \
6108
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
6109
    gen_addr_reg_index(ctx, EA);                                              \
6110
    tcg_gen_andi_tl(EA, EA, ~0xf);                                            \
A
aurel32 已提交
6111 6112
    if (ctx->le_mode) {                                                       \
        gen_qemu_ld64(ctx, cpu_avrl[rD(ctx->opcode)], EA);                    \
6113
        tcg_gen_addi_tl(EA, EA, 8);                                           \
A
aurel32 已提交
6114
        gen_qemu_ld64(ctx, cpu_avrh[rD(ctx->opcode)], EA);                    \
6115
    } else {                                                                  \
A
aurel32 已提交
6116
        gen_qemu_ld64(ctx, cpu_avrh[rD(ctx->opcode)], EA);                    \
6117
        tcg_gen_addi_tl(EA, EA, 8);                                           \
A
aurel32 已提交
6118
        gen_qemu_ld64(ctx, cpu_avrl[rD(ctx->opcode)], EA);                    \
6119 6120
    }                                                                         \
    tcg_temp_free(EA);                                                        \
6121 6122 6123 6124 6125
}

#define GEN_VR_STX(name, opc2, opc3)                                          \
GEN_HANDLER(st##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC)              \
{                                                                             \
6126
    TCGv EA;                                                                  \
6127
    if (unlikely(!ctx->altivec_enabled)) {                                    \
A
aurel32 已提交
6128
        gen_exception(ctx, POWERPC_EXCP_VPU);                                 \
6129 6130
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
6131
    gen_set_access_type(ctx, ACCESS_INT);                                     \
6132
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
6133
    gen_addr_reg_index(ctx, EA);                                              \
6134
    tcg_gen_andi_tl(EA, EA, ~0xf);                                            \
A
aurel32 已提交
6135 6136
    if (ctx->le_mode) {                                                       \
        gen_qemu_st64(ctx, cpu_avrl[rD(ctx->opcode)], EA);                    \
6137
        tcg_gen_addi_tl(EA, EA, 8);                                           \
A
aurel32 已提交
6138
        gen_qemu_st64(ctx, cpu_avrh[rD(ctx->opcode)], EA);                    \
6139
    } else {                                                                  \
A
aurel32 已提交
6140
        gen_qemu_st64(ctx, cpu_avrh[rD(ctx->opcode)], EA);                    \
6141
        tcg_gen_addi_tl(EA, EA, 8);                                           \
A
aurel32 已提交
6142
        gen_qemu_st64(ctx, cpu_avrl[rD(ctx->opcode)], EA);                    \
6143 6144
    }                                                                         \
    tcg_temp_free(EA);                                                        \
6145 6146
}

A
aurel32 已提交
6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182
#define GEN_VR_LVE(name, opc2, opc3)                                    \
    GEN_HANDLER(lve##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC)   \
    {                                                                   \
        TCGv EA;                                                        \
        TCGv_ptr rs;                                                    \
        if (unlikely(!ctx->altivec_enabled)) {                          \
            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
            return;                                                     \
        }                                                               \
        gen_set_access_type(ctx, ACCESS_INT);                           \
        EA = tcg_temp_new();                                            \
        gen_addr_reg_index(ctx, EA);                                    \
        rs = gen_avr_ptr(rS(ctx->opcode));                              \
        gen_helper_lve##name (rs, EA);                                  \
        tcg_temp_free(EA);                                              \
        tcg_temp_free_ptr(rs);                                          \
    }

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

6183
GEN_VR_LDX(lvx, 0x07, 0x03);
6184
/* As we don't emulate the cache, lvxl is stricly equivalent to lvx */
6185
GEN_VR_LDX(lvxl, 0x07, 0x0B);
6186

A
aurel32 已提交
6187 6188 6189 6190
GEN_VR_LVE(bx, 0x07, 0x00);
GEN_VR_LVE(hx, 0x07, 0x01);
GEN_VR_LVE(wx, 0x07, 0x02);

6191
GEN_VR_STX(svx, 0x07, 0x07);
6192
/* As we don't emulate the cache, stvxl is stricly equivalent to stvx */
6193
GEN_VR_STX(svxl, 0x07, 0x0F);
6194

A
aurel32 已提交
6195 6196 6197 6198
GEN_VR_STVE(bx, 0x07, 0x04);
GEN_VR_STVE(hx, 0x07, 0x05);
GEN_VR_STVE(wx, 0x07, 0x06);

A
aurel32 已提交
6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230
GEN_HANDLER(lvsl, 0x1f, 0x06, 0x00, 0x00000001, PPC_ALTIVEC)
{
    TCGv_ptr rd;
    TCGv EA;
    if (unlikely(!ctx->altivec_enabled)) {
        gen_exception(ctx, POWERPC_EXCP_VPU);
        return;
    }
    EA = tcg_temp_new();
    gen_addr_reg_index(ctx, EA);
    rd = gen_avr_ptr(rD(ctx->opcode));
    gen_helper_lvsl(rd, EA);
    tcg_temp_free(EA);
    tcg_temp_free_ptr(rd);
}

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

6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248
/* Logical operations */
#define GEN_VX_LOGICAL(name, tcg_op, opc2, opc3)                        \
GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC)            \
{                                                                       \
    if (unlikely(!ctx->altivec_enabled)) {                              \
        gen_exception(ctx, POWERPC_EXCP_VPU);                           \
        return;                                                         \
    }                                                                   \
    tcg_op(cpu_avrh[rD(ctx->opcode)], cpu_avrh[rA(ctx->opcode)], cpu_avrh[rB(ctx->opcode)]); \
    tcg_op(cpu_avrl[rD(ctx->opcode)], cpu_avrl[rA(ctx->opcode)], cpu_avrl[rB(ctx->opcode)]); \
}

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

6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265
#define GEN_VXFORM(name, opc2, opc3)                                    \
GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC)            \
{                                                                       \
    TCGv_ptr ra, rb, rd;                                                \
    if (unlikely(!ctx->altivec_enabled)) {                              \
        gen_exception(ctx, POWERPC_EXCP_VPU);                           \
        return;                                                         \
    }                                                                   \
    ra = gen_avr_ptr(rA(ctx->opcode));                                  \
    rb = gen_avr_ptr(rB(ctx->opcode));                                  \
    rd = gen_avr_ptr(rD(ctx->opcode));                                  \
    gen_helper_##name (rd, ra, rb);                                     \
    tcg_temp_free_ptr(ra);                                              \
    tcg_temp_free_ptr(rb);                                              \
    tcg_temp_free_ptr(rd);                                              \
}

A
aurel32 已提交
6266 6267 6268 6269 6270 6271
GEN_VXFORM(vaddubm, 0, 0);
GEN_VXFORM(vadduhm, 0, 1);
GEN_VXFORM(vadduwm, 0, 2);
GEN_VXFORM(vsububm, 0, 16);
GEN_VXFORM(vsubuhm, 0, 17);
GEN_VXFORM(vsubuwm, 0, 18);
6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283
GEN_VXFORM(vmaxub, 1, 0);
GEN_VXFORM(vmaxuh, 1, 1);
GEN_VXFORM(vmaxuw, 1, 2);
GEN_VXFORM(vmaxsb, 1, 4);
GEN_VXFORM(vmaxsh, 1, 5);
GEN_VXFORM(vmaxsw, 1, 6);
GEN_VXFORM(vminub, 1, 8);
GEN_VXFORM(vminuh, 1, 9);
GEN_VXFORM(vminuw, 1, 10);
GEN_VXFORM(vminsb, 1, 12);
GEN_VXFORM(vminsh, 1, 13);
GEN_VXFORM(vminsw, 1, 14);
A
aurel32 已提交
6284 6285 6286 6287 6288 6289
GEN_VXFORM(vavgub, 1, 16);
GEN_VXFORM(vavguh, 1, 17);
GEN_VXFORM(vavguw, 1, 18);
GEN_VXFORM(vavgsb, 1, 20);
GEN_VXFORM(vavgsh, 1, 21);
GEN_VXFORM(vavgsw, 1, 22);
A
aurel32 已提交
6290 6291 6292 6293 6294 6295
GEN_VXFORM(vmrghb, 6, 0);
GEN_VXFORM(vmrghh, 6, 1);
GEN_VXFORM(vmrghw, 6, 2);
GEN_VXFORM(vmrglb, 6, 4);
GEN_VXFORM(vmrglh, 6, 5);
GEN_VXFORM(vmrglw, 6, 6);
A
aurel32 已提交
6296 6297 6298 6299 6300 6301 6302 6303
GEN_VXFORM(vmuloub, 4, 0);
GEN_VXFORM(vmulouh, 4, 1);
GEN_VXFORM(vmulosb, 4, 4);
GEN_VXFORM(vmulosh, 4, 5);
GEN_VXFORM(vmuleub, 4, 8);
GEN_VXFORM(vmuleuh, 4, 9);
GEN_VXFORM(vmulesb, 4, 12);
GEN_VXFORM(vmulesh, 4, 13);
A
aurel32 已提交
6304 6305 6306
GEN_VXFORM(vslb, 2, 4);
GEN_VXFORM(vslh, 2, 5);
GEN_VXFORM(vslw, 2, 6);
A
aurel32 已提交
6307 6308 6309 6310 6311 6312
GEN_VXFORM(vsrb, 2, 8);
GEN_VXFORM(vsrh, 2, 9);
GEN_VXFORM(vsrw, 2, 10);
GEN_VXFORM(vsrab, 2, 12);
GEN_VXFORM(vsrah, 2, 13);
GEN_VXFORM(vsraw, 2, 14);
A
aurel32 已提交
6313 6314
GEN_VXFORM(vslo, 6, 16);
GEN_VXFORM(vsro, 6, 17);
A
aurel32 已提交
6315 6316
GEN_VXFORM(vaddcuw, 0, 6);
GEN_VXFORM(vsubcuw, 0, 22);
A
aurel32 已提交
6317 6318 6319
GEN_VXFORM(vrlb, 2, 0);
GEN_VXFORM(vrlh, 2, 1);
GEN_VXFORM(vrlw, 2, 2);
6320 6321 6322 6323 6324 6325 6326 6327
GEN_VXFORM(vpkuhum, 7, 0);
GEN_VXFORM(vpkuwum, 7, 1);
GEN_VXFORM(vpkuhus, 7, 2);
GEN_VXFORM(vpkuwus, 7, 3);
GEN_VXFORM(vpkshus, 7, 4);
GEN_VXFORM(vpkswus, 7, 5);
GEN_VXFORM(vpkshss, 7, 6);
GEN_VXFORM(vpkswss, 7, 7);
A
aurel32 已提交
6328
GEN_VXFORM(vpkpx, 7, 12);
A
aurel32 已提交
6329

6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344
#define GEN_VXFORM_NOA(name, opc2, opc3)                                \
    GEN_HANDLER(name, 0x04, opc2, opc3, 0x001f0000, PPC_ALTIVEC)        \
    {                                                                   \
        TCGv_ptr rb, rd;                                                \
        if (unlikely(!ctx->altivec_enabled)) {                          \
            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
            return;                                                     \
        }                                                               \
        rb = gen_avr_ptr(rB(ctx->opcode));                              \
        rd = gen_avr_ptr(rD(ctx->opcode));                              \
        gen_helper_##name (rd, rb);                                     \
        tcg_temp_free_ptr(rb);                                          \
        tcg_temp_free_ptr(rd);                                         \
    }

A
aurel32 已提交
6345 6346 6347 6348
GEN_VXFORM_NOA(vupkhsb, 7, 8);
GEN_VXFORM_NOA(vupkhsh, 7, 9);
GEN_VXFORM_NOA(vupklsb, 7, 10);
GEN_VXFORM_NOA(vupklsh, 7, 11);
A
aurel32 已提交
6349 6350 6351
GEN_VXFORM_NOA(vupkhpx, 7, 13);
GEN_VXFORM_NOA(vupklpx, 7, 15);

6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367
#define GEN_VXFORM_SIMM(name, opc2, opc3)                               \
    GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC)        \
    {                                                                   \
        TCGv_ptr rd;                                                    \
        TCGv_i32 simm;                                                  \
        if (unlikely(!ctx->altivec_enabled)) {                          \
            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
            return;                                                     \
        }                                                               \
        simm = tcg_const_i32(SIMM5(ctx->opcode));                       \
        rd = gen_avr_ptr(rD(ctx->opcode));                              \
        gen_helper_##name (rd, simm);                                   \
        tcg_temp_free_i32(simm);                                        \
        tcg_temp_free_ptr(rd);                                          \
    }

6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385
#define GEN_VXFORM_UIMM(name, opc2, opc3)                               \
    GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC)        \
    {                                                                   \
        TCGv_ptr rb, rd;                                                \
        TCGv_i32 uimm;                                                  \
        if (unlikely(!ctx->altivec_enabled)) {                          \
            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
            return;                                                     \
        }                                                               \
        uimm = tcg_const_i32(UIMM5(ctx->opcode));                       \
        rb = gen_avr_ptr(rB(ctx->opcode));                              \
        rd = gen_avr_ptr(rD(ctx->opcode));                              \
        gen_helper_##name (rd, rb, uimm);                               \
        tcg_temp_free_i32(uimm);                                        \
        tcg_temp_free_ptr(rb);                                          \
        tcg_temp_free_ptr(rd);                                          \
    }

A
aurel32 已提交
6386 6387 6388 6389
GEN_VXFORM_UIMM(vspltb, 6, 8);
GEN_VXFORM_UIMM(vsplth, 6, 9);
GEN_VXFORM_UIMM(vspltw, 6, 10);

A
aurel32 已提交
6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408
GEN_HANDLER(vsldoi, 0x04, 0x16, 0xFF, 0x00000400, PPC_ALTIVEC)
{
    TCGv_ptr ra, rb, rd;
    TCGv sh;
    if (unlikely(!ctx->altivec_enabled)) {
        gen_exception(ctx, POWERPC_EXCP_VPU);
        return;
    }
    ra = gen_avr_ptr(rA(ctx->opcode));
    rb = gen_avr_ptr(rB(ctx->opcode));
    rd = gen_avr_ptr(rD(ctx->opcode));
    sh = tcg_const_i32(VSH(ctx->opcode));
    gen_helper_vsldoi (rd, ra, rb, sh);
    tcg_temp_free_ptr(ra);
    tcg_temp_free_ptr(rb);
    tcg_temp_free_ptr(rd);
    tcg_temp_free(sh);
}

6409 6410 6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431
#define GEN_VAFORM_PAIRED(name0, name1, opc2)                           \
    GEN_HANDLER(name0##_##name1, 0x04, opc2, 0xFF, 0x00000000, PPC_ALTIVEC) \
    {                                                                   \
        TCGv_ptr ra, rb, rc, rd;                                        \
        if (unlikely(!ctx->altivec_enabled)) {                          \
            gen_exception(ctx, POWERPC_EXCP_VPU);                       \
            return;                                                     \
        }                                                               \
        ra = gen_avr_ptr(rA(ctx->opcode));                              \
        rb = gen_avr_ptr(rB(ctx->opcode));                              \
        rc = gen_avr_ptr(rC(ctx->opcode));                              \
        rd = gen_avr_ptr(rD(ctx->opcode));                              \
        if (Rc(ctx->opcode)) {                                          \
            gen_helper_##name1 (rd, ra, rb, rc);                        \
        } else {                                                        \
            gen_helper_##name0 (rd, ra, rb, rc);                        \
        }                                                               \
        tcg_temp_free_ptr(ra);                                          \
        tcg_temp_free_ptr(rb);                                          \
        tcg_temp_free_ptr(rc);                                          \
        tcg_temp_free_ptr(rd);                                          \
    }

A
aurel32 已提交
6432 6433
GEN_VAFORM_PAIRED(vmhaddshs, vmhraddshs, 16)

A
aurel32 已提交
6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451
GEN_HANDLER(vmladduhm, 0x04, 0x11, 0xFF, 0x00000000, PPC_ALTIVEC)
{
    TCGv_ptr ra, rb, rc, rd;
    if (unlikely(!ctx->altivec_enabled)) {
        gen_exception(ctx, POWERPC_EXCP_VPU);
        return;
    }
    ra = gen_avr_ptr(rA(ctx->opcode));
    rb = gen_avr_ptr(rB(ctx->opcode));
    rc = gen_avr_ptr(rC(ctx->opcode));
    rd = gen_avr_ptr(rD(ctx->opcode));
    gen_helper_vmladduhm(rd, ra, rb, rc);
    tcg_temp_free_ptr(ra);
    tcg_temp_free_ptr(rb);
    tcg_temp_free_ptr(rc);
    tcg_temp_free_ptr(rd);
}

A
aurel32 已提交
6452
GEN_VAFORM_PAIRED(vmsumubm, vmsummbm, 18)
A
aurel32 已提交
6453
GEN_VAFORM_PAIRED(vmsumuhm, vmsumuhs, 19)
A
aurel32 已提交
6454
GEN_VAFORM_PAIRED(vmsumshm, vmsumshs, 20)
A
aurel32 已提交
6455
GEN_VAFORM_PAIRED(vsel, vperm, 21)
A
aurel32 已提交
6456

6457 6458
/***                           SPE extension                               ***/
/* Register moves */
6459

P
pbrook 已提交
6460
static always_inline void gen_load_gpr64(TCGv_i64 t, int reg) {
A
aurel32 已提交
6461 6462 6463
#if defined(TARGET_PPC64)
    tcg_gen_mov_i64(t, cpu_gpr[reg]);
#else
P
pbrook 已提交
6464
    tcg_gen_concat_i32_i64(t, cpu_gpr[reg], cpu_gprh[reg]);
6465
#endif
A
aurel32 已提交
6466
}
6467

P
pbrook 已提交
6468
static always_inline void gen_store_gpr64(int reg, TCGv_i64 t) {
A
aurel32 已提交
6469 6470 6471
#if defined(TARGET_PPC64)
    tcg_gen_mov_i64(cpu_gpr[reg], t);
#else
P
pbrook 已提交
6472
    TCGv_i64 tmp = tcg_temp_new_i64();
A
aurel32 已提交
6473 6474 6475
    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 已提交
6476
    tcg_temp_free_i64(tmp);
6477
#endif
A
aurel32 已提交
6478
}
6479

6480 6481 6482 6483 6484 6485 6486 6487 6488 6489
#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 */
6490
static always_inline void gen_speundef (DisasContext *ctx)
6491
{
A
aurel32 已提交
6492
    gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
6493 6494
}

6495 6496 6497
/* SPE logic */
#if defined(TARGET_PPC64)
#define GEN_SPEOP_LOGIC2(name, tcg_op)                                        \
6498
static always_inline void gen_##name (DisasContext *ctx)                      \
6499 6500
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
6501
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6502 6503
        return;                                                               \
    }                                                                         \
6504 6505 6506 6507 6508 6509 6510 6511
    tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],                \
           cpu_gpr[rB(ctx->opcode)]);                                         \
}
#else
#define GEN_SPEOP_LOGIC2(name, tcg_op)                                        \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
6512
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6513 6514 6515 6516 6517 6518
        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)]);                                        \
6519
}
6520 6521 6522 6523 6524 6525 6526 6527 6528 6529
#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);
6530

6531 6532 6533
/* SPE logic immediate */
#if defined(TARGET_PPC64)
#define GEN_SPEOP_TCG_LOGIC_IMM2(name, tcg_opi)                               \
6534 6535 6536
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
6537
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6538 6539
        return;                                                               \
    }                                                                         \
P
pbrook 已提交
6540 6541 6542
    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
    TCGv_i64 t2 = tcg_temp_local_new_i64();                                   \
6543 6544 6545 6546
    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 已提交
6547
    tcg_temp_free_i64(t2);                                                    \
6548 6549
    tcg_opi(t1, t1, rB(ctx->opcode));                                         \
    tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1);                 \
P
pbrook 已提交
6550 6551
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
6552
}
6553 6554
#else
#define GEN_SPEOP_TCG_LOGIC_IMM2(name, tcg_opi)                               \
6555
static always_inline void gen_##name (DisasContext *ctx)                      \
6556 6557
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
6558
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6559 6560
        return;                                                               \
    }                                                                         \
6561 6562 6563 6564
    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));                                                 \
6565
}
6566 6567 6568 6569 6570
#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);
6571

6572 6573 6574
/* SPE arithmetic */
#if defined(TARGET_PPC64)
#define GEN_SPEOP_ARITH1(name, tcg_op)                                        \
6575
static always_inline void gen_##name (DisasContext *ctx)                      \
6576 6577
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
6578
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6579 6580
        return;                                                               \
    }                                                                         \
P
pbrook 已提交
6581 6582 6583
    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
    TCGv_i64 t2 = tcg_temp_local_new_i64();                                   \
6584 6585 6586 6587
    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 已提交
6588
    tcg_temp_free_i64(t2);                                                    \
6589 6590
    tcg_op(t1, t1);                                                           \
    tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1);                 \
P
pbrook 已提交
6591 6592
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
6593
}
6594
#else
P
pbrook 已提交
6595
#define GEN_SPEOP_ARITH1(name, tcg_op)                                        \
6596 6597 6598
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
6599
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6600 6601 6602 6603 6604 6605
        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
6606

P
pbrook 已提交
6607
static always_inline void gen_op_evabs (TCGv_i32 ret, TCGv_i32 arg1)
6608 6609 6610
{
    int l1 = gen_new_label();
    int l2 = gen_new_label();
6611

6612 6613 6614 6615
    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 已提交
6616
    tcg_gen_mov_i32(ret, arg1);
6617 6618 6619 6620 6621 6622
    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 已提交
6623
static always_inline void gen_op_evrndw (TCGv_i32 ret, TCGv_i32 arg1)
6624
{
6625 6626 6627 6628
    tcg_gen_addi_i32(ret, arg1, 0x8000);
    tcg_gen_ext16u_i32(ret, ret);
}
GEN_SPEOP_ARITH1(evrndw, gen_op_evrndw);
P
pbrook 已提交
6629 6630
GEN_SPEOP_ARITH1(evcntlsw, gen_helper_cntlsw32);
GEN_SPEOP_ARITH1(evcntlzw, gen_helper_cntlzw32);
6631

6632 6633 6634
#if defined(TARGET_PPC64)
#define GEN_SPEOP_ARITH2(name, tcg_op)                                        \
static always_inline void gen_##name (DisasContext *ctx)                      \
6635 6636
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
6637
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6638 6639
        return;                                                               \
    }                                                                         \
P
pbrook 已提交
6640 6641 6642
    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t2 = tcg_temp_local_new_i32();                                   \
6643
    TCGv_i64 t3 = tcg_temp_local_new_i64();                                   \
6644 6645 6646 6647 6648 6649 6650
    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 已提交
6651
    tcg_temp_free_i64(t3);                                                    \
6652
    tcg_op(t1, t1, t2);                                                       \
P
pbrook 已提交
6653
    tcg_temp_free_i32(t2);                                                    \
6654
    tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1);                 \
P
pbrook 已提交
6655 6656
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
6657
}
6658 6659 6660
#else
#define GEN_SPEOP_ARITH2(name, tcg_op)                                        \
static always_inline void gen_##name (DisasContext *ctx)                      \
6661 6662
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
6663
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6664 6665
        return;                                                               \
    }                                                                         \
6666 6667 6668 6669
    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)]);                                        \
6670
}
6671
#endif
6672

P
pbrook 已提交
6673
static always_inline void gen_op_evsrwu (TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
6674
{
P
pbrook 已提交
6675
    TCGv_i32 t0;
6676
    int l1, l2;
6677

6678 6679
    l1 = gen_new_label();
    l2 = gen_new_label();
P
pbrook 已提交
6680
    t0 = tcg_temp_local_new_i32();
6681 6682 6683 6684 6685 6686 6687 6688
    /* 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 已提交
6689
    tcg_temp_free_i32(t0);
6690 6691
}
GEN_SPEOP_ARITH2(evsrwu, gen_op_evsrwu);
P
pbrook 已提交
6692
static always_inline void gen_op_evsrws (TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
6693
{
P
pbrook 已提交
6694
    TCGv_i32 t0;
6695 6696 6697 6698
    int l1, l2;

    l1 = gen_new_label();
    l2 = gen_new_label();
P
pbrook 已提交
6699
    t0 = tcg_temp_local_new_i32();
6700 6701 6702 6703 6704 6705 6706 6707
    /* 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 已提交
6708
    tcg_temp_free_i32(t0);
6709 6710
}
GEN_SPEOP_ARITH2(evsrws, gen_op_evsrws);
P
pbrook 已提交
6711
static always_inline void gen_op_evslw (TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
6712
{
P
pbrook 已提交
6713
    TCGv_i32 t0;
6714 6715 6716 6717
    int l1, l2;

    l1 = gen_new_label();
    l2 = gen_new_label();
P
pbrook 已提交
6718
    t0 = tcg_temp_local_new_i32();
6719 6720 6721 6722 6723 6724 6725 6726
    /* 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 已提交
6727
    tcg_temp_free_i32(t0);
6728 6729
}
GEN_SPEOP_ARITH2(evslw, gen_op_evslw);
P
pbrook 已提交
6730
static always_inline void gen_op_evrlw (TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
6731
{
P
pbrook 已提交
6732
    TCGv_i32 t0 = tcg_temp_new_i32();
6733 6734
    tcg_gen_andi_i32(t0, arg2, 0x1F);
    tcg_gen_rotl_i32(ret, arg1, t0);
P
pbrook 已提交
6735
    tcg_temp_free_i32(t0);
6736 6737 6738 6739 6740
}
GEN_SPEOP_ARITH2(evrlw, gen_op_evrlw);
static always_inline void gen_evmergehi (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
A
aurel32 已提交
6741
        gen_exception(ctx, POWERPC_EXCP_APU);
6742 6743 6744
        return;
    }
#if defined(TARGET_PPC64)
P
pbrook 已提交
6745 6746
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
6747 6748 6749 6750 6751 6752 6753 6754 6755 6756 6757
    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 已提交
6758
static always_inline void gen_op_evsubf (TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
6759
{
6760 6761 6762
    tcg_gen_sub_i32(ret, arg2, arg1);
}
GEN_SPEOP_ARITH2(evsubfw, gen_op_evsubf);
6763

6764 6765 6766 6767 6768 6769
/* SPE arithmetic immediate */
#if defined(TARGET_PPC64)
#define GEN_SPEOP_ARITH_IMM2(name, tcg_op)                                    \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
6770
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6771 6772
        return;                                                               \
    }                                                                         \
P
pbrook 已提交
6773 6774 6775
    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
    TCGv_i64 t2 = tcg_temp_local_new_i64();                                   \
6776 6777 6778 6779
    tcg_gen_trunc_i64_i32(t0, cpu_gpr[rB(ctx->opcode)]);                      \
    tcg_op(t0, t0, rA(ctx->opcode));                                          \
    tcg_gen_shri_i64(t2, cpu_gpr[rB(ctx->opcode)], 32);                       \
    tcg_gen_trunc_i64_i32(t1, t2);                                            \
A
aurel32 已提交
6780
    tcg_temp_free_i64(t2);                                                    \
6781 6782
    tcg_op(t1, t1, rA(ctx->opcode));                                          \
    tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1);                 \
P
pbrook 已提交
6783 6784
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
6785 6786 6787 6788 6789 6790
}
#else
#define GEN_SPEOP_ARITH_IMM2(name, tcg_op)                                    \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
6791
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6792 6793 6794 6795 6796 6797 6798 6799 6800 6801 6802 6803 6804 6805 6806 6807 6808
        return;                                                               \
    }                                                                         \
    tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],                \
           rA(ctx->opcode));                                                  \
    tcg_op(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)],              \
           rA(ctx->opcode));                                                  \
}
#endif
GEN_SPEOP_ARITH_IMM2(evaddiw, tcg_gen_addi_i32);
GEN_SPEOP_ARITH_IMM2(evsubifw, tcg_gen_subi_i32);

/* SPE comparison */
#if defined(TARGET_PPC64)
#define GEN_SPEOP_COMP(name, tcg_cond)                                        \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
6809
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6810 6811 6812 6813 6814 6815
        return;                                                               \
    }                                                                         \
    int l1 = gen_new_label();                                                 \
    int l2 = gen_new_label();                                                 \
    int l3 = gen_new_label();                                                 \
    int l4 = gen_new_label();                                                 \
P
pbrook 已提交
6816 6817 6818
    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
    TCGv_i64 t2 = tcg_temp_local_new_i64();                                   \
6819 6820 6821
    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 已提交
6822
    tcg_gen_movi_i32(cpu_crf[crfD(ctx->opcode)], 0);                          \
6823 6824 6825 6826 6827 6828 6829 6830 6831
    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 已提交
6832
    tcg_temp_free_i64(t2);                                                    \
6833 6834 6835 6836 6837 6838 6839 6840
    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 已提交
6841 6842
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
6843 6844 6845 6846 6847 6848
}
#else
#define GEN_SPEOP_COMP(name, tcg_cond)                                        \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
6849
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
6850 6851 6852 6853 6854 6855 6856 6857 6858 6859 6860 6861 6862 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877 6878 6879 6880 6881 6882 6883 6884 6885
        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 已提交
6886 6887
    gen_helper_brinc(cpu_gpr[rD(ctx->opcode)],
                     cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
6888
}
6889 6890 6891
static always_inline void gen_evmergelo (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
A
aurel32 已提交
6892
        gen_exception(ctx, POWERPC_EXCP_APU);
6893 6894 6895
        return;
    }
#if defined(TARGET_PPC64)
P
pbrook 已提交
6896 6897
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
6898 6899 6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x00000000FFFFFFFFLL);
    tcg_gen_shli_tl(t1, cpu_gpr[rA(ctx->opcode)], 32);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], t0, t1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
#else
    tcg_gen_mov_i32(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
    tcg_gen_mov_i32(cpu_gprh[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
#endif
}
static always_inline void gen_evmergehilo (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
A
aurel32 已提交
6911
        gen_exception(ctx, POWERPC_EXCP_APU);
6912 6913 6914
        return;
    }
#if defined(TARGET_PPC64)
P
pbrook 已提交
6915 6916
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
6917 6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 6928 6929
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x00000000FFFFFFFFLL);
    tcg_gen_andi_tl(t1, cpu_gpr[rA(ctx->opcode)], 0xFFFFFFFF0000000ULL);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], t0, t1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
#else
    tcg_gen_mov_i32(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
    tcg_gen_mov_i32(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]);
#endif
}
static always_inline void gen_evmergelohi (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
A
aurel32 已提交
6930
        gen_exception(ctx, POWERPC_EXCP_APU);
6931 6932 6933
        return;
    }
#if defined(TARGET_PPC64)
P
pbrook 已提交
6934 6935
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
6936 6937 6938 6939 6940 6941 6942 6943 6944 6945 6946 6947
    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)
{
6948
    uint64_t imm = ((int32_t)(rA(ctx->opcode) << 11)) >> 27;
6949

6950
#if defined(TARGET_PPC64)
6951
    tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], (imm << 32) | imm);
6952 6953 6954 6955 6956
#else
    tcg_gen_movi_i32(cpu_gpr[rD(ctx->opcode)], imm);
    tcg_gen_movi_i32(cpu_gprh[rD(ctx->opcode)], imm);
#endif
}
6957
static always_inline void gen_evsplatfi (DisasContext *ctx)
6958
{
6959
    uint64_t imm = rA(ctx->opcode) << 11;
6960

6961
#if defined(TARGET_PPC64)
6962
    tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], (imm << 32) | imm);
6963 6964 6965 6966
#else
    tcg_gen_movi_i32(cpu_gpr[rD(ctx->opcode)], imm);
    tcg_gen_movi_i32(cpu_gprh[rD(ctx->opcode)], imm);
#endif
6967 6968
}

6969 6970 6971 6972 6973 6974
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 已提交
6975
    TCGv_i32 t0 = tcg_temp_local_new_i32();
6976
#if defined(TARGET_PPC64)
P
pbrook 已提交
6977 6978
    TCGv t1 = tcg_temp_local_new();
    TCGv t2 = tcg_temp_local_new();
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
#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 已提交
7010
    tcg_temp_free_i32(t0);
7011 7012 7013 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 7028 7029 7030 7031 7032
#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);
}
7033 7034 7035 7036 7037 7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7058 7059

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

7060
/* SPE load and stores */
A
aurel32 已提交
7061
static always_inline void gen_addr_spe_imm_index (DisasContext *ctx, TCGv EA, int sh)
7062 7063 7064
{
    target_ulong uimm = rB(ctx->opcode);

A
aurel32 已提交
7065
    if (rA(ctx->opcode) == 0) {
7066
        tcg_gen_movi_tl(EA, uimm << sh);
A
aurel32 已提交
7067
    } else {
7068
        tcg_gen_addi_tl(EA, cpu_gpr[rA(ctx->opcode)], uimm << sh);
A
aurel32 已提交
7069 7070 7071 7072 7073 7074
#if defined(TARGET_PPC64)
        if (!ctx->sf_mode) {
            tcg_gen_ext32u_tl(EA, EA);
        }
#endif
    }
7075
}
7076 7077 7078 7079

static always_inline void gen_op_evldd(DisasContext *ctx, TCGv addr)
{
#if defined(TARGET_PPC64)
A
aurel32 已提交
7080
    gen_qemu_ld64(ctx, cpu_gpr[rD(ctx->opcode)], addr);
7081 7082
#else
    TCGv_i64 t0 = tcg_temp_new_i64();
A
aurel32 已提交
7083
    gen_qemu_ld64(ctx, t0, addr);
7084 7085 7086 7087 7088
    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
7089
}
7090 7091 7092

static always_inline void gen_op_evldw(DisasContext *ctx, TCGv addr)
{
7093
#if defined(TARGET_PPC64)
7094
    TCGv t0 = tcg_temp_new();
A
aurel32 已提交
7095
    gen_qemu_ld32u(ctx, t0, addr);
7096
    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 32);
A
aurel32 已提交
7097 7098
    gen_addr_add(ctx, addr, addr, 4);
    gen_qemu_ld32u(ctx, t0, addr);
7099 7100 7101
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
    tcg_temp_free(t0);
#else
A
aurel32 已提交
7102 7103 7104
    gen_qemu_ld32u(ctx, cpu_gprh[rD(ctx->opcode)], addr);
    gen_addr_add(ctx, addr, addr, 4);
    gen_qemu_ld32u(ctx, cpu_gpr[rD(ctx->opcode)], addr);
7105
#endif
7106
}
7107 7108 7109 7110 7111

static always_inline void gen_op_evldh(DisasContext *ctx, TCGv addr)
{
    TCGv t0 = tcg_temp_new();
#if defined(TARGET_PPC64)
A
aurel32 已提交
7112
    gen_qemu_ld16u(ctx, t0, addr);
7113
    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 48);
A
aurel32 已提交
7114 7115
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, t0, addr);
7116 7117
    tcg_gen_shli_tl(t0, t0, 32);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
A
aurel32 已提交
7118 7119
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, t0, addr);
7120 7121
    tcg_gen_shli_tl(t0, t0, 16);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
A
aurel32 已提交
7122 7123
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, t0, addr);
7124
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
7125
#else
A
aurel32 已提交
7126
    gen_qemu_ld16u(ctx, t0, addr);
7127
    tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16);
A
aurel32 已提交
7128 7129
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, t0, addr);
7130
    tcg_gen_or_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rD(ctx->opcode)], t0);
A
aurel32 已提交
7131 7132
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, t0, addr);
7133
    tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16);
A
aurel32 已提交
7134 7135
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, t0, addr);
7136
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
7137
#endif
7138
    tcg_temp_free(t0);
7139 7140
}

7141 7142 7143
static always_inline void gen_op_evlhhesplat(DisasContext *ctx, TCGv addr)
{
    TCGv t0 = tcg_temp_new();
A
aurel32 已提交
7144
    gen_qemu_ld16u(ctx, t0, addr);
7145 7146 7147 7148 7149 7150 7151 7152 7153 7154
#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);
7155 7156
}

7157 7158 7159
static always_inline void gen_op_evlhhousplat(DisasContext *ctx, TCGv addr)
{
    TCGv t0 = tcg_temp_new();
A
aurel32 已提交
7160
    gen_qemu_ld16u(ctx, t0, addr);
7161 7162 7163 7164 7165 7166 7167 7168
#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);
7169 7170
}

7171 7172 7173
static always_inline void gen_op_evlhhossplat(DisasContext *ctx, TCGv addr)
{
    TCGv t0 = tcg_temp_new();
A
aurel32 已提交
7174
    gen_qemu_ld16s(ctx, t0, addr);
7175 7176 7177 7178 7179 7180 7181 7182 7183 7184 7185 7186 7187 7188 7189
#if defined(TARGET_PPC64)
    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 32);
    tcg_gen_ext32u_tl(t0, t0);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
#else
    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0);
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0);
#endif
    tcg_temp_free(t0);
}

static always_inline void gen_op_evlwhe(DisasContext *ctx, TCGv addr)
{
    TCGv t0 = tcg_temp_new();
#if defined(TARGET_PPC64)
A
aurel32 已提交
7190
    gen_qemu_ld16u(ctx, t0, addr);
7191
    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 48);
A
aurel32 已提交
7192 7193
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, t0, addr);
7194 7195 7196
    tcg_gen_shli_tl(t0, t0, 16);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
#else
A
aurel32 已提交
7197
    gen_qemu_ld16u(ctx, t0, addr);
7198
    tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16);
A
aurel32 已提交
7199 7200
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, t0, addr);
7201 7202 7203 7204 7205 7206 7207 7208 7209
    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 16);
#endif
    tcg_temp_free(t0);
}

static always_inline void gen_op_evlwhou(DisasContext *ctx, TCGv addr)
{
#if defined(TARGET_PPC64)
    TCGv t0 = tcg_temp_new();
A
aurel32 已提交
7210 7211 7212
    gen_qemu_ld16u(ctx, cpu_gpr[rD(ctx->opcode)], addr);
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, t0, addr);
7213 7214 7215 7216
    tcg_gen_shli_tl(t0, t0, 32);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
    tcg_temp_free(t0);
#else
A
aurel32 已提交
7217 7218 7219
    gen_qemu_ld16u(ctx, cpu_gprh[rD(ctx->opcode)], addr);
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, cpu_gpr[rD(ctx->opcode)], addr);
7220 7221 7222 7223 7224 7225 7226
#endif
}

static always_inline void gen_op_evlwhos(DisasContext *ctx, TCGv addr)
{
#if defined(TARGET_PPC64)
    TCGv t0 = tcg_temp_new();
A
aurel32 已提交
7227
    gen_qemu_ld16s(ctx, t0, addr);
7228
    tcg_gen_ext32u_tl(cpu_gpr[rD(ctx->opcode)], t0);
A
aurel32 已提交
7229 7230
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16s(ctx, t0, addr);
7231 7232 7233 7234
    tcg_gen_shli_tl(t0, t0, 32);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
    tcg_temp_free(t0);
#else
A
aurel32 已提交
7235 7236 7237
    gen_qemu_ld16s(ctx, cpu_gprh[rD(ctx->opcode)], addr);
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16s(ctx, cpu_gpr[rD(ctx->opcode)], addr);
7238 7239 7240 7241 7242 7243
#endif
}

static always_inline void gen_op_evlwwsplat(DisasContext *ctx, TCGv addr)
{
    TCGv t0 = tcg_temp_new();
A
aurel32 已提交
7244
    gen_qemu_ld32u(ctx, t0, addr);
7245
#if defined(TARGET_PPC64)
7246 7247 7248 7249 7250 7251 7252 7253 7254 7255 7256 7257 7258
    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 32);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
#else
    tcg_gen_mov_tl(cpu_gprh[rD(ctx->opcode)], t0);
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0);
#endif
    tcg_temp_free(t0);
}

static always_inline void gen_op_evlwhsplat(DisasContext *ctx, TCGv addr)
{
    TCGv t0 = tcg_temp_new();
#if defined(TARGET_PPC64)
A
aurel32 已提交
7259
    gen_qemu_ld16u(ctx, t0, addr);
7260 7261 7262
    tcg_gen_shli_tl(cpu_gpr[rD(ctx->opcode)], t0, 48);
    tcg_gen_shli_tl(t0, t0, 32);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
A
aurel32 已提交
7263 7264
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, t0, addr);
7265 7266 7267 7268
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
    tcg_gen_shli_tl(t0, t0, 16);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rD(ctx->opcode)], t0);
#else
A
aurel32 已提交
7269
    gen_qemu_ld16u(ctx, t0, addr);
7270 7271
    tcg_gen_shli_tl(cpu_gprh[rD(ctx->opcode)], t0, 16);
    tcg_gen_or_tl(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rD(ctx->opcode)], t0);
A
aurel32 已提交
7272 7273
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_ld16u(ctx, t0, addr);
7274 7275
    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);
7276
#endif
7277 7278 7279 7280 7281 7282
    tcg_temp_free(t0);
}

static always_inline void gen_op_evstdd(DisasContext *ctx, TCGv addr)
{
#if defined(TARGET_PPC64)
A
aurel32 已提交
7283
    gen_qemu_st64(ctx, cpu_gpr[rS(ctx->opcode)], addr);
7284
#else
7285 7286
    TCGv_i64 t0 = tcg_temp_new_i64();
    tcg_gen_concat_i32_i64(t0, cpu_gpr[rS(ctx->opcode)], cpu_gprh[rS(ctx->opcode)]);
A
aurel32 已提交
7287
    gen_qemu_st64(ctx, t0, addr);
7288 7289 7290 7291 7292 7293
    tcg_temp_free_i64(t0);
#endif
}

static always_inline void gen_op_evstdw(DisasContext *ctx, TCGv addr)
{
7294
#if defined(TARGET_PPC64)
7295 7296
    TCGv t0 = tcg_temp_new();
    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 32);
A
aurel32 已提交
7297
    gen_qemu_st32(ctx, t0, addr);
7298 7299
    tcg_temp_free(t0);
#else
A
aurel32 已提交
7300
    gen_qemu_st32(ctx, cpu_gprh[rS(ctx->opcode)], addr);
7301
#endif
A
aurel32 已提交
7302 7303
    gen_addr_add(ctx, addr, addr, 4);
    gen_qemu_st32(ctx, cpu_gpr[rS(ctx->opcode)], addr);
7304 7305 7306 7307 7308 7309 7310 7311 7312 7313
}

static always_inline void gen_op_evstdh(DisasContext *ctx, TCGv addr)
{
    TCGv t0 = tcg_temp_new();
#if defined(TARGET_PPC64)
    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 48);
#else
    tcg_gen_shri_tl(t0, cpu_gprh[rS(ctx->opcode)], 16);
#endif
A
aurel32 已提交
7314 7315
    gen_qemu_st16(ctx, t0, addr);
    gen_addr_add(ctx, addr, addr, 2);
7316 7317
#if defined(TARGET_PPC64)
    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 32);
A
aurel32 已提交
7318
    gen_qemu_st16(ctx, t0, addr);
7319
#else
A
aurel32 已提交
7320
    gen_qemu_st16(ctx, cpu_gprh[rS(ctx->opcode)], addr);
7321
#endif
A
aurel32 已提交
7322
    gen_addr_add(ctx, addr, addr, 2);
7323
    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 16);
A
aurel32 已提交
7324
    gen_qemu_st16(ctx, t0, addr);
7325
    tcg_temp_free(t0);
A
aurel32 已提交
7326 7327
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_st16(ctx, cpu_gpr[rS(ctx->opcode)], addr);
7328 7329 7330 7331 7332 7333 7334 7335 7336 7337
}

static always_inline void gen_op_evstwhe(DisasContext *ctx, TCGv addr)
{
    TCGv t0 = tcg_temp_new();
#if defined(TARGET_PPC64)
    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 48);
#else
    tcg_gen_shri_tl(t0, cpu_gprh[rS(ctx->opcode)], 16);
#endif
A
aurel32 已提交
7338 7339
    gen_qemu_st16(ctx, t0, addr);
    gen_addr_add(ctx, addr, addr, 2);
7340
    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 16);
A
aurel32 已提交
7341
    gen_qemu_st16(ctx, t0, addr);
7342 7343 7344 7345 7346 7347 7348 7349
    tcg_temp_free(t0);
}

static always_inline void gen_op_evstwho(DisasContext *ctx, TCGv addr)
{
#if defined(TARGET_PPC64)
    TCGv t0 = tcg_temp_new();
    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 32);
A
aurel32 已提交
7350
    gen_qemu_st16(ctx, t0, addr);
7351 7352
    tcg_temp_free(t0);
#else
A
aurel32 已提交
7353
    gen_qemu_st16(ctx, cpu_gprh[rS(ctx->opcode)], addr);
7354
#endif
A
aurel32 已提交
7355 7356
    gen_addr_add(ctx, addr, addr, 2);
    gen_qemu_st16(ctx, cpu_gpr[rS(ctx->opcode)], addr);
7357 7358 7359 7360 7361 7362 7363
}

static always_inline void gen_op_evstwwe(DisasContext *ctx, TCGv addr)
{
#if defined(TARGET_PPC64)
    TCGv t0 = tcg_temp_new();
    tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], 32);
A
aurel32 已提交
7364
    gen_qemu_st32(ctx, t0, addr);
7365 7366
    tcg_temp_free(t0);
#else
A
aurel32 已提交
7367
    gen_qemu_st32(ctx, cpu_gprh[rS(ctx->opcode)], addr);
7368 7369 7370 7371 7372
#endif
}

static always_inline void gen_op_evstwwo(DisasContext *ctx, TCGv addr)
{
A
aurel32 已提交
7373
    gen_qemu_st32(ctx, cpu_gpr[rS(ctx->opcode)], addr);
7374 7375 7376
}

#define GEN_SPEOP_LDST(name, opc2, sh)                                        \
A
aurel32 已提交
7377
GEN_HANDLER(name, 0x04, opc2, 0x0C, 0x00000000, PPC_SPE)                      \
7378 7379 7380
{                                                                             \
    TCGv t0;                                                                  \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
7381
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
7382 7383
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
7384
    gen_set_access_type(ctx, ACCESS_INT);                                     \
7385 7386
    t0 = tcg_temp_new();                                                      \
    if (Rc(ctx->opcode)) {                                                    \
A
aurel32 已提交
7387
        gen_addr_spe_imm_index(ctx, t0, sh);                                  \
7388
    } else {                                                                  \
A
aurel32 已提交
7389
        gen_addr_reg_index(ctx, t0);                                          \
7390 7391 7392 7393 7394 7395 7396 7397 7398 7399 7400 7401 7402 7403 7404 7405 7406 7407 7408 7409 7410 7411 7412 7413
    }                                                                         \
    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);
7414 7415 7416 7417 7418 7419 7420 7421 7422 7423 7424 7425 7426 7427 7428 7429 7430 7431 7432 7433 7434 7435 7436 7437 7438 7439 7440 7441 7442 7443 7444 7445 7446 7447 7448 7449 7450 7451 7452 7453 7454 7455 7456 7457 7458 7459 7460 7461 7462 7463 7464 7465 7466 7467 7468 7469 7470 7471 7472 7473 7474 7475 7476 7477 7478 7479 7480 7481 7482 7483 7484 7485 7486 7487 7488 7489 7490 7491

/* 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 已提交
7492 7493
#if defined(TARGET_PPC64)
#define GEN_SPEFPUOP_CONV_32_32(name)                                         \
7494
static always_inline void gen_##name (DisasContext *ctx)                      \
7495
{                                                                             \
A
aurel32 已提交
7496 7497 7498 7499 7500 7501 7502 7503 7504 7505 7506 7507
    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);                                                        \
7508
}
A
aurel32 已提交
7509 7510 7511 7512 7513 7514 7515 7516 7517 7518 7519 7520 7521 7522 7523 7524 7525 7526 7527 7528 7529 7530 7531 7532 7533 7534 7535 7536 7537
#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)                                       \
7538 7539
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
A
aurel32 已提交
7540 7541
    TCGv_i32 t0, t1;                                                          \
    TCGv_i64 t2;                                                              \
7542
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
7543
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
7544 7545
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
7546 7547 7548 7549 7550 7551 7552 7553 7554 7555 7556 7557 7558
    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);                                                        \
7559
}
A
aurel32 已提交
7560
#define GEN_SPEFPUOP_ARITH2_64_64(name)                                       \
7561 7562 7563
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
7564
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
7565 7566
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
7567 7568
    gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],     \
                      cpu_gpr[rB(ctx->opcode)]);                              \
7569
}
A
aurel32 已提交
7570
#define GEN_SPEFPUOP_COMP_32(name)                                            \
7571 7572
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
A
aurel32 已提交
7573
    TCGv_i32 t0, t1;                                                          \
7574
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
7575
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
7576 7577
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
7578 7579 7580 7581 7582 7583 7584 7585 7586 7587 7588 7589
    t0 = tcg_temp_new_i32();                                                  \
    t1 = tcg_temp_new_i32();                                                  \
    tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]);                       \
    tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]);                       \
    gen_helper_##name(cpu_crf[crfD(ctx->opcode)], t0, t1);                    \
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
}
#define GEN_SPEFPUOP_COMP_64(name)                                            \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
7590
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
A
aurel32 已提交
7591 7592 7593 7594 7595 7596 7597 7598 7599 7600
        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)]);    \
7601
}
A
aurel32 已提交
7602 7603 7604 7605 7606 7607 7608 7609 7610 7611 7612 7613 7614 7615 7616 7617 7618 7619 7620 7621 7622 7623 7624 7625 7626 7627 7628 7629 7630
#define GEN_SPEFPUOP_CONV_32_64(name)                                         \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    TCGv_i64 t0 = tcg_temp_new_i64();                                         \
    gen_load_gpr64(t0, rB(ctx->opcode));                                      \
    gen_helper_##name(cpu_gpr[rD(ctx->opcode)], t0);                          \
    tcg_temp_free_i64(t0);                                                    \
}
#define GEN_SPEFPUOP_CONV_64_32(name)                                         \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    TCGv_i64 t0 = tcg_temp_new_i64();                                         \
    gen_helper_##name(t0, cpu_gpr[rB(ctx->opcode)]);                          \
    gen_store_gpr64(rD(ctx->opcode), t0);                                     \
    tcg_temp_free_i64(t0);                                                    \
}
#define GEN_SPEFPUOP_CONV_64_64(name)                                         \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    TCGv_i64 t0 = tcg_temp_new_i64();                                         \
    gen_load_gpr64(t0, rB(ctx->opcode));                                      \
    gen_helper_##name(t0, t0);                                                \
    gen_store_gpr64(rD(ctx->opcode), t0);                                     \
    tcg_temp_free_i64(t0);                                                    \
}
#define GEN_SPEFPUOP_ARITH2_32_32(name)                                       \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
7631
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
A
aurel32 已提交
7632 7633 7634 7635 7636 7637 7638 7639 7640 7641
        return;                                                               \
    }                                                                         \
    gen_helper_##name(cpu_gpr[rD(ctx->opcode)],                               \
                      cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);    \
}
#define GEN_SPEFPUOP_ARITH2_64_64(name)                                       \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    TCGv_i64 t0, t1;                                                          \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
7642
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
A
aurel32 已提交
7643 7644 7645 7646 7647 7648 7649 7650 7651 7652 7653 7654 7655 7656 7657
        return;                                                               \
    }                                                                         \
    t0 = tcg_temp_new_i64();                                                  \
    t1 = tcg_temp_new_i64();                                                  \
    gen_load_gpr64(t0, rA(ctx->opcode));                                      \
    gen_load_gpr64(t1, rB(ctx->opcode));                                      \
    gen_helper_##name(t0, t0, t1);                                            \
    gen_store_gpr64(rD(ctx->opcode), t0);                                     \
    tcg_temp_free_i64(t0);                                                    \
    tcg_temp_free_i64(t1);                                                    \
}
#define GEN_SPEFPUOP_COMP_32(name)                                            \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
7658
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
A
aurel32 已提交
7659 7660 7661 7662 7663 7664 7665 7666 7667 7668
        return;                                                               \
    }                                                                         \
    gen_helper_##name(cpu_crf[crfD(ctx->opcode)],                             \
                      cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);    \
}
#define GEN_SPEFPUOP_COMP_64(name)                                            \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    TCGv_i64 t0, t1;                                                          \
    if (unlikely(!ctx->spe_enabled)) {                                        \
A
aurel32 已提交
7669
        gen_exception(ctx, POWERPC_EXCP_APU);                                 \
A
aurel32 已提交
7670 7671 7672 7673 7674 7675 7676 7677 7678 7679 7680
        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
7681

7682 7683
/* Single precision floating-point vectors operations */
/* Arithmetic */
A
aurel32 已提交
7684 7685 7686 7687 7688 7689 7690
GEN_SPEFPUOP_ARITH2_64_64(evfsadd);
GEN_SPEFPUOP_ARITH2_64_64(evfssub);
GEN_SPEFPUOP_ARITH2_64_64(evfsmul);
GEN_SPEFPUOP_ARITH2_64_64(evfsdiv);
static always_inline void gen_evfsabs (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
A
aurel32 已提交
7691
        gen_exception(ctx, POWERPC_EXCP_APU);
A
aurel32 已提交
7692 7693 7694 7695 7696 7697 7698 7699 7700 7701 7702 7703
        return;
    }
#if defined(TARGET_PPC64)
    tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~0x8000000080000000LL);
#else
    tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~0x80000000);
    tcg_gen_andi_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], ~0x80000000);
#endif
}
static always_inline void gen_evfsnabs (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
A
aurel32 已提交
7704
        gen_exception(ctx, POWERPC_EXCP_APU);
A
aurel32 已提交
7705 7706 7707 7708 7709 7710 7711 7712 7713 7714 7715 7716
        return;
    }
#if defined(TARGET_PPC64)
    tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000080000000LL);
#else
    tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
    tcg_gen_ori_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000);
#endif
}
static always_inline void gen_evfsneg (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
A
aurel32 已提交
7717
        gen_exception(ctx, POWERPC_EXCP_APU);
A
aurel32 已提交
7718 7719 7720 7721 7722 7723 7724 7725 7726 7727
        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
}

7728
/* Conversion */
A
aurel32 已提交
7729 7730 7731 7732 7733 7734 7735 7736 7737 7738 7739
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);

7740
/* Comparison */
A
aurel32 已提交
7741 7742 7743 7744 7745 7746
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);
7747 7748 7749 7750 7751 7752 7753 7754 7755 7756 7757 7758 7759 7760 7761 7762 7763 7764 7765

/* 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 已提交
7766 7767 7768 7769 7770 7771 7772
GEN_SPEFPUOP_ARITH2_32_32(efsadd);
GEN_SPEFPUOP_ARITH2_32_32(efssub);
GEN_SPEFPUOP_ARITH2_32_32(efsmul);
GEN_SPEFPUOP_ARITH2_32_32(efsdiv);
static always_inline void gen_efsabs (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
A
aurel32 已提交
7773
        gen_exception(ctx, POWERPC_EXCP_APU);
A
aurel32 已提交
7774 7775 7776 7777 7778 7779 7780
        return;
    }
    tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], (target_long)~0x80000000LL);
}
static always_inline void gen_efsnabs (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
A
aurel32 已提交
7781
        gen_exception(ctx, POWERPC_EXCP_APU);
A
aurel32 已提交
7782 7783 7784 7785 7786 7787 7788
        return;
    }
    tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
}
static always_inline void gen_efsneg (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
A
aurel32 已提交
7789
        gen_exception(ctx, POWERPC_EXCP_APU);
A
aurel32 已提交
7790 7791 7792 7793 7794
        return;
    }
    tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
}

7795
/* Conversion */
A
aurel32 已提交
7796 7797 7798 7799 7800 7801 7802 7803 7804 7805 7806 7807
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);

7808
/* Comparison */
A
aurel32 已提交
7809 7810 7811 7812 7813 7814
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);
7815 7816

/* Opcodes definitions */
7817
GEN_SPE(efsadd,         efssub,        0x00, 0x0B, 0x00000000, PPC_SPEFPU); //
7818 7819 7820 7821 7822 7823 7824 7825 7826
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); //
7827 7828
GEN_SPE(efsctuiz,       speundef,      0x0C, 0x0B, 0x00180000, PPC_SPEFPU); //
GEN_SPE(efsctsiz,       speundef,      0x0D, 0x0B, 0x00180000, PPC_SPEFPU); //
7829 7830 7831 7832 7833
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 已提交
7834 7835 7836 7837 7838 7839 7840
GEN_SPEFPUOP_ARITH2_64_64(efdadd);
GEN_SPEFPUOP_ARITH2_64_64(efdsub);
GEN_SPEFPUOP_ARITH2_64_64(efdmul);
GEN_SPEFPUOP_ARITH2_64_64(efddiv);
static always_inline void gen_efdabs (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
A
aurel32 已提交
7841
        gen_exception(ctx, POWERPC_EXCP_APU);
A
aurel32 已提交
7842 7843 7844 7845 7846 7847 7848 7849 7850 7851 7852
        return;
    }
#if defined(TARGET_PPC64)
    tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~0x8000000000000000LL);
#else
    tcg_gen_andi_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], ~0x80000000);
#endif
}
static always_inline void gen_efdnabs (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
A
aurel32 已提交
7853
        gen_exception(ctx, POWERPC_EXCP_APU);
A
aurel32 已提交
7854 7855 7856 7857 7858 7859 7860 7861 7862 7863 7864
        return;
    }
#if defined(TARGET_PPC64)
    tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000000000000LL);
#else
    tcg_gen_ori_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000);
#endif
}
static always_inline void gen_efdneg (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
A
aurel32 已提交
7865
        gen_exception(ctx, POWERPC_EXCP_APU);
A
aurel32 已提交
7866 7867 7868 7869 7870 7871 7872 7873 7874
        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
}

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

/* Comparison */
A
aurel32 已提交
7893 7894 7895 7896 7897 7898
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);
7899 7900 7901 7902 7903 7904 7905 7906 7907 7908 7909 7910 7911 7912 7913 7914 7915 7916 7917

/* 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 已提交
7918 7919 7920
/* End opcode list */
GEN_OPCODE_MARK(end);

7921
#include "translate_init.c"
7922
#include "helper_regs.h"
B
bellard 已提交
7923

7924
/*****************************************************************************/
7925
/* Misc PowerPC helpers */
7926 7927 7928
void cpu_dump_state (CPUState *env, FILE *f,
                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
                     int flags)
B
bellard 已提交
7929
{
7930 7931 7932
#define RGPL  4
#define RFPL  4

B
bellard 已提交
7933 7934
    int i;

J
j_mayer 已提交
7935
    cpu_fprintf(f, "NIP " ADDRX "   LR " ADDRX " CTR " ADDRX " XER %08x\n",
A
aurel32 已提交
7936
                env->nip, env->lr, env->ctr, env->xer);
7937 7938
    cpu_fprintf(f, "MSR " ADDRX " HID0 " ADDRX "  HF " ADDRX " idx %d\n",
                env->msr, env->spr[SPR_HID0], env->hflags, env->mmu_idx);
7939
#if !defined(NO_TIMER_DUMP)
J
j_mayer 已提交
7940
    cpu_fprintf(f, "TB %08x %08x "
7941 7942 7943 7944
#if !defined(CONFIG_USER_ONLY)
                "DECR %08x"
#endif
                "\n",
J
j_mayer 已提交
7945
                cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env)
7946 7947 7948 7949
#if !defined(CONFIG_USER_ONLY)
                , cpu_ppc_load_decr(env)
#endif
                );
J
j_mayer 已提交
7950
#endif
7951
    for (i = 0; i < 32; i++) {
7952 7953
        if ((i & (RGPL - 1)) == 0)
            cpu_fprintf(f, "GPR%02d", i);
7954
        cpu_fprintf(f, " " REGX, ppc_dump_gpr(env, i));
7955
        if ((i & (RGPL - 1)) == (RGPL - 1))
B
bellard 已提交
7956
            cpu_fprintf(f, "\n");
7957
    }
7958
    cpu_fprintf(f, "CR ");
7959
    for (i = 0; i < 8; i++)
B
bellard 已提交
7960 7961
        cpu_fprintf(f, "%01x", env->crf[i]);
    cpu_fprintf(f, "  [");
7962 7963 7964 7965 7966 7967 7968 7969
    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 已提交
7970
        cpu_fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' ');
7971
    }
7972
    cpu_fprintf(f, " ]             RES " ADDRX "\n", env->reserve);
7973 7974 7975
    for (i = 0; i < 32; i++) {
        if ((i & (RFPL - 1)) == 0)
            cpu_fprintf(f, "FPR%02d", i);
B
bellard 已提交
7976
        cpu_fprintf(f, " %016" PRIx64, *((uint64_t *)&env->fpr[i]));
7977
        if ((i & (RFPL - 1)) == (RFPL - 1))
B
bellard 已提交
7978
            cpu_fprintf(f, "\n");
B
bellard 已提交
7979
    }
7980
    cpu_fprintf(f, "FPSCR %08x\n", env->fpscr);
7981
#if !defined(CONFIG_USER_ONLY)
7982
    cpu_fprintf(f, "SRR0 " ADDRX " SRR1 " ADDRX " SDR1 " ADDRX "\n",
7983
                env->spr[SPR_SRR0], env->spr[SPR_SRR1], env->sdr1);
7984
#endif
B
bellard 已提交
7985

7986 7987
#undef RGPL
#undef RFPL
B
bellard 已提交
7988 7989
}

7990 7991 7992 7993 7994 7995 7996 7997 7998 7999 8000 8001 8002 8003 8004 8005 8006 8007 8008 8009 8010 8011 8012 8013 8014 8015 8016 8017 8018 8019 8020 8021 8022 8023 8024 8025 8026 8027 8028 8029 8030 8031 8032 8033 8034 8035 8036
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
}

8037
/*****************************************************************************/
8038 8039 8040
static always_inline void gen_intermediate_code_internal (CPUState *env,
                                                          TranslationBlock *tb,
                                                          int search_pc)
B
bellard 已提交
8041
{
8042
    DisasContext ctx, *ctxp = &ctx;
B
bellard 已提交
8043
    opc_handler_t **table, *handler;
B
bellard 已提交
8044
    target_ulong pc_start;
B
bellard 已提交
8045
    uint16_t *gen_opc_end;
8046
    CPUBreakpoint *bp;
B
bellard 已提交
8047
    int j, lj = -1;
P
pbrook 已提交
8048 8049
    int num_insns;
    int max_insns;
B
bellard 已提交
8050 8051 8052

    pc_start = tb->pc;
    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
B
bellard 已提交
8053
    ctx.nip = pc_start;
B
bellard 已提交
8054
    ctx.tb = tb;
8055
    ctx.exception = POWERPC_EXCP_NONE;
8056
    ctx.spr_cb = env->spr_cb;
A
aurel32 已提交
8057 8058 8059
    ctx.mem_idx = env->mmu_idx;
    ctx.access_type = -1;
    ctx.le_mode = env->hflags & (1 << MSR_LE) ? 1 : 0;
8060 8061
#if defined(TARGET_PPC64)
    ctx.sf_mode = msr_sf;
8062
#endif
B
bellard 已提交
8063
    ctx.fpu_enabled = msr_fp;
8064
    if ((env->flags & POWERPC_FLAG_SPE) && msr_spe)
8065 8066 8067
        ctx.spe_enabled = msr_spe;
    else
        ctx.spe_enabled = 0;
8068 8069 8070 8071
    if ((env->flags & POWERPC_FLAG_VRE) && msr_vr)
        ctx.altivec_enabled = msr_vr;
    else
        ctx.altivec_enabled = 0;
8072
    if ((env->flags & POWERPC_FLAG_SE) && msr_se)
8073
        ctx.singlestep_enabled = CPU_SINGLE_STEP;
8074
    else
8075
        ctx.singlestep_enabled = 0;
8076
    if ((env->flags & POWERPC_FLAG_BE) && msr_be)
8077 8078 8079
        ctx.singlestep_enabled |= CPU_BRANCH_STEP;
    if (unlikely(env->singlestep_enabled))
        ctx.singlestep_enabled |= GDBSTUB_SINGLE_STEP;
8080
#if defined (DO_SINGLE_STEP) && 0
8081 8082 8083
    /* Single step trace mode */
    msr_se = 1;
#endif
P
pbrook 已提交
8084 8085 8086 8087 8088 8089
    num_insns = 0;
    max_insns = tb->cflags & CF_COUNT_MASK;
    if (max_insns == 0)
        max_insns = CF_COUNT_MASK;

    gen_icount_start();
8090
    /* Set env in case of segfault during code fetch */
8091
    while (ctx.exception == POWERPC_EXCP_NONE && gen_opc_ptr < gen_opc_end) {
8092 8093
        if (unlikely(!TAILQ_EMPTY(&env->breakpoints))) {
            TAILQ_FOREACH(bp, &env->breakpoints, entry) {
8094
                if (bp->pc == ctx.nip) {
A
aurel32 已提交
8095
                    gen_debug_exception(ctxp);
8096 8097 8098 8099
                    break;
                }
            }
        }
8100
        if (unlikely(search_pc)) {
B
bellard 已提交
8101 8102 8103 8104 8105
            j = gen_opc_ptr - gen_opc_buf;
            if (lj < j) {
                lj++;
                while (lj < j)
                    gen_opc_instr_start[lj++] = 0;
B
bellard 已提交
8106
                gen_opc_pc[lj] = ctx.nip;
B
bellard 已提交
8107
                gen_opc_instr_start[lj] = 1;
P
pbrook 已提交
8108
                gen_opc_icount[lj] = num_insns;
B
bellard 已提交
8109 8110
            }
        }
8111 8112
#if defined PPC_DEBUG_DISAS
        if (loglevel & CPU_LOG_TB_IN_ASM) {
B
bellard 已提交
8113
            fprintf(logfile, "----------------\n");
8114
            fprintf(logfile, "nip=" ADDRX " super=%d ir=%d\n",
A
aurel32 已提交
8115
                    ctx.nip, ctx.mem_idx, (int)msr_ir);
8116 8117
        }
#endif
P
pbrook 已提交
8118 8119
        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
            gen_io_start();
A
aurel32 已提交
8120
        if (unlikely(ctx.le_mode)) {
8121 8122 8123
            ctx.opcode = bswap32(ldl_code(ctx.nip));
        } else {
            ctx.opcode = ldl_code(ctx.nip);
8124
        }
8125 8126
#if defined PPC_DEBUG_DISAS
        if (loglevel & CPU_LOG_TB_IN_ASM) {
8127
            fprintf(logfile, "translate opcode %08x (%02x %02x %02x) (%s)\n",
8128
                    ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode),
8129
                    opc3(ctx.opcode), little_endian ? "little" : "big");
B
bellard 已提交
8130 8131
        }
#endif
B
bellard 已提交
8132
        ctx.nip += 4;
8133
        table = env->opcodes;
P
pbrook 已提交
8134
        num_insns++;
B
bellard 已提交
8135 8136 8137 8138 8139 8140 8141 8142 8143 8144
        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 ? */
8145
        if (unlikely(handler->handler == &gen_invalid)) {
J
j_mayer 已提交
8146
            if (loglevel != 0) {
8147
                fprintf(logfile, "invalid/unsupported opcode: "
8148
                        "%02x - %02x - %02x (%08x) " ADDRX " %d\n",
8149
                        opc1(ctx.opcode), opc2(ctx.opcode),
8150
                        opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, (int)msr_ir);
B
bellard 已提交
8151 8152
            } else {
                printf("invalid/unsupported opcode: "
8153
                       "%02x - %02x - %02x (%08x) " ADDRX " %d\n",
B
bellard 已提交
8154
                       opc1(ctx.opcode), opc2(ctx.opcode),
8155
                       opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, (int)msr_ir);
B
bellard 已提交
8156
            }
8157 8158
        } else {
            if (unlikely((ctx.opcode & handler->inval) != 0)) {
J
j_mayer 已提交
8159
                if (loglevel != 0) {
B
bellard 已提交
8160
                    fprintf(logfile, "invalid bits: %08x for opcode: "
8161
                            "%02x - %02x - %02x (%08x) " ADDRX "\n",
B
bellard 已提交
8162 8163
                            ctx.opcode & handler->inval, opc1(ctx.opcode),
                            opc2(ctx.opcode), opc3(ctx.opcode),
B
bellard 已提交
8164
                            ctx.opcode, ctx.nip - 4);
8165 8166
                } else {
                    printf("invalid bits: %08x for opcode: "
8167
                           "%02x - %02x - %02x (%08x) " ADDRX "\n",
8168 8169
                           ctx.opcode & handler->inval, opc1(ctx.opcode),
                           opc2(ctx.opcode), opc3(ctx.opcode),
B
bellard 已提交
8170
                           ctx.opcode, ctx.nip - 4);
8171
                }
A
aurel32 已提交
8172
                gen_inval_exception(ctxp, POWERPC_EXCP_INVAL_INVAL);
B
bellard 已提交
8173
                break;
B
bellard 已提交
8174 8175
            }
        }
B
bellard 已提交
8176
        (*(handler->handler))(&ctx);
8177 8178 8179
#if defined(DO_PPC_STATISTICS)
        handler->count++;
#endif
8180
        /* Check trace mode exceptions */
8181 8182 8183 8184 8185
        if (unlikely(ctx.singlestep_enabled & CPU_SINGLE_STEP &&
                     (ctx.nip <= 0x100 || ctx.nip > 0xF00) &&
                     ctx.exception != POWERPC_SYSCALL &&
                     ctx.exception != POWERPC_EXCP_TRAP &&
                     ctx.exception != POWERPC_EXCP_BRANCH)) {
A
aurel32 已提交
8186
            gen_exception(ctxp, POWERPC_EXCP_TRACE);
8187
        } else if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) ||
P
pbrook 已提交
8188 8189
                            (env->singlestep_enabled) ||
                            num_insns >= max_insns)) {
8190 8191 8192
            /* if we reach a page boundary or are single stepping, stop
             * generation
             */
8193
            break;
8194
        }
8195 8196 8197 8198
#if defined (DO_SINGLE_STEP)
        break;
#endif
    }
P
pbrook 已提交
8199 8200
    if (tb->cflags & CF_LAST_IO)
        gen_io_end();
8201
    if (ctx.exception == POWERPC_EXCP_NONE) {
8202
        gen_goto_tb(&ctx, 0, ctx.nip);
8203
    } else if (ctx.exception != POWERPC_EXCP_BRANCH) {
8204
        if (unlikely(env->singlestep_enabled)) {
A
aurel32 已提交
8205
            gen_debug_exception(ctxp);
8206
        }
8207
        /* Generate the return instruction */
B
bellard 已提交
8208
        tcg_gen_exit_tb(0);
8209
    }
P
pbrook 已提交
8210
    gen_icount_end(tb, num_insns);
B
bellard 已提交
8211
    *gen_opc_ptr = INDEX_op_end;
8212
    if (unlikely(search_pc)) {
8213 8214 8215 8216 8217
        j = gen_opc_ptr - gen_opc_buf;
        lj++;
        while (lj <= j)
            gen_opc_instr_start[lj++] = 0;
    } else {
B
bellard 已提交
8218
        tb->size = ctx.nip - pc_start;
P
pbrook 已提交
8219
        tb->icount = num_insns;
8220
    }
8221
#if defined(DEBUG_DISAS)
8222
    if (loglevel & CPU_LOG_TB_CPU) {
8223
        fprintf(logfile, "---------------- excp: %04x\n", ctx.exception);
B
bellard 已提交
8224
        cpu_dump_state(env, logfile, fprintf, 0);
8225 8226
    }
    if (loglevel & CPU_LOG_TB_IN_ASM) {
8227
        int flags;
8228
        flags = env->bfd_mach;
A
aurel32 已提交
8229
        flags |= ctx.le_mode << 16;
B
bellard 已提交
8230
        fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
8231
        target_disas(logfile, pc_start, ctx.nip - pc_start, flags);
B
bellard 已提交
8232
        fprintf(logfile, "\n");
8233
    }
B
bellard 已提交
8234 8235 8236
#endif
}

8237
void gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
B
bellard 已提交
8238
{
8239
    gen_intermediate_code_internal(env, tb, 0);
B
bellard 已提交
8240 8241
}

8242
void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
B
bellard 已提交
8243
{
8244
    gen_intermediate_code_internal(env, tb, 1);
B
bellard 已提交
8245
}
A
aurel32 已提交
8246 8247 8248 8249 8250 8251

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