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

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

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

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

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

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

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

/* dyngen register indexes */
static TCGv cpu_T[3];
#if defined(TARGET_PPC64)
#define cpu_T64 cpu_T
#else
P
pbrook 已提交
77
static TCGv_i64 cpu_T64[3];
A
aurel32 已提交
78
#endif
A
aurel32 已提交
79
static TCGv_i64 cpu_FT[2];
P
pbrook 已提交
80 81 82 83 84

#include "gen-icount.h"

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

P
pbrook 已提交
89 90
    if (done_init)
        return;
A
aurel32 已提交
91

P
pbrook 已提交
92
    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
A
aurel32 已提交
93
#if TARGET_LONG_BITS > HOST_LONG_BITS
P
pbrook 已提交
94 95 96
    cpu_T[0] = tcg_global_mem_new(TCG_AREG0, offsetof(CPUState, t0), "T0");
    cpu_T[1] = tcg_global_mem_new(TCG_AREG0, offsetof(CPUState, t1), "T1");
    cpu_T[2] = tcg_global_mem_new(TCG_AREG0, offsetof(CPUState, t2), "T2");
A
aurel32 已提交
97
#else
P
pbrook 已提交
98 99
    cpu_T[0] = tcg_global_reg_new(TCG_AREG1, "T0");
    cpu_T[1] = tcg_global_reg_new(TCG_AREG2, "T1");
100 101 102 103 104
#ifdef HOST_I386
    /* XXX: This is a temporary workaround for i386.
     *      On i386 qemu_st32 runs out of registers.
     *      The proper fix is to remove cpu_T.
     */
P
pbrook 已提交
105
    cpu_T[2] = tcg_global_mem_new(TCG_AREG0, offsetof(CPUState, t2), "T2");
106
#else
P
pbrook 已提交
107
    cpu_T[2] = tcg_global_reg_new(TCG_AREG3, "T2");
A
aurel32 已提交
108
#endif
109
#endif
A
aurel32 已提交
110
#if !defined(TARGET_PPC64)
P
pbrook 已提交
111 112 113 114 115 116 117 118 119 120 121 122 123
    cpu_T64[0] = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUState, t0_64),
                                        "T0_64");
    cpu_T64[1] = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUState, t1_64),
                                        "T1_64");
    cpu_T64[2] = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUState, t2_64),
                                        "T2_64");
#endif

    cpu_FT[0] = tcg_global_mem_new_i64(TCG_AREG0,
                                       offsetof(CPUState, ft0), "FT0");
    cpu_FT[1] = tcg_global_mem_new_i64(TCG_AREG0,
                                       offsetof(CPUState, ft1), "FT1");

A
aurel32 已提交
124
    p = cpu_reg_names;
A
aurel32 已提交
125 126 127

    for (i = 0; i < 8; i++) {
        sprintf(p, "crf%d", i);
P
pbrook 已提交
128 129
        cpu_crf[i] = tcg_global_mem_new_i32(TCG_AREG0,
                                            offsetof(CPUState, crf[i]), p);
A
aurel32 已提交
130 131 132
        p += 5;
    }

A
aurel32 已提交
133 134
    for (i = 0; i < 32; i++) {
        sprintf(p, "r%d", i);
P
pbrook 已提交
135
        cpu_gpr[i] = tcg_global_mem_new(TCG_AREG0,
A
aurel32 已提交
136 137 138 139
                                        offsetof(CPUState, gpr[i]), p);
        p += (i < 10) ? 3 : 4;
#if !defined(TARGET_PPC64)
        sprintf(p, "r%dH", i);
P
pbrook 已提交
140 141
        cpu_gprh[i] = tcg_global_mem_new_i32(TCG_AREG0,
                                             offsetof(CPUState, gprh[i]), p);
A
aurel32 已提交
142 143
        p += (i < 10) ? 4 : 5;
#endif
144

A
aurel32 已提交
145
        sprintf(p, "fp%d", i);
P
pbrook 已提交
146 147
        cpu_fpr[i] = tcg_global_mem_new_i64(TCG_AREG0,
                                            offsetof(CPUState, fpr[i]), p);
A
aurel32 已提交
148
        p += (i < 10) ? 4 : 5;
A
aurel32 已提交
149

150
        sprintf(p, "avr%dH", i);
151 152 153 154
#ifdef WORDS_BIGENDIAN
        cpu_avrh[i] = tcg_global_mem_new_i64(TCG_AREG0,
                                             offsetof(CPUState, avr[i].u64[0]), p);
#else
P
pbrook 已提交
155
        cpu_avrh[i] = tcg_global_mem_new_i64(TCG_AREG0,
156 157
                                             offsetof(CPUState, avr[i].u64[1]), p);
#endif
158
        p += (i < 10) ? 6 : 7;
A
aurel32 已提交
159

160
        sprintf(p, "avr%dL", i);
161 162 163 164
#ifdef WORDS_BIGENDIAN
        cpu_avrl[i] = tcg_global_mem_new_i64(TCG_AREG0,
                                             offsetof(CPUState, avr[i].u64[1]), p);
#else
P
pbrook 已提交
165
        cpu_avrl[i] = tcg_global_mem_new_i64(TCG_AREG0,
166 167
                                             offsetof(CPUState, avr[i].u64[0]), p);
#endif
168
        p += (i < 10) ? 6 : 7;
A
aurel32 已提交
169
    }
A
aurel32 已提交
170

P
pbrook 已提交
171
    cpu_nip = tcg_global_mem_new(TCG_AREG0,
A
aurel32 已提交
172 173
                                 offsetof(CPUState, nip), "nip");

P
pbrook 已提交
174
    cpu_ctr = tcg_global_mem_new(TCG_AREG0,
A
aurel32 已提交
175 176
                                 offsetof(CPUState, ctr), "ctr");

P
pbrook 已提交
177
    cpu_lr = tcg_global_mem_new(TCG_AREG0,
A
aurel32 已提交
178 179
                                offsetof(CPUState, lr), "lr");

P
pbrook 已提交
180
    cpu_xer = tcg_global_mem_new(TCG_AREG0,
A
aurel32 已提交
181 182
                                 offsetof(CPUState, xer), "xer");

P
pbrook 已提交
183 184
    cpu_fpscr = tcg_global_mem_new_i32(TCG_AREG0,
                                       offsetof(CPUState, fpscr), "fpscr");
185

A
aurel32 已提交
186 187 188
    cpu_access_type = tcg_global_mem_new_i32(TCG_AREG0,
                                             offsetof(CPUState, access_type), "access_type");

A
aurel32 已提交
189
    /* register helpers */
P
pbrook 已提交
190
#define GEN_HELPER 2
A
aurel32 已提交
191 192
#include "helper.h"

P
pbrook 已提交
193 194 195
    done_init = 1;
}

196 197 198 199
#if defined(OPTIMIZE_FPRF_UPDATE)
static uint16_t *gen_fprf_buf[OPC_BUF_SIZE];
static uint16_t **gen_fprf_ptr;
#endif
B
bellard 已提交
200 201 202 203

/* internal defines */
typedef struct DisasContext {
    struct TranslationBlock *tb;
B
bellard 已提交
204
    target_ulong nip;
B
bellard 已提交
205
    uint32_t opcode;
206
    uint32_t exception;
B
bellard 已提交
207 208 209
    /* Routine used to access memory */
    int mem_idx;
    /* Translation flags */
210
#if !defined(CONFIG_USER_ONLY)
B
bellard 已提交
211
    int supervisor;
212 213 214
#endif
#if defined(TARGET_PPC64)
    int sf_mode;
215
#endif
B
bellard 已提交
216
    int fpu_enabled;
217
    int altivec_enabled;
218
    int spe_enabled;
219
    ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */
220
    int singlestep_enabled;
221
    int dcache_line_size;
B
bellard 已提交
222 223
} DisasContext;

224
struct opc_handler_t {
B
bellard 已提交
225 226
    /* invalid bits */
    uint32_t inval;
227
    /* instruction type */
228
    uint64_t type;
B
bellard 已提交
229 230
    /* handler */
    void (*handler)(DisasContext *ctx);
231
#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU)
232
    const char *oname;
233 234
#endif
#if defined(DO_PPC_STATISTICS)
235 236
    uint64_t count;
#endif
237
};
B
bellard 已提交
238

239 240 241 242 243 244 245
static always_inline void gen_reset_fpstatus (void)
{
#ifdef CONFIG_SOFTFLOAT
    gen_op_reset_fpstatus();
#endif
}

246
static always_inline void gen_compute_fprf (TCGv_i64 arg, int set_fprf, int set_rc)
247
{
248
    TCGv_i32 t0 = tcg_temp_new_i32();
A
aurel32 已提交
249

250 251 252 253 254
    if (set_fprf != 0) {
        /* This case might be optimized later */
#if defined(OPTIMIZE_FPRF_UPDATE)
        *gen_fprf_ptr++ = gen_opc_ptr;
#endif
255
        tcg_gen_movi_i32(t0, 1);
A
aurel32 已提交
256
        gen_helper_compute_fprf(t0, arg, t0);
P
pbrook 已提交
257
        if (unlikely(set_rc)) {
258
            tcg_gen_mov_i32(cpu_crf[1], t0);
P
pbrook 已提交
259
        }
A
aurel32 已提交
260
        gen_helper_float_check_status();
261 262
    } else if (unlikely(set_rc)) {
        /* We always need to compute fpcc */
263
        tcg_gen_movi_i32(t0, 0);
A
aurel32 已提交
264
        gen_helper_compute_fprf(t0, arg, t0);
265
        tcg_gen_mov_i32(cpu_crf[1], t0);
266
        if (set_fprf)
A
aurel32 已提交
267
            gen_helper_float_check_status();
268
    }
A
aurel32 已提交
269

270
    tcg_temp_free_i32(t0);
271 272 273 274 275 276 277 278 279 280 281 282 283
}

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

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

A
aurel32 已提交
284 285 286 287 288
static always_inline void gen_set_access_type(int access_type)
{
    tcg_gen_movi_i32(cpu_access_type, access_type);
}

289
static always_inline void gen_update_nip (DisasContext *ctx, target_ulong nip)
290 291 292
{
#if defined(TARGET_PPC64)
    if (ctx->sf_mode)
A
aurel32 已提交
293
        tcg_gen_movi_tl(cpu_nip, nip);
294 295
    else
#endif
A
aurel32 已提交
296
        tcg_gen_movi_tl(cpu_nip, (uint32_t)nip);
297 298
}

299
#define GEN_EXCP(ctx, excp, error)                                            \
B
bellard 已提交
300
do {                                                                          \
301 302
    TCGv_i32 t0 = tcg_const_i32(excp);                                        \
    TCGv_i32 t1 = tcg_const_i32(error);                                       \
303
    if ((ctx)->exception == POWERPC_EXCP_NONE) {                              \
304
        gen_update_nip(ctx, (ctx)->nip);                                      \
305
    }                                                                         \
306 307 308
    gen_helper_raise_exception_err(t0, t1);                                   \
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
309
    ctx->exception = (excp);                                                  \
B
bellard 已提交
310 311
} while (0)

312 313 314
#define GEN_EXCP_INVAL(ctx)                                                   \
GEN_EXCP((ctx), POWERPC_EXCP_PROGRAM,                                         \
         POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL)
315

316 317 318
#define GEN_EXCP_PRIVOPC(ctx)                                                 \
GEN_EXCP((ctx), POWERPC_EXCP_PROGRAM,                                         \
         POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_OPC)
319

320 321 322 323 324 325 326 327 328
#define GEN_EXCP_PRIVREG(ctx)                                                 \
GEN_EXCP((ctx), POWERPC_EXCP_PROGRAM,                                         \
         POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG)

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

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

330 331 332
#define GEN_EXCP_NO_VR(ctx)                                                   \
GEN_EXCP(ctx, POWERPC_EXCP_VPU, 0)

333
/* Stop translation */
334
static always_inline void GEN_STOP (DisasContext *ctx)
335
{
336
    gen_update_nip(ctx, ctx->nip);
337
    ctx->exception = POWERPC_EXCP_STOP;
338 339
}

340
/* No need to update nip here, as execution flow will change */
341
static always_inline void GEN_SYNC (DisasContext *ctx)
342
{
343
    ctx->exception = POWERPC_EXCP_SYNC;
344 345
}

B
bellard 已提交
346 347 348 349 350
#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)

351 352 353 354 355
#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 已提交
356 357
typedef struct opcode_t {
    unsigned char opc1, opc2, opc3;
T
ths 已提交
358
#if HOST_LONG_BITS == 64 /* Explicitly align to 64 bits */
359 360 361 362
    unsigned char pad[5];
#else
    unsigned char pad[1];
#endif
B
bellard 已提交
363
    opc_handler_t handler;
364
    const char *oname;
B
bellard 已提交
365 366
} opcode_t;

367
/*****************************************************************************/
B
bellard 已提交
368 369
/***                           Instruction decoding                        ***/
#define EXTRACT_HELPER(name, shift, nb)                                       \
370
static always_inline uint32_t name (uint32_t opcode)                          \
B
bellard 已提交
371 372 373 374 375
{                                                                             \
    return (opcode >> (shift)) & ((1 << (nb)) - 1);                           \
}

#define EXTRACT_SHELPER(name, shift, nb)                                      \
376
static always_inline int32_t name (uint32_t opcode)                           \
B
bellard 已提交
377
{                                                                             \
378
    return (int16_t)((opcode >> (shift)) & ((1 << (nb)) - 1));                \
B
bellard 已提交
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
}

/* 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 */
406
EXTRACT_HELPER(_SPR, 11, 10);
407
static always_inline uint32_t SPR (uint32_t opcode)
408 409 410 411 412
{
    uint32_t sprn = _SPR(opcode);

    return ((sprn >> 5) & 0x1F) | ((sprn & 0x1F) << 5);
}
B
bellard 已提交
413 414 415 416 417 418 419 420 421 422 423 424 425 426
/***                              Get constants                            ***/
EXTRACT_HELPER(IMM, 12, 8);
/* 16 bits signed immediate value */
EXTRACT_SHELPER(SIMM, 0, 16);
/* 16 bits unsigned immediate value */
EXTRACT_HELPER(UIMM, 0, 16);
/* Bit count */
EXTRACT_HELPER(NB, 11, 5);
/* Shift count */
EXTRACT_HELPER(SH, 11, 5);
/* Mask start */
EXTRACT_HELPER(MB, 6, 5);
/* Mask end */
EXTRACT_HELPER(ME, 1, 5);
B
bellard 已提交
427 428
/* Trap operand */
EXTRACT_HELPER(TO, 21, 5);
B
bellard 已提交
429 430 431 432

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

B
bellard 已提交
435 436 437 438
/***                            Jump target decoding                       ***/
/* Displacement */
EXTRACT_SHELPER(d, 0, 16);
/* Immediate address */
439
static always_inline target_ulong LI (uint32_t opcode)
B
bellard 已提交
440 441 442 443
{
    return (opcode >> 0) & 0x03FFFFFC;
}

444
static always_inline uint32_t BD (uint32_t opcode)
B
bellard 已提交
445 446 447 448 449 450 451 452 453 454 455 456
{
    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 */
457
static always_inline target_ulong MASK (uint32_t start, uint32_t end)
B
bellard 已提交
458
{
459
    target_ulong ret;
B
bellard 已提交
460

461 462
#if defined(TARGET_PPC64)
    if (likely(start == 0)) {
463
        ret = UINT64_MAX << (63 - end);
464
    } else if (likely(end == 63)) {
465
        ret = UINT64_MAX >> start;
466 467 468
    }
#else
    if (likely(start == 0)) {
469
        ret = UINT32_MAX << (31  - end);
470
    } else if (likely(end == 31)) {
471
        ret = UINT32_MAX >> start;
472 473 474 475 476 477 478 479
    }
#endif
    else {
        ret = (((target_ulong)(-1ULL)) >> (start)) ^
            (((target_ulong)(-1ULL) >> (end)) >> 1);
        if (unlikely(start > end))
            return ~ret;
    }
B
bellard 已提交
480 481 482 483

    return ret;
}

484 485 486
/*****************************************************************************/
/* PowerPC Instructions types definitions                                    */
enum {
487
    PPC_NONE           = 0x0000000000000000ULL,
488
    /* PowerPC base instructions set                                         */
489 490
    PPC_INSNS_BASE     = 0x0000000000000001ULL,
    /*   integer operations instructions                                     */
491
#define PPC_INTEGER PPC_INSNS_BASE
492
    /*   flow control instructions                                           */
493
#define PPC_FLOW    PPC_INSNS_BASE
494
    /*   virtual memory instructions                                         */
495
#define PPC_MEM     PPC_INSNS_BASE
496
    /*   ld/st with reservation instructions                                 */
497
#define PPC_RES     PPC_INSNS_BASE
498
    /*   spr/msr access instructions                                         */
499
#define PPC_MISC    PPC_INSNS_BASE
500 501
    /* Deprecated instruction sets                                           */
    /*   Original POWER instruction set                                      */
502
    PPC_POWER          = 0x0000000000000002ULL,
503
    /*   POWER2 instruction set extension                                    */
504
    PPC_POWER2         = 0x0000000000000004ULL,
505
    /*   Power RTC support                                                   */
506
    PPC_POWER_RTC      = 0x0000000000000008ULL,
507
    /*   Power-to-PowerPC bridge (601)                                       */
508
    PPC_POWER_BR       = 0x0000000000000010ULL,
509
    /* 64 bits PowerPC instruction set                                       */
510
    PPC_64B            = 0x0000000000000020ULL,
511
    /*   New 64 bits extensions (PowerPC 2.0x)                               */
512
    PPC_64BX           = 0x0000000000000040ULL,
513
    /*   64 bits hypervisor extensions                                       */
514
    PPC_64H            = 0x0000000000000080ULL,
515
    /*   New wait instruction (PowerPC 2.0x)                                 */
516
    PPC_WAIT           = 0x0000000000000100ULL,
517
    /*   Time base mftb instruction                                          */
518
    PPC_MFTB           = 0x0000000000000200ULL,
519 520 521

    /* Fixed-point unit extensions                                           */
    /*   PowerPC 602 specific                                                */
522
    PPC_602_SPEC       = 0x0000000000000400ULL,
523 524 525 526 527 528
    /*   isel instruction                                                    */
    PPC_ISEL           = 0x0000000000000800ULL,
    /*   popcntb instruction                                                 */
    PPC_POPCNTB        = 0x0000000000001000ULL,
    /*   string load / store                                                 */
    PPC_STRING         = 0x0000000000002000ULL,
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545

    /* 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                                          */
546
    PPC_SPE            = 0x0000000002000000ULL,
547
    /*   PowerPC 2.03 SPE floating-point extension                           */
548
    PPC_SPEFPU         = 0x0000000004000000ULL,
549

550
    /* Optional memory control instructions                                  */
551 552 553 554 555 556 557 558 559
    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                                            */
560
    PPC_CACHE          = 0x0000000200000000ULL,
561
    /*   icbi instruction                                                    */
562
    PPC_CACHE_ICBI     = 0x0000000400000000ULL,
563
    /*   dcbz instruction with fixed cache line size                         */
564
    PPC_CACHE_DCBZ     = 0x0000000800000000ULL,
565
    /*   dcbz instruction with tunable cache line size                       */
566
    PPC_CACHE_DCBZT    = 0x0000001000000000ULL,
567
    /*   dcba instruction                                                    */
568 569 570
    PPC_CACHE_DCBA     = 0x0000002000000000ULL,
    /*   Freescale cache locking instructions                                */
    PPC_CACHE_LOCK     = 0x0000004000000000ULL,
571 572 573

    /* MMU related extensions                                                */
    /*   external control instructions                                       */
574
    PPC_EXTERN         = 0x0000010000000000ULL,
575
    /*   segment register access instructions                                */
576
    PPC_SEGMENT        = 0x0000020000000000ULL,
577
    /*   PowerPC 6xx TLB management instructions                             */
578
    PPC_6xx_TLB        = 0x0000040000000000ULL,
579
    /* PowerPC 74xx TLB management instructions                              */
580
    PPC_74xx_TLB       = 0x0000080000000000ULL,
581
    /*   PowerPC 40x TLB management instructions                             */
582
    PPC_40x_TLB        = 0x0000100000000000ULL,
583
    /*   segment register access instructions for PowerPC 64 "bridge"        */
584
    PPC_SEGMENT_64B    = 0x0000200000000000ULL,
585
    /*   SLB management                                                      */
586
    PPC_SLBI           = 0x0000400000000000ULL,
587

588
    /* Embedded PowerPC dedicated instructions                               */
589
    PPC_WRTEE          = 0x0001000000000000ULL,
590
    /* PowerPC 40x exception model                                           */
591
    PPC_40x_EXCP       = 0x0002000000000000ULL,
592
    /* PowerPC 405 Mac instructions                                          */
593
    PPC_405_MAC        = 0x0004000000000000ULL,
594
    /* PowerPC 440 specific instructions                                     */
595
    PPC_440_SPEC       = 0x0008000000000000ULL,
596
    /* BookE (embedded) PowerPC specification                                */
597 598 599 600 601 602 603
    PPC_BOOKE          = 0x0010000000000000ULL,
    /* mfapidi instruction                                                   */
    PPC_MFAPIDI        = 0x0020000000000000ULL,
    /* tlbiva instruction                                                    */
    PPC_TLBIVA         = 0x0040000000000000ULL,
    /* tlbivax instruction                                                   */
    PPC_TLBIVAX        = 0x0080000000000000ULL,
604
    /* PowerPC 4xx dedicated instructions                                    */
605
    PPC_4xx_COMMON     = 0x0100000000000000ULL,
606
    /* PowerPC 40x ibct instructions                                         */
607
    PPC_40x_ICBT       = 0x0200000000000000ULL,
608
    /* rfmci is not implemented in all BookE PowerPC                         */
609 610 611 612 613 614 615
    PPC_RFMCI          = 0x0400000000000000ULL,
    /* rfdi instruction                                                      */
    PPC_RFDI           = 0x0800000000000000ULL,
    /* DCR accesses                                                          */
    PPC_DCR            = 0x1000000000000000ULL,
    /* DCR extended accesse                                                  */
    PPC_DCRX           = 0x2000000000000000ULL,
616
    /* user-mode DCR access, implemented in PowerPC 460                      */
617
    PPC_DCRUX          = 0x4000000000000000ULL,
618 619 620 621
};

/*****************************************************************************/
/* PowerPC instructions table                                                */
622 623 624 625 626
#if HOST_LONG_BITS == 64
#define OPC_ALIGN 8
#else
#define OPC_ALIGN 4
#endif
B
bellard 已提交
627
#if defined(__APPLE__)
628
#define OPCODES_SECTION                                                       \
629
    __attribute__ ((section("__TEXT,__opcodes"), unused, aligned (OPC_ALIGN) ))
B
bellard 已提交
630
#else
631
#define OPCODES_SECTION                                                       \
632
    __attribute__ ((section(".opcodes"), unused, aligned (OPC_ALIGN) ))
B
bellard 已提交
633 634
#endif

635
#if defined(DO_PPC_STATISTICS)
B
bellard 已提交
636
#define GEN_OPCODE(name, op1, op2, op3, invl, _typ)                           \
637
OPCODES_SECTION opcode_t opc_##name = {                                       \
B
bellard 已提交
638 639 640
    .opc1 = op1,                                                              \
    .opc2 = op2,                                                              \
    .opc3 = op3,                                                              \
641
    .pad  = { 0, },                                                           \
B
bellard 已提交
642 643
    .handler = {                                                              \
        .inval   = invl,                                                      \
644
        .type = _typ,                                                         \
B
bellard 已提交
645
        .handler = &gen_##name,                                               \
646
        .oname = stringify(name),                                             \
B
bellard 已提交
647
    },                                                                        \
648
    .oname = stringify(name),                                                 \
B
bellard 已提交
649
}
650 651 652 653 654 655 656 657 658 659 660 661 662 663
#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,                                                            \
}
664 665 666 667 668 669 670 671 672 673 674 675 676 677
#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),                                                 \
}
678 679 680 681 682 683 684 685 686 687 688 689 690
#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,                                                            \
}
691
#endif
B
bellard 已提交
692 693

#define GEN_OPCODE_MARK(name)                                                 \
694
OPCODES_SECTION opcode_t opc_##name = {                                       \
B
bellard 已提交
695 696 697
    .opc1 = 0xFF,                                                             \
    .opc2 = 0xFF,                                                             \
    .opc3 = 0xFF,                                                             \
698
    .pad  = { 0, },                                                           \
B
bellard 已提交
699 700
    .handler = {                                                              \
        .inval   = 0x00000000,                                                \
701
        .type = 0x00,                                                         \
B
bellard 已提交
702 703
        .handler = NULL,                                                      \
    },                                                                        \
704
    .oname = stringify(name),                                                 \
B
bellard 已提交
705 706 707 708 709 710
}

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

/* Invalid instruction */
711 712
GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE)
{
713
    GEN_EXCP_INVAL(ctx);
714 715
}

B
bellard 已提交
716 717
static opc_handler_t invalid_handler = {
    .inval   = 0xFFFFFFFF,
718
    .type    = PPC_NONE,
B
bellard 已提交
719 720 721
    .handler = gen_invalid,
};

722 723
/***                           Integer comparison                          ***/

724
static always_inline void gen_op_cmp(TCGv arg0, TCGv arg1, int s, int crf)
725 726 727
{
    int l1, l2, l3;

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

752
static always_inline void gen_op_cmpi(TCGv arg0, target_ulong arg1, int s, int crf)
753
{
754 755 756
    TCGv t0 = tcg_const_local_tl(arg1);
    gen_op_cmp(arg0, t0, s, crf);
    tcg_temp_free(t0);
757 758 759
}

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

777
static always_inline void gen_op_cmpi32(TCGv arg0, target_ulong arg1, int s, int crf)
778
{
779 780 781
    TCGv t0 = tcg_const_local_tl(arg1);
    gen_op_cmp32(arg0, t0, s, crf);
    tcg_temp_free(t0);
782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852
}
#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 已提交
853
    TCGv_i32 t0;
854 855 856 857 858

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

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

B
bellard 已提交
873 874
/***                           Integer arithmetic                          ***/

875 876 877 878
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 已提交
879

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

907 908 909
static always_inline void gen_op_arith_compute_ca(DisasContext *ctx, TCGv arg1, TCGv arg2, int sub)
{
    int l1 = gen_new_label();
910 911

#if defined(TARGET_PPC64)
912 913
    if (!(ctx->sf_mode)) {
        TCGv t0, t1;
P
pbrook 已提交
914 915
        t0 = tcg_temp_new();
        t1 = tcg_temp_new();
916

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

941 942 943 944 945
/* 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;
946

947
    if ((!compute_ca && !compute_ov) ||
P
pbrook 已提交
948
        (!TCGV_EQUAL(ret,arg1) && !TCGV_EQUAL(ret, arg2)))  {
949 950
        t0 = ret;
    } else {
P
pbrook 已提交
951
        t0 = tcg_temp_local_new();
952
    }
B
bellard 已提交
953

954
    if (add_ca) {
P
pbrook 已提交
955
        t1 = tcg_temp_local_new();
956 957 958
        tcg_gen_andi_tl(t1, cpu_xer, (1 << XER_CA));
        tcg_gen_shri_tl(t1, t1, XER_CA);
    }
B
bellard 已提交
959

960 961 962 963 964 965 966 967 968 969
    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 已提交
970

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

static always_inline void gen_op_arith_divw (DisasContext *ctx, TCGv ret, TCGv arg1, TCGv arg2,
                                             int sign, int compute_ov)
1085
{
1086 1087
    int l1 = gen_new_label();
    int l2 = gen_new_label();
P
pbrook 已提交
1088 1089
    TCGv_i32 t0 = tcg_temp_local_new_i32();
    TCGv_i32 t1 = tcg_temp_local_new_i32();
1090

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

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

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

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

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

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

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

/* 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 已提交
1351
{
1352
    TCGv t0, t1;
1353

1354
    if ((!compute_ca && !compute_ov) ||
P
pbrook 已提交
1355
        (!TCGV_EQUAL(ret, arg1) && !TCGV_EQUAL(ret, arg2)))  {
1356
        t0 = ret;
J
j_mayer 已提交
1357
    } else {
P
pbrook 已提交
1358
        t0 = tcg_temp_local_new();
1359
    }
1360

1361
    if (add_ca) {
P
pbrook 已提交
1362
        t1 = tcg_temp_local_new();
1363 1364
        tcg_gen_andi_tl(t1, cpu_xer, (1 << XER_CA));
        tcg_gen_shri_tl(t1, t1, XER_CA);
1365
    }
B
bellard 已提交
1366

1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384
    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 已提交
1385
    } else {
1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397
        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 已提交
1398
    if (!TCGV_EQUAL(t0, ret)) {
1399 1400
        tcg_gen_mov_tl(ret, t0);
        tcg_temp_free(t0);
B
bellard 已提交
1401 1402
    }
}
1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436
/* 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 已提交
1437 1438 1439
/* subfic */
GEN_HANDLER(subfic, 0x08, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
1440 1441
    /* Start with XER CA and OV disabled, the most likely case */
    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_CA));
P
pbrook 已提交
1442
    TCGv t0 = tcg_temp_local_new();
1443 1444 1445 1446 1447 1448
    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 已提交
1449 1450 1451
}

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

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

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

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

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

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

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

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

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

B
bellard 已提交
1659 1660 1661 1662
/***                             Integer rotate                            ***/
/* rlwimi & rlwimi. */
GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
1663
    uint32_t mb, me, sh;
B
bellard 已提交
1664 1665 1666

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

B
bellard 已提交
1703 1704 1705
    sh = SH(ctx->opcode);
    mb = MB(ctx->opcode);
    me = ME(ctx->opcode);
1706 1707 1708 1709 1710

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

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

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

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

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

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

J
j_mayer 已提交
1860 1861
    sh = SH(ctx->opcode) | (shn << 5);
    mb = MB(ctx->opcode) | (mbn << 5);
J
j_mayer 已提交
1862 1863 1864 1865
    gen_rldinm(ctx, mb, 63 - sh, sh);
}
GEN_PPC64_R4(rldic, 0x1E, 0x04);

1866 1867
static always_inline void gen_rldnm (DisasContext *ctx, uint32_t mb,
                                     uint32_t me)
J
j_mayer 已提交
1868
{
1869
    TCGv t0;
1870 1871 1872

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

1886
/* rldcl - rldcl. */
1887
static always_inline void gen_rldcl (DisasContext *ctx, int mbn)
1888
{
J
j_mayer 已提交
1889
    uint32_t mb;
1890

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

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

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

B
bellard 已提交
1934 1935
/***                             Integer shift                             ***/
/* slw & slw. */
1936 1937
GEN_HANDLER(slw, 0x1F, 0x18, 0x00, 0x00000000, PPC_INTEGER)
{
1938
    TCGv t0;
1939 1940 1941 1942
    int l1, l2;
    l1 = gen_new_label();
    l2 = gen_new_label();

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

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

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

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

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

2120 2121 2122
#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);
2123

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

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

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

2177
#define GEN_FLOAT_BS(name, op1, op2, set_fprf, type)                          \
2178
GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, type)                        \
2179
{                                                                             \
2180
    if (unlikely(!ctx->fpu_enabled)) {                                        \
2181
        GEN_EXCP_NO_FP(ctx);                                                  \
B
bellard 已提交
2182 2183
        return;                                                               \
    }                                                                         \
2184
    gen_reset_fpstatus();                                                     \
A
aurel32 已提交
2185 2186 2187
    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 已提交
2188 2189
}

2190
/* fadd - fadds */
2191
GEN_FLOAT_AB(add, 0x15, 0x000007C0, 1, PPC_FLOAT);
2192
/* fdiv - fdivs */
2193
GEN_FLOAT_AB(div, 0x12, 0x000007C0, 1, PPC_FLOAT);
2194
/* fmul - fmuls */
2195
GEN_FLOAT_AC(mul, 0x19, 0x0000F800, 1, PPC_FLOAT);
B
bellard 已提交
2196

2197
/* fre */
2198
GEN_FLOAT_BS(re, 0x3F, 0x18, 1, PPC_FLOAT_EXT);
2199

2200
/* fres */
2201
GEN_FLOAT_BS(res, 0x3B, 0x18, 1, PPC_FLOAT_FRES);
B
bellard 已提交
2202

2203
/* frsqrte */
2204 2205 2206
GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, 1, PPC_FLOAT_FRSQRTE);

/* frsqrtes */
A
aurel32 已提交
2207
GEN_HANDLER(frsqrtes, 0x3B, 0x1A, 0xFF, 0x001F07C0, PPC_FLOAT_FRSQRTES)
2208
{
A
aurel32 已提交
2209 2210 2211 2212 2213 2214 2215 2216
    if (unlikely(!ctx->fpu_enabled)) {
        GEN_EXCP_NO_FP(ctx);
        return;
    }
    gen_reset_fpstatus();
    gen_helper_frsqrte(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);
    gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]);
    gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 1, Rc(ctx->opcode) != 0);
2217
}
B
bellard 已提交
2218

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

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

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

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

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

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

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

2310 2311
/***                         Floating-point move                           ***/
/* fabs */
2312 2313
/* XXX: beware that fabs never checks for NaNs nor update FPSCR */
GEN_FLOAT_B(abs, 0x08, 0x08, 0, PPC_FLOAT);
2314 2315

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

/* fnabs */
2328 2329
/* XXX: beware that fnabs never checks for NaNs nor update FPSCR */
GEN_FLOAT_B(nabs, 0x08, 0x04, 0, PPC_FLOAT);
2330
/* fneg */
2331 2332
/* XXX: beware that fneg never checks for NaNs nor update FPSCR */
GEN_FLOAT_B(neg, 0x08, 0x01, 0, PPC_FLOAT);
2333

B
bellard 已提交
2334 2335 2336 2337
/***                  Floating-Point status & ctrl register                ***/
/* mcrfs */
GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT)
{
2338 2339
    int bfa;

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

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

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

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

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

2388
    if (unlikely(!ctx->fpu_enabled)) {
2389
        GEN_EXCP_NO_FP(ctx);
B
bellard 已提交
2390 2391
        return;
    }
2392 2393 2394 2395
    crb = 32 - (crbD(ctx->opcode) >> 2);
    gen_optimize_fprf();
    gen_reset_fpstatus();
    /* XXX: we pretend we can only do IEEE floating-point computations */
A
aurel32 已提交
2396
    if (likely(crb != FPSCR_FEX && crb != FPSCR_VX && crb != FPSCR_NI)) {
2397
        TCGv_i32 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)) {
2414
        GEN_EXCP_NO_FP(ctx);
B
bellard 已提交
2415 2416
        return;
    }
2417 2418
    gen_optimize_fprf();
    gen_reset_fpstatus();
A
aurel32 已提交
2419 2420
    t0 = tcg_const_i32(FM(ctx->opcode));
    gen_helper_store_fpscr(cpu_fpr[rB(ctx->opcode)], t0);
2421
    tcg_temp_free_i32(t0);
2422
    if (unlikely(Rc(ctx->opcode) != 0)) {
2423
        tcg_gen_shri_i32(cpu_crf[1], cpu_fpscr, FPSCR_OX);
2424 2425
    }
    /* We can raise a differed exception */
A
aurel32 已提交
2426
    gen_helper_float_check_status();
B
bellard 已提交
2427 2428 2429 2430 2431
}

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

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

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

2464
    simm &= ~maskl;
2465 2466 2467 2468 2469 2470
    if (rA(ctx->opcode) == 0)
        tcg_gen_movi_tl(EA, simm);
    else if (likely(simm != 0))
        tcg_gen_addi_tl(EA, cpu_gpr[rA(ctx->opcode)], simm);
    else
        tcg_gen_mov_tl(EA, cpu_gpr[rA(ctx->opcode)]);
2471 2472
}

2473 2474
static always_inline void gen_addr_reg_index (TCGv EA,
                                              DisasContext *ctx)
2475
{
2476 2477 2478 2479
    if (rA(ctx->opcode) == 0)
        tcg_gen_mov_tl(EA, cpu_gpr[rB(ctx->opcode)]);
    else
        tcg_gen_add_tl(EA, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
2480 2481
}

2482 2483
static always_inline void gen_addr_register (TCGv EA,
                                             DisasContext *ctx)
2484
{
2485 2486 2487 2488
    if (rA(ctx->opcode) == 0)
        tcg_gen_movi_tl(EA, 0);
    else
        tcg_gen_mov_tl(EA, cpu_gpr[rA(ctx->opcode)]);
2489 2490
}

2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501
#if defined(TARGET_PPC64)
#define _GEN_MEM_FUNCS(name, mode)                                            \
    &gen_op_##name##_##mode,                                                  \
    &gen_op_##name##_le_##mode,                                               \
    &gen_op_##name##_64_##mode,                                               \
    &gen_op_##name##_le_64_##mode
#else
#define _GEN_MEM_FUNCS(name, mode)                                            \
    &gen_op_##name##_##mode,                                                  \
    &gen_op_##name##_le_##mode
#endif
2502
#if defined(CONFIG_USER_ONLY)
2503
#if defined(TARGET_PPC64)
2504
#define NB_MEM_FUNCS 4
2505
#else
2506
#define NB_MEM_FUNCS 2
2507
#endif
2508 2509
#define GEN_MEM_FUNCS(name)                                                   \
    _GEN_MEM_FUNCS(name, raw)
2510
#else
2511
#if defined(TARGET_PPC64)
2512
#define NB_MEM_FUNCS 12
2513
#else
2514
#define NB_MEM_FUNCS 6
2515
#endif
2516 2517 2518 2519 2520 2521 2522
#define GEN_MEM_FUNCS(name)                                                   \
    _GEN_MEM_FUNCS(name, user),                                               \
    _GEN_MEM_FUNCS(name, kernel),                                             \
    _GEN_MEM_FUNCS(name, hypv)
#endif

/***                             Integer load                              ***/
A
aurel32 已提交
2523 2524 2525 2526 2527 2528 2529
#if defined(TARGET_PPC64)
#define GEN_QEMU_LD_PPC64(width)                                                 \
static always_inline void gen_qemu_ld##width##_ppc64(TCGv t0, TCGv t1, int flags)\
{                                                                                \
    if (likely(flags & 2))                                                       \
        tcg_gen_qemu_ld##width(t0, t1, flags >> 2);                              \
    else {                                                                       \
P
pbrook 已提交
2530
        TCGv addr = tcg_temp_new();                                   \
A
aurel32 已提交
2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549
        tcg_gen_ext32u_tl(addr, t1);                                             \
        tcg_gen_qemu_ld##width(t0, addr, flags >> 2);                            \
        tcg_temp_free(addr);                                                     \
    }                                                                            \
}
GEN_QEMU_LD_PPC64(8u)
GEN_QEMU_LD_PPC64(8s)
GEN_QEMU_LD_PPC64(16u)
GEN_QEMU_LD_PPC64(16s)
GEN_QEMU_LD_PPC64(32u)
GEN_QEMU_LD_PPC64(32s)
GEN_QEMU_LD_PPC64(64)

#define GEN_QEMU_ST_PPC64(width)                                                 \
static always_inline void gen_qemu_st##width##_ppc64(TCGv t0, TCGv t1, int flags)\
{                                                                                \
    if (likely(flags & 2))                                                       \
        tcg_gen_qemu_st##width(t0, t1, flags >> 2);                              \
    else {                                                                       \
P
pbrook 已提交
2550
        TCGv addr = tcg_temp_new();                                   \
A
aurel32 已提交
2551 2552 2553 2554 2555 2556 2557 2558 2559 2560
        tcg_gen_ext32u_tl(addr, t1);                                             \
        tcg_gen_qemu_st##width(t0, addr, flags >> 2);                            \
        tcg_temp_free(addr);                                                     \
    }                                                                            \
}
GEN_QEMU_ST_PPC64(8)
GEN_QEMU_ST_PPC64(16)
GEN_QEMU_ST_PPC64(32)
GEN_QEMU_ST_PPC64(64)

2561
static always_inline void gen_qemu_ld8u(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2562
{
2563
    gen_qemu_ld8u_ppc64(arg0, arg1, flags);
A
aurel32 已提交
2564 2565
}

2566
static always_inline void gen_qemu_ld8s(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2567
{
2568
    gen_qemu_ld8s_ppc64(arg0, arg1, flags);
A
aurel32 已提交
2569 2570
}

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

2585
static always_inline void gen_qemu_ld16s(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2586 2587
{
    if (unlikely(flags & 1)) {
P
pbrook 已提交
2588
        TCGv_i32 t0;
2589
        gen_qemu_ld16u_ppc64(arg0, arg1, flags);
P
pbrook 已提交
2590
        t0 = tcg_temp_new_i32();
2591 2592 2593 2594
        tcg_gen_trunc_tl_i32(t0, arg0);
        tcg_gen_bswap16_i32(t0, t0);
        tcg_gen_extu_i32_tl(arg0, t0);
        tcg_gen_ext16s_tl(arg0, arg0);
P
pbrook 已提交
2595
        tcg_temp_free_i32(t0);
A
aurel32 已提交
2596
    } else
2597
        gen_qemu_ld16s_ppc64(arg0, arg1, flags);
A
aurel32 已提交
2598 2599
}

2600
static always_inline void gen_qemu_ld32u(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2601 2602
{
    if (unlikely(flags & 1)) {
P
pbrook 已提交
2603
        TCGv_i32 t0;
2604
        gen_qemu_ld32u_ppc64(arg0, arg1, flags);
P
pbrook 已提交
2605
        t0 = tcg_temp_new_i32();
2606 2607 2608
        tcg_gen_trunc_tl_i32(t0, arg0);
        tcg_gen_bswap_i32(t0, t0);
        tcg_gen_extu_i32_tl(arg0, t0);
P
pbrook 已提交
2609
        tcg_temp_free_i32(t0);
A
aurel32 已提交
2610
    } else
2611
        gen_qemu_ld32u_ppc64(arg0, arg1, flags);
A
aurel32 已提交
2612 2613
}

2614
static always_inline void gen_qemu_ld32s(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2615 2616
{
    if (unlikely(flags & 1)) {
P
pbrook 已提交
2617
        TCGv_i32 t0;
2618
        gen_qemu_ld32u_ppc64(arg0, arg1, flags);
P
pbrook 已提交
2619
        t0 = tcg_temp_new_i32();
2620 2621 2622
        tcg_gen_trunc_tl_i32(t0, arg0);
        tcg_gen_bswap_i32(t0, t0);
        tcg_gen_ext_i32_tl(arg0, t0);
P
pbrook 已提交
2623
        tcg_temp_free_i32(t0);
A
aurel32 已提交
2624
    } else
2625
        gen_qemu_ld32s_ppc64(arg0, arg1, flags);
A
aurel32 已提交
2626 2627
}

2628
static always_inline void gen_qemu_ld64(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2629
{
2630
    gen_qemu_ld64_ppc64(arg0, arg1, flags);
A
aurel32 已提交
2631
    if (unlikely(flags & 1))
2632
        tcg_gen_bswap_i64(arg0, arg0);
A
aurel32 已提交
2633 2634
}

2635
static always_inline void gen_qemu_st8(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2636
{
2637
    gen_qemu_st8_ppc64(arg0, arg1, flags);
A
aurel32 已提交
2638 2639
}

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

2658
static always_inline void gen_qemu_st32(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2659 2660
{
    if (unlikely(flags & 1)) {
P
pbrook 已提交
2661 2662 2663
        TCGv_i32 t0;
        TCGv_i64 t1;
        t0 = tcg_temp_new_i32();
2664 2665
        tcg_gen_trunc_tl_i32(t0, arg0);
        tcg_gen_bswap_i32(t0, t0);
P
pbrook 已提交
2666
        t1 = tcg_temp_new_i64();
2667
        tcg_gen_extu_i32_tl(t1, t0);
P
pbrook 已提交
2668
        tcg_temp_free_i32(t0);
2669
        gen_qemu_st32_ppc64(t1, arg1, flags);
P
pbrook 已提交
2670
        tcg_temp_free_i64(t1);
A
aurel32 已提交
2671
    } else
2672
        gen_qemu_st32_ppc64(arg0, arg1, flags);
A
aurel32 已提交
2673 2674
}

2675
static always_inline void gen_qemu_st64(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2676 2677
{
    if (unlikely(flags & 1)) {
P
pbrook 已提交
2678
        TCGv_i64 t0 = tcg_temp_new_i64();
2679 2680
        tcg_gen_bswap_i64(t0, arg0);
        gen_qemu_st64_ppc64(t0, arg1, flags);
P
pbrook 已提交
2681
        tcg_temp_free_i64(t0);
A
aurel32 已提交
2682
    } else
2683
        gen_qemu_st64_ppc64(arg0, arg1, flags);
A
aurel32 已提交
2684 2685 2686 2687
}


#else /* defined(TARGET_PPC64) */
2688 2689 2690 2691
#define GEN_QEMU_LD_PPC32(width)                                                      \
static always_inline void gen_qemu_ld##width##_ppc32(TCGv arg0, TCGv arg1, int flags) \
{                                                                                     \
    tcg_gen_qemu_ld##width(arg0, arg1, flags >> 1);                                   \
A
aurel32 已提交
2692 2693 2694 2695 2696 2697 2698
}
GEN_QEMU_LD_PPC32(8u)
GEN_QEMU_LD_PPC32(8s)
GEN_QEMU_LD_PPC32(16u)
GEN_QEMU_LD_PPC32(16s)
GEN_QEMU_LD_PPC32(32u)
GEN_QEMU_LD_PPC32(32s)
2699 2700 2701 2702
static always_inline void gen_qemu_ld64_ppc32(TCGv_i64 arg0, TCGv arg1, int flags)
{
    tcg_gen_qemu_ld64(arg0, arg1, flags >> 1);
}
A
aurel32 已提交
2703

2704 2705 2706 2707
#define GEN_QEMU_ST_PPC32(width)                                                      \
static always_inline void gen_qemu_st##width##_ppc32(TCGv arg0, TCGv arg1, int flags) \
{                                                                                     \
    tcg_gen_qemu_st##width(arg0, arg1, flags >> 1);                                   \
A
aurel32 已提交
2708 2709 2710 2711
}
GEN_QEMU_ST_PPC32(8)
GEN_QEMU_ST_PPC32(16)
GEN_QEMU_ST_PPC32(32)
2712 2713 2714 2715
static always_inline void gen_qemu_st64_ppc32(TCGv_i64 arg0, TCGv arg1, int flags)
{
    tcg_gen_qemu_st64(arg0, arg1, flags >> 1);
}
A
aurel32 已提交
2716

2717
static always_inline void gen_qemu_ld8u(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2718
{
2719
    gen_qemu_ld8u_ppc32(arg0, arg1, flags >> 1);
A
aurel32 已提交
2720 2721
}

2722
static always_inline void gen_qemu_ld8s(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2723
{
2724
    gen_qemu_ld8s_ppc32(arg0, arg1, flags >> 1);
A
aurel32 已提交
2725 2726
}

2727
static always_inline void gen_qemu_ld16u(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2728
{
2729
    gen_qemu_ld16u_ppc32(arg0, arg1, flags >> 1);
A
aurel32 已提交
2730
    if (unlikely(flags & 1))
2731
        tcg_gen_bswap16_i32(arg0, arg0);
A
aurel32 已提交
2732 2733
}

2734
static always_inline void gen_qemu_ld16s(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2735 2736
{
    if (unlikely(flags & 1)) {
2737 2738 2739
        gen_qemu_ld16u_ppc32(arg0, arg1, flags);
        tcg_gen_bswap16_i32(arg0, arg0);
        tcg_gen_ext16s_i32(arg0, arg0);
A
aurel32 已提交
2740
    } else
2741
        gen_qemu_ld16s_ppc32(arg0, arg1, flags);
A
aurel32 已提交
2742 2743
}

2744
static always_inline void gen_qemu_ld32u(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2745
{
2746
    gen_qemu_ld32u_ppc32(arg0, arg1, flags);
A
aurel32 已提交
2747
    if (unlikely(flags & 1))
2748
        tcg_gen_bswap_i32(arg0, arg0);
A
aurel32 已提交
2749 2750
}

2751 2752 2753 2754 2755 2756 2757
static always_inline void gen_qemu_ld64(TCGv_i64 arg0, TCGv arg1, int flags)
{
    gen_qemu_ld64_ppc32(arg0, arg1, flags);
    if (unlikely(flags & 1))
        tcg_gen_bswap_i64(arg0, arg0);
}

2758
static always_inline void gen_qemu_st8(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2759
{
2760
    gen_qemu_st8_ppc32(arg0, arg1, flags);
A
aurel32 已提交
2761 2762
}

2763
static always_inline void gen_qemu_st16(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2764 2765
{
    if (unlikely(flags & 1)) {
P
pbrook 已提交
2766
        TCGv_i32 temp = tcg_temp_new_i32();
2767
        tcg_gen_ext16u_i32(temp, arg0);
A
aurel32 已提交
2768
        tcg_gen_bswap16_i32(temp, temp);
2769
        gen_qemu_st16_ppc32(temp, arg1, flags);
P
pbrook 已提交
2770
        tcg_temp_free_i32(temp);
A
aurel32 已提交
2771
    } else
2772
        gen_qemu_st16_ppc32(arg0, arg1, flags);
A
aurel32 已提交
2773 2774
}

2775
static always_inline void gen_qemu_st32(TCGv arg0, TCGv arg1, int flags)
A
aurel32 已提交
2776 2777
{
    if (unlikely(flags & 1)) {
P
pbrook 已提交
2778
        TCGv_i32 temp = tcg_temp_new_i32();
2779
        tcg_gen_bswap_i32(temp, arg0);
2780
        gen_qemu_st32_ppc32(temp, arg1, flags);
P
pbrook 已提交
2781
        tcg_temp_free_i32(temp);
A
aurel32 已提交
2782
    } else
2783
        gen_qemu_st32_ppc32(arg0, arg1, flags);
A
aurel32 已提交
2784 2785
}

2786 2787 2788 2789 2790 2791 2792 2793 2794 2795
static always_inline void gen_qemu_st64(TCGv_i64 arg0, TCGv arg1, int flags)
{
    if (unlikely(flags & 1)) {
        TCGv_i64 temp = tcg_temp_new_i64();
        tcg_gen_bswap_i64(temp, arg0);
        gen_qemu_st64_ppc32(temp, arg1, flags);
        tcg_temp_free_i64(temp);
    } else
        gen_qemu_st64_ppc32(arg0, arg1, flags);
}
A
aurel32 已提交
2796 2797
#endif

2798 2799
#define GEN_LD(name, ldop, opc, type)                                         \
GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type)                          \
B
bellard 已提交
2800
{                                                                             \
2801
    TCGv EA = tcg_temp_new();                                                 \
A
aurel32 已提交
2802
    gen_set_access_type(ACCESS_INT);                                          \
A
aurel32 已提交
2803
    gen_addr_imm_index(EA, ctx, 0);                                           \
2804
    gen_qemu_##ldop(cpu_gpr[rD(ctx->opcode)], EA, ctx->mem_idx);              \
A
aurel32 已提交
2805
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2806 2807
}

2808 2809
#define GEN_LDU(name, ldop, opc, type)                                        \
GEN_HANDLER(name##u, opc, 0xFF, 0xFF, 0x00000000, type)                       \
B
bellard 已提交
2810
{                                                                             \
A
aurel32 已提交
2811
    TCGv EA;                                                                  \
2812 2813
    if (unlikely(rA(ctx->opcode) == 0 ||                                      \
                 rA(ctx->opcode) == rD(ctx->opcode))) {                       \
2814
        GEN_EXCP_INVAL(ctx);                                                  \
2815
        return;                                                               \
2816
    }                                                                         \
2817
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
2818
    gen_set_access_type(ACCESS_INT);                                          \
J
j_mayer 已提交
2819
    if (type == PPC_64B)                                                      \
A
aurel32 已提交
2820
        gen_addr_imm_index(EA, ctx, 0x03);                                    \
J
j_mayer 已提交
2821
    else                                                                      \
A
aurel32 已提交
2822
        gen_addr_imm_index(EA, ctx, 0);                                       \
2823
    gen_qemu_##ldop(cpu_gpr[rD(ctx->opcode)], EA, ctx->mem_idx);              \
A
aurel32 已提交
2824 2825
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2826 2827
}

2828 2829
#define GEN_LDUX(name, ldop, opc2, opc3, type)                                \
GEN_HANDLER(name##ux, 0x1F, opc2, opc3, 0x00000001, type)                     \
B
bellard 已提交
2830
{                                                                             \
A
aurel32 已提交
2831
    TCGv EA;                                                                  \
2832 2833
    if (unlikely(rA(ctx->opcode) == 0 ||                                      \
                 rA(ctx->opcode) == rD(ctx->opcode))) {                       \
2834
        GEN_EXCP_INVAL(ctx);                                                  \
2835
        return;                                                               \
2836
    }                                                                         \
2837
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
2838
    gen_set_access_type(ACCESS_INT);                                          \
A
aurel32 已提交
2839
    gen_addr_reg_index(EA, ctx);                                              \
2840
    gen_qemu_##ldop(cpu_gpr[rD(ctx->opcode)], EA, ctx->mem_idx);              \
A
aurel32 已提交
2841 2842
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2843 2844
}

2845 2846
#define GEN_LDX(name, ldop, opc2, opc3, type)                                 \
GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type)                      \
B
bellard 已提交
2847
{                                                                             \
2848
    TCGv EA = tcg_temp_new();                                                 \
A
aurel32 已提交
2849
    gen_set_access_type(ACCESS_INT);                                          \
A
aurel32 已提交
2850
    gen_addr_reg_index(EA, ctx);                                              \
2851
    gen_qemu_##ldop(cpu_gpr[rD(ctx->opcode)], EA, ctx->mem_idx);              \
A
aurel32 已提交
2852
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2853 2854
}

2855 2856 2857 2858 2859
#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 已提交
2860 2861

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

    /* Restore CPU state */
    if (unlikely(ctx->supervisor == 0)) {
        GEN_EXCP_PRIVOPC(ctx);
        return;
    }
    ra = rA(ctx->opcode);
    rd = rD(ctx->opcode);
    if (unlikely((rd & 1) || rd == ra)) {
        GEN_EXCP_INVAL(ctx);
        return;
    }
    if (unlikely(ctx->mem_idx & 1)) {
        /* Little-endian mode is not handled */
        GEN_EXCP(ctx, POWERPC_EXCP_ALIGN, POWERPC_EXCP_ALIGN_LE);
        return;
    }
P
pbrook 已提交
2927
    EA = tcg_temp_new();
A
aurel32 已提交
2928
    gen_set_access_type(ACCESS_INT);
A
aurel32 已提交
2929 2930 2931 2932 2933
    gen_addr_imm_index(EA, ctx, 0x0F);
    gen_qemu_ld64(cpu_gpr[rd], EA, ctx->mem_idx);
    tcg_gen_addi_tl(EA, EA, 8);
    gen_qemu_ld64(cpu_gpr[rd+1], EA, ctx->mem_idx);
    tcg_temp_free(EA);
2934 2935
#endif
}
2936
#endif
B
bellard 已提交
2937 2938

/***                              Integer store                            ***/
2939 2940
#define GEN_ST(name, stop, opc, type)                                         \
GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type)                          \
B
bellard 已提交
2941
{                                                                             \
2942
    TCGv EA = tcg_temp_new();                                                 \
A
aurel32 已提交
2943
    gen_set_access_type(ACCESS_INT);                                          \
A
aurel32 已提交
2944
    gen_addr_imm_index(EA, ctx, 0);                                           \
2945
    gen_qemu_##stop(cpu_gpr[rS(ctx->opcode)], EA, ctx->mem_idx);              \
A
aurel32 已提交
2946
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2947 2948
}

2949 2950
#define GEN_STU(name, stop, opc, type)                                        \
GEN_HANDLER(stop##u, opc, 0xFF, 0xFF, 0x00000000, type)                       \
B
bellard 已提交
2951
{                                                                             \
A
aurel32 已提交
2952
    TCGv EA;                                                                  \
2953
    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
2954
        GEN_EXCP_INVAL(ctx);                                                  \
2955
        return;                                                               \
2956
    }                                                                         \
2957
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
2958
    gen_set_access_type(ACCESS_INT);                                          \
J
j_mayer 已提交
2959
    if (type == PPC_64B)                                                      \
A
aurel32 已提交
2960
        gen_addr_imm_index(EA, ctx, 0x03);                                    \
J
j_mayer 已提交
2961
    else                                                                      \
A
aurel32 已提交
2962
        gen_addr_imm_index(EA, ctx, 0);                                       \
2963
    gen_qemu_##stop(cpu_gpr[rS(ctx->opcode)], EA, ctx->mem_idx);              \
A
aurel32 已提交
2964 2965
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2966 2967
}

2968 2969
#define GEN_STUX(name, stop, opc2, opc3, type)                                \
GEN_HANDLER(name##ux, 0x1F, opc2, opc3, 0x00000001, type)                     \
B
bellard 已提交
2970
{                                                                             \
A
aurel32 已提交
2971
    TCGv EA;                                                                  \
2972
    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
2973
        GEN_EXCP_INVAL(ctx);                                                  \
2974
        return;                                                               \
2975
    }                                                                         \
2976
    EA = tcg_temp_new();                                                      \
A
aurel32 已提交
2977
    gen_set_access_type(ACCESS_INT);                                          \
A
aurel32 已提交
2978
    gen_addr_reg_index(EA, ctx);                                              \
2979
    gen_qemu_##stop(cpu_gpr[rS(ctx->opcode)], EA, ctx->mem_idx);              \
A
aurel32 已提交
2980 2981
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2982 2983
}

2984 2985
#define GEN_STX(name, stop, opc2, opc3, type)                                 \
GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type)                      \
B
bellard 已提交
2986
{                                                                             \
2987
    TCGv EA = tcg_temp_new();                                                 \
A
aurel32 已提交
2988
    gen_set_access_type(ACCESS_INT);                                          \
A
aurel32 已提交
2989
    gen_addr_reg_index(EA, ctx);                                              \
2990
    gen_qemu_##stop(cpu_gpr[rS(ctx->opcode)], EA, ctx->mem_idx);              \
A
aurel32 已提交
2991
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
2992 2993
}

2994 2995 2996 2997 2998
#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 已提交
2999 3000

/* stb stbu stbux stbx */
3001
GEN_STS(stb, st8, 0x06, PPC_INTEGER);
B
bellard 已提交
3002
/* sth sthu sthux sthx */
3003
GEN_STS(sth, st16, 0x0C, PPC_INTEGER);
B
bellard 已提交
3004
/* stw stwu stwux stwx */
3005
GEN_STS(stw, st32, 0x04, PPC_INTEGER);
3006
#if defined(TARGET_PPC64)
3007 3008
GEN_STUX(std, st64, 0x15, 0x05, PPC_64B);
GEN_STX(std, st64, 0x15, 0x04, PPC_64B);
3009
GEN_HANDLER(std, 0x3E, 0xFF, 0xFF, 0x00000000, PPC_64B)
3010
{
3011
    int rs;
A
aurel32 已提交
3012
    TCGv EA;
3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024

    rs = rS(ctx->opcode);
    if ((ctx->opcode & 0x3) == 0x2) {
#if defined(CONFIG_USER_ONLY)
        GEN_EXCP_PRIVOPC(ctx);
#else
        /* stq */
        if (unlikely(ctx->supervisor == 0)) {
            GEN_EXCP_PRIVOPC(ctx);
            return;
        }
        if (unlikely(rs & 1)) {
3025
            GEN_EXCP_INVAL(ctx);
3026 3027
            return;
        }
3028 3029 3030 3031 3032
        if (unlikely(ctx->mem_idx & 1)) {
            /* Little-endian mode is not handled */
            GEN_EXCP(ctx, POWERPC_EXCP_ALIGN, POWERPC_EXCP_ALIGN_LE);
            return;
        }
P
pbrook 已提交
3033
        EA = tcg_temp_new();
A
aurel32 已提交
3034
        gen_set_access_type(ACCESS_INT);
A
aurel32 已提交
3035 3036 3037 3038 3039
        gen_addr_imm_index(EA, ctx, 0x03);
        gen_qemu_st64(cpu_gpr[rs], EA, ctx->mem_idx);
        tcg_gen_addi_tl(EA, EA, 8);
        gen_qemu_st64(cpu_gpr[rs+1], EA, ctx->mem_idx);
        tcg_temp_free(EA);
3040 3041 3042 3043 3044 3045 3046 3047 3048
#endif
    } else {
        /* std / stdu */
        if (Rc(ctx->opcode)) {
            if (unlikely(rA(ctx->opcode) == 0)) {
                GEN_EXCP_INVAL(ctx);
                return;
            }
        }
P
pbrook 已提交
3049
        EA = tcg_temp_new();
A
aurel32 已提交
3050
        gen_set_access_type(ACCESS_INT);
A
aurel32 已提交
3051 3052
        gen_addr_imm_index(EA, ctx, 0x03);
        gen_qemu_st64(cpu_gpr[rs], EA, ctx->mem_idx);
3053
        if (Rc(ctx->opcode))
A
aurel32 已提交
3054 3055
            tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);
        tcg_temp_free(EA);
3056 3057 3058
    }
}
#endif
B
bellard 已提交
3059 3060
/***                Integer load and store with byte reverse               ***/
/* lhbrx */
A
aurel32 已提交
3061 3062
void always_inline gen_qemu_ld16ur(TCGv t0, TCGv t1, int flags)
{
P
pbrook 已提交
3063 3064 3065
    TCGv_i32 temp = tcg_temp_new_i32();
    gen_qemu_ld16u(t0, t1, flags);
    tcg_gen_trunc_tl_i32(temp, t0);
A
aurel32 已提交
3066 3067
    tcg_gen_bswap16_i32(temp, temp);
    tcg_gen_extu_i32_tl(t0, temp);
P
pbrook 已提交
3068
    tcg_temp_free_i32(temp);
A
aurel32 已提交
3069
}
3070
GEN_LDX(lhbr, ld16ur, 0x16, 0x18, PPC_INTEGER);
A
aurel32 已提交
3071

B
bellard 已提交
3072
/* lwbrx */
A
aurel32 已提交
3073 3074
void always_inline gen_qemu_ld32ur(TCGv t0, TCGv t1, int flags)
{
P
pbrook 已提交
3075 3076 3077
    TCGv_i32 temp = tcg_temp_new_i32();
    gen_qemu_ld32u(t0, t1, flags);
    tcg_gen_trunc_tl_i32(temp, t0);
A
aurel32 已提交
3078 3079
    tcg_gen_bswap_i32(temp, temp);
    tcg_gen_extu_i32_tl(t0, temp);
P
pbrook 已提交
3080
    tcg_temp_free_i32(temp);
A
aurel32 已提交
3081
}
3082
GEN_LDX(lwbr, ld32ur, 0x16, 0x10, PPC_INTEGER);
A
aurel32 已提交
3083

B
bellard 已提交
3084
/* sthbrx */
A
aurel32 已提交
3085 3086
void always_inline gen_qemu_st16r(TCGv t0, TCGv t1, int flags)
{
P
pbrook 已提交
3087 3088
    TCGv_i32 temp = tcg_temp_new_i32();
    TCGv t2 = tcg_temp_new();
A
aurel32 已提交
3089 3090 3091
    tcg_gen_trunc_tl_i32(temp, t0);
    tcg_gen_ext16u_i32(temp, temp);
    tcg_gen_bswap16_i32(temp, temp);
P
pbrook 已提交
3092 3093 3094 3095
    tcg_gen_extu_i32_tl(t2, temp);
    tcg_temp_free_i32(temp);
    gen_qemu_st16(t2, t1, flags);
    tcg_temp_free(t2);
A
aurel32 已提交
3096
}
3097
GEN_STX(sthbr, st16r, 0x16, 0x1C, PPC_INTEGER);
A
aurel32 已提交
3098

B
bellard 已提交
3099
/* stwbrx */
A
aurel32 已提交
3100 3101
void always_inline gen_qemu_st32r(TCGv t0, TCGv t1, int flags)
{
P
pbrook 已提交
3102 3103
    TCGv_i32 temp = tcg_temp_new_i32();
    TCGv t2 = tcg_temp_new();
A
aurel32 已提交
3104 3105
    tcg_gen_trunc_tl_i32(temp, t0);
    tcg_gen_bswap_i32(temp, temp);
P
pbrook 已提交
3106 3107
    tcg_gen_extu_i32_tl(t2, temp);
    tcg_temp_free_i32(temp);
3108
    gen_qemu_st32(t2, t1, flags);
P
pbrook 已提交
3109
    tcg_temp_free(t2);
A
aurel32 已提交
3110
}
3111
GEN_STX(stwbr, st32r, 0x16, 0x14, PPC_INTEGER);
B
bellard 已提交
3112 3113

/***                    Integer load and store multiple                    ***/
3114
#define op_ldstm(name, reg) (*gen_op_##name[ctx->mem_idx])(reg)
3115 3116
static GenOpFunc1 *gen_op_lmw[NB_MEM_FUNCS] = {
    GEN_MEM_FUNCS(lmw),
3117
};
3118 3119
static GenOpFunc1 *gen_op_stmw[NB_MEM_FUNCS] = {
    GEN_MEM_FUNCS(stmw),
3120
};
3121

B
bellard 已提交
3122 3123 3124
/* lmw */
GEN_HANDLER(lmw, 0x2E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
3125
    /* NIP cannot be restored if the memory exception comes from an helper */
3126
    gen_update_nip(ctx, ctx->nip - 4);
3127
    gen_addr_imm_index(cpu_T[0], ctx, 0);
3128
    op_ldstm(lmw, rD(ctx->opcode));
B
bellard 已提交
3129 3130 3131 3132 3133
}

/* stmw */
GEN_HANDLER(stmw, 0x2F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
3134
    /* NIP cannot be restored if the memory exception comes from an helper */
3135
    gen_update_nip(ctx, ctx->nip - 4);
3136
    gen_addr_imm_index(cpu_T[0], ctx, 0);
3137
    op_ldstm(stmw, rS(ctx->opcode));
B
bellard 已提交
3138 3139 3140
}

/***                    Integer load and store strings                     ***/
3141 3142
#define op_ldsts(name, start) (*gen_op_##name[ctx->mem_idx])(start)
#define op_ldstsx(name, rd, ra, rb) (*gen_op_##name[ctx->mem_idx])(rd, ra, rb)
3143 3144 3145 3146 3147 3148 3149 3150 3151
/* string load & stores are by definition endian-safe */
#define gen_op_lswi_le_raw       gen_op_lswi_raw
#define gen_op_lswi_le_user      gen_op_lswi_user
#define gen_op_lswi_le_kernel    gen_op_lswi_kernel
#define gen_op_lswi_le_hypv      gen_op_lswi_hypv
#define gen_op_lswi_le_64_raw    gen_op_lswi_raw
#define gen_op_lswi_le_64_user   gen_op_lswi_user
#define gen_op_lswi_le_64_kernel gen_op_lswi_kernel
#define gen_op_lswi_le_64_hypv   gen_op_lswi_hypv
3152 3153
static GenOpFunc1 *gen_op_lswi[NB_MEM_FUNCS] = {
    GEN_MEM_FUNCS(lswi),
3154
};
3155 3156 3157 3158 3159 3160 3161 3162
#define gen_op_lswx_le_raw       gen_op_lswx_raw
#define gen_op_lswx_le_user      gen_op_lswx_user
#define gen_op_lswx_le_kernel    gen_op_lswx_kernel
#define gen_op_lswx_le_hypv      gen_op_lswx_hypv
#define gen_op_lswx_le_64_raw    gen_op_lswx_raw
#define gen_op_lswx_le_64_user   gen_op_lswx_user
#define gen_op_lswx_le_64_kernel gen_op_lswx_kernel
#define gen_op_lswx_le_64_hypv   gen_op_lswx_hypv
3163 3164
static GenOpFunc3 *gen_op_lswx[NB_MEM_FUNCS] = {
    GEN_MEM_FUNCS(lswx),
3165
};
3166 3167 3168 3169 3170 3171 3172 3173
#define gen_op_stsw_le_raw       gen_op_stsw_raw
#define gen_op_stsw_le_user      gen_op_stsw_user
#define gen_op_stsw_le_kernel    gen_op_stsw_kernel
#define gen_op_stsw_le_hypv      gen_op_stsw_hypv
#define gen_op_stsw_le_64_raw    gen_op_stsw_raw
#define gen_op_stsw_le_64_user   gen_op_stsw_user
#define gen_op_stsw_le_64_kernel gen_op_stsw_kernel
#define gen_op_stsw_le_64_hypv   gen_op_stsw_hypv
3174 3175
static GenOpFunc1 *gen_op_stsw[NB_MEM_FUNCS] = {
    GEN_MEM_FUNCS(stsw),
3176 3177
};

B
bellard 已提交
3178
/* lswi */
3179
/* PowerPC32 specification says we must generate an exception if
3180 3181 3182 3183
 * 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...
 */
3184
GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_STRING)
B
bellard 已提交
3185 3186 3187
{
    int nb = NB(ctx->opcode);
    int start = rD(ctx->opcode);
3188
    int ra = rA(ctx->opcode);
B
bellard 已提交
3189 3190 3191 3192 3193
    int nr;

    if (nb == 0)
        nb = 32;
    nr = nb / 4;
3194 3195 3196
    if (unlikely(((start + nr) > 32  &&
                  start <= ra && (start + nr - 32) > ra) ||
                 ((start + nr) <= 32 && start <= ra && (start + nr) > ra))) {
3197 3198
        GEN_EXCP(ctx, POWERPC_EXCP_PROGRAM,
                 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_LSWX);
3199
        return;
B
bellard 已提交
3200
    }
3201
    /* NIP cannot be restored if the memory exception comes from an helper */
3202
    gen_update_nip(ctx, ctx->nip - 4);
3203
    gen_addr_register(cpu_T[0], ctx);
3204
    tcg_gen_movi_tl(cpu_T[1], nb);
3205
    op_ldsts(lswi, start);
B
bellard 已提交
3206 3207 3208
}

/* lswx */
3209
GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001, PPC_STRING)
B
bellard 已提交
3210
{
3211 3212 3213
    int ra = rA(ctx->opcode);
    int rb = rB(ctx->opcode);

3214
    /* NIP cannot be restored if the memory exception comes from an helper */
3215
    gen_update_nip(ctx, ctx->nip - 4);
3216
    gen_addr_reg_index(cpu_T[0], ctx);
3217 3218
    if (ra == 0) {
        ra = rb;
B
bellard 已提交
3219
    }
A
aurel32 已提交
3220
    tcg_gen_andi_tl(cpu_T[1], cpu_xer, 0x7F);
3221
    op_ldstsx(lswx, rD(ctx->opcode), ra, rb);
B
bellard 已提交
3222 3223 3224
}

/* stswi */
3225
GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_STRING)
B
bellard 已提交
3226
{
B
bellard 已提交
3227 3228
    int nb = NB(ctx->opcode);

3229
    /* NIP cannot be restored if the memory exception comes from an helper */
3230
    gen_update_nip(ctx, ctx->nip - 4);
3231
    gen_addr_register(cpu_T[0], ctx);
B
bellard 已提交
3232 3233
    if (nb == 0)
        nb = 32;
3234
    tcg_gen_movi_tl(cpu_T[1], nb);
3235
    op_ldsts(stsw, rS(ctx->opcode));
B
bellard 已提交
3236 3237 3238
}

/* stswx */
3239
GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_STRING)
B
bellard 已提交
3240
{
3241
    /* NIP cannot be restored if the memory exception comes from an helper */
3242
    gen_update_nip(ctx, ctx->nip - 4);
3243
    gen_addr_reg_index(cpu_T[0], ctx);
A
aurel32 已提交
3244
    tcg_gen_andi_tl(cpu_T[1], cpu_xer, 0x7F);
3245
    op_ldsts(stsw, rS(ctx->opcode));
B
bellard 已提交
3246 3247 3248 3249
}

/***                        Memory synchronisation                         ***/
/* eieio */
3250
GEN_HANDLER(eieio, 0x1F, 0x16, 0x1A, 0x03FFF801, PPC_MEM_EIEIO)
B
bellard 已提交
3251 3252 3253 3254
{
}

/* isync */
3255
GEN_HANDLER(isync, 0x13, 0x16, 0x04, 0x03FFF801, PPC_MEM)
B
bellard 已提交
3256
{
3257
    GEN_STOP(ctx);
B
bellard 已提交
3258 3259
}

3260 3261
#define op_lwarx() (*gen_op_lwarx[ctx->mem_idx])()
#define op_stwcx() (*gen_op_stwcx[ctx->mem_idx])()
3262 3263
static GenOpFunc *gen_op_lwarx[NB_MEM_FUNCS] = {
    GEN_MEM_FUNCS(lwarx),
3264
};
3265 3266
static GenOpFunc *gen_op_stwcx[NB_MEM_FUNCS] = {
    GEN_MEM_FUNCS(stwcx),
B
bellard 已提交
3267
};
3268

3269
/* lwarx */
3270
GEN_HANDLER(lwarx, 0x1F, 0x14, 0x00, 0x00000001, PPC_RES)
B
bellard 已提交
3271
{
3272 3273
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
A
aurel32 已提交
3274
    gen_set_access_type(ACCESS_RES);
3275
    gen_addr_reg_index(cpu_T[0], ctx);
B
bellard 已提交
3276
    op_lwarx();
A
aurel32 已提交
3277
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[1]);
B
bellard 已提交
3278 3279 3280
}

/* stwcx. */
3281
GEN_HANDLER2(stwcx_, "stwcx.", 0x1F, 0x16, 0x04, 0x00000000, PPC_RES)
B
bellard 已提交
3282
{
3283 3284
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
A
aurel32 已提交
3285
    gen_set_access_type(ACCESS_RES);
3286
    gen_addr_reg_index(cpu_T[0], ctx);
A
aurel32 已提交
3287
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]);
3288
    op_stwcx();
B
bellard 已提交
3289 3290
}

J
j_mayer 已提交
3291 3292 3293
#if defined(TARGET_PPC64)
#define op_ldarx() (*gen_op_ldarx[ctx->mem_idx])()
#define op_stdcx() (*gen_op_stdcx[ctx->mem_idx])()
3294 3295
static GenOpFunc *gen_op_ldarx[NB_MEM_FUNCS] = {
    GEN_MEM_FUNCS(ldarx),
J
j_mayer 已提交
3296
};
3297 3298
static GenOpFunc *gen_op_stdcx[NB_MEM_FUNCS] = {
    GEN_MEM_FUNCS(stdcx),
J
j_mayer 已提交
3299 3300 3301
};

/* ldarx */
3302
GEN_HANDLER(ldarx, 0x1F, 0x14, 0x02, 0x00000001, PPC_64B)
J
j_mayer 已提交
3303
{
3304 3305
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
A
aurel32 已提交
3306
    gen_set_access_type(ACCESS_RES);
3307
    gen_addr_reg_index(cpu_T[0], ctx);
J
j_mayer 已提交
3308
    op_ldarx();
A
aurel32 已提交
3309
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[1]);
J
j_mayer 已提交
3310 3311 3312
}

/* stdcx. */
3313
GEN_HANDLER2(stdcx_, "stdcx.", 0x1F, 0x16, 0x06, 0x00000000, PPC_64B)
J
j_mayer 已提交
3314
{
3315 3316
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
A
aurel32 已提交
3317
    gen_set_access_type(ACCESS_RES);
3318
    gen_addr_reg_index(cpu_T[0], ctx);
A
aurel32 已提交
3319
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]);
J
j_mayer 已提交
3320 3321 3322 3323
    op_stdcx();
}
#endif /* defined(TARGET_PPC64) */

B
bellard 已提交
3324
/* sync */
3325
GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x039FF801, PPC_MEM_SYNC)
B
bellard 已提交
3326 3327 3328
{
}

3329 3330 3331 3332
/* wait */
GEN_HANDLER(wait, 0x1F, 0x1E, 0x01, 0x03FFF801, PPC_WAIT)
{
    /* Stop translation, as the CPU is supposed to sleep from now */
3333 3334
    gen_op_wait();
    GEN_EXCP(ctx, EXCP_HLT, 1);
3335 3336
}

B
bellard 已提交
3337
/***                         Floating-point load                           ***/
3338 3339
#define GEN_LDF(name, ldop, opc, type)                                        \
GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type)                          \
B
bellard 已提交
3340
{                                                                             \
3341
    TCGv EA;                                                                  \
3342
    if (unlikely(!ctx->fpu_enabled)) {                                        \
3343
        GEN_EXCP_NO_FP(ctx);                                                  \
3344 3345
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
3346
    gen_set_access_type(ACCESS_FLOAT);                                        \
3347 3348 3349 3350
    EA = tcg_temp_new();                                                      \
    gen_addr_imm_index(EA, ctx, 0);                                           \
    gen_qemu_##ldop(cpu_fpr[rD(ctx->opcode)], EA, ctx->mem_idx);              \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
3351 3352
}

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

3373 3374
#define GEN_LDUXF(name, ldop, opc, type)                                      \
GEN_HANDLER(name##ux, 0x1F, 0x17, opc, 0x00000001, type)                      \
B
bellard 已提交
3375
{                                                                             \
3376
    TCGv EA;                                                                  \
3377
    if (unlikely(!ctx->fpu_enabled)) {                                        \
3378
        GEN_EXCP_NO_FP(ctx);                                                  \
3379 3380
        return;                                                               \
    }                                                                         \
3381
    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
3382
        GEN_EXCP_INVAL(ctx);                                                  \
3383
        return;                                                               \
3384
    }                                                                         \
A
aurel32 已提交
3385
    gen_set_access_type(ACCESS_FLOAT);                                        \
3386 3387 3388 3389 3390
    EA = tcg_temp_new();                                                      \
    gen_addr_reg_index(EA, ctx);                                              \
    gen_qemu_##ldop(cpu_fpr[rD(ctx->opcode)], EA, ctx->mem_idx);              \
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
3391 3392
}

3393 3394
#define GEN_LDXF(name, ldop, opc2, opc3, type)                                \
GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type)                      \
B
bellard 已提交
3395
{                                                                             \
3396
    TCGv EA;                                                                  \
3397
    if (unlikely(!ctx->fpu_enabled)) {                                        \
3398
        GEN_EXCP_NO_FP(ctx);                                                  \
3399 3400
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
3401
    gen_set_access_type(ACCESS_FLOAT);                                        \
3402 3403 3404 3405
    EA = tcg_temp_new();                                                      \
    gen_addr_reg_index(EA, ctx);                                              \
    gen_qemu_##ldop(cpu_fpr[rD(ctx->opcode)], EA, ctx->mem_idx);              \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
3406 3407
}

3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423
#define GEN_LDFS(name, ldop, op, type)                                        \
GEN_LDF(name, ldop, op | 0x20, type);                                         \
GEN_LDUF(name, ldop, op | 0x21, type);                                        \
GEN_LDUXF(name, ldop, op | 0x01, type);                                       \
GEN_LDXF(name, ldop, 0x17, op | 0x00, type)

static always_inline void gen_qemu_ld32fs(TCGv_i64 arg1, TCGv arg2, int flags)
{
    TCGv t0 = tcg_temp_new();
    TCGv_i32 t1 = tcg_temp_new_i32();
    gen_qemu_ld32u(t0, arg2, flags);
    tcg_gen_trunc_tl_i32(t1, t0);
    tcg_temp_free(t0);
    gen_helper_float32_to_float64(arg1, t1);
    tcg_temp_free_i32(t1);
}
B
bellard 已提交
3424

3425 3426 3427 3428
 /* lfd lfdu lfdux lfdx */
GEN_LDFS(lfd, ld64, 0x12, PPC_FLOAT);
 /* lfs lfsu lfsux lfsx */
GEN_LDFS(lfs, ld32fs, 0x10, PPC_FLOAT);
B
bellard 已提交
3429 3430

/***                         Floating-point store                          ***/
3431 3432
#define GEN_STF(name, stop, opc, type)                                        \
GEN_HANDLER(name, opc, 0xFF, 0xFF, 0x00000000, type)                          \
B
bellard 已提交
3433
{                                                                             \
3434
    TCGv EA;                                                                  \
3435
    if (unlikely(!ctx->fpu_enabled)) {                                        \
3436
        GEN_EXCP_NO_FP(ctx);                                                  \
3437 3438
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
3439
    gen_set_access_type(ACCESS_FLOAT);                                        \
3440 3441 3442 3443
    EA = tcg_temp_new();                                                      \
    gen_addr_imm_index(EA, ctx, 0);                                           \
    gen_qemu_##stop(cpu_fpr[rS(ctx->opcode)], EA, ctx->mem_idx);              \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
3444 3445
}

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

3466 3467
#define GEN_STUXF(name, stop, opc, type)                                      \
GEN_HANDLER(name##ux, 0x1F, 0x17, opc, 0x00000001, type)                      \
B
bellard 已提交
3468
{                                                                             \
3469
    TCGv EA;                                                                  \
3470
    if (unlikely(!ctx->fpu_enabled)) {                                        \
3471
        GEN_EXCP_NO_FP(ctx);                                                  \
3472 3473
        return;                                                               \
    }                                                                         \
3474
    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
3475
        GEN_EXCP_INVAL(ctx);                                                  \
3476
        return;                                                               \
3477
    }                                                                         \
A
aurel32 已提交
3478
    gen_set_access_type(ACCESS_FLOAT);                                        \
3479 3480 3481 3482 3483
    EA = tcg_temp_new();                                                      \
    gen_addr_reg_index(EA, ctx);                                              \
    gen_qemu_##stop(cpu_fpr[rS(ctx->opcode)], EA, ctx->mem_idx);              \
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], EA);                             \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
3484 3485
}

3486 3487
#define GEN_STXF(name, stop, opc2, opc3, type)                                \
GEN_HANDLER(name##x, 0x1F, opc2, opc3, 0x00000001, type)                      \
B
bellard 已提交
3488
{                                                                             \
3489
    TCGv EA;                                                                  \
3490
    if (unlikely(!ctx->fpu_enabled)) {                                        \
3491
        GEN_EXCP_NO_FP(ctx);                                                  \
3492 3493
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
3494
    gen_set_access_type(ACCESS_FLOAT);                                        \
3495 3496 3497 3498
    EA = tcg_temp_new();                                                      \
    gen_addr_reg_index(EA, ctx);                                              \
    gen_qemu_##stop(cpu_fpr[rS(ctx->opcode)], EA, ctx->mem_idx);              \
    tcg_temp_free(EA);                                                        \
B
bellard 已提交
3499 3500
}

3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516
#define GEN_STFS(name, stop, op, type)                                        \
GEN_STF(name, stop, op | 0x20, type);                                         \
GEN_STUF(name, stop, op | 0x21, type);                                        \
GEN_STUXF(name, stop, op | 0x01, type);                                       \
GEN_STXF(name, stop, 0x17, op | 0x00, type)

static always_inline void gen_qemu_st32fs(TCGv_i64 arg1, TCGv arg2, int flags)
{
    TCGv_i32 t0 = tcg_temp_new_i32();
    TCGv t1 = tcg_temp_new();
    gen_helper_float64_to_float32(t0, arg1);
    tcg_gen_extu_i32_tl(t1, t0);
    tcg_temp_free_i32(t0);
    gen_qemu_st32(t1, arg2, flags);
    tcg_temp_free(t1);
}
B
bellard 已提交
3517 3518

/* stfd stfdu stfdux stfdx */
3519
GEN_STFS(stfd, st64, 0x16, PPC_FLOAT);
B
bellard 已提交
3520
/* stfs stfsu stfsux stfsx */
3521
GEN_STFS(stfs, st32fs, 0x14, PPC_FLOAT);
B
bellard 已提交
3522 3523

/* Optional: */
3524 3525 3526 3527 3528 3529 3530
static always_inline void gen_qemu_st32fiw(TCGv_i64 arg1, TCGv arg2, int flags)
{
    TCGv t0 = tcg_temp_new();
    tcg_gen_trunc_i64_tl(t0, arg1),
    gen_qemu_st32(t0, arg2, flags);
    tcg_temp_free(t0);
}
B
bellard 已提交
3531
/* stfiwx */
3532
GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX);
B
bellard 已提交
3533 3534

/***                                Branch                                 ***/
3535 3536
static always_inline void gen_goto_tb (DisasContext *ctx, int n,
                                       target_ulong dest)
3537 3538 3539
{
    TranslationBlock *tb;
    tb = ctx->tb;
3540 3541 3542 3543
#if defined(TARGET_PPC64)
    if (!ctx->sf_mode)
        dest = (uint32_t) dest;
#endif
B
bellard 已提交
3544
    if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) &&
3545
        likely(!ctx->singlestep_enabled)) {
B
bellard 已提交
3546
        tcg_gen_goto_tb(n);
3547
        tcg_gen_movi_tl(cpu_nip, dest & ~3);
B
bellard 已提交
3548
        tcg_gen_exit_tb((long)tb + n);
3549
    } else {
3550
        tcg_gen_movi_tl(cpu_nip, dest & ~3);
3551 3552
        if (unlikely(ctx->singlestep_enabled)) {
            if ((ctx->singlestep_enabled &
A
aurel32 已提交
3553
                (CPU_BRANCH_STEP | CPU_SINGLE_STEP)) &&
3554 3555 3556 3557 3558 3559 3560 3561
                ctx->exception == POWERPC_EXCP_BRANCH) {
                target_ulong tmp = ctx->nip;
                ctx->nip = dest;
                GEN_EXCP(ctx, POWERPC_EXCP_TRACE, 0);
                ctx->nip = tmp;
            }
            if (ctx->singlestep_enabled & GDBSTUB_SINGLE_STEP) {
                gen_update_nip(ctx, dest);
3562
                gen_helper_raise_debug();
3563 3564
            }
        }
B
bellard 已提交
3565
        tcg_gen_exit_tb(0);
3566
    }
B
bellard 已提交
3567 3568
}

3569
static always_inline void gen_setlr (DisasContext *ctx, target_ulong nip)
3570 3571
{
#if defined(TARGET_PPC64)
3572 3573
    if (ctx->sf_mode == 0)
        tcg_gen_movi_tl(cpu_lr, (uint32_t)nip);
3574 3575
    else
#endif
3576
        tcg_gen_movi_tl(cpu_lr, nip);
3577 3578
}

B
bellard 已提交
3579 3580 3581
/* b ba bl bla */
GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
{
3582
    target_ulong li, target;
B
bellard 已提交
3583

3584
    ctx->exception = POWERPC_EXCP_BRANCH;
B
bellard 已提交
3585
    /* sign extend LI */
3586
#if defined(TARGET_PPC64)
3587 3588 3589
    if (ctx->sf_mode)
        li = ((int64_t)LI(ctx->opcode) << 38) >> 38;
    else
3590
#endif
3591
        li = ((int32_t)LI(ctx->opcode) << 6) >> 6;
3592
    if (likely(AA(ctx->opcode) == 0))
B
bellard 已提交
3593
        target = ctx->nip + li - 4;
B
bellard 已提交
3594
    else
3595
        target = li;
3596 3597
    if (LK(ctx->opcode))
        gen_setlr(ctx, ctx->nip);
3598
    gen_goto_tb(ctx, 0, target);
B
bellard 已提交
3599 3600
}

3601 3602 3603 3604
#define BCOND_IM  0
#define BCOND_LR  1
#define BCOND_CTR 2

3605
static always_inline void gen_bcond (DisasContext *ctx, int type)
3606 3607
{
    uint32_t bo = BO(ctx->opcode);
3608 3609
    int l1 = gen_new_label();
    TCGv target;
3610

3611
    ctx->exception = POWERPC_EXCP_BRANCH;
3612
    if (type == BCOND_LR || type == BCOND_CTR) {
P
pbrook 已提交
3613
        target = tcg_temp_local_new();
3614 3615 3616 3617
        if (type == BCOND_CTR)
            tcg_gen_mov_tl(target, cpu_ctr);
        else
            tcg_gen_mov_tl(target, cpu_lr);
3618
    }
3619 3620
    if (LK(ctx->opcode))
        gen_setlr(ctx, ctx->nip);
3621 3622 3623
    l1 = gen_new_label();
    if ((bo & 0x4) == 0) {
        /* Decrement and test CTR */
P
pbrook 已提交
3624
        TCGv temp = tcg_temp_new();
3625 3626 3627 3628 3629
        if (unlikely(type == BCOND_CTR)) {
            GEN_EXCP_INVAL(ctx);
            return;
        }
        tcg_gen_subi_tl(cpu_ctr, cpu_ctr, 1);
3630
#if defined(TARGET_PPC64)
3631 3632 3633
        if (!ctx->sf_mode)
            tcg_gen_ext32u_tl(temp, cpu_ctr);
        else
3634
#endif
3635 3636 3637 3638 3639
            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);
3640
        }
P
pbrook 已提交
3641
        tcg_temp_free(temp);
3642 3643 3644 3645 3646
    }
    if ((bo & 0x10) == 0) {
        /* Test CR */
        uint32_t bi = BI(ctx->opcode);
        uint32_t mask = 1 << (3 - (bi & 0x03));
P
pbrook 已提交
3647
        TCGv_i32 temp = tcg_temp_new_i32();
3648

3649
        if (bo & 0x8) {
3650 3651
            tcg_gen_andi_i32(temp, cpu_crf[bi >> 2], mask);
            tcg_gen_brcondi_i32(TCG_COND_EQ, temp, 0, l1);
3652
        } else {
3653 3654
            tcg_gen_andi_i32(temp, cpu_crf[bi >> 2], mask);
            tcg_gen_brcondi_i32(TCG_COND_NE, temp, 0, l1);
3655
        }
P
pbrook 已提交
3656
        tcg_temp_free_i32(temp);
3657
    }
3658
    if (type == BCOND_IM) {
3659 3660 3661 3662 3663 3664
        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 已提交
3665
        gen_set_label(l1);
3666
        gen_goto_tb(ctx, 1, ctx->nip);
3667
    } else {
3668
#if defined(TARGET_PPC64)
3669 3670 3671 3672 3673 3674 3675 3676 3677 3678
        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);
3679 3680
        else
#endif
3681
            tcg_gen_movi_tl(cpu_nip, ctx->nip);
B
bellard 已提交
3682
        tcg_gen_exit_tb(0);
J
j_mayer 已提交
3683
    }
3684 3685 3686
}

GEN_HANDLER(bc, 0x10, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
3687
{
3688 3689 3690 3691
    gen_bcond(ctx, BCOND_IM);
}

GEN_HANDLER(bcctr, 0x13, 0x10, 0x10, 0x00000000, PPC_FLOW)
3692
{
3693 3694 3695 3696
    gen_bcond(ctx, BCOND_CTR);
}

GEN_HANDLER(bclr, 0x13, 0x10, 0x00, 0x00000000, PPC_FLOW)
3697
{
3698 3699
    gen_bcond(ctx, BCOND_LR);
}
B
bellard 已提交
3700 3701

/***                      Condition register logical                       ***/
3702 3703
#define GEN_CRLOGIC(name, tcg_op, opc)                                        \
GEN_HANDLER(name, 0x13, 0x01, opc, 0x00000001, PPC_INTEGER)                   \
B
bellard 已提交
3704
{                                                                             \
3705 3706
    uint8_t bitmask;                                                          \
    int sh;                                                                   \
P
pbrook 已提交
3707
    TCGv_i32 t0, t1;                                                          \
3708
    sh = (crbD(ctx->opcode) & 0x03) - (crbA(ctx->opcode) & 0x03);             \
P
pbrook 已提交
3709
    t0 = tcg_temp_new_i32();                                                  \
3710
    if (sh > 0)                                                               \
3711
        tcg_gen_shri_i32(t0, cpu_crf[crbA(ctx->opcode) >> 2], sh);            \
3712
    else if (sh < 0)                                                          \
3713
        tcg_gen_shli_i32(t0, cpu_crf[crbA(ctx->opcode) >> 2], -sh);           \
3714
    else                                                                      \
3715
        tcg_gen_mov_i32(t0, cpu_crf[crbA(ctx->opcode) >> 2]);                 \
P
pbrook 已提交
3716
    t1 = tcg_temp_new_i32();                                                  \
3717 3718
    sh = (crbD(ctx->opcode) & 0x03) - (crbB(ctx->opcode) & 0x03);             \
    if (sh > 0)                                                               \
3719
        tcg_gen_shri_i32(t1, cpu_crf[crbB(ctx->opcode) >> 2], sh);            \
3720
    else if (sh < 0)                                                          \
3721
        tcg_gen_shli_i32(t1, cpu_crf[crbB(ctx->opcode) >> 2], -sh);           \
3722
    else                                                                      \
3723 3724
        tcg_gen_mov_i32(t1, cpu_crf[crbB(ctx->opcode) >> 2]);                 \
    tcg_op(t0, t0, t1);                                                       \
3725
    bitmask = 1 << (3 - (crbD(ctx->opcode) & 0x03));                          \
3726 3727 3728
    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 已提交
3729 3730
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
B
bellard 已提交
3731 3732 3733
}

/* crand */
3734
GEN_CRLOGIC(crand, tcg_gen_and_i32, 0x08);
B
bellard 已提交
3735
/* crandc */
3736
GEN_CRLOGIC(crandc, tcg_gen_andc_i32, 0x04);
B
bellard 已提交
3737
/* creqv */
3738
GEN_CRLOGIC(creqv, tcg_gen_eqv_i32, 0x09);
B
bellard 已提交
3739
/* crnand */
3740
GEN_CRLOGIC(crnand, tcg_gen_nand_i32, 0x07);
B
bellard 已提交
3741
/* crnor */
3742
GEN_CRLOGIC(crnor, tcg_gen_nor_i32, 0x01);
B
bellard 已提交
3743
/* cror */
3744
GEN_CRLOGIC(cror, tcg_gen_or_i32, 0x0E);
B
bellard 已提交
3745
/* crorc */
3746
GEN_CRLOGIC(crorc, tcg_gen_orc_i32, 0x0D);
B
bellard 已提交
3747
/* crxor */
3748
GEN_CRLOGIC(crxor, tcg_gen_xor_i32, 0x06);
B
bellard 已提交
3749 3750 3751
/* mcrf */
GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER)
{
A
aurel32 已提交
3752
    tcg_gen_mov_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfS(ctx->opcode)]);
B
bellard 已提交
3753 3754 3755 3756
}

/***                           System linkage                              ***/
/* rfi (supervisor only) */
3757
GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW)
B
bellard 已提交
3758
{
3759
#if defined(CONFIG_USER_ONLY)
3760
    GEN_EXCP_PRIVOPC(ctx);
3761 3762
#else
    /* Restore CPU state */
3763
    if (unlikely(!ctx->supervisor)) {
3764
        GEN_EXCP_PRIVOPC(ctx);
3765
        return;
3766
    }
3767
    gen_op_rfi();
3768
    GEN_SYNC(ctx);
3769
#endif
B
bellard 已提交
3770 3771
}

J
j_mayer 已提交
3772
#if defined(TARGET_PPC64)
3773
GEN_HANDLER(rfid, 0x13, 0x12, 0x00, 0x03FF8001, PPC_64B)
J
j_mayer 已提交
3774 3775
{
#if defined(CONFIG_USER_ONLY)
3776
    GEN_EXCP_PRIVOPC(ctx);
J
j_mayer 已提交
3777 3778 3779
#else
    /* Restore CPU state */
    if (unlikely(!ctx->supervisor)) {
3780
        GEN_EXCP_PRIVOPC(ctx);
J
j_mayer 已提交
3781 3782
        return;
    }
3783
    gen_op_rfid();
3784
    GEN_SYNC(ctx);
J
j_mayer 已提交
3785 3786 3787
#endif
}

J
j_mayer 已提交
3788
GEN_HANDLER(hrfid, 0x13, 0x12, 0x08, 0x03FF8001, PPC_64H)
3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803
{
#if defined(CONFIG_USER_ONLY)
    GEN_EXCP_PRIVOPC(ctx);
#else
    /* Restore CPU state */
    if (unlikely(ctx->supervisor <= 1)) {
        GEN_EXCP_PRIVOPC(ctx);
        return;
    }
    gen_op_hrfid();
    GEN_SYNC(ctx);
#endif
}
#endif

B
bellard 已提交
3804
/* sc */
3805 3806 3807 3808 3809
#if defined(CONFIG_USER_ONLY)
#define POWERPC_SYSCALL POWERPC_EXCP_SYSCALL_USER
#else
#define POWERPC_SYSCALL POWERPC_EXCP_SYSCALL
#endif
3810
GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFF01D, PPC_FLOW)
B
bellard 已提交
3811
{
3812 3813 3814
    uint32_t lev;

    lev = (ctx->opcode >> 5) & 0x7F;
3815
    GEN_EXCP(ctx, POWERPC_SYSCALL, lev);
B
bellard 已提交
3816 3817 3818 3819
}

/***                                Trap                                   ***/
/* tw */
3820
GEN_HANDLER(tw, 0x1F, 0x04, 0x00, 0x00000001, PPC_FLOW)
B
bellard 已提交
3821
{
3822
    TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
3823
    /* Update the nip since this might generate a trap exception */
3824
    gen_update_nip(ctx, ctx->nip);
3825 3826
    gen_helper_tw(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], t0);
    tcg_temp_free_i32(t0);
B
bellard 已提交
3827 3828 3829 3830 3831
}

/* twi */
GEN_HANDLER(twi, 0x03, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
{
3832 3833
    TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
    TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
3834 3835
    /* Update the nip since this might generate a trap exception */
    gen_update_nip(ctx, ctx->nip);
3836 3837 3838
    gen_helper_tw(cpu_gpr[rA(ctx->opcode)], t0, t1);
    tcg_temp_free(t0);
    tcg_temp_free_i32(t1);
B
bellard 已提交
3839 3840
}

3841 3842 3843 3844
#if defined(TARGET_PPC64)
/* td */
GEN_HANDLER(td, 0x1F, 0x04, 0x02, 0x00000001, PPC_64B)
{
3845
    TCGv_i32 t0 = tcg_const_i32(TO(ctx->opcode));
3846 3847
    /* Update the nip since this might generate a trap exception */
    gen_update_nip(ctx, ctx->nip);
3848 3849
    gen_helper_td(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], t0);
    tcg_temp_free_i32(t0);
3850 3851 3852 3853 3854
}

/* tdi */
GEN_HANDLER(tdi, 0x02, 0xFF, 0xFF, 0x00000000, PPC_64B)
{
3855 3856
    TCGv t0 = tcg_const_tl(SIMM(ctx->opcode));
    TCGv_i32 t1 = tcg_const_i32(TO(ctx->opcode));
3857 3858
    /* Update the nip since this might generate a trap exception */
    gen_update_nip(ctx, ctx->nip);
3859 3860 3861
    gen_helper_td(cpu_gpr[rA(ctx->opcode)], t0, t1);
    tcg_temp_free(t0);
    tcg_temp_free_i32(t1);
3862 3863 3864
}
#endif

B
bellard 已提交
3865 3866 3867 3868
/***                          Processor control                            ***/
/* mcrxr */
GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC)
{
A
aurel32 已提交
3869 3870
    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);
3871
    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~(1 << XER_SO | 1 << XER_OV | 1 << XER_CA));
B
bellard 已提交
3872 3873 3874
}

/* mfcr */
3875
GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x00000801, PPC_MISC)
B
bellard 已提交
3876
{
3877
    uint32_t crm, crn;
3878

3879 3880 3881 3882
    if (likely(ctx->opcode & 0x00100000)) {
        crm = CRM(ctx->opcode);
        if (likely((crm ^ (crm - 1)) == 0)) {
            crn = ffs(crm);
3883
            tcg_gen_extu_i32_tl(cpu_gpr[rD(ctx->opcode)], cpu_crf[7 - crn]);
3884
        }
3885
    } else {
P
pbrook 已提交
3886
        gen_helper_load_cr(cpu_gpr[rD(ctx->opcode)]);
3887
    }
B
bellard 已提交
3888 3889 3890 3891 3892
}

/* mfmsr */
GEN_HANDLER(mfmsr, 0x1F, 0x13, 0x02, 0x001FF801, PPC_MISC)
{
3893
#if defined(CONFIG_USER_ONLY)
3894
    GEN_EXCP_PRIVREG(ctx);
3895
#else
3896
    if (unlikely(!ctx->supervisor)) {
3897
        GEN_EXCP_PRIVREG(ctx);
3898
        return;
3899
    }
A
aurel32 已提交
3900
    gen_op_load_msr();
A
aurel32 已提交
3901
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
3902
#endif
B
bellard 已提交
3903 3904
}

J
j_mayer 已提交
3905
#if 1
3906
#define SPR_NOACCESS ((void *)(-1UL))
3907 3908 3909 3910 3911 3912 3913 3914 3915
#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 已提交
3916
/* mfspr */
3917
static always_inline void gen_op_mfspr (DisasContext *ctx)
B
bellard 已提交
3918
{
3919
    void (*read_cb)(void *opaque, int sprn);
B
bellard 已提交
3920 3921
    uint32_t sprn = SPR(ctx->opcode);

3922
#if !defined(CONFIG_USER_ONLY)
3923 3924
    if (ctx->supervisor == 2)
        read_cb = ctx->spr_cb[sprn].hea_read;
3925
    else if (ctx->supervisor)
3926 3927
        read_cb = ctx->spr_cb[sprn].oea_read;
    else
3928
#endif
3929
        read_cb = ctx->spr_cb[sprn].uea_read;
3930 3931
    if (likely(read_cb != NULL)) {
        if (likely(read_cb != SPR_NOACCESS)) {
3932
            (*read_cb)(ctx, sprn);
A
aurel32 已提交
3933
            tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
3934 3935
        } else {
            /* Privilege exception */
3936 3937 3938 3939 3940 3941
            /* 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) {
3942
                    fprintf(logfile, "Trying to read privileged spr %d %03x at "
J
j_mayer 已提交
3943
                            ADDRX "\n", sprn, sprn, ctx->nip);
3944
                }
J
j_mayer 已提交
3945 3946
                printf("Trying to read privileged spr %d %03x at " ADDRX "\n",
                       sprn, sprn, ctx->nip);
3947
            }
3948
            GEN_EXCP_PRIVREG(ctx);
B
bellard 已提交
3949
        }
3950 3951
    } else {
        /* Not defined */
J
j_mayer 已提交
3952
        if (loglevel != 0) {
J
j_mayer 已提交
3953 3954
            fprintf(logfile, "Trying to read invalid spr %d %03x at "
                    ADDRX "\n", sprn, sprn, ctx->nip);
3955
        }
J
j_mayer 已提交
3956 3957
        printf("Trying to read invalid spr %d %03x at " ADDRX "\n",
               sprn, sprn, ctx->nip);
3958 3959
        GEN_EXCP(ctx, POWERPC_EXCP_PROGRAM,
                 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_SPR);
B
bellard 已提交
3960 3961 3962
    }
}

3963
GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC)
B
bellard 已提交
3964
{
3965
    gen_op_mfspr(ctx);
3966
}
3967 3968

/* mftb */
3969
GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_MFTB)
3970 3971
{
    gen_op_mfspr(ctx);
B
bellard 已提交
3972 3973 3974
}

/* mtcrf */
3975
GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00000801, PPC_MISC)
B
bellard 已提交
3976
{
3977
    uint32_t crm, crn;
3978

3979 3980
    crm = CRM(ctx->opcode);
    if (likely((ctx->opcode & 0x00100000) || (crm ^ (crm - 1)) == 0)) {
P
pbrook 已提交
3981
        TCGv_i32 temp = tcg_temp_new_i32();
3982
        crn = ffs(crm);
P
pbrook 已提交
3983 3984
        tcg_gen_trunc_tl_i32(temp, cpu_gpr[rS(ctx->opcode)]);
        tcg_gen_shri_i32(cpu_crf[7 - crn], temp, crn * 4);
3985
        tcg_gen_andi_i32(cpu_crf[7 - crn], cpu_crf[7 - crn], 0xf);
P
pbrook 已提交
3986
        tcg_temp_free_i32(temp);
3987
    } else {
P
pbrook 已提交
3988 3989 3990
        TCGv_i32 temp = tcg_const_i32(crm);
        gen_helper_store_cr(cpu_gpr[rS(ctx->opcode)], temp);
        tcg_temp_free_i32(temp);
3991
    }
B
bellard 已提交
3992 3993 3994
}

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

B
bellard 已提交
4024 4025
GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC)
{
4026
#if defined(CONFIG_USER_ONLY)
4027
    GEN_EXCP_PRIVREG(ctx);
4028
#else
4029
    if (unlikely(!ctx->supervisor)) {
4030
        GEN_EXCP_PRIVREG(ctx);
4031
        return;
4032
    }
A
aurel32 已提交
4033
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
4034 4035 4036 4037
    if (ctx->opcode & 0x00010000) {
        /* Special form that does not need any synchronisation */
        gen_op_update_riee();
    } else {
4038 4039 4040 4041
        /* 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
         */
4042
        gen_update_nip(ctx, ctx->nip);
4043
#if defined(TARGET_PPC64)
4044
        if (!ctx->sf_mode)
A
aurel32 已提交
4045
            gen_op_store_msr_32();
4046
        else
4047
#endif
A
aurel32 已提交
4048
            gen_op_store_msr();
4049 4050
        /* Must stop the translation as machine state (may have) changed */
        /* Note that mtmsrd is not always defined as context-synchronizing */
4051
        ctx->exception = POWERPC_EXCP_STOP;
4052
    }
4053
#endif
B
bellard 已提交
4054 4055 4056 4057 4058
}

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

4062
#if !defined(CONFIG_USER_ONLY)
4063 4064
    if (ctx->supervisor == 2)
        write_cb = ctx->spr_cb[sprn].hea_write;
4065
    else if (ctx->supervisor)
4066 4067
        write_cb = ctx->spr_cb[sprn].oea_write;
    else
4068
#endif
4069
        write_cb = ctx->spr_cb[sprn].uea_write;
4070 4071
    if (likely(write_cb != NULL)) {
        if (likely(write_cb != SPR_NOACCESS)) {
A
aurel32 已提交
4072
            tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
4073 4074 4075
            (*write_cb)(ctx, sprn);
        } else {
            /* Privilege exception */
J
j_mayer 已提交
4076
            if (loglevel != 0) {
J
j_mayer 已提交
4077 4078
                fprintf(logfile, "Trying to write privileged spr %d %03x at "
                        ADDRX "\n", sprn, sprn, ctx->nip);
4079
            }
J
j_mayer 已提交
4080 4081
            printf("Trying to write privileged spr %d %03x at " ADDRX "\n",
                   sprn, sprn, ctx->nip);
4082
            GEN_EXCP_PRIVREG(ctx);
4083
        }
4084 4085
    } else {
        /* Not defined */
J
j_mayer 已提交
4086
        if (loglevel != 0) {
J
j_mayer 已提交
4087 4088
            fprintf(logfile, "Trying to write invalid spr %d %03x at "
                    ADDRX "\n", sprn, sprn, ctx->nip);
4089
        }
J
j_mayer 已提交
4090 4091
        printf("Trying to write invalid spr %d %03x at " ADDRX "\n",
               sprn, sprn, ctx->nip);
4092 4093
        GEN_EXCP(ctx, POWERPC_EXCP_PROGRAM,
                 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_SPR);
B
bellard 已提交
4094 4095 4096 4097 4098
    }
}

/***                         Cache management                              ***/
/* dcbf */
4099
GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03C00001, PPC_CACHE)
B
bellard 已提交
4100
{
J
j_mayer 已提交
4101
    /* XXX: specification says this is treated as a load by the MMU */
P
pbrook 已提交
4102
    TCGv t0 = tcg_temp_new();
A
aurel32 已提交
4103
    gen_set_access_type(ACCESS_CACHE);
4104 4105 4106
    gen_addr_reg_index(t0, ctx);
    gen_qemu_ld8u(t0, t0, ctx->mem_idx);
    tcg_temp_free(t0);
B
bellard 已提交
4107 4108 4109
}

/* dcbi (Supervisor only) */
4110
GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE)
B
bellard 已提交
4111
{
4112
#if defined(CONFIG_USER_ONLY)
4113
    GEN_EXCP_PRIVOPC(ctx);
4114
#else
A
aurel32 已提交
4115
    TCGv EA, val;
4116
    if (unlikely(!ctx->supervisor)) {
4117
        GEN_EXCP_PRIVOPC(ctx);
4118
        return;
4119
    }
P
pbrook 已提交
4120
    EA = tcg_temp_new();
A
aurel32 已提交
4121
    gen_set_access_type(ACCESS_CACHE);
A
aurel32 已提交
4122
    gen_addr_reg_index(EA, ctx);
P
pbrook 已提交
4123
    val = tcg_temp_new();
4124
    /* XXX: specification says this should be treated as a store by the MMU */
A
aurel32 已提交
4125 4126 4127 4128
    gen_qemu_ld8u(val, EA, ctx->mem_idx);
    gen_qemu_st8(val, EA, ctx->mem_idx);
    tcg_temp_free(val);
    tcg_temp_free(EA);
4129
#endif
B
bellard 已提交
4130 4131 4132
}

/* dcdst */
4133
GEN_HANDLER(dcbst, 0x1F, 0x16, 0x01, 0x03E00001, PPC_CACHE)
B
bellard 已提交
4134
{
4135
    /* XXX: specification say this is treated as a load by the MMU */
P
pbrook 已提交
4136
    TCGv t0 = tcg_temp_new();
A
aurel32 已提交
4137
    gen_set_access_type(ACCESS_CACHE);
4138 4139 4140
    gen_addr_reg_index(t0, ctx);
    gen_qemu_ld8u(t0, t0, ctx->mem_idx);
    tcg_temp_free(t0);
B
bellard 已提交
4141 4142 4143
}

/* dcbt */
4144
GEN_HANDLER(dcbt, 0x1F, 0x16, 0x08, 0x02000001, PPC_CACHE)
B
bellard 已提交
4145
{
4146
    /* interpreted as no-op */
4147 4148 4149
    /* XXX: specification say this is treated as a load by the MMU
     *      but does not generate any exception
     */
B
bellard 已提交
4150 4151 4152
}

/* dcbtst */
4153
GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x02000001, PPC_CACHE)
B
bellard 已提交
4154
{
4155
    /* interpreted as no-op */
4156 4157 4158
    /* XXX: specification say this is treated as a load by the MMU
     *      but does not generate any exception
     */
B
bellard 已提交
4159 4160 4161
}

/* dcbz */
4162
#define op_dcbz(n) (*gen_op_dcbz[n][ctx->mem_idx])()
4163 4164
static GenOpFunc *gen_op_dcbz[4][NB_MEM_FUNCS] = {
    /* 32 bytes cache line size */
4165
    {
4166 4167 4168 4169 4170 4171 4172 4173 4174
#define gen_op_dcbz_l32_le_raw        gen_op_dcbz_l32_raw
#define gen_op_dcbz_l32_le_user       gen_op_dcbz_l32_user
#define gen_op_dcbz_l32_le_kernel     gen_op_dcbz_l32_kernel
#define gen_op_dcbz_l32_le_hypv       gen_op_dcbz_l32_hypv
#define gen_op_dcbz_l32_le_64_raw     gen_op_dcbz_l32_64_raw
#define gen_op_dcbz_l32_le_64_user    gen_op_dcbz_l32_64_user
#define gen_op_dcbz_l32_le_64_kernel  gen_op_dcbz_l32_64_kernel
#define gen_op_dcbz_l32_le_64_hypv    gen_op_dcbz_l32_64_hypv
        GEN_MEM_FUNCS(dcbz_l32),
4175
    },
4176
    /* 64 bytes cache line size */
4177
    {
4178 4179 4180 4181 4182 4183 4184 4185 4186
#define gen_op_dcbz_l64_le_raw        gen_op_dcbz_l64_raw
#define gen_op_dcbz_l64_le_user       gen_op_dcbz_l64_user
#define gen_op_dcbz_l64_le_kernel     gen_op_dcbz_l64_kernel
#define gen_op_dcbz_l64_le_hypv       gen_op_dcbz_l64_hypv
#define gen_op_dcbz_l64_le_64_raw     gen_op_dcbz_l64_64_raw
#define gen_op_dcbz_l64_le_64_user    gen_op_dcbz_l64_64_user
#define gen_op_dcbz_l64_le_64_kernel  gen_op_dcbz_l64_64_kernel
#define gen_op_dcbz_l64_le_64_hypv    gen_op_dcbz_l64_64_hypv
        GEN_MEM_FUNCS(dcbz_l64),
4187
    },
4188
    /* 128 bytes cache line size */
4189
    {
4190 4191 4192 4193 4194 4195 4196 4197 4198
#define gen_op_dcbz_l128_le_raw       gen_op_dcbz_l128_raw
#define gen_op_dcbz_l128_le_user      gen_op_dcbz_l128_user
#define gen_op_dcbz_l128_le_kernel    gen_op_dcbz_l128_kernel
#define gen_op_dcbz_l128_le_hypv      gen_op_dcbz_l128_hypv
#define gen_op_dcbz_l128_le_64_raw    gen_op_dcbz_l128_64_raw
#define gen_op_dcbz_l128_le_64_user   gen_op_dcbz_l128_64_user
#define gen_op_dcbz_l128_le_64_kernel gen_op_dcbz_l128_64_kernel
#define gen_op_dcbz_l128_le_64_hypv   gen_op_dcbz_l128_64_hypv
        GEN_MEM_FUNCS(dcbz_l128),
4199
    },
4200
    /* tunable cache line size */
4201
    {
4202 4203 4204 4205 4206 4207 4208 4209 4210
#define gen_op_dcbz_le_raw            gen_op_dcbz_raw
#define gen_op_dcbz_le_user           gen_op_dcbz_user
#define gen_op_dcbz_le_kernel         gen_op_dcbz_kernel
#define gen_op_dcbz_le_hypv           gen_op_dcbz_hypv
#define gen_op_dcbz_le_64_raw         gen_op_dcbz_64_raw
#define gen_op_dcbz_le_64_user        gen_op_dcbz_64_user
#define gen_op_dcbz_le_64_kernel      gen_op_dcbz_64_kernel
#define gen_op_dcbz_le_64_hypv        gen_op_dcbz_64_hypv
        GEN_MEM_FUNCS(dcbz),
4211
    },
4212
};
4213

4214 4215
static always_inline void handler_dcbz (DisasContext *ctx,
                                        int dcache_line_size)
4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236
{
    int n;

    switch (dcache_line_size) {
    case 32:
        n = 0;
        break;
    case 64:
        n = 1;
        break;
    case 128:
        n = 2;
        break;
    default:
        n = 3;
        break;
    }
    op_dcbz(n);
}

GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE_DCBZ)
B
bellard 已提交
4237
{
4238
    gen_addr_reg_index(cpu_T[0], ctx);
4239 4240 4241 4242
    handler_dcbz(ctx, ctx->dcache_line_size);
    gen_op_check_reservation();
}

4243
GEN_HANDLER2(dcbz_970, "dcbz", 0x1F, 0x16, 0x1F, 0x03C00001, PPC_CACHE_DCBZT)
4244
{
4245
    gen_addr_reg_index(cpu_T[0], ctx);
4246 4247 4248 4249
    if (ctx->opcode & 0x00200000)
        handler_dcbz(ctx, ctx->dcache_line_size);
    else
        handler_dcbz(ctx, -1);
B
bellard 已提交
4250
    gen_op_check_reservation();
B
bellard 已提交
4251 4252 4253
}

/* icbi */
4254
#define op_icbi() (*gen_op_icbi[ctx->mem_idx])()
4255 4256 4257 4258 4259 4260 4261 4262 4263 4264
#define gen_op_icbi_le_raw       gen_op_icbi_raw
#define gen_op_icbi_le_user      gen_op_icbi_user
#define gen_op_icbi_le_kernel    gen_op_icbi_kernel
#define gen_op_icbi_le_hypv      gen_op_icbi_hypv
#define gen_op_icbi_le_64_raw    gen_op_icbi_64_raw
#define gen_op_icbi_le_64_user   gen_op_icbi_64_user
#define gen_op_icbi_le_64_kernel gen_op_icbi_64_kernel
#define gen_op_icbi_le_64_hypv   gen_op_icbi_64_hypv
static GenOpFunc *gen_op_icbi[NB_MEM_FUNCS] = {
    GEN_MEM_FUNCS(icbi),
4265
};
4266

4267
GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_CACHE_ICBI)
B
bellard 已提交
4268
{
4269 4270
    /* NIP cannot be restored if the memory exception comes from an helper */
    gen_update_nip(ctx, ctx->nip - 4);
4271
    gen_addr_reg_index(cpu_T[0], ctx);
4272
    op_icbi();
B
bellard 已提交
4273 4274 4275 4276
}

/* Optional: */
/* dcba */
4277
GEN_HANDLER(dcba, 0x1F, 0x16, 0x17, 0x03E00001, PPC_CACHE_DCBA)
B
bellard 已提交
4278
{
4279 4280 4281 4282
    /* interpreted as no-op */
    /* XXX: specification say this is treated as a store by the MMU
     *      but does not generate any exception
     */
B
bellard 已提交
4283 4284 4285 4286 4287 4288 4289
}

/***                    Segment register manipulation                      ***/
/* Supervisor only: */
/* mfsr */
GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT)
{
4290
#if defined(CONFIG_USER_ONLY)
4291
    GEN_EXCP_PRIVREG(ctx);
4292
#else
4293
    if (unlikely(!ctx->supervisor)) {
4294
        GEN_EXCP_PRIVREG(ctx);
4295
        return;
4296
    }
4297
    tcg_gen_movi_tl(cpu_T[1], SR(ctx->opcode));
4298
    gen_op_load_sr();
A
aurel32 已提交
4299
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4300
#endif
B
bellard 已提交
4301 4302 4303
}

/* mfsrin */
4304
GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT)
B
bellard 已提交
4305
{
4306
#if defined(CONFIG_USER_ONLY)
4307
    GEN_EXCP_PRIVREG(ctx);
4308
#else
4309
    if (unlikely(!ctx->supervisor)) {
4310
        GEN_EXCP_PRIVREG(ctx);
4311
        return;
4312
    }
A
aurel32 已提交
4313
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4314 4315
    gen_op_srli_T1(28);
    gen_op_load_sr();
A
aurel32 已提交
4316
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4317
#endif
B
bellard 已提交
4318 4319 4320
}

/* mtsr */
B
bellard 已提交
4321
GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT)
B
bellard 已提交
4322
{
4323
#if defined(CONFIG_USER_ONLY)
4324
    GEN_EXCP_PRIVREG(ctx);
4325
#else
4326
    if (unlikely(!ctx->supervisor)) {
4327
        GEN_EXCP_PRIVREG(ctx);
4328
        return;
4329
    }
A
aurel32 已提交
4330
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
4331
    tcg_gen_movi_tl(cpu_T[1], SR(ctx->opcode));
4332
    gen_op_store_sr();
4333
#endif
B
bellard 已提交
4334 4335 4336
}

/* mtsrin */
4337
GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT)
B
bellard 已提交
4338
{
4339
#if defined(CONFIG_USER_ONLY)
4340
    GEN_EXCP_PRIVREG(ctx);
4341
#else
4342
    if (unlikely(!ctx->supervisor)) {
4343
        GEN_EXCP_PRIVREG(ctx);
4344
        return;
4345
    }
A
aurel32 已提交
4346 4347
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4348 4349
    gen_op_srli_T1(28);
    gen_op_store_sr();
4350
#endif
B
bellard 已提交
4351 4352
}

4353 4354 4355
#if defined(TARGET_PPC64)
/* Specific implementation for PowerPC 64 "bridge" emulation using SLB */
/* mfsr */
4356
GEN_HANDLER2(mfsr_64b, "mfsr", 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT_64B)
4357 4358 4359 4360 4361 4362 4363 4364
{
#if defined(CONFIG_USER_ONLY)
    GEN_EXCP_PRIVREG(ctx);
#else
    if (unlikely(!ctx->supervisor)) {
        GEN_EXCP_PRIVREG(ctx);
        return;
    }
4365
    tcg_gen_movi_tl(cpu_T[1], SR(ctx->opcode));
4366
    gen_op_load_slb();
A
aurel32 已提交
4367
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4368 4369 4370 4371
#endif
}

/* mfsrin */
4372 4373
GEN_HANDLER2(mfsrin_64b, "mfsrin", 0x1F, 0x13, 0x14, 0x001F0001,
             PPC_SEGMENT_64B)
4374 4375 4376 4377 4378 4379 4380 4381
{
#if defined(CONFIG_USER_ONLY)
    GEN_EXCP_PRIVREG(ctx);
#else
    if (unlikely(!ctx->supervisor)) {
        GEN_EXCP_PRIVREG(ctx);
        return;
    }
A
aurel32 已提交
4382
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4383 4384
    gen_op_srli_T1(28);
    gen_op_load_slb();
A
aurel32 已提交
4385
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4386 4387 4388 4389
#endif
}

/* mtsr */
4390
GEN_HANDLER2(mtsr_64b, "mtsr", 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT_64B)
4391 4392 4393 4394 4395 4396 4397 4398
{
#if defined(CONFIG_USER_ONLY)
    GEN_EXCP_PRIVREG(ctx);
#else
    if (unlikely(!ctx->supervisor)) {
        GEN_EXCP_PRIVREG(ctx);
        return;
    }
A
aurel32 已提交
4399
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
4400
    tcg_gen_movi_tl(cpu_T[1], SR(ctx->opcode));
4401 4402 4403 4404 4405
    gen_op_store_slb();
#endif
}

/* mtsrin */
4406 4407
GEN_HANDLER2(mtsrin_64b, "mtsrin", 0x1F, 0x12, 0x07, 0x001F0001,
             PPC_SEGMENT_64B)
4408 4409 4410 4411 4412 4413 4414 4415
{
#if defined(CONFIG_USER_ONLY)
    GEN_EXCP_PRIVREG(ctx);
#else
    if (unlikely(!ctx->supervisor)) {
        GEN_EXCP_PRIVREG(ctx);
        return;
    }
A
aurel32 已提交
4416 4417
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4418 4419 4420 4421 4422 4423
    gen_op_srli_T1(28);
    gen_op_store_slb();
#endif
}
#endif /* defined(TARGET_PPC64) */

B
bellard 已提交
4424 4425 4426
/***                      Lookaside buffer management                      ***/
/* Optional & supervisor only: */
/* tlbia */
4427
GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA)
B
bellard 已提交
4428
{
4429
#if defined(CONFIG_USER_ONLY)
4430
    GEN_EXCP_PRIVOPC(ctx);
4431
#else
4432
    if (unlikely(!ctx->supervisor)) {
4433
        GEN_EXCP_PRIVOPC(ctx);
4434
        return;
4435 4436 4437
    }
    gen_op_tlbia();
#endif
B
bellard 已提交
4438 4439 4440
}

/* tlbie */
4441
GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM_TLBIE)
B
bellard 已提交
4442
{
4443
#if defined(CONFIG_USER_ONLY)
4444
    GEN_EXCP_PRIVOPC(ctx);
4445
#else
4446
    if (unlikely(!ctx->supervisor)) {
4447
        GEN_EXCP_PRIVOPC(ctx);
4448
        return;
4449
    }
A
aurel32 已提交
4450
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rB(ctx->opcode)]);
4451 4452 4453 4454 4455 4456
#if defined(TARGET_PPC64)
    if (ctx->sf_mode)
        gen_op_tlbie_64();
    else
#endif
        gen_op_tlbie();
4457
#endif
B
bellard 已提交
4458 4459 4460
}

/* tlbsync */
4461
GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM_TLBSYNC)
B
bellard 已提交
4462
{
4463
#if defined(CONFIG_USER_ONLY)
4464
    GEN_EXCP_PRIVOPC(ctx);
4465
#else
4466
    if (unlikely(!ctx->supervisor)) {
4467
        GEN_EXCP_PRIVOPC(ctx);
4468
        return;
4469 4470 4471 4472
    }
    /* This has no effect: it should ensure that all previous
     * tlbie have completed
     */
4473
    GEN_STOP(ctx);
4474
#endif
B
bellard 已提交
4475 4476
}

J
j_mayer 已提交
4477 4478 4479 4480 4481
#if defined(TARGET_PPC64)
/* slbia */
GEN_HANDLER(slbia, 0x1F, 0x12, 0x0F, 0x03FFFC01, PPC_SLBI)
{
#if defined(CONFIG_USER_ONLY)
4482
    GEN_EXCP_PRIVOPC(ctx);
J
j_mayer 已提交
4483 4484
#else
    if (unlikely(!ctx->supervisor)) {
4485
        GEN_EXCP_PRIVOPC(ctx);
J
j_mayer 已提交
4486 4487 4488 4489 4490 4491 4492 4493 4494 4495
        return;
    }
    gen_op_slbia();
#endif
}

/* slbie */
GEN_HANDLER(slbie, 0x1F, 0x12, 0x0D, 0x03FF0001, PPC_SLBI)
{
#if defined(CONFIG_USER_ONLY)
4496
    GEN_EXCP_PRIVOPC(ctx);
J
j_mayer 已提交
4497 4498
#else
    if (unlikely(!ctx->supervisor)) {
4499
        GEN_EXCP_PRIVOPC(ctx);
J
j_mayer 已提交
4500 4501
        return;
    }
A
aurel32 已提交
4502
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rB(ctx->opcode)]);
J
j_mayer 已提交
4503 4504 4505 4506 4507
    gen_op_slbie();
#endif
}
#endif

B
bellard 已提交
4508 4509
/***                              External control                         ***/
/* Optional: */
4510 4511
#define op_eciwx() (*gen_op_eciwx[ctx->mem_idx])()
#define op_ecowx() (*gen_op_ecowx[ctx->mem_idx])()
4512 4513
static GenOpFunc *gen_op_eciwx[NB_MEM_FUNCS] = {
    GEN_MEM_FUNCS(eciwx),
4514
};
4515 4516
static GenOpFunc *gen_op_ecowx[NB_MEM_FUNCS] = {
    GEN_MEM_FUNCS(ecowx),
4517
};
4518

4519
/* eciwx */
B
bellard 已提交
4520 4521
GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN)
{
4522
    /* Should check EAR[E] & alignment ! */
A
aurel32 已提交
4523
    gen_set_access_type(ACCESS_RES);
4524
    gen_addr_reg_index(cpu_T[0], ctx);
4525
    op_eciwx();
A
aurel32 已提交
4526
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4527 4528 4529 4530 4531 4532
}

/* ecowx */
GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN)
{
    /* Should check EAR[E] & alignment ! */
4533
    gen_addr_reg_index(cpu_T[0], ctx);
A
aurel32 已提交
4534
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]);
4535 4536 4537 4538 4539 4540 4541
    op_ecowx();
}

/* PowerPC 601 specific instructions */
/* abs - abs. */
GEN_HANDLER(abs, 0x1F, 0x08, 0x0B, 0x0000F800, PPC_POWER_BR)
{
A
aurel32 已提交
4542
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
4543
    gen_op_POWER_abs();
A
aurel32 已提交
4544
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4545
    if (unlikely(Rc(ctx->opcode) != 0))
4546
        gen_set_Rc0(ctx, cpu_T[0]);
4547 4548 4549 4550 4551
}

/* abso - abso. */
GEN_HANDLER(abso, 0x1F, 0x08, 0x1B, 0x0000F800, PPC_POWER_BR)
{
A
aurel32 已提交
4552
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
4553
    gen_op_POWER_abso();
A
aurel32 已提交
4554
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4555
    if (unlikely(Rc(ctx->opcode) != 0))
4556
        gen_set_Rc0(ctx, cpu_T[0]);
4557 4558 4559
}

/* clcs */
4560
GEN_HANDLER(clcs, 0x1F, 0x10, 0x13, 0x0000F800, PPC_POWER_BR)
4561
{
A
aurel32 已提交
4562
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
4563
    gen_op_POWER_clcs();
4564
    /* Rc=1 sets CR0 to an undefined state */
A
aurel32 已提交
4565
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4566 4567 4568 4569 4570
}

/* div - div. */
GEN_HANDLER(div, 0x1F, 0x0B, 0x0A, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4571 4572
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4573
    gen_op_POWER_div();
A
aurel32 已提交
4574
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4575
    if (unlikely(Rc(ctx->opcode) != 0))
4576
        gen_set_Rc0(ctx, cpu_T[0]);
4577 4578 4579 4580 4581
}

/* divo - divo. */
GEN_HANDLER(divo, 0x1F, 0x0B, 0x1A, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4582 4583
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4584
    gen_op_POWER_divo();
A
aurel32 已提交
4585
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4586
    if (unlikely(Rc(ctx->opcode) != 0))
4587
        gen_set_Rc0(ctx, cpu_T[0]);
4588 4589 4590 4591 4592
}

/* divs - divs. */
GEN_HANDLER(divs, 0x1F, 0x0B, 0x0B, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4593 4594
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4595
    gen_op_POWER_divs();
A
aurel32 已提交
4596
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4597
    if (unlikely(Rc(ctx->opcode) != 0))
4598
        gen_set_Rc0(ctx, cpu_T[0]);
4599 4600 4601 4602 4603
}

/* divso - divso. */
GEN_HANDLER(divso, 0x1F, 0x0B, 0x1B, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4604 4605
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4606
    gen_op_POWER_divso();
A
aurel32 已提交
4607
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4608
    if (unlikely(Rc(ctx->opcode) != 0))
4609
        gen_set_Rc0(ctx, cpu_T[0]);
4610 4611 4612 4613 4614
}

/* doz - doz. */
GEN_HANDLER(doz, 0x1F, 0x08, 0x08, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4615 4616
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4617
    gen_op_POWER_doz();
A
aurel32 已提交
4618
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4619
    if (unlikely(Rc(ctx->opcode) != 0))
4620
        gen_set_Rc0(ctx, cpu_T[0]);
4621 4622 4623 4624 4625
}

/* dozo - dozo. */
GEN_HANDLER(dozo, 0x1F, 0x08, 0x18, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4626 4627
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4628
    gen_op_POWER_dozo();
A
aurel32 已提交
4629
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4630
    if (unlikely(Rc(ctx->opcode) != 0))
4631
        gen_set_Rc0(ctx, cpu_T[0]);
4632 4633 4634 4635 4636
}

/* dozi */
GEN_HANDLER(dozi, 0x09, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4637
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
4638
    tcg_gen_movi_tl(cpu_T[1], SIMM(ctx->opcode));
4639
    gen_op_POWER_doz();
A
aurel32 已提交
4640
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4641 4642
}

4643 4644 4645
/* As lscbx load from memory byte after byte, it's always endian safe.
 * Original POWER is 32 bits only, define 64 bits ops as 32 bits ones
 */
4646
#define op_POWER_lscbx(start, ra, rb)                                         \
4647
(*gen_op_POWER_lscbx[ctx->mem_idx])(start, ra, rb)
4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661
#define gen_op_POWER_lscbx_64_raw       gen_op_POWER_lscbx_raw
#define gen_op_POWER_lscbx_64_user      gen_op_POWER_lscbx_user
#define gen_op_POWER_lscbx_64_kernel    gen_op_POWER_lscbx_kernel
#define gen_op_POWER_lscbx_64_hypv      gen_op_POWER_lscbx_hypv
#define gen_op_POWER_lscbx_le_raw       gen_op_POWER_lscbx_raw
#define gen_op_POWER_lscbx_le_user      gen_op_POWER_lscbx_user
#define gen_op_POWER_lscbx_le_kernel    gen_op_POWER_lscbx_kernel
#define gen_op_POWER_lscbx_le_hypv      gen_op_POWER_lscbx_hypv
#define gen_op_POWER_lscbx_le_64_raw    gen_op_POWER_lscbx_raw
#define gen_op_POWER_lscbx_le_64_user   gen_op_POWER_lscbx_user
#define gen_op_POWER_lscbx_le_64_kernel gen_op_POWER_lscbx_kernel
#define gen_op_POWER_lscbx_le_64_hypv   gen_op_POWER_lscbx_hypv
static GenOpFunc3 *gen_op_POWER_lscbx[NB_MEM_FUNCS] = {
    GEN_MEM_FUNCS(POWER_lscbx),
4662 4663 4664 4665 4666 4667 4668 4669
};

/* lscbx - lscbx. */
GEN_HANDLER(lscbx, 0x1F, 0x15, 0x08, 0x00000000, PPC_POWER_BR)
{
    int ra = rA(ctx->opcode);
    int rb = rB(ctx->opcode);

4670
    gen_addr_reg_index(cpu_T[0], ctx);
4671 4672 4673 4674
    if (ra == 0) {
        ra = rb;
    }
    /* NIP cannot be restored if the memory exception comes from an helper */
4675
    gen_update_nip(ctx, ctx->nip - 4);
A
aurel32 已提交
4676 4677 4678
    tcg_gen_andi_tl(cpu_T[1], cpu_xer, 0x7F);
    tcg_gen_shri_tl(cpu_T[2], cpu_xer, XER_CMP);
    tcg_gen_andi_tl(cpu_T[2], cpu_T[2], 0xFF);
4679
    op_POWER_lscbx(rD(ctx->opcode), ra, rb);
A
aurel32 已提交
4680 4681
    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~0x7F);
    tcg_gen_or_tl(cpu_xer, cpu_xer, cpu_T[0]);
4682
    if (unlikely(Rc(ctx->opcode) != 0))
4683
        gen_set_Rc0(ctx, cpu_T[0]);
4684 4685 4686 4687 4688
}

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

/* maskir - maskir. */
GEN_HANDLER(maskir, 0x1F, 0x1D, 0x10, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4700 4701 4702
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[2], cpu_gpr[rB(ctx->opcode)]);
4703
    gen_op_POWER_maskir();
A
aurel32 已提交
4704
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4705
    if (unlikely(Rc(ctx->opcode) != 0))
4706
        gen_set_Rc0(ctx, cpu_T[0]);
4707 4708 4709 4710 4711
}

/* mul - mul. */
GEN_HANDLER(mul, 0x1F, 0x0B, 0x03, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4712 4713
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4714
    gen_op_POWER_mul();
A
aurel32 已提交
4715
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4716
    if (unlikely(Rc(ctx->opcode) != 0))
4717
        gen_set_Rc0(ctx, cpu_T[0]);
4718 4719 4720 4721 4722
}

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

/* nabs - nabs. */
GEN_HANDLER(nabs, 0x1F, 0x08, 0x0F, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4734
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
4735
    gen_op_POWER_nabs();
A
aurel32 已提交
4736
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4737
    if (unlikely(Rc(ctx->opcode) != 0))
4738
        gen_set_Rc0(ctx, cpu_T[0]);
4739 4740 4741 4742 4743
}

/* nabso - nabso. */
GEN_HANDLER(nabso, 0x1F, 0x08, 0x1F, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4744
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
4745
    gen_op_POWER_nabso();
A
aurel32 已提交
4746
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4747
    if (unlikely(Rc(ctx->opcode) != 0))
4748
        gen_set_Rc0(ctx, cpu_T[0]);
4749 4750 4751 4752 4753 4754 4755 4756 4757
}

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

    mb = MB(ctx->opcode);
    me = ME(ctx->opcode);
A
aurel32 已提交
4758 4759 4760
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[2], cpu_gpr[rB(ctx->opcode)]);
4761
    gen_op_POWER_rlmi(MASK(mb, me), ~MASK(mb, me));
A
aurel32 已提交
4762
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4763
    if (unlikely(Rc(ctx->opcode) != 0))
4764
        gen_set_Rc0(ctx, cpu_T[0]);
4765 4766 4767 4768 4769
}

/* rrib - rrib. */
GEN_HANDLER(rrib, 0x1F, 0x19, 0x10, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4770 4771 4772
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[2], cpu_gpr[rB(ctx->opcode)]);
4773
    gen_op_POWER_rrib();
A
aurel32 已提交
4774
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4775
    if (unlikely(Rc(ctx->opcode) != 0))
4776
        gen_set_Rc0(ctx, cpu_T[0]);
4777 4778 4779 4780 4781
}

/* sle - sle. */
GEN_HANDLER(sle, 0x1F, 0x19, 0x04, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4782 4783
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4784
    gen_op_POWER_sle();
A
aurel32 已提交
4785
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4786
    if (unlikely(Rc(ctx->opcode) != 0))
4787
        gen_set_Rc0(ctx, cpu_T[0]);
4788 4789 4790 4791 4792
}

/* sleq - sleq. */
GEN_HANDLER(sleq, 0x1F, 0x19, 0x06, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4793 4794
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4795
    gen_op_POWER_sleq();
A
aurel32 已提交
4796
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4797
    if (unlikely(Rc(ctx->opcode) != 0))
4798
        gen_set_Rc0(ctx, cpu_T[0]);
4799 4800 4801 4802 4803
}

/* sliq - sliq. */
GEN_HANDLER(sliq, 0x1F, 0x18, 0x05, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4804
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
4805
    tcg_gen_movi_tl(cpu_T[1], SH(ctx->opcode));
4806
    gen_op_POWER_sle();
A
aurel32 已提交
4807
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4808
    if (unlikely(Rc(ctx->opcode) != 0))
4809
        gen_set_Rc0(ctx, cpu_T[0]);
4810 4811 4812 4813 4814
}

/* slliq - slliq. */
GEN_HANDLER(slliq, 0x1F, 0x18, 0x07, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4815
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
4816
    tcg_gen_movi_tl(cpu_T[1], SH(ctx->opcode));
4817
    gen_op_POWER_sleq();
A
aurel32 已提交
4818
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4819
    if (unlikely(Rc(ctx->opcode) != 0))
4820
        gen_set_Rc0(ctx, cpu_T[0]);
4821 4822 4823 4824 4825
}

/* sllq - sllq. */
GEN_HANDLER(sllq, 0x1F, 0x18, 0x06, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4826 4827
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4828
    gen_op_POWER_sllq();
A
aurel32 已提交
4829
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4830
    if (unlikely(Rc(ctx->opcode) != 0))
4831
        gen_set_Rc0(ctx, cpu_T[0]);
4832 4833 4834 4835 4836
}

/* slq - slq. */
GEN_HANDLER(slq, 0x1F, 0x18, 0x04, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4837 4838
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4839
    gen_op_POWER_slq();
A
aurel32 已提交
4840
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4841
    if (unlikely(Rc(ctx->opcode) != 0))
4842
        gen_set_Rc0(ctx, cpu_T[0]);
4843 4844
}

4845
/* sraiq - sraiq. */
4846 4847
GEN_HANDLER(sraiq, 0x1F, 0x18, 0x1D, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4848
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
4849
    tcg_gen_movi_tl(cpu_T[1], SH(ctx->opcode));
4850
    gen_op_POWER_sraq();
A
aurel32 已提交
4851
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4852
    if (unlikely(Rc(ctx->opcode) != 0))
4853
        gen_set_Rc0(ctx, cpu_T[0]);
4854 4855 4856 4857 4858
}

/* sraq - sraq. */
GEN_HANDLER(sraq, 0x1F, 0x18, 0x1C, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4859 4860
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4861
    gen_op_POWER_sraq();
A
aurel32 已提交
4862
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4863
    if (unlikely(Rc(ctx->opcode) != 0))
4864
        gen_set_Rc0(ctx, cpu_T[0]);
4865 4866 4867 4868 4869
}

/* sre - sre. */
GEN_HANDLER(sre, 0x1F, 0x19, 0x14, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4870 4871
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4872
    gen_op_POWER_sre();
A
aurel32 已提交
4873
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4874
    if (unlikely(Rc(ctx->opcode) != 0))
4875
        gen_set_Rc0(ctx, cpu_T[0]);
4876 4877 4878 4879 4880
}

/* srea - srea. */
GEN_HANDLER(srea, 0x1F, 0x19, 0x1C, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4881 4882
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4883
    gen_op_POWER_srea();
A
aurel32 已提交
4884
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4885
    if (unlikely(Rc(ctx->opcode) != 0))
4886
        gen_set_Rc0(ctx, cpu_T[0]);
4887 4888 4889 4890 4891
}

/* sreq */
GEN_HANDLER(sreq, 0x1F, 0x19, 0x16, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4892 4893
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4894
    gen_op_POWER_sreq();
A
aurel32 已提交
4895
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4896
    if (unlikely(Rc(ctx->opcode) != 0))
4897
        gen_set_Rc0(ctx, cpu_T[0]);
4898 4899 4900 4901 4902
}

/* sriq */
GEN_HANDLER(sriq, 0x1F, 0x18, 0x15, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4903
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
4904
    tcg_gen_movi_tl(cpu_T[1], SH(ctx->opcode));
4905
    gen_op_POWER_srq();
A
aurel32 已提交
4906
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4907
    if (unlikely(Rc(ctx->opcode) != 0))
4908
        gen_set_Rc0(ctx, cpu_T[0]);
4909 4910 4911 4912 4913
}

/* srliq */
GEN_HANDLER(srliq, 0x1F, 0x18, 0x17, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4914 4915
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4916
    tcg_gen_movi_tl(cpu_T[1], SH(ctx->opcode));
4917
    gen_op_POWER_srlq();
A
aurel32 已提交
4918
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4919
    if (unlikely(Rc(ctx->opcode) != 0))
4920
        gen_set_Rc0(ctx, cpu_T[0]);
4921 4922 4923 4924 4925
}

/* srlq */
GEN_HANDLER(srlq, 0x1F, 0x18, 0x16, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4926 4927
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4928
    gen_op_POWER_srlq();
A
aurel32 已提交
4929
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4930
    if (unlikely(Rc(ctx->opcode) != 0))
4931
        gen_set_Rc0(ctx, cpu_T[0]);
4932 4933 4934 4935 4936
}

/* srq */
GEN_HANDLER(srq, 0x1F, 0x18, 0x14, 0x00000000, PPC_POWER_BR)
{
A
aurel32 已提交
4937 4938
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
4939
    gen_op_POWER_srq();
A
aurel32 已提交
4940
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
4941
    if (unlikely(Rc(ctx->opcode) != 0))
4942
        gen_set_Rc0(ctx, cpu_T[0]);
4943 4944 4945 4946 4947 4948 4949
}

/* PowerPC 602 specific instructions */
/* dsa  */
GEN_HANDLER(dsa, 0x1F, 0x14, 0x13, 0x03FFF801, PPC_602_SPEC)
{
    /* XXX: TODO */
4950
    GEN_EXCP_INVAL(ctx);
4951 4952 4953 4954 4955 4956
}

/* esa */
GEN_HANDLER(esa, 0x1F, 0x14, 0x12, 0x03FFF801, PPC_602_SPEC)
{
    /* XXX: TODO */
4957
    GEN_EXCP_INVAL(ctx);
4958 4959 4960 4961 4962 4963
}

/* mfrom */
GEN_HANDLER(mfrom, 0x1F, 0x09, 0x08, 0x03E0F801, PPC_602_SPEC)
{
#if defined(CONFIG_USER_ONLY)
4964
    GEN_EXCP_PRIVOPC(ctx);
4965 4966
#else
    if (unlikely(!ctx->supervisor)) {
4967
        GEN_EXCP_PRIVOPC(ctx);
4968 4969
        return;
    }
A
aurel32 已提交
4970
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
4971
    gen_op_602_mfrom();
A
aurel32 已提交
4972
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
4973 4974 4975 4976 4977
#endif
}

/* 602 - 603 - G2 TLB management */
/* tlbld */
4978
GEN_HANDLER2(tlbld_6xx, "tlbld", 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB)
4979 4980
{
#if defined(CONFIG_USER_ONLY)
4981
    GEN_EXCP_PRIVOPC(ctx);
4982 4983
#else
    if (unlikely(!ctx->supervisor)) {
4984
        GEN_EXCP_PRIVOPC(ctx);
4985 4986
        return;
    }
A
aurel32 已提交
4987
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rB(ctx->opcode)]);
4988 4989 4990 4991 4992
    gen_op_6xx_tlbld();
#endif
}

/* tlbli */
4993
GEN_HANDLER2(tlbli_6xx, "tlbli", 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB)
4994 4995
{
#if defined(CONFIG_USER_ONLY)
4996
    GEN_EXCP_PRIVOPC(ctx);
4997 4998
#else
    if (unlikely(!ctx->supervisor)) {
4999
        GEN_EXCP_PRIVOPC(ctx);
5000 5001
        return;
    }
A
aurel32 已提交
5002
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rB(ctx->opcode)]);
5003 5004 5005 5006
    gen_op_6xx_tlbli();
#endif
}

5007 5008
/* 74xx TLB management */
/* tlbld */
5009
GEN_HANDLER2(tlbld_74xx, "tlbld", 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_74xx_TLB)
5010 5011 5012 5013 5014 5015 5016 5017
{
#if defined(CONFIG_USER_ONLY)
    GEN_EXCP_PRIVOPC(ctx);
#else
    if (unlikely(!ctx->supervisor)) {
        GEN_EXCP_PRIVOPC(ctx);
        return;
    }
A
aurel32 已提交
5018
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rB(ctx->opcode)]);
5019 5020 5021 5022 5023
    gen_op_74xx_tlbld();
#endif
}

/* tlbli */
5024
GEN_HANDLER2(tlbli_74xx, "tlbli", 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_74xx_TLB)
5025 5026 5027 5028 5029 5030 5031 5032
{
#if defined(CONFIG_USER_ONLY)
    GEN_EXCP_PRIVOPC(ctx);
#else
    if (unlikely(!ctx->supervisor)) {
        GEN_EXCP_PRIVOPC(ctx);
        return;
    }
A
aurel32 已提交
5033
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rB(ctx->opcode)]);
5034 5035 5036 5037
    gen_op_74xx_tlbli();
#endif
}

5038 5039 5040 5041 5042 5043 5044 5045 5046 5047
/* 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 已提交
5048
    /* Cache line invalidate: privileged and treated as no-op */
5049
#if defined(CONFIG_USER_ONLY)
5050
    GEN_EXCP_PRIVOPC(ctx);
5051 5052
#else
    if (unlikely(!ctx->supervisor)) {
5053
        GEN_EXCP_PRIVOPC(ctx);
5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067
        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)
5068
    GEN_EXCP_PRIVOPC(ctx);
5069 5070
#else
    if (unlikely(!ctx->supervisor)) {
5071
        GEN_EXCP_PRIVOPC(ctx);
5072 5073 5074 5075 5076
        return;
    }
    int ra = rA(ctx->opcode);
    int rd = rD(ctx->opcode);

5077
    gen_addr_reg_index(cpu_T[0], ctx);
5078
    gen_op_POWER_mfsri();
A
aurel32 已提交
5079
    tcg_gen_mov_tl(cpu_gpr[rd], cpu_T[0]);
5080
    if (ra != 0 && ra != rd)
A
aurel32 已提交
5081
        tcg_gen_mov_tl(cpu_gpr[ra], cpu_T[1]);
5082 5083 5084 5085 5086 5087
#endif
}

GEN_HANDLER(rac, 0x1F, 0x12, 0x19, 0x00000001, PPC_POWER)
{
#if defined(CONFIG_USER_ONLY)
5088
    GEN_EXCP_PRIVOPC(ctx);
5089 5090
#else
    if (unlikely(!ctx->supervisor)) {
5091
        GEN_EXCP_PRIVOPC(ctx);
5092 5093
        return;
    }
5094
    gen_addr_reg_index(cpu_T[0], ctx);
5095
    gen_op_POWER_rac();
A
aurel32 已提交
5096
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
5097 5098 5099 5100 5101 5102
#endif
}

GEN_HANDLER(rfsvc, 0x13, 0x12, 0x02, 0x03FFF0001, PPC_POWER)
{
#if defined(CONFIG_USER_ONLY)
5103
    GEN_EXCP_PRIVOPC(ctx);
5104 5105
#else
    if (unlikely(!ctx->supervisor)) {
5106
        GEN_EXCP_PRIVOPC(ctx);
5107 5108 5109
        return;
    }
    gen_op_POWER_rfsvc();
5110
    GEN_SYNC(ctx);
5111 5112 5113 5114 5115 5116 5117
#endif
}

/* svc is not implemented for now */

/* POWER2 specific instructions */
/* Quad manipulation (load/store two floats at a time) */
5118
/* Original POWER2 is 32 bits only, define 64 bits ops as 32 bits ones */
5119 5120
#define op_POWER2_lfq() (*gen_op_POWER2_lfq[ctx->mem_idx])()
#define op_POWER2_stfq() (*gen_op_POWER2_stfq[ctx->mem_idx])()
5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138
#define gen_op_POWER2_lfq_64_raw        gen_op_POWER2_lfq_raw
#define gen_op_POWER2_lfq_64_user       gen_op_POWER2_lfq_user
#define gen_op_POWER2_lfq_64_kernel     gen_op_POWER2_lfq_kernel
#define gen_op_POWER2_lfq_64_hypv       gen_op_POWER2_lfq_hypv
#define gen_op_POWER2_lfq_le_64_raw     gen_op_POWER2_lfq_le_raw
#define gen_op_POWER2_lfq_le_64_user    gen_op_POWER2_lfq_le_user
#define gen_op_POWER2_lfq_le_64_kernel  gen_op_POWER2_lfq_le_kernel
#define gen_op_POWER2_lfq_le_64_hypv    gen_op_POWER2_lfq_le_hypv
#define gen_op_POWER2_stfq_64_raw       gen_op_POWER2_stfq_raw
#define gen_op_POWER2_stfq_64_user      gen_op_POWER2_stfq_user
#define gen_op_POWER2_stfq_64_kernel    gen_op_POWER2_stfq_kernel
#define gen_op_POWER2_stfq_64_hypv      gen_op_POWER2_stfq_hypv
#define gen_op_POWER2_stfq_le_64_raw    gen_op_POWER2_stfq_le_raw
#define gen_op_POWER2_stfq_le_64_user   gen_op_POWER2_stfq_le_user
#define gen_op_POWER2_stfq_le_64_kernel gen_op_POWER2_stfq_le_kernel
#define gen_op_POWER2_stfq_le_64_hypv   gen_op_POWER2_stfq_le_hypv
static GenOpFunc *gen_op_POWER2_lfq[NB_MEM_FUNCS] = {
    GEN_MEM_FUNCS(POWER2_lfq),
5139
};
5140 5141
static GenOpFunc *gen_op_POWER2_stfq[NB_MEM_FUNCS] = {
    GEN_MEM_FUNCS(POWER2_stfq),
5142 5143 5144 5145 5146 5147
};

/* lfq */
GEN_HANDLER(lfq, 0x38, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
{
    /* NIP cannot be restored if the memory exception comes from an helper */
5148
    gen_update_nip(ctx, ctx->nip - 4);
5149
    gen_addr_imm_index(cpu_T[0], ctx, 0);
5150
    op_POWER2_lfq();
A
aurel32 已提交
5151 5152
    tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode)], cpu_FT[0]);
    tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode) + 1], cpu_FT[1]);
5153 5154 5155 5156 5157 5158 5159 5160
}

/* lfqu */
GEN_HANDLER(lfqu, 0x39, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
{
    int ra = rA(ctx->opcode);

    /* NIP cannot be restored if the memory exception comes from an helper */
5161
    gen_update_nip(ctx, ctx->nip - 4);
5162
    gen_addr_imm_index(cpu_T[0], ctx, 0);
5163
    op_POWER2_lfq();
A
aurel32 已提交
5164 5165
    tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode)], cpu_FT[0]);
    tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode) + 1], cpu_FT[1]);
5166
    if (ra != 0)
A
aurel32 已提交
5167
        tcg_gen_mov_tl(cpu_gpr[ra], cpu_T[0]);
5168 5169 5170 5171 5172 5173 5174 5175
}

/* lfqux */
GEN_HANDLER(lfqux, 0x1F, 0x17, 0x19, 0x00000001, PPC_POWER2)
{
    int ra = rA(ctx->opcode);

    /* NIP cannot be restored if the memory exception comes from an helper */
5176
    gen_update_nip(ctx, ctx->nip - 4);
5177
    gen_addr_reg_index(cpu_T[0], ctx);
5178
    op_POWER2_lfq();
A
aurel32 已提交
5179 5180
    tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode)], cpu_FT[0]);
    tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode) + 1], cpu_FT[1]);
5181
    if (ra != 0)
A
aurel32 已提交
5182
        tcg_gen_mov_tl(cpu_gpr[ra], cpu_T[0]);
5183 5184 5185 5186 5187 5188
}

/* lfqx */
GEN_HANDLER(lfqx, 0x1F, 0x17, 0x18, 0x00000001, PPC_POWER2)
{
    /* NIP cannot be restored if the memory exception comes from an helper */
5189
    gen_update_nip(ctx, ctx->nip - 4);
5190
    gen_addr_reg_index(cpu_T[0], ctx);
5191
    op_POWER2_lfq();
A
aurel32 已提交
5192 5193
    tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode)], cpu_FT[0]);
    tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode) + 1], cpu_FT[1]);
5194 5195 5196 5197 5198 5199
}

/* stfq */
GEN_HANDLER(stfq, 0x3C, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
{
    /* NIP cannot be restored if the memory exception comes from an helper */
5200
    gen_update_nip(ctx, ctx->nip - 4);
5201
    gen_addr_imm_index(cpu_T[0], ctx, 0);
A
aurel32 已提交
5202 5203
    tcg_gen_mov_i64(cpu_FT[0], cpu_fpr[rS(ctx->opcode)]);
    tcg_gen_mov_i64(cpu_FT[1], cpu_fpr[rS(ctx->opcode) + 1]);
5204 5205 5206 5207 5208 5209 5210 5211 5212
    op_POWER2_stfq();
}

/* stfqu */
GEN_HANDLER(stfqu, 0x3D, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
{
    int ra = rA(ctx->opcode);

    /* NIP cannot be restored if the memory exception comes from an helper */
5213
    gen_update_nip(ctx, ctx->nip - 4);
5214
    gen_addr_imm_index(cpu_T[0], ctx, 0);
A
aurel32 已提交
5215 5216
    tcg_gen_mov_i64(cpu_FT[0], cpu_fpr[rS(ctx->opcode)]);
    tcg_gen_mov_i64(cpu_FT[1], cpu_fpr[rS(ctx->opcode) + 1]);
5217 5218
    op_POWER2_stfq();
    if (ra != 0)
A
aurel32 已提交
5219
        tcg_gen_mov_tl(cpu_gpr[ra], cpu_T[0]);
5220 5221 5222 5223 5224 5225 5226 5227
}

/* stfqux */
GEN_HANDLER(stfqux, 0x1F, 0x17, 0x1D, 0x00000001, PPC_POWER2)
{
    int ra = rA(ctx->opcode);

    /* NIP cannot be restored if the memory exception comes from an helper */
5228
    gen_update_nip(ctx, ctx->nip - 4);
5229
    gen_addr_reg_index(cpu_T[0], ctx);
A
aurel32 已提交
5230 5231
    tcg_gen_mov_i64(cpu_FT[0], cpu_fpr[rS(ctx->opcode)]);
    tcg_gen_mov_i64(cpu_FT[1], cpu_fpr[rS(ctx->opcode) + 1]);
5232 5233
    op_POWER2_stfq();
    if (ra != 0)
A
aurel32 已提交
5234
        tcg_gen_mov_tl(cpu_gpr[ra], cpu_T[0]);
5235 5236 5237 5238 5239 5240
}

/* stfqx */
GEN_HANDLER(stfqx, 0x1F, 0x17, 0x1C, 0x00000001, PPC_POWER2)
{
    /* NIP cannot be restored if the memory exception comes from an helper */
5241
    gen_update_nip(ctx, ctx->nip - 4);
5242
    gen_addr_reg_index(cpu_T[0], ctx);
A
aurel32 已提交
5243 5244
    tcg_gen_mov_i64(cpu_FT[0], cpu_fpr[rS(ctx->opcode)]);
    tcg_gen_mov_i64(cpu_FT[1], cpu_fpr[rS(ctx->opcode) + 1]);
5245 5246 5247 5248
    op_POWER2_stfq();
}

/* BookE specific instructions */
5249
/* XXX: not implemented on 440 ? */
5250
GEN_HANDLER(mfapidi, 0x1F, 0x13, 0x08, 0x0000F801, PPC_MFAPIDI)
5251 5252
{
    /* XXX: TODO */
5253
    GEN_EXCP_INVAL(ctx);
5254 5255
}

5256
/* XXX: not implemented on 440 ? */
5257
GEN_HANDLER(tlbiva, 0x1F, 0x12, 0x18, 0x03FFF801, PPC_TLBIVA)
5258 5259
{
#if defined(CONFIG_USER_ONLY)
5260
    GEN_EXCP_PRIVOPC(ctx);
5261 5262
#else
    if (unlikely(!ctx->supervisor)) {
5263
        GEN_EXCP_PRIVOPC(ctx);
5264 5265
        return;
    }
5266
    gen_addr_reg_index(cpu_T[0], ctx);
5267
    /* Use the same micro-ops as for tlbie */
5268 5269 5270 5271 5272 5273
#if defined(TARGET_PPC64)
    if (ctx->sf_mode)
        gen_op_tlbie_64();
    else
#endif
        gen_op_tlbie();
5274 5275 5276 5277
#endif
}

/* All 405 MAC instructions are translated here */
5278 5279 5280
static always_inline void gen_405_mulladd_insn (DisasContext *ctx,
                                                int opc2, int opc3,
                                                int ra, int rb, int rt, int Rc)
5281
{
5282 5283
    TCGv t0, t1;

P
pbrook 已提交
5284 5285
    t0 = tcg_temp_local_new();
    t1 = tcg_temp_local_new();
5286

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

5399 5400
#define GEN_MAC_HANDLER(name, opc2, opc3)                                     \
GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_405_MAC)                  \
5401 5402 5403 5404 5405 5406
{                                                                             \
    gen_405_mulladd_insn(ctx, opc2, opc3, rA(ctx->opcode), rB(ctx->opcode),   \
                         rD(ctx->opcode), Rc(ctx->opcode));                   \
}

/* macchw    - macchw.    */
5407
GEN_MAC_HANDLER(macchw, 0x0C, 0x05);
5408
/* macchwo   - macchwo.   */
5409
GEN_MAC_HANDLER(macchwo, 0x0C, 0x15);
5410
/* macchws   - macchws.   */
5411
GEN_MAC_HANDLER(macchws, 0x0C, 0x07);
5412
/* macchwso  - macchwso.  */
5413
GEN_MAC_HANDLER(macchwso, 0x0C, 0x17);
5414
/* macchwsu  - macchwsu.  */
5415
GEN_MAC_HANDLER(macchwsu, 0x0C, 0x06);
5416
/* macchwsuo - macchwsuo. */
5417
GEN_MAC_HANDLER(macchwsuo, 0x0C, 0x16);
5418
/* macchwu   - macchwu.   */
5419
GEN_MAC_HANDLER(macchwu, 0x0C, 0x04);
5420
/* macchwuo  - macchwuo.  */
5421
GEN_MAC_HANDLER(macchwuo, 0x0C, 0x14);
5422
/* machhw    - machhw.    */
5423
GEN_MAC_HANDLER(machhw, 0x0C, 0x01);
5424
/* machhwo   - machhwo.   */
5425
GEN_MAC_HANDLER(machhwo, 0x0C, 0x11);
5426
/* machhws   - machhws.   */
5427
GEN_MAC_HANDLER(machhws, 0x0C, 0x03);
5428
/* machhwso  - machhwso.  */
5429
GEN_MAC_HANDLER(machhwso, 0x0C, 0x13);
5430
/* machhwsu  - machhwsu.  */
5431
GEN_MAC_HANDLER(machhwsu, 0x0C, 0x02);
5432
/* machhwsuo - machhwsuo. */
5433
GEN_MAC_HANDLER(machhwsuo, 0x0C, 0x12);
5434
/* machhwu   - machhwu.   */
5435
GEN_MAC_HANDLER(machhwu, 0x0C, 0x00);
5436
/* machhwuo  - machhwuo.  */
5437
GEN_MAC_HANDLER(machhwuo, 0x0C, 0x10);
5438
/* maclhw    - maclhw.    */
5439
GEN_MAC_HANDLER(maclhw, 0x0C, 0x0D);
5440
/* maclhwo   - maclhwo.   */
5441
GEN_MAC_HANDLER(maclhwo, 0x0C, 0x1D);
5442
/* maclhws   - maclhws.   */
5443
GEN_MAC_HANDLER(maclhws, 0x0C, 0x0F);
5444
/* maclhwso  - maclhwso.  */
5445
GEN_MAC_HANDLER(maclhwso, 0x0C, 0x1F);
5446
/* maclhwu   - maclhwu.   */
5447
GEN_MAC_HANDLER(maclhwu, 0x0C, 0x0C);
5448
/* maclhwuo  - maclhwuo.  */
5449
GEN_MAC_HANDLER(maclhwuo, 0x0C, 0x1C);
5450
/* maclhwsu  - maclhwsu.  */
5451
GEN_MAC_HANDLER(maclhwsu, 0x0C, 0x0E);
5452
/* maclhwsuo - maclhwsuo. */
5453
GEN_MAC_HANDLER(maclhwsuo, 0x0C, 0x1E);
5454
/* nmacchw   - nmacchw.   */
5455
GEN_MAC_HANDLER(nmacchw, 0x0E, 0x05);
5456
/* nmacchwo  - nmacchwo.  */
5457
GEN_MAC_HANDLER(nmacchwo, 0x0E, 0x15);
5458
/* nmacchws  - nmacchws.  */
5459
GEN_MAC_HANDLER(nmacchws, 0x0E, 0x07);
5460
/* nmacchwso - nmacchwso. */
5461
GEN_MAC_HANDLER(nmacchwso, 0x0E, 0x17);
5462
/* nmachhw   - nmachhw.   */
5463
GEN_MAC_HANDLER(nmachhw, 0x0E, 0x01);
5464
/* nmachhwo  - nmachhwo.  */
5465
GEN_MAC_HANDLER(nmachhwo, 0x0E, 0x11);
5466
/* nmachhws  - nmachhws.  */
5467
GEN_MAC_HANDLER(nmachhws, 0x0E, 0x03);
5468
/* nmachhwso - nmachhwso. */
5469
GEN_MAC_HANDLER(nmachhwso, 0x0E, 0x13);
5470
/* nmaclhw   - nmaclhw.   */
5471
GEN_MAC_HANDLER(nmaclhw, 0x0E, 0x0D);
5472
/* nmaclhwo  - nmaclhwo.  */
5473
GEN_MAC_HANDLER(nmaclhwo, 0x0E, 0x1D);
5474
/* nmaclhws  - nmaclhws.  */
5475
GEN_MAC_HANDLER(nmaclhws, 0x0E, 0x0F);
5476
/* nmaclhwso - nmaclhwso. */
5477
GEN_MAC_HANDLER(nmaclhwso, 0x0E, 0x1F);
5478 5479

/* mulchw  - mulchw.  */
5480
GEN_MAC_HANDLER(mulchw, 0x08, 0x05);
5481
/* mulchwu - mulchwu. */
5482
GEN_MAC_HANDLER(mulchwu, 0x08, 0x04);
5483
/* mulhhw  - mulhhw.  */
5484
GEN_MAC_HANDLER(mulhhw, 0x08, 0x01);
5485
/* mulhhwu - mulhhwu. */
5486
GEN_MAC_HANDLER(mulhhwu, 0x08, 0x00);
5487
/* mullhw  - mullhw.  */
5488
GEN_MAC_HANDLER(mullhw, 0x08, 0x0D);
5489
/* mullhwu - mullhwu. */
5490
GEN_MAC_HANDLER(mullhwu, 0x08, 0x0C);
5491 5492

/* mfdcr */
5493
GEN_HANDLER(mfdcr, 0x1F, 0x03, 0x0A, 0x00000001, PPC_DCR)
5494 5495
{
#if defined(CONFIG_USER_ONLY)
5496
    GEN_EXCP_PRIVREG(ctx);
5497 5498 5499 5500
#else
    uint32_t dcrn = SPR(ctx->opcode);

    if (unlikely(!ctx->supervisor)) {
5501
        GEN_EXCP_PRIVREG(ctx);
5502 5503
        return;
    }
5504
    tcg_gen_movi_tl(cpu_T[0], dcrn);
5505
    gen_op_load_dcr();
A
aurel32 已提交
5506
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
5507 5508 5509 5510
#endif
}

/* mtdcr */
5511
GEN_HANDLER(mtdcr, 0x1F, 0x03, 0x0E, 0x00000001, PPC_DCR)
5512 5513
{
#if defined(CONFIG_USER_ONLY)
5514
    GEN_EXCP_PRIVREG(ctx);
5515 5516 5517 5518
#else
    uint32_t dcrn = SPR(ctx->opcode);

    if (unlikely(!ctx->supervisor)) {
5519
        GEN_EXCP_PRIVREG(ctx);
5520 5521
        return;
    }
5522
    tcg_gen_movi_tl(cpu_T[0], dcrn);
A
aurel32 已提交
5523
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]);
5524 5525 5526 5527 5528
    gen_op_store_dcr();
#endif
}

/* mfdcrx */
5529
/* XXX: not implemented on 440 ? */
5530
GEN_HANDLER(mfdcrx, 0x1F, 0x03, 0x08, 0x00000000, PPC_DCRX)
5531 5532
{
#if defined(CONFIG_USER_ONLY)
5533
    GEN_EXCP_PRIVREG(ctx);
5534 5535
#else
    if (unlikely(!ctx->supervisor)) {
5536
        GEN_EXCP_PRIVREG(ctx);
5537 5538
        return;
    }
A
aurel32 已提交
5539
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
5540
    gen_op_load_dcr();
A
aurel32 已提交
5541
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
5542
    /* Note: Rc update flag set leads to undefined state of Rc0 */
5543 5544 5545 5546
#endif
}

/* mtdcrx */
5547
/* XXX: not implemented on 440 ? */
5548
GEN_HANDLER(mtdcrx, 0x1F, 0x03, 0x0C, 0x00000000, PPC_DCRX)
5549 5550
{
#if defined(CONFIG_USER_ONLY)
5551
    GEN_EXCP_PRIVREG(ctx);
5552 5553
#else
    if (unlikely(!ctx->supervisor)) {
5554
        GEN_EXCP_PRIVREG(ctx);
5555 5556
        return;
    }
A
aurel32 已提交
5557 5558
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]);
5559
    gen_op_store_dcr();
5560
    /* Note: Rc update flag set leads to undefined state of Rc0 */
5561 5562 5563
#endif
}

5564 5565 5566
/* mfdcrux (PPC 460) : user-mode access to DCR */
GEN_HANDLER(mfdcrux, 0x1F, 0x03, 0x09, 0x00000000, PPC_DCRUX)
{
A
aurel32 已提交
5567
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
5568
    gen_op_load_dcr();
A
aurel32 已提交
5569
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
5570 5571 5572 5573 5574 5575
    /* Note: Rc update flag set leads to undefined state of Rc0 */
}

/* mtdcrux (PPC 460) : user-mode access to DCR */
GEN_HANDLER(mtdcrux, 0x1F, 0x03, 0x0D, 0x00000000, PPC_DCRUX)
{
A
aurel32 已提交
5576 5577
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]);
5578 5579 5580 5581
    gen_op_store_dcr();
    /* Note: Rc update flag set leads to undefined state of Rc0 */
}

5582 5583 5584 5585
/* dccci */
GEN_HANDLER(dccci, 0x1F, 0x06, 0x0E, 0x03E00001, PPC_4xx_COMMON)
{
#if defined(CONFIG_USER_ONLY)
5586
    GEN_EXCP_PRIVOPC(ctx);
5587 5588
#else
    if (unlikely(!ctx->supervisor)) {
5589
        GEN_EXCP_PRIVOPC(ctx);
5590 5591 5592 5593 5594 5595 5596 5597 5598 5599
        return;
    }
    /* interpreted as no-op */
#endif
}

/* dcread */
GEN_HANDLER(dcread, 0x1F, 0x06, 0x0F, 0x00000001, PPC_4xx_COMMON)
{
#if defined(CONFIG_USER_ONLY)
5600
    GEN_EXCP_PRIVOPC(ctx);
5601
#else
A
aurel32 已提交
5602
    TCGv EA, val;
5603
    if (unlikely(!ctx->supervisor)) {
5604
        GEN_EXCP_PRIVOPC(ctx);
5605 5606
        return;
    }
P
pbrook 已提交
5607
    EA = tcg_temp_new();
A
aurel32 已提交
5608
    gen_set_access_type(ACCESS_CACHE);
A
aurel32 已提交
5609
    gen_addr_reg_index(EA, ctx);
P
pbrook 已提交
5610
    val = tcg_temp_new();
A
aurel32 已提交
5611 5612 5613 5614
    gen_qemu_ld32u(val, EA, ctx->mem_idx);
    tcg_temp_free(val);
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], EA);
    tcg_temp_free(EA);
5615 5616 5617 5618
#endif
}

/* icbt */
5619
GEN_HANDLER2(icbt_40x, "icbt", 0x1F, 0x06, 0x08, 0x03E00001, PPC_40x_ICBT)
5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630
{
    /* 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)
5631
    GEN_EXCP_PRIVOPC(ctx);
5632 5633
#else
    if (unlikely(!ctx->supervisor)) {
5634
        GEN_EXCP_PRIVOPC(ctx);
5635 5636 5637 5638 5639 5640 5641 5642 5643 5644
        return;
    }
    /* interpreted as no-op */
#endif
}

/* icread */
GEN_HANDLER(icread, 0x1F, 0x06, 0x1F, 0x03E00001, PPC_4xx_COMMON)
{
#if defined(CONFIG_USER_ONLY)
5645
    GEN_EXCP_PRIVOPC(ctx);
5646 5647
#else
    if (unlikely(!ctx->supervisor)) {
5648
        GEN_EXCP_PRIVOPC(ctx);
5649 5650 5651 5652 5653 5654 5655
        return;
    }
    /* interpreted as no-op */
#endif
}

/* rfci (supervisor only) */
5656
GEN_HANDLER2(rfci_40x, "rfci", 0x13, 0x13, 0x01, 0x03FF8001, PPC_40x_EXCP)
5657 5658
{
#if defined(CONFIG_USER_ONLY)
5659
    GEN_EXCP_PRIVOPC(ctx);
5660 5661
#else
    if (unlikely(!ctx->supervisor)) {
5662
        GEN_EXCP_PRIVOPC(ctx);
5663 5664 5665 5666
        return;
    }
    /* Restore CPU state */
    gen_op_40x_rfci();
5667
    GEN_SYNC(ctx);
5668 5669 5670 5671 5672 5673
#endif
}

GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE)
{
#if defined(CONFIG_USER_ONLY)
5674
    GEN_EXCP_PRIVOPC(ctx);
5675 5676
#else
    if (unlikely(!ctx->supervisor)) {
5677
        GEN_EXCP_PRIVOPC(ctx);
5678 5679 5680 5681
        return;
    }
    /* Restore CPU state */
    gen_op_rfci();
5682
    GEN_SYNC(ctx);
5683 5684 5685 5686
#endif
}

/* BookE specific */
5687
/* XXX: not implemented on 440 ? */
5688
GEN_HANDLER(rfdi, 0x13, 0x07, 0x01, 0x03FF8001, PPC_RFDI)
5689 5690
{
#if defined(CONFIG_USER_ONLY)
5691
    GEN_EXCP_PRIVOPC(ctx);
5692 5693
#else
    if (unlikely(!ctx->supervisor)) {
5694
        GEN_EXCP_PRIVOPC(ctx);
5695 5696 5697
        return;
    }
    /* Restore CPU state */
5698
    gen_op_rfdi();
5699
    GEN_SYNC(ctx);
5700 5701 5702
#endif
}

5703
/* XXX: not implemented on 440 ? */
5704
GEN_HANDLER(rfmci, 0x13, 0x06, 0x01, 0x03FF8001, PPC_RFMCI)
5705 5706
{
#if defined(CONFIG_USER_ONLY)
5707
    GEN_EXCP_PRIVOPC(ctx);
5708 5709
#else
    if (unlikely(!ctx->supervisor)) {
5710
        GEN_EXCP_PRIVOPC(ctx);
5711 5712 5713 5714
        return;
    }
    /* Restore CPU state */
    gen_op_rfmci();
5715
    GEN_SYNC(ctx);
5716 5717
#endif
}
5718

5719
/* TLB management - PowerPC 405 implementation */
5720
/* tlbre */
5721
GEN_HANDLER2(tlbre_40x, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_TLB)
5722 5723
{
#if defined(CONFIG_USER_ONLY)
5724
    GEN_EXCP_PRIVOPC(ctx);
5725 5726
#else
    if (unlikely(!ctx->supervisor)) {
5727
        GEN_EXCP_PRIVOPC(ctx);
5728 5729 5730 5731
        return;
    }
    switch (rB(ctx->opcode)) {
    case 0:
A
aurel32 已提交
5732
        tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
5733
        gen_op_4xx_tlbre_hi();
A
aurel32 已提交
5734
        tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
5735 5736
        break;
    case 1:
A
aurel32 已提交
5737
        tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
5738
        gen_op_4xx_tlbre_lo();
A
aurel32 已提交
5739
        tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
5740 5741
        break;
    default:
5742
        GEN_EXCP_INVAL(ctx);
5743
        break;
5744
    }
5745 5746 5747
#endif
}

5748
/* tlbsx - tlbsx. */
5749
GEN_HANDLER2(tlbsx_40x, "tlbsx", 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_TLB)
5750 5751
{
#if defined(CONFIG_USER_ONLY)
5752
    GEN_EXCP_PRIVOPC(ctx);
5753 5754
#else
    if (unlikely(!ctx->supervisor)) {
5755
        GEN_EXCP_PRIVOPC(ctx);
5756 5757
        return;
    }
5758
    gen_addr_reg_index(cpu_T[0], ctx);
5759
    gen_op_4xx_tlbsx();
5760
    if (Rc(ctx->opcode))
5761
        gen_op_4xx_tlbsx_check();
A
aurel32 已提交
5762
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
5763
#endif
B
bellard 已提交
5764 5765
}

5766
/* tlbwe */
5767
GEN_HANDLER2(tlbwe_40x, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_TLB)
B
bellard 已提交
5768
{
5769
#if defined(CONFIG_USER_ONLY)
5770
    GEN_EXCP_PRIVOPC(ctx);
5771 5772
#else
    if (unlikely(!ctx->supervisor)) {
5773
        GEN_EXCP_PRIVOPC(ctx);
5774 5775 5776 5777
        return;
    }
    switch (rB(ctx->opcode)) {
    case 0:
A
aurel32 已提交
5778 5779
        tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
        tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]);
5780 5781 5782
        gen_op_4xx_tlbwe_hi();
        break;
    case 1:
A
aurel32 已提交
5783 5784
        tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
        tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]);
5785 5786 5787
        gen_op_4xx_tlbwe_lo();
        break;
    default:
5788
        GEN_EXCP_INVAL(ctx);
5789
        break;
5790
    }
5791 5792 5793
#endif
}

5794
/* TLB management - PowerPC 440 implementation */
5795
/* tlbre */
5796
GEN_HANDLER2(tlbre_440, "tlbre", 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE)
5797 5798
{
#if defined(CONFIG_USER_ONLY)
5799
    GEN_EXCP_PRIVOPC(ctx);
5800 5801
#else
    if (unlikely(!ctx->supervisor)) {
5802
        GEN_EXCP_PRIVOPC(ctx);
5803 5804 5805 5806 5807 5808
        return;
    }
    switch (rB(ctx->opcode)) {
    case 0:
    case 1:
    case 2:
A
aurel32 已提交
5809
        tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
5810
        gen_op_440_tlbre(rB(ctx->opcode));
A
aurel32 已提交
5811
        tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
5812 5813
        break;
    default:
5814
        GEN_EXCP_INVAL(ctx);
5815 5816 5817 5818 5819 5820
        break;
    }
#endif
}

/* tlbsx - tlbsx. */
5821
GEN_HANDLER2(tlbsx_440, "tlbsx", 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE)
5822 5823
{
#if defined(CONFIG_USER_ONLY)
5824
    GEN_EXCP_PRIVOPC(ctx);
5825 5826
#else
    if (unlikely(!ctx->supervisor)) {
5827
        GEN_EXCP_PRIVOPC(ctx);
5828 5829
        return;
    }
5830
    gen_addr_reg_index(cpu_T[0], ctx);
5831
    gen_op_440_tlbsx();
5832
    if (Rc(ctx->opcode))
5833
        gen_op_4xx_tlbsx_check();
A
aurel32 已提交
5834
    tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], cpu_T[0]);
5835 5836 5837 5838
#endif
}

/* tlbwe */
5839
GEN_HANDLER2(tlbwe_440, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE)
5840 5841
{
#if defined(CONFIG_USER_ONLY)
5842
    GEN_EXCP_PRIVOPC(ctx);
5843 5844
#else
    if (unlikely(!ctx->supervisor)) {
5845
        GEN_EXCP_PRIVOPC(ctx);
5846 5847 5848 5849 5850 5851
        return;
    }
    switch (rB(ctx->opcode)) {
    case 0:
    case 1:
    case 2:
A
aurel32 已提交
5852 5853
        tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rA(ctx->opcode)]);
        tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rS(ctx->opcode)]);
5854
        gen_op_440_tlbwe(rB(ctx->opcode));
5855 5856
        break;
    default:
5857
        GEN_EXCP_INVAL(ctx);
5858 5859 5860 5861 5862
        break;
    }
#endif
}

5863
/* wrtee */
5864
GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_WRTEE)
5865 5866
{
#if defined(CONFIG_USER_ONLY)
5867
    GEN_EXCP_PRIVOPC(ctx);
5868 5869
#else
    if (unlikely(!ctx->supervisor)) {
5870
        GEN_EXCP_PRIVOPC(ctx);
5871 5872
        return;
    }
A
aurel32 已提交
5873
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rD(ctx->opcode)]);
5874
    gen_op_wrte();
J
j_mayer 已提交
5875 5876 5877
    /* Stop translation to have a chance to raise an exception
     * if we just set msr_ee to 1
     */
5878
    GEN_STOP(ctx);
5879 5880 5881 5882
#endif
}

/* wrteei */
5883
GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000EFC01, PPC_WRTEE)
5884 5885
{
#if defined(CONFIG_USER_ONLY)
5886
    GEN_EXCP_PRIVOPC(ctx);
5887 5888
#else
    if (unlikely(!ctx->supervisor)) {
5889
        GEN_EXCP_PRIVOPC(ctx);
5890 5891
        return;
    }
5892
    tcg_gen_movi_tl(cpu_T[0], ctx->opcode & 0x00010000);
5893
    gen_op_wrte();
J
j_mayer 已提交
5894 5895 5896
    /* Stop translation to have a chance to raise an exception
     * if we just set msr_ee to 1
     */
5897
    GEN_STOP(ctx);
5898 5899 5900
#endif
}

J
j_mayer 已提交
5901
/* PowerPC 440 specific instructions */
5902 5903 5904
/* dlmzb */
GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC)
{
A
aurel32 已提交
5905 5906
    tcg_gen_mov_tl(cpu_T[0], cpu_gpr[rS(ctx->opcode)]);
    tcg_gen_mov_tl(cpu_T[1], cpu_gpr[rB(ctx->opcode)]);
5907
    gen_op_440_dlmzb();
A
aurel32 已提交
5908
    tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], cpu_T[0]);
A
aurel32 已提交
5909 5910
    tcg_gen_andi_tl(cpu_xer, cpu_xer, ~0x7F);
    tcg_gen_or_tl(cpu_xer, cpu_xer, cpu_T[0]);
5911 5912
    if (Rc(ctx->opcode)) {
        gen_op_440_dlmzb_update_Rc();
P
pbrook 已提交
5913 5914
        tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_T[0]);
        tcg_gen_andi_i32(cpu_crf[0], cpu_crf[0], 0xf);
5915 5916 5917 5918 5919 5920 5921 5922 5923 5924
    }
}

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

/* msync replaces sync on 440 */
5925
GEN_HANDLER(msync, 0x1F, 0x16, 0x12, 0x03FFF801, PPC_BOOKE)
5926 5927 5928 5929 5930
{
    /* interpreted as no-op */
}

/* icbt */
5931
GEN_HANDLER2(icbt_440, "icbt", 0x1F, 0x16, 0x00, 0x03E00001, PPC_BOOKE)
5932 5933 5934 5935 5936
{
    /* interpreted as no-op */
    /* XXX: specification say this is treated as a load by the MMU
     *      but does not generate any exception
     */
B
bellard 已提交
5937 5938
}

5939 5940 5941 5942
/***                      Altivec vector extension                         ***/
/* Altivec registers moves */

#define GEN_VR_LDX(name, opc2, opc3)                                          \
5943
GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC)                  \
5944
{                                                                             \
5945
    TCGv EA;                                                                  \
5946 5947 5948 5949
    if (unlikely(!ctx->altivec_enabled)) {                                    \
        GEN_EXCP_NO_VR(ctx);                                                  \
        return;                                                               \
    }                                                                         \
5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962
    EA = tcg_temp_new();                                                      \
    gen_addr_reg_index(EA, ctx);                                              \
    tcg_gen_andi_tl(EA, EA, ~0xf);                                            \
    if (ctx->mem_idx & 1) {                                                   \
        gen_qemu_ld64(cpu_avrl[rD(ctx->opcode)], EA, ctx->mem_idx);           \
        tcg_gen_addi_tl(EA, EA, 8);                                           \
        gen_qemu_ld64(cpu_avrh[rD(ctx->opcode)], EA, ctx->mem_idx);           \
    } else {                                                                  \
        gen_qemu_ld64(cpu_avrh[rD(ctx->opcode)], EA, ctx->mem_idx);           \
        tcg_gen_addi_tl(EA, EA, 8);                                           \
        gen_qemu_ld64(cpu_avrl[rD(ctx->opcode)], EA, ctx->mem_idx);           \
    }                                                                         \
    tcg_temp_free(EA);                                                        \
5963 5964 5965 5966 5967
}

#define GEN_VR_STX(name, opc2, opc3)                                          \
GEN_HANDLER(st##name, 0x1F, opc2, opc3, 0x00000001, PPC_ALTIVEC)              \
{                                                                             \
5968
    TCGv EA;                                                                  \
5969 5970 5971 5972
    if (unlikely(!ctx->altivec_enabled)) {                                    \
        GEN_EXCP_NO_VR(ctx);                                                  \
        return;                                                               \
    }                                                                         \
5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985
    EA = tcg_temp_new();                                                      \
    gen_addr_reg_index(EA, ctx);                                              \
    tcg_gen_andi_tl(EA, EA, ~0xf);                                            \
    if (ctx->mem_idx & 1) {                                                   \
        gen_qemu_st64(cpu_avrl[rD(ctx->opcode)], EA, ctx->mem_idx);           \
        tcg_gen_addi_tl(EA, EA, 8);                                           \
        gen_qemu_st64(cpu_avrh[rD(ctx->opcode)], EA, ctx->mem_idx);           \
    } else {                                                                  \
        gen_qemu_st64(cpu_avrh[rD(ctx->opcode)], EA, ctx->mem_idx);           \
        tcg_gen_addi_tl(EA, EA, 8);                                           \
        gen_qemu_st64(cpu_avrl[rD(ctx->opcode)], EA, ctx->mem_idx);           \
    }                                                                         \
    tcg_temp_free(EA);                                                        \
5986 5987
}

5988
GEN_VR_LDX(lvx, 0x07, 0x03);
5989
/* As we don't emulate the cache, lvxl is stricly equivalent to lvx */
5990
GEN_VR_LDX(lvxl, 0x07, 0x0B);
5991

5992
GEN_VR_STX(svx, 0x07, 0x07);
5993
/* As we don't emulate the cache, stvxl is stricly equivalent to stvx */
5994
GEN_VR_STX(svxl, 0x07, 0x0F);
5995

5996 5997
/***                           SPE extension                               ***/
/* Register moves */
5998

P
pbrook 已提交
5999
static always_inline void gen_load_gpr64(TCGv_i64 t, int reg) {
A
aurel32 已提交
6000 6001 6002
#if defined(TARGET_PPC64)
    tcg_gen_mov_i64(t, cpu_gpr[reg]);
#else
P
pbrook 已提交
6003
    tcg_gen_concat_i32_i64(t, cpu_gpr[reg], cpu_gprh[reg]);
6004
#endif
A
aurel32 已提交
6005
}
6006

P
pbrook 已提交
6007
static always_inline void gen_store_gpr64(int reg, TCGv_i64 t) {
A
aurel32 已提交
6008 6009 6010
#if defined(TARGET_PPC64)
    tcg_gen_mov_i64(cpu_gpr[reg], t);
#else
P
pbrook 已提交
6011
    TCGv_i64 tmp = tcg_temp_new_i64();
A
aurel32 已提交
6012 6013 6014
    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 已提交
6015
    tcg_temp_free_i64(tmp);
6016
#endif
A
aurel32 已提交
6017
}
6018

6019 6020 6021 6022 6023 6024 6025 6026 6027 6028
#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 */
6029
static always_inline void gen_speundef (DisasContext *ctx)
6030
{
6031
    GEN_EXCP_INVAL(ctx);
6032 6033 6034
}

/* SPE load and stores */
6035
static always_inline void gen_addr_spe_imm_index (TCGv EA, DisasContext *ctx, int sh)
6036 6037 6038
{
    target_long simm = rB(ctx->opcode);

6039 6040 6041 6042 6043 6044
    if (rA(ctx->opcode) == 0)
        tcg_gen_movi_tl(EA, simm << sh);
    else if (likely(simm != 0))
        tcg_gen_addi_tl(EA, cpu_gpr[rA(ctx->opcode)], simm << sh);
    else
        tcg_gen_mov_tl(EA, cpu_gpr[rA(ctx->opcode)]);
6045 6046 6047 6048
}

#define op_spe_ldst(name)        (*gen_op_##name[ctx->mem_idx])()
#define OP_SPE_LD_TABLE(name)                                                 \
6049 6050
static GenOpFunc *gen_op_spe_l##name[NB_MEM_FUNCS] = {                        \
    GEN_MEM_FUNCS(spe_l##name),                                               \
6051 6052
};
#define OP_SPE_ST_TABLE(name)                                                 \
6053 6054
static GenOpFunc *gen_op_spe_st##name[NB_MEM_FUNCS] = {                       \
    GEN_MEM_FUNCS(spe_st##name),                                              \
6055
};
6056 6057

#define GEN_SPE_LD(name, sh)                                                  \
6058
static always_inline void gen_evl##name (DisasContext *ctx)                   \
6059 6060
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
6061
        GEN_EXCP_NO_AP(ctx);                                                  \
6062 6063
        return;                                                               \
    }                                                                         \
6064
    gen_addr_spe_imm_index(cpu_T[0], ctx, sh);                                \
6065
    op_spe_ldst(spe_l##name);                                                 \
A
aurel32 已提交
6066
    gen_store_gpr64(rD(ctx->opcode), cpu_T64[1]);                             \
6067 6068 6069
}

#define GEN_SPE_LDX(name)                                                     \
6070
static always_inline void gen_evl##name##x (DisasContext *ctx)                \
6071 6072
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
6073
        GEN_EXCP_NO_AP(ctx);                                                  \
6074 6075
        return;                                                               \
    }                                                                         \
6076
    gen_addr_reg_index(cpu_T[0], ctx);                                        \
6077
    op_spe_ldst(spe_l##name);                                                 \
A
aurel32 已提交
6078
    gen_store_gpr64(rD(ctx->opcode), cpu_T64[1]);                             \
6079 6080 6081 6082 6083 6084 6085 6086
}

#define GEN_SPEOP_LD(name, sh)                                                \
OP_SPE_LD_TABLE(name);                                                        \
GEN_SPE_LD(name, sh);                                                         \
GEN_SPE_LDX(name)

#define GEN_SPE_ST(name, sh)                                                  \
6087
static always_inline void gen_evst##name (DisasContext *ctx)                  \
6088 6089
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
6090
        GEN_EXCP_NO_AP(ctx);                                                  \
6091 6092
        return;                                                               \
    }                                                                         \
6093
    gen_addr_spe_imm_index(cpu_T[0], ctx, sh);                                \
A
aurel32 已提交
6094
    gen_load_gpr64(cpu_T64[1], rS(ctx->opcode));                              \
6095 6096 6097 6098
    op_spe_ldst(spe_st##name);                                                \
}

#define GEN_SPE_STX(name)                                                     \
6099
static always_inline void gen_evst##name##x (DisasContext *ctx)               \
6100 6101
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
6102
        GEN_EXCP_NO_AP(ctx);                                                  \
6103 6104
        return;                                                               \
    }                                                                         \
6105
    gen_addr_reg_index(cpu_T[0], ctx);                                        \
A
aurel32 已提交
6106
    gen_load_gpr64(cpu_T64[1], rS(ctx->opcode));                              \
6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118
    op_spe_ldst(spe_st##name);                                                \
}

#define GEN_SPEOP_ST(name, sh)                                                \
OP_SPE_ST_TABLE(name);                                                        \
GEN_SPE_ST(name, sh);                                                         \
GEN_SPE_STX(name)

#define GEN_SPEOP_LDST(name, sh)                                              \
GEN_SPEOP_LD(name, sh);                                                       \
GEN_SPEOP_ST(name, sh)

6119 6120 6121
/* SPE logic */
#if defined(TARGET_PPC64)
#define GEN_SPEOP_LOGIC2(name, tcg_op)                                        \
6122
static always_inline void gen_##name (DisasContext *ctx)                      \
6123 6124
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
6125
        GEN_EXCP_NO_AP(ctx);                                                  \
6126 6127
        return;                                                               \
    }                                                                         \
6128 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142
    tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],                \
           cpu_gpr[rB(ctx->opcode)]);                                         \
}
#else
#define GEN_SPEOP_LOGIC2(name, tcg_op)                                        \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        return;                                                               \
    }                                                                         \
    tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],                \
           cpu_gpr[rB(ctx->opcode)]);                                         \
    tcg_op(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)],              \
           cpu_gprh[rB(ctx->opcode)]);                                        \
6143
}
6144 6145 6146 6147 6148 6149 6150 6151 6152 6153
#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);
6154

6155 6156 6157
/* SPE logic immediate */
#if defined(TARGET_PPC64)
#define GEN_SPEOP_TCG_LOGIC_IMM2(name, tcg_opi)                               \
6158 6159 6160 6161 6162 6163
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        return;                                                               \
    }                                                                         \
P
pbrook 已提交
6164 6165 6166
    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
    TCGv_i64 t2 = tcg_temp_local_new_i64();                                   \
6167 6168 6169 6170
    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 已提交
6171
    tcg_temp_free_i64(t2);                                                    \
6172 6173
    tcg_opi(t1, t1, rB(ctx->opcode));                                         \
    tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1);                 \
P
pbrook 已提交
6174 6175
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
6176
}
6177 6178
#else
#define GEN_SPEOP_TCG_LOGIC_IMM2(name, tcg_opi)                               \
6179
static always_inline void gen_##name (DisasContext *ctx)                      \
6180 6181
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
6182
        GEN_EXCP_NO_AP(ctx);                                                  \
6183 6184
        return;                                                               \
    }                                                                         \
6185 6186 6187 6188
    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));                                                 \
6189
}
6190 6191 6192 6193 6194
#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);
6195

6196 6197 6198
/* SPE arithmetic */
#if defined(TARGET_PPC64)
#define GEN_SPEOP_ARITH1(name, tcg_op)                                        \
6199
static always_inline void gen_##name (DisasContext *ctx)                      \
6200 6201
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
6202
        GEN_EXCP_NO_AP(ctx);                                                  \
6203 6204
        return;                                                               \
    }                                                                         \
P
pbrook 已提交
6205 6206 6207
    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
    TCGv_i64 t2 = tcg_temp_local_new_i64();                                   \
6208 6209 6210 6211
    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 已提交
6212
    tcg_temp_free_i64(t2);                                                    \
6213 6214
    tcg_op(t1, t1);                                                           \
    tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1);                 \
P
pbrook 已提交
6215 6216
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
6217
}
6218
#else
P
pbrook 已提交
6219
#define GEN_SPEOP_ARITH1(name, tcg_op)                                        \
6220 6221 6222 6223 6224 6225 6226 6227 6228 6229
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        return;                                                               \
    }                                                                         \
    tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);               \
    tcg_op(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]);             \
}
#endif
6230

P
pbrook 已提交
6231
static always_inline void gen_op_evabs (TCGv_i32 ret, TCGv_i32 arg1)
6232 6233 6234
{
    int l1 = gen_new_label();
    int l2 = gen_new_label();
6235

6236 6237 6238 6239
    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 已提交
6240
    tcg_gen_mov_i32(ret, arg1);
6241 6242 6243 6244 6245 6246
    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 已提交
6247
static always_inline void gen_op_evrndw (TCGv_i32 ret, TCGv_i32 arg1)
6248
{
6249 6250 6251 6252
    tcg_gen_addi_i32(ret, arg1, 0x8000);
    tcg_gen_ext16u_i32(ret, ret);
}
GEN_SPEOP_ARITH1(evrndw, gen_op_evrndw);
P
pbrook 已提交
6253 6254
GEN_SPEOP_ARITH1(evcntlsw, gen_helper_cntlsw32);
GEN_SPEOP_ARITH1(evcntlzw, gen_helper_cntlzw32);
6255

6256 6257 6258
#if defined(TARGET_PPC64)
#define GEN_SPEOP_ARITH2(name, tcg_op)                                        \
static always_inline void gen_##name (DisasContext *ctx)                      \
6259 6260
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
6261
        GEN_EXCP_NO_AP(ctx);                                                  \
6262 6263
        return;                                                               \
    }                                                                         \
P
pbrook 已提交
6264 6265 6266 6267
    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t2 = tcg_temp_local_new_i32();                                   \
    TCGv_i64 t3 = tcg_temp_local_new(TCG_TYPE_I64);                           \
6268 6269 6270 6271 6272 6273 6274
    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 已提交
6275
    tcg_temp_free_i64(t3);                                                    \
6276
    tcg_op(t1, t1, t2);                                                       \
P
pbrook 已提交
6277
    tcg_temp_free_i32(t2);                                                    \
6278
    tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1);                 \
P
pbrook 已提交
6279 6280
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
6281
}
6282 6283 6284
#else
#define GEN_SPEOP_ARITH2(name, tcg_op)                                        \
static always_inline void gen_##name (DisasContext *ctx)                      \
6285 6286
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
6287
        GEN_EXCP_NO_AP(ctx);                                                  \
6288 6289
        return;                                                               \
    }                                                                         \
6290 6291 6292 6293
    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)]);                                        \
6294
}
6295
#endif
6296

P
pbrook 已提交
6297
static always_inline void gen_op_evsrwu (TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
6298
{
P
pbrook 已提交
6299
    TCGv_i32 t0;
6300
    int l1, l2;
6301

6302 6303
    l1 = gen_new_label();
    l2 = gen_new_label();
P
pbrook 已提交
6304
    t0 = tcg_temp_local_new_i32();
6305 6306 6307 6308 6309 6310 6311 6312
    /* 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 已提交
6313
    tcg_temp_free_i32(t0);
6314 6315
}
GEN_SPEOP_ARITH2(evsrwu, gen_op_evsrwu);
P
pbrook 已提交
6316
static always_inline void gen_op_evsrws (TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
6317
{
P
pbrook 已提交
6318
    TCGv_i32 t0;
6319 6320 6321 6322
    int l1, l2;

    l1 = gen_new_label();
    l2 = gen_new_label();
P
pbrook 已提交
6323
    t0 = tcg_temp_local_new_i32();
6324 6325 6326 6327 6328 6329 6330 6331
    /* 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 已提交
6332
    tcg_temp_free_i32(t0);
6333 6334
}
GEN_SPEOP_ARITH2(evsrws, gen_op_evsrws);
P
pbrook 已提交
6335
static always_inline void gen_op_evslw (TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
6336
{
P
pbrook 已提交
6337
    TCGv_i32 t0;
6338 6339 6340 6341
    int l1, l2;

    l1 = gen_new_label();
    l2 = gen_new_label();
P
pbrook 已提交
6342
    t0 = tcg_temp_local_new_i32();
6343 6344 6345 6346 6347 6348 6349 6350
    /* 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 已提交
6351
    tcg_temp_free_i32(t0);
6352 6353
}
GEN_SPEOP_ARITH2(evslw, gen_op_evslw);
P
pbrook 已提交
6354
static always_inline void gen_op_evrlw (TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
6355
{
P
pbrook 已提交
6356
    TCGv_i32 t0 = tcg_temp_new_i32();
6357 6358
    tcg_gen_andi_i32(t0, arg2, 0x1F);
    tcg_gen_rotl_i32(ret, arg1, t0);
P
pbrook 已提交
6359
    tcg_temp_free_i32(t0);
6360 6361 6362 6363 6364 6365 6366 6367 6368
}
GEN_SPEOP_ARITH2(evrlw, gen_op_evrlw);
static always_inline void gen_evmergehi (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
        GEN_EXCP_NO_AP(ctx);
        return;
    }
#if defined(TARGET_PPC64)
P
pbrook 已提交
6369 6370
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381
    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 已提交
6382
static always_inline void gen_op_evsubf (TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2)
6383
{
6384 6385 6386
    tcg_gen_sub_i32(ret, arg2, arg1);
}
GEN_SPEOP_ARITH2(evsubfw, gen_op_evsubf);
6387

6388 6389 6390 6391 6392 6393 6394 6395 6396
/* SPE arithmetic immediate */
#if defined(TARGET_PPC64)
#define GEN_SPEOP_ARITH_IMM2(name, tcg_op)                                    \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        return;                                                               \
    }                                                                         \
P
pbrook 已提交
6397 6398 6399
    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
    TCGv_i64 t2 = tcg_temp_local_new_i64();                                   \
6400 6401 6402 6403
    tcg_gen_trunc_i64_i32(t0, cpu_gpr[rB(ctx->opcode)]);                      \
    tcg_op(t0, t0, rA(ctx->opcode));                                          \
    tcg_gen_shri_i64(t2, cpu_gpr[rB(ctx->opcode)], 32);                       \
    tcg_gen_trunc_i64_i32(t1, t2);                                            \
P
pbrook 已提交
6404
    tcg_temp_free_i64(t2);                                                        \
6405 6406
    tcg_op(t1, t1, rA(ctx->opcode));                                          \
    tcg_gen_concat_i32_i64(cpu_gpr[rD(ctx->opcode)], t0, t1);                 \
P
pbrook 已提交
6407 6408
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
6409 6410 6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439
}
#else
#define GEN_SPEOP_ARITH_IMM2(name, tcg_op)                                    \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        return;                                                               \
    }                                                                         \
    tcg_op(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],                \
           rA(ctx->opcode));                                                  \
    tcg_op(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rB(ctx->opcode)],              \
           rA(ctx->opcode));                                                  \
}
#endif
GEN_SPEOP_ARITH_IMM2(evaddiw, tcg_gen_addi_i32);
GEN_SPEOP_ARITH_IMM2(evsubifw, tcg_gen_subi_i32);

/* SPE comparison */
#if defined(TARGET_PPC64)
#define GEN_SPEOP_COMP(name, tcg_cond)                                        \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        return;                                                               \
    }                                                                         \
    int l1 = gen_new_label();                                                 \
    int l2 = gen_new_label();                                                 \
    int l3 = gen_new_label();                                                 \
    int l4 = gen_new_label();                                                 \
P
pbrook 已提交
6440 6441 6442
    TCGv_i32 t0 = tcg_temp_local_new_i32();                                   \
    TCGv_i32 t1 = tcg_temp_local_new_i32();                                   \
    TCGv_i64 t2 = tcg_temp_local_new_i64();                                   \
6443 6444 6445
    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 已提交
6446
    tcg_gen_movi_i32(cpu_crf[crfD(ctx->opcode)], 0);                          \
6447 6448 6449 6450 6451 6452 6453 6454 6455
    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 已提交
6456
    tcg_temp_free_i64(t2);                                                    \
6457 6458 6459 6460 6461 6462 6463 6464
    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 已提交
6465 6466
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509
}
#else
#define GEN_SPEOP_COMP(name, tcg_cond)                                        \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        return;                                                               \
    }                                                                         \
    int l1 = gen_new_label();                                                 \
    int l2 = gen_new_label();                                                 \
    int l3 = gen_new_label();                                                 \
    int l4 = gen_new_label();                                                 \
                                                                              \
    tcg_gen_brcond_i32(tcg_cond, cpu_gpr[rA(ctx->opcode)],                    \
                       cpu_gpr[rB(ctx->opcode)], l1);                         \
    tcg_gen_movi_tl(cpu_crf[crfD(ctx->opcode)], 0);                           \
    tcg_gen_br(l2);                                                           \
    gen_set_label(l1);                                                        \
    tcg_gen_movi_i32(cpu_crf[crfD(ctx->opcode)],                              \
                     CRF_CL | CRF_CH_OR_CL | CRF_CH_AND_CL);                  \
    gen_set_label(l2);                                                        \
    tcg_gen_brcond_i32(tcg_cond, cpu_gprh[rA(ctx->opcode)],                   \
                       cpu_gprh[rB(ctx->opcode)], l3);                        \
    tcg_gen_andi_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)],  \
                     ~(CRF_CH | CRF_CH_AND_CL));                              \
    tcg_gen_br(l4);                                                           \
    gen_set_label(l3);                                                        \
    tcg_gen_ori_i32(cpu_crf[crfD(ctx->opcode)], cpu_crf[crfD(ctx->opcode)],   \
                    CRF_CH | CRF_CH_OR_CL);                                   \
    gen_set_label(l4);                                                        \
}
#endif
GEN_SPEOP_COMP(evcmpgtu, TCG_COND_GTU);
GEN_SPEOP_COMP(evcmpgts, TCG_COND_GT);
GEN_SPEOP_COMP(evcmpltu, TCG_COND_LTU);
GEN_SPEOP_COMP(evcmplts, TCG_COND_LT);
GEN_SPEOP_COMP(evcmpeq, TCG_COND_EQ);

/* SPE misc */
static always_inline void gen_brinc (DisasContext *ctx)
{
    /* Note: brinc is usable even if SPE is disabled */
P
pbrook 已提交
6510 6511
    gen_helper_brinc(cpu_gpr[rD(ctx->opcode)],
                     cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
6512
}
6513 6514 6515 6516 6517 6518 6519
static always_inline void gen_evmergelo (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
        GEN_EXCP_NO_AP(ctx);
        return;
    }
#if defined(TARGET_PPC64)
P
pbrook 已提交
6520 6521
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x00000000FFFFFFFFLL);
    tcg_gen_shli_tl(t1, cpu_gpr[rA(ctx->opcode)], 32);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], t0, t1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
#else
    tcg_gen_mov_i32(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
    tcg_gen_mov_i32(cpu_gprh[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
#endif
}
static always_inline void gen_evmergehilo (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
        GEN_EXCP_NO_AP(ctx);
        return;
    }
#if defined(TARGET_PPC64)
P
pbrook 已提交
6539 6540
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
6541 6542 6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557
    tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x00000000FFFFFFFFLL);
    tcg_gen_andi_tl(t1, cpu_gpr[rA(ctx->opcode)], 0xFFFFFFFF0000000ULL);
    tcg_gen_or_tl(cpu_gpr[rD(ctx->opcode)], t0, t1);
    tcg_temp_free(t0);
    tcg_temp_free(t1);
#else
    tcg_gen_mov_i32(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
    tcg_gen_mov_i32(cpu_gprh[rD(ctx->opcode)], cpu_gprh[rA(ctx->opcode)]);
#endif
}
static always_inline void gen_evmergelohi (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
        GEN_EXCP_NO_AP(ctx);
        return;
    }
#if defined(TARGET_PPC64)
P
pbrook 已提交
6558 6559
    TCGv t0 = tcg_temp_new();
    TCGv t1 = tcg_temp_new();
6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571
    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)
{
6572
    uint64_t imm = ((int32_t)(rA(ctx->opcode) << 11)) >> 27;
6573

6574
#if defined(TARGET_PPC64)
6575
    tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], (imm << 32) | imm);
6576 6577 6578 6579 6580
#else
    tcg_gen_movi_i32(cpu_gpr[rD(ctx->opcode)], imm);
    tcg_gen_movi_i32(cpu_gprh[rD(ctx->opcode)], imm);
#endif
}
6581
static always_inline void gen_evsplatfi (DisasContext *ctx)
6582
{
6583
    uint64_t imm = rA(ctx->opcode) << 11;
6584

6585
#if defined(TARGET_PPC64)
6586
    tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], (imm << 32) | imm);
6587 6588 6589 6590
#else
    tcg_gen_movi_i32(cpu_gpr[rD(ctx->opcode)], imm);
    tcg_gen_movi_i32(cpu_gprh[rD(ctx->opcode)], imm);
#endif
6591 6592
}

6593 6594 6595 6596 6597 6598
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 已提交
6599
    TCGv_i32 t0 = tcg_temp_local_new_i32();
6600
#if defined(TARGET_PPC64)
P
pbrook 已提交
6601 6602
    TCGv t1 = tcg_temp_local_new();
    TCGv t2 = tcg_temp_local_new();
6603 6604 6605 6606 6607 6608 6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 6621 6622 6623 6624 6625 6626 6627 6628 6629 6630 6631 6632 6633
#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 已提交
6634
    tcg_temp_free_i32(t0);
6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656
#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);
}
6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693

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

/* Load and stores */
GEN_SPEOP_LDST(dd, 3);
GEN_SPEOP_LDST(dw, 3);
GEN_SPEOP_LDST(dh, 3);
GEN_SPEOP_LDST(whe, 2);
GEN_SPEOP_LD(whou, 2);
GEN_SPEOP_LD(whos, 2);
GEN_SPEOP_ST(who, 2);

#define _GEN_OP_SPE_STWWE(suffix)                                             \
6694
static always_inline void gen_op_spe_stwwe_##suffix (void)                    \
6695 6696 6697 6698 6699
{                                                                             \
    gen_op_srli32_T1_64();                                                    \
    gen_op_spe_stwwo_##suffix();                                              \
}
#define _GEN_OP_SPE_STWWE_LE(suffix)                                          \
6700
static always_inline void gen_op_spe_stwwe_le_##suffix (void)                 \
6701 6702 6703 6704 6705 6706 6707 6708
{                                                                             \
    gen_op_srli32_T1_64();                                                    \
    gen_op_spe_stwwo_le_##suffix();                                           \
}
#if defined(TARGET_PPC64)
#define GEN_OP_SPE_STWWE(suffix)                                              \
_GEN_OP_SPE_STWWE(suffix);                                                    \
_GEN_OP_SPE_STWWE_LE(suffix);                                                 \
6709
static always_inline void gen_op_spe_stwwe_64_##suffix (void)                 \
6710 6711 6712 6713
{                                                                             \
    gen_op_srli32_T1_64();                                                    \
    gen_op_spe_stwwo_64_##suffix();                                           \
}                                                                             \
6714
static always_inline void gen_op_spe_stwwe_le_64_##suffix (void)              \
6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727
{                                                                             \
    gen_op_srli32_T1_64();                                                    \
    gen_op_spe_stwwo_le_64_##suffix();                                        \
}
#else
#define GEN_OP_SPE_STWWE(suffix)                                              \
_GEN_OP_SPE_STWWE(suffix);                                                    \
_GEN_OP_SPE_STWWE_LE(suffix)
#endif
#if defined(CONFIG_USER_ONLY)
GEN_OP_SPE_STWWE(raw);
#else /* defined(CONFIG_USER_ONLY) */
GEN_OP_SPE_STWWE(user);
6728 6729
GEN_OP_SPE_STWWE(kernel);
GEN_OP_SPE_STWWE(hypv);
6730 6731 6732 6733 6734
#endif /* defined(CONFIG_USER_ONLY) */
GEN_SPEOP_ST(wwe, 2);
GEN_SPEOP_ST(wwo, 2);

#define GEN_SPE_LDSPLAT(name, op, suffix)                                     \
6735
static always_inline void gen_op_spe_l##name##_##suffix (void)                \
6736 6737 6738 6739 6740 6741
{                                                                             \
    gen_op_##op##_##suffix();                                                 \
    gen_op_splatw_T1_64();                                                    \
}

#define GEN_OP_SPE_LHE(suffix)                                                \
6742
static always_inline void gen_op_spe_lhe_##suffix (void)                      \
6743 6744 6745 6746 6747 6748
{                                                                             \
    gen_op_spe_lh_##suffix();                                                 \
    gen_op_sli16_T1_64();                                                     \
}

#define GEN_OP_SPE_LHX(suffix)                                                \
6749
static always_inline void gen_op_spe_lhx_##suffix (void)                      \
6750 6751 6752 6753 6754 6755 6756 6757 6758 6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778 6779
{                                                                             \
    gen_op_spe_lh_##suffix();                                                 \
    gen_op_extsh_T1_64();                                                     \
}

#if defined(CONFIG_USER_ONLY)
GEN_OP_SPE_LHE(raw);
GEN_SPE_LDSPLAT(hhesplat, spe_lhe, raw);
GEN_OP_SPE_LHE(le_raw);
GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_raw);
GEN_SPE_LDSPLAT(hhousplat, spe_lh, raw);
GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_raw);
GEN_OP_SPE_LHX(raw);
GEN_SPE_LDSPLAT(hhossplat, spe_lhx, raw);
GEN_OP_SPE_LHX(le_raw);
GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_raw);
#if defined(TARGET_PPC64)
GEN_OP_SPE_LHE(64_raw);
GEN_SPE_LDSPLAT(hhesplat, spe_lhe, 64_raw);
GEN_OP_SPE_LHE(le_64_raw);
GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_64_raw);
GEN_SPE_LDSPLAT(hhousplat, spe_lh, 64_raw);
GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_64_raw);
GEN_OP_SPE_LHX(64_raw);
GEN_SPE_LDSPLAT(hhossplat, spe_lhx, 64_raw);
GEN_OP_SPE_LHX(le_64_raw);
GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_raw);
#endif
#else
GEN_OP_SPE_LHE(user);
6780 6781
GEN_OP_SPE_LHE(kernel);
GEN_OP_SPE_LHE(hypv);
6782
GEN_SPE_LDSPLAT(hhesplat, spe_lhe, user);
6783 6784
GEN_SPE_LDSPLAT(hhesplat, spe_lhe, kernel);
GEN_SPE_LDSPLAT(hhesplat, spe_lhe, hypv);
6785
GEN_OP_SPE_LHE(le_user);
6786 6787
GEN_OP_SPE_LHE(le_kernel);
GEN_OP_SPE_LHE(le_hypv);
6788
GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_user);
6789 6790
GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_kernel);
GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_hypv);
6791
GEN_SPE_LDSPLAT(hhousplat, spe_lh, user);
6792 6793
GEN_SPE_LDSPLAT(hhousplat, spe_lh, kernel);
GEN_SPE_LDSPLAT(hhousplat, spe_lh, hypv);
6794
GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_user);
6795 6796
GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_kernel);
GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_hypv);
6797
GEN_OP_SPE_LHX(user);
6798 6799
GEN_OP_SPE_LHX(kernel);
GEN_OP_SPE_LHX(hypv);
6800
GEN_SPE_LDSPLAT(hhossplat, spe_lhx, user);
6801 6802
GEN_SPE_LDSPLAT(hhossplat, spe_lhx, kernel);
GEN_SPE_LDSPLAT(hhossplat, spe_lhx, hypv);
6803
GEN_OP_SPE_LHX(le_user);
6804 6805
GEN_OP_SPE_LHX(le_kernel);
GEN_OP_SPE_LHX(le_hypv);
6806
GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_user);
6807 6808
GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_kernel);
GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_hypv);
6809 6810
#if defined(TARGET_PPC64)
GEN_OP_SPE_LHE(64_user);
6811 6812
GEN_OP_SPE_LHE(64_kernel);
GEN_OP_SPE_LHE(64_hypv);
6813
GEN_SPE_LDSPLAT(hhesplat, spe_lhe, 64_user);
6814 6815
GEN_SPE_LDSPLAT(hhesplat, spe_lhe, 64_kernel);
GEN_SPE_LDSPLAT(hhesplat, spe_lhe, 64_hypv);
6816
GEN_OP_SPE_LHE(le_64_user);
6817 6818
GEN_OP_SPE_LHE(le_64_kernel);
GEN_OP_SPE_LHE(le_64_hypv);
6819
GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_64_user);
6820 6821
GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_64_kernel);
GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_64_hypv);
6822
GEN_SPE_LDSPLAT(hhousplat, spe_lh, 64_user);
6823 6824
GEN_SPE_LDSPLAT(hhousplat, spe_lh, 64_kernel);
GEN_SPE_LDSPLAT(hhousplat, spe_lh, 64_hypv);
6825
GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_64_user);
6826 6827
GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_64_kernel);
GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_64_hypv);
6828
GEN_OP_SPE_LHX(64_user);
6829 6830
GEN_OP_SPE_LHX(64_kernel);
GEN_OP_SPE_LHX(64_hypv);
6831
GEN_SPE_LDSPLAT(hhossplat, spe_lhx, 64_user);
6832 6833
GEN_SPE_LDSPLAT(hhossplat, spe_lhx, 64_kernel);
GEN_SPE_LDSPLAT(hhossplat, spe_lhx, 64_hypv);
6834
GEN_OP_SPE_LHX(le_64_user);
6835 6836
GEN_OP_SPE_LHX(le_64_kernel);
GEN_OP_SPE_LHX(le_64_hypv);
6837
GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_user);
6838 6839
GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_kernel);
GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_hypv);
6840 6841 6842 6843 6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 6859 6860 6861 6862 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877 6878 6879 6880 6881 6882 6883 6884 6885 6886 6887 6888 6889 6890 6891 6892 6893 6894 6895 6896 6897 6898 6899 6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 6928 6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939 6940 6941 6942 6943
#endif
#endif
GEN_SPEOP_LD(hhesplat, 1);
GEN_SPEOP_LD(hhousplat, 1);
GEN_SPEOP_LD(hhossplat, 1);
GEN_SPEOP_LD(wwsplat, 2);
GEN_SPEOP_LD(whsplat, 2);

GEN_SPE(evlddx,         evldd,         0x00, 0x0C, 0x00000000, PPC_SPE); //
GEN_SPE(evldwx,         evldw,         0x01, 0x0C, 0x00000000, PPC_SPE); //
GEN_SPE(evldhx,         evldh,         0x02, 0x0C, 0x00000000, PPC_SPE); //
GEN_SPE(evlhhesplatx,   evlhhesplat,   0x04, 0x0C, 0x00000000, PPC_SPE); //
GEN_SPE(evlhhousplatx,  evlhhousplat,  0x06, 0x0C, 0x00000000, PPC_SPE); //
GEN_SPE(evlhhossplatx,  evlhhossplat,  0x07, 0x0C, 0x00000000, PPC_SPE); //
GEN_SPE(evlwhex,        evlwhe,        0x08, 0x0C, 0x00000000, PPC_SPE); //
GEN_SPE(evlwhoux,       evlwhou,       0x0A, 0x0C, 0x00000000, PPC_SPE); //
GEN_SPE(evlwhosx,       evlwhos,       0x0B, 0x0C, 0x00000000, PPC_SPE); //
GEN_SPE(evlwwsplatx,    evlwwsplat,    0x0C, 0x0C, 0x00000000, PPC_SPE); //
GEN_SPE(evlwhsplatx,    evlwhsplat,    0x0E, 0x0C, 0x00000000, PPC_SPE); //
GEN_SPE(evstddx,        evstdd,        0x10, 0x0C, 0x00000000, PPC_SPE); //
GEN_SPE(evstdwx,        evstdw,        0x11, 0x0C, 0x00000000, PPC_SPE); //
GEN_SPE(evstdhx,        evstdh,        0x12, 0x0C, 0x00000000, PPC_SPE); //
GEN_SPE(evstwhex,       evstwhe,       0x18, 0x0C, 0x00000000, PPC_SPE); //
GEN_SPE(evstwhox,       evstwho,       0x1A, 0x0C, 0x00000000, PPC_SPE); //
GEN_SPE(evstwwex,       evstwwe,       0x1C, 0x0C, 0x00000000, PPC_SPE); //
GEN_SPE(evstwwox,       evstwwo,       0x1E, 0x0C, 0x00000000, PPC_SPE); //

/* 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 已提交
6944 6945
#if defined(TARGET_PPC64)
#define GEN_SPEFPUOP_CONV_32_32(name)                                         \
6946
static always_inline void gen_##name (DisasContext *ctx)                      \
6947
{                                                                             \
A
aurel32 已提交
6948 6949 6950 6951 6952 6953 6954 6955 6956 6957 6958 6959
    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);                                                        \
6960
}
A
aurel32 已提交
6961 6962 6963 6964 6965 6966 6967 6968 6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 6987 6988 6989
#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)                                       \
6990 6991
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
A
aurel32 已提交
6992 6993
    TCGv_i32 t0, t1;                                                          \
    TCGv_i64 t2;                                                              \
6994 6995 6996 6997
    if (unlikely(!ctx->spe_enabled)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
6998 6999 7000 7001 7002 7003 7004 7005 7006 7007 7008 7009 7010
    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);                                                        \
7011
}
A
aurel32 已提交
7012
#define GEN_SPEFPUOP_ARITH2_64_64(name)                                       \
7013 7014 7015 7016 7017 7018
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
7019 7020
    gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],     \
                      cpu_gpr[rB(ctx->opcode)]);                              \
7021
}
A
aurel32 已提交
7022
#define GEN_SPEFPUOP_COMP_32(name)                                            \
7023 7024
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
A
aurel32 已提交
7025
    TCGv_i32 t0, t1;                                                          \
7026 7027 7028 7029
    if (unlikely(!ctx->spe_enabled)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        return;                                                               \
    }                                                                         \
A
aurel32 已提交
7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052
    t0 = tcg_temp_new_i32();                                                  \
    t1 = tcg_temp_new_i32();                                                  \
    tcg_gen_trunc_tl_i32(t0, cpu_gpr[rA(ctx->opcode)]);                       \
    tcg_gen_trunc_tl_i32(t1, cpu_gpr[rB(ctx->opcode)]);                       \
    gen_helper_##name(cpu_crf[crfD(ctx->opcode)], t0, t1);                    \
    tcg_temp_free_i32(t0);                                                    \
    tcg_temp_free_i32(t1);                                                    \
}
#define GEN_SPEFPUOP_COMP_64(name)                                            \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        return;                                                               \
    }                                                                         \
    gen_helper_##name(cpu_crf[crfD(ctx->opcode)],                             \
                      cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);    \
}
#else
#define GEN_SPEFPUOP_CONV_32_32(name)                                         \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    gen_helper_##name(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);    \
7053
}
A
aurel32 已提交
7054 7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 7080 7081 7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 7093 7094 7095 7096 7097 7098 7099 7100 7101 7102 7103 7104 7105 7106 7107 7108 7109 7110 7111 7112 7113 7114 7115 7116 7117 7118 7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132
#define GEN_SPEFPUOP_CONV_32_64(name)                                         \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    TCGv_i64 t0 = tcg_temp_new_i64();                                         \
    gen_load_gpr64(t0, rB(ctx->opcode));                                      \
    gen_helper_##name(cpu_gpr[rD(ctx->opcode)], t0);                          \
    tcg_temp_free_i64(t0);                                                    \
}
#define GEN_SPEFPUOP_CONV_64_32(name)                                         \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    TCGv_i64 t0 = tcg_temp_new_i64();                                         \
    gen_helper_##name(t0, cpu_gpr[rB(ctx->opcode)]);                          \
    gen_store_gpr64(rD(ctx->opcode), t0);                                     \
    tcg_temp_free_i64(t0);                                                    \
}
#define GEN_SPEFPUOP_CONV_64_64(name)                                         \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    TCGv_i64 t0 = tcg_temp_new_i64();                                         \
    gen_load_gpr64(t0, rB(ctx->opcode));                                      \
    gen_helper_##name(t0, t0);                                                \
    gen_store_gpr64(rD(ctx->opcode), t0);                                     \
    tcg_temp_free_i64(t0);                                                    \
}
#define GEN_SPEFPUOP_ARITH2_32_32(name)                                       \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        return;                                                               \
    }                                                                         \
    gen_helper_##name(cpu_gpr[rD(ctx->opcode)],                               \
                      cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);    \
}
#define GEN_SPEFPUOP_ARITH2_64_64(name)                                       \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    TCGv_i64 t0, t1;                                                          \
    if (unlikely(!ctx->spe_enabled)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        return;                                                               \
    }                                                                         \
    t0 = tcg_temp_new_i64();                                                  \
    t1 = tcg_temp_new_i64();                                                  \
    gen_load_gpr64(t0, rA(ctx->opcode));                                      \
    gen_load_gpr64(t1, rB(ctx->opcode));                                      \
    gen_helper_##name(t0, t0, t1);                                            \
    gen_store_gpr64(rD(ctx->opcode), t0);                                     \
    tcg_temp_free_i64(t0);                                                    \
    tcg_temp_free_i64(t1);                                                    \
}
#define GEN_SPEFPUOP_COMP_32(name)                                            \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    if (unlikely(!ctx->spe_enabled)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        return;                                                               \
    }                                                                         \
    gen_helper_##name(cpu_crf[crfD(ctx->opcode)],                             \
                      cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);    \
}
#define GEN_SPEFPUOP_COMP_64(name)                                            \
static always_inline void gen_##name (DisasContext *ctx)                      \
{                                                                             \
    TCGv_i64 t0, t1;                                                          \
    if (unlikely(!ctx->spe_enabled)) {                                        \
        GEN_EXCP_NO_AP(ctx);                                                  \
        return;                                                               \
    }                                                                         \
    t0 = tcg_temp_new_i64();                                                  \
    t1 = tcg_temp_new_i64();                                                  \
    gen_load_gpr64(t0, rA(ctx->opcode));                                      \
    gen_load_gpr64(t1, rB(ctx->opcode));                                      \
    gen_helper_##name(cpu_crf[crfD(ctx->opcode)], t0, t1);                    \
    tcg_temp_free_i64(t0);                                                    \
    tcg_temp_free_i64(t1);                                                    \
}
#endif
7133

7134 7135
/* Single precision floating-point vectors operations */
/* Arithmetic */
A
aurel32 已提交
7136 7137 7138 7139 7140 7141 7142 7143 7144 7145 7146 7147 7148 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7160 7161 7162 7163 7164 7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179
GEN_SPEFPUOP_ARITH2_64_64(evfsadd);
GEN_SPEFPUOP_ARITH2_64_64(evfssub);
GEN_SPEFPUOP_ARITH2_64_64(evfsmul);
GEN_SPEFPUOP_ARITH2_64_64(evfsdiv);
static always_inline void gen_evfsabs (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
        GEN_EXCP_NO_AP(ctx);
        return;
    }
#if defined(TARGET_PPC64)
    tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~0x8000000080000000LL);
#else
    tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~0x80000000);
    tcg_gen_andi_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], ~0x80000000);
#endif
}
static always_inline void gen_evfsnabs (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
        GEN_EXCP_NO_AP(ctx);
        return;
    }
#if defined(TARGET_PPC64)
    tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000080000000LL);
#else
    tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
    tcg_gen_ori_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000);
#endif
}
static always_inline void gen_evfsneg (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
        GEN_EXCP_NO_AP(ctx);
        return;
    }
#if defined(TARGET_PPC64)
    tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000080000000LL);
#else
    tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
    tcg_gen_xori_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000);
#endif
}

7180
/* Conversion */
A
aurel32 已提交
7181 7182 7183 7184 7185 7186 7187 7188 7189 7190 7191
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);

7192
/* Comparison */
A
aurel32 已提交
7193 7194 7195 7196 7197 7198
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);
7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212 7213 7214 7215 7216 7217

/* 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 已提交
7218 7219 7220 7221 7222 7223 7224 7225 7226 7227 7228 7229 7230 7231 7232 7233 7234 7235 7236 7237 7238 7239 7240 7241 7242 7243 7244 7245 7246
GEN_SPEFPUOP_ARITH2_32_32(efsadd);
GEN_SPEFPUOP_ARITH2_32_32(efssub);
GEN_SPEFPUOP_ARITH2_32_32(efsmul);
GEN_SPEFPUOP_ARITH2_32_32(efsdiv);
static always_inline void gen_efsabs (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
        GEN_EXCP_NO_AP(ctx);
        return;
    }
    tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], (target_long)~0x80000000LL);
}
static always_inline void gen_efsnabs (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
        GEN_EXCP_NO_AP(ctx);
        return;
    }
    tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
}
static always_inline void gen_efsneg (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
        GEN_EXCP_NO_AP(ctx);
        return;
    }
    tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x80000000);
}

7247
/* Conversion */
A
aurel32 已提交
7248 7249 7250 7251 7252 7253 7254 7255 7256 7257 7258 7259
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);

7260
/* Comparison */
A
aurel32 已提交
7261 7262 7263 7264 7265 7266
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);
7267 7268

/* Opcodes definitions */
7269
GEN_SPE(efsadd,         efssub,        0x00, 0x0B, 0x00000000, PPC_SPEFPU); //
7270 7271 7272 7273 7274 7275 7276 7277 7278
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); //
7279 7280
GEN_SPE(efsctuiz,       speundef,      0x0C, 0x0B, 0x00180000, PPC_SPEFPU); //
GEN_SPE(efsctsiz,       speundef,      0x0D, 0x0B, 0x00180000, PPC_SPEFPU); //
7281 7282 7283 7284 7285
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 已提交
7286 7287 7288 7289 7290 7291 7292 7293 7294 7295 7296 7297 7298 7299 7300 7301 7302 7303 7304 7305 7306 7307 7308 7309 7310 7311 7312 7313 7314 7315 7316 7317 7318 7319 7320 7321 7322 7323 7324 7325 7326
GEN_SPEFPUOP_ARITH2_64_64(efdadd);
GEN_SPEFPUOP_ARITH2_64_64(efdsub);
GEN_SPEFPUOP_ARITH2_64_64(efdmul);
GEN_SPEFPUOP_ARITH2_64_64(efddiv);
static always_inline void gen_efdabs (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
        GEN_EXCP_NO_AP(ctx);
        return;
    }
#if defined(TARGET_PPC64)
    tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], ~0x8000000000000000LL);
#else
    tcg_gen_andi_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], ~0x80000000);
#endif
}
static always_inline void gen_efdnabs (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
        GEN_EXCP_NO_AP(ctx);
        return;
    }
#if defined(TARGET_PPC64)
    tcg_gen_ori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000000000000LL);
#else
    tcg_gen_ori_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000);
#endif
}
static always_inline void gen_efdneg (DisasContext *ctx)
{
    if (unlikely(!ctx->spe_enabled)) {
        GEN_EXCP_NO_AP(ctx);
        return;
    }
#if defined(TARGET_PPC64)
    tcg_gen_xori_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], 0x8000000000000000LL);
#else
    tcg_gen_xori_tl(cpu_gprh[rA(ctx->opcode)], cpu_gprh[rA(ctx->opcode)], 0x80000000);
#endif
}

7327
/* Conversion */
A
aurel32 已提交
7328 7329 7330 7331 7332 7333 7334 7335 7336 7337 7338 7339 7340 7341 7342
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);
7343 7344

/* Comparison */
A
aurel32 已提交
7345 7346 7347 7348 7349 7350
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);
7351 7352 7353 7354 7355 7356 7357 7358 7359 7360 7361 7362 7363 7364 7365 7366 7367 7368 7369

/* 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 已提交
7370 7371 7372
/* End opcode list */
GEN_OPCODE_MARK(end);

7373
#include "translate_init.c"
7374
#include "helper_regs.h"
B
bellard 已提交
7375

7376
/*****************************************************************************/
7377
/* Misc PowerPC helpers */
7378 7379 7380
void cpu_dump_state (CPUState *env, FILE *f,
                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
                     int flags)
B
bellard 已提交
7381
{
7382 7383 7384
#define RGPL  4
#define RFPL  4

B
bellard 已提交
7385 7386
    int i;

J
j_mayer 已提交
7387
    cpu_fprintf(f, "NIP " ADDRX "   LR " ADDRX " CTR " ADDRX " XER %08x\n",
A
aurel32 已提交
7388
                env->nip, env->lr, env->ctr, env->xer);
7389 7390
    cpu_fprintf(f, "MSR " ADDRX " HID0 " ADDRX "  HF " ADDRX " idx %d\n",
                env->msr, env->spr[SPR_HID0], env->hflags, env->mmu_idx);
7391
#if !defined(NO_TIMER_DUMP)
J
j_mayer 已提交
7392
    cpu_fprintf(f, "TB %08x %08x "
7393 7394 7395 7396
#if !defined(CONFIG_USER_ONLY)
                "DECR %08x"
#endif
                "\n",
J
j_mayer 已提交
7397
                cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env)
7398 7399 7400 7401
#if !defined(CONFIG_USER_ONLY)
                , cpu_ppc_load_decr(env)
#endif
                );
J
j_mayer 已提交
7402
#endif
7403
    for (i = 0; i < 32; i++) {
7404 7405
        if ((i & (RGPL - 1)) == 0)
            cpu_fprintf(f, "GPR%02d", i);
7406
        cpu_fprintf(f, " " REGX, ppc_dump_gpr(env, i));
7407
        if ((i & (RGPL - 1)) == (RGPL - 1))
B
bellard 已提交
7408
            cpu_fprintf(f, "\n");
7409
    }
7410
    cpu_fprintf(f, "CR ");
7411
    for (i = 0; i < 8; i++)
B
bellard 已提交
7412 7413
        cpu_fprintf(f, "%01x", env->crf[i]);
    cpu_fprintf(f, "  [");
7414 7415 7416 7417 7418 7419 7420 7421
    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 已提交
7422
        cpu_fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' ');
7423
    }
7424
    cpu_fprintf(f, " ]             RES " ADDRX "\n", env->reserve);
7425 7426 7427
    for (i = 0; i < 32; i++) {
        if ((i & (RFPL - 1)) == 0)
            cpu_fprintf(f, "FPR%02d", i);
B
bellard 已提交
7428
        cpu_fprintf(f, " %016" PRIx64, *((uint64_t *)&env->fpr[i]));
7429
        if ((i & (RFPL - 1)) == (RFPL - 1))
B
bellard 已提交
7430
            cpu_fprintf(f, "\n");
B
bellard 已提交
7431
    }
7432
#if !defined(CONFIG_USER_ONLY)
7433
    cpu_fprintf(f, "SRR0 " ADDRX " SRR1 " ADDRX " SDR1 " ADDRX "\n",
7434
                env->spr[SPR_SRR0], env->spr[SPR_SRR1], env->sdr1);
7435
#endif
B
bellard 已提交
7436

7437 7438
#undef RGPL
#undef RFPL
B
bellard 已提交
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
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
}

7488
/*****************************************************************************/
7489 7490 7491
static always_inline void gen_intermediate_code_internal (CPUState *env,
                                                          TranslationBlock *tb,
                                                          int search_pc)
B
bellard 已提交
7492
{
7493
    DisasContext ctx, *ctxp = &ctx;
B
bellard 已提交
7494
    opc_handler_t **table, *handler;
B
bellard 已提交
7495
    target_ulong pc_start;
B
bellard 已提交
7496
    uint16_t *gen_opc_end;
7497
    int supervisor, little_endian;
7498
    CPUBreakpoint *bp;
B
bellard 已提交
7499
    int j, lj = -1;
P
pbrook 已提交
7500 7501
    int num_insns;
    int max_insns;
B
bellard 已提交
7502 7503 7504

    pc_start = tb->pc;
    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
7505 7506 7507
#if defined(OPTIMIZE_FPRF_UPDATE)
    gen_fprf_ptr = gen_fprf_buf;
#endif
B
bellard 已提交
7508
    ctx.nip = pc_start;
B
bellard 已提交
7509
    ctx.tb = tb;
7510
    ctx.exception = POWERPC_EXCP_NONE;
7511
    ctx.spr_cb = env->spr_cb;
7512 7513
    supervisor = env->mmu_idx;
#if !defined(CONFIG_USER_ONLY)
7514
    ctx.supervisor = supervisor;
7515
#endif
7516
    little_endian = env->hflags & (1 << MSR_LE) ? 1 : 0;
7517 7518
#if defined(TARGET_PPC64)
    ctx.sf_mode = msr_sf;
7519
    ctx.mem_idx = (supervisor << 2) | (msr_sf << 1) | little_endian;
7520
#else
7521
    ctx.mem_idx = (supervisor << 1) | little_endian;
7522
#endif
7523
    ctx.dcache_line_size = env->dcache_line_size;
B
bellard 已提交
7524
    ctx.fpu_enabled = msr_fp;
7525
    if ((env->flags & POWERPC_FLAG_SPE) && msr_spe)
7526 7527 7528
        ctx.spe_enabled = msr_spe;
    else
        ctx.spe_enabled = 0;
7529 7530 7531 7532
    if ((env->flags & POWERPC_FLAG_VRE) && msr_vr)
        ctx.altivec_enabled = msr_vr;
    else
        ctx.altivec_enabled = 0;
7533
    if ((env->flags & POWERPC_FLAG_SE) && msr_se)
7534
        ctx.singlestep_enabled = CPU_SINGLE_STEP;
7535
    else
7536
        ctx.singlestep_enabled = 0;
7537
    if ((env->flags & POWERPC_FLAG_BE) && msr_be)
7538 7539 7540
        ctx.singlestep_enabled |= CPU_BRANCH_STEP;
    if (unlikely(env->singlestep_enabled))
        ctx.singlestep_enabled |= GDBSTUB_SINGLE_STEP;
7541
#if defined (DO_SINGLE_STEP) && 0
7542 7543 7544
    /* Single step trace mode */
    msr_se = 1;
#endif
P
pbrook 已提交
7545 7546 7547 7548 7549 7550
    num_insns = 0;
    max_insns = tb->cflags & CF_COUNT_MASK;
    if (max_insns == 0)
        max_insns = CF_COUNT_MASK;

    gen_icount_start();
7551
    /* Set env in case of segfault during code fetch */
7552
    while (ctx.exception == POWERPC_EXCP_NONE && gen_opc_ptr < gen_opc_end) {
7553 7554
        if (unlikely(!TAILQ_EMPTY(&env->breakpoints))) {
            TAILQ_FOREACH(bp, &env->breakpoints, entry) {
7555
                if (bp->pc == ctx.nip) {
7556
                    gen_update_nip(&ctx, ctx.nip);
7557
                    gen_helper_raise_debug();
7558 7559 7560 7561
                    break;
                }
            }
        }
7562
        if (unlikely(search_pc)) {
B
bellard 已提交
7563 7564 7565 7566 7567
            j = gen_opc_ptr - gen_opc_buf;
            if (lj < j) {
                lj++;
                while (lj < j)
                    gen_opc_instr_start[lj++] = 0;
B
bellard 已提交
7568
                gen_opc_pc[lj] = ctx.nip;
B
bellard 已提交
7569
                gen_opc_instr_start[lj] = 1;
P
pbrook 已提交
7570
                gen_opc_icount[lj] = num_insns;
B
bellard 已提交
7571 7572
            }
        }
7573 7574
#if defined PPC_DEBUG_DISAS
        if (loglevel & CPU_LOG_TB_IN_ASM) {
B
bellard 已提交
7575
            fprintf(logfile, "----------------\n");
7576
            fprintf(logfile, "nip=" ADDRX " super=%d ir=%d\n",
7577
                    ctx.nip, supervisor, (int)msr_ir);
7578 7579
        }
#endif
P
pbrook 已提交
7580 7581
        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
            gen_io_start();
7582 7583 7584 7585
        if (unlikely(little_endian)) {
            ctx.opcode = bswap32(ldl_code(ctx.nip));
        } else {
            ctx.opcode = ldl_code(ctx.nip);
7586
        }
7587 7588
#if defined PPC_DEBUG_DISAS
        if (loglevel & CPU_LOG_TB_IN_ASM) {
7589
            fprintf(logfile, "translate opcode %08x (%02x %02x %02x) (%s)\n",
7590
                    ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode),
7591
                    opc3(ctx.opcode), little_endian ? "little" : "big");
B
bellard 已提交
7592 7593
        }
#endif
B
bellard 已提交
7594
        ctx.nip += 4;
7595
        table = env->opcodes;
P
pbrook 已提交
7596
        num_insns++;
B
bellard 已提交
7597 7598 7599 7600 7601 7602 7603 7604 7605 7606
        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 ? */
7607
        if (unlikely(handler->handler == &gen_invalid)) {
J
j_mayer 已提交
7608
            if (loglevel != 0) {
7609
                fprintf(logfile, "invalid/unsupported opcode: "
7610
                        "%02x - %02x - %02x (%08x) " ADDRX " %d\n",
7611
                        opc1(ctx.opcode), opc2(ctx.opcode),
7612
                        opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, (int)msr_ir);
B
bellard 已提交
7613 7614
            } else {
                printf("invalid/unsupported opcode: "
7615
                       "%02x - %02x - %02x (%08x) " ADDRX " %d\n",
B
bellard 已提交
7616
                       opc1(ctx.opcode), opc2(ctx.opcode),
7617
                       opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, (int)msr_ir);
B
bellard 已提交
7618
            }
7619 7620
        } else {
            if (unlikely((ctx.opcode & handler->inval) != 0)) {
J
j_mayer 已提交
7621
                if (loglevel != 0) {
B
bellard 已提交
7622
                    fprintf(logfile, "invalid bits: %08x for opcode: "
7623
                            "%02x - %02x - %02x (%08x) " ADDRX "\n",
B
bellard 已提交
7624 7625
                            ctx.opcode & handler->inval, opc1(ctx.opcode),
                            opc2(ctx.opcode), opc3(ctx.opcode),
B
bellard 已提交
7626
                            ctx.opcode, ctx.nip - 4);
7627 7628
                } else {
                    printf("invalid bits: %08x for opcode: "
7629
                           "%02x - %02x - %02x (%08x) " ADDRX "\n",
7630 7631
                           ctx.opcode & handler->inval, opc1(ctx.opcode),
                           opc2(ctx.opcode), opc3(ctx.opcode),
B
bellard 已提交
7632
                           ctx.opcode, ctx.nip - 4);
7633
                }
7634
                GEN_EXCP_INVAL(ctxp);
B
bellard 已提交
7635
                break;
B
bellard 已提交
7636 7637
            }
        }
B
bellard 已提交
7638
        (*(handler->handler))(&ctx);
7639 7640 7641
#if defined(DO_PPC_STATISTICS)
        handler->count++;
#endif
7642
        /* Check trace mode exceptions */
7643 7644 7645 7646 7647
        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)) {
7648
            GEN_EXCP(ctxp, POWERPC_EXCP_TRACE, 0);
7649
        } else if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) ||
P
pbrook 已提交
7650 7651
                            (env->singlestep_enabled) ||
                            num_insns >= max_insns)) {
7652 7653 7654
            /* if we reach a page boundary or are single stepping, stop
             * generation
             */
7655
            break;
7656
        }
7657 7658 7659 7660
#if defined (DO_SINGLE_STEP)
        break;
#endif
    }
P
pbrook 已提交
7661 7662
    if (tb->cflags & CF_LAST_IO)
        gen_io_end();
7663
    if (ctx.exception == POWERPC_EXCP_NONE) {
7664
        gen_goto_tb(&ctx, 0, ctx.nip);
7665
    } else if (ctx.exception != POWERPC_EXCP_BRANCH) {
7666 7667
        if (unlikely(env->singlestep_enabled)) {
            gen_update_nip(&ctx, ctx.nip);
7668
            gen_helper_raise_debug();
7669
        }
7670
        /* Generate the return instruction */
B
bellard 已提交
7671
        tcg_gen_exit_tb(0);
7672
    }
P
pbrook 已提交
7673
    gen_icount_end(tb, num_insns);
B
bellard 已提交
7674
    *gen_opc_ptr = INDEX_op_end;
7675
    if (unlikely(search_pc)) {
7676 7677 7678 7679 7680
        j = gen_opc_ptr - gen_opc_buf;
        lj++;
        while (lj <= j)
            gen_opc_instr_start[lj++] = 0;
    } else {
B
bellard 已提交
7681
        tb->size = ctx.nip - pc_start;
P
pbrook 已提交
7682
        tb->icount = num_insns;
7683
    }
7684
#if defined(DEBUG_DISAS)
7685
    if (loglevel & CPU_LOG_TB_CPU) {
7686
        fprintf(logfile, "---------------- excp: %04x\n", ctx.exception);
B
bellard 已提交
7687
        cpu_dump_state(env, logfile, fprintf, 0);
7688 7689
    }
    if (loglevel & CPU_LOG_TB_IN_ASM) {
7690
        int flags;
7691
        flags = env->bfd_mach;
7692
        flags |= little_endian << 16;
B
bellard 已提交
7693
        fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
7694
        target_disas(logfile, pc_start, ctx.nip - pc_start, flags);
B
bellard 已提交
7695
        fprintf(logfile, "\n");
7696
    }
B
bellard 已提交
7697 7698 7699
#endif
}

7700
void gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
B
bellard 已提交
7701
{
7702
    gen_intermediate_code_internal(env, tb, 0);
B
bellard 已提交
7703 7704
}

7705
void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
B
bellard 已提交
7706
{
7707
    gen_intermediate_code_internal(env, tb, 1);
B
bellard 已提交
7708
}
A
aurel32 已提交
7709 7710 7711 7712 7713 7714

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