translate.c 312.2 KB
Newer Older
B
bellard 已提交
1 2
/*
 *  ARM translation
3
 *
B
bellard 已提交
4
 *  Copyright (c) 2003 Fabrice Bellard
P
pbrook 已提交
5
 *  Copyright (c) 2005-2007 CodeSourcery
6
 *  Copyright (c) 2007 OpenedHand, Ltd.
B
bellard 已提交
7 8 9 10 11 12 13 14 15 16 17 18
 *
 * 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
19
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
B
bellard 已提交
20 21 22 23 24 25 26 27 28 29
 */
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>

#include "cpu.h"
#include "exec-all.h"
#include "disas.h"
B
bellard 已提交
30
#include "tcg-op.h"
31
#include "qemu-log.h"
P
pbrook 已提交
32

P
pbrook 已提交
33
#include "helpers.h"
P
pbrook 已提交
34
#define GEN_HELPER 1
P
pbrook 已提交
35
#include "helpers.h"
B
bellard 已提交
36

P
pbrook 已提交
37 38 39 40 41
#define ENABLE_ARCH_5J    0
#define ENABLE_ARCH_6     arm_feature(env, ARM_FEATURE_V6)
#define ENABLE_ARCH_6K   arm_feature(env, ARM_FEATURE_V6K)
#define ENABLE_ARCH_6T2   arm_feature(env, ARM_FEATURE_THUMB2)
#define ENABLE_ARCH_7     arm_feature(env, ARM_FEATURE_V7)
B
bellard 已提交
42

P
pbrook 已提交
43
#define ARCH(x) do { if (!ENABLE_ARCH_##x) goto illegal_op; } while(0)
B
bellard 已提交
44

B
bellard 已提交
45 46
/* internal defines */
typedef struct DisasContext {
B
bellard 已提交
47
    target_ulong pc;
B
bellard 已提交
48
    int is_jmp;
49 50 51 52
    /* Nonzero if this instruction has been conditionally skipped.  */
    int condjmp;
    /* The label that will be jumped to when the instruction is skipped.  */
    int condlabel;
P
pbrook 已提交
53 54 55
    /* Thumb-2 condtional execution bits.  */
    int condexec_mask;
    int condexec_cond;
B
bellard 已提交
56
    struct TranslationBlock *tb;
B
bellard 已提交
57
    int singlestep_enabled;
B
bellard 已提交
58
    int thumb;
B
bellard 已提交
59 60 61
#if !defined(CONFIG_USER_ONLY)
    int user;
#endif
B
bellard 已提交
62 63
} DisasContext;

B
bellard 已提交
64 65 66 67 68 69
#if defined(CONFIG_USER_ONLY)
#define IS_USER(s) 1
#else
#define IS_USER(s) (s->user)
#endif

P
pbrook 已提交
70 71 72 73
/* These instructions trap after executing, so defer them until after the
   conditional executions state has been updated.  */
#define DISAS_WFI 4
#define DISAS_SWI 5
B
bellard 已提交
74

P
pbrook 已提交
75
static TCGv_ptr cpu_env;
P
pbrook 已提交
76
/* We reuse the same 64-bit temporaries for efficiency.  */
P
pbrook 已提交
77
static TCGv_i64 cpu_V0, cpu_V1, cpu_M0;
78
static TCGv_i32 cpu_R[16];
P
Paul Brook 已提交
79 80 81 82 83 84 85
static TCGv_i32 cpu_exclusive_addr;
static TCGv_i32 cpu_exclusive_val;
static TCGv_i32 cpu_exclusive_high;
#ifdef CONFIG_USER_ONLY
static TCGv_i32 cpu_exclusive_test;
static TCGv_i32 cpu_exclusive_info;
#endif
P
pbrook 已提交
86

P
pbrook 已提交
87
/* FIXME:  These should be removed.  */
P
pbrook 已提交
88 89
static TCGv cpu_F0s, cpu_F1s;
static TCGv_i64 cpu_F0d, cpu_F1d;
P
pbrook 已提交
90

P
pbrook 已提交
91 92
#include "gen-icount.h"

93 94 95 96
static const char *regnames[] =
    { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
      "r8", "r9", "r10", "r11", "r12", "r13", "r14", "pc" };

P
pbrook 已提交
97 98 99
/* initialize TCG globals.  */
void arm_translate_init(void)
{
100 101
    int i;

P
pbrook 已提交
102 103
    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");

104 105 106 107 108
    for (i = 0; i < 16; i++) {
        cpu_R[i] = tcg_global_mem_new_i32(TCG_AREG0,
                                          offsetof(CPUState, regs[i]),
                                          regnames[i]);
    }
P
Paul Brook 已提交
109 110 111 112 113 114 115 116 117 118 119 120
    cpu_exclusive_addr = tcg_global_mem_new_i32(TCG_AREG0,
        offsetof(CPUState, exclusive_addr), "exclusive_addr");
    cpu_exclusive_val = tcg_global_mem_new_i32(TCG_AREG0,
        offsetof(CPUState, exclusive_val), "exclusive_val");
    cpu_exclusive_high = tcg_global_mem_new_i32(TCG_AREG0,
        offsetof(CPUState, exclusive_high), "exclusive_high");
#ifdef CONFIG_USER_ONLY
    cpu_exclusive_test = tcg_global_mem_new_i32(TCG_AREG0,
        offsetof(CPUState, exclusive_test), "exclusive_test");
    cpu_exclusive_info = tcg_global_mem_new_i32(TCG_AREG0,
        offsetof(CPUState, exclusive_info), "exclusive_info");
#endif
121

P
pbrook 已提交
122 123
#define GEN_HELPER 2
#include "helpers.h"
P
pbrook 已提交
124 125 126 127 128
}

static int num_temps;

/* Allocate a temporary variable.  */
P
pbrook 已提交
129
static TCGv_i32 new_tmp(void)
P
pbrook 已提交
130
{
131 132
    num_temps++;
    return tcg_temp_new_i32();
P
pbrook 已提交
133 134 135 136 137
}

/* Release a temporary variable.  */
static void dead_tmp(TCGv tmp)
{
138
    tcg_temp_free(tmp);
P
pbrook 已提交
139 140 141
    num_temps--;
}

P
pbrook 已提交
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
static inline TCGv load_cpu_offset(int offset)
{
    TCGv tmp = new_tmp();
    tcg_gen_ld_i32(tmp, cpu_env, offset);
    return tmp;
}

#define load_cpu_field(name) load_cpu_offset(offsetof(CPUState, name))

static inline void store_cpu_offset(TCGv var, int offset)
{
    tcg_gen_st_i32(var, cpu_env, offset);
    dead_tmp(var);
}

#define store_cpu_field(var, name) \
    store_cpu_offset(var, offsetof(CPUState, name))

P
pbrook 已提交
160 161 162 163 164 165 166 167 168 169 170 171
/* Set a variable to the value of a CPU register.  */
static void load_reg_var(DisasContext *s, TCGv var, int reg)
{
    if (reg == 15) {
        uint32_t addr;
        /* normaly, since we updated PC, we need only to add one insn */
        if (s->thumb)
            addr = (long)s->pc + 2;
        else
            addr = (long)s->pc + 4;
        tcg_gen_movi_i32(var, addr);
    } else {
172
        tcg_gen_mov_i32(var, cpu_R[reg]);
P
pbrook 已提交
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
    }
}

/* Create a new temporary and set it to the value of a CPU register.  */
static inline TCGv load_reg(DisasContext *s, int reg)
{
    TCGv tmp = new_tmp();
    load_reg_var(s, tmp, reg);
    return tmp;
}

/* Set a CPU register.  The source must be a temporary and will be
   marked as dead.  */
static void store_reg(DisasContext *s, int reg, TCGv var)
{
    if (reg == 15) {
        tcg_gen_andi_i32(var, var, ~1);
        s->is_jmp = DISAS_JUMP;
    }
192
    tcg_gen_mov_i32(cpu_R[reg], var);
P
pbrook 已提交
193 194 195 196
    dead_tmp(var);
}

/* Value extensions.  */
P
pbrook 已提交
197 198
#define gen_uxtb(var) tcg_gen_ext8u_i32(var, var)
#define gen_uxth(var) tcg_gen_ext16u_i32(var, var)
P
pbrook 已提交
199 200 201
#define gen_sxtb(var) tcg_gen_ext8s_i32(var, var)
#define gen_sxth(var) tcg_gen_ext16s_i32(var, var)

P
pbrook 已提交
202 203
#define gen_sxtb16(var) gen_helper_sxtb16(var, var)
#define gen_uxtb16(var) gen_helper_uxtb16(var, var)
P
pbrook 已提交
204

P
pbrook 已提交
205

206 207 208 209 210 211
static inline void gen_set_cpsr(TCGv var, uint32_t mask)
{
    TCGv tmp_mask = tcg_const_i32(mask);
    gen_helper_cpsr_write(var, tmp_mask);
    tcg_temp_free_i32(tmp_mask);
}
P
pbrook 已提交
212 213 214 215 216 217 218 219 220 221 222
/* Set NZCV flags from the high 4 bits of var.  */
#define gen_set_nzcv(var) gen_set_cpsr(var, CPSR_NZCV)

static void gen_exception(int excp)
{
    TCGv tmp = new_tmp();
    tcg_gen_movi_i32(tmp, excp);
    gen_helper_exception(tmp);
    dead_tmp(tmp);
}

P
pbrook 已提交
223 224 225 226
static void gen_smul_dual(TCGv a, TCGv b)
{
    TCGv tmp1 = new_tmp();
    TCGv tmp2 = new_tmp();
227 228
    tcg_gen_ext16s_i32(tmp1, a);
    tcg_gen_ext16s_i32(tmp2, b);
P
pbrook 已提交
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
    tcg_gen_mul_i32(tmp1, tmp1, tmp2);
    dead_tmp(tmp2);
    tcg_gen_sari_i32(a, a, 16);
    tcg_gen_sari_i32(b, b, 16);
    tcg_gen_mul_i32(b, b, a);
    tcg_gen_mov_i32(a, tmp1);
    dead_tmp(tmp1);
}

/* Byteswap each halfword.  */
static void gen_rev16(TCGv var)
{
    TCGv tmp = new_tmp();
    tcg_gen_shri_i32(tmp, var, 8);
    tcg_gen_andi_i32(tmp, tmp, 0x00ff00ff);
    tcg_gen_shli_i32(var, var, 8);
    tcg_gen_andi_i32(var, var, 0xff00ff00);
    tcg_gen_or_i32(var, var, tmp);
    dead_tmp(tmp);
}

/* Byteswap low halfword and sign extend.  */
static void gen_revsh(TCGv var)
{
    TCGv tmp = new_tmp();
    tcg_gen_shri_i32(tmp, var, 8);
    tcg_gen_andi_i32(tmp, tmp, 0x00ff);
    tcg_gen_shli_i32(var, var, 8);
    tcg_gen_ext8s_i32(var, var);
    tcg_gen_or_i32(var, var, tmp);
    dead_tmp(tmp);
}

/* Unsigned bitfield extract.  */
static void gen_ubfx(TCGv var, int shift, uint32_t mask)
{
    if (shift)
        tcg_gen_shri_i32(var, var, shift);
    tcg_gen_andi_i32(var, var, mask);
}

/* Signed bitfield extract.  */
static void gen_sbfx(TCGv var, int shift, int width)
{
    uint32_t signbit;

    if (shift)
        tcg_gen_sari_i32(var, var, shift);
    if (shift + width < 32) {
        signbit = 1u << (width - 1);
        tcg_gen_andi_i32(var, var, (1u << width) - 1);
        tcg_gen_xori_i32(var, var, signbit);
        tcg_gen_subi_i32(var, var, signbit);
    }
}

/* Bitfield insertion.  Insert val into base.  Clobbers base and val.  */
static void gen_bfi(TCGv dest, TCGv base, TCGv val, int shift, uint32_t mask)
{
    tcg_gen_andi_i32(val, val, mask);
P
pbrook 已提交
289 290
    tcg_gen_shli_i32(val, val, shift);
    tcg_gen_andi_i32(base, base, ~(mask << shift));
P
pbrook 已提交
291 292 293
    tcg_gen_or_i32(dest, base, val);
}

P
pbrook 已提交
294 295
/* Round the top 32 bits of a 64-bit value.  */
static void gen_roundqd(TCGv a, TCGv b)
P
pbrook 已提交
296
{
P
pbrook 已提交
297 298
    tcg_gen_shri_i32(a, a, 31);
    tcg_gen_add_i32(a, a, b);
P
pbrook 已提交
299 300
}

P
pbrook 已提交
301 302
/* FIXME: Most targets have native widening multiplication.
   It would be good to use that instead of a full wide multiply.  */
P
pbrook 已提交
303
/* 32x32->64 multiply.  Marks inputs as dead.  */
P
pbrook 已提交
304
static TCGv_i64 gen_mulu_i64_i32(TCGv a, TCGv b)
P
pbrook 已提交
305
{
P
pbrook 已提交
306 307
    TCGv_i64 tmp1 = tcg_temp_new_i64();
    TCGv_i64 tmp2 = tcg_temp_new_i64();
P
pbrook 已提交
308 309 310 311 312 313

    tcg_gen_extu_i32_i64(tmp1, a);
    dead_tmp(a);
    tcg_gen_extu_i32_i64(tmp2, b);
    dead_tmp(b);
    tcg_gen_mul_i64(tmp1, tmp1, tmp2);
314
    tcg_temp_free_i64(tmp2);
P
pbrook 已提交
315 316 317
    return tmp1;
}

P
pbrook 已提交
318
static TCGv_i64 gen_muls_i64_i32(TCGv a, TCGv b)
P
pbrook 已提交
319
{
P
pbrook 已提交
320 321
    TCGv_i64 tmp1 = tcg_temp_new_i64();
    TCGv_i64 tmp2 = tcg_temp_new_i64();
P
pbrook 已提交
322 323 324 325 326 327

    tcg_gen_ext_i32_i64(tmp1, a);
    dead_tmp(a);
    tcg_gen_ext_i32_i64(tmp2, b);
    dead_tmp(b);
    tcg_gen_mul_i64(tmp1, tmp1, tmp2);
328
    tcg_temp_free_i64(tmp2);
P
pbrook 已提交
329 330 331
    return tmp1;
}

P
pbrook 已提交
332
/* Signed 32x32->64 multiply.  */
P
pbrook 已提交
333
static void gen_imull(TCGv a, TCGv b)
P
pbrook 已提交
334
{
P
pbrook 已提交
335 336
    TCGv_i64 tmp1 = tcg_temp_new_i64();
    TCGv_i64 tmp2 = tcg_temp_new_i64();
P
pbrook 已提交
337

P
pbrook 已提交
338 339
    tcg_gen_ext_i32_i64(tmp1, a);
    tcg_gen_ext_i32_i64(tmp2, b);
P
pbrook 已提交
340
    tcg_gen_mul_i64(tmp1, tmp1, tmp2);
341
    tcg_temp_free_i64(tmp2);
P
pbrook 已提交
342
    tcg_gen_trunc_i64_i32(a, tmp1);
P
pbrook 已提交
343
    tcg_gen_shri_i64(tmp1, tmp1, 32);
P
pbrook 已提交
344
    tcg_gen_trunc_i64_i32(b, tmp1);
345
    tcg_temp_free_i64(tmp1);
P
pbrook 已提交
346 347
}

P
pbrook 已提交
348 349 350 351 352 353 354
/* Swap low and high halfwords.  */
static void gen_swap_half(TCGv var)
{
    TCGv tmp = new_tmp();
    tcg_gen_shri_i32(tmp, var, 16);
    tcg_gen_shli_i32(var, var, 16);
    tcg_gen_or_i32(var, var, tmp);
P
pbrook 已提交
355
    dead_tmp(tmp);
P
pbrook 已提交
356 357
}

P
pbrook 已提交
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
/* Dual 16-bit add.  Result placed in t0 and t1 is marked as dead.
    tmp = (t0 ^ t1) & 0x8000;
    t0 &= ~0x8000;
    t1 &= ~0x8000;
    t0 = (t0 + t1) ^ tmp;
 */

static void gen_add16(TCGv t0, TCGv t1)
{
    TCGv tmp = new_tmp();
    tcg_gen_xor_i32(tmp, t0, t1);
    tcg_gen_andi_i32(tmp, tmp, 0x8000);
    tcg_gen_andi_i32(t0, t0, ~0x8000);
    tcg_gen_andi_i32(t1, t1, ~0x8000);
    tcg_gen_add_i32(t0, t0, t1);
    tcg_gen_xor_i32(t0, t0, tmp);
    dead_tmp(tmp);
    dead_tmp(t1);
}

P
pbrook 已提交
378 379
#define gen_set_CF(var) tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, CF))

P
pbrook 已提交
380 381 382 383 384
/* Set CF to the top bit of var.  */
static void gen_set_CF_bit31(TCGv var)
{
    TCGv tmp = new_tmp();
    tcg_gen_shri_i32(tmp, var, 31);
385
    gen_set_CF(tmp);
P
pbrook 已提交
386 387 388 389 390 391
    dead_tmp(tmp);
}

/* Set N and Z flags from var.  */
static inline void gen_logic_CC(TCGv var)
{
P
pbrook 已提交
392 393
    tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, NF));
    tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, ZF));
P
pbrook 已提交
394 395 396
}

/* T0 += T1 + CF.  */
397
static void gen_adc(TCGv t0, TCGv t1)
P
pbrook 已提交
398
{
P
pbrook 已提交
399
    TCGv tmp;
400
    tcg_gen_add_i32(t0, t0, t1);
P
pbrook 已提交
401
    tmp = load_cpu_field(CF);
402
    tcg_gen_add_i32(t0, t0, tmp);
P
pbrook 已提交
403 404 405
    dead_tmp(tmp);
}

406 407 408 409 410 411 412 413 414 415
/* dest = T0 + T1 + CF. */
static void gen_add_carry(TCGv dest, TCGv t0, TCGv t1)
{
    TCGv tmp;
    tcg_gen_add_i32(dest, t0, t1);
    tmp = load_cpu_field(CF);
    tcg_gen_add_i32(dest, dest, tmp);
    dead_tmp(tmp);
}

P
pbrook 已提交
416 417 418
/* dest = T0 - T1 + CF - 1.  */
static void gen_sub_carry(TCGv dest, TCGv t0, TCGv t1)
{
P
pbrook 已提交
419
    TCGv tmp;
P
pbrook 已提交
420
    tcg_gen_sub_i32(dest, t0, t1);
P
pbrook 已提交
421
    tmp = load_cpu_field(CF);
P
pbrook 已提交
422 423 424 425 426
    tcg_gen_add_i32(dest, dest, tmp);
    tcg_gen_subi_i32(dest, dest, 1);
    dead_tmp(tmp);
}

P
pbrook 已提交
427 428 429
/* FIXME:  Implement this natively.  */
#define tcg_gen_abs_i32(t0, t1) gen_helper_abs(t0, t1)

P
pbrook 已提交
430
static void shifter_out_im(TCGv var, int shift)
P
pbrook 已提交
431
{
P
pbrook 已提交
432 433 434
    TCGv tmp = new_tmp();
    if (shift == 0) {
        tcg_gen_andi_i32(tmp, var, 1);
P
pbrook 已提交
435
    } else {
P
pbrook 已提交
436
        tcg_gen_shri_i32(tmp, var, shift);
437
        if (shift != 31)
P
pbrook 已提交
438 439 440 441 442
            tcg_gen_andi_i32(tmp, tmp, 1);
    }
    gen_set_CF(tmp);
    dead_tmp(tmp);
}
P
pbrook 已提交
443

P
pbrook 已提交
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480
/* Shift by immediate.  Includes special handling for shift == 0.  */
static inline void gen_arm_shift_im(TCGv var, int shiftop, int shift, int flags)
{
    switch (shiftop) {
    case 0: /* LSL */
        if (shift != 0) {
            if (flags)
                shifter_out_im(var, 32 - shift);
            tcg_gen_shli_i32(var, var, shift);
        }
        break;
    case 1: /* LSR */
        if (shift == 0) {
            if (flags) {
                tcg_gen_shri_i32(var, var, 31);
                gen_set_CF(var);
            }
            tcg_gen_movi_i32(var, 0);
        } else {
            if (flags)
                shifter_out_im(var, shift - 1);
            tcg_gen_shri_i32(var, var, shift);
        }
        break;
    case 2: /* ASR */
        if (shift == 0)
            shift = 32;
        if (flags)
            shifter_out_im(var, shift - 1);
        if (shift == 32)
          shift = 31;
        tcg_gen_sari_i32(var, var, shift);
        break;
    case 3: /* ROR/RRX */
        if (shift != 0) {
            if (flags)
                shifter_out_im(var, shift - 1);
481
            tcg_gen_rotri_i32(var, var, shift); break;
P
pbrook 已提交
482
        } else {
P
pbrook 已提交
483
            TCGv tmp = load_cpu_field(CF);
P
pbrook 已提交
484 485 486
            if (flags)
                shifter_out_im(var, 0);
            tcg_gen_shri_i32(var, var, 1);
P
pbrook 已提交
487 488 489 490 491 492 493
            tcg_gen_shli_i32(tmp, tmp, 31);
            tcg_gen_or_i32(var, var, tmp);
            dead_tmp(tmp);
        }
    }
};

P
pbrook 已提交
494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
static inline void gen_arm_shift_reg(TCGv var, int shiftop,
                                     TCGv shift, int flags)
{
    if (flags) {
        switch (shiftop) {
        case 0: gen_helper_shl_cc(var, var, shift); break;
        case 1: gen_helper_shr_cc(var, var, shift); break;
        case 2: gen_helper_sar_cc(var, var, shift); break;
        case 3: gen_helper_ror_cc(var, var, shift); break;
        }
    } else {
        switch (shiftop) {
        case 0: gen_helper_shl(var, var, shift); break;
        case 1: gen_helper_shr(var, var, shift); break;
        case 2: gen_helper_sar(var, var, shift); break;
509 510
        case 3: tcg_gen_andi_i32(shift, shift, 0x1f);
                tcg_gen_rotr_i32(var, var, shift); break;
P
pbrook 已提交
511 512 513 514 515
        }
    }
    dead_tmp(shift);
}

P
pbrook 已提交
516 517 518 519 520 521 522 523 524
#define PAS_OP(pfx) \
    switch (op2) {  \
    case 0: gen_pas_helper(glue(pfx,add16)); break; \
    case 1: gen_pas_helper(glue(pfx,addsubx)); break; \
    case 2: gen_pas_helper(glue(pfx,subaddx)); break; \
    case 3: gen_pas_helper(glue(pfx,sub16)); break; \
    case 4: gen_pas_helper(glue(pfx,add8)); break; \
    case 7: gen_pas_helper(glue(pfx,sub8)); break; \
    }
P
pbrook 已提交
525
static void gen_arm_parallel_addsub(int op1, int op2, TCGv a, TCGv b)
P
pbrook 已提交
526
{
P
pbrook 已提交
527
    TCGv_ptr tmp;
P
pbrook 已提交
528 529 530 531

    switch (op1) {
#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp)
    case 1:
P
pbrook 已提交
532
        tmp = tcg_temp_new_ptr();
P
pbrook 已提交
533 534
        tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
        PAS_OP(s)
535
        tcg_temp_free_ptr(tmp);
P
pbrook 已提交
536 537
        break;
    case 5:
P
pbrook 已提交
538
        tmp = tcg_temp_new_ptr();
P
pbrook 已提交
539 540
        tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
        PAS_OP(u)
541
        tcg_temp_free_ptr(tmp);
P
pbrook 已提交
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559
        break;
#undef gen_pas_helper
#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b)
    case 2:
        PAS_OP(q);
        break;
    case 3:
        PAS_OP(sh);
        break;
    case 6:
        PAS_OP(uq);
        break;
    case 7:
        PAS_OP(uh);
        break;
#undef gen_pas_helper
    }
}
P
pbrook 已提交
560 561
#undef PAS_OP

P
pbrook 已提交
562 563 564 565 566 567 568 569 570 571
/* For unknown reasons Arm and Thumb-2 use arbitrarily different encodings.  */
#define PAS_OP(pfx) \
    switch (op2) {  \
    case 0: gen_pas_helper(glue(pfx,add8)); break; \
    case 1: gen_pas_helper(glue(pfx,add16)); break; \
    case 2: gen_pas_helper(glue(pfx,addsubx)); break; \
    case 4: gen_pas_helper(glue(pfx,sub8)); break; \
    case 5: gen_pas_helper(glue(pfx,sub16)); break; \
    case 6: gen_pas_helper(glue(pfx,subaddx)); break; \
    }
P
pbrook 已提交
572
static void gen_thumb2_parallel_addsub(int op1, int op2, TCGv a, TCGv b)
P
pbrook 已提交
573
{
P
pbrook 已提交
574
    TCGv_ptr tmp;
P
pbrook 已提交
575 576 577 578

    switch (op1) {
#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp)
    case 0:
P
pbrook 已提交
579
        tmp = tcg_temp_new_ptr();
P
pbrook 已提交
580 581
        tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
        PAS_OP(s)
582
        tcg_temp_free_ptr(tmp);
P
pbrook 已提交
583 584
        break;
    case 4:
P
pbrook 已提交
585
        tmp = tcg_temp_new_ptr();
P
pbrook 已提交
586 587
        tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
        PAS_OP(u)
588
        tcg_temp_free_ptr(tmp);
P
pbrook 已提交
589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606
        break;
#undef gen_pas_helper
#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b)
    case 1:
        PAS_OP(q);
        break;
    case 2:
        PAS_OP(sh);
        break;
    case 5:
        PAS_OP(uq);
        break;
    case 6:
        PAS_OP(uh);
        break;
#undef gen_pas_helper
    }
}
P
pbrook 已提交
607 608
#undef PAS_OP

P
pbrook 已提交
609 610 611 612 613 614 615 616
static void gen_test_cc(int cc, int label)
{
    TCGv tmp;
    TCGv tmp2;
    int inv;

    switch (cc) {
    case 0: /* eq: Z */
P
pbrook 已提交
617
        tmp = load_cpu_field(ZF);
P
pbrook 已提交
618
        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
P
pbrook 已提交
619 620
        break;
    case 1: /* ne: !Z */
P
pbrook 已提交
621
        tmp = load_cpu_field(ZF);
P
pbrook 已提交
622
        tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label);
P
pbrook 已提交
623 624 625
        break;
    case 2: /* cs: C */
        tmp = load_cpu_field(CF);
P
pbrook 已提交
626
        tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label);
P
pbrook 已提交
627 628 629
        break;
    case 3: /* cc: !C */
        tmp = load_cpu_field(CF);
P
pbrook 已提交
630
        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
P
pbrook 已提交
631 632
        break;
    case 4: /* mi: N */
P
pbrook 已提交
633
        tmp = load_cpu_field(NF);
P
pbrook 已提交
634
        tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
P
pbrook 已提交
635 636
        break;
    case 5: /* pl: !N */
P
pbrook 已提交
637
        tmp = load_cpu_field(NF);
P
pbrook 已提交
638
        tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
P
pbrook 已提交
639 640 641
        break;
    case 6: /* vs: V */
        tmp = load_cpu_field(VF);
P
pbrook 已提交
642
        tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
P
pbrook 已提交
643 644 645
        break;
    case 7: /* vc: !V */
        tmp = load_cpu_field(VF);
P
pbrook 已提交
646
        tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
P
pbrook 已提交
647 648 649 650
        break;
    case 8: /* hi: C && !Z */
        inv = gen_new_label();
        tmp = load_cpu_field(CF);
P
pbrook 已提交
651
        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv);
P
pbrook 已提交
652
        dead_tmp(tmp);
P
pbrook 已提交
653
        tmp = load_cpu_field(ZF);
P
pbrook 已提交
654
        tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label);
P
pbrook 已提交
655 656 657 658
        gen_set_label(inv);
        break;
    case 9: /* ls: !C || Z */
        tmp = load_cpu_field(CF);
P
pbrook 已提交
659
        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
P
pbrook 已提交
660
        dead_tmp(tmp);
P
pbrook 已提交
661
        tmp = load_cpu_field(ZF);
P
pbrook 已提交
662
        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
P
pbrook 已提交
663 664 665
        break;
    case 10: /* ge: N == V -> N ^ V == 0 */
        tmp = load_cpu_field(VF);
P
pbrook 已提交
666
        tmp2 = load_cpu_field(NF);
P
pbrook 已提交
667 668
        tcg_gen_xor_i32(tmp, tmp, tmp2);
        dead_tmp(tmp2);
P
pbrook 已提交
669
        tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
P
pbrook 已提交
670 671 672
        break;
    case 11: /* lt: N != V -> N ^ V != 0 */
        tmp = load_cpu_field(VF);
P
pbrook 已提交
673
        tmp2 = load_cpu_field(NF);
P
pbrook 已提交
674 675
        tcg_gen_xor_i32(tmp, tmp, tmp2);
        dead_tmp(tmp2);
P
pbrook 已提交
676
        tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
P
pbrook 已提交
677 678 679
        break;
    case 12: /* gt: !Z && N == V */
        inv = gen_new_label();
P
pbrook 已提交
680
        tmp = load_cpu_field(ZF);
P
pbrook 已提交
681
        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv);
P
pbrook 已提交
682 683
        dead_tmp(tmp);
        tmp = load_cpu_field(VF);
P
pbrook 已提交
684
        tmp2 = load_cpu_field(NF);
P
pbrook 已提交
685 686
        tcg_gen_xor_i32(tmp, tmp, tmp2);
        dead_tmp(tmp2);
P
pbrook 已提交
687
        tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
P
pbrook 已提交
688 689 690
        gen_set_label(inv);
        break;
    case 13: /* le: Z || N != V */
P
pbrook 已提交
691
        tmp = load_cpu_field(ZF);
P
pbrook 已提交
692
        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
P
pbrook 已提交
693 694
        dead_tmp(tmp);
        tmp = load_cpu_field(VF);
P
pbrook 已提交
695
        tmp2 = load_cpu_field(NF);
P
pbrook 已提交
696 697
        tcg_gen_xor_i32(tmp, tmp, tmp2);
        dead_tmp(tmp2);
P
pbrook 已提交
698
        tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
P
pbrook 已提交
699 700 701 702 703 704 705
        break;
    default:
        fprintf(stderr, "Bad condition code 0x%x\n", cc);
        abort();
    }
    dead_tmp(tmp);
}
B
bellard 已提交
706

707
static const uint8_t table_logic_cc[16] = {
B
bellard 已提交
708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724
    1, /* and */
    1, /* xor */
    0, /* sub */
    0, /* rsb */
    0, /* add */
    0, /* adc */
    0, /* sbc */
    0, /* rsc */
    1, /* andl */
    1, /* xorl */
    0, /* cmp */
    0, /* cmn */
    1, /* orr */
    1, /* mov */
    1, /* bic */
    1, /* mvn */
};
725

P
pbrook 已提交
726 727
/* Set PC and Thumb state from an immediate address.  */
static inline void gen_bx_im(DisasContext *s, uint32_t addr)
B
bellard 已提交
728
{
P
pbrook 已提交
729
    TCGv tmp;
B
bellard 已提交
730

P
pbrook 已提交
731
    s->is_jmp = DISAS_UPDATE;
P
pbrook 已提交
732
    if (s->thumb != (addr & 1)) {
733
        tmp = new_tmp();
P
pbrook 已提交
734 735
        tcg_gen_movi_i32(tmp, addr & 1);
        tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, thumb));
736
        dead_tmp(tmp);
P
pbrook 已提交
737
    }
738
    tcg_gen_movi_i32(cpu_R[15], addr & ~1);
P
pbrook 已提交
739 740 741 742 743 744
}

/* Set PC and Thumb state from var.  var is marked as dead.  */
static inline void gen_bx(DisasContext *s, TCGv var)
{
    s->is_jmp = DISAS_UPDATE;
745 746 747
    tcg_gen_andi_i32(cpu_R[15], var, ~1);
    tcg_gen_andi_i32(var, var, 1);
    store_cpu_field(var, thumb);
P
pbrook 已提交
748 749
}

750 751 752 753 754 755 756 757 758 759 760 761 762
/* Variant of store_reg which uses branch&exchange logic when storing
   to r15 in ARM architecture v7 and above. The source must be a temporary
   and will be marked as dead. */
static inline void store_reg_bx(CPUState *env, DisasContext *s,
                                int reg, TCGv var)
{
    if (reg == 15 && ENABLE_ARCH_7) {
        gen_bx(s, var);
    } else {
        store_reg(s, reg, var);
    }
}

P
pbrook 已提交
763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792
static inline TCGv gen_ld8s(TCGv addr, int index)
{
    TCGv tmp = new_tmp();
    tcg_gen_qemu_ld8s(tmp, addr, index);
    return tmp;
}
static inline TCGv gen_ld8u(TCGv addr, int index)
{
    TCGv tmp = new_tmp();
    tcg_gen_qemu_ld8u(tmp, addr, index);
    return tmp;
}
static inline TCGv gen_ld16s(TCGv addr, int index)
{
    TCGv tmp = new_tmp();
    tcg_gen_qemu_ld16s(tmp, addr, index);
    return tmp;
}
static inline TCGv gen_ld16u(TCGv addr, int index)
{
    TCGv tmp = new_tmp();
    tcg_gen_qemu_ld16u(tmp, addr, index);
    return tmp;
}
static inline TCGv gen_ld32(TCGv addr, int index)
{
    TCGv tmp = new_tmp();
    tcg_gen_qemu_ld32u(tmp, addr, index);
    return tmp;
}
793 794 795 796 797 798
static inline TCGv_i64 gen_ld64(TCGv addr, int index)
{
    TCGv_i64 tmp = tcg_temp_new_i64();
    tcg_gen_qemu_ld64(tmp, addr, index);
    return tmp;
}
P
pbrook 已提交
799 800 801 802 803 804 805 806 807 808 809 810 811 812 813
static inline void gen_st8(TCGv val, TCGv addr, int index)
{
    tcg_gen_qemu_st8(val, addr, index);
    dead_tmp(val);
}
static inline void gen_st16(TCGv val, TCGv addr, int index)
{
    tcg_gen_qemu_st16(val, addr, index);
    dead_tmp(val);
}
static inline void gen_st32(TCGv val, TCGv addr, int index)
{
    tcg_gen_qemu_st32(val, addr, index);
    dead_tmp(val);
}
814 815 816 817 818
static inline void gen_st64(TCGv_i64 val, TCGv addr, int index)
{
    tcg_gen_qemu_st64(val, addr, index);
    tcg_temp_free_i64(val);
}
B
bellard 已提交
819

P
pbrook 已提交
820 821
static inline void gen_set_pc_im(uint32_t val)
{
822
    tcg_gen_movi_i32(cpu_R[15], val);
P
pbrook 已提交
823 824
}

B
bellard 已提交
825 826 827
/* Force a TB lookup after an instruction that changes the CPU state.  */
static inline void gen_lookup_tb(DisasContext *s)
{
828
    tcg_gen_movi_i32(cpu_R[15], s->pc & ~1);
B
bellard 已提交
829 830 831
    s->is_jmp = DISAS_UPDATE;
}

P
pbrook 已提交
832 833
static inline void gen_add_data_offset(DisasContext *s, unsigned int insn,
                                       TCGv var)
B
bellard 已提交
834
{
B
bellard 已提交
835
    int val, rm, shift, shiftop;
P
pbrook 已提交
836
    TCGv offset;
B
bellard 已提交
837 838 839 840 841 842

    if (!(insn & (1 << 25))) {
        /* immediate */
        val = insn & 0xfff;
        if (!(insn & (1 << 23)))
            val = -val;
B
bellard 已提交
843
        if (val != 0)
P
pbrook 已提交
844
            tcg_gen_addi_i32(var, var, val);
B
bellard 已提交
845 846 847 848
    } else {
        /* shift/register */
        rm = (insn) & 0xf;
        shift = (insn >> 7) & 0x1f;
B
bellard 已提交
849
        shiftop = (insn >> 5) & 3;
P
pbrook 已提交
850
        offset = load_reg(s, rm);
P
pbrook 已提交
851
        gen_arm_shift_im(offset, shiftop, shift, 0);
B
bellard 已提交
852
        if (!(insn & (1 << 23)))
P
pbrook 已提交
853
            tcg_gen_sub_i32(var, var, offset);
B
bellard 已提交
854
        else
P
pbrook 已提交
855
            tcg_gen_add_i32(var, var, offset);
P
pbrook 已提交
856
        dead_tmp(offset);
B
bellard 已提交
857 858 859
    }
}

P
pbrook 已提交
860
static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn,
P
pbrook 已提交
861
                                        int extra, TCGv var)
B
bellard 已提交
862 863
{
    int val, rm;
P
pbrook 已提交
864
    TCGv offset;
865

B
bellard 已提交
866 867 868 869 870
    if (insn & (1 << 22)) {
        /* immediate */
        val = (insn & 0xf) | ((insn >> 4) & 0xf0);
        if (!(insn & (1 << 23)))
            val = -val;
871
        val += extra;
B
bellard 已提交
872
        if (val != 0)
P
pbrook 已提交
873
            tcg_gen_addi_i32(var, var, val);
B
bellard 已提交
874 875
    } else {
        /* register */
P
pbrook 已提交
876
        if (extra)
P
pbrook 已提交
877
            tcg_gen_addi_i32(var, var, extra);
B
bellard 已提交
878
        rm = (insn) & 0xf;
P
pbrook 已提交
879
        offset = load_reg(s, rm);
B
bellard 已提交
880
        if (!(insn & (1 << 23)))
P
pbrook 已提交
881
            tcg_gen_sub_i32(var, var, offset);
B
bellard 已提交
882
        else
P
pbrook 已提交
883
            tcg_gen_add_i32(var, var, offset);
P
pbrook 已提交
884
        dead_tmp(offset);
B
bellard 已提交
885 886 887
    }
}

P
pbrook 已提交
888 889 890 891 892 893 894
#define VFP_OP2(name)                                                 \
static inline void gen_vfp_##name(int dp)                             \
{                                                                     \
    if (dp)                                                           \
        gen_helper_vfp_##name##d(cpu_F0d, cpu_F0d, cpu_F1d, cpu_env); \
    else                                                              \
        gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, cpu_F1s, cpu_env); \
B
bellard 已提交
895 896
}

P
pbrook 已提交
897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946
VFP_OP2(add)
VFP_OP2(sub)
VFP_OP2(mul)
VFP_OP2(div)

#undef VFP_OP2

static inline void gen_vfp_abs(int dp)
{
    if (dp)
        gen_helper_vfp_absd(cpu_F0d, cpu_F0d);
    else
        gen_helper_vfp_abss(cpu_F0s, cpu_F0s);
}

static inline void gen_vfp_neg(int dp)
{
    if (dp)
        gen_helper_vfp_negd(cpu_F0d, cpu_F0d);
    else
        gen_helper_vfp_negs(cpu_F0s, cpu_F0s);
}

static inline void gen_vfp_sqrt(int dp)
{
    if (dp)
        gen_helper_vfp_sqrtd(cpu_F0d, cpu_F0d, cpu_env);
    else
        gen_helper_vfp_sqrts(cpu_F0s, cpu_F0s, cpu_env);
}

static inline void gen_vfp_cmp(int dp)
{
    if (dp)
        gen_helper_vfp_cmpd(cpu_F0d, cpu_F1d, cpu_env);
    else
        gen_helper_vfp_cmps(cpu_F0s, cpu_F1s, cpu_env);
}

static inline void gen_vfp_cmpe(int dp)
{
    if (dp)
        gen_helper_vfp_cmped(cpu_F0d, cpu_F1d, cpu_env);
    else
        gen_helper_vfp_cmpes(cpu_F0s, cpu_F1s, cpu_env);
}

static inline void gen_vfp_F1_ld0(int dp)
{
    if (dp)
B
balrog 已提交
947
        tcg_gen_movi_i64(cpu_F1d, 0);
P
pbrook 已提交
948
    else
B
balrog 已提交
949
        tcg_gen_movi_i32(cpu_F1s, 0);
P
pbrook 已提交
950 951 952 953 954 955 956 957 958 959 960 961 962
}

static inline void gen_vfp_uito(int dp)
{
    if (dp)
        gen_helper_vfp_uitod(cpu_F0d, cpu_F0s, cpu_env);
    else
        gen_helper_vfp_uitos(cpu_F0s, cpu_F0s, cpu_env);
}

static inline void gen_vfp_sito(int dp)
{
    if (dp)
963
        gen_helper_vfp_sitod(cpu_F0d, cpu_F0s, cpu_env);
P
pbrook 已提交
964
    else
965
        gen_helper_vfp_sitos(cpu_F0s, cpu_F0s, cpu_env);
P
pbrook 已提交
966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992
}

static inline void gen_vfp_toui(int dp)
{
    if (dp)
        gen_helper_vfp_touid(cpu_F0s, cpu_F0d, cpu_env);
    else
        gen_helper_vfp_touis(cpu_F0s, cpu_F0s, cpu_env);
}

static inline void gen_vfp_touiz(int dp)
{
    if (dp)
        gen_helper_vfp_touizd(cpu_F0s, cpu_F0d, cpu_env);
    else
        gen_helper_vfp_touizs(cpu_F0s, cpu_F0s, cpu_env);
}

static inline void gen_vfp_tosi(int dp)
{
    if (dp)
        gen_helper_vfp_tosid(cpu_F0s, cpu_F0d, cpu_env);
    else
        gen_helper_vfp_tosis(cpu_F0s, cpu_F0s, cpu_env);
}

static inline void gen_vfp_tosiz(int dp)
P
pbrook 已提交
993 994
{
    if (dp)
P
pbrook 已提交
995
        gen_helper_vfp_tosizd(cpu_F0s, cpu_F0d, cpu_env);
P
pbrook 已提交
996
    else
P
pbrook 已提交
997 998 999 1000 1001 1002
        gen_helper_vfp_tosizs(cpu_F0s, cpu_F0s, cpu_env);
}

#define VFP_GEN_FIX(name) \
static inline void gen_vfp_##name(int dp, int shift) \
{ \
1003
    TCGv tmp_shift = tcg_const_i32(shift); \
P
pbrook 已提交
1004
    if (dp) \
1005
        gen_helper_vfp_##name##d(cpu_F0d, cpu_F0d, tmp_shift, cpu_env);\
P
pbrook 已提交
1006
    else \
1007 1008
        gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, tmp_shift, cpu_env);\
    tcg_temp_free_i32(tmp_shift); \
P
pbrook 已提交
1009
}
P
pbrook 已提交
1010 1011 1012 1013 1014 1015 1016 1017 1018
VFP_GEN_FIX(tosh)
VFP_GEN_FIX(tosl)
VFP_GEN_FIX(touh)
VFP_GEN_FIX(toul)
VFP_GEN_FIX(shto)
VFP_GEN_FIX(slto)
VFP_GEN_FIX(uhto)
VFP_GEN_FIX(ulto)
#undef VFP_GEN_FIX
P
pbrook 已提交
1019

1020
static inline void gen_vfp_ld(DisasContext *s, int dp, TCGv addr)
B
bellard 已提交
1021 1022
{
    if (dp)
1023
        tcg_gen_qemu_ld64(cpu_F0d, addr, IS_USER(s));
B
bellard 已提交
1024
    else
1025
        tcg_gen_qemu_ld32u(cpu_F0s, addr, IS_USER(s));
B
bellard 已提交
1026 1027
}

1028
static inline void gen_vfp_st(DisasContext *s, int dp, TCGv addr)
B
bellard 已提交
1029 1030
{
    if (dp)
1031
        tcg_gen_qemu_st64(cpu_F0d, addr, IS_USER(s));
B
bellard 已提交
1032
    else
1033
        tcg_gen_qemu_st32(cpu_F0s, addr, IS_USER(s));
B
bellard 已提交
1034 1035
}

B
bellard 已提交
1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048
static inline long
vfp_reg_offset (int dp, int reg)
{
    if (dp)
        return offsetof(CPUARMState, vfp.regs[reg]);
    else if (reg & 1) {
        return offsetof(CPUARMState, vfp.regs[reg >> 1])
          + offsetof(CPU_DoubleU, l.upper);
    } else {
        return offsetof(CPUARMState, vfp.regs[reg >> 1])
          + offsetof(CPU_DoubleU, l.lower);
    }
}
P
pbrook 已提交
1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059

/* Return the offset of a 32-bit piece of a NEON register.
   zero is the least significant end of the register.  */
static inline long
neon_reg_offset (int reg, int n)
{
    int sreg;
    sreg = reg * 2 + n;
    return vfp_reg_offset(0, sreg);
}

P
pbrook 已提交
1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072
static TCGv neon_load_reg(int reg, int pass)
{
    TCGv tmp = new_tmp();
    tcg_gen_ld_i32(tmp, cpu_env, neon_reg_offset(reg, pass));
    return tmp;
}

static void neon_store_reg(int reg, int pass, TCGv var)
{
    tcg_gen_st_i32(var, cpu_env, neon_reg_offset(reg, pass));
    dead_tmp(var);
}

P
pbrook 已提交
1073
static inline void neon_load_reg64(TCGv_i64 var, int reg)
P
pbrook 已提交
1074 1075 1076 1077
{
    tcg_gen_ld_i64(var, cpu_env, vfp_reg_offset(1, reg));
}

P
pbrook 已提交
1078
static inline void neon_store_reg64(TCGv_i64 var, int reg)
P
pbrook 已提交
1079 1080 1081 1082
{
    tcg_gen_st_i64(var, cpu_env, vfp_reg_offset(1, reg));
}

P
pbrook 已提交
1083 1084 1085 1086 1087
#define tcg_gen_ld_f32 tcg_gen_ld_i32
#define tcg_gen_ld_f64 tcg_gen_ld_i64
#define tcg_gen_st_f32 tcg_gen_st_i32
#define tcg_gen_st_f64 tcg_gen_st_i64

B
bellard 已提交
1088 1089 1090
static inline void gen_mov_F0_vreg(int dp, int reg)
{
    if (dp)
P
pbrook 已提交
1091
        tcg_gen_ld_f64(cpu_F0d, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1092
    else
P
pbrook 已提交
1093
        tcg_gen_ld_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1094 1095 1096 1097 1098
}

static inline void gen_mov_F1_vreg(int dp, int reg)
{
    if (dp)
P
pbrook 已提交
1099
        tcg_gen_ld_f64(cpu_F1d, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1100
    else
P
pbrook 已提交
1101
        tcg_gen_ld_f32(cpu_F1s, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1102 1103 1104 1105 1106
}

static inline void gen_mov_vreg_F0(int dp, int reg)
{
    if (dp)
P
pbrook 已提交
1107
        tcg_gen_st_f64(cpu_F0d, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1108
    else
P
pbrook 已提交
1109
        tcg_gen_st_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1110 1111
}

1112 1113
#define ARM_CP_RW_BIT	(1 << 20)

P
pbrook 已提交
1114
static inline void iwmmxt_load_reg(TCGv_i64 var, int reg)
P
pbrook 已提交
1115 1116 1117 1118
{
    tcg_gen_ld_i64(var, cpu_env, offsetof(CPUState, iwmmxt.regs[reg]));
}

P
pbrook 已提交
1119
static inline void iwmmxt_store_reg(TCGv_i64 var, int reg)
P
pbrook 已提交
1120 1121 1122 1123
{
    tcg_gen_st_i64(var, cpu_env, offsetof(CPUState, iwmmxt.regs[reg]));
}

1124
static inline TCGv iwmmxt_load_creg(int reg)
P
pbrook 已提交
1125
{
1126 1127 1128
    TCGv var = new_tmp();
    tcg_gen_ld_i32(var, cpu_env, offsetof(CPUState, iwmmxt.cregs[reg]));
    return var;
P
pbrook 已提交
1129 1130
}

1131
static inline void iwmmxt_store_creg(int reg, TCGv var)
P
pbrook 已提交
1132
{
1133
    tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, iwmmxt.cregs[reg]));
1134
    dead_tmp(var);
P
pbrook 已提交
1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272
}

static inline void gen_op_iwmmxt_movq_wRn_M0(int rn)
{
    iwmmxt_store_reg(cpu_M0, rn);
}

static inline void gen_op_iwmmxt_movq_M0_wRn(int rn)
{
    iwmmxt_load_reg(cpu_M0, rn);
}

static inline void gen_op_iwmmxt_orq_M0_wRn(int rn)
{
    iwmmxt_load_reg(cpu_V1, rn);
    tcg_gen_or_i64(cpu_M0, cpu_M0, cpu_V1);
}

static inline void gen_op_iwmmxt_andq_M0_wRn(int rn)
{
    iwmmxt_load_reg(cpu_V1, rn);
    tcg_gen_and_i64(cpu_M0, cpu_M0, cpu_V1);
}

static inline void gen_op_iwmmxt_xorq_M0_wRn(int rn)
{
    iwmmxt_load_reg(cpu_V1, rn);
    tcg_gen_xor_i64(cpu_M0, cpu_M0, cpu_V1);
}

#define IWMMXT_OP(name) \
static inline void gen_op_iwmmxt_##name##_M0_wRn(int rn) \
{ \
    iwmmxt_load_reg(cpu_V1, rn); \
    gen_helper_iwmmxt_##name(cpu_M0, cpu_M0, cpu_V1); \
}

#define IWMMXT_OP_ENV(name) \
static inline void gen_op_iwmmxt_##name##_M0_wRn(int rn) \
{ \
    iwmmxt_load_reg(cpu_V1, rn); \
    gen_helper_iwmmxt_##name(cpu_M0, cpu_env, cpu_M0, cpu_V1); \
}

#define IWMMXT_OP_ENV_SIZE(name) \
IWMMXT_OP_ENV(name##b) \
IWMMXT_OP_ENV(name##w) \
IWMMXT_OP_ENV(name##l)

#define IWMMXT_OP_ENV1(name) \
static inline void gen_op_iwmmxt_##name##_M0(void) \
{ \
    gen_helper_iwmmxt_##name(cpu_M0, cpu_env, cpu_M0); \
}

IWMMXT_OP(maddsq)
IWMMXT_OP(madduq)
IWMMXT_OP(sadb)
IWMMXT_OP(sadw)
IWMMXT_OP(mulslw)
IWMMXT_OP(mulshw)
IWMMXT_OP(mululw)
IWMMXT_OP(muluhw)
IWMMXT_OP(macsw)
IWMMXT_OP(macuw)

IWMMXT_OP_ENV_SIZE(unpackl)
IWMMXT_OP_ENV_SIZE(unpackh)

IWMMXT_OP_ENV1(unpacklub)
IWMMXT_OP_ENV1(unpackluw)
IWMMXT_OP_ENV1(unpacklul)
IWMMXT_OP_ENV1(unpackhub)
IWMMXT_OP_ENV1(unpackhuw)
IWMMXT_OP_ENV1(unpackhul)
IWMMXT_OP_ENV1(unpacklsb)
IWMMXT_OP_ENV1(unpacklsw)
IWMMXT_OP_ENV1(unpacklsl)
IWMMXT_OP_ENV1(unpackhsb)
IWMMXT_OP_ENV1(unpackhsw)
IWMMXT_OP_ENV1(unpackhsl)

IWMMXT_OP_ENV_SIZE(cmpeq)
IWMMXT_OP_ENV_SIZE(cmpgtu)
IWMMXT_OP_ENV_SIZE(cmpgts)

IWMMXT_OP_ENV_SIZE(mins)
IWMMXT_OP_ENV_SIZE(minu)
IWMMXT_OP_ENV_SIZE(maxs)
IWMMXT_OP_ENV_SIZE(maxu)

IWMMXT_OP_ENV_SIZE(subn)
IWMMXT_OP_ENV_SIZE(addn)
IWMMXT_OP_ENV_SIZE(subu)
IWMMXT_OP_ENV_SIZE(addu)
IWMMXT_OP_ENV_SIZE(subs)
IWMMXT_OP_ENV_SIZE(adds)

IWMMXT_OP_ENV(avgb0)
IWMMXT_OP_ENV(avgb1)
IWMMXT_OP_ENV(avgw0)
IWMMXT_OP_ENV(avgw1)

IWMMXT_OP(msadb)

IWMMXT_OP_ENV(packuw)
IWMMXT_OP_ENV(packul)
IWMMXT_OP_ENV(packuq)
IWMMXT_OP_ENV(packsw)
IWMMXT_OP_ENV(packsl)
IWMMXT_OP_ENV(packsq)

static void gen_op_iwmmxt_set_mup(void)
{
    TCGv tmp;
    tmp = load_cpu_field(iwmmxt.cregs[ARM_IWMMXT_wCon]);
    tcg_gen_ori_i32(tmp, tmp, 2);
    store_cpu_field(tmp, iwmmxt.cregs[ARM_IWMMXT_wCon]);
}

static void gen_op_iwmmxt_set_cup(void)
{
    TCGv tmp;
    tmp = load_cpu_field(iwmmxt.cregs[ARM_IWMMXT_wCon]);
    tcg_gen_ori_i32(tmp, tmp, 1);
    store_cpu_field(tmp, iwmmxt.cregs[ARM_IWMMXT_wCon]);
}

static void gen_op_iwmmxt_setpsr_nz(void)
{
    TCGv tmp = new_tmp();
    gen_helper_iwmmxt_setpsr_nz(tmp, cpu_M0);
    store_cpu_field(tmp, iwmmxt.cregs[ARM_IWMMXT_wCASF]);
}

static inline void gen_op_iwmmxt_addl_M0_wRn(int rn)
{
    iwmmxt_load_reg(cpu_V1, rn);
P
pbrook 已提交
1273
    tcg_gen_ext32u_i64(cpu_V1, cpu_V1);
P
pbrook 已提交
1274 1275 1276
    tcg_gen_add_i64(cpu_M0, cpu_M0, cpu_V1);
}

1277
static inline int gen_iwmmxt_address(DisasContext *s, uint32_t insn, TCGv dest)
1278 1279 1280
{
    int rd;
    uint32_t offset;
1281
    TCGv tmp;
1282 1283

    rd = (insn >> 16) & 0xf;
1284
    tmp = load_reg(s, rd);
1285 1286 1287 1288 1289

    offset = (insn & 0xff) << ((insn >> 7) & 2);
    if (insn & (1 << 24)) {
        /* Pre indexed */
        if (insn & (1 << 23))
1290
            tcg_gen_addi_i32(tmp, tmp, offset);
1291
        else
1292 1293
            tcg_gen_addi_i32(tmp, tmp, -offset);
        tcg_gen_mov_i32(dest, tmp);
1294
        if (insn & (1 << 21))
1295 1296 1297
            store_reg(s, rd, tmp);
        else
            dead_tmp(tmp);
1298 1299
    } else if (insn & (1 << 21)) {
        /* Post indexed */
1300
        tcg_gen_mov_i32(dest, tmp);
1301
        if (insn & (1 << 23))
1302
            tcg_gen_addi_i32(tmp, tmp, offset);
1303
        else
1304 1305
            tcg_gen_addi_i32(tmp, tmp, -offset);
        store_reg(s, rd, tmp);
1306 1307 1308 1309 1310
    } else if (!(insn & (1 << 23)))
        return 1;
    return 0;
}

1311
static inline int gen_iwmmxt_shift(uint32_t insn, uint32_t mask, TCGv dest)
1312 1313
{
    int rd = (insn >> 0) & 0xf;
1314
    TCGv tmp;
1315

1316 1317
    if (insn & (1 << 8)) {
        if (rd < ARM_IWMMXT_wCGR0 || rd > ARM_IWMMXT_wCGR3) {
1318
            return 1;
1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329
        } else {
            tmp = iwmmxt_load_creg(rd);
        }
    } else {
        tmp = new_tmp();
        iwmmxt_load_reg(cpu_V0, rd);
        tcg_gen_trunc_i64_i32(tmp, cpu_V0);
    }
    tcg_gen_andi_i32(tmp, tmp, mask);
    tcg_gen_mov_i32(dest, tmp);
    dead_tmp(tmp);
1330 1331 1332 1333 1334 1335 1336 1337 1338
    return 0;
}

/* Disassemble an iwMMXt instruction.  Returns nonzero if an error occured
   (ie. an undefined instruction).  */
static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
{
    int rd, wrd;
    int rdhi, rdlo, rd0, rd1, i;
1339 1340
    TCGv addr;
    TCGv tmp, tmp2, tmp3;
1341 1342 1343 1344 1345 1346 1347

    if ((insn & 0x0e000e00) == 0x0c000000) {
        if ((insn & 0x0fe00ff0) == 0x0c400000) {
            wrd = insn & 0xf;
            rdlo = (insn >> 12) & 0xf;
            rdhi = (insn >> 16) & 0xf;
            if (insn & ARM_CP_RW_BIT) {			/* TMRRC */
1348 1349 1350 1351
                iwmmxt_load_reg(cpu_V0, wrd);
                tcg_gen_trunc_i64_i32(cpu_R[rdlo], cpu_V0);
                tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
                tcg_gen_trunc_i64_i32(cpu_R[rdhi], cpu_V0);
1352
            } else {					/* TMCRR */
1353 1354
                tcg_gen_concat_i32_i64(cpu_V0, cpu_R[rdlo], cpu_R[rdhi]);
                iwmmxt_store_reg(cpu_V0, wrd);
1355 1356 1357 1358 1359 1360
                gen_op_iwmmxt_set_mup();
            }
            return 0;
        }

        wrd = (insn >> 12) & 0xf;
1361 1362 1363
        addr = new_tmp();
        if (gen_iwmmxt_address(s, insn, addr)) {
            dead_tmp(addr);
1364
            return 1;
1365
        }
1366 1367
        if (insn & ARM_CP_RW_BIT) {
            if ((insn >> 28) == 0xf) {			/* WLDRW wCx */
1368 1369 1370
                tmp = new_tmp();
                tcg_gen_qemu_ld32u(tmp, addr, IS_USER(s));
                iwmmxt_store_creg(wrd, tmp);
1371
            } else {
P
pbrook 已提交
1372 1373 1374
                i = 1;
                if (insn & (1 << 8)) {
                    if (insn & (1 << 22)) {		/* WLDRD */
1375
                        tcg_gen_qemu_ld64(cpu_M0, addr, IS_USER(s));
P
pbrook 已提交
1376 1377
                        i = 0;
                    } else {				/* WLDRW wRd */
1378
                        tmp = gen_ld32(addr, IS_USER(s));
P
pbrook 已提交
1379 1380 1381
                    }
                } else {
                    if (insn & (1 << 22)) {		/* WLDRH */
1382
                        tmp = gen_ld16u(addr, IS_USER(s));
P
pbrook 已提交
1383
                    } else {				/* WLDRB */
1384
                        tmp = gen_ld8u(addr, IS_USER(s));
P
pbrook 已提交
1385 1386 1387 1388 1389 1390
                    }
                }
                if (i) {
                    tcg_gen_extu_i32_i64(cpu_M0, tmp);
                    dead_tmp(tmp);
                }
1391 1392 1393 1394
                gen_op_iwmmxt_movq_wRn_M0(wrd);
            }
        } else {
            if ((insn >> 28) == 0xf) {			/* WSTRW wCx */
1395 1396
                tmp = iwmmxt_load_creg(wrd);
                gen_st32(tmp, addr, IS_USER(s));
1397 1398
            } else {
                gen_op_iwmmxt_movq_M0_wRn(wrd);
P
pbrook 已提交
1399 1400 1401 1402
                tmp = new_tmp();
                if (insn & (1 << 8)) {
                    if (insn & (1 << 22)) {		/* WSTRD */
                        dead_tmp(tmp);
1403
                        tcg_gen_qemu_st64(cpu_M0, addr, IS_USER(s));
P
pbrook 已提交
1404 1405
                    } else {				/* WSTRW wRd */
                        tcg_gen_trunc_i64_i32(tmp, cpu_M0);
1406
                        gen_st32(tmp, addr, IS_USER(s));
P
pbrook 已提交
1407 1408 1409 1410
                    }
                } else {
                    if (insn & (1 << 22)) {		/* WSTRH */
                        tcg_gen_trunc_i64_i32(tmp, cpu_M0);
1411
                        gen_st16(tmp, addr, IS_USER(s));
P
pbrook 已提交
1412 1413
                    } else {				/* WSTRB */
                        tcg_gen_trunc_i64_i32(tmp, cpu_M0);
1414
                        gen_st8(tmp, addr, IS_USER(s));
P
pbrook 已提交
1415 1416
                    }
                }
1417 1418
            }
        }
1419
        dead_tmp(addr);
1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450
        return 0;
    }

    if ((insn & 0x0f000000) != 0x0e000000)
        return 1;

    switch (((insn >> 12) & 0xf00) | ((insn >> 4) & 0xff)) {
    case 0x000:						/* WOR */
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 0) & 0xf;
        rd1 = (insn >> 16) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
        gen_op_iwmmxt_orq_M0_wRn(rd1);
        gen_op_iwmmxt_setpsr_nz();
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        gen_op_iwmmxt_set_cup();
        break;
    case 0x011:						/* TMCR */
        if (insn & 0xf)
            return 1;
        rd = (insn >> 12) & 0xf;
        wrd = (insn >> 16) & 0xf;
        switch (wrd) {
        case ARM_IWMMXT_wCID:
        case ARM_IWMMXT_wCASF:
            break;
        case ARM_IWMMXT_wCon:
            gen_op_iwmmxt_set_cup();
            /* Fall through.  */
        case ARM_IWMMXT_wCSSF:
1451 1452
            tmp = iwmmxt_load_creg(wrd);
            tmp2 = load_reg(s, rd);
1453
            tcg_gen_andc_i32(tmp, tmp, tmp2);
1454 1455
            dead_tmp(tmp2);
            iwmmxt_store_creg(wrd, tmp);
1456 1457 1458 1459 1460 1461
            break;
        case ARM_IWMMXT_wCGR0:
        case ARM_IWMMXT_wCGR1:
        case ARM_IWMMXT_wCGR2:
        case ARM_IWMMXT_wCGR3:
            gen_op_iwmmxt_set_cup();
1462 1463
            tmp = load_reg(s, rd);
            iwmmxt_store_creg(wrd, tmp);
1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484
            break;
        default:
            return 1;
        }
        break;
    case 0x100:						/* WXOR */
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 0) & 0xf;
        rd1 = (insn >> 16) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
        gen_op_iwmmxt_xorq_M0_wRn(rd1);
        gen_op_iwmmxt_setpsr_nz();
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        gen_op_iwmmxt_set_cup();
        break;
    case 0x111:						/* TMRC */
        if (insn & 0xf)
            return 1;
        rd = (insn >> 12) & 0xf;
        wrd = (insn >> 16) & 0xf;
1485 1486
        tmp = iwmmxt_load_creg(wrd);
        store_reg(s, rd, tmp);
1487 1488 1489 1490 1491 1492
        break;
    case 0x300:						/* WANDN */
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 0) & 0xf;
        rd1 = (insn >> 16) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
P
pbrook 已提交
1493
        tcg_gen_neg_i64(cpu_M0, cpu_M0);
1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585
        gen_op_iwmmxt_andq_M0_wRn(rd1);
        gen_op_iwmmxt_setpsr_nz();
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        gen_op_iwmmxt_set_cup();
        break;
    case 0x200:						/* WAND */
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 0) & 0xf;
        rd1 = (insn >> 16) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
        gen_op_iwmmxt_andq_M0_wRn(rd1);
        gen_op_iwmmxt_setpsr_nz();
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        gen_op_iwmmxt_set_cup();
        break;
    case 0x810: case 0xa10:				/* WMADD */
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 0) & 0xf;
        rd1 = (insn >> 16) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
        if (insn & (1 << 21))
            gen_op_iwmmxt_maddsq_M0_wRn(rd1);
        else
            gen_op_iwmmxt_madduq_M0_wRn(rd1);
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        break;
    case 0x10e: case 0x50e: case 0x90e: case 0xd0e:	/* WUNPCKIL */
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        rd1 = (insn >> 0) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
        switch ((insn >> 22) & 3) {
        case 0:
            gen_op_iwmmxt_unpacklb_M0_wRn(rd1);
            break;
        case 1:
            gen_op_iwmmxt_unpacklw_M0_wRn(rd1);
            break;
        case 2:
            gen_op_iwmmxt_unpackll_M0_wRn(rd1);
            break;
        case 3:
            return 1;
        }
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        gen_op_iwmmxt_set_cup();
        break;
    case 0x10c: case 0x50c: case 0x90c: case 0xd0c:	/* WUNPCKIH */
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        rd1 = (insn >> 0) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
        switch ((insn >> 22) & 3) {
        case 0:
            gen_op_iwmmxt_unpackhb_M0_wRn(rd1);
            break;
        case 1:
            gen_op_iwmmxt_unpackhw_M0_wRn(rd1);
            break;
        case 2:
            gen_op_iwmmxt_unpackhl_M0_wRn(rd1);
            break;
        case 3:
            return 1;
        }
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        gen_op_iwmmxt_set_cup();
        break;
    case 0x012: case 0x112: case 0x412: case 0x512:	/* WSAD */
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        rd1 = (insn >> 0) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
        if (insn & (1 << 22))
            gen_op_iwmmxt_sadw_M0_wRn(rd1);
        else
            gen_op_iwmmxt_sadb_M0_wRn(rd1);
        if (!(insn & (1 << 20)))
            gen_op_iwmmxt_addl_M0_wRn(wrd);
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        break;
    case 0x010: case 0x110: case 0x210: case 0x310:	/* WMUL */
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        rd1 = (insn >> 0) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
P
pbrook 已提交
1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596
        if (insn & (1 << 21)) {
            if (insn & (1 << 20))
                gen_op_iwmmxt_mulshw_M0_wRn(rd1);
            else
                gen_op_iwmmxt_mulslw_M0_wRn(rd1);
        } else {
            if (insn & (1 << 20))
                gen_op_iwmmxt_muluhw_M0_wRn(rd1);
            else
                gen_op_iwmmxt_mululw_M0_wRn(rd1);
        }
1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        break;
    case 0x410: case 0x510: case 0x610: case 0x710:	/* WMAC */
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        rd1 = (insn >> 0) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
        if (insn & (1 << 21))
            gen_op_iwmmxt_macsw_M0_wRn(rd1);
        else
            gen_op_iwmmxt_macuw_M0_wRn(rd1);
        if (!(insn & (1 << 20))) {
P
pbrook 已提交
1610 1611
            iwmmxt_load_reg(cpu_V1, wrd);
            tcg_gen_add_i64(cpu_M0, cpu_M0, cpu_V1);
1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642
        }
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        break;
    case 0x006: case 0x406: case 0x806: case 0xc06:	/* WCMPEQ */
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        rd1 = (insn >> 0) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
        switch ((insn >> 22) & 3) {
        case 0:
            gen_op_iwmmxt_cmpeqb_M0_wRn(rd1);
            break;
        case 1:
            gen_op_iwmmxt_cmpeqw_M0_wRn(rd1);
            break;
        case 2:
            gen_op_iwmmxt_cmpeql_M0_wRn(rd1);
            break;
        case 3:
            return 1;
        }
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        gen_op_iwmmxt_set_cup();
        break;
    case 0x800: case 0x900: case 0xc00: case 0xd00:	/* WAVG2 */
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        rd1 = (insn >> 0) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
P
pbrook 已提交
1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653
        if (insn & (1 << 22)) {
            if (insn & (1 << 20))
                gen_op_iwmmxt_avgw1_M0_wRn(rd1);
            else
                gen_op_iwmmxt_avgw0_M0_wRn(rd1);
        } else {
            if (insn & (1 << 20))
                gen_op_iwmmxt_avgb1_M0_wRn(rd1);
            else
                gen_op_iwmmxt_avgb0_M0_wRn(rd1);
        }
1654 1655 1656 1657 1658 1659 1660 1661 1662
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        gen_op_iwmmxt_set_cup();
        break;
    case 0x802: case 0x902: case 0xa02: case 0xb02:	/* WALIGNR */
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        rd1 = (insn >> 0) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
1663 1664 1665 1666 1667
        tmp = iwmmxt_load_creg(ARM_IWMMXT_wCGR0 + ((insn >> 20) & 3));
        tcg_gen_andi_i32(tmp, tmp, 7);
        iwmmxt_load_reg(cpu_V1, rd1);
        gen_helper_iwmmxt_align(cpu_M0, cpu_M0, cpu_V1, tmp);
        dead_tmp(tmp);
1668 1669 1670 1671
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        break;
    case 0x601: case 0x605: case 0x609: case 0x60d:	/* TINSR */
1672 1673
        if (((insn >> 6) & 3) == 3)
            return 1;
1674 1675
        rd = (insn >> 12) & 0xf;
        wrd = (insn >> 16) & 0xf;
1676
        tmp = load_reg(s, rd);
1677 1678 1679
        gen_op_iwmmxt_movq_M0_wRn(wrd);
        switch ((insn >> 6) & 3) {
        case 0:
1680 1681
            tmp2 = tcg_const_i32(0xff);
            tmp3 = tcg_const_i32((insn & 7) << 3);
1682 1683
            break;
        case 1:
1684 1685
            tmp2 = tcg_const_i32(0xffff);
            tmp3 = tcg_const_i32((insn & 3) << 4);
1686 1687
            break;
        case 2:
1688 1689
            tmp2 = tcg_const_i32(0xffffffff);
            tmp3 = tcg_const_i32((insn & 1) << 5);
1690
            break;
1691 1692 1693
        default:
            TCGV_UNUSED(tmp2);
            TCGV_UNUSED(tmp3);
1694
        }
1695 1696 1697 1698
        gen_helper_iwmmxt_insr(cpu_M0, cpu_M0, tmp, tmp2, tmp3);
        tcg_temp_free(tmp3);
        tcg_temp_free(tmp2);
        dead_tmp(tmp);
1699 1700 1701 1702 1703 1704
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        break;
    case 0x107: case 0x507: case 0x907: case 0xd07:	/* TEXTRM */
        rd = (insn >> 12) & 0xf;
        wrd = (insn >> 16) & 0xf;
1705
        if (rd == 15 || ((insn >> 22) & 3) == 3)
1706 1707
            return 1;
        gen_op_iwmmxt_movq_M0_wRn(wrd);
1708
        tmp = new_tmp();
1709 1710
        switch ((insn >> 22) & 3) {
        case 0:
1711 1712 1713 1714 1715 1716
            tcg_gen_shri_i64(cpu_M0, cpu_M0, (insn & 7) << 3);
            tcg_gen_trunc_i64_i32(tmp, cpu_M0);
            if (insn & 8) {
                tcg_gen_ext8s_i32(tmp, tmp);
            } else {
                tcg_gen_andi_i32(tmp, tmp, 0xff);
1717 1718 1719
            }
            break;
        case 1:
1720 1721 1722 1723 1724 1725
            tcg_gen_shri_i64(cpu_M0, cpu_M0, (insn & 3) << 4);
            tcg_gen_trunc_i64_i32(tmp, cpu_M0);
            if (insn & 8) {
                tcg_gen_ext16s_i32(tmp, tmp);
            } else {
                tcg_gen_andi_i32(tmp, tmp, 0xffff);
1726 1727 1728
            }
            break;
        case 2:
1729 1730
            tcg_gen_shri_i64(cpu_M0, cpu_M0, (insn & 1) << 5);
            tcg_gen_trunc_i64_i32(tmp, cpu_M0);
1731 1732
            break;
        }
1733
        store_reg(s, rd, tmp);
1734 1735
        break;
    case 0x117: case 0x517: case 0x917: case 0xd17:	/* TEXTRC */
1736
        if ((insn & 0x000ff008) != 0x0003f000 || ((insn >> 22) & 3) == 3)
1737
            return 1;
1738
        tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF);
1739 1740
        switch ((insn >> 22) & 3) {
        case 0:
1741
            tcg_gen_shri_i32(tmp, tmp, ((insn & 7) << 2) + 0);
1742 1743
            break;
        case 1:
1744
            tcg_gen_shri_i32(tmp, tmp, ((insn & 3) << 3) + 4);
1745 1746
            break;
        case 2:
1747
            tcg_gen_shri_i32(tmp, tmp, ((insn & 1) << 4) + 12);
1748 1749
            break;
        }
1750 1751 1752
        tcg_gen_shli_i32(tmp, tmp, 28);
        gen_set_nzcv(tmp);
        dead_tmp(tmp);
1753 1754
        break;
    case 0x401: case 0x405: case 0x409: case 0x40d:	/* TBCST */
1755 1756
        if (((insn >> 6) & 3) == 3)
            return 1;
1757 1758
        rd = (insn >> 12) & 0xf;
        wrd = (insn >> 16) & 0xf;
1759
        tmp = load_reg(s, rd);
1760 1761
        switch ((insn >> 6) & 3) {
        case 0:
1762
            gen_helper_iwmmxt_bcstb(cpu_M0, tmp);
1763 1764
            break;
        case 1:
1765
            gen_helper_iwmmxt_bcstw(cpu_M0, tmp);
1766 1767
            break;
        case 2:
1768
            gen_helper_iwmmxt_bcstl(cpu_M0, tmp);
1769 1770
            break;
        }
1771
        dead_tmp(tmp);
1772 1773 1774 1775
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        break;
    case 0x113: case 0x513: case 0x913: case 0xd13:	/* TANDC */
1776
        if ((insn & 0x000ff00f) != 0x0003f000 || ((insn >> 22) & 3) == 3)
1777
            return 1;
1778 1779 1780
        tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF);
        tmp2 = new_tmp();
        tcg_gen_mov_i32(tmp2, tmp);
1781 1782 1783
        switch ((insn >> 22) & 3) {
        case 0:
            for (i = 0; i < 7; i ++) {
1784 1785
                tcg_gen_shli_i32(tmp2, tmp2, 4);
                tcg_gen_and_i32(tmp, tmp, tmp2);
1786 1787 1788 1789
            }
            break;
        case 1:
            for (i = 0; i < 3; i ++) {
1790 1791
                tcg_gen_shli_i32(tmp2, tmp2, 8);
                tcg_gen_and_i32(tmp, tmp, tmp2);
1792 1793 1794
            }
            break;
        case 2:
1795 1796
            tcg_gen_shli_i32(tmp2, tmp2, 16);
            tcg_gen_and_i32(tmp, tmp, tmp2);
1797 1798
            break;
        }
1799 1800 1801
        gen_set_nzcv(tmp);
        dead_tmp(tmp2);
        dead_tmp(tmp);
1802 1803 1804 1805 1806 1807 1808
        break;
    case 0x01c: case 0x41c: case 0x81c: case 0xc1c:	/* WACC */
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
        switch ((insn >> 22) & 3) {
        case 0:
P
pbrook 已提交
1809
            gen_helper_iwmmxt_addcb(cpu_M0, cpu_M0);
1810 1811
            break;
        case 1:
P
pbrook 已提交
1812
            gen_helper_iwmmxt_addcw(cpu_M0, cpu_M0);
1813 1814
            break;
        case 2:
P
pbrook 已提交
1815
            gen_helper_iwmmxt_addcl(cpu_M0, cpu_M0);
1816 1817 1818 1819 1820 1821 1822 1823
            break;
        case 3:
            return 1;
        }
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        break;
    case 0x115: case 0x515: case 0x915: case 0xd15:	/* TORC */
1824
        if ((insn & 0x000ff00f) != 0x0003f000 || ((insn >> 22) & 3) == 3)
1825
            return 1;
1826 1827 1828
        tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF);
        tmp2 = new_tmp();
        tcg_gen_mov_i32(tmp2, tmp);
1829 1830 1831
        switch ((insn >> 22) & 3) {
        case 0:
            for (i = 0; i < 7; i ++) {
1832 1833
                tcg_gen_shli_i32(tmp2, tmp2, 4);
                tcg_gen_or_i32(tmp, tmp, tmp2);
1834 1835 1836 1837
            }
            break;
        case 1:
            for (i = 0; i < 3; i ++) {
1838 1839
                tcg_gen_shli_i32(tmp2, tmp2, 8);
                tcg_gen_or_i32(tmp, tmp, tmp2);
1840 1841 1842
            }
            break;
        case 2:
1843 1844
            tcg_gen_shli_i32(tmp2, tmp2, 16);
            tcg_gen_or_i32(tmp, tmp, tmp2);
1845 1846
            break;
        }
1847 1848 1849
        gen_set_nzcv(tmp);
        dead_tmp(tmp2);
        dead_tmp(tmp);
1850 1851 1852 1853
        break;
    case 0x103: case 0x503: case 0x903: case 0xd03:	/* TMOVMSK */
        rd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
1854
        if ((insn & 0xf) != 0 || ((insn >> 22) & 3) == 3)
1855 1856
            return 1;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
1857
        tmp = new_tmp();
1858 1859
        switch ((insn >> 22) & 3) {
        case 0:
1860
            gen_helper_iwmmxt_msbb(tmp, cpu_M0);
1861 1862
            break;
        case 1:
1863
            gen_helper_iwmmxt_msbw(tmp, cpu_M0);
1864 1865
            break;
        case 2:
1866
            gen_helper_iwmmxt_msbl(tmp, cpu_M0);
1867 1868
            break;
        }
1869
        store_reg(s, rd, tmp);
1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966
        break;
    case 0x106: case 0x306: case 0x506: case 0x706:	/* WCMPGT */
    case 0x906: case 0xb06: case 0xd06: case 0xf06:
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        rd1 = (insn >> 0) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
        switch ((insn >> 22) & 3) {
        case 0:
            if (insn & (1 << 21))
                gen_op_iwmmxt_cmpgtsb_M0_wRn(rd1);
            else
                gen_op_iwmmxt_cmpgtub_M0_wRn(rd1);
            break;
        case 1:
            if (insn & (1 << 21))
                gen_op_iwmmxt_cmpgtsw_M0_wRn(rd1);
            else
                gen_op_iwmmxt_cmpgtuw_M0_wRn(rd1);
            break;
        case 2:
            if (insn & (1 << 21))
                gen_op_iwmmxt_cmpgtsl_M0_wRn(rd1);
            else
                gen_op_iwmmxt_cmpgtul_M0_wRn(rd1);
            break;
        case 3:
            return 1;
        }
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        gen_op_iwmmxt_set_cup();
        break;
    case 0x00e: case 0x20e: case 0x40e: case 0x60e:	/* WUNPCKEL */
    case 0x80e: case 0xa0e: case 0xc0e: case 0xe0e:
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
        switch ((insn >> 22) & 3) {
        case 0:
            if (insn & (1 << 21))
                gen_op_iwmmxt_unpacklsb_M0();
            else
                gen_op_iwmmxt_unpacklub_M0();
            break;
        case 1:
            if (insn & (1 << 21))
                gen_op_iwmmxt_unpacklsw_M0();
            else
                gen_op_iwmmxt_unpackluw_M0();
            break;
        case 2:
            if (insn & (1 << 21))
                gen_op_iwmmxt_unpacklsl_M0();
            else
                gen_op_iwmmxt_unpacklul_M0();
            break;
        case 3:
            return 1;
        }
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        gen_op_iwmmxt_set_cup();
        break;
    case 0x00c: case 0x20c: case 0x40c: case 0x60c:	/* WUNPCKEH */
    case 0x80c: case 0xa0c: case 0xc0c: case 0xe0c:
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
        switch ((insn >> 22) & 3) {
        case 0:
            if (insn & (1 << 21))
                gen_op_iwmmxt_unpackhsb_M0();
            else
                gen_op_iwmmxt_unpackhub_M0();
            break;
        case 1:
            if (insn & (1 << 21))
                gen_op_iwmmxt_unpackhsw_M0();
            else
                gen_op_iwmmxt_unpackhuw_M0();
            break;
        case 2:
            if (insn & (1 << 21))
                gen_op_iwmmxt_unpackhsl_M0();
            else
                gen_op_iwmmxt_unpackhul_M0();
            break;
        case 3:
            return 1;
        }
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        gen_op_iwmmxt_set_cup();
        break;
    case 0x204: case 0x604: case 0xa04: case 0xe04:	/* WSRL */
    case 0x214: case 0x614: case 0xa14: case 0xe14:
1967 1968
        if (((insn >> 22) & 3) == 0)
            return 1;
1969 1970 1971
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
1972 1973 1974
        tmp = new_tmp();
        if (gen_iwmmxt_shift(insn, 0xff, tmp)) {
            dead_tmp(tmp);
1975
            return 1;
1976
        }
1977 1978
        switch ((insn >> 22) & 3) {
        case 1:
1979
            gen_helper_iwmmxt_srlw(cpu_M0, cpu_env, cpu_M0, tmp);
1980 1981
            break;
        case 2:
1982
            gen_helper_iwmmxt_srll(cpu_M0, cpu_env, cpu_M0, tmp);
1983 1984
            break;
        case 3:
1985
            gen_helper_iwmmxt_srlq(cpu_M0, cpu_env, cpu_M0, tmp);
1986 1987
            break;
        }
1988
        dead_tmp(tmp);
1989 1990 1991 1992 1993 1994
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        gen_op_iwmmxt_set_cup();
        break;
    case 0x004: case 0x404: case 0x804: case 0xc04:	/* WSRA */
    case 0x014: case 0x414: case 0x814: case 0xc14:
1995 1996
        if (((insn >> 22) & 3) == 0)
            return 1;
1997 1998 1999
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
2000 2001 2002
        tmp = new_tmp();
        if (gen_iwmmxt_shift(insn, 0xff, tmp)) {
            dead_tmp(tmp);
2003
            return 1;
2004
        }
2005 2006
        switch ((insn >> 22) & 3) {
        case 1:
2007
            gen_helper_iwmmxt_sraw(cpu_M0, cpu_env, cpu_M0, tmp);
2008 2009
            break;
        case 2:
2010
            gen_helper_iwmmxt_sral(cpu_M0, cpu_env, cpu_M0, tmp);
2011 2012
            break;
        case 3:
2013
            gen_helper_iwmmxt_sraq(cpu_M0, cpu_env, cpu_M0, tmp);
2014 2015
            break;
        }
2016
        dead_tmp(tmp);
2017 2018 2019 2020 2021 2022
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        gen_op_iwmmxt_set_cup();
        break;
    case 0x104: case 0x504: case 0x904: case 0xd04:	/* WSLL */
    case 0x114: case 0x514: case 0x914: case 0xd14:
2023 2024
        if (((insn >> 22) & 3) == 0)
            return 1;
2025 2026 2027
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
2028 2029 2030
        tmp = new_tmp();
        if (gen_iwmmxt_shift(insn, 0xff, tmp)) {
            dead_tmp(tmp);
2031
            return 1;
2032
        }
2033 2034
        switch ((insn >> 22) & 3) {
        case 1:
2035
            gen_helper_iwmmxt_sllw(cpu_M0, cpu_env, cpu_M0, tmp);
2036 2037
            break;
        case 2:
2038
            gen_helper_iwmmxt_slll(cpu_M0, cpu_env, cpu_M0, tmp);
2039 2040
            break;
        case 3:
2041
            gen_helper_iwmmxt_sllq(cpu_M0, cpu_env, cpu_M0, tmp);
2042 2043
            break;
        }
2044
        dead_tmp(tmp);
2045 2046 2047 2048 2049 2050
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        gen_op_iwmmxt_set_cup();
        break;
    case 0x304: case 0x704: case 0xb04: case 0xf04:	/* WROR */
    case 0x314: case 0x714: case 0xb14: case 0xf14:
2051 2052
        if (((insn >> 22) & 3) == 0)
            return 1;
2053 2054 2055
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
2056
        tmp = new_tmp();
2057 2058
        switch ((insn >> 22) & 3) {
        case 1:
2059 2060
            if (gen_iwmmxt_shift(insn, 0xf, tmp)) {
                dead_tmp(tmp);
2061
                return 1;
2062 2063
            }
            gen_helper_iwmmxt_rorw(cpu_M0, cpu_env, cpu_M0, tmp);
2064 2065
            break;
        case 2:
2066 2067
            if (gen_iwmmxt_shift(insn, 0x1f, tmp)) {
                dead_tmp(tmp);
2068
                return 1;
2069 2070
            }
            gen_helper_iwmmxt_rorl(cpu_M0, cpu_env, cpu_M0, tmp);
2071 2072
            break;
        case 3:
2073 2074
            if (gen_iwmmxt_shift(insn, 0x3f, tmp)) {
                dead_tmp(tmp);
2075
                return 1;
2076 2077
            }
            gen_helper_iwmmxt_rorq(cpu_M0, cpu_env, cpu_M0, tmp);
2078 2079
            break;
        }
2080
        dead_tmp(tmp);
2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        gen_op_iwmmxt_set_cup();
        break;
    case 0x116: case 0x316: case 0x516: case 0x716:	/* WMIN */
    case 0x916: case 0xb16: case 0xd16: case 0xf16:
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        rd1 = (insn >> 0) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
        switch ((insn >> 22) & 3) {
        case 0:
            if (insn & (1 << 21))
                gen_op_iwmmxt_minsb_M0_wRn(rd1);
            else
                gen_op_iwmmxt_minub_M0_wRn(rd1);
            break;
        case 1:
            if (insn & (1 << 21))
                gen_op_iwmmxt_minsw_M0_wRn(rd1);
            else
                gen_op_iwmmxt_minuw_M0_wRn(rd1);
            break;
        case 2:
            if (insn & (1 << 21))
                gen_op_iwmmxt_minsl_M0_wRn(rd1);
            else
                gen_op_iwmmxt_minul_M0_wRn(rd1);
            break;
        case 3:
            return 1;
        }
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        break;
    case 0x016: case 0x216: case 0x416: case 0x616:	/* WMAX */
    case 0x816: case 0xa16: case 0xc16: case 0xe16:
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        rd1 = (insn >> 0) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
        switch ((insn >> 22) & 3) {
        case 0:
            if (insn & (1 << 21))
                gen_op_iwmmxt_maxsb_M0_wRn(rd1);
            else
                gen_op_iwmmxt_maxub_M0_wRn(rd1);
            break;
        case 1:
            if (insn & (1 << 21))
                gen_op_iwmmxt_maxsw_M0_wRn(rd1);
            else
                gen_op_iwmmxt_maxuw_M0_wRn(rd1);
            break;
        case 2:
            if (insn & (1 << 21))
                gen_op_iwmmxt_maxsl_M0_wRn(rd1);
            else
                gen_op_iwmmxt_maxul_M0_wRn(rd1);
            break;
        case 3:
            return 1;
        }
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        break;
    case 0x002: case 0x102: case 0x202: case 0x302:	/* WALIGNI */
    case 0x402: case 0x502: case 0x602: case 0x702:
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        rd1 = (insn >> 0) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
2153 2154 2155 2156
        tmp = tcg_const_i32((insn >> 20) & 3);
        iwmmxt_load_reg(cpu_V1, rd1);
        gen_helper_iwmmxt_align(cpu_M0, cpu_M0, cpu_V1, tmp);
        tcg_temp_free(tmp);
2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        break;
    case 0x01a: case 0x11a: case 0x21a: case 0x31a:	/* WSUB */
    case 0x41a: case 0x51a: case 0x61a: case 0x71a:
    case 0x81a: case 0x91a: case 0xa1a: case 0xb1a:
    case 0xc1a: case 0xd1a: case 0xe1a: case 0xf1a:
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        rd1 = (insn >> 0) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
        switch ((insn >> 20) & 0xf) {
        case 0x0:
            gen_op_iwmmxt_subnb_M0_wRn(rd1);
            break;
        case 0x1:
            gen_op_iwmmxt_subub_M0_wRn(rd1);
            break;
        case 0x3:
            gen_op_iwmmxt_subsb_M0_wRn(rd1);
            break;
        case 0x4:
            gen_op_iwmmxt_subnw_M0_wRn(rd1);
            break;
        case 0x5:
            gen_op_iwmmxt_subuw_M0_wRn(rd1);
            break;
        case 0x7:
            gen_op_iwmmxt_subsw_M0_wRn(rd1);
            break;
        case 0x8:
            gen_op_iwmmxt_subnl_M0_wRn(rd1);
            break;
        case 0x9:
            gen_op_iwmmxt_subul_M0_wRn(rd1);
            break;
        case 0xb:
            gen_op_iwmmxt_subsl_M0_wRn(rd1);
            break;
        default:
            return 1;
        }
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        gen_op_iwmmxt_set_cup();
        break;
    case 0x01e: case 0x11e: case 0x21e: case 0x31e:	/* WSHUFH */
    case 0x41e: case 0x51e: case 0x61e: case 0x71e:
    case 0x81e: case 0x91e: case 0xa1e: case 0xb1e:
    case 0xc1e: case 0xd1e: case 0xe1e: case 0xf1e:
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
2210 2211 2212
        tmp = tcg_const_i32(((insn >> 16) & 0xf0) | (insn & 0x0f));
        gen_helper_iwmmxt_shufh(cpu_M0, cpu_env, cpu_M0, tmp);
        tcg_temp_free(tmp);
2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        gen_op_iwmmxt_set_cup();
        break;
    case 0x018: case 0x118: case 0x218: case 0x318:	/* WADD */
    case 0x418: case 0x518: case 0x618: case 0x718:
    case 0x818: case 0x918: case 0xa18: case 0xb18:
    case 0xc18: case 0xd18: case 0xe18: case 0xf18:
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        rd1 = (insn >> 0) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
        switch ((insn >> 20) & 0xf) {
        case 0x0:
            gen_op_iwmmxt_addnb_M0_wRn(rd1);
            break;
        case 0x1:
            gen_op_iwmmxt_addub_M0_wRn(rd1);
            break;
        case 0x3:
            gen_op_iwmmxt_addsb_M0_wRn(rd1);
            break;
        case 0x4:
            gen_op_iwmmxt_addnw_M0_wRn(rd1);
            break;
        case 0x5:
            gen_op_iwmmxt_adduw_M0_wRn(rd1);
            break;
        case 0x7:
            gen_op_iwmmxt_addsw_M0_wRn(rd1);
            break;
        case 0x8:
            gen_op_iwmmxt_addnl_M0_wRn(rd1);
            break;
        case 0x9:
            gen_op_iwmmxt_addul_M0_wRn(rd1);
            break;
        case 0xb:
            gen_op_iwmmxt_addsl_M0_wRn(rd1);
            break;
        default:
            return 1;
        }
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        gen_op_iwmmxt_set_cup();
        break;
    case 0x008: case 0x108: case 0x208: case 0x308:	/* WPACK */
    case 0x408: case 0x508: case 0x608: case 0x708:
    case 0x808: case 0x908: case 0xa08: case 0xb08:
    case 0xc08: case 0xd08: case 0xe08: case 0xf08:
2264 2265
        if (!(insn & (1 << 20)) || ((insn >> 22) & 3) == 0)
            return 1;
2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        rd1 = (insn >> 0) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
        switch ((insn >> 22) & 3) {
        case 1:
            if (insn & (1 << 21))
                gen_op_iwmmxt_packsw_M0_wRn(rd1);
            else
                gen_op_iwmmxt_packuw_M0_wRn(rd1);
            break;
        case 2:
            if (insn & (1 << 21))
                gen_op_iwmmxt_packsl_M0_wRn(rd1);
            else
                gen_op_iwmmxt_packul_M0_wRn(rd1);
            break;
        case 3:
            if (insn & (1 << 21))
                gen_op_iwmmxt_packsq_M0_wRn(rd1);
            else
                gen_op_iwmmxt_packuq_M0_wRn(rd1);
            break;
        }
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        gen_op_iwmmxt_set_cup();
        break;
    case 0x201: case 0x203: case 0x205: case 0x207:
    case 0x209: case 0x20b: case 0x20d: case 0x20f:
    case 0x211: case 0x213: case 0x215: case 0x217:
    case 0x219: case 0x21b: case 0x21d: case 0x21f:
        wrd = (insn >> 5) & 0xf;
        rd0 = (insn >> 12) & 0xf;
        rd1 = (insn >> 0) & 0xf;
        if (rd0 == 0xf || rd1 == 0xf)
            return 1;
        gen_op_iwmmxt_movq_M0_wRn(wrd);
2304 2305
        tmp = load_reg(s, rd0);
        tmp2 = load_reg(s, rd1);
2306 2307
        switch ((insn >> 16) & 0xf) {
        case 0x0:					/* TMIA */
2308
            gen_helper_iwmmxt_muladdsl(cpu_M0, cpu_M0, tmp, tmp2);
2309 2310
            break;
        case 0x8:					/* TMIAPH */
2311
            gen_helper_iwmmxt_muladdsw(cpu_M0, cpu_M0, tmp, tmp2);
2312 2313 2314
            break;
        case 0xc: case 0xd: case 0xe: case 0xf:		/* TMIAxy */
            if (insn & (1 << 16))
2315
                tcg_gen_shri_i32(tmp, tmp, 16);
2316
            if (insn & (1 << 17))
2317 2318
                tcg_gen_shri_i32(tmp2, tmp2, 16);
            gen_helper_iwmmxt_muladdswl(cpu_M0, cpu_M0, tmp, tmp2);
2319 2320
            break;
        default:
2321 2322
            dead_tmp(tmp2);
            dead_tmp(tmp);
2323 2324
            return 1;
        }
2325 2326
        dead_tmp(tmp2);
        dead_tmp(tmp);
2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        break;
    default:
        return 1;
    }

    return 0;
}

/* Disassemble an XScale DSP instruction.  Returns nonzero if an error occured
   (ie. an undefined instruction).  */
static int disas_dsp_insn(CPUState *env, DisasContext *s, uint32_t insn)
{
    int acc, rd0, rd1, rdhi, rdlo;
2342
    TCGv tmp, tmp2;
2343 2344 2345 2346 2347 2348 2349 2350 2351 2352

    if ((insn & 0x0ff00f10) == 0x0e200010) {
        /* Multiply with Internal Accumulate Format */
        rd0 = (insn >> 12) & 0xf;
        rd1 = insn & 0xf;
        acc = (insn >> 5) & 7;

        if (acc != 0)
            return 1;

2353 2354
        tmp = load_reg(s, rd0);
        tmp2 = load_reg(s, rd1);
2355 2356
        switch ((insn >> 16) & 0xf) {
        case 0x0:					/* MIA */
2357
            gen_helper_iwmmxt_muladdsl(cpu_M0, cpu_M0, tmp, tmp2);
2358 2359
            break;
        case 0x8:					/* MIAPH */
2360
            gen_helper_iwmmxt_muladdsw(cpu_M0, cpu_M0, tmp, tmp2);
2361 2362 2363 2364 2365 2366
            break;
        case 0xc:					/* MIABB */
        case 0xd:					/* MIABT */
        case 0xe:					/* MIATB */
        case 0xf:					/* MIATT */
            if (insn & (1 << 16))
2367
                tcg_gen_shri_i32(tmp, tmp, 16);
2368
            if (insn & (1 << 17))
2369 2370
                tcg_gen_shri_i32(tmp2, tmp2, 16);
            gen_helper_iwmmxt_muladdswl(cpu_M0, cpu_M0, tmp, tmp2);
2371 2372 2373 2374
            break;
        default:
            return 1;
        }
2375 2376
        dead_tmp(tmp2);
        dead_tmp(tmp);
2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391

        gen_op_iwmmxt_movq_wRn_M0(acc);
        return 0;
    }

    if ((insn & 0x0fe00ff8) == 0x0c400000) {
        /* Internal Accumulator Access Format */
        rdhi = (insn >> 16) & 0xf;
        rdlo = (insn >> 12) & 0xf;
        acc = insn & 7;

        if (acc != 0)
            return 1;

        if (insn & ARM_CP_RW_BIT) {			/* MRA */
2392 2393 2394 2395 2396
            iwmmxt_load_reg(cpu_V0, acc);
            tcg_gen_trunc_i64_i32(cpu_R[rdlo], cpu_V0);
            tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
            tcg_gen_trunc_i64_i32(cpu_R[rdhi], cpu_V0);
            tcg_gen_andi_i32(cpu_R[rdhi], cpu_R[rdhi], (1 << (40 - 32)) - 1);
2397
        } else {					/* MAR */
2398 2399
            tcg_gen_concat_i32_i64(cpu_V0, cpu_R[rdlo], cpu_R[rdhi]);
            iwmmxt_store_reg(cpu_V0, acc);
2400 2401 2402 2403 2404 2405 2406
        }
        return 0;
    }

    return 1;
}

2407 2408 2409 2410
/* Disassemble system coprocessor instruction.  Return nonzero if
   instruction is not defined.  */
static int disas_cp_insn(CPUState *env, DisasContext *s, uint32_t insn)
{
2411
    TCGv tmp, tmp2;
2412 2413 2414 2415 2416 2417
    uint32_t rd = (insn >> 12) & 0xf;
    uint32_t cp = (insn >> 8) & 0xf;
    if (IS_USER(s)) {
        return 1;
    }

2418
    if (insn & ARM_CP_RW_BIT) {
2419 2420
        if (!env->cp[cp].cp_read)
            return 1;
P
pbrook 已提交
2421 2422
        gen_set_pc_im(s->pc);
        tmp = new_tmp();
2423 2424 2425
        tmp2 = tcg_const_i32(insn);
        gen_helper_get_cp(tmp, cpu_env, tmp2);
        tcg_temp_free(tmp2);
P
pbrook 已提交
2426
        store_reg(s, rd, tmp);
2427 2428 2429
    } else {
        if (!env->cp[cp].cp_write)
            return 1;
P
pbrook 已提交
2430 2431
        gen_set_pc_im(s->pc);
        tmp = load_reg(s, rd);
2432 2433 2434
        tmp2 = tcg_const_i32(insn);
        gen_helper_set_cp(cpu_env, tmp2, tmp);
        tcg_temp_free(tmp2);
B
balrog 已提交
2435
        dead_tmp(tmp);
2436 2437 2438 2439
    }
    return 0;
}

P
pbrook 已提交
2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459
static int cp15_user_ok(uint32_t insn)
{
    int cpn = (insn >> 16) & 0xf;
    int cpm = insn & 0xf;
    int op = ((insn >> 5) & 7) | ((insn >> 18) & 0x38);

    if (cpn == 13 && cpm == 0) {
        /* TLS register.  */
        if (op == 2 || (op == 3 && (insn & ARM_CP_RW_BIT)))
            return 1;
    }
    if (cpn == 7) {
        /* ISB, DSB, DMB.  */
        if ((cpm == 5 && op == 4)
                || (cpm == 10 && (op == 4 || op == 5)))
            return 1;
    }
    return 0;
}

2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475
static int cp15_tls_load_store(CPUState *env, DisasContext *s, uint32_t insn, uint32_t rd)
{
    TCGv tmp;
    int cpn = (insn >> 16) & 0xf;
    int cpm = insn & 0xf;
    int op = ((insn >> 5) & 7) | ((insn >> 18) & 0x38);

    if (!arm_feature(env, ARM_FEATURE_V6K))
        return 0;

    if (!(cpn == 13 && cpm == 0))
        return 0;

    if (insn & ARM_CP_RW_BIT) {
        switch (op) {
        case 2:
P
Paul Brook 已提交
2476
            tmp = load_cpu_field(cp15.c13_tls1);
2477 2478
            break;
        case 3:
P
Paul Brook 已提交
2479
            tmp = load_cpu_field(cp15.c13_tls2);
2480 2481
            break;
        case 4:
P
Paul Brook 已提交
2482
            tmp = load_cpu_field(cp15.c13_tls3);
2483 2484 2485 2486 2487 2488 2489 2490 2491 2492
            break;
        default:
            return 0;
        }
        store_reg(s, rd, tmp);

    } else {
        tmp = load_reg(s, rd);
        switch (op) {
        case 2:
P
Paul Brook 已提交
2493
            store_cpu_field(tmp, cp15.c13_tls1);
2494 2495
            break;
        case 3:
P
Paul Brook 已提交
2496
            store_cpu_field(tmp, cp15.c13_tls2);
2497 2498
            break;
        case 4:
P
Paul Brook 已提交
2499
            store_cpu_field(tmp, cp15.c13_tls3);
2500 2501
            break;
        default:
P
Paul Brook 已提交
2502
            dead_tmp(tmp);
2503 2504 2505 2506 2507 2508
            return 0;
        }
    }
    return 1;
}

B
bellard 已提交
2509 2510
/* Disassemble system coprocessor (cp15) instruction.  Return nonzero if
   instruction is not defined.  */
2511
static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn)
B
bellard 已提交
2512 2513
{
    uint32_t rd;
2514
    TCGv tmp, tmp2;
B
bellard 已提交
2515

P
pbrook 已提交
2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532
    /* M profile cores use memory mapped registers instead of cp15.  */
    if (arm_feature(env, ARM_FEATURE_M))
	return 1;

    if ((insn & (1 << 25)) == 0) {
        if (insn & (1 << 20)) {
            /* mrrc */
            return 1;
        }
        /* mcrr.  Used for block cache operations, so implement as no-op.  */
        return 0;
    }
    if ((insn & (1 << 4)) == 0) {
        /* cdp */
        return 1;
    }
    if (IS_USER(s) && !cp15_user_ok(insn)) {
B
bellard 已提交
2533 2534
        return 1;
    }
B
bellard 已提交
2535 2536 2537
    if ((insn & 0x0fff0fff) == 0x0e070f90
        || (insn & 0x0fff0fff) == 0x0e070f58) {
        /* Wait for interrupt.  */
P
pbrook 已提交
2538
        gen_set_pc_im(s->pc);
P
pbrook 已提交
2539
        s->is_jmp = DISAS_WFI;
B
bellard 已提交
2540 2541
        return 0;
    }
B
bellard 已提交
2542
    rd = (insn >> 12) & 0xf;
2543 2544 2545 2546

    if (cp15_tls_load_store(env, s, insn, rd))
        return 0;

2547
    tmp2 = tcg_const_i32(insn);
2548
    if (insn & ARM_CP_RW_BIT) {
P
pbrook 已提交
2549
        tmp = new_tmp();
2550
        gen_helper_get_cp15(tmp, cpu_env, tmp2);
B
bellard 已提交
2551 2552
        /* If the destination register is r15 then sets condition codes.  */
        if (rd != 15)
P
pbrook 已提交
2553 2554 2555
            store_reg(s, rd, tmp);
        else
            dead_tmp(tmp);
B
bellard 已提交
2556
    } else {
P
pbrook 已提交
2557
        tmp = load_reg(s, rd);
2558
        gen_helper_set_cp15(cpu_env, tmp2, tmp);
P
pbrook 已提交
2559
        dead_tmp(tmp);
2560 2561 2562 2563 2564 2565
        /* Normally we would always end the TB here, but Linux
         * arch/arm/mach-pxa/sleep.S expects two instructions following
         * an MMU enable to execute from cache.  Imitate this behaviour.  */
        if (!arm_feature(env, ARM_FEATURE_XSCALE) ||
                (insn & 0x0fff0fff) != 0x0e010f10)
            gen_lookup_tb(s);
B
bellard 已提交
2566
    }
2567
    tcg_temp_free_i32(tmp2);
B
bellard 已提交
2568 2569 2570
    return 0;
}

P
pbrook 已提交
2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590
#define VFP_REG_SHR(x, n) (((n) > 0) ? (x) >> (n) : (x) << -(n))
#define VFP_SREG(insn, bigbit, smallbit) \
  ((VFP_REG_SHR(insn, bigbit - 1) & 0x1e) | (((insn) >> (smallbit)) & 1))
#define VFP_DREG(reg, insn, bigbit, smallbit) do { \
    if (arm_feature(env, ARM_FEATURE_VFP3)) { \
        reg = (((insn) >> (bigbit)) & 0x0f) \
              | (((insn) >> ((smallbit) - 4)) & 0x10); \
    } else { \
        if (insn & (1 << (smallbit))) \
            return 1; \
        reg = ((insn) >> (bigbit)) & 0x0f; \
    }} while (0)

#define VFP_SREG_D(insn) VFP_SREG(insn, 12, 22)
#define VFP_DREG_D(reg, insn) VFP_DREG(reg, insn, 12, 22)
#define VFP_SREG_N(insn) VFP_SREG(insn, 16,  7)
#define VFP_DREG_N(reg, insn) VFP_DREG(reg, insn, 16,  7)
#define VFP_SREG_M(insn) VFP_SREG(insn,  0,  5)
#define VFP_DREG_M(reg, insn) VFP_DREG(reg, insn,  0,  5)

P
pbrook 已提交
2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604
/* Move between integer and VFP cores.  */
static TCGv gen_vfp_mrs(void)
{
    TCGv tmp = new_tmp();
    tcg_gen_mov_i32(tmp, cpu_F0s);
    return tmp;
}

static void gen_vfp_msr(TCGv tmp)
{
    tcg_gen_mov_i32(cpu_F0s, tmp);
    dead_tmp(tmp);
}

P
pbrook 已提交
2605 2606 2607 2608 2609 2610
static inline int
vfp_enabled(CPUState * env)
{
    return ((env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) != 0);
}

P
pbrook 已提交
2611 2612 2613 2614 2615
static void gen_neon_dup_u8(TCGv var, int shift)
{
    TCGv tmp = new_tmp();
    if (shift)
        tcg_gen_shri_i32(var, var, shift);
P
pbrook 已提交
2616
    tcg_gen_ext8u_i32(var, var);
P
pbrook 已提交
2617 2618 2619 2620 2621 2622 2623 2624 2625 2626
    tcg_gen_shli_i32(tmp, var, 8);
    tcg_gen_or_i32(var, var, tmp);
    tcg_gen_shli_i32(tmp, var, 16);
    tcg_gen_or_i32(var, var, tmp);
    dead_tmp(tmp);
}

static void gen_neon_dup_low16(TCGv var)
{
    TCGv tmp = new_tmp();
P
pbrook 已提交
2627
    tcg_gen_ext16u_i32(var, var);
P
pbrook 已提交
2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641
    tcg_gen_shli_i32(tmp, var, 16);
    tcg_gen_or_i32(var, var, tmp);
    dead_tmp(tmp);
}

static void gen_neon_dup_high16(TCGv var)
{
    TCGv tmp = new_tmp();
    tcg_gen_andi_i32(var, var, 0xffff0000);
    tcg_gen_shri_i32(tmp, var, 16);
    tcg_gen_or_i32(var, var, tmp);
    dead_tmp(tmp);
}

B
bellard 已提交
2642 2643 2644 2645 2646 2647
/* Disassemble a VFP instruction.  Returns nonzero if an error occured
   (ie. an undefined instruction).  */
static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
{
    uint32_t rd, rn, rm, op, i, n, offset, delta_d, delta_m, bank_mask;
    int dp, veclen;
2648
    TCGv addr;
P
pbrook 已提交
2649
    TCGv tmp;
P
pbrook 已提交
2650
    TCGv tmp2;
B
bellard 已提交
2651

P
pbrook 已提交
2652 2653 2654
    if (!arm_feature(env, ARM_FEATURE_VFP))
        return 1;

P
pbrook 已提交
2655 2656
    if (!vfp_enabled(env)) {
        /* VFP disabled.  Only allow fmxr/fmrx to/from some control regs.  */
P
pbrook 已提交
2657 2658 2659
        if ((insn & 0x0fe00fff) != 0x0ee00a10)
            return 1;
        rn = (insn >> 16) & 0xf;
P
pbrook 已提交
2660 2661
        if (rn != ARM_VFP_FPSID && rn != ARM_VFP_FPEXC
            && rn != ARM_VFP_MVFR1 && rn != ARM_VFP_MVFR0)
P
pbrook 已提交
2662 2663
            return 1;
    }
B
bellard 已提交
2664 2665 2666 2667 2668 2669 2670
    dp = ((insn & 0xf00) == 0xb00);
    switch ((insn >> 24) & 0xf) {
    case 0xe:
        if (insn & (1 << 4)) {
            /* single register transfer */
            rd = (insn >> 12) & 0xf;
            if (dp) {
P
pbrook 已提交
2671 2672 2673 2674 2675
                int size;
                int pass;

                VFP_DREG_N(rn, insn);
                if (insn & 0xf)
B
bellard 已提交
2676
                    return 1;
P
pbrook 已提交
2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691
                if (insn & 0x00c00060
                    && !arm_feature(env, ARM_FEATURE_NEON))
                    return 1;

                pass = (insn >> 21) & 1;
                if (insn & (1 << 22)) {
                    size = 0;
                    offset = ((insn >> 5) & 3) * 8;
                } else if (insn & (1 << 5)) {
                    size = 1;
                    offset = (insn & (1 << 6)) ? 16 : 0;
                } else {
                    size = 2;
                    offset = 0;
                }
2692
                if (insn & ARM_CP_RW_BIT) {
B
bellard 已提交
2693
                    /* vfp->arm */
P
pbrook 已提交
2694
                    tmp = neon_load_reg(rn, pass);
P
pbrook 已提交
2695 2696 2697
                    switch (size) {
                    case 0:
                        if (offset)
P
pbrook 已提交
2698
                            tcg_gen_shri_i32(tmp, tmp, offset);
P
pbrook 已提交
2699
                        if (insn & (1 << 23))
P
pbrook 已提交
2700
                            gen_uxtb(tmp);
P
pbrook 已提交
2701
                        else
P
pbrook 已提交
2702
                            gen_sxtb(tmp);
P
pbrook 已提交
2703 2704 2705 2706
                        break;
                    case 1:
                        if (insn & (1 << 23)) {
                            if (offset) {
P
pbrook 已提交
2707
                                tcg_gen_shri_i32(tmp, tmp, 16);
P
pbrook 已提交
2708
                            } else {
P
pbrook 已提交
2709
                                gen_uxth(tmp);
P
pbrook 已提交
2710 2711 2712
                            }
                        } else {
                            if (offset) {
P
pbrook 已提交
2713
                                tcg_gen_sari_i32(tmp, tmp, 16);
P
pbrook 已提交
2714
                            } else {
P
pbrook 已提交
2715
                                gen_sxth(tmp);
P
pbrook 已提交
2716 2717 2718 2719 2720 2721
                            }
                        }
                        break;
                    case 2:
                        break;
                    }
P
pbrook 已提交
2722
                    store_reg(s, rd, tmp);
B
bellard 已提交
2723 2724
                } else {
                    /* arm->vfp */
P
pbrook 已提交
2725
                    tmp = load_reg(s, rd);
P
pbrook 已提交
2726 2727 2728
                    if (insn & (1 << 23)) {
                        /* VDUP */
                        if (size == 0) {
P
pbrook 已提交
2729
                            gen_neon_dup_u8(tmp, 0);
P
pbrook 已提交
2730
                        } else if (size == 1) {
P
pbrook 已提交
2731
                            gen_neon_dup_low16(tmp);
P
pbrook 已提交
2732
                        }
P
pbrook 已提交
2733 2734 2735 2736 2737 2738
                        for (n = 0; n <= pass * 2; n++) {
                            tmp2 = new_tmp();
                            tcg_gen_mov_i32(tmp2, tmp);
                            neon_store_reg(rn, n, tmp2);
                        }
                        neon_store_reg(rn, n, tmp);
P
pbrook 已提交
2739 2740 2741 2742
                    } else {
                        /* VMOV */
                        switch (size) {
                        case 0:
P
pbrook 已提交
2743 2744 2745
                            tmp2 = neon_load_reg(rn, pass);
                            gen_bfi(tmp, tmp2, tmp, offset, 0xff);
                            dead_tmp(tmp2);
P
pbrook 已提交
2746 2747
                            break;
                        case 1:
P
pbrook 已提交
2748 2749 2750
                            tmp2 = neon_load_reg(rn, pass);
                            gen_bfi(tmp, tmp2, tmp, offset, 0xffff);
                            dead_tmp(tmp2);
P
pbrook 已提交
2751 2752 2753 2754
                            break;
                        case 2:
                            break;
                        }
P
pbrook 已提交
2755
                        neon_store_reg(rn, pass, tmp);
P
pbrook 已提交
2756
                    }
B
bellard 已提交
2757
                }
P
pbrook 已提交
2758 2759 2760 2761
            } else { /* !dp */
                if ((insn & 0x6f) != 0x00)
                    return 1;
                rn = VFP_SREG_N(insn);
2762
                if (insn & ARM_CP_RW_BIT) {
B
bellard 已提交
2763 2764 2765
                    /* vfp->arm */
                    if (insn & (1 << 21)) {
                        /* system register */
P
pbrook 已提交
2766
                        rn >>= 1;
P
pbrook 已提交
2767

B
bellard 已提交
2768
                        switch (rn) {
P
pbrook 已提交
2769
                        case ARM_VFP_FPSID:
P
pbrook 已提交
2770
                            /* VFP2 allows access to FSID from userspace.
P
pbrook 已提交
2771 2772 2773 2774 2775
                               VFP3 restricts all id registers to privileged
                               accesses.  */
                            if (IS_USER(s)
                                && arm_feature(env, ARM_FEATURE_VFP3))
                                return 1;
P
pbrook 已提交
2776
                            tmp = load_cpu_field(vfp.xregs[rn]);
P
pbrook 已提交
2777
                            break;
P
pbrook 已提交
2778
                        case ARM_VFP_FPEXC:
P
pbrook 已提交
2779 2780
                            if (IS_USER(s))
                                return 1;
P
pbrook 已提交
2781
                            tmp = load_cpu_field(vfp.xregs[rn]);
P
pbrook 已提交
2782
                            break;
P
pbrook 已提交
2783 2784
                        case ARM_VFP_FPINST:
                        case ARM_VFP_FPINST2:
P
pbrook 已提交
2785 2786 2787 2788
                            /* Not present in VFP3.  */
                            if (IS_USER(s)
                                || arm_feature(env, ARM_FEATURE_VFP3))
                                return 1;
P
pbrook 已提交
2789
                            tmp = load_cpu_field(vfp.xregs[rn]);
B
bellard 已提交
2790
                            break;
P
pbrook 已提交
2791
                        case ARM_VFP_FPSCR:
2792
                            if (rd == 15) {
P
pbrook 已提交
2793 2794 2795 2796 2797 2798
                                tmp = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]);
                                tcg_gen_andi_i32(tmp, tmp, 0xf0000000);
                            } else {
                                tmp = new_tmp();
                                gen_helper_vfp_get_fpscr(tmp, cpu_env);
                            }
B
bellard 已提交
2799
                            break;
P
pbrook 已提交
2800 2801 2802 2803 2804
                        case ARM_VFP_MVFR0:
                        case ARM_VFP_MVFR1:
                            if (IS_USER(s)
                                || !arm_feature(env, ARM_FEATURE_VFP3))
                                return 1;
P
pbrook 已提交
2805
                            tmp = load_cpu_field(vfp.xregs[rn]);
P
pbrook 已提交
2806
                            break;
B
bellard 已提交
2807 2808 2809 2810 2811
                        default:
                            return 1;
                        }
                    } else {
                        gen_mov_F0_vreg(0, rn);
P
pbrook 已提交
2812
                        tmp = gen_vfp_mrs();
B
bellard 已提交
2813 2814
                    }
                    if (rd == 15) {
B
bellard 已提交
2815
                        /* Set the 4 flag bits in the CPSR.  */
P
pbrook 已提交
2816 2817 2818 2819 2820
                        gen_set_nzcv(tmp);
                        dead_tmp(tmp);
                    } else {
                        store_reg(s, rd, tmp);
                    }
B
bellard 已提交
2821 2822
                } else {
                    /* arm->vfp */
P
pbrook 已提交
2823
                    tmp = load_reg(s, rd);
B
bellard 已提交
2824
                    if (insn & (1 << 21)) {
P
pbrook 已提交
2825
                        rn >>= 1;
B
bellard 已提交
2826 2827
                        /* system register */
                        switch (rn) {
P
pbrook 已提交
2828
                        case ARM_VFP_FPSID:
P
pbrook 已提交
2829 2830
                        case ARM_VFP_MVFR0:
                        case ARM_VFP_MVFR1:
B
bellard 已提交
2831 2832
                            /* Writes are ignored.  */
                            break;
P
pbrook 已提交
2833
                        case ARM_VFP_FPSCR:
P
pbrook 已提交
2834 2835
                            gen_helper_vfp_set_fpscr(cpu_env, tmp);
                            dead_tmp(tmp);
B
bellard 已提交
2836
                            gen_lookup_tb(s);
B
bellard 已提交
2837
                            break;
P
pbrook 已提交
2838
                        case ARM_VFP_FPEXC:
P
pbrook 已提交
2839 2840
                            if (IS_USER(s))
                                return 1;
2841 2842 2843
                            /* TODO: VFP subarchitecture support.
                             * For now, keep the EN bit only */
                            tcg_gen_andi_i32(tmp, tmp, 1 << 30);
P
pbrook 已提交
2844
                            store_cpu_field(tmp, vfp.xregs[rn]);
P
pbrook 已提交
2845 2846 2847 2848
                            gen_lookup_tb(s);
                            break;
                        case ARM_VFP_FPINST:
                        case ARM_VFP_FPINST2:
P
pbrook 已提交
2849
                            store_cpu_field(tmp, vfp.xregs[rn]);
P
pbrook 已提交
2850
                            break;
B
bellard 已提交
2851 2852 2853 2854
                        default:
                            return 1;
                        }
                    } else {
P
pbrook 已提交
2855
                        gen_vfp_msr(tmp);
B
bellard 已提交
2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869
                        gen_mov_vreg_F0(0, rn);
                    }
                }
            }
        } else {
            /* data processing */
            /* The opcode is in bits 23, 21, 20 and 6.  */
            op = ((insn >> 20) & 8) | ((insn >> 19) & 6) | ((insn >> 6) & 1);
            if (dp) {
                if (op == 15) {
                    /* rn is opcode */
                    rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1);
                } else {
                    /* rn is register number */
P
pbrook 已提交
2870
                    VFP_DREG_N(rn, insn);
B
bellard 已提交
2871 2872 2873 2874
                }

                if (op == 15 && (rn == 15 || rn > 17)) {
                    /* Integer or single precision destination.  */
P
pbrook 已提交
2875
                    rd = VFP_SREG_D(insn);
B
bellard 已提交
2876
                } else {
P
pbrook 已提交
2877
                    VFP_DREG_D(rd, insn);
B
bellard 已提交
2878 2879 2880 2881 2882 2883
                }

                if (op == 15 && (rn == 16 || rn == 17)) {
                    /* Integer source.  */
                    rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1);
                } else {
P
pbrook 已提交
2884
                    VFP_DREG_M(rm, insn);
B
bellard 已提交
2885 2886
                }
            } else {
P
pbrook 已提交
2887
                rn = VFP_SREG_N(insn);
B
bellard 已提交
2888 2889
                if (op == 15 && rn == 15) {
                    /* Double precision destination.  */
P
pbrook 已提交
2890 2891 2892 2893 2894
                    VFP_DREG_D(rd, insn);
                } else {
                    rd = VFP_SREG_D(insn);
                }
                rm = VFP_SREG_M(insn);
B
bellard 已提交
2895 2896 2897 2898 2899 2900 2901 2902 2903 2904
            }

            veclen = env->vfp.vec_len;
            if (op == 15 && rn > 3)
                veclen = 0;

            /* Shut up compiler warnings.  */
            delta_m = 0;
            delta_d = 0;
            bank_mask = 0;
2905

B
bellard 已提交
2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951
            if (veclen > 0) {
                if (dp)
                    bank_mask = 0xc;
                else
                    bank_mask = 0x18;

                /* Figure out what type of vector operation this is.  */
                if ((rd & bank_mask) == 0) {
                    /* scalar */
                    veclen = 0;
                } else {
                    if (dp)
                        delta_d = (env->vfp.vec_stride >> 1) + 1;
                    else
                        delta_d = env->vfp.vec_stride + 1;

                    if ((rm & bank_mask) == 0) {
                        /* mixed scalar/vector */
                        delta_m = 0;
                    } else {
                        /* vector */
                        delta_m = delta_d;
                    }
                }
            }

            /* Load the initial operands.  */
            if (op == 15) {
                switch (rn) {
                case 16:
                case 17:
                    /* Integer source */
                    gen_mov_F0_vreg(0, rm);
                    break;
                case 8:
                case 9:
                    /* Compare */
                    gen_mov_F0_vreg(dp, rd);
                    gen_mov_F1_vreg(dp, rm);
                    break;
                case 10:
                case 11:
                    /* Compare with zero */
                    gen_mov_F0_vreg(dp, rd);
                    gen_vfp_F1_ld0(dp);
                    break;
P
pbrook 已提交
2952 2953 2954 2955
                case 20:
                case 21:
                case 22:
                case 23:
P
pbrook 已提交
2956 2957 2958 2959
                case 28:
                case 29:
                case 30:
                case 31:
P
pbrook 已提交
2960 2961 2962
                    /* Source and destination the same.  */
                    gen_mov_F0_vreg(dp, rd);
                    break;
B
bellard 已提交
2963 2964 2965
                default:
                    /* One source operand.  */
                    gen_mov_F0_vreg(dp, rm);
P
pbrook 已提交
2966
                    break;
B
bellard 已提交
2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995
                }
            } else {
                /* Two source operands.  */
                gen_mov_F0_vreg(dp, rn);
                gen_mov_F1_vreg(dp, rm);
            }

            for (;;) {
                /* Perform the calculation.  */
                switch (op) {
                case 0: /* mac: fd + (fn * fm) */
                    gen_vfp_mul(dp);
                    gen_mov_F1_vreg(dp, rd);
                    gen_vfp_add(dp);
                    break;
                case 1: /* nmac: fd - (fn * fm) */
                    gen_vfp_mul(dp);
                    gen_vfp_neg(dp);
                    gen_mov_F1_vreg(dp, rd);
                    gen_vfp_add(dp);
                    break;
                case 2: /* msc: -fd + (fn * fm) */
                    gen_vfp_mul(dp);
                    gen_mov_F1_vreg(dp, rd);
                    gen_vfp_sub(dp);
                    break;
                case 3: /* nmsc: -fd - (fn * fm)  */
                    gen_vfp_mul(dp);
                    gen_vfp_neg(dp);
P
pbrook 已提交
2996 2997
                    gen_mov_F1_vreg(dp, rd);
                    gen_vfp_sub(dp);
B
bellard 已提交
2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014
                    break;
                case 4: /* mul: fn * fm */
                    gen_vfp_mul(dp);
                    break;
                case 5: /* nmul: -(fn * fm) */
                    gen_vfp_mul(dp);
                    gen_vfp_neg(dp);
                    break;
                case 6: /* add: fn + fm */
                    gen_vfp_add(dp);
                    break;
                case 7: /* sub: fn - fm */
                    gen_vfp_sub(dp);
                    break;
                case 8: /* div: fn / fm */
                    gen_vfp_div(dp);
                    break;
P
pbrook 已提交
3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026
                case 14: /* fconst */
                    if (!arm_feature(env, ARM_FEATURE_VFP3))
                      return 1;

                    n = (insn << 12) & 0x80000000;
                    i = ((insn >> 12) & 0x70) | (insn & 0xf);
                    if (dp) {
                        if (i & 0x40)
                            i |= 0x3f80;
                        else
                            i |= 0x4000;
                        n |= i << 16;
P
pbrook 已提交
3027
                        tcg_gen_movi_i64(cpu_F0d, ((uint64_t)n) << 32);
P
pbrook 已提交
3028 3029 3030 3031 3032 3033
                    } else {
                        if (i & 0x40)
                            i |= 0x780;
                        else
                            i |= 0x800;
                        n |= i << 19;
B
balrog 已提交
3034
                        tcg_gen_movi_i32(cpu_F0s, n);
P
pbrook 已提交
3035 3036
                    }
                    break;
B
bellard 已提交
3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050
                case 15: /* extension space */
                    switch (rn) {
                    case 0: /* cpy */
                        /* no-op */
                        break;
                    case 1: /* abs */
                        gen_vfp_abs(dp);
                        break;
                    case 2: /* neg */
                        gen_vfp_neg(dp);
                        break;
                    case 3: /* sqrt */
                        gen_vfp_sqrt(dp);
                        break;
P
Paul Brook 已提交
3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091
                    case 4: /* vcvtb.f32.f16 */
                        if (!arm_feature(env, ARM_FEATURE_VFP_FP16))
                          return 1;
                        tmp = gen_vfp_mrs();
                        tcg_gen_ext16u_i32(tmp, tmp);
                        gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp, cpu_env);
                        dead_tmp(tmp);
                        break;
                    case 5: /* vcvtt.f32.f16 */
                        if (!arm_feature(env, ARM_FEATURE_VFP_FP16))
                          return 1;
                        tmp = gen_vfp_mrs();
                        tcg_gen_shri_i32(tmp, tmp, 16);
                        gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp, cpu_env);
                        dead_tmp(tmp);
                        break;
                    case 6: /* vcvtb.f16.f32 */
                        if (!arm_feature(env, ARM_FEATURE_VFP_FP16))
                          return 1;
                        tmp = new_tmp();
                        gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
                        gen_mov_F0_vreg(0, rd);
                        tmp2 = gen_vfp_mrs();
                        tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000);
                        tcg_gen_or_i32(tmp, tmp, tmp2);
                        dead_tmp(tmp2);
                        gen_vfp_msr(tmp);
                        break;
                    case 7: /* vcvtt.f16.f32 */
                        if (!arm_feature(env, ARM_FEATURE_VFP_FP16))
                          return 1;
                        tmp = new_tmp();
                        gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
                        tcg_gen_shli_i32(tmp, tmp, 16);
                        gen_mov_F0_vreg(0, rd);
                        tmp2 = gen_vfp_mrs();
                        tcg_gen_ext16u_i32(tmp2, tmp2);
                        tcg_gen_or_i32(tmp, tmp, tmp2);
                        dead_tmp(tmp2);
                        gen_vfp_msr(tmp);
                        break;
B
bellard 已提交
3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106
                    case 8: /* cmp */
                        gen_vfp_cmp(dp);
                        break;
                    case 9: /* cmpe */
                        gen_vfp_cmpe(dp);
                        break;
                    case 10: /* cmpz */
                        gen_vfp_cmp(dp);
                        break;
                    case 11: /* cmpez */
                        gen_vfp_F1_ld0(dp);
                        gen_vfp_cmpe(dp);
                        break;
                    case 15: /* single<->double conversion */
                        if (dp)
P
pbrook 已提交
3107
                            gen_helper_vfp_fcvtsd(cpu_F0s, cpu_F0d, cpu_env);
B
bellard 已提交
3108
                        else
P
pbrook 已提交
3109
                            gen_helper_vfp_fcvtds(cpu_F0d, cpu_F0s, cpu_env);
B
bellard 已提交
3110 3111 3112 3113 3114 3115 3116
                        break;
                    case 16: /* fuito */
                        gen_vfp_uito(dp);
                        break;
                    case 17: /* fsito */
                        gen_vfp_sito(dp);
                        break;
P
pbrook 已提交
3117 3118 3119
                    case 20: /* fshto */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
P
pbrook 已提交
3120
                        gen_vfp_shto(dp, 16 - rm);
P
pbrook 已提交
3121 3122 3123 3124
                        break;
                    case 21: /* fslto */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
P
pbrook 已提交
3125
                        gen_vfp_slto(dp, 32 - rm);
P
pbrook 已提交
3126 3127 3128 3129
                        break;
                    case 22: /* fuhto */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
P
pbrook 已提交
3130
                        gen_vfp_uhto(dp, 16 - rm);
P
pbrook 已提交
3131 3132 3133 3134
                        break;
                    case 23: /* fulto */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
P
pbrook 已提交
3135
                        gen_vfp_ulto(dp, 32 - rm);
P
pbrook 已提交
3136
                        break;
B
bellard 已提交
3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148
                    case 24: /* ftoui */
                        gen_vfp_toui(dp);
                        break;
                    case 25: /* ftouiz */
                        gen_vfp_touiz(dp);
                        break;
                    case 26: /* ftosi */
                        gen_vfp_tosi(dp);
                        break;
                    case 27: /* ftosiz */
                        gen_vfp_tosiz(dp);
                        break;
P
pbrook 已提交
3149 3150 3151
                    case 28: /* ftosh */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
P
pbrook 已提交
3152
                        gen_vfp_tosh(dp, 16 - rm);
P
pbrook 已提交
3153 3154 3155 3156
                        break;
                    case 29: /* ftosl */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
P
pbrook 已提交
3157
                        gen_vfp_tosl(dp, 32 - rm);
P
pbrook 已提交
3158 3159 3160 3161
                        break;
                    case 30: /* ftouh */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
P
pbrook 已提交
3162
                        gen_vfp_touh(dp, 16 - rm);
P
pbrook 已提交
3163 3164 3165 3166
                        break;
                    case 31: /* ftoul */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
P
pbrook 已提交
3167
                        gen_vfp_toul(dp, 32 - rm);
P
pbrook 已提交
3168
                        break;
B
bellard 已提交
3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229
                    default: /* undefined */
                        printf ("rn:%d\n", rn);
                        return 1;
                    }
                    break;
                default: /* undefined */
                    printf ("op:%d\n", op);
                    return 1;
                }

                /* Write back the result.  */
                if (op == 15 && (rn >= 8 && rn <= 11))
                    ; /* Comparison, do nothing.  */
                else if (op == 15 && rn > 17)
                    /* Integer result.  */
                    gen_mov_vreg_F0(0, rd);
                else if (op == 15 && rn == 15)
                    /* conversion */
                    gen_mov_vreg_F0(!dp, rd);
                else
                    gen_mov_vreg_F0(dp, rd);

                /* break out of the loop if we have finished  */
                if (veclen == 0)
                    break;

                if (op == 15 && delta_m == 0) {
                    /* single source one-many */
                    while (veclen--) {
                        rd = ((rd + delta_d) & (bank_mask - 1))
                             | (rd & bank_mask);
                        gen_mov_vreg_F0(dp, rd);
                    }
                    break;
                }
                /* Setup the next operands.  */
                veclen--;
                rd = ((rd + delta_d) & (bank_mask - 1))
                     | (rd & bank_mask);

                if (op == 15) {
                    /* One source operand.  */
                    rm = ((rm + delta_m) & (bank_mask - 1))
                         | (rm & bank_mask);
                    gen_mov_F0_vreg(dp, rm);
                } else {
                    /* Two source operands.  */
                    rn = ((rn + delta_d) & (bank_mask - 1))
                         | (rn & bank_mask);
                    gen_mov_F0_vreg(dp, rn);
                    if (delta_m) {
                        rm = ((rm + delta_m) & (bank_mask - 1))
                             | (rm & bank_mask);
                        gen_mov_F1_vreg(dp, rm);
                    }
                }
            }
        }
        break;
    case 0xc:
    case 0xd:
P
pbrook 已提交
3230
        if (dp && (insn & 0x03e00000) == 0x00400000) {
B
bellard 已提交
3231 3232 3233 3234
            /* two-register transfer */
            rn = (insn >> 16) & 0xf;
            rd = (insn >> 12) & 0xf;
            if (dp) {
P
pbrook 已提交
3235 3236 3237 3238
                VFP_DREG_M(rm, insn);
            } else {
                rm = VFP_SREG_M(insn);
            }
B
bellard 已提交
3239

3240
            if (insn & ARM_CP_RW_BIT) {
B
bellard 已提交
3241 3242
                /* vfp->arm */
                if (dp) {
P
pbrook 已提交
3243 3244 3245 3246 3247 3248
                    gen_mov_F0_vreg(0, rm * 2);
                    tmp = gen_vfp_mrs();
                    store_reg(s, rd, tmp);
                    gen_mov_F0_vreg(0, rm * 2 + 1);
                    tmp = gen_vfp_mrs();
                    store_reg(s, rn, tmp);
B
bellard 已提交
3249 3250
                } else {
                    gen_mov_F0_vreg(0, rm);
P
pbrook 已提交
3251 3252
                    tmp = gen_vfp_mrs();
                    store_reg(s, rn, tmp);
B
bellard 已提交
3253
                    gen_mov_F0_vreg(0, rm + 1);
P
pbrook 已提交
3254 3255
                    tmp = gen_vfp_mrs();
                    store_reg(s, rd, tmp);
B
bellard 已提交
3256 3257 3258 3259
                }
            } else {
                /* arm->vfp */
                if (dp) {
P
pbrook 已提交
3260 3261 3262 3263 3264 3265
                    tmp = load_reg(s, rd);
                    gen_vfp_msr(tmp);
                    gen_mov_vreg_F0(0, rm * 2);
                    tmp = load_reg(s, rn);
                    gen_vfp_msr(tmp);
                    gen_mov_vreg_F0(0, rm * 2 + 1);
B
bellard 已提交
3266
                } else {
P
pbrook 已提交
3267 3268
                    tmp = load_reg(s, rn);
                    gen_vfp_msr(tmp);
B
bellard 已提交
3269
                    gen_mov_vreg_F0(0, rm);
P
pbrook 已提交
3270 3271
                    tmp = load_reg(s, rd);
                    gen_vfp_msr(tmp);
B
bellard 已提交
3272 3273 3274 3275 3276 3277 3278
                    gen_mov_vreg_F0(0, rm + 1);
                }
            }
        } else {
            /* Load/store */
            rn = (insn >> 16) & 0xf;
            if (dp)
P
pbrook 已提交
3279
                VFP_DREG_D(rd, insn);
B
bellard 已提交
3280
            else
P
pbrook 已提交
3281 3282
                rd = VFP_SREG_D(insn);
            if (s->thumb && rn == 15) {
3283 3284
                addr = new_tmp();
                tcg_gen_movi_i32(addr, s->pc & ~2);
P
pbrook 已提交
3285
            } else {
3286
                addr = load_reg(s, rn);
P
pbrook 已提交
3287
            }
B
bellard 已提交
3288 3289 3290 3291 3292
            if ((insn & 0x01200000) == 0x01000000) {
                /* Single load/store */
                offset = (insn & 0xff) << 2;
                if ((insn & (1 << 23)) == 0)
                    offset = -offset;
3293
                tcg_gen_addi_i32(addr, addr, offset);
B
bellard 已提交
3294
                if (insn & (1 << 20)) {
3295
                    gen_vfp_ld(s, dp, addr);
B
bellard 已提交
3296 3297 3298
                    gen_mov_vreg_F0(dp, rd);
                } else {
                    gen_mov_F0_vreg(dp, rd);
3299
                    gen_vfp_st(s, dp, addr);
B
bellard 已提交
3300
                }
3301
                dead_tmp(addr);
B
bellard 已提交
3302 3303 3304 3305 3306 3307 3308 3309
            } else {
                /* load/store multiple */
                if (dp)
                    n = (insn >> 1) & 0x7f;
                else
                    n = insn & 0xff;

                if (insn & (1 << 24)) /* pre-decrement */
3310
                    tcg_gen_addi_i32(addr, addr, -((insn & 0xff) << 2));
B
bellard 已提交
3311 3312 3313 3314 3315 3316

                if (dp)
                    offset = 8;
                else
                    offset = 4;
                for (i = 0; i < n; i++) {
3317
                    if (insn & ARM_CP_RW_BIT) {
B
bellard 已提交
3318
                        /* load */
3319
                        gen_vfp_ld(s, dp, addr);
B
bellard 已提交
3320 3321 3322 3323
                        gen_mov_vreg_F0(dp, rd + i);
                    } else {
                        /* store */
                        gen_mov_F0_vreg(dp, rd + i);
3324
                        gen_vfp_st(s, dp, addr);
B
bellard 已提交
3325
                    }
3326
                    tcg_gen_addi_i32(addr, addr, offset);
B
bellard 已提交
3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337
                }
                if (insn & (1 << 21)) {
                    /* writeback */
                    if (insn & (1 << 24))
                        offset = -offset * n;
                    else if (dp && (insn & 1))
                        offset = 4;
                    else
                        offset = 0;

                    if (offset != 0)
3338 3339 3340 3341
                        tcg_gen_addi_i32(addr, addr, offset);
                    store_reg(s, rn, addr);
                } else {
                    dead_tmp(addr);
B
bellard 已提交
3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352
                }
            }
        }
        break;
    default:
        /* Should never happen.  */
        return 1;
    }
    return 0;
}

3353
static inline void gen_goto_tb(DisasContext *s, int n, uint32_t dest)
B
bellard 已提交
3354
{
3355 3356 3357 3358
    TranslationBlock *tb;

    tb = s->tb;
    if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
B
bellard 已提交
3359
        tcg_gen_goto_tb(n);
P
pbrook 已提交
3360
        gen_set_pc_im(dest);
B
bellard 已提交
3361
        tcg_gen_exit_tb((long)tb + n);
3362
    } else {
P
pbrook 已提交
3363
        gen_set_pc_im(dest);
B
bellard 已提交
3364
        tcg_gen_exit_tb(0);
3365
    }
B
bellard 已提交
3366 3367
}

B
bellard 已提交
3368 3369
static inline void gen_jmp (DisasContext *s, uint32_t dest)
{
3370
    if (unlikely(s->singlestep_enabled)) {
B
bellard 已提交
3371
        /* An indirect jump so that we still trigger the debug exception.  */
B
bellard 已提交
3372
        if (s->thumb)
P
pbrook 已提交
3373 3374
            dest |= 1;
        gen_bx_im(s, dest);
B
bellard 已提交
3375
    } else {
3376
        gen_goto_tb(s, 0, dest);
B
bellard 已提交
3377 3378 3379 3380
        s->is_jmp = DISAS_TB_JUMP;
    }
}

P
pbrook 已提交
3381
static inline void gen_mulxy(TCGv t0, TCGv t1, int x, int y)
B
bellard 已提交
3382
{
B
bellard 已提交
3383
    if (x)
P
pbrook 已提交
3384
        tcg_gen_sari_i32(t0, t0, 16);
B
bellard 已提交
3385
    else
P
pbrook 已提交
3386
        gen_sxth(t0);
B
bellard 已提交
3387
    if (y)
P
pbrook 已提交
3388
        tcg_gen_sari_i32(t1, t1, 16);
B
bellard 已提交
3389
    else
P
pbrook 已提交
3390 3391
        gen_sxth(t1);
    tcg_gen_mul_i32(t0, t0, t1);
B
bellard 已提交
3392 3393 3394
}

/* Return the mask of PSR bits set by a MSR instruction.  */
P
pbrook 已提交
3395
static uint32_t msr_mask(CPUState *env, DisasContext *s, int flags, int spsr) {
B
bellard 已提交
3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406
    uint32_t mask;

    mask = 0;
    if (flags & (1 << 0))
        mask |= 0xff;
    if (flags & (1 << 1))
        mask |= 0xff00;
    if (flags & (1 << 2))
        mask |= 0xff0000;
    if (flags & (1 << 3))
        mask |= 0xff000000;
P
pbrook 已提交
3407

P
pbrook 已提交
3408
    /* Mask out undefined bits.  */
P
pbrook 已提交
3409 3410
    mask &= ~CPSR_RESERVED;
    if (!arm_feature(env, ARM_FEATURE_V6))
P
pbrook 已提交
3411
        mask &= ~(CPSR_E | CPSR_GE);
P
pbrook 已提交
3412
    if (!arm_feature(env, ARM_FEATURE_THUMB2))
P
pbrook 已提交
3413
        mask &= ~CPSR_IT;
P
pbrook 已提交
3414
    /* Mask out execution state bits.  */
P
pbrook 已提交
3415
    if (!spsr)
P
pbrook 已提交
3416
        mask &= ~CPSR_EXEC;
B
bellard 已提交
3417 3418
    /* Mask out privileged bits.  */
    if (IS_USER(s))
P
pbrook 已提交
3419
        mask &= CPSR_USER;
B
bellard 已提交
3420 3421 3422
    return mask;
}

3423 3424
/* Returns nonzero if access to the PSR is not permitted. Marks t0 as dead. */
static int gen_set_psr(DisasContext *s, uint32_t mask, int spsr, TCGv t0)
B
bellard 已提交
3425
{
P
pbrook 已提交
3426
    TCGv tmp;
B
bellard 已提交
3427 3428 3429 3430
    if (spsr) {
        /* ??? This is also undefined in system mode.  */
        if (IS_USER(s))
            return 1;
P
pbrook 已提交
3431 3432 3433

        tmp = load_cpu_field(spsr);
        tcg_gen_andi_i32(tmp, tmp, ~mask);
3434 3435
        tcg_gen_andi_i32(t0, t0, mask);
        tcg_gen_or_i32(tmp, tmp, t0);
P
pbrook 已提交
3436
        store_cpu_field(tmp, spsr);
B
bellard 已提交
3437
    } else {
3438
        gen_set_cpsr(t0, mask);
B
bellard 已提交
3439
    }
3440
    dead_tmp(t0);
B
bellard 已提交
3441 3442 3443 3444
    gen_lookup_tb(s);
    return 0;
}

3445 3446 3447 3448 3449 3450 3451 3452 3453
/* Returns nonzero if access to the PSR is not permitted.  */
static int gen_set_psr_im(DisasContext *s, uint32_t mask, int spsr, uint32_t val)
{
    TCGv tmp;
    tmp = new_tmp();
    tcg_gen_movi_i32(tmp, val);
    return gen_set_psr(s, mask, spsr, tmp);
}

3454 3455
/* Generate an old-style exception return. Marks pc as dead. */
static void gen_exception_return(DisasContext *s, TCGv pc)
B
bellard 已提交
3456
{
P
pbrook 已提交
3457
    TCGv tmp;
3458
    store_reg(s, 15, pc);
P
pbrook 已提交
3459 3460 3461
    tmp = load_cpu_field(spsr);
    gen_set_cpsr(tmp, 0xffffffff);
    dead_tmp(tmp);
B
bellard 已提交
3462 3463 3464
    s->is_jmp = DISAS_UPDATE;
}

P
pbrook 已提交
3465 3466
/* Generate a v6 exception return.  Marks both values as dead.  */
static void gen_rfe(DisasContext *s, TCGv pc, TCGv cpsr)
B
bellard 已提交
3467
{
P
pbrook 已提交
3468 3469 3470
    gen_set_cpsr(cpsr, 0xffffffff);
    dead_tmp(cpsr);
    store_reg(s, 15, pc);
P
pbrook 已提交
3471 3472
    s->is_jmp = DISAS_UPDATE;
}
3473

P
pbrook 已提交
3474 3475 3476 3477
static inline void
gen_set_condexec (DisasContext *s)
{
    if (s->condexec_mask) {
P
pbrook 已提交
3478 3479 3480
        uint32_t val = (s->condexec_cond << 4) | (s->condexec_mask >> 1);
        TCGv tmp = new_tmp();
        tcg_gen_movi_i32(tmp, val);
P
pbrook 已提交
3481
        store_cpu_field(tmp, condexec_bits);
P
pbrook 已提交
3482 3483
    }
}
3484

P
pbrook 已提交
3485 3486 3487 3488
static void gen_nop_hint(DisasContext *s, int val)
{
    switch (val) {
    case 3: /* wfi */
P
pbrook 已提交
3489
        gen_set_pc_im(s->pc);
P
pbrook 已提交
3490 3491 3492 3493 3494 3495 3496 3497 3498
        s->is_jmp = DISAS_WFI;
        break;
    case 2: /* wfe */
    case 4: /* sev */
        /* TODO: Implement SEV and WFE.  May help SMP performance.  */
    default: /* nop */
        break;
    }
}
B
bellard 已提交
3499

P
pbrook 已提交
3500
#define CPU_V001 cpu_V0, cpu_V0, cpu_V1
P
pbrook 已提交
3501

3502
static inline int gen_neon_add(int size, TCGv t0, TCGv t1)
P
pbrook 已提交
3503 3504
{
    switch (size) {
3505 3506 3507
    case 0: gen_helper_neon_add_u8(t0, t0, t1); break;
    case 1: gen_helper_neon_add_u16(t0, t0, t1); break;
    case 2: tcg_gen_add_i32(t0, t0, t1); break;
P
pbrook 已提交
3508 3509 3510 3511 3512
    default: return 1;
    }
    return 0;
}

3513
static inline void gen_neon_rsb(int size, TCGv t0, TCGv t1)
P
pbrook 已提交
3514 3515
{
    switch (size) {
3516 3517 3518
    case 0: gen_helper_neon_sub_u8(t0, t1, t0); break;
    case 1: gen_helper_neon_sub_u16(t0, t1, t0); break;
    case 2: tcg_gen_sub_i32(t0, t1, t0); break;
P
pbrook 已提交
3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537
    default: return;
    }
}

/* 32-bit pairwise ops end up the same as the elementwise versions.  */
#define gen_helper_neon_pmax_s32  gen_helper_neon_max_s32
#define gen_helper_neon_pmax_u32  gen_helper_neon_max_u32
#define gen_helper_neon_pmin_s32  gen_helper_neon_min_s32
#define gen_helper_neon_pmin_u32  gen_helper_neon_min_u32

/* FIXME: This is wrong.  They set the wrong overflow bit.  */
#define gen_helper_neon_qadd_s32(a, e, b, c) gen_helper_add_saturate(a, b, c)
#define gen_helper_neon_qadd_u32(a, e, b, c) gen_helper_add_usaturate(a, b, c)
#define gen_helper_neon_qsub_s32(a, e, b, c) gen_helper_sub_saturate(a, b, c)
#define gen_helper_neon_qsub_u32(a, e, b, c) gen_helper_sub_usaturate(a, b, c)

#define GEN_NEON_INTEGER_OP_ENV(name) do { \
    switch ((size << 1) | u) { \
    case 0: \
3538
        gen_helper_neon_##name##_s8(tmp, cpu_env, tmp, tmp2); \
P
pbrook 已提交
3539 3540
        break; \
    case 1: \
3541
        gen_helper_neon_##name##_u8(tmp, cpu_env, tmp, tmp2); \
P
pbrook 已提交
3542 3543
        break; \
    case 2: \
3544
        gen_helper_neon_##name##_s16(tmp, cpu_env, tmp, tmp2); \
P
pbrook 已提交
3545 3546
        break; \
    case 3: \
3547
        gen_helper_neon_##name##_u16(tmp, cpu_env, tmp, tmp2); \
P
pbrook 已提交
3548 3549
        break; \
    case 4: \
3550
        gen_helper_neon_##name##_s32(tmp, cpu_env, tmp, tmp2); \
P
pbrook 已提交
3551 3552
        break; \
    case 5: \
3553
        gen_helper_neon_##name##_u32(tmp, cpu_env, tmp, tmp2); \
P
pbrook 已提交
3554 3555 3556
        break; \
    default: return 1; \
    }} while (0)
P
pbrook 已提交
3557 3558 3559

#define GEN_NEON_INTEGER_OP(name) do { \
    switch ((size << 1) | u) { \
P
pbrook 已提交
3560
    case 0: \
3561
        gen_helper_neon_##name##_s8(tmp, tmp, tmp2); \
P
pbrook 已提交
3562 3563
        break; \
    case 1: \
3564
        gen_helper_neon_##name##_u8(tmp, tmp, tmp2); \
P
pbrook 已提交
3565 3566
        break; \
    case 2: \
3567
        gen_helper_neon_##name##_s16(tmp, tmp, tmp2); \
P
pbrook 已提交
3568 3569
        break; \
    case 3: \
3570
        gen_helper_neon_##name##_u16(tmp, tmp, tmp2); \
P
pbrook 已提交
3571 3572
        break; \
    case 4: \
3573
        gen_helper_neon_##name##_s32(tmp, tmp, tmp2); \
P
pbrook 已提交
3574 3575
        break; \
    case 5: \
3576
        gen_helper_neon_##name##_u32(tmp, tmp, tmp2); \
P
pbrook 已提交
3577
        break; \
P
pbrook 已提交
3578 3579 3580
    default: return 1; \
    }} while (0)

3581
static TCGv neon_load_scratch(int scratch)
P
pbrook 已提交
3582
{
3583 3584 3585
    TCGv tmp = new_tmp();
    tcg_gen_ld_i32(tmp, cpu_env, offsetof(CPUARMState, vfp.scratch[scratch]));
    return tmp;
P
pbrook 已提交
3586 3587
}

3588
static void neon_store_scratch(int scratch, TCGv var)
P
pbrook 已提交
3589
{
3590 3591
    tcg_gen_st_i32(var, cpu_env, offsetof(CPUARMState, vfp.scratch[scratch]));
    dead_tmp(var);
P
pbrook 已提交
3592 3593
}

3594
static inline TCGv neon_get_scalar(int size, int reg)
P
pbrook 已提交
3595
{
3596
    TCGv tmp;
P
pbrook 已提交
3597
    if (size == 1) {
3598
        tmp = neon_load_reg(reg >> 1, reg & 1);
P
pbrook 已提交
3599
    } else {
3600 3601 3602 3603 3604 3605
        tmp = neon_load_reg(reg >> 2, (reg >> 1) & 1);
        if (reg & 1) {
            gen_neon_dup_low16(tmp);
        } else {
            gen_neon_dup_high16(tmp);
        }
P
pbrook 已提交
3606
    }
3607
    return tmp;
P
pbrook 已提交
3608 3609
}

3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700
static void gen_neon_unzip_u8(TCGv t0, TCGv t1)
{
    TCGv rd, rm, tmp;

    rd = new_tmp();
    rm = new_tmp();
    tmp = new_tmp();

    tcg_gen_andi_i32(rd, t0, 0xff);
    tcg_gen_shri_i32(tmp, t0, 8);
    tcg_gen_andi_i32(tmp, tmp, 0xff00);
    tcg_gen_or_i32(rd, rd, tmp);
    tcg_gen_shli_i32(tmp, t1, 16);
    tcg_gen_andi_i32(tmp, tmp, 0xff0000);
    tcg_gen_or_i32(rd, rd, tmp);
    tcg_gen_shli_i32(tmp, t1, 8);
    tcg_gen_andi_i32(tmp, tmp, 0xff000000);
    tcg_gen_or_i32(rd, rd, tmp);

    tcg_gen_shri_i32(rm, t0, 8);
    tcg_gen_andi_i32(rm, rm, 0xff);
    tcg_gen_shri_i32(tmp, t0, 16);
    tcg_gen_andi_i32(tmp, tmp, 0xff00);
    tcg_gen_or_i32(rm, rm, tmp);
    tcg_gen_shli_i32(tmp, t1, 8);
    tcg_gen_andi_i32(tmp, tmp, 0xff0000);
    tcg_gen_or_i32(rm, rm, tmp);
    tcg_gen_andi_i32(tmp, t1, 0xff000000);
    tcg_gen_or_i32(t1, rm, tmp);
    tcg_gen_mov_i32(t0, rd);

    dead_tmp(tmp);
    dead_tmp(rm);
    dead_tmp(rd);
}

static void gen_neon_zip_u8(TCGv t0, TCGv t1)
{
    TCGv rd, rm, tmp;

    rd = new_tmp();
    rm = new_tmp();
    tmp = new_tmp();

    tcg_gen_andi_i32(rd, t0, 0xff);
    tcg_gen_shli_i32(tmp, t1, 8);
    tcg_gen_andi_i32(tmp, tmp, 0xff00);
    tcg_gen_or_i32(rd, rd, tmp);
    tcg_gen_shli_i32(tmp, t0, 16);
    tcg_gen_andi_i32(tmp, tmp, 0xff0000);
    tcg_gen_or_i32(rd, rd, tmp);
    tcg_gen_shli_i32(tmp, t1, 24);
    tcg_gen_andi_i32(tmp, tmp, 0xff000000);
    tcg_gen_or_i32(rd, rd, tmp);

    tcg_gen_andi_i32(rm, t1, 0xff000000);
    tcg_gen_shri_i32(tmp, t0, 8);
    tcg_gen_andi_i32(tmp, tmp, 0xff0000);
    tcg_gen_or_i32(rm, rm, tmp);
    tcg_gen_shri_i32(tmp, t1, 8);
    tcg_gen_andi_i32(tmp, tmp, 0xff00);
    tcg_gen_or_i32(rm, rm, tmp);
    tcg_gen_shri_i32(tmp, t0, 16);
    tcg_gen_andi_i32(tmp, tmp, 0xff);
    tcg_gen_or_i32(t1, rm, tmp);
    tcg_gen_mov_i32(t0, rd);

    dead_tmp(tmp);
    dead_tmp(rm);
    dead_tmp(rd);
}

static void gen_neon_zip_u16(TCGv t0, TCGv t1)
{
    TCGv tmp, tmp2;

    tmp = new_tmp();
    tmp2 = new_tmp();

    tcg_gen_andi_i32(tmp, t0, 0xffff);
    tcg_gen_shli_i32(tmp2, t1, 16);
    tcg_gen_or_i32(tmp, tmp, tmp2);
    tcg_gen_andi_i32(t1, t1, 0xffff0000);
    tcg_gen_shri_i32(tmp2, t0, 16);
    tcg_gen_or_i32(t1, t1, tmp2);
    tcg_gen_mov_i32(t0, tmp);

    dead_tmp(tmp2);
    dead_tmp(tmp);
}

P
pbrook 已提交
3701 3702 3703
static void gen_neon_unzip(int reg, int q, int tmp, int size)
{
    int n;
3704
    TCGv t0, t1;
P
pbrook 已提交
3705 3706

    for (n = 0; n < q + 1; n += 2) {
3707 3708
        t0 = neon_load_reg(reg, n);
        t1 = neon_load_reg(reg, n + 1);
P
pbrook 已提交
3709
        switch (size) {
3710 3711
        case 0: gen_neon_unzip_u8(t0, t1); break;
        case 1: gen_neon_zip_u16(t0, t1); break; /* zip and unzip are the same.  */
P
pbrook 已提交
3712 3713 3714
        case 2: /* no-op */; break;
        default: abort();
        }
3715 3716
        neon_store_scratch(tmp + n, t0);
        neon_store_scratch(tmp + n + 1, t1);
P
pbrook 已提交
3717 3718 3719
    }
}

3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761
static void gen_neon_trn_u8(TCGv t0, TCGv t1)
{
    TCGv rd, tmp;

    rd = new_tmp();
    tmp = new_tmp();

    tcg_gen_shli_i32(rd, t0, 8);
    tcg_gen_andi_i32(rd, rd, 0xff00ff00);
    tcg_gen_andi_i32(tmp, t1, 0x00ff00ff);
    tcg_gen_or_i32(rd, rd, tmp);

    tcg_gen_shri_i32(t1, t1, 8);
    tcg_gen_andi_i32(t1, t1, 0x00ff00ff);
    tcg_gen_andi_i32(tmp, t0, 0xff00ff00);
    tcg_gen_or_i32(t1, t1, tmp);
    tcg_gen_mov_i32(t0, rd);

    dead_tmp(tmp);
    dead_tmp(rd);
}

static void gen_neon_trn_u16(TCGv t0, TCGv t1)
{
    TCGv rd, tmp;

    rd = new_tmp();
    tmp = new_tmp();

    tcg_gen_shli_i32(rd, t0, 16);
    tcg_gen_andi_i32(tmp, t1, 0xffff);
    tcg_gen_or_i32(rd, rd, tmp);
    tcg_gen_shri_i32(t1, t1, 16);
    tcg_gen_andi_i32(tmp, t0, 0xffff0000);
    tcg_gen_or_i32(t1, t1, tmp);
    tcg_gen_mov_i32(t0, rd);

    dead_tmp(tmp);
    dead_tmp(rd);
}


P
pbrook 已提交
3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787
static struct {
    int nregs;
    int interleave;
    int spacing;
} neon_ls_element_type[11] = {
    {4, 4, 1},
    {4, 4, 2},
    {4, 1, 1},
    {4, 2, 1},
    {3, 3, 1},
    {3, 3, 2},
    {3, 1, 1},
    {1, 1, 1},
    {2, 2, 1},
    {2, 2, 2},
    {2, 1, 1}
};

/* Translate a NEON load/store element instruction.  Return nonzero if the
   instruction is invalid.  */
static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn)
{
    int rd, rn, rm;
    int op;
    int nregs;
    int interleave;
3788
    int spacing;
P
pbrook 已提交
3789 3790 3791 3792 3793 3794 3795
    int stride;
    int size;
    int reg;
    int pass;
    int load;
    int shift;
    int n;
3796
    TCGv addr;
P
pbrook 已提交
3797
    TCGv tmp;
P
pbrook 已提交
3798
    TCGv tmp2;
3799
    TCGv_i64 tmp64;
P
pbrook 已提交
3800 3801 3802 3803 3804 3805 3806

    if (!vfp_enabled(env))
      return 1;
    VFP_DREG_D(rd, insn);
    rn = (insn >> 16) & 0xf;
    rm = insn & 0xf;
    load = (insn & (1 << 21)) != 0;
3807
    addr = new_tmp();
P
pbrook 已提交
3808 3809 3810 3811
    if ((insn & (1 << 23)) == 0) {
        /* Load store all elements.  */
        op = (insn >> 8) & 0xf;
        size = (insn >> 6) & 3;
3812
        if (op > 10)
P
pbrook 已提交
3813 3814 3815
            return 1;
        nregs = neon_ls_element_type[op].nregs;
        interleave = neon_ls_element_type[op].interleave;
3816 3817 3818
        spacing = neon_ls_element_type[op].spacing;
        if (size == 3 && (interleave | spacing) != 1)
            return 1;
3819
        load_reg_var(s, addr, rn);
P
pbrook 已提交
3820 3821 3822
        stride = (1 << size) * interleave;
        for (reg = 0; reg < nregs; reg++) {
            if (interleave > 2 || (interleave == 2 && nregs == 2)) {
3823 3824
                load_reg_var(s, addr, rn);
                tcg_gen_addi_i32(addr, addr, (1 << size) * reg);
P
pbrook 已提交
3825
            } else if (interleave == 2 && nregs == 4 && reg == 2) {
3826 3827
                load_reg_var(s, addr, rn);
                tcg_gen_addi_i32(addr, addr, 1 << size);
P
pbrook 已提交
3828
            }
3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849
            if (size == 3) {
                if (load) {
                    tmp64 = gen_ld64(addr, IS_USER(s));
                    neon_store_reg64(tmp64, rd);
                    tcg_temp_free_i64(tmp64);
                } else {
                    tmp64 = tcg_temp_new_i64();
                    neon_load_reg64(tmp64, rd);
                    gen_st64(tmp64, addr, IS_USER(s));
                }
                tcg_gen_addi_i32(addr, addr, stride);
            } else {
                for (pass = 0; pass < 2; pass++) {
                    if (size == 2) {
                        if (load) {
                            tmp = gen_ld32(addr, IS_USER(s));
                            neon_store_reg(rd, pass, tmp);
                        } else {
                            tmp = neon_load_reg(rd, pass);
                            gen_st32(tmp, addr, IS_USER(s));
                        }
3850
                        tcg_gen_addi_i32(addr, addr, stride);
3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866
                    } else if (size == 1) {
                        if (load) {
                            tmp = gen_ld16u(addr, IS_USER(s));
                            tcg_gen_addi_i32(addr, addr, stride);
                            tmp2 = gen_ld16u(addr, IS_USER(s));
                            tcg_gen_addi_i32(addr, addr, stride);
                            gen_bfi(tmp, tmp, tmp2, 16, 0xffff);
                            dead_tmp(tmp2);
                            neon_store_reg(rd, pass, tmp);
                        } else {
                            tmp = neon_load_reg(rd, pass);
                            tmp2 = new_tmp();
                            tcg_gen_shri_i32(tmp2, tmp, 16);
                            gen_st16(tmp, addr, IS_USER(s));
                            tcg_gen_addi_i32(addr, addr, stride);
                            gen_st16(tmp2, addr, IS_USER(s));
3867
                            tcg_gen_addi_i32(addr, addr, stride);
P
pbrook 已提交
3868
                        }
3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880
                    } else /* size == 0 */ {
                        if (load) {
                            TCGV_UNUSED(tmp2);
                            for (n = 0; n < 4; n++) {
                                tmp = gen_ld8u(addr, IS_USER(s));
                                tcg_gen_addi_i32(addr, addr, stride);
                                if (n == 0) {
                                    tmp2 = tmp;
                                } else {
                                    gen_bfi(tmp2, tmp2, tmp, n * 8, 0xff);
                                    dead_tmp(tmp);
                                }
P
pbrook 已提交
3881
                            }
3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895
                            neon_store_reg(rd, pass, tmp2);
                        } else {
                            tmp2 = neon_load_reg(rd, pass);
                            for (n = 0; n < 4; n++) {
                                tmp = new_tmp();
                                if (n == 0) {
                                    tcg_gen_mov_i32(tmp, tmp2);
                                } else {
                                    tcg_gen_shri_i32(tmp, tmp2, n * 8);
                                }
                                gen_st8(tmp, addr, IS_USER(s));
                                tcg_gen_addi_i32(addr, addr, stride);
                            }
                            dead_tmp(tmp2);
P
pbrook 已提交
3896 3897 3898 3899
                        }
                    }
                }
            }
3900
            rd += spacing;
P
pbrook 已提交
3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911
        }
        stride = nregs * 8;
    } else {
        size = (insn >> 10) & 3;
        if (size == 3) {
            /* Load single element to all lanes.  */
            if (!load)
                return 1;
            size = (insn >> 6) & 3;
            nregs = ((insn >> 8) & 3) + 1;
            stride = (insn & (1 << 5)) ? 2 : 1;
3912
            load_reg_var(s, addr, rn);
P
pbrook 已提交
3913 3914 3915
            for (reg = 0; reg < nregs; reg++) {
                switch (size) {
                case 0:
3916
                    tmp = gen_ld8u(addr, IS_USER(s));
P
pbrook 已提交
3917
                    gen_neon_dup_u8(tmp, 0);
P
pbrook 已提交
3918 3919
                    break;
                case 1:
3920
                    tmp = gen_ld16u(addr, IS_USER(s));
P
pbrook 已提交
3921
                    gen_neon_dup_low16(tmp);
P
pbrook 已提交
3922 3923
                    break;
                case 2:
3924
                    tmp = gen_ld32(addr, IS_USER(s));
P
pbrook 已提交
3925 3926 3927
                    break;
                case 3:
                    return 1;
P
pbrook 已提交
3928 3929
                default: /* Avoid compiler warnings.  */
                    abort();
B
bellard 已提交
3930
                }
3931
                tcg_gen_addi_i32(addr, addr, 1 << size);
P
pbrook 已提交
3932 3933 3934
                tmp2 = new_tmp();
                tcg_gen_mov_i32(tmp2, tmp);
                neon_store_reg(rd, 0, tmp2);
P
pbrook 已提交
3935
                neon_store_reg(rd, 1, tmp);
P
pbrook 已提交
3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958
                rd += stride;
            }
            stride = (1 << size) * nregs;
        } else {
            /* Single element.  */
            pass = (insn >> 7) & 1;
            switch (size) {
            case 0:
                shift = ((insn >> 5) & 3) * 8;
                stride = 1;
                break;
            case 1:
                shift = ((insn >> 6) & 1) * 16;
                stride = (insn & (1 << 5)) ? 2 : 1;
                break;
            case 2:
                shift = 0;
                stride = (insn & (1 << 6)) ? 2 : 1;
                break;
            default:
                abort();
            }
            nregs = ((insn >> 8) & 3) + 1;
3959
            load_reg_var(s, addr, rn);
P
pbrook 已提交
3960 3961 3962 3963
            for (reg = 0; reg < nregs; reg++) {
                if (load) {
                    switch (size) {
                    case 0:
3964
                        tmp = gen_ld8u(addr, IS_USER(s));
P
pbrook 已提交
3965 3966
                        break;
                    case 1:
3967
                        tmp = gen_ld16u(addr, IS_USER(s));
P
pbrook 已提交
3968 3969
                        break;
                    case 2:
3970
                        tmp = gen_ld32(addr, IS_USER(s));
P
pbrook 已提交
3971
                        break;
P
pbrook 已提交
3972 3973
                    default: /* Avoid compiler warnings.  */
                        abort();
P
pbrook 已提交
3974 3975
                    }
                    if (size != 2) {
P
pbrook 已提交
3976 3977 3978
                        tmp2 = neon_load_reg(rd, pass);
                        gen_bfi(tmp, tmp2, tmp, shift, size ? 0xffff : 0xff);
                        dead_tmp(tmp2);
P
pbrook 已提交
3979
                    }
P
pbrook 已提交
3980
                    neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
3981
                } else { /* Store */
P
pbrook 已提交
3982 3983 3984
                    tmp = neon_load_reg(rd, pass);
                    if (shift)
                        tcg_gen_shri_i32(tmp, tmp, shift);
P
pbrook 已提交
3985 3986
                    switch (size) {
                    case 0:
3987
                        gen_st8(tmp, addr, IS_USER(s));
P
pbrook 已提交
3988 3989
                        break;
                    case 1:
3990
                        gen_st16(tmp, addr, IS_USER(s));
P
pbrook 已提交
3991 3992
                        break;
                    case 2:
3993
                        gen_st32(tmp, addr, IS_USER(s));
P
pbrook 已提交
3994
                        break;
B
bellard 已提交
3995 3996
                    }
                }
P
pbrook 已提交
3997
                rd += stride;
3998
                tcg_gen_addi_i32(addr, addr, 1 << size);
B
bellard 已提交
3999
            }
P
pbrook 已提交
4000
            stride = nregs * (1 << size);
B
bellard 已提交
4001
        }
P
pbrook 已提交
4002
    }
4003
    dead_tmp(addr);
P
pbrook 已提交
4004
    if (rm != 15) {
P
pbrook 已提交
4005 4006 4007
        TCGv base;

        base = load_reg(s, rn);
P
pbrook 已提交
4008
        if (rm == 13) {
P
pbrook 已提交
4009
            tcg_gen_addi_i32(base, base, stride);
P
pbrook 已提交
4010
        } else {
P
pbrook 已提交
4011 4012 4013 4014
            TCGv index;
            index = load_reg(s, rm);
            tcg_gen_add_i32(base, base, index);
            dead_tmp(index);
P
pbrook 已提交
4015
        }
P
pbrook 已提交
4016
        store_reg(s, rn, base);
P
pbrook 已提交
4017 4018 4019
    }
    return 0;
}
4020

P
pbrook 已提交
4021 4022 4023 4024
/* Bitwise select.  dest = c ? t : f.  Clobbers T and F.  */
static void gen_neon_bsl(TCGv dest, TCGv t, TCGv f, TCGv c)
{
    tcg_gen_and_i32(t, t, c);
4025
    tcg_gen_andc_i32(f, f, c);
P
pbrook 已提交
4026 4027 4028
    tcg_gen_or_i32(dest, t, f);
}

P
pbrook 已提交
4029
static inline void gen_neon_narrow(int size, TCGv dest, TCGv_i64 src)
P
pbrook 已提交
4030 4031 4032 4033 4034 4035 4036 4037 4038
{
    switch (size) {
    case 0: gen_helper_neon_narrow_u8(dest, src); break;
    case 1: gen_helper_neon_narrow_u16(dest, src); break;
    case 2: tcg_gen_trunc_i64_i32(dest, src); break;
    default: abort();
    }
}

P
pbrook 已提交
4039
static inline void gen_neon_narrow_sats(int size, TCGv dest, TCGv_i64 src)
P
pbrook 已提交
4040 4041 4042 4043 4044 4045 4046 4047 4048
{
    switch (size) {
    case 0: gen_helper_neon_narrow_sat_s8(dest, cpu_env, src); break;
    case 1: gen_helper_neon_narrow_sat_s16(dest, cpu_env, src); break;
    case 2: gen_helper_neon_narrow_sat_s32(dest, cpu_env, src); break;
    default: abort();
    }
}

P
pbrook 已提交
4049
static inline void gen_neon_narrow_satu(int size, TCGv dest, TCGv_i64 src)
P
pbrook 已提交
4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092
{
    switch (size) {
    case 0: gen_helper_neon_narrow_sat_u8(dest, cpu_env, src); break;
    case 1: gen_helper_neon_narrow_sat_u16(dest, cpu_env, src); break;
    case 2: gen_helper_neon_narrow_sat_u32(dest, cpu_env, src); break;
    default: abort();
    }
}

static inline void gen_neon_shift_narrow(int size, TCGv var, TCGv shift,
                                         int q, int u)
{
    if (q) {
        if (u) {
            switch (size) {
            case 1: gen_helper_neon_rshl_u16(var, var, shift); break;
            case 2: gen_helper_neon_rshl_u32(var, var, shift); break;
            default: abort();
            }
        } else {
            switch (size) {
            case 1: gen_helper_neon_rshl_s16(var, var, shift); break;
            case 2: gen_helper_neon_rshl_s32(var, var, shift); break;
            default: abort();
            }
        }
    } else {
        if (u) {
            switch (size) {
            case 1: gen_helper_neon_rshl_u16(var, var, shift); break;
            case 2: gen_helper_neon_rshl_u32(var, var, shift); break;
            default: abort();
            }
        } else {
            switch (size) {
            case 1: gen_helper_neon_shl_s16(var, var, shift); break;
            case 2: gen_helper_neon_shl_s32(var, var, shift); break;
            default: abort();
            }
        }
    }
}

P
pbrook 已提交
4093
static inline void gen_neon_widen(TCGv_i64 dest, TCGv src, int size, int u)
P
pbrook 已提交
4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132
{
    if (u) {
        switch (size) {
        case 0: gen_helper_neon_widen_u8(dest, src); break;
        case 1: gen_helper_neon_widen_u16(dest, src); break;
        case 2: tcg_gen_extu_i32_i64(dest, src); break;
        default: abort();
        }
    } else {
        switch (size) {
        case 0: gen_helper_neon_widen_s8(dest, src); break;
        case 1: gen_helper_neon_widen_s16(dest, src); break;
        case 2: tcg_gen_ext_i32_i64(dest, src); break;
        default: abort();
        }
    }
    dead_tmp(src);
}

static inline void gen_neon_addl(int size)
{
    switch (size) {
    case 0: gen_helper_neon_addl_u16(CPU_V001); break;
    case 1: gen_helper_neon_addl_u32(CPU_V001); break;
    case 2: tcg_gen_add_i64(CPU_V001); break;
    default: abort();
    }
}

static inline void gen_neon_subl(int size)
{
    switch (size) {
    case 0: gen_helper_neon_subl_u16(CPU_V001); break;
    case 1: gen_helper_neon_subl_u32(CPU_V001); break;
    case 2: tcg_gen_sub_i64(CPU_V001); break;
    default: abort();
    }
}

P
pbrook 已提交
4133
static inline void gen_neon_negl(TCGv_i64 var, int size)
P
pbrook 已提交
4134 4135 4136 4137 4138 4139 4140 4141 4142
{
    switch (size) {
    case 0: gen_helper_neon_negl_u16(var, var); break;
    case 1: gen_helper_neon_negl_u32(var, var); break;
    case 2: gen_helper_neon_negl_u64(var, var); break;
    default: abort();
    }
}

P
pbrook 已提交
4143
static inline void gen_neon_addl_saturate(TCGv_i64 op0, TCGv_i64 op1, int size)
P
pbrook 已提交
4144 4145 4146 4147 4148 4149 4150 4151
{
    switch (size) {
    case 1: gen_helper_neon_addl_saturate_s32(op0, cpu_env, op0, op1); break;
    case 2: gen_helper_neon_addl_saturate_s64(op0, cpu_env, op0, op1); break;
    default: abort();
    }
}

P
pbrook 已提交
4152
static inline void gen_neon_mull(TCGv_i64 dest, TCGv a, TCGv b, int size, int u)
P
pbrook 已提交
4153
{
P
pbrook 已提交
4154
    TCGv_i64 tmp;
P
pbrook 已提交
4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172

    switch ((size << 1) | u) {
    case 0: gen_helper_neon_mull_s8(dest, a, b); break;
    case 1: gen_helper_neon_mull_u8(dest, a, b); break;
    case 2: gen_helper_neon_mull_s16(dest, a, b); break;
    case 3: gen_helper_neon_mull_u16(dest, a, b); break;
    case 4:
        tmp = gen_muls_i64_i32(a, b);
        tcg_gen_mov_i64(dest, tmp);
        break;
    case 5:
        tmp = gen_mulu_i64_i32(a, b);
        tcg_gen_mov_i64(dest, tmp);
        break;
    default: abort();
    }
}

P
pbrook 已提交
4173 4174
/* Translate a NEON data processing instruction.  Return nonzero if the
   instruction is invalid.
P
pbrook 已提交
4175 4176
   We process data in a mixture of 32-bit and 64-bit chunks.
   Mostly we use 32-bit chunks so we can use normal scalar instructions.  */
B
bellard 已提交
4177

P
pbrook 已提交
4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189
static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
{
    int op;
    int q;
    int rd, rn, rm;
    int size;
    int shift;
    int pass;
    int count;
    int pairwise;
    int u;
    int n;
4190
    uint32_t imm, mask;
4191
    TCGv tmp, tmp2, tmp3, tmp4, tmp5;
P
pbrook 已提交
4192
    TCGv_i64 tmp64;
P
pbrook 已提交
4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204

    if (!vfp_enabled(env))
      return 1;
    q = (insn & (1 << 6)) != 0;
    u = (insn >> 24) & 1;
    VFP_DREG_D(rd, insn);
    VFP_DREG_N(rn, insn);
    VFP_DREG_M(rm, insn);
    size = (insn >> 20) & 3;
    if ((insn & (1 << 23)) == 0) {
        /* Three register same length.  */
        op = ((insn >> 7) & 0x1e) | ((insn >> 4) & 1);
P
pbrook 已提交
4205 4206 4207
        if (size == 3 && (op == 1 || op == 5 || op == 8 || op == 9
                          || op == 10 || op  == 11 || op == 16)) {
            /* 64-bit element instructions.  */
P
pbrook 已提交
4208
            for (pass = 0; pass < (q ? 2 : 1); pass++) {
P
pbrook 已提交
4209 4210
                neon_load_reg64(cpu_V0, rn + pass);
                neon_load_reg64(cpu_V1, rm + pass);
P
pbrook 已提交
4211 4212 4213
                switch (op) {
                case 1: /* VQADD */
                    if (u) {
P
pbrook 已提交
4214
                        gen_helper_neon_add_saturate_u64(CPU_V001);
B
bellard 已提交
4215
                    } else {
P
pbrook 已提交
4216
                        gen_helper_neon_add_saturate_s64(CPU_V001);
B
bellard 已提交
4217
                    }
P
pbrook 已提交
4218 4219 4220
                    break;
                case 5: /* VQSUB */
                    if (u) {
P
pbrook 已提交
4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244
                        gen_helper_neon_sub_saturate_u64(CPU_V001);
                    } else {
                        gen_helper_neon_sub_saturate_s64(CPU_V001);
                    }
                    break;
                case 8: /* VSHL */
                    if (u) {
                        gen_helper_neon_shl_u64(cpu_V0, cpu_V1, cpu_V0);
                    } else {
                        gen_helper_neon_shl_s64(cpu_V0, cpu_V1, cpu_V0);
                    }
                    break;
                case 9: /* VQSHL */
                    if (u) {
                        gen_helper_neon_qshl_u64(cpu_V0, cpu_env,
                                                 cpu_V0, cpu_V0);
                    } else {
                        gen_helper_neon_qshl_s64(cpu_V1, cpu_env,
                                                 cpu_V1, cpu_V0);
                    }
                    break;
                case 10: /* VRSHL */
                    if (u) {
                        gen_helper_neon_rshl_u64(cpu_V0, cpu_V1, cpu_V0);
B
bellard 已提交
4245
                    } else {
P
pbrook 已提交
4246 4247 4248 4249 4250 4251 4252 4253 4254 4255
                        gen_helper_neon_rshl_s64(cpu_V0, cpu_V1, cpu_V0);
                    }
                    break;
                case 11: /* VQRSHL */
                    if (u) {
                        gen_helper_neon_qrshl_u64(cpu_V0, cpu_env,
                                                  cpu_V1, cpu_V0);
                    } else {
                        gen_helper_neon_qrshl_s64(cpu_V0, cpu_env,
                                                  cpu_V1, cpu_V0);
B
bellard 已提交
4256
                    }
P
pbrook 已提交
4257 4258 4259
                    break;
                case 16:
                    if (u) {
P
pbrook 已提交
4260
                        tcg_gen_sub_i64(CPU_V001);
P
pbrook 已提交
4261
                    } else {
P
pbrook 已提交
4262
                        tcg_gen_add_i64(CPU_V001);
P
pbrook 已提交
4263 4264 4265 4266
                    }
                    break;
                default:
                    abort();
B
bellard 已提交
4267
                }
P
pbrook 已提交
4268
                neon_store_reg64(cpu_V0, rd + pass);
B
bellard 已提交
4269
            }
P
pbrook 已提交
4270
            return 0;
B
bellard 已提交
4271
        }
P
pbrook 已提交
4272 4273 4274 4275
        switch (op) {
        case 8: /* VSHL */
        case 9: /* VQSHL */
        case 10: /* VRSHL */
P
pbrook 已提交
4276
        case 11: /* VQRSHL */
P
pbrook 已提交
4277
            {
P
pbrook 已提交
4278 4279 4280
                int rtmp;
                /* Shift instruction operands are reversed.  */
                rtmp = rn;
P
pbrook 已提交
4281
                rn = rm;
P
pbrook 已提交
4282
                rm = rtmp;
P
pbrook 已提交
4283 4284
                pairwise = 0;
            }
B
bellard 已提交
4285
            break;
P
pbrook 已提交
4286 4287 4288 4289
        case 20: /* VPMAX */
        case 21: /* VPMIN */
        case 23: /* VPADD */
            pairwise = 1;
B
bellard 已提交
4290
            break;
P
pbrook 已提交
4291 4292
        case 26: /* VPADD (float) */
            pairwise = (u && size < 2);
B
bellard 已提交
4293
            break;
P
pbrook 已提交
4294 4295
        case 30: /* VPMIN/VPMAX (float) */
            pairwise = u;
B
bellard 已提交
4296
            break;
P
pbrook 已提交
4297 4298
        default:
            pairwise = 0;
B
bellard 已提交
4299
            break;
P
pbrook 已提交
4300
        }
4301

P
pbrook 已提交
4302 4303 4304 4305 4306 4307
        for (pass = 0; pass < (q ? 4 : 2); pass++) {

        if (pairwise) {
            /* Pairwise.  */
            if (q)
                n = (pass & 1) * 2;
B
bellard 已提交
4308
            else
P
pbrook 已提交
4309 4310
                n = 0;
            if (pass < q + 1) {
4311 4312
                tmp = neon_load_reg(rn, n);
                tmp2 = neon_load_reg(rn, n + 1);
P
pbrook 已提交
4313
            } else {
4314 4315
                tmp = neon_load_reg(rm, n);
                tmp2 = neon_load_reg(rm, n + 1);
P
pbrook 已提交
4316 4317 4318
            }
        } else {
            /* Elementwise.  */
4319 4320
            tmp = neon_load_reg(rn, pass);
            tmp2 = neon_load_reg(rm, pass);
P
pbrook 已提交
4321 4322 4323 4324 4325 4326
        }
        switch (op) {
        case 0: /* VHADD */
            GEN_NEON_INTEGER_OP(hadd);
            break;
        case 1: /* VQADD */
P
pbrook 已提交
4327
            GEN_NEON_INTEGER_OP_ENV(qadd);
B
bellard 已提交
4328
            break;
P
pbrook 已提交
4329 4330
        case 2: /* VRHADD */
            GEN_NEON_INTEGER_OP(rhadd);
B
bellard 已提交
4331
            break;
P
pbrook 已提交
4332 4333 4334
        case 3: /* Logic ops.  */
            switch ((u << 2) | size) {
            case 0: /* VAND */
4335
                tcg_gen_and_i32(tmp, tmp, tmp2);
P
pbrook 已提交
4336 4337
                break;
            case 1: /* BIC */
4338
                tcg_gen_andc_i32(tmp, tmp, tmp2);
P
pbrook 已提交
4339 4340
                break;
            case 2: /* VORR */
4341
                tcg_gen_or_i32(tmp, tmp, tmp2);
P
pbrook 已提交
4342 4343
                break;
            case 3: /* VORN */
4344
                tcg_gen_orc_i32(tmp, tmp, tmp2);
P
pbrook 已提交
4345 4346
                break;
            case 4: /* VEOR */
4347
                tcg_gen_xor_i32(tmp, tmp, tmp2);
P
pbrook 已提交
4348 4349
                break;
            case 5: /* VBSL */
4350 4351 4352
                tmp3 = neon_load_reg(rd, pass);
                gen_neon_bsl(tmp, tmp, tmp2, tmp3);
                dead_tmp(tmp3);
P
pbrook 已提交
4353 4354
                break;
            case 6: /* VBIT */
4355 4356 4357
                tmp3 = neon_load_reg(rd, pass);
                gen_neon_bsl(tmp, tmp, tmp3, tmp2);
                dead_tmp(tmp3);
P
pbrook 已提交
4358 4359
                break;
            case 7: /* VBIF */
4360 4361 4362
                tmp3 = neon_load_reg(rd, pass);
                gen_neon_bsl(tmp, tmp3, tmp, tmp2);
                dead_tmp(tmp3);
P
pbrook 已提交
4363
                break;
B
bellard 已提交
4364 4365
            }
            break;
P
pbrook 已提交
4366 4367 4368 4369
        case 4: /* VHSUB */
            GEN_NEON_INTEGER_OP(hsub);
            break;
        case 5: /* VQSUB */
P
pbrook 已提交
4370
            GEN_NEON_INTEGER_OP_ENV(qsub);
B
bellard 已提交
4371
            break;
P
pbrook 已提交
4372 4373 4374 4375 4376 4377 4378
        case 6: /* VCGT */
            GEN_NEON_INTEGER_OP(cgt);
            break;
        case 7: /* VCGE */
            GEN_NEON_INTEGER_OP(cge);
            break;
        case 8: /* VSHL */
P
pbrook 已提交
4379
            GEN_NEON_INTEGER_OP(shl);
B
bellard 已提交
4380
            break;
P
pbrook 已提交
4381
        case 9: /* VQSHL */
P
pbrook 已提交
4382
            GEN_NEON_INTEGER_OP_ENV(qshl);
B
bellard 已提交
4383
            break;
P
pbrook 已提交
4384
        case 10: /* VRSHL */
P
pbrook 已提交
4385
            GEN_NEON_INTEGER_OP(rshl);
B
bellard 已提交
4386
            break;
P
pbrook 已提交
4387
        case 11: /* VQRSHL */
P
pbrook 已提交
4388
            GEN_NEON_INTEGER_OP_ENV(qrshl);
P
pbrook 已提交
4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400
            break;
        case 12: /* VMAX */
            GEN_NEON_INTEGER_OP(max);
            break;
        case 13: /* VMIN */
            GEN_NEON_INTEGER_OP(min);
            break;
        case 14: /* VABD */
            GEN_NEON_INTEGER_OP(abd);
            break;
        case 15: /* VABA */
            GEN_NEON_INTEGER_OP(abd);
4401 4402 4403
            dead_tmp(tmp2);
            tmp2 = neon_load_reg(rd, pass);
            gen_neon_add(size, tmp, tmp2);
P
pbrook 已提交
4404 4405 4406
            break;
        case 16:
            if (!u) { /* VADD */
4407
                if (gen_neon_add(size, tmp, tmp2))
P
pbrook 已提交
4408 4409 4410
                    return 1;
            } else { /* VSUB */
                switch (size) {
4411 4412 4413
                case 0: gen_helper_neon_sub_u8(tmp, tmp, tmp2); break;
                case 1: gen_helper_neon_sub_u16(tmp, tmp, tmp2); break;
                case 2: tcg_gen_sub_i32(tmp, tmp, tmp2); break;
P
pbrook 已提交
4414 4415 4416 4417 4418 4419 4420
                default: return 1;
                }
            }
            break;
        case 17:
            if (!u) { /* VTST */
                switch (size) {
4421 4422 4423
                case 0: gen_helper_neon_tst_u8(tmp, tmp, tmp2); break;
                case 1: gen_helper_neon_tst_u16(tmp, tmp, tmp2); break;
                case 2: gen_helper_neon_tst_u32(tmp, tmp, tmp2); break;
P
pbrook 已提交
4424 4425 4426 4427
                default: return 1;
                }
            } else { /* VCEQ */
                switch (size) {
4428 4429 4430
                case 0: gen_helper_neon_ceq_u8(tmp, tmp, tmp2); break;
                case 1: gen_helper_neon_ceq_u16(tmp, tmp, tmp2); break;
                case 2: gen_helper_neon_ceq_u32(tmp, tmp, tmp2); break;
P
pbrook 已提交
4431 4432 4433 4434 4435 4436
                default: return 1;
                }
            }
            break;
        case 18: /* Multiply.  */
            switch (size) {
4437 4438 4439
            case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break;
            case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break;
            case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break;
P
pbrook 已提交
4440 4441
            default: return 1;
            }
4442 4443
            dead_tmp(tmp2);
            tmp2 = neon_load_reg(rd, pass);
P
pbrook 已提交
4444
            if (u) { /* VMLS */
4445
                gen_neon_rsb(size, tmp, tmp2);
P
pbrook 已提交
4446
            } else { /* VMLA */
4447
                gen_neon_add(size, tmp, tmp2);
P
pbrook 已提交
4448 4449 4450 4451
            }
            break;
        case 19: /* VMUL */
            if (u) { /* polynomial */
4452
                gen_helper_neon_mul_p8(tmp, tmp, tmp2);
P
pbrook 已提交
4453 4454
            } else { /* Integer */
                switch (size) {
4455 4456 4457
                case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break;
                case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break;
                case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break;
P
pbrook 已提交
4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470
                default: return 1;
                }
            }
            break;
        case 20: /* VPMAX */
            GEN_NEON_INTEGER_OP(pmax);
            break;
        case 21: /* VPMIN */
            GEN_NEON_INTEGER_OP(pmin);
            break;
        case 22: /* Hultiply high.  */
            if (!u) { /* VQDMULH */
                switch (size) {
4471 4472
                case 1: gen_helper_neon_qdmulh_s16(tmp, cpu_env, tmp, tmp2); break;
                case 2: gen_helper_neon_qdmulh_s32(tmp, cpu_env, tmp, tmp2); break;
P
pbrook 已提交
4473 4474 4475 4476
                default: return 1;
                }
            } else { /* VQRDHMUL */
                switch (size) {
4477 4478
                case 1: gen_helper_neon_qrdmulh_s16(tmp, cpu_env, tmp, tmp2); break;
                case 2: gen_helper_neon_qrdmulh_s32(tmp, cpu_env, tmp, tmp2); break;
P
pbrook 已提交
4479 4480 4481 4482 4483 4484 4485 4486
                default: return 1;
                }
            }
            break;
        case 23: /* VPADD */
            if (u)
                return 1;
            switch (size) {
4487 4488 4489
            case 0: gen_helper_neon_padd_u8(tmp, tmp, tmp2); break;
            case 1: gen_helper_neon_padd_u16(tmp, tmp, tmp2); break;
            case 2: tcg_gen_add_i32(tmp, tmp, tmp2); break;
P
pbrook 已提交
4490 4491 4492 4493 4494 4495
            default: return 1;
            }
            break;
        case 26: /* Floating point arithnetic.  */
            switch ((u << 2) | size) {
            case 0: /* VADD */
4496
                gen_helper_neon_add_f32(tmp, tmp, tmp2);
P
pbrook 已提交
4497 4498
                break;
            case 2: /* VSUB */
4499
                gen_helper_neon_sub_f32(tmp, tmp, tmp2);
P
pbrook 已提交
4500 4501
                break;
            case 4: /* VPADD */
4502
                gen_helper_neon_add_f32(tmp, tmp, tmp2);
P
pbrook 已提交
4503 4504
                break;
            case 6: /* VABD */
4505
                gen_helper_neon_abd_f32(tmp, tmp, tmp2);
P
pbrook 已提交
4506 4507 4508 4509 4510 4511
                break;
            default:
                return 1;
            }
            break;
        case 27: /* Float multiply.  */
4512
            gen_helper_neon_mul_f32(tmp, tmp, tmp2);
P
pbrook 已提交
4513
            if (!u) {
4514 4515
                dead_tmp(tmp2);
                tmp2 = neon_load_reg(rd, pass);
P
pbrook 已提交
4516
                if (size == 0) {
4517
                    gen_helper_neon_add_f32(tmp, tmp, tmp2);
P
pbrook 已提交
4518
                } else {
4519
                    gen_helper_neon_sub_f32(tmp, tmp2, tmp);
P
pbrook 已提交
4520 4521 4522 4523 4524
                }
            }
            break;
        case 28: /* Float compare.  */
            if (!u) {
4525
                gen_helper_neon_ceq_f32(tmp, tmp, tmp2);
B
bellard 已提交
4526
            } else {
P
pbrook 已提交
4527
                if (size == 0)
4528
                    gen_helper_neon_cge_f32(tmp, tmp, tmp2);
P
pbrook 已提交
4529
                else
4530
                    gen_helper_neon_cgt_f32(tmp, tmp, tmp2);
B
bellard 已提交
4531
            }
B
bellard 已提交
4532
            break;
P
pbrook 已提交
4533 4534 4535 4536
        case 29: /* Float compare absolute.  */
            if (!u)
                return 1;
            if (size == 0)
4537
                gen_helper_neon_acge_f32(tmp, tmp, tmp2);
P
pbrook 已提交
4538
            else
4539
                gen_helper_neon_acgt_f32(tmp, tmp, tmp2);
B
bellard 已提交
4540
            break;
P
pbrook 已提交
4541 4542
        case 30: /* Float min/max.  */
            if (size == 0)
4543
                gen_helper_neon_max_f32(tmp, tmp, tmp2);
P
pbrook 已提交
4544
            else
4545
                gen_helper_neon_min_f32(tmp, tmp, tmp2);
P
pbrook 已提交
4546 4547 4548
            break;
        case 31:
            if (size == 0)
4549
                gen_helper_recps_f32(tmp, tmp, tmp2, cpu_env);
P
pbrook 已提交
4550
            else
4551
                gen_helper_rsqrts_f32(tmp, tmp, tmp2, cpu_env);
B
bellard 已提交
4552
            break;
P
pbrook 已提交
4553 4554
        default:
            abort();
B
bellard 已提交
4555
        }
4556 4557
        dead_tmp(tmp2);

P
pbrook 已提交
4558 4559 4560 4561
        /* Save the result.  For elementwise operations we can put it
           straight into the destination register.  For pairwise operations
           we have to be careful to avoid clobbering the source operands.  */
        if (pairwise && rd == rm) {
4562
            neon_store_scratch(pass, tmp);
P
pbrook 已提交
4563
        } else {
4564
            neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
4565 4566 4567 4568 4569
        }

        } /* for pass */
        if (pairwise && rd == rm) {
            for (pass = 0; pass < (q ? 4 : 2); pass++) {
4570 4571
                tmp = neon_load_scratch(pass);
                neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
4572 4573
            }
        }
P
pbrook 已提交
4574
        /* End of 3 register same size operations.  */
P
pbrook 已提交
4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620
    } else if (insn & (1 << 4)) {
        if ((insn & 0x00380080) != 0) {
            /* Two registers and shift.  */
            op = (insn >> 8) & 0xf;
            if (insn & (1 << 7)) {
                /* 64-bit shift.   */
                size = 3;
            } else {
                size = 2;
                while ((insn & (1 << (size + 19))) == 0)
                    size--;
            }
            shift = (insn >> 16) & ((1 << (3 + size)) - 1);
            /* To avoid excessive dumplication of ops we implement shift
               by immediate using the variable shift operations.  */
            if (op < 8) {
                /* Shift by immediate:
                   VSHR, VSRA, VRSHR, VRSRA, VSRI, VSHL, VQSHL, VQSHLU.  */
                /* Right shifts are encoded as N - shift, where N is the
                   element size in bits.  */
                if (op <= 4)
                    shift = shift - (1 << (size + 3));
                if (size == 3) {
                    count = q + 1;
                } else {
                    count = q ? 4: 2;
                }
                switch (size) {
                case 0:
                    imm = (uint8_t) shift;
                    imm |= imm << 8;
                    imm |= imm << 16;
                    break;
                case 1:
                    imm = (uint16_t) shift;
                    imm |= imm << 16;
                    break;
                case 2:
                case 3:
                    imm = shift;
                    break;
                default:
                    abort();
                }

                for (pass = 0; pass < count; pass++) {
P
pbrook 已提交
4621 4622 4623 4624 4625 4626 4627 4628
                    if (size == 3) {
                        neon_load_reg64(cpu_V0, rm + pass);
                        tcg_gen_movi_i64(cpu_V1, imm);
                        switch (op) {
                        case 0:  /* VSHR */
                        case 1:  /* VSRA */
                            if (u)
                                gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1);
P
pbrook 已提交
4629
                            else
P
pbrook 已提交
4630
                                gen_helper_neon_shl_s64(cpu_V0, cpu_V0, cpu_V1);
P
pbrook 已提交
4631
                            break;
P
pbrook 已提交
4632 4633 4634 4635
                        case 2: /* VRSHR */
                        case 3: /* VRSRA */
                            if (u)
                                gen_helper_neon_rshl_u64(cpu_V0, cpu_V0, cpu_V1);
P
pbrook 已提交
4636
                            else
P
pbrook 已提交
4637
                                gen_helper_neon_rshl_s64(cpu_V0, cpu_V0, cpu_V1);
P
pbrook 已提交
4638
                            break;
P
pbrook 已提交
4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649
                        case 4: /* VSRI */
                            if (!u)
                                return 1;
                            gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1);
                            break;
                        case 5: /* VSHL, VSLI */
                            gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1);
                            break;
                        case 6: /* VQSHL */
                            if (u)
                                gen_helper_neon_qshl_u64(cpu_V0, cpu_env, cpu_V0, cpu_V1);
P
pbrook 已提交
4650
                            else
P
pbrook 已提交
4651 4652 4653 4654
                                gen_helper_neon_qshl_s64(cpu_V0, cpu_env, cpu_V0, cpu_V1);
                            break;
                        case 7: /* VQSHLU */
                            gen_helper_neon_qshl_u64(cpu_V0, cpu_env, cpu_V0, cpu_V1);
P
pbrook 已提交
4655 4656
                            break;
                        }
P
pbrook 已提交
4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667
                        if (op == 1 || op == 3) {
                            /* Accumulate.  */
                            neon_load_reg64(cpu_V0, rd + pass);
                            tcg_gen_add_i64(cpu_V0, cpu_V0, cpu_V1);
                        } else if (op == 4 || (op == 5 && u)) {
                            /* Insert */
                            cpu_abort(env, "VS[LR]I.64 not implemented");
                        }
                        neon_store_reg64(cpu_V0, rd + pass);
                    } else { /* size < 3 */
                        /* Operands in T0 and T1.  */
4668 4669 4670
                        tmp = neon_load_reg(rm, pass);
                        tmp2 = new_tmp();
                        tcg_gen_movi_i32(tmp2, imm);
P
pbrook 已提交
4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686
                        switch (op) {
                        case 0:  /* VSHR */
                        case 1:  /* VSRA */
                            GEN_NEON_INTEGER_OP(shl);
                            break;
                        case 2: /* VRSHR */
                        case 3: /* VRSRA */
                            GEN_NEON_INTEGER_OP(rshl);
                            break;
                        case 4: /* VSRI */
                            if (!u)
                                return 1;
                            GEN_NEON_INTEGER_OP(shl);
                            break;
                        case 5: /* VSHL, VSLI */
                            switch (size) {
4687 4688 4689
                            case 0: gen_helper_neon_shl_u8(tmp, tmp, tmp2); break;
                            case 1: gen_helper_neon_shl_u16(tmp, tmp, tmp2); break;
                            case 2: gen_helper_neon_shl_u32(tmp, tmp, tmp2); break;
P
pbrook 已提交
4690 4691 4692 4693 4694 4695 4696 4697
                            default: return 1;
                            }
                            break;
                        case 6: /* VQSHL */
                            GEN_NEON_INTEGER_OP_ENV(qshl);
                            break;
                        case 7: /* VQSHLU */
                            switch (size) {
4698 4699 4700
                            case 0: gen_helper_neon_qshl_u8(tmp, cpu_env, tmp, tmp2); break;
                            case 1: gen_helper_neon_qshl_u16(tmp, cpu_env, tmp, tmp2); break;
                            case 2: gen_helper_neon_qshl_u32(tmp, cpu_env, tmp, tmp2); break;
P
pbrook 已提交
4701 4702 4703 4704
                            default: return 1;
                            }
                            break;
                        }
4705
                        dead_tmp(tmp2);
P
pbrook 已提交
4706 4707 4708

                        if (op == 1 || op == 3) {
                            /* Accumulate.  */
4709 4710 4711
                            tmp2 = neon_load_reg(rd, pass);
                            gen_neon_add(size, tmp2, tmp);
                            dead_tmp(tmp2);
P
pbrook 已提交
4712 4713 4714 4715 4716
                        } else if (op == 4 || (op == 5 && u)) {
                            /* Insert */
                            switch (size) {
                            case 0:
                                if (op == 4)
4717
                                    mask = 0xff >> -shift;
P
pbrook 已提交
4718
                                else
4719 4720 4721
                                    mask = (uint8_t)(0xff << shift);
                                mask |= mask << 8;
                                mask |= mask << 16;
P
pbrook 已提交
4722 4723 4724
                                break;
                            case 1:
                                if (op == 4)
4725
                                    mask = 0xffff >> -shift;
P
pbrook 已提交
4726
                                else
4727 4728
                                    mask = (uint16_t)(0xffff << shift);
                                mask |= mask << 16;
P
pbrook 已提交
4729 4730
                                break;
                            case 2:
4731 4732 4733 4734 4735 4736 4737 4738
                                if (shift < -31 || shift > 31) {
                                    mask = 0;
                                } else {
                                    if (op == 4)
                                        mask = 0xffffffffu >> -shift;
                                    else
                                        mask = 0xffffffffu << shift;
                                }
P
pbrook 已提交
4739 4740 4741 4742
                                break;
                            default:
                                abort();
                            }
4743
                            tmp2 = neon_load_reg(rd, pass);
4744 4745
                            tcg_gen_andi_i32(tmp, tmp, mask);
                            tcg_gen_andi_i32(tmp2, tmp2, ~mask);
4746 4747
                            tcg_gen_or_i32(tmp, tmp, tmp2);
                            dead_tmp(tmp2);
P
pbrook 已提交
4748
                        }
4749
                        neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
4750 4751 4752
                    }
                } /* for pass */
            } else if (op < 10) {
P
pbrook 已提交
4753
                /* Shift by immediate and narrow:
P
pbrook 已提交
4754 4755 4756 4757 4758
                   VSHRN, VRSHRN, VQSHRN, VQRSHRN.  */
                shift = shift - (1 << (size + 3));
                size++;
                switch (size) {
                case 1:
P
pbrook 已提交
4759
                    imm = (uint16_t)shift;
P
pbrook 已提交
4760
                    imm |= imm << 16;
P
pbrook 已提交
4761
                    tmp2 = tcg_const_i32(imm);
P
pbrook 已提交
4762
                    TCGV_UNUSED_I64(tmp64);
P
pbrook 已提交
4763 4764
                    break;
                case 2:
P
pbrook 已提交
4765 4766
                    imm = (uint32_t)shift;
                    tmp2 = tcg_const_i32(imm);
P
pbrook 已提交
4767
                    TCGV_UNUSED_I64(tmp64);
4768
                    break;
P
pbrook 已提交
4769
                case 3:
P
pbrook 已提交
4770 4771
                    tmp64 = tcg_const_i64(shift);
                    TCGV_UNUSED(tmp2);
P
pbrook 已提交
4772 4773 4774 4775 4776
                    break;
                default:
                    abort();
                }

P
pbrook 已提交
4777 4778 4779 4780 4781
                for (pass = 0; pass < 2; pass++) {
                    if (size == 3) {
                        neon_load_reg64(cpu_V0, rm + pass);
                        if (q) {
                          if (u)
P
pbrook 已提交
4782
                            gen_helper_neon_rshl_u64(cpu_V0, cpu_V0, tmp64);
P
pbrook 已提交
4783
                          else
P
pbrook 已提交
4784
                            gen_helper_neon_rshl_s64(cpu_V0, cpu_V0, tmp64);
P
pbrook 已提交
4785 4786
                        } else {
                          if (u)
P
pbrook 已提交
4787
                            gen_helper_neon_shl_u64(cpu_V0, cpu_V0, tmp64);
P
pbrook 已提交
4788
                          else
P
pbrook 已提交
4789
                            gen_helper_neon_shl_s64(cpu_V0, cpu_V0, tmp64);
P
pbrook 已提交
4790
                        }
B
bellard 已提交
4791
                    } else {
P
pbrook 已提交
4792 4793
                        tmp = neon_load_reg(rm + pass, 0);
                        gen_neon_shift_narrow(size, tmp, tmp2, q, u);
P
pbrook 已提交
4794 4795 4796
                        tmp3 = neon_load_reg(rm + pass, 1);
                        gen_neon_shift_narrow(size, tmp3, tmp2, q, u);
                        tcg_gen_concat_i32_i64(cpu_V0, tmp, tmp3);
P
pbrook 已提交
4797
                        dead_tmp(tmp);
P
pbrook 已提交
4798
                        dead_tmp(tmp3);
P
pbrook 已提交
4799
                    }
P
pbrook 已提交
4800 4801 4802
                    tmp = new_tmp();
                    if (op == 8 && !u) {
                        gen_neon_narrow(size - 1, tmp, cpu_V0);
P
pbrook 已提交
4803
                    } else {
P
pbrook 已提交
4804 4805
                        if (op == 8)
                            gen_neon_narrow_sats(size - 1, tmp, cpu_V0);
P
pbrook 已提交
4806
                        else
P
pbrook 已提交
4807 4808
                            gen_neon_narrow_satu(size - 1, tmp, cpu_V0);
                    }
4809
                    neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
4810
                } /* for pass */
4811 4812
                if (size == 3) {
                    tcg_temp_free_i64(tmp64);
4813 4814
                } else {
                    dead_tmp(tmp2);
4815
                }
P
pbrook 已提交
4816 4817
            } else if (op == 10) {
                /* VSHLL */
P
pbrook 已提交
4818
                if (q || size == 3)
P
pbrook 已提交
4819
                    return 1;
P
pbrook 已提交
4820 4821
                tmp = neon_load_reg(rm, 0);
                tmp2 = neon_load_reg(rm, 1);
P
pbrook 已提交
4822
                for (pass = 0; pass < 2; pass++) {
P
pbrook 已提交
4823 4824 4825 4826
                    if (pass == 1)
                        tmp = tmp2;

                    gen_neon_widen(cpu_V0, tmp, size, u);
P
pbrook 已提交
4827 4828 4829

                    if (shift != 0) {
                        /* The shift is less than the width of the source
P
pbrook 已提交
4830 4831 4832 4833 4834 4835 4836 4837 4838
                           type, so we can just shift the whole register.  */
                        tcg_gen_shli_i64(cpu_V0, cpu_V0, shift);
                        if (size < 2 || !u) {
                            uint64_t imm64;
                            if (size == 0) {
                                imm = (0xffu >> (8 - shift));
                                imm |= imm << 16;
                            } else {
                                imm = 0xffff >> (16 - shift);
P
pbrook 已提交
4839
                            }
P
pbrook 已提交
4840 4841
                            imm64 = imm | (((uint64_t)imm) << 32);
                            tcg_gen_andi_i64(cpu_V0, cpu_V0, imm64);
P
pbrook 已提交
4842 4843
                        }
                    }
P
pbrook 已提交
4844
                    neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
4845 4846 4847 4848
                }
            } else if (op == 15 || op == 16) {
                /* VCVT fixed-point.  */
                for (pass = 0; pass < (q ? 4 : 2); pass++) {
P
pbrook 已提交
4849
                    tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, pass));
P
pbrook 已提交
4850 4851
                    if (op & 1) {
                        if (u)
P
pbrook 已提交
4852
                            gen_vfp_ulto(0, shift);
P
pbrook 已提交
4853
                        else
P
pbrook 已提交
4854
                            gen_vfp_slto(0, shift);
P
pbrook 已提交
4855 4856
                    } else {
                        if (u)
P
pbrook 已提交
4857
                            gen_vfp_toul(0, shift);
P
pbrook 已提交
4858
                        else
P
pbrook 已提交
4859
                            gen_vfp_tosl(0, shift);
B
bellard 已提交
4860
                    }
P
pbrook 已提交
4861
                    tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, pass));
B
bellard 已提交
4862 4863
                }
            } else {
P
pbrook 已提交
4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892
                return 1;
            }
        } else { /* (insn & 0x00380080) == 0 */
            int invert;

            op = (insn >> 8) & 0xf;
            /* One register and immediate.  */
            imm = (u << 7) | ((insn >> 12) & 0x70) | (insn & 0xf);
            invert = (insn & (1 << 5)) != 0;
            switch (op) {
            case 0: case 1:
                /* no-op */
                break;
            case 2: case 3:
                imm <<= 8;
                break;
            case 4: case 5:
                imm <<= 16;
                break;
            case 6: case 7:
                imm <<= 24;
                break;
            case 8: case 9:
                imm |= imm << 16;
                break;
            case 10: case 11:
                imm = (imm << 8) | (imm << 24);
                break;
            case 12:
4893
                imm = (imm << 8) | 0xff;
P
pbrook 已提交
4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912
                break;
            case 13:
                imm = (imm << 16) | 0xffff;
                break;
            case 14:
                imm |= (imm << 8) | (imm << 16) | (imm << 24);
                if (invert)
                    imm = ~imm;
                break;
            case 15:
                imm = ((imm & 0x80) << 24) | ((imm & 0x3f) << 19)
                      | ((imm & 0x40) ? (0x1f << 25) : (1 << 30));
                break;
            }
            if (invert)
                imm = ~imm;

            for (pass = 0; pass < (q ? 4 : 2); pass++) {
                if (op & 1 && op < 12) {
P
pbrook 已提交
4913
                    tmp = neon_load_reg(rd, pass);
P
pbrook 已提交
4914 4915 4916
                    if (invert) {
                        /* The immediate value has already been inverted, so
                           BIC becomes AND.  */
P
pbrook 已提交
4917
                        tcg_gen_andi_i32(tmp, tmp, imm);
P
pbrook 已提交
4918
                    } else {
P
pbrook 已提交
4919
                        tcg_gen_ori_i32(tmp, tmp, imm);
P
pbrook 已提交
4920 4921
                    }
                } else {
P
pbrook 已提交
4922 4923
                    /* VMOV, VMVN.  */
                    tmp = new_tmp();
P
pbrook 已提交
4924
                    if (op == 14 && invert) {
P
pbrook 已提交
4925 4926
                        uint32_t val;
                        val = 0;
P
pbrook 已提交
4927 4928
                        for (n = 0; n < 4; n++) {
                            if (imm & (1 << (n + (pass & 1) * 4)))
P
pbrook 已提交
4929
                                val |= 0xff << (n * 8);
P
pbrook 已提交
4930
                        }
P
pbrook 已提交
4931 4932 4933
                        tcg_gen_movi_i32(tmp, val);
                    } else {
                        tcg_gen_movi_i32(tmp, imm);
P
pbrook 已提交
4934 4935
                    }
                }
P
pbrook 已提交
4936
                neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
4937 4938
            }
        }
P
pbrook 已提交
4939
    } else { /* (insn & 0x00800010 == 0x00800000) */
P
pbrook 已提交
4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969
        if (size != 3) {
            op = (insn >> 8) & 0xf;
            if ((insn & (1 << 6)) == 0) {
                /* Three registers of different lengths.  */
                int src1_wide;
                int src2_wide;
                int prewiden;
                /* prewiden, src1_wide, src2_wide */
                static const int neon_3reg_wide[16][3] = {
                    {1, 0, 0}, /* VADDL */
                    {1, 1, 0}, /* VADDW */
                    {1, 0, 0}, /* VSUBL */
                    {1, 1, 0}, /* VSUBW */
                    {0, 1, 1}, /* VADDHN */
                    {0, 0, 0}, /* VABAL */
                    {0, 1, 1}, /* VSUBHN */
                    {0, 0, 0}, /* VABDL */
                    {0, 0, 0}, /* VMLAL */
                    {0, 0, 0}, /* VQDMLAL */
                    {0, 0, 0}, /* VMLSL */
                    {0, 0, 0}, /* VQDMLSL */
                    {0, 0, 0}, /* Integer VMULL */
                    {0, 0, 0}, /* VQDMULL */
                    {0, 0, 0}  /* Polynomial VMULL */
                };

                prewiden = neon_3reg_wide[op][0];
                src1_wide = neon_3reg_wide[op][1];
                src2_wide = neon_3reg_wide[op][2];

P
pbrook 已提交
4970 4971 4972
                if (size == 0 && (op == 9 || op == 11 || op == 13))
                    return 1;

P
pbrook 已提交
4973 4974 4975
                /* Avoid overlapping operands.  Wide source operands are
                   always aligned so will never overlap with wide
                   destinations in problematic ways.  */
P
pbrook 已提交
4976
                if (rd == rm && !src2_wide) {
4977 4978
                    tmp = neon_load_reg(rm, 1);
                    neon_store_scratch(2, tmp);
P
pbrook 已提交
4979
                } else if (rd == rn && !src1_wide) {
4980 4981
                    tmp = neon_load_reg(rn, 1);
                    neon_store_scratch(2, tmp);
P
pbrook 已提交
4982
                }
P
pbrook 已提交
4983
                TCGV_UNUSED(tmp3);
P
pbrook 已提交
4984
                for (pass = 0; pass < 2; pass++) {
P
pbrook 已提交
4985 4986
                    if (src1_wide) {
                        neon_load_reg64(cpu_V0, rn + pass);
P
pbrook 已提交
4987
                        TCGV_UNUSED(tmp);
P
pbrook 已提交
4988
                    } else {
P
pbrook 已提交
4989
                        if (pass == 1 && rd == rn) {
4990
                            tmp = neon_load_scratch(2);
P
pbrook 已提交
4991
                        } else {
P
pbrook 已提交
4992 4993 4994 4995
                            tmp = neon_load_reg(rn, pass);
                        }
                        if (prewiden) {
                            gen_neon_widen(cpu_V0, tmp, size, u);
P
pbrook 已提交
4996 4997
                        }
                    }
P
pbrook 已提交
4998 4999
                    if (src2_wide) {
                        neon_load_reg64(cpu_V1, rm + pass);
P
pbrook 已提交
5000
                        TCGV_UNUSED(tmp2);
P
pbrook 已提交
5001
                    } else {
P
pbrook 已提交
5002
                        if (pass == 1 && rd == rm) {
5003
                            tmp2 = neon_load_scratch(2);
P
pbrook 已提交
5004
                        } else {
P
pbrook 已提交
5005 5006 5007 5008
                            tmp2 = neon_load_reg(rm, pass);
                        }
                        if (prewiden) {
                            gen_neon_widen(cpu_V1, tmp2, size, u);
P
pbrook 已提交
5009 5010 5011 5012
                        }
                    }
                    switch (op) {
                    case 0: case 1: case 4: /* VADDL, VADDW, VADDHN, VRADDHN */
P
pbrook 已提交
5013
                        gen_neon_addl(size);
P
pbrook 已提交
5014
                        break;
5015
                    case 2: case 3: case 6: /* VSUBL, VSUBW, VSUBHN, VRSUBHN */
P
pbrook 已提交
5016
                        gen_neon_subl(size);
P
pbrook 已提交
5017 5018 5019
                        break;
                    case 5: case 7: /* VABAL, VABDL */
                        switch ((size << 1) | u) {
P
pbrook 已提交
5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037
                        case 0:
                            gen_helper_neon_abdl_s16(cpu_V0, tmp, tmp2);
                            break;
                        case 1:
                            gen_helper_neon_abdl_u16(cpu_V0, tmp, tmp2);
                            break;
                        case 2:
                            gen_helper_neon_abdl_s32(cpu_V0, tmp, tmp2);
                            break;
                        case 3:
                            gen_helper_neon_abdl_u32(cpu_V0, tmp, tmp2);
                            break;
                        case 4:
                            gen_helper_neon_abdl_s64(cpu_V0, tmp, tmp2);
                            break;
                        case 5:
                            gen_helper_neon_abdl_u64(cpu_V0, tmp, tmp2);
                            break;
P
pbrook 已提交
5038 5039
                        default: abort();
                        }
P
pbrook 已提交
5040 5041
                        dead_tmp(tmp2);
                        dead_tmp(tmp);
P
pbrook 已提交
5042 5043 5044
                        break;
                    case 8: case 9: case 10: case 11: case 12: case 13:
                        /* VMLAL, VQDMLAL, VMLSL, VQDMLSL, VMULL, VQDMULL */
P
pbrook 已提交
5045
                        gen_neon_mull(cpu_V0, tmp, tmp2, size, u);
5046 5047
                        dead_tmp(tmp2);
                        dead_tmp(tmp);
P
pbrook 已提交
5048 5049 5050 5051 5052 5053 5054 5055 5056 5057
                        break;
                    case 14: /* Polynomial VMULL */
                        cpu_abort(env, "Polynomial VMULL not implemented");

                    default: /* 15 is RESERVED.  */
                        return 1;
                    }
                    if (op == 5 || op == 13 || (op >= 8 && op <= 11)) {
                        /* Accumulate.  */
                        if (op == 10 || op == 11) {
P
pbrook 已提交
5058
                            gen_neon_negl(cpu_V0, size);
P
pbrook 已提交
5059 5060 5061
                        }

                        if (op != 13) {
P
pbrook 已提交
5062
                            neon_load_reg64(cpu_V1, rd + pass);
P
pbrook 已提交
5063 5064 5065 5066
                        }

                        switch (op) {
                        case 5: case 8: case 10: /* VABAL, VMLAL, VMLSL */
P
pbrook 已提交
5067
                            gen_neon_addl(size);
P
pbrook 已提交
5068 5069
                            break;
                        case 9: case 11: /* VQDMLAL, VQDMLSL */
P
pbrook 已提交
5070 5071 5072
                            gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
                            gen_neon_addl_saturate(cpu_V0, cpu_V1, size);
                            break;
P
pbrook 已提交
5073 5074
                            /* Fall through.  */
                        case 13: /* VQDMULL */
P
pbrook 已提交
5075
                            gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
P
pbrook 已提交
5076 5077 5078 5079
                            break;
                        default:
                            abort();
                        }
P
pbrook 已提交
5080
                        neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
5081 5082
                    } else if (op == 4 || op == 6) {
                        /* Narrowing operation.  */
P
pbrook 已提交
5083
                        tmp = new_tmp();
5084
                        if (!u) {
P
pbrook 已提交
5085
                            switch (size) {
P
pbrook 已提交
5086 5087 5088 5089 5090 5091 5092 5093 5094 5095
                            case 0:
                                gen_helper_neon_narrow_high_u8(tmp, cpu_V0);
                                break;
                            case 1:
                                gen_helper_neon_narrow_high_u16(tmp, cpu_V0);
                                break;
                            case 2:
                                tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
                                tcg_gen_trunc_i64_i32(tmp, cpu_V0);
                                break;
P
pbrook 已提交
5096 5097 5098 5099
                            default: abort();
                            }
                        } else {
                            switch (size) {
P
pbrook 已提交
5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110
                            case 0:
                                gen_helper_neon_narrow_round_high_u8(tmp, cpu_V0);
                                break;
                            case 1:
                                gen_helper_neon_narrow_round_high_u16(tmp, cpu_V0);
                                break;
                            case 2:
                                tcg_gen_addi_i64(cpu_V0, cpu_V0, 1u << 31);
                                tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
                                tcg_gen_trunc_i64_i32(tmp, cpu_V0);
                                break;
P
pbrook 已提交
5111 5112 5113
                            default: abort();
                            }
                        }
P
pbrook 已提交
5114 5115 5116 5117 5118 5119
                        if (pass == 0) {
                            tmp3 = tmp;
                        } else {
                            neon_store_reg(rd, 0, tmp3);
                            neon_store_reg(rd, 1, tmp);
                        }
P
pbrook 已提交
5120 5121
                    } else {
                        /* Write back the result.  */
P
pbrook 已提交
5122
                        neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135
                    }
                }
            } else {
                /* Two registers and a scalar.  */
                switch (op) {
                case 0: /* Integer VMLA scalar */
                case 1: /* Float VMLA scalar */
                case 4: /* Integer VMLS scalar */
                case 5: /* Floating point VMLS scalar */
                case 8: /* Integer VMUL scalar */
                case 9: /* Floating point VMUL scalar */
                case 12: /* VQDMULH scalar */
                case 13: /* VQRDMULH scalar */
5136 5137
                    tmp = neon_get_scalar(size, rm);
                    neon_store_scratch(0, tmp);
P
pbrook 已提交
5138
                    for (pass = 0; pass < (u ? 4 : 2); pass++) {
5139 5140
                        tmp = neon_load_scratch(0);
                        tmp2 = neon_load_reg(rn, pass);
P
pbrook 已提交
5141 5142
                        if (op == 12) {
                            if (size == 1) {
5143
                                gen_helper_neon_qdmulh_s16(tmp, cpu_env, tmp, tmp2);
P
pbrook 已提交
5144
                            } else {
5145
                                gen_helper_neon_qdmulh_s32(tmp, cpu_env, tmp, tmp2);
P
pbrook 已提交
5146 5147 5148
                            }
                        } else if (op == 13) {
                            if (size == 1) {
5149
                                gen_helper_neon_qrdmulh_s16(tmp, cpu_env, tmp, tmp2);
P
pbrook 已提交
5150
                            } else {
5151
                                gen_helper_neon_qrdmulh_s32(tmp, cpu_env, tmp, tmp2);
P
pbrook 已提交
5152 5153
                            }
                        } else if (op & 1) {
5154
                            gen_helper_neon_mul_f32(tmp, tmp, tmp2);
P
pbrook 已提交
5155 5156
                        } else {
                            switch (size) {
5157 5158 5159
                            case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break;
                            case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break;
                            case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break;
P
pbrook 已提交
5160 5161 5162
                            default: return 1;
                            }
                        }
5163
                        dead_tmp(tmp2);
P
pbrook 已提交
5164 5165
                        if (op < 8) {
                            /* Accumulate.  */
5166
                            tmp2 = neon_load_reg(rd, pass);
P
pbrook 已提交
5167 5168
                            switch (op) {
                            case 0:
5169
                                gen_neon_add(size, tmp, tmp2);
P
pbrook 已提交
5170 5171
                                break;
                            case 1:
5172
                                gen_helper_neon_add_f32(tmp, tmp, tmp2);
P
pbrook 已提交
5173 5174
                                break;
                            case 4:
5175
                                gen_neon_rsb(size, tmp, tmp2);
P
pbrook 已提交
5176 5177
                                break;
                            case 5:
5178
                                gen_helper_neon_sub_f32(tmp, tmp2, tmp);
P
pbrook 已提交
5179 5180 5181 5182
                                break;
                            default:
                                abort();
                            }
5183
                            dead_tmp(tmp2);
P
pbrook 已提交
5184
                        }
5185
                        neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
5186 5187 5188 5189 5190 5191 5192 5193
                    }
                    break;
                case 2: /* VMLAL sclar */
                case 3: /* VQDMLAL scalar */
                case 6: /* VMLSL scalar */
                case 7: /* VQDMLSL scalar */
                case 10: /* VMULL scalar */
                case 11: /* VQDMULL scalar */
P
pbrook 已提交
5194 5195 5196
                    if (size == 0 && (op == 3 || op == 7 || op == 11))
                        return 1;

5197 5198
                    tmp2 = neon_get_scalar(size, rm);
                    tmp3 = neon_load_reg(rn, 1);
P
pbrook 已提交
5199

P
pbrook 已提交
5200
                    for (pass = 0; pass < 2; pass++) {
P
pbrook 已提交
5201 5202
                        if (pass == 0) {
                            tmp = neon_load_reg(rn, 0);
P
pbrook 已提交
5203
                        } else {
5204
                            tmp = tmp3;
P
pbrook 已提交
5205
                        }
P
pbrook 已提交
5206
                        gen_neon_mull(cpu_V0, tmp, tmp2, size, u);
5207
                        dead_tmp(tmp);
P
pbrook 已提交
5208
                        if (op == 6 || op == 7) {
P
pbrook 已提交
5209 5210 5211 5212
                            gen_neon_negl(cpu_V0, size);
                        }
                        if (op != 11) {
                            neon_load_reg64(cpu_V1, rd + pass);
P
pbrook 已提交
5213 5214 5215
                        }
                        switch (op) {
                        case 2: case 6:
P
pbrook 已提交
5216
                            gen_neon_addl(size);
P
pbrook 已提交
5217 5218
                            break;
                        case 3: case 7:
P
pbrook 已提交
5219 5220
                            gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
                            gen_neon_addl_saturate(cpu_V0, cpu_V1, size);
P
pbrook 已提交
5221 5222 5223 5224 5225
                            break;
                        case 10:
                            /* no-op */
                            break;
                        case 11:
P
pbrook 已提交
5226
                            gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
P
pbrook 已提交
5227 5228 5229 5230
                            break;
                        default:
                            abort();
                        }
P
pbrook 已提交
5231
                        neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
5232
                    }
5233 5234 5235

                    dead_tmp(tmp2);

P
pbrook 已提交
5236 5237 5238 5239 5240 5241 5242 5243 5244
                    break;
                default: /* 14 and 15 are RESERVED */
                    return 1;
                }
            }
        } else { /* size == 3 */
            if (!u) {
                /* Extract.  */
                imm = (insn >> 8) & 0xf;
P
pbrook 已提交
5245 5246 5247 5248 5249 5250 5251 5252

                if (imm > 7 && !q)
                    return 1;

                if (imm == 0) {
                    neon_load_reg64(cpu_V0, rn);
                    if (q) {
                        neon_load_reg64(cpu_V1, rn + 1);
P
pbrook 已提交
5253
                    }
P
pbrook 已提交
5254 5255 5256 5257
                } else if (imm == 8) {
                    neon_load_reg64(cpu_V0, rn + 1);
                    if (q) {
                        neon_load_reg64(cpu_V1, rm);
P
pbrook 已提交
5258
                    }
P
pbrook 已提交
5259
                } else if (q) {
P
pbrook 已提交
5260
                    tmp64 = tcg_temp_new_i64();
P
pbrook 已提交
5261 5262
                    if (imm < 8) {
                        neon_load_reg64(cpu_V0, rn);
P
pbrook 已提交
5263
                        neon_load_reg64(tmp64, rn + 1);
P
pbrook 已提交
5264 5265
                    } else {
                        neon_load_reg64(cpu_V0, rn + 1);
P
pbrook 已提交
5266
                        neon_load_reg64(tmp64, rm);
P
pbrook 已提交
5267 5268
                    }
                    tcg_gen_shri_i64(cpu_V0, cpu_V0, (imm & 7) * 8);
P
pbrook 已提交
5269
                    tcg_gen_shli_i64(cpu_V1, tmp64, 64 - ((imm & 7) * 8));
P
pbrook 已提交
5270 5271 5272
                    tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1);
                    if (imm < 8) {
                        neon_load_reg64(cpu_V1, rm);
P
pbrook 已提交
5273
                    } else {
P
pbrook 已提交
5274 5275
                        neon_load_reg64(cpu_V1, rm + 1);
                        imm -= 8;
P
pbrook 已提交
5276
                    }
P
pbrook 已提交
5277
                    tcg_gen_shli_i64(cpu_V1, cpu_V1, 64 - (imm * 8));
P
pbrook 已提交
5278 5279
                    tcg_gen_shri_i64(tmp64, tmp64, imm * 8);
                    tcg_gen_or_i64(cpu_V1, cpu_V1, tmp64);
5280
                    tcg_temp_free_i64(tmp64);
P
pbrook 已提交
5281
                } else {
P
pbrook 已提交
5282
                    /* BUGFIX */
P
pbrook 已提交
5283
                    neon_load_reg64(cpu_V0, rn);
P
pbrook 已提交
5284
                    tcg_gen_shri_i64(cpu_V0, cpu_V0, imm * 8);
P
pbrook 已提交
5285
                    neon_load_reg64(cpu_V1, rm);
P
pbrook 已提交
5286
                    tcg_gen_shli_i64(cpu_V1, cpu_V1, 64 - (imm * 8));
P
pbrook 已提交
5287 5288 5289 5290 5291
                    tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1);
                }
                neon_store_reg64(cpu_V0, rd);
                if (q) {
                    neon_store_reg64(cpu_V1, rd + 1);
P
pbrook 已提交
5292 5293 5294 5295 5296 5297 5298 5299 5300 5301
                }
            } else if ((insn & (1 << 11)) == 0) {
                /* Two register misc.  */
                op = ((insn >> 12) & 0x30) | ((insn >> 7) & 0xf);
                size = (insn >> 18) & 3;
                switch (op) {
                case 0: /* VREV64 */
                    if (size == 3)
                        return 1;
                    for (pass = 0; pass < (q ? 2 : 1); pass++) {
5302 5303
                        tmp = neon_load_reg(rm, pass * 2);
                        tmp2 = neon_load_reg(rm, pass * 2 + 1);
P
pbrook 已提交
5304
                        switch (size) {
5305 5306
                        case 0: tcg_gen_bswap32_i32(tmp, tmp); break;
                        case 1: gen_swap_half(tmp); break;
P
pbrook 已提交
5307 5308 5309
                        case 2: /* no-op */ break;
                        default: abort();
                        }
5310
                        neon_store_reg(rd, pass * 2 + 1, tmp);
P
pbrook 已提交
5311
                        if (size == 2) {
5312
                            neon_store_reg(rd, pass * 2, tmp2);
P
pbrook 已提交
5313 5314
                        } else {
                            switch (size) {
5315 5316
                            case 0: tcg_gen_bswap32_i32(tmp2, tmp2); break;
                            case 1: gen_swap_half(tmp2); break;
P
pbrook 已提交
5317 5318
                            default: abort();
                            }
5319
                            neon_store_reg(rd, pass * 2, tmp2);
P
pbrook 已提交
5320 5321 5322 5323 5324 5325 5326
                        }
                    }
                    break;
                case 4: case 5: /* VPADDL */
                case 12: case 13: /* VPADAL */
                    if (size == 3)
                        return 1;
P
pbrook 已提交
5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337
                    for (pass = 0; pass < q + 1; pass++) {
                        tmp = neon_load_reg(rm, pass * 2);
                        gen_neon_widen(cpu_V0, tmp, size, op & 1);
                        tmp = neon_load_reg(rm, pass * 2 + 1);
                        gen_neon_widen(cpu_V1, tmp, size, op & 1);
                        switch (size) {
                        case 0: gen_helper_neon_paddl_u16(CPU_V001); break;
                        case 1: gen_helper_neon_paddl_u32(CPU_V001); break;
                        case 2: tcg_gen_add_i64(CPU_V001); break;
                        default: abort();
                        }
P
pbrook 已提交
5338 5339
                        if (op >= 12) {
                            /* Accumulate.  */
P
pbrook 已提交
5340 5341
                            neon_load_reg64(cpu_V1, rd + pass);
                            gen_neon_addl(size);
P
pbrook 已提交
5342
                        }
P
pbrook 已提交
5343
                        neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
5344 5345 5346 5347 5348
                    }
                    break;
                case 33: /* VTRN */
                    if (size == 2) {
                        for (n = 0; n < (q ? 4 : 2); n += 2) {
5349 5350 5351 5352
                            tmp = neon_load_reg(rm, n);
                            tmp2 = neon_load_reg(rd, n + 1);
                            neon_store_reg(rm, n, tmp2);
                            neon_store_reg(rd, n + 1, tmp);
P
pbrook 已提交
5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371
                        }
                    } else {
                        goto elementwise;
                    }
                    break;
                case 34: /* VUZP */
                    /* Reg  Before       After
                       Rd   A3 A2 A1 A0  B2 B0 A2 A0
                       Rm   B3 B2 B1 B0  B3 B1 A3 A1
                     */
                    if (size == 3)
                        return 1;
                    gen_neon_unzip(rd, q, 0, size);
                    gen_neon_unzip(rm, q, 4, size);
                    if (q) {
                        static int unzip_order_q[8] =
                            {0, 2, 4, 6, 1, 3, 5, 7};
                        for (n = 0; n < 8; n++) {
                            int reg = (n < 4) ? rd : rm;
5372 5373
                            tmp = neon_load_scratch(unzip_order_q[n]);
                            neon_store_reg(reg, n % 4, tmp);
P
pbrook 已提交
5374 5375 5376 5377 5378 5379
                        }
                    } else {
                        static int unzip_order[4] =
                            {0, 4, 1, 5};
                        for (n = 0; n < 4; n++) {
                            int reg = (n < 2) ? rd : rm;
5380 5381
                            tmp = neon_load_scratch(unzip_order[n]);
                            neon_store_reg(reg, n % 2, tmp);
P
pbrook 已提交
5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393
                        }
                    }
                    break;
                case 35: /* VZIP */
                    /* Reg  Before       After
                       Rd   A3 A2 A1 A0  B1 A1 B0 A0
                       Rm   B3 B2 B1 B0  B3 A3 B2 A2
                     */
                    if (size == 3)
                        return 1;
                    count = (q ? 4 : 2);
                    for (n = 0; n < count; n++) {
5394 5395
                        tmp = neon_load_reg(rd, n);
                        tmp2 = neon_load_reg(rd, n);
P
pbrook 已提交
5396
                        switch (size) {
5397 5398
                        case 0: gen_neon_zip_u8(tmp, tmp2); break;
                        case 1: gen_neon_zip_u16(tmp, tmp2); break;
P
pbrook 已提交
5399 5400 5401
                        case 2: /* no-op */; break;
                        default: abort();
                        }
5402 5403
                        neon_store_scratch(n * 2, tmp);
                        neon_store_scratch(n * 2 + 1, tmp2);
P
pbrook 已提交
5404 5405 5406
                    }
                    for (n = 0; n < count * 2; n++) {
                        int reg = (n < count) ? rd : rm;
5407 5408
                        tmp = neon_load_scratch(n);
                        neon_store_reg(reg, n % count, tmp);
P
pbrook 已提交
5409 5410 5411
                    }
                    break;
                case 36: case 37: /* VMOVN, VQMOVUN, VQMOVN */
P
pbrook 已提交
5412 5413
                    if (size == 3)
                        return 1;
P
pbrook 已提交
5414
                    TCGV_UNUSED(tmp2);
P
pbrook 已提交
5415
                    for (pass = 0; pass < 2; pass++) {
P
pbrook 已提交
5416 5417
                        neon_load_reg64(cpu_V0, rm + pass);
                        tmp = new_tmp();
P
pbrook 已提交
5418
                        if (op == 36 && q == 0) {
P
pbrook 已提交
5419
                            gen_neon_narrow(size, tmp, cpu_V0);
P
pbrook 已提交
5420
                        } else if (q) {
P
pbrook 已提交
5421
                            gen_neon_narrow_satu(size, tmp, cpu_V0);
P
pbrook 已提交
5422
                        } else {
P
pbrook 已提交
5423 5424 5425 5426 5427 5428 5429
                            gen_neon_narrow_sats(size, tmp, cpu_V0);
                        }
                        if (pass == 0) {
                            tmp2 = tmp;
                        } else {
                            neon_store_reg(rd, 0, tmp2);
                            neon_store_reg(rd, 1, tmp);
P
pbrook 已提交
5430 5431 5432 5433
                        }
                    }
                    break;
                case 38: /* VSHLL */
P
pbrook 已提交
5434
                    if (q || size == 3)
P
pbrook 已提交
5435
                        return 1;
P
pbrook 已提交
5436 5437
                    tmp = neon_load_reg(rm, 0);
                    tmp2 = neon_load_reg(rm, 1);
P
pbrook 已提交
5438
                    for (pass = 0; pass < 2; pass++) {
P
pbrook 已提交
5439 5440 5441
                        if (pass == 1)
                            tmp = tmp2;
                        gen_neon_widen(cpu_V0, tmp, size, 1);
5442
                        tcg_gen_shli_i64(cpu_V0, cpu_V0, 8 << size);
P
pbrook 已提交
5443
                        neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
5444 5445
                    }
                    break;
P
Paul Brook 已提交
5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489
                case 44: /* VCVT.F16.F32 */
                    if (!arm_feature(env, ARM_FEATURE_VFP_FP16))
                      return 1;
                    tmp = new_tmp();
                    tmp2 = new_tmp();
                    tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 0));
                    gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
                    tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 1));
                    gen_helper_vfp_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env);
                    tcg_gen_shli_i32(tmp2, tmp2, 16);
                    tcg_gen_or_i32(tmp2, tmp2, tmp);
                    tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 2));
                    gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
                    tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 3));
                    neon_store_reg(rd, 0, tmp2);
                    tmp2 = new_tmp();
                    gen_helper_vfp_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env);
                    tcg_gen_shli_i32(tmp2, tmp2, 16);
                    tcg_gen_or_i32(tmp2, tmp2, tmp);
                    neon_store_reg(rd, 1, tmp2);
                    dead_tmp(tmp);
                    break;
                case 46: /* VCVT.F32.F16 */
                    if (!arm_feature(env, ARM_FEATURE_VFP_FP16))
                      return 1;
                    tmp3 = new_tmp();
                    tmp = neon_load_reg(rm, 0);
                    tmp2 = neon_load_reg(rm, 1);
                    tcg_gen_ext16u_i32(tmp3, tmp);
                    gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
                    tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 0));
                    tcg_gen_shri_i32(tmp3, tmp, 16);
                    gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
                    tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 1));
                    dead_tmp(tmp);
                    tcg_gen_ext16u_i32(tmp3, tmp2);
                    gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
                    tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 2));
                    tcg_gen_shri_i32(tmp3, tmp2, 16);
                    gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
                    tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 3));
                    dead_tmp(tmp2);
                    dead_tmp(tmp3);
                    break;
P
pbrook 已提交
5490 5491 5492 5493
                default:
                elementwise:
                    for (pass = 0; pass < (q ? 4 : 2); pass++) {
                        if (op == 30 || op == 31 || op >= 58) {
P
pbrook 已提交
5494 5495
                            tcg_gen_ld_f32(cpu_F0s, cpu_env,
                                           neon_reg_offset(rm, pass));
5496
                            TCGV_UNUSED(tmp);
P
pbrook 已提交
5497
                        } else {
5498
                            tmp = neon_load_reg(rm, pass);
P
pbrook 已提交
5499 5500 5501 5502
                        }
                        switch (op) {
                        case 1: /* VREV32 */
                            switch (size) {
5503 5504
                            case 0: tcg_gen_bswap32_i32(tmp, tmp); break;
                            case 1: gen_swap_half(tmp); break;
P
pbrook 已提交
5505 5506 5507 5508 5509 5510
                            default: return 1;
                            }
                            break;
                        case 2: /* VREV16 */
                            if (size != 0)
                                return 1;
5511
                            gen_rev16(tmp);
P
pbrook 已提交
5512 5513 5514
                            break;
                        case 8: /* CLS */
                            switch (size) {
5515 5516 5517
                            case 0: gen_helper_neon_cls_s8(tmp, tmp); break;
                            case 1: gen_helper_neon_cls_s16(tmp, tmp); break;
                            case 2: gen_helper_neon_cls_s32(tmp, tmp); break;
P
pbrook 已提交
5518 5519 5520 5521 5522
                            default: return 1;
                            }
                            break;
                        case 9: /* CLZ */
                            switch (size) {
5523 5524 5525
                            case 0: gen_helper_neon_clz_u8(tmp, tmp); break;
                            case 1: gen_helper_neon_clz_u16(tmp, tmp); break;
                            case 2: gen_helper_clz(tmp, tmp); break;
P
pbrook 已提交
5526 5527 5528 5529 5530 5531
                            default: return 1;
                            }
                            break;
                        case 10: /* CNT */
                            if (size != 0)
                                return 1;
5532
                            gen_helper_neon_cnt_u8(tmp, tmp);
P
pbrook 已提交
5533 5534 5535 5536
                            break;
                        case 11: /* VNOT */
                            if (size != 0)
                                return 1;
5537
                            tcg_gen_not_i32(tmp, tmp);
P
pbrook 已提交
5538 5539 5540
                            break;
                        case 14: /* VQABS */
                            switch (size) {
5541 5542 5543
                            case 0: gen_helper_neon_qabs_s8(tmp, cpu_env, tmp); break;
                            case 1: gen_helper_neon_qabs_s16(tmp, cpu_env, tmp); break;
                            case 2: gen_helper_neon_qabs_s32(tmp, cpu_env, tmp); break;
P
pbrook 已提交
5544 5545 5546 5547 5548
                            default: return 1;
                            }
                            break;
                        case 15: /* VQNEG */
                            switch (size) {
5549 5550 5551
                            case 0: gen_helper_neon_qneg_s8(tmp, cpu_env, tmp); break;
                            case 1: gen_helper_neon_qneg_s16(tmp, cpu_env, tmp); break;
                            case 2: gen_helper_neon_qneg_s32(tmp, cpu_env, tmp); break;
P
pbrook 已提交
5552 5553 5554 5555
                            default: return 1;
                            }
                            break;
                        case 16: case 19: /* VCGT #0, VCLE #0 */
5556
                            tmp2 = tcg_const_i32(0);
P
pbrook 已提交
5557
                            switch(size) {
5558 5559 5560
                            case 0: gen_helper_neon_cgt_s8(tmp, tmp, tmp2); break;
                            case 1: gen_helper_neon_cgt_s16(tmp, tmp, tmp2); break;
                            case 2: gen_helper_neon_cgt_s32(tmp, tmp, tmp2); break;
P
pbrook 已提交
5561 5562
                            default: return 1;
                            }
5563
                            tcg_temp_free(tmp2);
P
pbrook 已提交
5564
                            if (op == 19)
5565
                                tcg_gen_not_i32(tmp, tmp);
P
pbrook 已提交
5566 5567
                            break;
                        case 17: case 20: /* VCGE #0, VCLT #0 */
5568
                            tmp2 = tcg_const_i32(0);
P
pbrook 已提交
5569
                            switch(size) {
5570 5571 5572
                            case 0: gen_helper_neon_cge_s8(tmp, tmp, tmp2); break;
                            case 1: gen_helper_neon_cge_s16(tmp, tmp, tmp2); break;
                            case 2: gen_helper_neon_cge_s32(tmp, tmp, tmp2); break;
P
pbrook 已提交
5573 5574
                            default: return 1;
                            }
5575
                            tcg_temp_free(tmp2);
P
pbrook 已提交
5576
                            if (op == 20)
5577
                                tcg_gen_not_i32(tmp, tmp);
P
pbrook 已提交
5578 5579
                            break;
                        case 18: /* VCEQ #0 */
5580
                            tmp2 = tcg_const_i32(0);
P
pbrook 已提交
5581
                            switch(size) {
5582 5583 5584
                            case 0: gen_helper_neon_ceq_u8(tmp, tmp, tmp2); break;
                            case 1: gen_helper_neon_ceq_u16(tmp, tmp, tmp2); break;
                            case 2: gen_helper_neon_ceq_u32(tmp, tmp, tmp2); break;
P
pbrook 已提交
5585 5586
                            default: return 1;
                            }
5587
                            tcg_temp_free(tmp2);
P
pbrook 已提交
5588 5589 5590
                            break;
                        case 22: /* VABS */
                            switch(size) {
5591 5592 5593
                            case 0: gen_helper_neon_abs_s8(tmp, tmp); break;
                            case 1: gen_helper_neon_abs_s16(tmp, tmp); break;
                            case 2: tcg_gen_abs_i32(tmp, tmp); break;
P
pbrook 已提交
5594 5595 5596 5597
                            default: return 1;
                            }
                            break;
                        case 23: /* VNEG */
P
pbrook 已提交
5598 5599
                            if (size == 3)
                                return 1;
5600 5601 5602
                            tmp2 = tcg_const_i32(0);
                            gen_neon_rsb(size, tmp, tmp2);
                            tcg_temp_free(tmp2);
P
pbrook 已提交
5603 5604
                            break;
                        case 24: case 27: /* Float VCGT #0, Float VCLE #0 */
5605 5606 5607
                            tmp2 = tcg_const_i32(0);
                            gen_helper_neon_cgt_f32(tmp, tmp, tmp2);
                            tcg_temp_free(tmp2);
P
pbrook 已提交
5608
                            if (op == 27)
5609
                                tcg_gen_not_i32(tmp, tmp);
P
pbrook 已提交
5610 5611
                            break;
                        case 25: case 28: /* Float VCGE #0, Float VCLT #0 */
5612 5613 5614
                            tmp2 = tcg_const_i32(0);
                            gen_helper_neon_cge_f32(tmp, tmp, tmp2);
                            tcg_temp_free(tmp2);
P
pbrook 已提交
5615
                            if (op == 28)
5616
                                tcg_gen_not_i32(tmp, tmp);
P
pbrook 已提交
5617 5618
                            break;
                        case 26: /* Float VCEQ #0 */
5619 5620 5621
                            tmp2 = tcg_const_i32(0);
                            gen_helper_neon_ceq_f32(tmp, tmp, tmp2);
                            tcg_temp_free(tmp2);
P
pbrook 已提交
5622 5623
                            break;
                        case 30: /* Float VABS */
P
pbrook 已提交
5624
                            gen_vfp_abs(0);
P
pbrook 已提交
5625 5626
                            break;
                        case 31: /* Float VNEG */
P
pbrook 已提交
5627
                            gen_vfp_neg(0);
P
pbrook 已提交
5628 5629
                            break;
                        case 32: /* VSWP */
5630 5631
                            tmp2 = neon_load_reg(rd, pass);
                            neon_store_reg(rm, pass, tmp2);
P
pbrook 已提交
5632 5633
                            break;
                        case 33: /* VTRN */
5634
                            tmp2 = neon_load_reg(rd, pass);
P
pbrook 已提交
5635
                            switch (size) {
5636 5637
                            case 0: gen_neon_trn_u8(tmp, tmp2); break;
                            case 1: gen_neon_trn_u16(tmp, tmp2); break;
P
pbrook 已提交
5638 5639 5640
                            case 2: abort();
                            default: return 1;
                            }
5641
                            neon_store_reg(rm, pass, tmp2);
P
pbrook 已提交
5642 5643
                            break;
                        case 56: /* Integer VRECPE */
5644
                            gen_helper_recpe_u32(tmp, tmp, cpu_env);
P
pbrook 已提交
5645 5646
                            break;
                        case 57: /* Integer VRSQRTE */
5647
                            gen_helper_rsqrte_u32(tmp, tmp, cpu_env);
P
pbrook 已提交
5648 5649
                            break;
                        case 58: /* Float VRECPE */
P
pbrook 已提交
5650
                            gen_helper_recpe_f32(cpu_F0s, cpu_F0s, cpu_env);
P
pbrook 已提交
5651 5652
                            break;
                        case 59: /* Float VRSQRTE */
P
pbrook 已提交
5653
                            gen_helper_rsqrte_f32(cpu_F0s, cpu_F0s, cpu_env);
P
pbrook 已提交
5654 5655
                            break;
                        case 60: /* VCVT.F32.S32 */
P
pbrook 已提交
5656
                            gen_vfp_tosiz(0);
P
pbrook 已提交
5657 5658
                            break;
                        case 61: /* VCVT.F32.U32 */
P
pbrook 已提交
5659
                            gen_vfp_touiz(0);
P
pbrook 已提交
5660 5661
                            break;
                        case 62: /* VCVT.S32.F32 */
P
pbrook 已提交
5662
                            gen_vfp_sito(0);
P
pbrook 已提交
5663 5664
                            break;
                        case 63: /* VCVT.U32.F32 */
P
pbrook 已提交
5665
                            gen_vfp_uito(0);
P
pbrook 已提交
5666 5667 5668 5669 5670 5671
                            break;
                        default:
                            /* Reserved: 21, 29, 39-56 */
                            return 1;
                        }
                        if (op == 30 || op == 31 || op >= 58) {
P
pbrook 已提交
5672 5673
                            tcg_gen_st_f32(cpu_F0s, cpu_env,
                                           neon_reg_offset(rd, pass));
P
pbrook 已提交
5674
                        } else {
5675
                            neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
5676 5677 5678 5679 5680 5681
                        }
                    }
                    break;
                }
            } else if ((insn & (1 << 10)) == 0) {
                /* VTBL, VTBX.  */
P
pbrook 已提交
5682
                n = ((insn >> 5) & 0x18) + 8;
P
pbrook 已提交
5683
                if (insn & (1 << 6)) {
P
pbrook 已提交
5684
                    tmp = neon_load_reg(rd, 0);
P
pbrook 已提交
5685
                } else {
P
pbrook 已提交
5686 5687
                    tmp = new_tmp();
                    tcg_gen_movi_i32(tmp, 0);
P
pbrook 已提交
5688
                }
P
pbrook 已提交
5689
                tmp2 = neon_load_reg(rm, 0);
5690 5691 5692
                tmp4 = tcg_const_i32(rn);
                tmp5 = tcg_const_i32(n);
                gen_helper_neon_tbl(tmp2, tmp2, tmp, tmp4, tmp5);
P
pbrook 已提交
5693
                dead_tmp(tmp);
P
pbrook 已提交
5694
                if (insn & (1 << 6)) {
P
pbrook 已提交
5695
                    tmp = neon_load_reg(rd, 1);
P
pbrook 已提交
5696
                } else {
P
pbrook 已提交
5697 5698
                    tmp = new_tmp();
                    tcg_gen_movi_i32(tmp, 0);
P
pbrook 已提交
5699
                }
P
pbrook 已提交
5700
                tmp3 = neon_load_reg(rm, 1);
5701
                gen_helper_neon_tbl(tmp3, tmp3, tmp, tmp4, tmp5);
5702 5703
                tcg_temp_free_i32(tmp5);
                tcg_temp_free_i32(tmp4);
P
pbrook 已提交
5704
                neon_store_reg(rd, 0, tmp2);
P
pbrook 已提交
5705 5706
                neon_store_reg(rd, 1, tmp3);
                dead_tmp(tmp);
P
pbrook 已提交
5707 5708 5709
            } else if ((insn & 0x380) == 0) {
                /* VDUP */
                if (insn & (1 << 19)) {
5710
                    tmp = neon_load_reg(rm, 1);
P
pbrook 已提交
5711
                } else {
5712
                    tmp = neon_load_reg(rm, 0);
P
pbrook 已提交
5713 5714
                }
                if (insn & (1 << 16)) {
5715
                    gen_neon_dup_u8(tmp, ((insn >> 17) & 3) * 8);
P
pbrook 已提交
5716 5717
                } else if (insn & (1 << 17)) {
                    if ((insn >> 18) & 1)
5718
                        gen_neon_dup_high16(tmp);
P
pbrook 已提交
5719
                    else
5720
                        gen_neon_dup_low16(tmp);
P
pbrook 已提交
5721 5722
                }
                for (pass = 0; pass < (q ? 4 : 2); pass++) {
5723 5724 5725
                    tmp2 = new_tmp();
                    tcg_gen_mov_i32(tmp2, tmp);
                    neon_store_reg(rd, pass, tmp2);
P
pbrook 已提交
5726
                }
5727
                dead_tmp(tmp);
P
pbrook 已提交
5728 5729 5730 5731 5732 5733 5734 5735
            } else {
                return 1;
            }
        }
    }
    return 0;
}

5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799 5800
static int disas_cp14_read(CPUState * env, DisasContext *s, uint32_t insn)
{
    int crn = (insn >> 16) & 0xf;
    int crm = insn & 0xf;
    int op1 = (insn >> 21) & 7;
    int op2 = (insn >> 5) & 7;
    int rt = (insn >> 12) & 0xf;
    TCGv tmp;

    if (arm_feature(env, ARM_FEATURE_THUMB2EE)) {
        if (op1 == 6 && crn == 0 && crm == 0 && op2 == 0) {
            /* TEECR */
            if (IS_USER(s))
                return 1;
            tmp = load_cpu_field(teecr);
            store_reg(s, rt, tmp);
            return 0;
        }
        if (op1 == 6 && crn == 1 && crm == 0 && op2 == 0) {
            /* TEEHBR */
            if (IS_USER(s) && (env->teecr & 1))
                return 1;
            tmp = load_cpu_field(teehbr);
            store_reg(s, rt, tmp);
            return 0;
        }
    }
    fprintf(stderr, "Unknown cp14 read op1:%d crn:%d crm:%d op2:%d\n",
            op1, crn, crm, op2);
    return 1;
}

static int disas_cp14_write(CPUState * env, DisasContext *s, uint32_t insn)
{
    int crn = (insn >> 16) & 0xf;
    int crm = insn & 0xf;
    int op1 = (insn >> 21) & 7;
    int op2 = (insn >> 5) & 7;
    int rt = (insn >> 12) & 0xf;
    TCGv tmp;

    if (arm_feature(env, ARM_FEATURE_THUMB2EE)) {
        if (op1 == 6 && crn == 0 && crm == 0 && op2 == 0) {
            /* TEECR */
            if (IS_USER(s))
                return 1;
            tmp = load_reg(s, rt);
            gen_helper_set_teecr(cpu_env, tmp);
            dead_tmp(tmp);
            return 0;
        }
        if (op1 == 6 && crn == 1 && crm == 0 && op2 == 0) {
            /* TEEHBR */
            if (IS_USER(s) && (env->teecr & 1))
                return 1;
            tmp = load_reg(s, rt);
            store_cpu_field(tmp, teehbr);
            return 0;
        }
    }
    fprintf(stderr, "Unknown cp14 write op1:%d crn:%d crm:%d op2:%d\n",
            op1, crn, crm, op2);
    return 1;
}

P
pbrook 已提交
5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821
static int disas_coproc_insn(CPUState * env, DisasContext *s, uint32_t insn)
{
    int cpnum;

    cpnum = (insn >> 8) & 0xf;
    if (arm_feature(env, ARM_FEATURE_XSCALE)
	    && ((env->cp15.c15_cpar ^ 0x3fff) & (1 << cpnum)))
	return 1;

    switch (cpnum) {
      case 0:
      case 1:
	if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
	    return disas_iwmmxt_insn(env, s, insn);
	} else if (arm_feature(env, ARM_FEATURE_XSCALE)) {
	    return disas_dsp_insn(env, s, insn);
	}
	return 1;
    case 10:
    case 11:
	return disas_vfp_insn (env, s, insn);
5822 5823 5824 5825 5826 5827 5828 5829 5830
    case 14:
        /* Coprocessors 7-15 are architecturally reserved by ARM.
           Unfortunately Intel decided to ignore this.  */
        if (arm_feature(env, ARM_FEATURE_XSCALE))
            goto board;
        if (insn & (1 << 20))
            return disas_cp14_read(env, s, insn);
        else
            return disas_cp14_write(env, s, insn);
P
pbrook 已提交
5831 5832 5833
    case 15:
	return disas_cp15_insn (env, s, insn);
    default:
5834
    board:
P
pbrook 已提交
5835 5836 5837 5838 5839
	/* Unknown coprocessor.  See if the board has hooked it.  */
	return disas_cp_insn (env, s, insn);
    }
}

P
pbrook 已提交
5840 5841

/* Store a 64-bit value to a register pair.  Clobbers val.  */
P
pbrook 已提交
5842
static void gen_storeq_reg(DisasContext *s, int rlow, int rhigh, TCGv_i64 val)
P
pbrook 已提交
5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854
{
    TCGv tmp;
    tmp = new_tmp();
    tcg_gen_trunc_i64_i32(tmp, val);
    store_reg(s, rlow, tmp);
    tmp = new_tmp();
    tcg_gen_shri_i64(val, val, 32);
    tcg_gen_trunc_i64_i32(tmp, val);
    store_reg(s, rhigh, tmp);
}

/* load a 32-bit value from a register and perform a 64-bit accumulate.  */
P
pbrook 已提交
5855
static void gen_addq_lo(DisasContext *s, TCGv_i64 val, int rlow)
P
pbrook 已提交
5856
{
P
pbrook 已提交
5857
    TCGv_i64 tmp;
P
pbrook 已提交
5858 5859
    TCGv tmp2;

P
pbrook 已提交
5860
    /* Load value and extend to 64 bits.  */
P
pbrook 已提交
5861
    tmp = tcg_temp_new_i64();
P
pbrook 已提交
5862 5863 5864 5865
    tmp2 = load_reg(s, rlow);
    tcg_gen_extu_i32_i64(tmp, tmp2);
    dead_tmp(tmp2);
    tcg_gen_add_i64(val, val, tmp);
5866
    tcg_temp_free_i64(tmp);
P
pbrook 已提交
5867 5868 5869
}

/* load and add a 64-bit value from a register pair.  */
P
pbrook 已提交
5870
static void gen_addq(DisasContext *s, TCGv_i64 val, int rlow, int rhigh)
P
pbrook 已提交
5871
{
P
pbrook 已提交
5872
    TCGv_i64 tmp;
P
pbrook 已提交
5873 5874
    TCGv tmpl;
    TCGv tmph;
P
pbrook 已提交
5875 5876

    /* Load 64-bit value rd:rn.  */
P
pbrook 已提交
5877 5878
    tmpl = load_reg(s, rlow);
    tmph = load_reg(s, rhigh);
P
pbrook 已提交
5879
    tmp = tcg_temp_new_i64();
P
pbrook 已提交
5880 5881 5882
    tcg_gen_concat_i32_i64(tmp, tmpl, tmph);
    dead_tmp(tmpl);
    dead_tmp(tmph);
P
pbrook 已提交
5883
    tcg_gen_add_i64(val, val, tmp);
5884
    tcg_temp_free_i64(tmp);
P
pbrook 已提交
5885 5886 5887
}

/* Set N and Z flags from a 64-bit value.  */
P
pbrook 已提交
5888
static void gen_logicq_cc(TCGv_i64 val)
P
pbrook 已提交
5889 5890 5891
{
    TCGv tmp = new_tmp();
    gen_helper_logicq_cc(tmp, val);
P
pbrook 已提交
5892 5893
    gen_logic_CC(tmp);
    dead_tmp(tmp);
P
pbrook 已提交
5894 5895
}

P
Paul Brook 已提交
5896 5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021
/* Load/Store exclusive instructions are implemented by remembering
   the value/address loaded, and seeing if these are the same
   when the store is performed. This should be is sufficient to implement
   the architecturally mandated semantics, and avoids having to monitor
   regular stores.

   In system emulation mode only one CPU will be running at once, so
   this sequence is effectively atomic.  In user emulation mode we
   throw an exception and handle the atomic operation elsewhere.  */
static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
                               TCGv addr, int size)
{
    TCGv tmp;

    switch (size) {
    case 0:
        tmp = gen_ld8u(addr, IS_USER(s));
        break;
    case 1:
        tmp = gen_ld16u(addr, IS_USER(s));
        break;
    case 2:
    case 3:
        tmp = gen_ld32(addr, IS_USER(s));
        break;
    default:
        abort();
    }
    tcg_gen_mov_i32(cpu_exclusive_val, tmp);
    store_reg(s, rt, tmp);
    if (size == 3) {
        tcg_gen_addi_i32(addr, addr, 4);
        tmp = gen_ld32(addr, IS_USER(s));
        tcg_gen_mov_i32(cpu_exclusive_high, tmp);
        store_reg(s, rt2, tmp);
    }
    tcg_gen_mov_i32(cpu_exclusive_addr, addr);
}

static void gen_clrex(DisasContext *s)
{
    tcg_gen_movi_i32(cpu_exclusive_addr, -1);
}

#ifdef CONFIG_USER_ONLY
static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
                                TCGv addr, int size)
{
    tcg_gen_mov_i32(cpu_exclusive_test, addr);
    tcg_gen_movi_i32(cpu_exclusive_info,
                     size | (rd << 4) | (rt << 8) | (rt2 << 12));
    gen_set_condexec(s);
    gen_set_pc_im(s->pc - 4);
    gen_exception(EXCP_STREX);
    s->is_jmp = DISAS_JUMP;
}
#else
static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
                                TCGv addr, int size)
{
    TCGv tmp;
    int done_label;
    int fail_label;

    /* if (env->exclusive_addr == addr && env->exclusive_val == [addr]) {
         [addr] = {Rt};
         {Rd} = 0;
       } else {
         {Rd} = 1;
       } */
    fail_label = gen_new_label();
    done_label = gen_new_label();
    tcg_gen_brcond_i32(TCG_COND_NE, addr, cpu_exclusive_addr, fail_label);
    switch (size) {
    case 0:
        tmp = gen_ld8u(addr, IS_USER(s));
        break;
    case 1:
        tmp = gen_ld16u(addr, IS_USER(s));
        break;
    case 2:
    case 3:
        tmp = gen_ld32(addr, IS_USER(s));
        break;
    default:
        abort();
    }
    tcg_gen_brcond_i32(TCG_COND_NE, tmp, cpu_exclusive_val, fail_label);
    dead_tmp(tmp);
    if (size == 3) {
        TCGv tmp2 = new_tmp();
        tcg_gen_addi_i32(tmp2, addr, 4);
        tmp = gen_ld32(addr, IS_USER(s));
        dead_tmp(tmp2);
        tcg_gen_brcond_i32(TCG_COND_NE, tmp, cpu_exclusive_high, fail_label);
        dead_tmp(tmp);
    }
    tmp = load_reg(s, rt);
    switch (size) {
    case 0:
        gen_st8(tmp, addr, IS_USER(s));
        break;
    case 1:
        gen_st16(tmp, addr, IS_USER(s));
        break;
    case 2:
    case 3:
        gen_st32(tmp, addr, IS_USER(s));
        break;
    default:
        abort();
    }
    if (size == 3) {
        tcg_gen_addi_i32(addr, addr, 4);
        tmp = load_reg(s, rt2);
        gen_st32(tmp, addr, IS_USER(s));
    }
    tcg_gen_movi_i32(cpu_R[rd], 0);
    tcg_gen_br(done_label);
    gen_set_label(fail_label);
    tcg_gen_movi_i32(cpu_R[rd], 1);
    gen_set_label(done_label);
    tcg_gen_movi_i32(cpu_exclusive_addr, -1);
}
#endif

P
pbrook 已提交
6022 6023 6024
static void disas_arm_insn(CPUState * env, DisasContext *s)
{
    unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;
P
pbrook 已提交
6025
    TCGv tmp;
P
pbrook 已提交
6026
    TCGv tmp2;
P
pbrook 已提交
6027
    TCGv tmp3;
P
pbrook 已提交
6028
    TCGv addr;
P
pbrook 已提交
6029
    TCGv_i64 tmp64;
P
pbrook 已提交
6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071

    insn = ldl_code(s->pc);
    s->pc += 4;

    /* M variants do not implement ARM mode.  */
    if (IS_M(env))
        goto illegal_op;
    cond = insn >> 28;
    if (cond == 0xf){
        /* Unconditional instructions.  */
        if (((insn >> 25) & 7) == 1) {
            /* NEON Data processing.  */
            if (!arm_feature(env, ARM_FEATURE_NEON))
                goto illegal_op;

            if (disas_neon_data_insn(env, s, insn))
                goto illegal_op;
            return;
        }
        if ((insn & 0x0f100000) == 0x04000000) {
            /* NEON load/store.  */
            if (!arm_feature(env, ARM_FEATURE_NEON))
                goto illegal_op;

            if (disas_neon_ls_insn(env, s, insn))
                goto illegal_op;
            return;
        }
        if ((insn & 0x0d70f000) == 0x0550f000)
            return; /* PLD */
        else if ((insn & 0x0ffffdff) == 0x01010000) {
            ARCH(6);
            /* setend */
            if (insn & (1 << 9)) {
                /* BE8 mode not implemented.  */
                goto illegal_op;
            }
            return;
        } else if ((insn & 0x0fffff00) == 0x057ff000) {
            switch ((insn >> 4) & 0xf) {
            case 1: /* clrex */
                ARCH(6K);
P
Paul Brook 已提交
6072
                gen_clrex(s);
P
pbrook 已提交
6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084
                return;
            case 4: /* dsb */
            case 5: /* dmb */
            case 6: /* isb */
                ARCH(7);
                /* We don't emulate caches so these are a no-op.  */
                return;
            default:
                goto illegal_op;
            }
        } else if ((insn & 0x0e5fffe0) == 0x084d0500) {
            /* srs */
6085
            int32_t offset;
P
pbrook 已提交
6086 6087 6088 6089 6090
            if (IS_USER(s))
                goto illegal_op;
            ARCH(6);
            op1 = (insn & 0x1f);
            if (op1 == (env->uncached_cpsr & CPSR_M)) {
P
pbrook 已提交
6091
                addr = load_reg(s, 13);
P
pbrook 已提交
6092
            } else {
P
pbrook 已提交
6093
                addr = new_tmp();
6094 6095 6096
                tmp = tcg_const_i32(op1);
                gen_helper_get_r13_banked(addr, cpu_env, tmp);
                tcg_temp_free_i32(tmp);
P
pbrook 已提交
6097 6098 6099 6100
            }
            i = (insn >> 23) & 3;
            switch (i) {
            case 0: offset = -4; break; /* DA */
6101 6102
            case 1: offset = 0; break; /* IA */
            case 2: offset = -8; break; /* DB */
P
pbrook 已提交
6103 6104 6105 6106
            case 3: offset = 4; break; /* IB */
            default: abort();
            }
            if (offset)
P
pbrook 已提交
6107 6108 6109
                tcg_gen_addi_i32(addr, addr, offset);
            tmp = load_reg(s, 14);
            gen_st32(tmp, addr, 0);
6110
            tmp = load_cpu_field(spsr);
P
pbrook 已提交
6111 6112
            tcg_gen_addi_i32(addr, addr, 4);
            gen_st32(tmp, addr, 0);
P
pbrook 已提交
6113 6114 6115 6116
            if (insn & (1 << 21)) {
                /* Base writeback.  */
                switch (i) {
                case 0: offset = -8; break;
6117 6118
                case 1: offset = 4; break;
                case 2: offset = -4; break;
P
pbrook 已提交
6119 6120 6121 6122
                case 3: offset = 0; break;
                default: abort();
                }
                if (offset)
6123
                    tcg_gen_addi_i32(addr, addr, offset);
P
pbrook 已提交
6124
                if (op1 == (env->uncached_cpsr & CPSR_M)) {
6125
                    store_reg(s, 13, addr);
P
pbrook 已提交
6126
                } else {
6127 6128 6129
                    tmp = tcg_const_i32(op1);
                    gen_helper_set_r13_banked(cpu_env, tmp, addr);
                    tcg_temp_free_i32(tmp);
6130
                    dead_tmp(addr);
P
pbrook 已提交
6131
                }
P
pbrook 已提交
6132 6133
            } else {
                dead_tmp(addr);
P
pbrook 已提交
6134
            }
6135
            return;
6136
        } else if ((insn & 0x0e50ffe0) == 0x08100a00) {
P
pbrook 已提交
6137
            /* rfe */
6138
            int32_t offset;
P
pbrook 已提交
6139 6140 6141 6142
            if (IS_USER(s))
                goto illegal_op;
            ARCH(6);
            rn = (insn >> 16) & 0xf;
P
pbrook 已提交
6143
            addr = load_reg(s, rn);
P
pbrook 已提交
6144 6145
            i = (insn >> 23) & 3;
            switch (i) {
P
pbrook 已提交
6146
            case 0: offset = -4; break; /* DA */
6147 6148
            case 1: offset = 0; break; /* IA */
            case 2: offset = -8; break; /* DB */
P
pbrook 已提交
6149
            case 3: offset = 4; break; /* IB */
P
pbrook 已提交
6150 6151 6152
            default: abort();
            }
            if (offset)
P
pbrook 已提交
6153 6154 6155 6156 6157
                tcg_gen_addi_i32(addr, addr, offset);
            /* Load PC into tmp and CPSR into tmp2.  */
            tmp = gen_ld32(addr, 0);
            tcg_gen_addi_i32(addr, addr, 4);
            tmp2 = gen_ld32(addr, 0);
P
pbrook 已提交
6158 6159 6160
            if (insn & (1 << 21)) {
                /* Base writeback.  */
                switch (i) {
P
pbrook 已提交
6161
                case 0: offset = -8; break;
6162 6163
                case 1: offset = 4; break;
                case 2: offset = -4; break;
P
pbrook 已提交
6164
                case 3: offset = 0; break;
P
pbrook 已提交
6165 6166 6167
                default: abort();
                }
                if (offset)
P
pbrook 已提交
6168 6169 6170 6171
                    tcg_gen_addi_i32(addr, addr, offset);
                store_reg(s, rn, addr);
            } else {
                dead_tmp(addr);
P
pbrook 已提交
6172
            }
P
pbrook 已提交
6173
            gen_rfe(s, tmp, tmp2);
6174
            return;
P
pbrook 已提交
6175 6176 6177 6178 6179
        } else if ((insn & 0x0e000000) == 0x0a000000) {
            /* branch link and change to thumb (blx <offset>) */
            int32_t offset;

            val = (uint32_t)s->pc;
P
pbrook 已提交
6180 6181 6182
            tmp = new_tmp();
            tcg_gen_movi_i32(tmp, val);
            store_reg(s, 14, tmp);
P
pbrook 已提交
6183 6184 6185 6186 6187 6188
            /* Sign-extend the 24-bit offset */
            offset = (((int32_t)insn) << 8) >> 8;
            /* offset * 4 + bit24 * 2 + (thumb bit) */
            val += (offset << 2) | ((insn >> 23) & 2) | 1;
            /* pipeline offset */
            val += 4;
P
pbrook 已提交
6189
            gen_bx_im(s, val);
P
pbrook 已提交
6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201
            return;
        } else if ((insn & 0x0e000f00) == 0x0c000100) {
            if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
                /* iWMMXt register transfer.  */
                if (env->cp15.c15_cpar & (1 << 1))
                    if (!disas_iwmmxt_insn(env, s, insn))
                        return;
            }
        } else if ((insn & 0x0fe00000) == 0x0c400000) {
            /* Coprocessor double register transfer.  */
        } else if ((insn & 0x0f000010) == 0x0e000010) {
            /* Additional coprocessor register transfer.  */
B
balrog 已提交
6202
        } else if ((insn & 0x0ff10020) == 0x01000000) {
P
pbrook 已提交
6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218
            uint32_t mask;
            uint32_t val;
            /* cps (privileged) */
            if (IS_USER(s))
                return;
            mask = val = 0;
            if (insn & (1 << 19)) {
                if (insn & (1 << 8))
                    mask |= CPSR_A;
                if (insn & (1 << 7))
                    mask |= CPSR_I;
                if (insn & (1 << 6))
                    mask |= CPSR_F;
                if (insn & (1 << 18))
                    val |= mask;
            }
B
balrog 已提交
6219
            if (insn & (1 << 17)) {
P
pbrook 已提交
6220 6221 6222 6223
                mask |= CPSR_M;
                val |= (insn & 0x1f);
            }
            if (mask) {
6224
                gen_set_psr_im(s, mask, 0, val);
P
pbrook 已提交
6225 6226 6227 6228 6229 6230 6231 6232 6233
            }
            return;
        }
        goto illegal_op;
    }
    if (cond != 0xe) {
        /* if not always execute, we generate a conditional jump to
           next instruction */
        s->condlabel = gen_new_label();
P
pbrook 已提交
6234
        gen_test_cc(cond ^ 1, s->condlabel);
P
pbrook 已提交
6235 6236 6237 6238 6239 6240 6241 6242 6243
        s->condjmp = 1;
    }
    if ((insn & 0x0f900000) == 0x03000000) {
        if ((insn & (1 << 21)) == 0) {
            ARCH(6T2);
            rd = (insn >> 12) & 0xf;
            val = ((insn >> 4) & 0xf000) | (insn & 0xfff);
            if ((insn & (1 << 22)) == 0) {
                /* MOVW */
P
pbrook 已提交
6244 6245
                tmp = new_tmp();
                tcg_gen_movi_i32(tmp, val);
P
pbrook 已提交
6246 6247
            } else {
                /* MOVT */
P
pbrook 已提交
6248
                tmp = load_reg(s, rd);
P
pbrook 已提交
6249
                tcg_gen_ext16u_i32(tmp, tmp);
P
pbrook 已提交
6250
                tcg_gen_ori_i32(tmp, tmp, val << 16);
P
pbrook 已提交
6251
            }
P
pbrook 已提交
6252
            store_reg(s, rd, tmp);
P
pbrook 已提交
6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264
        } else {
            if (((insn >> 12) & 0xf) != 0xf)
                goto illegal_op;
            if (((insn >> 16) & 0xf) == 0) {
                gen_nop_hint(s, insn & 0xff);
            } else {
                /* CPSR = immediate */
                val = insn & 0xff;
                shift = ((insn >> 8) & 0xf) * 2;
                if (shift)
                    val = (val >> shift) | (val << (32 - shift));
                i = ((insn & (1 << 22)) != 0);
6265
                if (gen_set_psr_im(s, msr_mask(env, s, (insn >> 16) & 0xf, i), i, val))
P
pbrook 已提交
6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278
                    goto illegal_op;
            }
        }
    } else if ((insn & 0x0f900000) == 0x01000000
               && (insn & 0x00000090) != 0x00000090) {
        /* miscellaneous instructions */
        op1 = (insn >> 21) & 3;
        sh = (insn >> 4) & 0xf;
        rm = insn & 0xf;
        switch (sh) {
        case 0x0: /* move program status register */
            if (op1 & 1) {
                /* PSR = reg */
6279
                tmp = load_reg(s, rm);
P
pbrook 已提交
6280
                i = ((op1 & 2) != 0);
6281
                if (gen_set_psr(s, msr_mask(env, s, (insn >> 16) & 0xf, i), i, tmp))
P
pbrook 已提交
6282 6283 6284 6285 6286 6287 6288
                    goto illegal_op;
            } else {
                /* reg = PSR */
                rd = (insn >> 12) & 0xf;
                if (op1 & 2) {
                    if (IS_USER(s))
                        goto illegal_op;
P
pbrook 已提交
6289
                    tmp = load_cpu_field(spsr);
P
pbrook 已提交
6290
                } else {
P
pbrook 已提交
6291 6292
                    tmp = new_tmp();
                    gen_helper_cpsr_read(tmp);
P
pbrook 已提交
6293
                }
P
pbrook 已提交
6294
                store_reg(s, rd, tmp);
P
pbrook 已提交
6295 6296 6297 6298 6299
            }
            break;
        case 0x1:
            if (op1 == 1) {
                /* branch/exchange thumb (bx).  */
P
pbrook 已提交
6300 6301
                tmp = load_reg(s, rm);
                gen_bx(s, tmp);
P
pbrook 已提交
6302 6303 6304
            } else if (op1 == 3) {
                /* clz */
                rd = (insn >> 12) & 0xf;
P
pbrook 已提交
6305 6306 6307
                tmp = load_reg(s, rm);
                gen_helper_clz(tmp, tmp);
                store_reg(s, rd, tmp);
P
pbrook 已提交
6308 6309 6310 6311 6312 6313 6314 6315
            } else {
                goto illegal_op;
            }
            break;
        case 0x2:
            if (op1 == 1) {
                ARCH(5J); /* bxj */
                /* Trivial implementation equivalent to bx.  */
P
pbrook 已提交
6316 6317
                tmp = load_reg(s, rm);
                gen_bx(s, tmp);
P
pbrook 已提交
6318 6319 6320 6321 6322 6323 6324 6325 6326
            } else {
                goto illegal_op;
            }
            break;
        case 0x3:
            if (op1 != 1)
              goto illegal_op;

            /* branch link/exchange thumb (blx) */
P
pbrook 已提交
6327 6328 6329 6330 6331
            tmp = load_reg(s, rm);
            tmp2 = new_tmp();
            tcg_gen_movi_i32(tmp2, s->pc);
            store_reg(s, 14, tmp2);
            gen_bx(s, tmp);
P
pbrook 已提交
6332 6333 6334 6335
            break;
        case 0x5: /* saturating add/subtract */
            rd = (insn >> 12) & 0xf;
            rn = (insn >> 16) & 0xf;
6336
            tmp = load_reg(s, rm);
P
pbrook 已提交
6337
            tmp2 = load_reg(s, rn);
P
pbrook 已提交
6338
            if (op1 & 2)
P
pbrook 已提交
6339
                gen_helper_double_saturate(tmp2, tmp2);
P
pbrook 已提交
6340
            if (op1 & 1)
P
pbrook 已提交
6341
                gen_helper_sub_saturate(tmp, tmp, tmp2);
P
pbrook 已提交
6342
            else
P
pbrook 已提交
6343 6344 6345
                gen_helper_add_saturate(tmp, tmp, tmp2);
            dead_tmp(tmp2);
            store_reg(s, rd, tmp);
P
pbrook 已提交
6346 6347 6348
            break;
        case 7: /* bkpt */
            gen_set_condexec(s);
P
pbrook 已提交
6349
            gen_set_pc_im(s->pc - 4);
P
pbrook 已提交
6350
            gen_exception(EXCP_BKPT);
P
pbrook 已提交
6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361
            s->is_jmp = DISAS_JUMP;
            break;
        case 0x8: /* signed multiply */
        case 0xa:
        case 0xc:
        case 0xe:
            rs = (insn >> 8) & 0xf;
            rn = (insn >> 12) & 0xf;
            rd = (insn >> 16) & 0xf;
            if (op1 == 1) {
                /* (32 * 16) >> 16 */
P
pbrook 已提交
6362 6363
                tmp = load_reg(s, rm);
                tmp2 = load_reg(s, rs);
P
pbrook 已提交
6364
                if (sh & 4)
P
pbrook 已提交
6365
                    tcg_gen_sari_i32(tmp2, tmp2, 16);
P
pbrook 已提交
6366
                else
P
pbrook 已提交
6367
                    gen_sxth(tmp2);
P
pbrook 已提交
6368 6369
                tmp64 = gen_muls_i64_i32(tmp, tmp2);
                tcg_gen_shri_i64(tmp64, tmp64, 16);
P
pbrook 已提交
6370
                tmp = new_tmp();
P
pbrook 已提交
6371
                tcg_gen_trunc_i64_i32(tmp, tmp64);
6372
                tcg_temp_free_i64(tmp64);
P
pbrook 已提交
6373
                if ((sh & 2) == 0) {
P
pbrook 已提交
6374 6375 6376
                    tmp2 = load_reg(s, rn);
                    gen_helper_add_setq(tmp, tmp, tmp2);
                    dead_tmp(tmp2);
P
pbrook 已提交
6377
                }
P
pbrook 已提交
6378
                store_reg(s, rd, tmp);
P
pbrook 已提交
6379 6380
            } else {
                /* 16 * 16 */
P
pbrook 已提交
6381 6382 6383 6384
                tmp = load_reg(s, rm);
                tmp2 = load_reg(s, rs);
                gen_mulxy(tmp, tmp2, sh & 2, sh & 4);
                dead_tmp(tmp2);
P
pbrook 已提交
6385
                if (op1 == 2) {
P
pbrook 已提交
6386 6387
                    tmp64 = tcg_temp_new_i64();
                    tcg_gen_ext_i32_i64(tmp64, tmp);
6388
                    dead_tmp(tmp);
P
pbrook 已提交
6389 6390
                    gen_addq(s, tmp64, rn, rd);
                    gen_storeq_reg(s, rn, rd, tmp64);
6391
                    tcg_temp_free_i64(tmp64);
P
pbrook 已提交
6392 6393
                } else {
                    if (op1 == 0) {
P
pbrook 已提交
6394 6395 6396
                        tmp2 = load_reg(s, rn);
                        gen_helper_add_setq(tmp, tmp, tmp2);
                        dead_tmp(tmp2);
P
pbrook 已提交
6397
                    }
P
pbrook 已提交
6398
                    store_reg(s, rd, tmp);
P
pbrook 已提交
6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415 6416 6417 6418
                }
            }
            break;
        default:
            goto illegal_op;
        }
    } else if (((insn & 0x0e000000) == 0 &&
                (insn & 0x00000090) != 0x90) ||
               ((insn & 0x0e000000) == (1 << 25))) {
        int set_cc, logic_cc, shiftop;

        op1 = (insn >> 21) & 0xf;
        set_cc = (insn >> 20) & 1;
        logic_cc = table_logic_cc[op1] & set_cc;

        /* data processing instruction */
        if (insn & (1 << 25)) {
            /* immediate operand */
            val = insn & 0xff;
            shift = ((insn >> 8) & 0xf) * 2;
6419
            if (shift) {
P
pbrook 已提交
6420
                val = (val >> shift) | (val << (32 - shift));
6421 6422 6423 6424 6425 6426
            }
            tmp2 = new_tmp();
            tcg_gen_movi_i32(tmp2, val);
            if (logic_cc && shift) {
                gen_set_CF_bit31(tmp2);
            }
P
pbrook 已提交
6427 6428 6429
        } else {
            /* register */
            rm = (insn) & 0xf;
6430
            tmp2 = load_reg(s, rm);
P
pbrook 已提交
6431 6432 6433
            shiftop = (insn >> 5) & 3;
            if (!(insn & (1 << 4))) {
                shift = (insn >> 7) & 0x1f;
6434
                gen_arm_shift_im(tmp2, shiftop, shift, logic_cc);
P
pbrook 已提交
6435 6436
            } else {
                rs = (insn >> 8) & 0xf;
P
pbrook 已提交
6437
                tmp = load_reg(s, rs);
6438
                gen_arm_shift_reg(tmp2, shiftop, tmp, logic_cc);
P
pbrook 已提交
6439 6440 6441 6442
            }
        }
        if (op1 != 0x0f && op1 != 0x0d) {
            rn = (insn >> 16) & 0xf;
6443 6444 6445
            tmp = load_reg(s, rn);
        } else {
            TCGV_UNUSED(tmp);
P
pbrook 已提交
6446 6447 6448 6449
        }
        rd = (insn >> 12) & 0xf;
        switch(op1) {
        case 0x00:
6450 6451 6452 6453
            tcg_gen_and_i32(tmp, tmp, tmp2);
            if (logic_cc) {
                gen_logic_CC(tmp);
            }
6454
            store_reg_bx(env, s, rd, tmp);
P
pbrook 已提交
6455 6456
            break;
        case 0x01:
6457 6458 6459 6460
            tcg_gen_xor_i32(tmp, tmp, tmp2);
            if (logic_cc) {
                gen_logic_CC(tmp);
            }
6461
            store_reg_bx(env, s, rd, tmp);
P
pbrook 已提交
6462 6463 6464 6465
            break;
        case 0x02:
            if (set_cc && rd == 15) {
                /* SUBS r15, ... is used for exception return.  */
6466
                if (IS_USER(s)) {
P
pbrook 已提交
6467
                    goto illegal_op;
6468 6469 6470
                }
                gen_helper_sub_cc(tmp, tmp, tmp2);
                gen_exception_return(s, tmp);
P
pbrook 已提交
6471
            } else {
6472 6473 6474 6475 6476
                if (set_cc) {
                    gen_helper_sub_cc(tmp, tmp, tmp2);
                } else {
                    tcg_gen_sub_i32(tmp, tmp, tmp2);
                }
6477
                store_reg_bx(env, s, rd, tmp);
P
pbrook 已提交
6478 6479 6480
            }
            break;
        case 0x03:
6481 6482 6483 6484 6485
            if (set_cc) {
                gen_helper_sub_cc(tmp, tmp2, tmp);
            } else {
                tcg_gen_sub_i32(tmp, tmp2, tmp);
            }
6486
            store_reg_bx(env, s, rd, tmp);
P
pbrook 已提交
6487 6488
            break;
        case 0x04:
6489 6490 6491 6492 6493
            if (set_cc) {
                gen_helper_add_cc(tmp, tmp, tmp2);
            } else {
                tcg_gen_add_i32(tmp, tmp, tmp2);
            }
6494
            store_reg_bx(env, s, rd, tmp);
P
pbrook 已提交
6495 6496
            break;
        case 0x05:
6497 6498 6499 6500 6501
            if (set_cc) {
                gen_helper_adc_cc(tmp, tmp, tmp2);
            } else {
                gen_add_carry(tmp, tmp, tmp2);
            }
6502
            store_reg_bx(env, s, rd, tmp);
P
pbrook 已提交
6503 6504
            break;
        case 0x06:
6505 6506 6507 6508 6509
            if (set_cc) {
                gen_helper_sbc_cc(tmp, tmp, tmp2);
            } else {
                gen_sub_carry(tmp, tmp, tmp2);
            }
6510
            store_reg_bx(env, s, rd, tmp);
P
pbrook 已提交
6511 6512
            break;
        case 0x07:
6513 6514 6515 6516 6517
            if (set_cc) {
                gen_helper_sbc_cc(tmp, tmp2, tmp);
            } else {
                gen_sub_carry(tmp, tmp2, tmp);
            }
6518
            store_reg_bx(env, s, rd, tmp);
P
pbrook 已提交
6519 6520 6521
            break;
        case 0x08:
            if (set_cc) {
6522 6523
                tcg_gen_and_i32(tmp, tmp, tmp2);
                gen_logic_CC(tmp);
P
pbrook 已提交
6524
            }
6525
            dead_tmp(tmp);
P
pbrook 已提交
6526 6527 6528
            break;
        case 0x09:
            if (set_cc) {
6529 6530
                tcg_gen_xor_i32(tmp, tmp, tmp2);
                gen_logic_CC(tmp);
P
pbrook 已提交
6531
            }
6532
            dead_tmp(tmp);
P
pbrook 已提交
6533 6534 6535
            break;
        case 0x0a:
            if (set_cc) {
6536
                gen_helper_sub_cc(tmp, tmp, tmp2);
P
pbrook 已提交
6537
            }
6538
            dead_tmp(tmp);
P
pbrook 已提交
6539 6540 6541
            break;
        case 0x0b:
            if (set_cc) {
6542
                gen_helper_add_cc(tmp, tmp, tmp2);
P
pbrook 已提交
6543
            }
6544
            dead_tmp(tmp);
P
pbrook 已提交
6545 6546
            break;
        case 0x0c:
6547 6548 6549 6550
            tcg_gen_or_i32(tmp, tmp, tmp2);
            if (logic_cc) {
                gen_logic_CC(tmp);
            }
6551
            store_reg_bx(env, s, rd, tmp);
P
pbrook 已提交
6552 6553 6554 6555
            break;
        case 0x0d:
            if (logic_cc && rd == 15) {
                /* MOVS r15, ... is used for exception return.  */
6556
                if (IS_USER(s)) {
P
pbrook 已提交
6557
                    goto illegal_op;
6558 6559
                }
                gen_exception_return(s, tmp2);
P
pbrook 已提交
6560
            } else {
6561 6562 6563
                if (logic_cc) {
                    gen_logic_CC(tmp2);
                }
6564
                store_reg_bx(env, s, rd, tmp2);
P
pbrook 已提交
6565 6566 6567
            }
            break;
        case 0x0e:
6568
            tcg_gen_andc_i32(tmp, tmp, tmp2);
6569 6570 6571
            if (logic_cc) {
                gen_logic_CC(tmp);
            }
6572
            store_reg_bx(env, s, rd, tmp);
P
pbrook 已提交
6573 6574 6575
            break;
        default:
        case 0x0f:
6576 6577 6578 6579
            tcg_gen_not_i32(tmp2, tmp2);
            if (logic_cc) {
                gen_logic_CC(tmp2);
            }
6580
            store_reg_bx(env, s, rd, tmp2);
P
pbrook 已提交
6581 6582
            break;
        }
6583 6584 6585
        if (op1 != 0x0f && op1 != 0x0d) {
            dead_tmp(tmp2);
        }
P
pbrook 已提交
6586 6587 6588 6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603
    } else {
        /* other instructions */
        op1 = (insn >> 24) & 0xf;
        switch(op1) {
        case 0x0:
        case 0x1:
            /* multiplies, extra load/stores */
            sh = (insn >> 5) & 3;
            if (sh == 0) {
                if (op1 == 0x0) {
                    rd = (insn >> 16) & 0xf;
                    rn = (insn >> 12) & 0xf;
                    rs = (insn >> 8) & 0xf;
                    rm = (insn) & 0xf;
                    op1 = (insn >> 20) & 0xf;
                    switch (op1) {
                    case 0: case 1: case 2: case 3: case 6:
                        /* 32 bit mul */
P
pbrook 已提交
6604 6605 6606 6607
                        tmp = load_reg(s, rs);
                        tmp2 = load_reg(s, rm);
                        tcg_gen_mul_i32(tmp, tmp, tmp2);
                        dead_tmp(tmp2);
P
pbrook 已提交
6608 6609 6610
                        if (insn & (1 << 22)) {
                            /* Subtract (mls) */
                            ARCH(6T2);
P
pbrook 已提交
6611 6612 6613
                            tmp2 = load_reg(s, rn);
                            tcg_gen_sub_i32(tmp, tmp2, tmp);
                            dead_tmp(tmp2);
P
pbrook 已提交
6614 6615
                        } else if (insn & (1 << 21)) {
                            /* Add */
P
pbrook 已提交
6616 6617 6618
                            tmp2 = load_reg(s, rn);
                            tcg_gen_add_i32(tmp, tmp, tmp2);
                            dead_tmp(tmp2);
P
pbrook 已提交
6619 6620
                        }
                        if (insn & (1 << 20))
P
pbrook 已提交
6621 6622
                            gen_logic_CC(tmp);
                        store_reg(s, rd, tmp);
P
pbrook 已提交
6623 6624 6625
                        break;
                    default:
                        /* 64 bit mul */
P
pbrook 已提交
6626 6627
                        tmp = load_reg(s, rs);
                        tmp2 = load_reg(s, rm);
P
pbrook 已提交
6628
                        if (insn & (1 << 22))
P
pbrook 已提交
6629
                            tmp64 = gen_muls_i64_i32(tmp, tmp2);
P
pbrook 已提交
6630
                        else
P
pbrook 已提交
6631
                            tmp64 = gen_mulu_i64_i32(tmp, tmp2);
P
pbrook 已提交
6632
                        if (insn & (1 << 21)) /* mult accumulate */
P
pbrook 已提交
6633
                            gen_addq(s, tmp64, rn, rd);
P
pbrook 已提交
6634 6635
                        if (!(insn & (1 << 23))) { /* double accumulate */
                            ARCH(6);
P
pbrook 已提交
6636 6637
                            gen_addq_lo(s, tmp64, rn);
                            gen_addq_lo(s, tmp64, rd);
P
pbrook 已提交
6638 6639
                        }
                        if (insn & (1 << 20))
P
pbrook 已提交
6640 6641
                            gen_logicq_cc(tmp64);
                        gen_storeq_reg(s, rn, rd, tmp64);
6642
                        tcg_temp_free_i64(tmp64);
P
pbrook 已提交
6643 6644 6645 6646 6647 6648 6649
                        break;
                    }
                } else {
                    rn = (insn >> 16) & 0xf;
                    rd = (insn >> 12) & 0xf;
                    if (insn & (1 << 23)) {
                        /* load/store exclusive */
P
pbrook 已提交
6650 6651
                        op1 = (insn >> 21) & 0x3;
                        if (op1)
6652
                            ARCH(6K);
P
pbrook 已提交
6653 6654
                        else
                            ARCH(6);
6655
                        addr = tcg_temp_local_new_i32();
6656
                        load_reg_var(s, addr, rn);
P
pbrook 已提交
6657
                        if (insn & (1 << 20)) {
P
pbrook 已提交
6658 6659
                            switch (op1) {
                            case 0: /* ldrex */
P
Paul Brook 已提交
6660
                                gen_load_exclusive(s, rd, 15, addr, 2);
P
pbrook 已提交
6661 6662
                                break;
                            case 1: /* ldrexd */
P
Paul Brook 已提交
6663
                                gen_load_exclusive(s, rd, rd + 1, addr, 3);
P
pbrook 已提交
6664 6665
                                break;
                            case 2: /* ldrexb */
P
Paul Brook 已提交
6666
                                gen_load_exclusive(s, rd, 15, addr, 0);
P
pbrook 已提交
6667 6668
                                break;
                            case 3: /* ldrexh */
P
Paul Brook 已提交
6669
                                gen_load_exclusive(s, rd, 15, addr, 1);
P
pbrook 已提交
6670 6671 6672 6673
                                break;
                            default:
                                abort();
                            }
P
pbrook 已提交
6674 6675
                        } else {
                            rm = insn & 0xf;
P
pbrook 已提交
6676 6677
                            switch (op1) {
                            case 0:  /*  strex */
P
Paul Brook 已提交
6678
                                gen_store_exclusive(s, rd, rm, 15, addr, 2);
P
pbrook 已提交
6679 6680
                                break;
                            case 1: /*  strexd */
A
Aurelien Jarno 已提交
6681
                                gen_store_exclusive(s, rd, rm, rm + 1, addr, 3);
P
pbrook 已提交
6682 6683
                                break;
                            case 2: /*  strexb */
P
Paul Brook 已提交
6684
                                gen_store_exclusive(s, rd, rm, 15, addr, 0);
P
pbrook 已提交
6685 6686
                                break;
                            case 3: /* strexh */
P
Paul Brook 已提交
6687
                                gen_store_exclusive(s, rd, rm, 15, addr, 1);
P
pbrook 已提交
6688 6689 6690 6691
                                break;
                            default:
                                abort();
                            }
P
pbrook 已提交
6692
                        }
6693
                        tcg_temp_free(addr);
P
pbrook 已提交
6694 6695 6696 6697
                    } else {
                        /* SWP instruction */
                        rm = (insn) & 0xf;

P
pbrook 已提交
6698 6699 6700 6701 6702
                        /* ??? This is not really atomic.  However we know
                           we never have multiple CPUs running in parallel,
                           so it is good enough.  */
                        addr = load_reg(s, rn);
                        tmp = load_reg(s, rm);
P
pbrook 已提交
6703
                        if (insn & (1 << 22)) {
P
pbrook 已提交
6704 6705
                            tmp2 = gen_ld8u(addr, IS_USER(s));
                            gen_st8(tmp, addr, IS_USER(s));
P
pbrook 已提交
6706
                        } else {
P
pbrook 已提交
6707 6708
                            tmp2 = gen_ld32(addr, IS_USER(s));
                            gen_st32(tmp, addr, IS_USER(s));
P
pbrook 已提交
6709
                        }
P
pbrook 已提交
6710 6711
                        dead_tmp(addr);
                        store_reg(s, rd, tmp2);
P
pbrook 已提交
6712 6713 6714 6715 6716 6717 6718 6719
                    }
                }
            } else {
                int address_offset;
                int load;
                /* Misc load/store */
                rn = (insn >> 16) & 0xf;
                rd = (insn >> 12) & 0xf;
P
pbrook 已提交
6720
                addr = load_reg(s, rn);
P
pbrook 已提交
6721
                if (insn & (1 << 24))
P
pbrook 已提交
6722
                    gen_add_datah_offset(s, insn, 0, addr);
P
pbrook 已提交
6723 6724 6725 6726 6727
                address_offset = 0;
                if (insn & (1 << 20)) {
                    /* load */
                    switch(sh) {
                    case 1:
P
pbrook 已提交
6728
                        tmp = gen_ld16u(addr, IS_USER(s));
P
pbrook 已提交
6729 6730
                        break;
                    case 2:
P
pbrook 已提交
6731
                        tmp = gen_ld8s(addr, IS_USER(s));
P
pbrook 已提交
6732 6733 6734
                        break;
                    default:
                    case 3:
P
pbrook 已提交
6735
                        tmp = gen_ld16s(addr, IS_USER(s));
P
pbrook 已提交
6736 6737 6738 6739 6740 6741 6742
                        break;
                    }
                    load = 1;
                } else if (sh & 2) {
                    /* doubleword */
                    if (sh & 1) {
                        /* store */
P
pbrook 已提交
6743 6744 6745 6746 6747
                        tmp = load_reg(s, rd);
                        gen_st32(tmp, addr, IS_USER(s));
                        tcg_gen_addi_i32(addr, addr, 4);
                        tmp = load_reg(s, rd + 1);
                        gen_st32(tmp, addr, IS_USER(s));
P
pbrook 已提交
6748 6749 6750
                        load = 0;
                    } else {
                        /* load */
P
pbrook 已提交
6751 6752 6753 6754
                        tmp = gen_ld32(addr, IS_USER(s));
                        store_reg(s, rd, tmp);
                        tcg_gen_addi_i32(addr, addr, 4);
                        tmp = gen_ld32(addr, IS_USER(s));
P
pbrook 已提交
6755 6756 6757 6758 6759 6760
                        rd++;
                        load = 1;
                    }
                    address_offset = -4;
                } else {
                    /* store */
P
pbrook 已提交
6761 6762
                    tmp = load_reg(s, rd);
                    gen_st16(tmp, addr, IS_USER(s));
P
pbrook 已提交
6763 6764 6765 6766 6767 6768 6769
                    load = 0;
                }
                /* Perform base writeback before the loaded value to
                   ensure correct behavior with overlapping index registers.
                   ldrd with base writeback is is undefined if the
                   destination and index registers overlap.  */
                if (!(insn & (1 << 24))) {
P
pbrook 已提交
6770 6771
                    gen_add_datah_offset(s, insn, address_offset, addr);
                    store_reg(s, rn, addr);
P
pbrook 已提交
6772 6773
                } else if (insn & (1 << 21)) {
                    if (address_offset)
P
pbrook 已提交
6774 6775 6776 6777
                        tcg_gen_addi_i32(addr, addr, address_offset);
                    store_reg(s, rn, addr);
                } else {
                    dead_tmp(addr);
P
pbrook 已提交
6778 6779 6780
                }
                if (load) {
                    /* Complete the load.  */
P
pbrook 已提交
6781
                    store_reg(s, rd, tmp);
P
pbrook 已提交
6782 6783 6784 6785 6786 6787 6788 6789 6790 6791 6792 6793 6794
                }
            }
            break;
        case 0x4:
        case 0x5:
            goto do_ldst;
        case 0x6:
        case 0x7:
            if (insn & (1 << 4)) {
                ARCH(6);
                /* Armv6 Media instructions.  */
                rm = insn & 0xf;
                rn = (insn >> 16) & 0xf;
B
bellard 已提交
6795
                rd = (insn >> 12) & 0xf;
P
pbrook 已提交
6796 6797 6798 6799
                rs = (insn >> 8) & 0xf;
                switch ((insn >> 23) & 3) {
                case 0: /* Parallel add/subtract.  */
                    op1 = (insn >> 20) & 7;
P
pbrook 已提交
6800 6801
                    tmp = load_reg(s, rn);
                    tmp2 = load_reg(s, rm);
P
pbrook 已提交
6802 6803 6804
                    sh = (insn >> 5) & 7;
                    if ((op1 & 3) == 0 || sh == 5 || sh == 6)
                        goto illegal_op;
P
pbrook 已提交
6805 6806 6807
                    gen_arm_parallel_addsub(op1, sh, tmp, tmp2);
                    dead_tmp(tmp2);
                    store_reg(s, rd, tmp);
P
pbrook 已提交
6808 6809 6810
                    break;
                case 1:
                    if ((insn & 0x00700020) == 0) {
B
balrog 已提交
6811
                        /* Halfword pack.  */
P
pbrook 已提交
6812 6813
                        tmp = load_reg(s, rn);
                        tmp2 = load_reg(s, rm);
P
pbrook 已提交
6814
                        shift = (insn >> 7) & 0x1f;
P
pbrook 已提交
6815 6816
                        if (insn & (1 << 6)) {
                            /* pkhtb */
6817 6818 6819
                            if (shift == 0)
                                shift = 31;
                            tcg_gen_sari_i32(tmp2, tmp2, shift);
P
pbrook 已提交
6820
                            tcg_gen_andi_i32(tmp, tmp, 0xffff0000);
P
pbrook 已提交
6821
                            tcg_gen_ext16u_i32(tmp2, tmp2);
P
pbrook 已提交
6822 6823
                        } else {
                            /* pkhbt */
6824 6825
                            if (shift)
                                tcg_gen_shli_i32(tmp2, tmp2, shift);
P
pbrook 已提交
6826
                            tcg_gen_ext16u_i32(tmp, tmp);
P
pbrook 已提交
6827 6828 6829
                            tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000);
                        }
                        tcg_gen_or_i32(tmp, tmp, tmp2);
6830
                        dead_tmp(tmp2);
P
pbrook 已提交
6831
                        store_reg(s, rd, tmp);
P
pbrook 已提交
6832 6833
                    } else if ((insn & 0x00200020) == 0x00200000) {
                        /* [us]sat */
P
pbrook 已提交
6834
                        tmp = load_reg(s, rm);
P
pbrook 已提交
6835 6836 6837 6838
                        shift = (insn >> 7) & 0x1f;
                        if (insn & (1 << 6)) {
                            if (shift == 0)
                                shift = 31;
P
pbrook 已提交
6839
                            tcg_gen_sari_i32(tmp, tmp, shift);
P
pbrook 已提交
6840
                        } else {
P
pbrook 已提交
6841
                            tcg_gen_shli_i32(tmp, tmp, shift);
P
pbrook 已提交
6842 6843 6844
                        }
                        sh = (insn >> 16) & 0x1f;
                        if (sh != 0) {
6845
                            tmp2 = tcg_const_i32(sh);
P
pbrook 已提交
6846
                            if (insn & (1 << 22))
6847
                                gen_helper_usat(tmp, tmp, tmp2);
P
pbrook 已提交
6848
                            else
6849 6850
                                gen_helper_ssat(tmp, tmp, tmp2);
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
6851
                        }
P
pbrook 已提交
6852
                        store_reg(s, rd, tmp);
P
pbrook 已提交
6853 6854
                    } else if ((insn & 0x00300fe0) == 0x00200f20) {
                        /* [us]sat16 */
P
pbrook 已提交
6855
                        tmp = load_reg(s, rm);
P
pbrook 已提交
6856 6857
                        sh = (insn >> 16) & 0x1f;
                        if (sh != 0) {
6858
                            tmp2 = tcg_const_i32(sh);
P
pbrook 已提交
6859
                            if (insn & (1 << 22))
6860
                                gen_helper_usat16(tmp, tmp, tmp2);
P
pbrook 已提交
6861
                            else
6862 6863
                                gen_helper_ssat16(tmp, tmp, tmp2);
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
6864
                        }
P
pbrook 已提交
6865
                        store_reg(s, rd, tmp);
P
pbrook 已提交
6866 6867
                    } else if ((insn & 0x00700fe0) == 0x00000fa0) {
                        /* Select bytes.  */
P
pbrook 已提交
6868 6869 6870 6871 6872 6873 6874 6875
                        tmp = load_reg(s, rn);
                        tmp2 = load_reg(s, rm);
                        tmp3 = new_tmp();
                        tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUState, GE));
                        gen_helper_sel_flags(tmp, tmp3, tmp, tmp2);
                        dead_tmp(tmp3);
                        dead_tmp(tmp2);
                        store_reg(s, rd, tmp);
P
pbrook 已提交
6876
                    } else if ((insn & 0x000003e0) == 0x00000060) {
P
pbrook 已提交
6877
                        tmp = load_reg(s, rm);
P
pbrook 已提交
6878 6879 6880 6881
                        shift = (insn >> 10) & 3;
                        /* ??? In many cases it's not neccessary to do a
                           rotate, a shift is sufficient.  */
                        if (shift != 0)
6882
                            tcg_gen_rotri_i32(tmp, tmp, shift * 8);
P
pbrook 已提交
6883 6884
                        op1 = (insn >> 20) & 7;
                        switch (op1) {
P
pbrook 已提交
6885 6886 6887 6888 6889 6890
                        case 0: gen_sxtb16(tmp);  break;
                        case 2: gen_sxtb(tmp);    break;
                        case 3: gen_sxth(tmp);    break;
                        case 4: gen_uxtb16(tmp);  break;
                        case 6: gen_uxtb(tmp);    break;
                        case 7: gen_uxth(tmp);    break;
P
pbrook 已提交
6891 6892 6893
                        default: goto illegal_op;
                        }
                        if (rn != 15) {
P
pbrook 已提交
6894
                            tmp2 = load_reg(s, rn);
P
pbrook 已提交
6895
                            if ((op1 & 3) == 0) {
P
pbrook 已提交
6896
                                gen_add16(tmp, tmp2);
P
pbrook 已提交
6897
                            } else {
P
pbrook 已提交
6898 6899
                                tcg_gen_add_i32(tmp, tmp, tmp2);
                                dead_tmp(tmp2);
P
pbrook 已提交
6900 6901
                            }
                        }
B
balrog 已提交
6902
                        store_reg(s, rd, tmp);
P
pbrook 已提交
6903 6904
                    } else if ((insn & 0x003f0f60) == 0x003f0f20) {
                        /* rev */
P
pbrook 已提交
6905
                        tmp = load_reg(s, rm);
P
pbrook 已提交
6906 6907
                        if (insn & (1 << 22)) {
                            if (insn & (1 << 7)) {
P
pbrook 已提交
6908
                                gen_revsh(tmp);
P
pbrook 已提交
6909 6910
                            } else {
                                ARCH(6T2);
P
pbrook 已提交
6911
                                gen_helper_rbit(tmp, tmp);
P
pbrook 已提交
6912 6913 6914
                            }
                        } else {
                            if (insn & (1 << 7))
P
pbrook 已提交
6915
                                gen_rev16(tmp);
P
pbrook 已提交
6916
                            else
A
aurel32 已提交
6917
                                tcg_gen_bswap32_i32(tmp, tmp);
P
pbrook 已提交
6918
                        }
P
pbrook 已提交
6919
                        store_reg(s, rd, tmp);
P
pbrook 已提交
6920 6921 6922 6923 6924
                    } else {
                        goto illegal_op;
                    }
                    break;
                case 2: /* Multiplies (Type 3).  */
P
pbrook 已提交
6925 6926
                    tmp = load_reg(s, rm);
                    tmp2 = load_reg(s, rs);
P
pbrook 已提交
6927 6928
                    if (insn & (1 << 20)) {
                        /* Signed multiply most significant [accumulate].  */
P
pbrook 已提交
6929
                        tmp64 = gen_muls_i64_i32(tmp, tmp2);
P
pbrook 已提交
6930
                        if (insn & (1 << 5))
P
pbrook 已提交
6931 6932
                            tcg_gen_addi_i64(tmp64, tmp64, 0x80000000u);
                        tcg_gen_shri_i64(tmp64, tmp64, 32);
P
pbrook 已提交
6933
                        tmp = new_tmp();
P
pbrook 已提交
6934
                        tcg_gen_trunc_i64_i32(tmp, tmp64);
6935
                        tcg_temp_free_i64(tmp64);
6936 6937
                        if (rd != 15) {
                            tmp2 = load_reg(s, rd);
P
pbrook 已提交
6938
                            if (insn & (1 << 6)) {
P
pbrook 已提交
6939
                                tcg_gen_sub_i32(tmp, tmp, tmp2);
P
pbrook 已提交
6940
                            } else {
P
pbrook 已提交
6941
                                tcg_gen_add_i32(tmp, tmp, tmp2);
P
pbrook 已提交
6942
                            }
P
pbrook 已提交
6943
                            dead_tmp(tmp2);
P
pbrook 已提交
6944
                        }
6945
                        store_reg(s, rn, tmp);
P
pbrook 已提交
6946 6947
                    } else {
                        if (insn & (1 << 5))
P
pbrook 已提交
6948 6949 6950 6951 6952 6953 6954 6955 6956
                            gen_swap_half(tmp2);
                        gen_smul_dual(tmp, tmp2);
                        /* This addition cannot overflow.  */
                        if (insn & (1 << 6)) {
                            tcg_gen_sub_i32(tmp, tmp, tmp2);
                        } else {
                            tcg_gen_add_i32(tmp, tmp, tmp2);
                        }
                        dead_tmp(tmp2);
P
pbrook 已提交
6957
                        if (insn & (1 << 22)) {
P
pbrook 已提交
6958
                            /* smlald, smlsld */
P
pbrook 已提交
6959 6960
                            tmp64 = tcg_temp_new_i64();
                            tcg_gen_ext_i32_i64(tmp64, tmp);
P
pbrook 已提交
6961
                            dead_tmp(tmp);
P
pbrook 已提交
6962 6963
                            gen_addq(s, tmp64, rd, rn);
                            gen_storeq_reg(s, rd, rn, tmp64);
6964
                            tcg_temp_free_i64(tmp64);
P
pbrook 已提交
6965
                        } else {
P
pbrook 已提交
6966
                            /* smuad, smusd, smlad, smlsd */
6967
                            if (rd != 15)
P
pbrook 已提交
6968
                              {
6969
                                tmp2 = load_reg(s, rd);
P
pbrook 已提交
6970 6971
                                gen_helper_add_setq(tmp, tmp, tmp2);
                                dead_tmp(tmp2);
P
pbrook 已提交
6972
                              }
6973
                            store_reg(s, rn, tmp);
P
pbrook 已提交
6974 6975 6976 6977 6978 6979 6980
                        }
                    }
                    break;
                case 3:
                    op1 = ((insn >> 17) & 0x38) | ((insn >> 5) & 7);
                    switch (op1) {
                    case 0: /* Unsigned sum of absolute differences.  */
P
pbrook 已提交
6981 6982 6983 6984 6985
                        ARCH(6);
                        tmp = load_reg(s, rm);
                        tmp2 = load_reg(s, rs);
                        gen_helper_usad8(tmp, tmp, tmp2);
                        dead_tmp(tmp2);
6986 6987
                        if (rd != 15) {
                            tmp2 = load_reg(s, rd);
P
pbrook 已提交
6988 6989
                            tcg_gen_add_i32(tmp, tmp, tmp2);
                            dead_tmp(tmp2);
P
pbrook 已提交
6990
                        }
6991
                        store_reg(s, rn, tmp);
P
pbrook 已提交
6992 6993 6994 6995 6996 6997 6998 6999
                        break;
                    case 0x20: case 0x24: case 0x28: case 0x2c:
                        /* Bitfield insert/clear.  */
                        ARCH(6T2);
                        shift = (insn >> 7) & 0x1f;
                        i = (insn >> 16) & 0x1f;
                        i = i + 1 - shift;
                        if (rm == 15) {
P
pbrook 已提交
7000 7001
                            tmp = new_tmp();
                            tcg_gen_movi_i32(tmp, 0);
P
pbrook 已提交
7002
                        } else {
P
pbrook 已提交
7003
                            tmp = load_reg(s, rm);
P
pbrook 已提交
7004 7005
                        }
                        if (i != 32) {
P
pbrook 已提交
7006
                            tmp2 = load_reg(s, rd);
P
pbrook 已提交
7007
                            gen_bfi(tmp, tmp2, tmp, shift, (1u << i) - 1);
P
pbrook 已提交
7008
                            dead_tmp(tmp2);
P
pbrook 已提交
7009
                        }
P
pbrook 已提交
7010
                        store_reg(s, rd, tmp);
P
pbrook 已提交
7011 7012 7013
                        break;
                    case 0x12: case 0x16: case 0x1a: case 0x1e: /* sbfx */
                    case 0x32: case 0x36: case 0x3a: case 0x3e: /* ubfx */
7014
                        ARCH(6T2);
P
pbrook 已提交
7015
                        tmp = load_reg(s, rm);
P
pbrook 已提交
7016 7017 7018 7019 7020 7021
                        shift = (insn >> 7) & 0x1f;
                        i = ((insn >> 16) & 0x1f) + 1;
                        if (shift + i > 32)
                            goto illegal_op;
                        if (i < 32) {
                            if (op1 & 0x20) {
P
pbrook 已提交
7022
                                gen_ubfx(tmp, shift, (1u << i) - 1);
P
pbrook 已提交
7023
                            } else {
P
pbrook 已提交
7024
                                gen_sbfx(tmp, shift, i);
P
pbrook 已提交
7025 7026
                            }
                        }
P
pbrook 已提交
7027
                        store_reg(s, rd, tmp);
P
pbrook 已提交
7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048
                        break;
                    default:
                        goto illegal_op;
                    }
                    break;
                }
                break;
            }
        do_ldst:
            /* Check for undefined extension instructions
             * per the ARM Bible IE:
             * xxxx 0111 1111 xxxx  xxxx xxxx 1111 xxxx
             */
            sh = (0xf << 20) | (0xf << 4);
            if (op1 == 0x7 && ((insn & sh) == sh))
            {
                goto illegal_op;
            }
            /* load/store byte/word */
            rn = (insn >> 16) & 0xf;
            rd = (insn >> 12) & 0xf;
P
pbrook 已提交
7049
            tmp2 = load_reg(s, rn);
P
pbrook 已提交
7050 7051
            i = (IS_USER(s) || (insn & 0x01200000) == 0x00200000);
            if (insn & (1 << 24))
P
pbrook 已提交
7052
                gen_add_data_offset(s, insn, tmp2);
P
pbrook 已提交
7053 7054 7055
            if (insn & (1 << 20)) {
                /* load */
                if (insn & (1 << 22)) {
P
pbrook 已提交
7056
                    tmp = gen_ld8u(tmp2, i);
P
pbrook 已提交
7057
                } else {
P
pbrook 已提交
7058
                    tmp = gen_ld32(tmp2, i);
P
pbrook 已提交
7059 7060 7061
                }
            } else {
                /* store */
P
pbrook 已提交
7062
                tmp = load_reg(s, rd);
P
pbrook 已提交
7063
                if (insn & (1 << 22))
P
pbrook 已提交
7064
                    gen_st8(tmp, tmp2, i);
P
pbrook 已提交
7065
                else
P
pbrook 已提交
7066
                    gen_st32(tmp, tmp2, i);
P
pbrook 已提交
7067 7068
            }
            if (!(insn & (1 << 24))) {
P
pbrook 已提交
7069 7070 7071 7072 7073 7074
                gen_add_data_offset(s, insn, tmp2);
                store_reg(s, rn, tmp2);
            } else if (insn & (1 << 21)) {
                store_reg(s, rn, tmp2);
            } else {
                dead_tmp(tmp2);
P
pbrook 已提交
7075 7076 7077 7078
            }
            if (insn & (1 << 20)) {
                /* Complete the load.  */
                if (rd == 15)
P
pbrook 已提交
7079
                    gen_bx(s, tmp);
P
pbrook 已提交
7080
                else
P
pbrook 已提交
7081
                    store_reg(s, rd, tmp);
P
pbrook 已提交
7082 7083 7084 7085 7086 7087
            }
            break;
        case 0x08:
        case 0x09:
            {
                int j, n, user, loaded_base;
P
pbrook 已提交
7088
                TCGv loaded_var;
P
pbrook 已提交
7089 7090 7091 7092 7093 7094 7095 7096 7097 7098 7099
                /* load/store multiple words */
                /* XXX: store correct base if write back */
                user = 0;
                if (insn & (1 << 22)) {
                    if (IS_USER(s))
                        goto illegal_op; /* only usable in supervisor mode */

                    if ((insn & (1 << 15)) == 0)
                        user = 1;
                }
                rn = (insn >> 16) & 0xf;
P
pbrook 已提交
7100
                addr = load_reg(s, rn);
P
pbrook 已提交
7101 7102 7103

                /* compute total size */
                loaded_base = 0;
P
pbrook 已提交
7104
                TCGV_UNUSED(loaded_var);
P
pbrook 已提交
7105 7106 7107 7108 7109 7110 7111 7112 7113
                n = 0;
                for(i=0;i<16;i++) {
                    if (insn & (1 << i))
                        n++;
                }
                /* XXX: test invalid n == 0 case ? */
                if (insn & (1 << 23)) {
                    if (insn & (1 << 24)) {
                        /* pre increment */
P
pbrook 已提交
7114
                        tcg_gen_addi_i32(addr, addr, 4);
P
pbrook 已提交
7115 7116 7117 7118 7119 7120
                    } else {
                        /* post increment */
                    }
                } else {
                    if (insn & (1 << 24)) {
                        /* pre decrement */
P
pbrook 已提交
7121
                        tcg_gen_addi_i32(addr, addr, -(n * 4));
P
pbrook 已提交
7122 7123 7124
                    } else {
                        /* post decrement */
                        if (n != 1)
P
pbrook 已提交
7125
                        tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
P
pbrook 已提交
7126 7127 7128 7129 7130 7131 7132
                    }
                }
                j = 0;
                for(i=0;i<16;i++) {
                    if (insn & (1 << i)) {
                        if (insn & (1 << 20)) {
                            /* load */
P
pbrook 已提交
7133
                            tmp = gen_ld32(addr, IS_USER(s));
P
pbrook 已提交
7134
                            if (i == 15) {
P
pbrook 已提交
7135
                                gen_bx(s, tmp);
P
pbrook 已提交
7136
                            } else if (user) {
7137 7138 7139
                                tmp2 = tcg_const_i32(i);
                                gen_helper_set_user_reg(tmp2, tmp);
                                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
7140
                                dead_tmp(tmp);
P
pbrook 已提交
7141
                            } else if (i == rn) {
P
pbrook 已提交
7142
                                loaded_var = tmp;
P
pbrook 已提交
7143 7144
                                loaded_base = 1;
                            } else {
P
pbrook 已提交
7145
                                store_reg(s, i, tmp);
P
pbrook 已提交
7146 7147 7148 7149 7150 7151
                            }
                        } else {
                            /* store */
                            if (i == 15) {
                                /* special case: r15 = PC + 8 */
                                val = (long)s->pc + 4;
P
pbrook 已提交
7152 7153
                                tmp = new_tmp();
                                tcg_gen_movi_i32(tmp, val);
P
pbrook 已提交
7154
                            } else if (user) {
P
pbrook 已提交
7155
                                tmp = new_tmp();
7156 7157 7158
                                tmp2 = tcg_const_i32(i);
                                gen_helper_get_user_reg(tmp, tmp2);
                                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
7159
                            } else {
P
pbrook 已提交
7160
                                tmp = load_reg(s, i);
P
pbrook 已提交
7161
                            }
P
pbrook 已提交
7162
                            gen_st32(tmp, addr, IS_USER(s));
P
pbrook 已提交
7163 7164 7165 7166
                        }
                        j++;
                        /* no need to add after the last transfer */
                        if (j != n)
P
pbrook 已提交
7167
                            tcg_gen_addi_i32(addr, addr, 4);
P
pbrook 已提交
7168 7169 7170 7171 7172 7173 7174 7175 7176
                    }
                }
                if (insn & (1 << 21)) {
                    /* write back */
                    if (insn & (1 << 23)) {
                        if (insn & (1 << 24)) {
                            /* pre increment */
                        } else {
                            /* post increment */
P
pbrook 已提交
7177
                            tcg_gen_addi_i32(addr, addr, 4);
P
pbrook 已提交
7178 7179 7180 7181 7182
                        }
                    } else {
                        if (insn & (1 << 24)) {
                            /* pre decrement */
                            if (n != 1)
P
pbrook 已提交
7183
                                tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
P
pbrook 已提交
7184 7185
                        } else {
                            /* post decrement */
P
pbrook 已提交
7186
                            tcg_gen_addi_i32(addr, addr, -(n * 4));
P
pbrook 已提交
7187 7188
                        }
                    }
P
pbrook 已提交
7189 7190 7191
                    store_reg(s, rn, addr);
                } else {
                    dead_tmp(addr);
P
pbrook 已提交
7192 7193
                }
                if (loaded_base) {
P
pbrook 已提交
7194
                    store_reg(s, rn, loaded_var);
P
pbrook 已提交
7195 7196 7197
                }
                if ((insn & (1 << 22)) && !user) {
                    /* Restore CPSR from SPSR.  */
P
pbrook 已提交
7198 7199 7200
                    tmp = load_cpu_field(spsr);
                    gen_set_cpsr(tmp, 0xffffffff);
                    dead_tmp(tmp);
P
pbrook 已提交
7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212
                    s->is_jmp = DISAS_UPDATE;
                }
            }
            break;
        case 0xa:
        case 0xb:
            {
                int32_t offset;

                /* branch (and link) */
                val = (int32_t)s->pc;
                if (insn & (1 << 24)) {
P
pbrook 已提交
7213 7214 7215
                    tmp = new_tmp();
                    tcg_gen_movi_i32(tmp, val);
                    store_reg(s, 14, tmp);
P
pbrook 已提交
7216 7217 7218 7219 7220 7221 7222 7223 7224 7225 7226 7227 7228 7229 7230
                }
                offset = (((int32_t)insn << 8) >> 8);
                val += (offset << 2) + 4;
                gen_jmp(s, val);
            }
            break;
        case 0xc:
        case 0xd:
        case 0xe:
            /* Coprocessor.  */
            if (disas_coproc_insn(env, s, insn))
                goto illegal_op;
            break;
        case 0xf:
            /* swi */
P
pbrook 已提交
7231
            gen_set_pc_im(s->pc);
P
pbrook 已提交
7232 7233 7234 7235 7236
            s->is_jmp = DISAS_SWI;
            break;
        default:
        illegal_op:
            gen_set_condexec(s);
P
pbrook 已提交
7237
            gen_set_pc_im(s->pc - 4);
P
pbrook 已提交
7238
            gen_exception(EXCP_UDEF);
P
pbrook 已提交
7239 7240 7241 7242 7243 7244 7245 7246 7247 7248 7249 7250 7251 7252 7253 7254 7255 7256 7257 7258
            s->is_jmp = DISAS_JUMP;
            break;
        }
    }
}

/* Return true if this is a Thumb-2 logical op.  */
static int
thumb2_logic_op(int op)
{
    return (op < 8);
}

/* Generate code for a Thumb-2 data processing operation.  If CONDS is nonzero
   then set condition code flags based on the result of the operation.
   If SHIFTER_OUT is nonzero then set the carry flag for logical operations
   to the high bit of T1.
   Returns zero if the opcode is valid.  */

static int
7259
gen_thumb2_data_op(DisasContext *s, int op, int conds, uint32_t shifter_out, TCGv t0, TCGv t1)
P
pbrook 已提交
7260 7261 7262 7263 7264 7265
{
    int logic_cc;

    logic_cc = 0;
    switch (op) {
    case 0: /* and */
7266
        tcg_gen_and_i32(t0, t0, t1);
P
pbrook 已提交
7267 7268 7269
        logic_cc = conds;
        break;
    case 1: /* bic */
7270
        tcg_gen_andc_i32(t0, t0, t1);
P
pbrook 已提交
7271 7272 7273
        logic_cc = conds;
        break;
    case 2: /* orr */
7274
        tcg_gen_or_i32(t0, t0, t1);
P
pbrook 已提交
7275 7276 7277
        logic_cc = conds;
        break;
    case 3: /* orn */
7278 7279
        tcg_gen_not_i32(t1, t1);
        tcg_gen_or_i32(t0, t0, t1);
P
pbrook 已提交
7280 7281 7282
        logic_cc = conds;
        break;
    case 4: /* eor */
7283
        tcg_gen_xor_i32(t0, t0, t1);
P
pbrook 已提交
7284 7285 7286 7287
        logic_cc = conds;
        break;
    case 8: /* add */
        if (conds)
7288
            gen_helper_add_cc(t0, t0, t1);
P
pbrook 已提交
7289
        else
7290
            tcg_gen_add_i32(t0, t0, t1);
P
pbrook 已提交
7291 7292 7293
        break;
    case 10: /* adc */
        if (conds)
7294
            gen_helper_adc_cc(t0, t0, t1);
P
pbrook 已提交
7295
        else
7296
            gen_adc(t0, t1);
P
pbrook 已提交
7297 7298 7299
        break;
    case 11: /* sbc */
        if (conds)
7300
            gen_helper_sbc_cc(t0, t0, t1);
P
pbrook 已提交
7301
        else
7302
            gen_sub_carry(t0, t0, t1);
P
pbrook 已提交
7303 7304 7305
        break;
    case 13: /* sub */
        if (conds)
7306
            gen_helper_sub_cc(t0, t0, t1);
P
pbrook 已提交
7307
        else
7308
            tcg_gen_sub_i32(t0, t0, t1);
P
pbrook 已提交
7309 7310 7311
        break;
    case 14: /* rsb */
        if (conds)
7312
            gen_helper_sub_cc(t0, t1, t0);
P
pbrook 已提交
7313
        else
7314
            tcg_gen_sub_i32(t0, t1, t0);
P
pbrook 已提交
7315 7316 7317 7318 7319
        break;
    default: /* 5, 6, 7, 9, 12, 15. */
        return 1;
    }
    if (logic_cc) {
7320
        gen_logic_CC(t0);
P
pbrook 已提交
7321
        if (shifter_out)
7322
            gen_set_CF_bit31(t1);
P
pbrook 已提交
7323 7324 7325 7326 7327 7328 7329 7330
    }
    return 0;
}

/* Translate a 32-bit thumb instruction.  Returns nonzero if the instruction
   is not legal.  */
static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
{
P
pbrook 已提交
7331
    uint32_t insn, imm, shift, offset;
P
pbrook 已提交
7332
    uint32_t rd, rn, rm, rs;
P
pbrook 已提交
7333
    TCGv tmp;
P
pbrook 已提交
7334 7335
    TCGv tmp2;
    TCGv tmp3;
P
pbrook 已提交
7336
    TCGv addr;
P
pbrook 已提交
7337
    TCGv_i64 tmp64;
P
pbrook 已提交
7338 7339 7340 7341 7342 7343 7344
    int op;
    int shiftop;
    int conds;
    int logic_cc;

    if (!(arm_feature(env, ARM_FEATURE_THUMB2)
          || arm_feature (env, ARM_FEATURE_M))) {
7345
        /* Thumb-1 cores may need to treat bl and blx as a pair of
P
pbrook 已提交
7346 7347 7348 7349 7350
           16-bit instructions to get correct prefetch abort behavior.  */
        insn = insn_hw1;
        if ((insn & (1 << 12)) == 0) {
            /* Second half of blx.  */
            offset = ((insn & 0x7ff) << 1);
P
pbrook 已提交
7351 7352 7353
            tmp = load_reg(s, 14);
            tcg_gen_addi_i32(tmp, tmp, offset);
            tcg_gen_andi_i32(tmp, tmp, 0xfffffffc);
P
pbrook 已提交
7354

P
pbrook 已提交
7355
            tmp2 = new_tmp();
P
pbrook 已提交
7356
            tcg_gen_movi_i32(tmp2, s->pc | 1);
P
pbrook 已提交
7357 7358
            store_reg(s, 14, tmp2);
            gen_bx(s, tmp);
P
pbrook 已提交
7359 7360 7361 7362 7363
            return 0;
        }
        if (insn & (1 << 11)) {
            /* Second half of bl.  */
            offset = ((insn & 0x7ff) << 1) | 1;
P
pbrook 已提交
7364
            tmp = load_reg(s, 14);
B
balrog 已提交
7365
            tcg_gen_addi_i32(tmp, tmp, offset);
P
pbrook 已提交
7366

P
pbrook 已提交
7367
            tmp2 = new_tmp();
P
pbrook 已提交
7368
            tcg_gen_movi_i32(tmp2, s->pc | 1);
P
pbrook 已提交
7369 7370
            store_reg(s, 14, tmp2);
            gen_bx(s, tmp);
P
pbrook 已提交
7371 7372 7373 7374 7375 7376 7377
            return 0;
        }
        if ((s->pc & ~TARGET_PAGE_MASK) == 0) {
            /* Instruction spans a page boundary.  Implement it as two
               16-bit instructions in case the second half causes an
               prefetch abort.  */
            offset = ((int32_t)insn << 21) >> 9;
7378
            tcg_gen_movi_i32(cpu_R[14], s->pc + 2 + offset);
P
pbrook 已提交
7379 7380 7381 7382 7383 7384 7385 7386 7387 7388 7389 7390 7391 7392 7393 7394 7395 7396 7397 7398 7399 7400 7401 7402 7403 7404 7405
            return 0;
        }
        /* Fall through to 32-bit decode.  */
    }

    insn = lduw_code(s->pc);
    s->pc += 2;
    insn |= (uint32_t)insn_hw1 << 16;

    if ((insn & 0xf800e800) != 0xf000e800) {
        ARCH(6T2);
    }

    rn = (insn >> 16) & 0xf;
    rs = (insn >> 12) & 0xf;
    rd = (insn >> 8) & 0xf;
    rm = insn & 0xf;
    switch ((insn >> 25) & 0xf) {
    case 0: case 1: case 2: case 3:
        /* 16-bit instructions.  Should never happen.  */
        abort();
    case 4:
        if (insn & (1 << 22)) {
            /* Other load/store, table branch.  */
            if (insn & 0x01200000) {
                /* Load/store doubleword.  */
                if (rn == 15) {
P
pbrook 已提交
7406 7407
                    addr = new_tmp();
                    tcg_gen_movi_i32(addr, s->pc & ~3);
P
pbrook 已提交
7408
                } else {
P
pbrook 已提交
7409
                    addr = load_reg(s, rn);
P
pbrook 已提交
7410 7411 7412 7413 7414
                }
                offset = (insn & 0xff) * 4;
                if ((insn & (1 << 23)) == 0)
                    offset = -offset;
                if (insn & (1 << 24)) {
P
pbrook 已提交
7415
                    tcg_gen_addi_i32(addr, addr, offset);
P
pbrook 已提交
7416 7417 7418 7419
                    offset = 0;
                }
                if (insn & (1 << 20)) {
                    /* ldrd */
P
pbrook 已提交
7420 7421 7422 7423 7424
                    tmp = gen_ld32(addr, IS_USER(s));
                    store_reg(s, rs, tmp);
                    tcg_gen_addi_i32(addr, addr, 4);
                    tmp = gen_ld32(addr, IS_USER(s));
                    store_reg(s, rd, tmp);
P
pbrook 已提交
7425 7426
                } else {
                    /* strd */
P
pbrook 已提交
7427 7428 7429 7430 7431
                    tmp = load_reg(s, rs);
                    gen_st32(tmp, addr, IS_USER(s));
                    tcg_gen_addi_i32(addr, addr, 4);
                    tmp = load_reg(s, rd);
                    gen_st32(tmp, addr, IS_USER(s));
P
pbrook 已提交
7432 7433 7434 7435 7436
                }
                if (insn & (1 << 21)) {
                    /* Base writeback.  */
                    if (rn == 15)
                        goto illegal_op;
P
pbrook 已提交
7437 7438 7439 7440
                    tcg_gen_addi_i32(addr, addr, offset - 4);
                    store_reg(s, rn, addr);
                } else {
                    dead_tmp(addr);
P
pbrook 已提交
7441 7442 7443
                }
            } else if ((insn & (1 << 23)) == 0) {
                /* Load/store exclusive word.  */
7444
                addr = tcg_temp_local_new();
7445
                load_reg_var(s, addr, rn);
P
Paul Brook 已提交
7446
                tcg_gen_addi_i32(addr, addr, (insn & 0xff) << 2);
B
bellard 已提交
7447
                if (insn & (1 << 20)) {
P
Paul Brook 已提交
7448
                    gen_load_exclusive(s, rs, 15, addr, 2);
P
pbrook 已提交
7449
                } else {
P
Paul Brook 已提交
7450
                    gen_store_exclusive(s, rd, rs, 15, addr, 2);
P
pbrook 已提交
7451
                }
7452
                tcg_temp_free(addr);
P
pbrook 已提交
7453 7454 7455
            } else if ((insn & (1 << 6)) == 0) {
                /* Table Branch.  */
                if (rn == 15) {
P
pbrook 已提交
7456 7457
                    addr = new_tmp();
                    tcg_gen_movi_i32(addr, s->pc);
P
pbrook 已提交
7458
                } else {
P
pbrook 已提交
7459
                    addr = load_reg(s, rn);
P
pbrook 已提交
7460
                }
P
pbrook 已提交
7461
                tmp = load_reg(s, rm);
P
pbrook 已提交
7462
                tcg_gen_add_i32(addr, addr, tmp);
P
pbrook 已提交
7463 7464
                if (insn & (1 << 4)) {
                    /* tbh */
P
pbrook 已提交
7465
                    tcg_gen_add_i32(addr, addr, tmp);
P
pbrook 已提交
7466
                    dead_tmp(tmp);
P
pbrook 已提交
7467
                    tmp = gen_ld16u(addr, IS_USER(s));
P
pbrook 已提交
7468
                } else { /* tbb */
P
pbrook 已提交
7469
                    dead_tmp(tmp);
P
pbrook 已提交
7470
                    tmp = gen_ld8u(addr, IS_USER(s));
P
pbrook 已提交
7471
                }
P
pbrook 已提交
7472 7473 7474 7475
                dead_tmp(addr);
                tcg_gen_shli_i32(tmp, tmp, 1);
                tcg_gen_addi_i32(tmp, tmp, s->pc);
                store_reg(s, 15, tmp);
P
pbrook 已提交
7476 7477
            } else {
                /* Load/store exclusive byte/halfword/doubleword.  */
P
Paul Brook 已提交
7478
                ARCH(7);
P
pbrook 已提交
7479
                op = (insn >> 4) & 0x3;
P
Paul Brook 已提交
7480 7481 7482
                if (op == 2) {
                    goto illegal_op;
                }
7483
                addr = tcg_temp_local_new();
7484
                load_reg_var(s, addr, rn);
P
pbrook 已提交
7485
                if (insn & (1 << 20)) {
P
Paul Brook 已提交
7486
                    gen_load_exclusive(s, rs, rd, addr, op);
P
pbrook 已提交
7487
                } else {
P
Paul Brook 已提交
7488
                    gen_store_exclusive(s, rm, rs, rd, addr, op);
P
pbrook 已提交
7489
                }
7490
                tcg_temp_free(addr);
P
pbrook 已提交
7491 7492 7493 7494 7495
            }
        } else {
            /* Load/store multiple, RFE, SRS.  */
            if (((insn >> 23) & 1) == ((insn >> 24) & 1)) {
                /* Not available in user mode.  */
P
pbrook 已提交
7496
                if (IS_USER(s))
P
pbrook 已提交
7497 7498 7499
                    goto illegal_op;
                if (insn & (1 << 20)) {
                    /* rfe */
P
pbrook 已提交
7500 7501 7502 7503 7504 7505 7506
                    addr = load_reg(s, rn);
                    if ((insn & (1 << 24)) == 0)
                        tcg_gen_addi_i32(addr, addr, -8);
                    /* Load PC into tmp and CPSR into tmp2.  */
                    tmp = gen_ld32(addr, 0);
                    tcg_gen_addi_i32(addr, addr, 4);
                    tmp2 = gen_ld32(addr, 0);
P
pbrook 已提交
7507 7508
                    if (insn & (1 << 21)) {
                        /* Base writeback.  */
P
pbrook 已提交
7509 7510 7511 7512 7513 7514 7515 7516
                        if (insn & (1 << 24)) {
                            tcg_gen_addi_i32(addr, addr, 4);
                        } else {
                            tcg_gen_addi_i32(addr, addr, -4);
                        }
                        store_reg(s, rn, addr);
                    } else {
                        dead_tmp(addr);
P
pbrook 已提交
7517
                    }
P
pbrook 已提交
7518
                    gen_rfe(s, tmp, tmp2);
P
pbrook 已提交
7519 7520 7521 7522
                } else {
                    /* srs */
                    op = (insn & 0x1f);
                    if (op == (env->uncached_cpsr & CPSR_M)) {
P
pbrook 已提交
7523
                        addr = load_reg(s, 13);
P
pbrook 已提交
7524
                    } else {
P
pbrook 已提交
7525
                        addr = new_tmp();
7526 7527 7528
                        tmp = tcg_const_i32(op);
                        gen_helper_get_r13_banked(addr, cpu_env, tmp);
                        tcg_temp_free_i32(tmp);
P
pbrook 已提交
7529 7530
                    }
                    if ((insn & (1 << 24)) == 0) {
P
pbrook 已提交
7531
                        tcg_gen_addi_i32(addr, addr, -8);
P
pbrook 已提交
7532
                    }
P
pbrook 已提交
7533 7534 7535 7536 7537 7538
                    tmp = load_reg(s, 14);
                    gen_st32(tmp, addr, 0);
                    tcg_gen_addi_i32(addr, addr, 4);
                    tmp = new_tmp();
                    gen_helper_cpsr_read(tmp);
                    gen_st32(tmp, addr, 0);
P
pbrook 已提交
7539 7540
                    if (insn & (1 << 21)) {
                        if ((insn & (1 << 24)) == 0) {
P
pbrook 已提交
7541
                            tcg_gen_addi_i32(addr, addr, -4);
P
pbrook 已提交
7542
                        } else {
P
pbrook 已提交
7543
                            tcg_gen_addi_i32(addr, addr, 4);
P
pbrook 已提交
7544 7545
                        }
                        if (op == (env->uncached_cpsr & CPSR_M)) {
P
pbrook 已提交
7546
                            store_reg(s, 13, addr);
P
pbrook 已提交
7547
                        } else {
7548 7549 7550
                            tmp = tcg_const_i32(op);
                            gen_helper_set_r13_banked(cpu_env, tmp, addr);
                            tcg_temp_free_i32(tmp);
P
pbrook 已提交
7551
                        }
P
pbrook 已提交
7552 7553
                    } else {
                        dead_tmp(addr);
P
pbrook 已提交
7554 7555 7556 7557 7558
                    }
                }
            } else {
                int i;
                /* Load/store multiple.  */
P
pbrook 已提交
7559
                addr = load_reg(s, rn);
P
pbrook 已提交
7560 7561 7562 7563 7564 7565
                offset = 0;
                for (i = 0; i < 16; i++) {
                    if (insn & (1 << i))
                        offset += 4;
                }
                if (insn & (1 << 24)) {
P
pbrook 已提交
7566
                    tcg_gen_addi_i32(addr, addr, -offset);
P
pbrook 已提交
7567 7568 7569 7570 7571 7572 7573
                }

                for (i = 0; i < 16; i++) {
                    if ((insn & (1 << i)) == 0)
                        continue;
                    if (insn & (1 << 20)) {
                        /* Load.  */
P
pbrook 已提交
7574
                        tmp = gen_ld32(addr, IS_USER(s));
P
pbrook 已提交
7575
                        if (i == 15) {
P
pbrook 已提交
7576
                            gen_bx(s, tmp);
P
pbrook 已提交
7577
                        } else {
P
pbrook 已提交
7578
                            store_reg(s, i, tmp);
P
pbrook 已提交
7579 7580 7581
                        }
                    } else {
                        /* Store.  */
P
pbrook 已提交
7582 7583
                        tmp = load_reg(s, i);
                        gen_st32(tmp, addr, IS_USER(s));
P
pbrook 已提交
7584
                    }
P
pbrook 已提交
7585
                    tcg_gen_addi_i32(addr, addr, 4);
P
pbrook 已提交
7586 7587 7588 7589
                }
                if (insn & (1 << 21)) {
                    /* Base register writeback.  */
                    if (insn & (1 << 24)) {
P
pbrook 已提交
7590
                        tcg_gen_addi_i32(addr, addr, -offset);
P
pbrook 已提交
7591 7592 7593 7594
                    }
                    /* Fault if writeback register is in register list.  */
                    if (insn & (1 << rn))
                        goto illegal_op;
P
pbrook 已提交
7595 7596 7597
                    store_reg(s, rn, addr);
                } else {
                    dead_tmp(addr);
P
pbrook 已提交
7598 7599 7600 7601 7602
                }
            }
        }
        break;
    case 5: /* Data processing register constant shift.  */
7603 7604 7605 7606 7607 7608 7609
        if (rn == 15) {
            tmp = new_tmp();
            tcg_gen_movi_i32(tmp, 0);
        } else {
            tmp = load_reg(s, rn);
        }
        tmp2 = load_reg(s, rm);
P
pbrook 已提交
7610 7611 7612 7613 7614
        op = (insn >> 21) & 0xf;
        shiftop = (insn >> 4) & 3;
        shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c);
        conds = (insn & (1 << 20)) != 0;
        logic_cc = (conds && thumb2_logic_op(op));
7615 7616
        gen_arm_shift_im(tmp2, shiftop, shift, logic_cc);
        if (gen_thumb2_data_op(s, op, conds, 0, tmp, tmp2))
P
pbrook 已提交
7617
            goto illegal_op;
7618 7619 7620 7621 7622 7623
        dead_tmp(tmp2);
        if (rd != 15) {
            store_reg(s, rd, tmp);
        } else {
            dead_tmp(tmp);
        }
P
pbrook 已提交
7624 7625 7626 7627 7628 7629 7630
        break;
    case 13: /* Misc data processing.  */
        op = ((insn >> 22) & 6) | ((insn >> 7) & 1);
        if (op < 4 && (insn & 0xf000) != 0xf000)
            goto illegal_op;
        switch (op) {
        case 0: /* Register controlled shift.  */
P
pbrook 已提交
7631 7632
            tmp = load_reg(s, rn);
            tmp2 = load_reg(s, rm);
P
pbrook 已提交
7633 7634 7635
            if ((insn & 0x70) != 0)
                goto illegal_op;
            op = (insn >> 21) & 3;
P
pbrook 已提交
7636 7637 7638 7639
            logic_cc = (insn & (1 << 20)) != 0;
            gen_arm_shift_reg(tmp, op, tmp2, logic_cc);
            if (logic_cc)
                gen_logic_CC(tmp);
7640
            store_reg_bx(env, s, rd, tmp);
P
pbrook 已提交
7641 7642
            break;
        case 1: /* Sign/zero extend.  */
P
pbrook 已提交
7643
            tmp = load_reg(s, rm);
P
pbrook 已提交
7644 7645 7646 7647
            shift = (insn >> 4) & 3;
            /* ??? In many cases it's not neccessary to do a
               rotate, a shift is sufficient.  */
            if (shift != 0)
7648
                tcg_gen_rotri_i32(tmp, tmp, shift * 8);
P
pbrook 已提交
7649 7650
            op = (insn >> 20) & 7;
            switch (op) {
P
pbrook 已提交
7651 7652 7653 7654 7655 7656
            case 0: gen_sxth(tmp);   break;
            case 1: gen_uxth(tmp);   break;
            case 2: gen_sxtb16(tmp); break;
            case 3: gen_uxtb16(tmp); break;
            case 4: gen_sxtb(tmp);   break;
            case 5: gen_uxtb(tmp);   break;
P
pbrook 已提交
7657 7658 7659
            default: goto illegal_op;
            }
            if (rn != 15) {
P
pbrook 已提交
7660
                tmp2 = load_reg(s, rn);
P
pbrook 已提交
7661
                if ((op >> 1) == 1) {
P
pbrook 已提交
7662
                    gen_add16(tmp, tmp2);
P
pbrook 已提交
7663
                } else {
P
pbrook 已提交
7664 7665
                    tcg_gen_add_i32(tmp, tmp, tmp2);
                    dead_tmp(tmp2);
P
pbrook 已提交
7666 7667
                }
            }
P
pbrook 已提交
7668
            store_reg(s, rd, tmp);
P
pbrook 已提交
7669 7670 7671 7672 7673 7674
            break;
        case 2: /* SIMD add/subtract.  */
            op = (insn >> 20) & 7;
            shift = (insn >> 4) & 7;
            if ((op & 3) == 3 || (shift & 3) == 3)
                goto illegal_op;
P
pbrook 已提交
7675 7676 7677 7678 7679
            tmp = load_reg(s, rn);
            tmp2 = load_reg(s, rm);
            gen_thumb2_parallel_addsub(op, shift, tmp, tmp2);
            dead_tmp(tmp2);
            store_reg(s, rd, tmp);
P
pbrook 已提交
7680 7681 7682 7683 7684
            break;
        case 3: /* Other data processing.  */
            op = ((insn >> 17) & 0x38) | ((insn >> 4) & 7);
            if (op < 4) {
                /* Saturating add/subtract.  */
P
pbrook 已提交
7685 7686
                tmp = load_reg(s, rn);
                tmp2 = load_reg(s, rm);
P
pbrook 已提交
7687
                if (op & 2)
P
pbrook 已提交
7688
                    gen_helper_double_saturate(tmp, tmp);
P
pbrook 已提交
7689
                if (op & 1)
P
pbrook 已提交
7690
                    gen_helper_sub_saturate(tmp, tmp2, tmp);
P
pbrook 已提交
7691
                else
P
pbrook 已提交
7692 7693
                    gen_helper_add_saturate(tmp, tmp, tmp2);
                dead_tmp(tmp2);
P
pbrook 已提交
7694
            } else {
P
pbrook 已提交
7695
                tmp = load_reg(s, rn);
P
pbrook 已提交
7696 7697
                switch (op) {
                case 0x0a: /* rbit */
P
pbrook 已提交
7698
                    gen_helper_rbit(tmp, tmp);
P
pbrook 已提交
7699 7700
                    break;
                case 0x08: /* rev */
A
aurel32 已提交
7701
                    tcg_gen_bswap32_i32(tmp, tmp);
P
pbrook 已提交
7702 7703
                    break;
                case 0x09: /* rev16 */
P
pbrook 已提交
7704
                    gen_rev16(tmp);
P
pbrook 已提交
7705 7706
                    break;
                case 0x0b: /* revsh */
P
pbrook 已提交
7707
                    gen_revsh(tmp);
P
pbrook 已提交
7708 7709
                    break;
                case 0x10: /* sel */
P
pbrook 已提交
7710
                    tmp2 = load_reg(s, rm);
P
pbrook 已提交
7711 7712
                    tmp3 = new_tmp();
                    tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUState, GE));
P
pbrook 已提交
7713
                    gen_helper_sel_flags(tmp, tmp3, tmp, tmp2);
P
pbrook 已提交
7714
                    dead_tmp(tmp3);
P
pbrook 已提交
7715
                    dead_tmp(tmp2);
P
pbrook 已提交
7716 7717
                    break;
                case 0x18: /* clz */
P
pbrook 已提交
7718
                    gen_helper_clz(tmp, tmp);
P
pbrook 已提交
7719 7720 7721 7722 7723
                    break;
                default:
                    goto illegal_op;
                }
            }
P
pbrook 已提交
7724
            store_reg(s, rd, tmp);
P
pbrook 已提交
7725 7726 7727
            break;
        case 4: case 5: /* 32-bit multiply.  Sum of absolute differences.  */
            op = (insn >> 4) & 0xf;
P
pbrook 已提交
7728 7729
            tmp = load_reg(s, rn);
            tmp2 = load_reg(s, rm);
P
pbrook 已提交
7730 7731
            switch ((insn >> 20) & 7) {
            case 0: /* 32 x 32 -> 32 */
P
pbrook 已提交
7732 7733
                tcg_gen_mul_i32(tmp, tmp, tmp2);
                dead_tmp(tmp2);
P
pbrook 已提交
7734
                if (rs != 15) {
P
pbrook 已提交
7735
                    tmp2 = load_reg(s, rs);
P
pbrook 已提交
7736
                    if (op)
P
pbrook 已提交
7737
                        tcg_gen_sub_i32(tmp, tmp2, tmp);
P
pbrook 已提交
7738
                    else
P
pbrook 已提交
7739 7740
                        tcg_gen_add_i32(tmp, tmp, tmp2);
                    dead_tmp(tmp2);
P
pbrook 已提交
7741 7742 7743
                }
                break;
            case 1: /* 16 x 16 -> 32 */
P
pbrook 已提交
7744 7745
                gen_mulxy(tmp, tmp2, op & 2, op & 1);
                dead_tmp(tmp2);
P
pbrook 已提交
7746
                if (rs != 15) {
P
pbrook 已提交
7747 7748 7749
                    tmp2 = load_reg(s, rs);
                    gen_helper_add_setq(tmp, tmp, tmp2);
                    dead_tmp(tmp2);
P
pbrook 已提交
7750 7751 7752 7753 7754
                }
                break;
            case 2: /* Dual multiply add.  */
            case 4: /* Dual multiply subtract.  */
                if (op)
P
pbrook 已提交
7755 7756
                    gen_swap_half(tmp2);
                gen_smul_dual(tmp, tmp2);
P
pbrook 已提交
7757 7758
                /* This addition cannot overflow.  */
                if (insn & (1 << 22)) {
P
pbrook 已提交
7759
                    tcg_gen_sub_i32(tmp, tmp, tmp2);
P
pbrook 已提交
7760
                } else {
P
pbrook 已提交
7761
                    tcg_gen_add_i32(tmp, tmp, tmp2);
P
pbrook 已提交
7762
                }
P
pbrook 已提交
7763
                dead_tmp(tmp2);
P
pbrook 已提交
7764 7765
                if (rs != 15)
                  {
P
pbrook 已提交
7766 7767 7768
                    tmp2 = load_reg(s, rs);
                    gen_helper_add_setq(tmp, tmp, tmp2);
                    dead_tmp(tmp2);
P
pbrook 已提交
7769 7770 7771 7772
                  }
                break;
            case 3: /* 32 * 16 -> 32msb */
                if (op)
P
pbrook 已提交
7773
                    tcg_gen_sari_i32(tmp2, tmp2, 16);
P
pbrook 已提交
7774
                else
P
pbrook 已提交
7775
                    gen_sxth(tmp2);
P
pbrook 已提交
7776 7777
                tmp64 = gen_muls_i64_i32(tmp, tmp2);
                tcg_gen_shri_i64(tmp64, tmp64, 16);
P
pbrook 已提交
7778
                tmp = new_tmp();
P
pbrook 已提交
7779
                tcg_gen_trunc_i64_i32(tmp, tmp64);
7780
                tcg_temp_free_i64(tmp64);
P
pbrook 已提交
7781 7782
                if (rs != 15)
                  {
P
pbrook 已提交
7783 7784 7785
                    tmp2 = load_reg(s, rs);
                    gen_helper_add_setq(tmp, tmp, tmp2);
                    dead_tmp(tmp2);
P
pbrook 已提交
7786 7787 7788
                  }
                break;
            case 5: case 6: /* 32 * 32 -> 32msb */
P
pbrook 已提交
7789 7790 7791 7792 7793 7794 7795 7796
                gen_imull(tmp, tmp2);
                if (insn & (1 << 5)) {
                    gen_roundqd(tmp, tmp2);
                    dead_tmp(tmp2);
                } else {
                    dead_tmp(tmp);
                    tmp = tmp2;
                }
P
pbrook 已提交
7797
                if (rs != 15) {
P
pbrook 已提交
7798
                    tmp2 = load_reg(s, rs);
P
pbrook 已提交
7799
                    if (insn & (1 << 21)) {
P
pbrook 已提交
7800
                        tcg_gen_add_i32(tmp, tmp, tmp2);
B
bellard 已提交
7801
                    } else {
P
pbrook 已提交
7802
                        tcg_gen_sub_i32(tmp, tmp2, tmp);
B
bellard 已提交
7803
                    }
P
pbrook 已提交
7804
                    dead_tmp(tmp2);
B
bellard 已提交
7805
                }
P
pbrook 已提交
7806 7807
                break;
            case 7: /* Unsigned sum of absolute differences.  */
P
pbrook 已提交
7808 7809
                gen_helper_usad8(tmp, tmp, tmp2);
                dead_tmp(tmp2);
P
pbrook 已提交
7810
                if (rs != 15) {
P
pbrook 已提交
7811 7812 7813
                    tmp2 = load_reg(s, rs);
                    tcg_gen_add_i32(tmp, tmp, tmp2);
                    dead_tmp(tmp2);
7814
                }
P
pbrook 已提交
7815
                break;
B
bellard 已提交
7816
            }
P
pbrook 已提交
7817
            store_reg(s, rd, tmp);
B
bellard 已提交
7818
            break;
P
pbrook 已提交
7819 7820
        case 6: case 7: /* 64-bit multiply, Divide.  */
            op = ((insn >> 4) & 0xf) | ((insn >> 16) & 0x70);
P
pbrook 已提交
7821 7822
            tmp = load_reg(s, rn);
            tmp2 = load_reg(s, rm);
P
pbrook 已提交
7823 7824 7825 7826 7827
            if ((op & 0x50) == 0x10) {
                /* sdiv, udiv */
                if (!arm_feature(env, ARM_FEATURE_DIV))
                    goto illegal_op;
                if (op & 0x20)
P
pbrook 已提交
7828
                    gen_helper_udiv(tmp, tmp, tmp2);
B
bellard 已提交
7829
                else
P
pbrook 已提交
7830 7831 7832
                    gen_helper_sdiv(tmp, tmp, tmp2);
                dead_tmp(tmp2);
                store_reg(s, rd, tmp);
P
pbrook 已提交
7833 7834 7835
            } else if ((op & 0xe) == 0xc) {
                /* Dual multiply accumulate long.  */
                if (op & 1)
P
pbrook 已提交
7836 7837
                    gen_swap_half(tmp2);
                gen_smul_dual(tmp, tmp2);
P
pbrook 已提交
7838
                if (op & 0x10) {
P
pbrook 已提交
7839
                    tcg_gen_sub_i32(tmp, tmp, tmp2);
B
bellard 已提交
7840
                } else {
P
pbrook 已提交
7841
                    tcg_gen_add_i32(tmp, tmp, tmp2);
B
bellard 已提交
7842
                }
P
pbrook 已提交
7843
                dead_tmp(tmp2);
P
pbrook 已提交
7844 7845 7846 7847 7848 7849
                /* BUGFIX */
                tmp64 = tcg_temp_new_i64();
                tcg_gen_ext_i32_i64(tmp64, tmp);
                dead_tmp(tmp);
                gen_addq(s, tmp64, rs, rd);
                gen_storeq_reg(s, rs, rd, tmp64);
7850
                tcg_temp_free_i64(tmp64);
B
bellard 已提交
7851
            } else {
P
pbrook 已提交
7852 7853
                if (op & 0x20) {
                    /* Unsigned 64-bit multiply  */
P
pbrook 已提交
7854
                    tmp64 = gen_mulu_i64_i32(tmp, tmp2);
B
bellard 已提交
7855
                } else {
P
pbrook 已提交
7856 7857
                    if (op & 8) {
                        /* smlalxy */
P
pbrook 已提交
7858 7859
                        gen_mulxy(tmp, tmp2, op & 2, op & 1);
                        dead_tmp(tmp2);
P
pbrook 已提交
7860 7861
                        tmp64 = tcg_temp_new_i64();
                        tcg_gen_ext_i32_i64(tmp64, tmp);
P
pbrook 已提交
7862
                        dead_tmp(tmp);
P
pbrook 已提交
7863 7864
                    } else {
                        /* Signed 64-bit multiply  */
P
pbrook 已提交
7865
                        tmp64 = gen_muls_i64_i32(tmp, tmp2);
P
pbrook 已提交
7866
                    }
B
bellard 已提交
7867
                }
P
pbrook 已提交
7868 7869
                if (op & 4) {
                    /* umaal */
P
pbrook 已提交
7870 7871
                    gen_addq_lo(s, tmp64, rs);
                    gen_addq_lo(s, tmp64, rd);
P
pbrook 已提交
7872 7873
                } else if (op & 0x40) {
                    /* 64-bit accumulate.  */
P
pbrook 已提交
7874
                    gen_addq(s, tmp64, rs, rd);
P
pbrook 已提交
7875
                }
P
pbrook 已提交
7876
                gen_storeq_reg(s, rs, rd, tmp64);
7877
                tcg_temp_free_i64(tmp64);
7878
            }
B
bellard 已提交
7879
            break;
P
pbrook 已提交
7880 7881 7882 7883 7884 7885 7886 7887 7888 7889 7890 7891 7892 7893 7894 7895 7896 7897 7898 7899 7900 7901 7902 7903 7904 7905 7906 7907 7908 7909 7910 7911 7912
        }
        break;
    case 6: case 7: case 14: case 15:
        /* Coprocessor.  */
        if (((insn >> 24) & 3) == 3) {
            /* Translate into the equivalent ARM encoding.  */
            insn = (insn & 0xe2ffffff) | ((insn & (1 << 28)) >> 4);
            if (disas_neon_data_insn(env, s, insn))
                goto illegal_op;
        } else {
            if (insn & (1 << 28))
                goto illegal_op;
            if (disas_coproc_insn (env, s, insn))
                goto illegal_op;
        }
        break;
    case 8: case 9: case 10: case 11:
        if (insn & (1 << 15)) {
            /* Branches, misc control.  */
            if (insn & 0x5000) {
                /* Unconditional branch.  */
                /* signextend(hw1[10:0]) -> offset[:12].  */
                offset = ((int32_t)insn << 5) >> 9 & ~(int32_t)0xfff;
                /* hw1[10:0] -> offset[11:1].  */
                offset |= (insn & 0x7ff) << 1;
                /* (~hw2[13, 11] ^ offset[24]) -> offset[23,22]
                   offset[24:22] already have the same value because of the
                   sign extension above.  */
                offset ^= ((~insn) & (1 << 13)) << 10;
                offset ^= ((~insn) & (1 << 11)) << 11;

                if (insn & (1 << 14)) {
                    /* Branch and link.  */
7913
                    tcg_gen_movi_i32(cpu_R[14], s->pc | 1);
B
bellard 已提交
7914
                }
7915

P
pbrook 已提交
7916
                offset += s->pc;
P
pbrook 已提交
7917 7918
                if (insn & (1 << 12)) {
                    /* b/bl */
P
pbrook 已提交
7919
                    gen_jmp(s, offset);
P
pbrook 已提交
7920 7921
                } else {
                    /* blx */
P
pbrook 已提交
7922 7923
                    offset &= ~(uint32_t)2;
                    gen_bx_im(s, offset);
B
bellard 已提交
7924
                }
P
pbrook 已提交
7925 7926 7927 7928 7929 7930 7931 7932
            } else if (((insn >> 23) & 7) == 7) {
                /* Misc control */
                if (insn & (1 << 13))
                    goto illegal_op;

                if (insn & (1 << 26)) {
                    /* Secure monitor call (v6Z) */
                    goto illegal_op; /* not implemented.  */
B
bellard 已提交
7933
                } else {
P
pbrook 已提交
7934 7935 7936 7937
                    op = (insn >> 20) & 7;
                    switch (op) {
                    case 0: /* msr cpsr.  */
                        if (IS_M(env)) {
P
pbrook 已提交
7938 7939 7940
                            tmp = load_reg(s, rn);
                            addr = tcg_const_i32(insn & 0xff);
                            gen_helper_v7m_msr(cpu_env, addr, tmp);
7941 7942
                            tcg_temp_free_i32(addr);
                            dead_tmp(tmp);
P
pbrook 已提交
7943 7944 7945 7946 7947 7948 7949
                            gen_lookup_tb(s);
                            break;
                        }
                        /* fall through */
                    case 1: /* msr spsr.  */
                        if (IS_M(env))
                            goto illegal_op;
7950 7951
                        tmp = load_reg(s, rn);
                        if (gen_set_psr(s,
P
pbrook 已提交
7952
                              msr_mask(env, s, (insn >> 8) & 0xf, op == 1),
7953
                              op == 1, tmp))
P
pbrook 已提交
7954 7955 7956 7957 7958 7959 7960 7961 7962 7963 7964 7965 7966 7967 7968 7969 7970 7971 7972 7973 7974 7975 7976 7977 7978 7979
                            goto illegal_op;
                        break;
                    case 2: /* cps, nop-hint.  */
                        if (((insn >> 8) & 7) == 0) {
                            gen_nop_hint(s, insn & 0xff);
                        }
                        /* Implemented as NOP in user mode.  */
                        if (IS_USER(s))
                            break;
                        offset = 0;
                        imm = 0;
                        if (insn & (1 << 10)) {
                            if (insn & (1 << 7))
                                offset |= CPSR_A;
                            if (insn & (1 << 6))
                                offset |= CPSR_I;
                            if (insn & (1 << 5))
                                offset |= CPSR_F;
                            if (insn & (1 << 9))
                                imm = CPSR_A | CPSR_I | CPSR_F;
                        }
                        if (insn & (1 << 8)) {
                            offset |= 0x1f;
                            imm |= (insn & 0x1f);
                        }
                        if (offset) {
7980
                            gen_set_psr_im(s, offset, 0, imm);
P
pbrook 已提交
7981 7982 7983
                        }
                        break;
                    case 3: /* Special control operations.  */
P
Paul Brook 已提交
7984
                        ARCH(7);
P
pbrook 已提交
7985 7986 7987
                        op = (insn >> 4) & 0xf;
                        switch (op) {
                        case 2: /* clrex */
P
Paul Brook 已提交
7988
                            gen_clrex(s);
P
pbrook 已提交
7989 7990 7991 7992 7993 7994 7995 7996 7997 7998 7999 8000
                            break;
                        case 4: /* dsb */
                        case 5: /* dmb */
                        case 6: /* isb */
                            /* These execute as NOPs.  */
                            break;
                        default:
                            goto illegal_op;
                        }
                        break;
                    case 4: /* bxj */
                        /* Trivial implementation equivalent to bx.  */
P
pbrook 已提交
8001 8002
                        tmp = load_reg(s, rn);
                        gen_bx(s, tmp);
P
pbrook 已提交
8003 8004
                        break;
                    case 5: /* Exception return.  */
8005 8006 8007 8008 8009 8010 8011 8012 8013 8014
                        if (IS_USER(s)) {
                            goto illegal_op;
                        }
                        if (rn != 14 || rd != 15) {
                            goto illegal_op;
                        }
                        tmp = load_reg(s, rn);
                        tcg_gen_subi_i32(tmp, tmp, insn & 0xff);
                        gen_exception_return(s, tmp);
                        break;
P
pbrook 已提交
8015
                    case 6: /* mrs cpsr.  */
P
pbrook 已提交
8016
                        tmp = new_tmp();
P
pbrook 已提交
8017
                        if (IS_M(env)) {
P
pbrook 已提交
8018 8019
                            addr = tcg_const_i32(insn & 0xff);
                            gen_helper_v7m_mrs(tmp, cpu_env, addr);
8020
                            tcg_temp_free_i32(addr);
P
pbrook 已提交
8021
                        } else {
P
pbrook 已提交
8022
                            gen_helper_cpsr_read(tmp);
P
pbrook 已提交
8023
                        }
P
pbrook 已提交
8024
                        store_reg(s, rd, tmp);
P
pbrook 已提交
8025 8026 8027 8028 8029
                        break;
                    case 7: /* mrs spsr.  */
                        /* Not accessible in user mode.  */
                        if (IS_USER(s) || IS_M(env))
                            goto illegal_op;
P
pbrook 已提交
8030 8031
                        tmp = load_cpu_field(spsr);
                        store_reg(s, rd, tmp);
P
pbrook 已提交
8032
                        break;
B
bellard 已提交
8033 8034
                    }
                }
P
pbrook 已提交
8035 8036 8037 8038 8039
            } else {
                /* Conditional branch.  */
                op = (insn >> 22) & 0xf;
                /* Generate a conditional jump to next instruction.  */
                s->condlabel = gen_new_label();
P
pbrook 已提交
8040
                gen_test_cc(op ^ 1, s->condlabel);
P
pbrook 已提交
8041 8042 8043 8044 8045 8046 8047 8048 8049 8050 8051 8052 8053 8054
                s->condjmp = 1;

                /* offset[11:1] = insn[10:0] */
                offset = (insn & 0x7ff) << 1;
                /* offset[17:12] = insn[21:16].  */
                offset |= (insn & 0x003f0000) >> 4;
                /* offset[31:20] = insn[26].  */
                offset |= ((int32_t)((insn << 5) & 0x80000000)) >> 11;
                /* offset[18] = insn[13].  */
                offset |= (insn & (1 << 13)) << 5;
                /* offset[19] = insn[11].  */
                offset |= (insn & (1 << 11)) << 8;

                /* jump to the offset */
P
pbrook 已提交
8055
                gen_jmp(s, s->pc + offset);
P
pbrook 已提交
8056 8057 8058 8059 8060 8061 8062 8063 8064 8065 8066
            }
        } else {
            /* Data processing immediate.  */
            if (insn & (1 << 25)) {
                if (insn & (1 << 24)) {
                    if (insn & (1 << 20))
                        goto illegal_op;
                    /* Bitfield/Saturate.  */
                    op = (insn >> 21) & 7;
                    imm = insn & 0x1f;
                    shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c);
P
pbrook 已提交
8067 8068 8069 8070 8071 8072
                    if (rn == 15) {
                        tmp = new_tmp();
                        tcg_gen_movi_i32(tmp, 0);
                    } else {
                        tmp = load_reg(s, rn);
                    }
P
pbrook 已提交
8073 8074 8075 8076 8077 8078
                    switch (op) {
                    case 2: /* Signed bitfield extract.  */
                        imm++;
                        if (shift + imm > 32)
                            goto illegal_op;
                        if (imm < 32)
P
pbrook 已提交
8079
                            gen_sbfx(tmp, shift, imm);
P
pbrook 已提交
8080 8081 8082 8083 8084 8085
                        break;
                    case 6: /* Unsigned bitfield extract.  */
                        imm++;
                        if (shift + imm > 32)
                            goto illegal_op;
                        if (imm < 32)
P
pbrook 已提交
8086
                            gen_ubfx(tmp, shift, (1u << imm) - 1);
P
pbrook 已提交
8087 8088 8089 8090 8091 8092
                        break;
                    case 3: /* Bitfield insert/clear.  */
                        if (imm < shift)
                            goto illegal_op;
                        imm = imm + 1 - shift;
                        if (imm != 32) {
P
pbrook 已提交
8093
                            tmp2 = load_reg(s, rd);
P
pbrook 已提交
8094
                            gen_bfi(tmp, tmp2, tmp, shift, (1u << imm) - 1);
P
pbrook 已提交
8095
                            dead_tmp(tmp2);
P
pbrook 已提交
8096 8097 8098 8099 8100 8101 8102
                        }
                        break;
                    case 7:
                        goto illegal_op;
                    default: /* Saturate.  */
                        if (shift) {
                            if (op & 1)
P
pbrook 已提交
8103
                                tcg_gen_sari_i32(tmp, tmp, shift);
P
pbrook 已提交
8104
                            else
P
pbrook 已提交
8105
                                tcg_gen_shli_i32(tmp, tmp, shift);
P
pbrook 已提交
8106
                        }
P
pbrook 已提交
8107
                        tmp2 = tcg_const_i32(imm);
P
pbrook 已提交
8108 8109 8110
                        if (op & 4) {
                            /* Unsigned.  */
                            if ((op & 1) && shift == 0)
P
pbrook 已提交
8111
                                gen_helper_usat16(tmp, tmp, tmp2);
P
pbrook 已提交
8112
                            else
P
pbrook 已提交
8113
                                gen_helper_usat(tmp, tmp, tmp2);
B
bellard 已提交
8114
                        } else {
P
pbrook 已提交
8115 8116
                            /* Signed.  */
                            if ((op & 1) && shift == 0)
P
pbrook 已提交
8117
                                gen_helper_ssat16(tmp, tmp, tmp2);
P
pbrook 已提交
8118
                            else
P
pbrook 已提交
8119
                                gen_helper_ssat(tmp, tmp, tmp2);
B
bellard 已提交
8120
                        }
8121
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8122
                        break;
B
bellard 已提交
8123
                    }
P
pbrook 已提交
8124
                    store_reg(s, rd, tmp);
P
pbrook 已提交
8125 8126 8127 8128 8129 8130 8131 8132
                } else {
                    imm = ((insn & 0x04000000) >> 15)
                          | ((insn & 0x7000) >> 4) | (insn & 0xff);
                    if (insn & (1 << 22)) {
                        /* 16-bit immediate.  */
                        imm |= (insn >> 4) & 0xf000;
                        if (insn & (1 << 23)) {
                            /* movt */
P
pbrook 已提交
8133
                            tmp = load_reg(s, rd);
P
pbrook 已提交
8134
                            tcg_gen_ext16u_i32(tmp, tmp);
P
pbrook 已提交
8135
                            tcg_gen_ori_i32(tmp, tmp, imm << 16);
B
bellard 已提交
8136
                        } else {
P
pbrook 已提交
8137
                            /* movw */
P
pbrook 已提交
8138 8139
                            tmp = new_tmp();
                            tcg_gen_movi_i32(tmp, imm);
B
bellard 已提交
8140 8141
                        }
                    } else {
P
pbrook 已提交
8142 8143
                        /* Add/sub 12-bit immediate.  */
                        if (rn == 15) {
P
pbrook 已提交
8144
                            offset = s->pc & ~(uint32_t)3;
P
pbrook 已提交
8145
                            if (insn & (1 << 23))
P
pbrook 已提交
8146
                                offset -= imm;
P
pbrook 已提交
8147
                            else
P
pbrook 已提交
8148
                                offset += imm;
P
pbrook 已提交
8149 8150
                            tmp = new_tmp();
                            tcg_gen_movi_i32(tmp, offset);
B
bellard 已提交
8151
                        } else {
P
pbrook 已提交
8152
                            tmp = load_reg(s, rn);
P
pbrook 已提交
8153
                            if (insn & (1 << 23))
P
pbrook 已提交
8154
                                tcg_gen_subi_i32(tmp, tmp, imm);
P
pbrook 已提交
8155
                            else
P
pbrook 已提交
8156
                                tcg_gen_addi_i32(tmp, tmp, imm);
B
bellard 已提交
8157
                        }
P
pbrook 已提交
8158
                    }
P
pbrook 已提交
8159
                    store_reg(s, rd, tmp);
P
pbrook 已提交
8160
                }
P
pbrook 已提交
8161 8162 8163 8164 8165 8166 8167 8168 8169 8170 8171 8172 8173 8174 8175 8176 8177 8178 8179 8180 8181 8182 8183 8184 8185 8186
            } else {
                int shifter_out = 0;
                /* modified 12-bit immediate.  */
                shift = ((insn & 0x04000000) >> 23) | ((insn & 0x7000) >> 12);
                imm = (insn & 0xff);
                switch (shift) {
                case 0: /* XY */
                    /* Nothing to do.  */
                    break;
                case 1: /* 00XY00XY */
                    imm |= imm << 16;
                    break;
                case 2: /* XY00XY00 */
                    imm |= imm << 16;
                    imm <<= 8;
                    break;
                case 3: /* XYXYXYXY */
                    imm |= imm << 16;
                    imm |= imm << 8;
                    break;
                default: /* Rotated constant.  */
                    shift = (shift << 1) | (imm >> 7);
                    imm |= 0x80;
                    imm = imm << (32 - shift);
                    shifter_out = 1;
                    break;
B
bellard 已提交
8187
                }
8188 8189
                tmp2 = new_tmp();
                tcg_gen_movi_i32(tmp2, imm);
P
pbrook 已提交
8190
                rn = (insn >> 16) & 0xf;
8191 8192 8193 8194 8195 8196
                if (rn == 15) {
                    tmp = new_tmp();
                    tcg_gen_movi_i32(tmp, 0);
                } else {
                    tmp = load_reg(s, rn);
                }
P
pbrook 已提交
8197 8198
                op = (insn >> 21) & 0xf;
                if (gen_thumb2_data_op(s, op, (insn & (1 << 20)) != 0,
8199
                                       shifter_out, tmp, tmp2))
P
pbrook 已提交
8200
                    goto illegal_op;
8201
                dead_tmp(tmp2);
P
pbrook 已提交
8202 8203
                rd = (insn >> 8) & 0xf;
                if (rd != 15) {
8204 8205 8206
                    store_reg(s, rd, tmp);
                } else {
                    dead_tmp(tmp);
B
bellard 已提交
8207 8208
                }
            }
P
pbrook 已提交
8209 8210 8211 8212 8213 8214
        }
        break;
    case 12: /* Load/store single data item.  */
        {
        int postinc = 0;
        int writeback = 0;
P
pbrook 已提交
8215
        int user;
P
pbrook 已提交
8216 8217
        if ((insn & 0x01100000) == 0x01000000) {
            if (disas_neon_ls_insn(env, s, insn))
8218
                goto illegal_op;
P
pbrook 已提交
8219 8220
            break;
        }
P
pbrook 已提交
8221
        user = IS_USER(s);
P
pbrook 已提交
8222
        if (rn == 15) {
P
pbrook 已提交
8223
            addr = new_tmp();
P
pbrook 已提交
8224 8225 8226 8227 8228 8229 8230
            /* PC relative.  */
            /* s->pc has already been incremented by 4.  */
            imm = s->pc & 0xfffffffc;
            if (insn & (1 << 23))
                imm += insn & 0xfff;
            else
                imm -= insn & 0xfff;
P
pbrook 已提交
8231
            tcg_gen_movi_i32(addr, imm);
P
pbrook 已提交
8232
        } else {
P
pbrook 已提交
8233
            addr = load_reg(s, rn);
P
pbrook 已提交
8234 8235 8236
            if (insn & (1 << 23)) {
                /* Positive offset.  */
                imm = insn & 0xfff;
P
pbrook 已提交
8237
                tcg_gen_addi_i32(addr, addr, imm);
P
pbrook 已提交
8238 8239 8240 8241 8242 8243 8244
            } else {
                op = (insn >> 8) & 7;
                imm = insn & 0xff;
                switch (op) {
                case 0: case 8: /* Shifted Register.  */
                    shift = (insn >> 4) & 0xf;
                    if (shift > 3)
8245
                        goto illegal_op;
P
pbrook 已提交
8246
                    tmp = load_reg(s, rm);
P
pbrook 已提交
8247
                    if (shift)
P
pbrook 已提交
8248
                        tcg_gen_shli_i32(tmp, tmp, shift);
P
pbrook 已提交
8249
                    tcg_gen_add_i32(addr, addr, tmp);
P
pbrook 已提交
8250
                    dead_tmp(tmp);
P
pbrook 已提交
8251 8252
                    break;
                case 4: /* Negative offset.  */
P
pbrook 已提交
8253
                    tcg_gen_addi_i32(addr, addr, -imm);
P
pbrook 已提交
8254 8255
                    break;
                case 6: /* User privilege.  */
P
pbrook 已提交
8256 8257
                    tcg_gen_addi_i32(addr, addr, imm);
                    user = 1;
P
pbrook 已提交
8258 8259 8260 8261 8262 8263 8264 8265 8266 8267 8268 8269
                    break;
                case 1: /* Post-decrement.  */
                    imm = -imm;
                    /* Fall through.  */
                case 3: /* Post-increment.  */
                    postinc = 1;
                    writeback = 1;
                    break;
                case 5: /* Pre-decrement.  */
                    imm = -imm;
                    /* Fall through.  */
                case 7: /* Pre-increment.  */
P
pbrook 已提交
8270
                    tcg_gen_addi_i32(addr, addr, imm);
P
pbrook 已提交
8271 8272 8273
                    writeback = 1;
                    break;
                default:
B
bellard 已提交
8274
                    goto illegal_op;
P
pbrook 已提交
8275 8276 8277 8278 8279 8280 8281 8282
                }
            }
        }
        op = ((insn >> 21) & 3) | ((insn >> 22) & 4);
        if (insn & (1 << 20)) {
            /* Load.  */
            if (rs == 15 && op != 2) {
                if (op & 2)
B
bellard 已提交
8283
                    goto illegal_op;
P
pbrook 已提交
8284 8285 8286
                /* Memory hint.  Implemented as NOP.  */
            } else {
                switch (op) {
P
pbrook 已提交
8287 8288 8289 8290 8291
                case 0: tmp = gen_ld8u(addr, user); break;
                case 4: tmp = gen_ld8s(addr, user); break;
                case 1: tmp = gen_ld16u(addr, user); break;
                case 5: tmp = gen_ld16s(addr, user); break;
                case 2: tmp = gen_ld32(addr, user); break;
P
pbrook 已提交
8292 8293 8294
                default: goto illegal_op;
                }
                if (rs == 15) {
P
pbrook 已提交
8295
                    gen_bx(s, tmp);
P
pbrook 已提交
8296
                } else {
P
pbrook 已提交
8297
                    store_reg(s, rs, tmp);
P
pbrook 已提交
8298 8299 8300 8301 8302
                }
            }
        } else {
            /* Store.  */
            if (rs == 15)
B
bellard 已提交
8303
                goto illegal_op;
P
pbrook 已提交
8304
            tmp = load_reg(s, rs);
P
pbrook 已提交
8305
            switch (op) {
P
pbrook 已提交
8306 8307 8308
            case 0: gen_st8(tmp, addr, user); break;
            case 1: gen_st16(tmp, addr, user); break;
            case 2: gen_st32(tmp, addr, user); break;
P
pbrook 已提交
8309
            default: goto illegal_op;
B
bellard 已提交
8310
            }
B
bellard 已提交
8311
        }
P
pbrook 已提交
8312
        if (postinc)
P
pbrook 已提交
8313 8314 8315 8316 8317 8318
            tcg_gen_addi_i32(addr, addr, imm);
        if (writeback) {
            store_reg(s, rn, addr);
        } else {
            dead_tmp(addr);
        }
P
pbrook 已提交
8319 8320 8321 8322
        }
        break;
    default:
        goto illegal_op;
B
bellard 已提交
8323
    }
P
pbrook 已提交
8324 8325 8326
    return 0;
illegal_op:
    return 1;
B
bellard 已提交
8327 8328
}

P
pbrook 已提交
8329
static void disas_thumb_insn(CPUState *env, DisasContext *s)
B
bellard 已提交
8330 8331 8332 8333
{
    uint32_t val, insn, op, rm, rn, rd, shift, cond;
    int32_t offset;
    int i;
P
pbrook 已提交
8334
    TCGv tmp;
P
pbrook 已提交
8335
    TCGv tmp2;
P
pbrook 已提交
8336
    TCGv addr;
B
bellard 已提交
8337

P
pbrook 已提交
8338 8339
    if (s->condexec_mask) {
        cond = s->condexec_cond;
8340 8341 8342 8343 8344
        if (cond != 0x0e) {     /* Skip conditional when condition is AL. */
          s->condlabel = gen_new_label();
          gen_test_cc(cond ^ 1, s->condlabel);
          s->condjmp = 1;
        }
P
pbrook 已提交
8345 8346
    }

B
bellard 已提交
8347
    insn = lduw_code(s->pc);
B
bellard 已提交
8348
    s->pc += 2;
B
bellard 已提交
8349

B
bellard 已提交
8350 8351
    switch (insn >> 12) {
    case 0: case 1:
8352

B
bellard 已提交
8353 8354 8355 8356 8357
        rd = insn & 7;
        op = (insn >> 11) & 3;
        if (op == 3) {
            /* add/subtract */
            rn = (insn >> 3) & 7;
8358
            tmp = load_reg(s, rn);
B
bellard 已提交
8359 8360
            if (insn & (1 << 10)) {
                /* immediate */
8361 8362
                tmp2 = new_tmp();
                tcg_gen_movi_i32(tmp2, (insn >> 6) & 7);
B
bellard 已提交
8363 8364 8365
            } else {
                /* reg */
                rm = (insn >> 6) & 7;
8366
                tmp2 = load_reg(s, rm);
B
bellard 已提交
8367
            }
P
pbrook 已提交
8368 8369
            if (insn & (1 << 9)) {
                if (s->condexec_mask)
8370
                    tcg_gen_sub_i32(tmp, tmp, tmp2);
P
pbrook 已提交
8371
                else
8372
                    gen_helper_sub_cc(tmp, tmp, tmp2);
P
pbrook 已提交
8373 8374
            } else {
                if (s->condexec_mask)
8375
                    tcg_gen_add_i32(tmp, tmp, tmp2);
P
pbrook 已提交
8376
                else
8377
                    gen_helper_add_cc(tmp, tmp, tmp2);
P
pbrook 已提交
8378
            }
8379 8380
            dead_tmp(tmp2);
            store_reg(s, rd, tmp);
B
bellard 已提交
8381 8382 8383 8384
        } else {
            /* shift immediate */
            rm = (insn >> 3) & 7;
            shift = (insn >> 6) & 0x1f;
P
pbrook 已提交
8385 8386 8387 8388 8389
            tmp = load_reg(s, rm);
            gen_arm_shift_im(tmp, op, shift, s->condexec_mask == 0);
            if (!s->condexec_mask)
                gen_logic_CC(tmp);
            store_reg(s, rd, tmp);
B
bellard 已提交
8390 8391 8392 8393 8394 8395
        }
        break;
    case 2: case 3:
        /* arithmetic large immediate */
        op = (insn >> 11) & 3;
        rd = (insn >> 8) & 0x7;
8396 8397 8398
        if (op == 0) { /* mov */
            tmp = new_tmp();
            tcg_gen_movi_i32(tmp, insn & 0xff);
P
pbrook 已提交
8399
            if (!s->condexec_mask)
8400 8401 8402 8403 8404 8405 8406 8407 8408 8409 8410 8411 8412 8413 8414 8415 8416 8417 8418 8419 8420 8421 8422 8423 8424 8425 8426 8427 8428
                gen_logic_CC(tmp);
            store_reg(s, rd, tmp);
        } else {
            tmp = load_reg(s, rd);
            tmp2 = new_tmp();
            tcg_gen_movi_i32(tmp2, insn & 0xff);
            switch (op) {
            case 1: /* cmp */
                gen_helper_sub_cc(tmp, tmp, tmp2);
                dead_tmp(tmp);
                dead_tmp(tmp2);
                break;
            case 2: /* add */
                if (s->condexec_mask)
                    tcg_gen_add_i32(tmp, tmp, tmp2);
                else
                    gen_helper_add_cc(tmp, tmp, tmp2);
                dead_tmp(tmp2);
                store_reg(s, rd, tmp);
                break;
            case 3: /* sub */
                if (s->condexec_mask)
                    tcg_gen_sub_i32(tmp, tmp, tmp2);
                else
                    gen_helper_sub_cc(tmp, tmp, tmp2);
                dead_tmp(tmp2);
                store_reg(s, rd, tmp);
                break;
            }
B
bellard 已提交
8429 8430 8431 8432 8433
        }
        break;
    case 4:
        if (insn & (1 << 11)) {
            rd = (insn >> 8) & 7;
B
bellard 已提交
8434 8435 8436
            /* load pc-relative.  Bit 1 of PC is ignored.  */
            val = s->pc + 2 + ((insn & 0xff) * 4);
            val &= ~(uint32_t)2;
P
pbrook 已提交
8437 8438 8439 8440 8441
            addr = new_tmp();
            tcg_gen_movi_i32(addr, val);
            tmp = gen_ld32(addr, IS_USER(s));
            dead_tmp(addr);
            store_reg(s, rd, tmp);
B
bellard 已提交
8442 8443 8444 8445 8446 8447 8448 8449 8450
            break;
        }
        if (insn & (1 << 10)) {
            /* data processing extended or blx */
            rd = (insn & 7) | ((insn >> 4) & 8);
            rm = (insn >> 3) & 0xf;
            op = (insn >> 8) & 3;
            switch (op) {
            case 0: /* add */
8451 8452 8453 8454 8455
                tmp = load_reg(s, rd);
                tmp2 = load_reg(s, rm);
                tcg_gen_add_i32(tmp, tmp, tmp2);
                dead_tmp(tmp2);
                store_reg(s, rd, tmp);
B
bellard 已提交
8456 8457
                break;
            case 1: /* cmp */
8458 8459 8460 8461 8462
                tmp = load_reg(s, rd);
                tmp2 = load_reg(s, rm);
                gen_helper_sub_cc(tmp, tmp, tmp2);
                dead_tmp(tmp2);
                dead_tmp(tmp);
B
bellard 已提交
8463 8464
                break;
            case 2: /* mov/cpy */
8465 8466
                tmp = load_reg(s, rm);
                store_reg(s, rd, tmp);
B
bellard 已提交
8467 8468
                break;
            case 3:/* branch [and link] exchange thumb register */
P
pbrook 已提交
8469
                tmp = load_reg(s, rm);
B
bellard 已提交
8470 8471
                if (insn & (1 << 7)) {
                    val = (uint32_t)s->pc | 1;
P
pbrook 已提交
8472 8473 8474
                    tmp2 = new_tmp();
                    tcg_gen_movi_i32(tmp2, val);
                    store_reg(s, 14, tmp2);
B
bellard 已提交
8475
                }
P
pbrook 已提交
8476
                gen_bx(s, tmp);
B
bellard 已提交
8477 8478 8479 8480 8481 8482 8483 8484 8485 8486 8487 8488 8489 8490 8491 8492 8493 8494 8495
                break;
            }
            break;
        }

        /* data processing register */
        rd = insn & 7;
        rm = (insn >> 3) & 7;
        op = (insn >> 6) & 0xf;
        if (op == 2 || op == 3 || op == 4 || op == 7) {
            /* the shift/rotate ops want the operands backwards */
            val = rm;
            rm = rd;
            rd = val;
            val = 1;
        } else {
            val = 0;
        }

8496 8497 8498 8499 8500 8501 8502 8503
        if (op == 9) { /* neg */
            tmp = new_tmp();
            tcg_gen_movi_i32(tmp, 0);
        } else if (op != 0xf) { /* mvn doesn't read its first operand */
            tmp = load_reg(s, rd);
        } else {
            TCGV_UNUSED(tmp);
        }
B
bellard 已提交
8504

8505
        tmp2 = load_reg(s, rm);
B
bellard 已提交
8506
        switch (op) {
B
bellard 已提交
8507
        case 0x0: /* and */
8508
            tcg_gen_and_i32(tmp, tmp, tmp2);
P
pbrook 已提交
8509
            if (!s->condexec_mask)
8510
                gen_logic_CC(tmp);
B
bellard 已提交
8511 8512
            break;
        case 0x1: /* eor */
8513
            tcg_gen_xor_i32(tmp, tmp, tmp2);
P
pbrook 已提交
8514
            if (!s->condexec_mask)
8515
                gen_logic_CC(tmp);
B
bellard 已提交
8516 8517
            break;
        case 0x2: /* lsl */
P
pbrook 已提交
8518
            if (s->condexec_mask) {
8519
                gen_helper_shl(tmp2, tmp2, tmp);
P
pbrook 已提交
8520
            } else {
8521 8522
                gen_helper_shl_cc(tmp2, tmp2, tmp);
                gen_logic_CC(tmp2);
P
pbrook 已提交
8523
            }
B
bellard 已提交
8524 8525
            break;
        case 0x3: /* lsr */
P
pbrook 已提交
8526
            if (s->condexec_mask) {
8527
                gen_helper_shr(tmp2, tmp2, tmp);
P
pbrook 已提交
8528
            } else {
8529 8530
                gen_helper_shr_cc(tmp2, tmp2, tmp);
                gen_logic_CC(tmp2);
P
pbrook 已提交
8531
            }
B
bellard 已提交
8532 8533
            break;
        case 0x4: /* asr */
P
pbrook 已提交
8534
            if (s->condexec_mask) {
8535
                gen_helper_sar(tmp2, tmp2, tmp);
P
pbrook 已提交
8536
            } else {
8537 8538
                gen_helper_sar_cc(tmp2, tmp2, tmp);
                gen_logic_CC(tmp2);
P
pbrook 已提交
8539
            }
B
bellard 已提交
8540 8541
            break;
        case 0x5: /* adc */
P
pbrook 已提交
8542
            if (s->condexec_mask)
8543
                gen_adc(tmp, tmp2);
P
pbrook 已提交
8544
            else
8545
                gen_helper_adc_cc(tmp, tmp, tmp2);
B
bellard 已提交
8546 8547
            break;
        case 0x6: /* sbc */
P
pbrook 已提交
8548
            if (s->condexec_mask)
8549
                gen_sub_carry(tmp, tmp, tmp2);
P
pbrook 已提交
8550
            else
8551
                gen_helper_sbc_cc(tmp, tmp, tmp2);
B
bellard 已提交
8552 8553
            break;
        case 0x7: /* ror */
P
pbrook 已提交
8554
            if (s->condexec_mask) {
8555 8556
                tcg_gen_andi_i32(tmp, tmp, 0x1f);
                tcg_gen_rotr_i32(tmp2, tmp2, tmp);
P
pbrook 已提交
8557
            } else {
8558 8559
                gen_helper_ror_cc(tmp2, tmp2, tmp);
                gen_logic_CC(tmp2);
P
pbrook 已提交
8560
            }
B
bellard 已提交
8561 8562
            break;
        case 0x8: /* tst */
8563 8564
            tcg_gen_and_i32(tmp, tmp, tmp2);
            gen_logic_CC(tmp);
B
bellard 已提交
8565
            rd = 16;
B
bellard 已提交
8566
            break;
B
bellard 已提交
8567
        case 0x9: /* neg */
P
pbrook 已提交
8568
            if (s->condexec_mask)
8569
                tcg_gen_neg_i32(tmp, tmp2);
P
pbrook 已提交
8570
            else
8571
                gen_helper_sub_cc(tmp, tmp, tmp2);
B
bellard 已提交
8572 8573
            break;
        case 0xa: /* cmp */
8574
            gen_helper_sub_cc(tmp, tmp, tmp2);
B
bellard 已提交
8575 8576 8577
            rd = 16;
            break;
        case 0xb: /* cmn */
8578
            gen_helper_add_cc(tmp, tmp, tmp2);
B
bellard 已提交
8579 8580 8581
            rd = 16;
            break;
        case 0xc: /* orr */
8582
            tcg_gen_or_i32(tmp, tmp, tmp2);
P
pbrook 已提交
8583
            if (!s->condexec_mask)
8584
                gen_logic_CC(tmp);
B
bellard 已提交
8585 8586
            break;
        case 0xd: /* mul */
8587
            tcg_gen_mul_i32(tmp, tmp, tmp2);
P
pbrook 已提交
8588
            if (!s->condexec_mask)
8589
                gen_logic_CC(tmp);
B
bellard 已提交
8590 8591
            break;
        case 0xe: /* bic */
8592
            tcg_gen_andc_i32(tmp, tmp, tmp2);
P
pbrook 已提交
8593
            if (!s->condexec_mask)
8594
                gen_logic_CC(tmp);
B
bellard 已提交
8595 8596
            break;
        case 0xf: /* mvn */
8597
            tcg_gen_not_i32(tmp2, tmp2);
P
pbrook 已提交
8598
            if (!s->condexec_mask)
8599
                gen_logic_CC(tmp2);
B
bellard 已提交
8600
            val = 1;
B
bellard 已提交
8601
            rm = rd;
B
bellard 已提交
8602 8603 8604
            break;
        }
        if (rd != 16) {
8605 8606 8607 8608 8609 8610 8611 8612 8613 8614 8615
            if (val) {
                store_reg(s, rm, tmp2);
                if (op != 0xf)
                    dead_tmp(tmp);
            } else {
                store_reg(s, rd, tmp);
                dead_tmp(tmp2);
            }
        } else {
            dead_tmp(tmp);
            dead_tmp(tmp2);
B
bellard 已提交
8616 8617 8618 8619 8620 8621 8622 8623 8624
        }
        break;

    case 5:
        /* load/store register offset.  */
        rd = insn & 7;
        rn = (insn >> 3) & 7;
        rm = (insn >> 6) & 7;
        op = (insn >> 9) & 7;
P
pbrook 已提交
8625
        addr = load_reg(s, rn);
P
pbrook 已提交
8626
        tmp = load_reg(s, rm);
P
pbrook 已提交
8627
        tcg_gen_add_i32(addr, addr, tmp);
P
pbrook 已提交
8628
        dead_tmp(tmp);
B
bellard 已提交
8629 8630

        if (op < 3) /* store */
P
pbrook 已提交
8631
            tmp = load_reg(s, rd);
B
bellard 已提交
8632 8633 8634

        switch (op) {
        case 0: /* str */
P
pbrook 已提交
8635
            gen_st32(tmp, addr, IS_USER(s));
B
bellard 已提交
8636 8637
            break;
        case 1: /* strh */
P
pbrook 已提交
8638
            gen_st16(tmp, addr, IS_USER(s));
B
bellard 已提交
8639 8640
            break;
        case 2: /* strb */
P
pbrook 已提交
8641
            gen_st8(tmp, addr, IS_USER(s));
B
bellard 已提交
8642 8643
            break;
        case 3: /* ldrsb */
P
pbrook 已提交
8644
            tmp = gen_ld8s(addr, IS_USER(s));
B
bellard 已提交
8645 8646
            break;
        case 4: /* ldr */
P
pbrook 已提交
8647
            tmp = gen_ld32(addr, IS_USER(s));
B
bellard 已提交
8648 8649
            break;
        case 5: /* ldrh */
P
pbrook 已提交
8650
            tmp = gen_ld16u(addr, IS_USER(s));
B
bellard 已提交
8651 8652
            break;
        case 6: /* ldrb */
P
pbrook 已提交
8653
            tmp = gen_ld8u(addr, IS_USER(s));
B
bellard 已提交
8654 8655
            break;
        case 7: /* ldrsh */
P
pbrook 已提交
8656
            tmp = gen_ld16s(addr, IS_USER(s));
B
bellard 已提交
8657 8658 8659
            break;
        }
        if (op >= 3) /* load */
P
pbrook 已提交
8660 8661
            store_reg(s, rd, tmp);
        dead_tmp(addr);
B
bellard 已提交
8662 8663 8664 8665 8666 8667
        break;

    case 6:
        /* load/store word immediate offset */
        rd = insn & 7;
        rn = (insn >> 3) & 7;
P
pbrook 已提交
8668
        addr = load_reg(s, rn);
B
bellard 已提交
8669
        val = (insn >> 4) & 0x7c;
P
pbrook 已提交
8670
        tcg_gen_addi_i32(addr, addr, val);
B
bellard 已提交
8671 8672 8673

        if (insn & (1 << 11)) {
            /* load */
P
pbrook 已提交
8674 8675
            tmp = gen_ld32(addr, IS_USER(s));
            store_reg(s, rd, tmp);
B
bellard 已提交
8676 8677
        } else {
            /* store */
P
pbrook 已提交
8678 8679
            tmp = load_reg(s, rd);
            gen_st32(tmp, addr, IS_USER(s));
B
bellard 已提交
8680
        }
P
pbrook 已提交
8681
        dead_tmp(addr);
B
bellard 已提交
8682 8683 8684 8685 8686 8687
        break;

    case 7:
        /* load/store byte immediate offset */
        rd = insn & 7;
        rn = (insn >> 3) & 7;
P
pbrook 已提交
8688
        addr = load_reg(s, rn);
B
bellard 已提交
8689
        val = (insn >> 6) & 0x1f;
P
pbrook 已提交
8690
        tcg_gen_addi_i32(addr, addr, val);
B
bellard 已提交
8691 8692 8693

        if (insn & (1 << 11)) {
            /* load */
P
pbrook 已提交
8694 8695
            tmp = gen_ld8u(addr, IS_USER(s));
            store_reg(s, rd, tmp);
B
bellard 已提交
8696 8697
        } else {
            /* store */
P
pbrook 已提交
8698 8699
            tmp = load_reg(s, rd);
            gen_st8(tmp, addr, IS_USER(s));
B
bellard 已提交
8700
        }
P
pbrook 已提交
8701
        dead_tmp(addr);
B
bellard 已提交
8702 8703 8704 8705 8706 8707
        break;

    case 8:
        /* load/store halfword immediate offset */
        rd = insn & 7;
        rn = (insn >> 3) & 7;
P
pbrook 已提交
8708
        addr = load_reg(s, rn);
B
bellard 已提交
8709
        val = (insn >> 5) & 0x3e;
P
pbrook 已提交
8710
        tcg_gen_addi_i32(addr, addr, val);
B
bellard 已提交
8711 8712 8713

        if (insn & (1 << 11)) {
            /* load */
P
pbrook 已提交
8714 8715
            tmp = gen_ld16u(addr, IS_USER(s));
            store_reg(s, rd, tmp);
B
bellard 已提交
8716 8717
        } else {
            /* store */
P
pbrook 已提交
8718 8719
            tmp = load_reg(s, rd);
            gen_st16(tmp, addr, IS_USER(s));
B
bellard 已提交
8720
        }
P
pbrook 已提交
8721
        dead_tmp(addr);
B
bellard 已提交
8722 8723 8724 8725 8726
        break;

    case 9:
        /* load/store from stack */
        rd = (insn >> 8) & 7;
P
pbrook 已提交
8727
        addr = load_reg(s, 13);
B
bellard 已提交
8728
        val = (insn & 0xff) * 4;
P
pbrook 已提交
8729
        tcg_gen_addi_i32(addr, addr, val);
B
bellard 已提交
8730 8731 8732

        if (insn & (1 << 11)) {
            /* load */
P
pbrook 已提交
8733 8734
            tmp = gen_ld32(addr, IS_USER(s));
            store_reg(s, rd, tmp);
B
bellard 已提交
8735 8736
        } else {
            /* store */
P
pbrook 已提交
8737 8738
            tmp = load_reg(s, rd);
            gen_st32(tmp, addr, IS_USER(s));
B
bellard 已提交
8739
        }
P
pbrook 已提交
8740
        dead_tmp(addr);
B
bellard 已提交
8741 8742 8743 8744 8745
        break;

    case 10:
        /* add to high reg */
        rd = (insn >> 8) & 7;
B
bellard 已提交
8746 8747
        if (insn & (1 << 11)) {
            /* SP */
P
pbrook 已提交
8748
            tmp = load_reg(s, 13);
B
bellard 已提交
8749 8750
        } else {
            /* PC. bit 1 is ignored.  */
P
pbrook 已提交
8751 8752
            tmp = new_tmp();
            tcg_gen_movi_i32(tmp, (s->pc + 2) & ~(uint32_t)2);
B
bellard 已提交
8753
        }
B
bellard 已提交
8754
        val = (insn & 0xff) * 4;
P
pbrook 已提交
8755 8756
        tcg_gen_addi_i32(tmp, tmp, val);
        store_reg(s, rd, tmp);
B
bellard 已提交
8757 8758 8759 8760 8761 8762 8763 8764
        break;

    case 11:
        /* misc */
        op = (insn >> 8) & 0xf;
        switch (op) {
        case 0:
            /* adjust stack pointer */
P
pbrook 已提交
8765
            tmp = load_reg(s, 13);
B
bellard 已提交
8766 8767
            val = (insn & 0x7f) * 4;
            if (insn & (1 << 7))
B
balrog 已提交
8768
                val = -(int32_t)val;
P
pbrook 已提交
8769 8770
            tcg_gen_addi_i32(tmp, tmp, val);
            store_reg(s, 13, tmp);
B
bellard 已提交
8771 8772
            break;

P
pbrook 已提交
8773 8774 8775 8776
        case 2: /* sign/zero extend.  */
            ARCH(6);
            rd = insn & 7;
            rm = (insn >> 3) & 7;
P
pbrook 已提交
8777
            tmp = load_reg(s, rm);
P
pbrook 已提交
8778
            switch ((insn >> 6) & 3) {
P
pbrook 已提交
8779 8780 8781 8782
            case 0: gen_sxth(tmp); break;
            case 1: gen_sxtb(tmp); break;
            case 2: gen_uxth(tmp); break;
            case 3: gen_uxtb(tmp); break;
P
pbrook 已提交
8783
            }
P
pbrook 已提交
8784
            store_reg(s, rd, tmp);
P
pbrook 已提交
8785
            break;
B
bellard 已提交
8786 8787
        case 4: case 5: case 0xc: case 0xd:
            /* push/pop */
P
pbrook 已提交
8788
            addr = load_reg(s, 13);
B
bellard 已提交
8789 8790
            if (insn & (1 << 8))
                offset = 4;
B
bellard 已提交
8791
            else
B
bellard 已提交
8792 8793 8794 8795 8796 8797
                offset = 0;
            for (i = 0; i < 8; i++) {
                if (insn & (1 << i))
                    offset += 4;
            }
            if ((insn & (1 << 11)) == 0) {
P
pbrook 已提交
8798
                tcg_gen_addi_i32(addr, addr, -offset);
B
bellard 已提交
8799
            }
B
bellard 已提交
8800 8801 8802 8803
            for (i = 0; i < 8; i++) {
                if (insn & (1 << i)) {
                    if (insn & (1 << 11)) {
                        /* pop */
P
pbrook 已提交
8804 8805
                        tmp = gen_ld32(addr, IS_USER(s));
                        store_reg(s, i, tmp);
B
bellard 已提交
8806 8807
                    } else {
                        /* push */
P
pbrook 已提交
8808 8809
                        tmp = load_reg(s, i);
                        gen_st32(tmp, addr, IS_USER(s));
B
bellard 已提交
8810
                    }
B
bellard 已提交
8811
                    /* advance to the next address.  */
P
pbrook 已提交
8812
                    tcg_gen_addi_i32(addr, addr, 4);
B
bellard 已提交
8813 8814
                }
            }
P
pbrook 已提交
8815
            TCGV_UNUSED(tmp);
B
bellard 已提交
8816 8817 8818
            if (insn & (1 << 8)) {
                if (insn & (1 << 11)) {
                    /* pop pc */
P
pbrook 已提交
8819
                    tmp = gen_ld32(addr, IS_USER(s));
B
bellard 已提交
8820 8821 8822 8823
                    /* don't set the pc until the rest of the instruction
                       has completed */
                } else {
                    /* push lr */
P
pbrook 已提交
8824 8825
                    tmp = load_reg(s, 14);
                    gen_st32(tmp, addr, IS_USER(s));
B
bellard 已提交
8826
                }
P
pbrook 已提交
8827
                tcg_gen_addi_i32(addr, addr, 4);
B
bellard 已提交
8828
            }
B
bellard 已提交
8829
            if ((insn & (1 << 11)) == 0) {
P
pbrook 已提交
8830
                tcg_gen_addi_i32(addr, addr, -offset);
B
bellard 已提交
8831
            }
B
bellard 已提交
8832
            /* write back the new stack pointer */
P
pbrook 已提交
8833
            store_reg(s, 13, addr);
B
bellard 已提交
8834 8835
            /* set the new PC value */
            if ((insn & 0x0900) == 0x0900)
P
pbrook 已提交
8836
                gen_bx(s, tmp);
B
bellard 已提交
8837 8838
            break;

P
pbrook 已提交
8839 8840
        case 1: case 3: case 9: case 11: /* czb */
            rm = insn & 7;
P
pbrook 已提交
8841
            tmp = load_reg(s, rm);
P
pbrook 已提交
8842 8843 8844
            s->condlabel = gen_new_label();
            s->condjmp = 1;
            if (insn & (1 << 11))
P
pbrook 已提交
8845
                tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, s->condlabel);
P
pbrook 已提交
8846
            else
P
pbrook 已提交
8847
                tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, s->condlabel);
P
pbrook 已提交
8848
            dead_tmp(tmp);
P
pbrook 已提交
8849 8850 8851 8852 8853 8854 8855 8856 8857 8858 8859 8860 8861 8862 8863 8864 8865
            offset = ((insn & 0xf8) >> 2) | (insn & 0x200) >> 3;
            val = (uint32_t)s->pc + 2;
            val += offset;
            gen_jmp(s, val);
            break;

        case 15: /* IT, nop-hint.  */
            if ((insn & 0xf) == 0) {
                gen_nop_hint(s, (insn >> 4) & 0xf);
                break;
            }
            /* If Then.  */
            s->condexec_cond = (insn >> 4) & 0xe;
            s->condexec_mask = insn & 0x1f;
            /* No actual code generated for this insn, just setup state.  */
            break;

P
pbrook 已提交
8866
        case 0xe: /* bkpt */
P
pbrook 已提交
8867
            gen_set_condexec(s);
P
pbrook 已提交
8868
            gen_set_pc_im(s->pc - 2);
P
pbrook 已提交
8869
            gen_exception(EXCP_BKPT);
P
pbrook 已提交
8870 8871 8872
            s->is_jmp = DISAS_JUMP;
            break;

P
pbrook 已提交
8873 8874 8875 8876
        case 0xa: /* rev */
            ARCH(6);
            rn = (insn >> 3) & 0x7;
            rd = insn & 0x7;
P
pbrook 已提交
8877
            tmp = load_reg(s, rn);
P
pbrook 已提交
8878
            switch ((insn >> 6) & 3) {
A
aurel32 已提交
8879
            case 0: tcg_gen_bswap32_i32(tmp, tmp); break;
P
pbrook 已提交
8880 8881
            case 1: gen_rev16(tmp); break;
            case 3: gen_revsh(tmp); break;
P
pbrook 已提交
8882 8883
            default: goto illegal_op;
            }
P
pbrook 已提交
8884
            store_reg(s, rd, tmp);
P
pbrook 已提交
8885 8886 8887 8888 8889 8890 8891
            break;

        case 6: /* cps */
            ARCH(6);
            if (IS_USER(s))
                break;
            if (IS_M(env)) {
P
pbrook 已提交
8892
                tmp = tcg_const_i32((insn & (1 << 4)) != 0);
P
pbrook 已提交
8893
                /* PRIMASK */
P
pbrook 已提交
8894 8895 8896
                if (insn & 1) {
                    addr = tcg_const_i32(16);
                    gen_helper_v7m_msr(cpu_env, addr, tmp);
8897
                    tcg_temp_free_i32(addr);
P
pbrook 已提交
8898
                }
P
pbrook 已提交
8899
                /* FAULTMASK */
P
pbrook 已提交
8900 8901 8902
                if (insn & 2) {
                    addr = tcg_const_i32(17);
                    gen_helper_v7m_msr(cpu_env, addr, tmp);
8903
                    tcg_temp_free_i32(addr);
P
pbrook 已提交
8904
                }
8905
                tcg_temp_free_i32(tmp);
P
pbrook 已提交
8906 8907 8908 8909 8910 8911
                gen_lookup_tb(s);
            } else {
                if (insn & (1 << 4))
                    shift = CPSR_A | CPSR_I | CPSR_F;
                else
                    shift = 0;
R
Rabin Vincent 已提交
8912
                gen_set_psr_im(s, ((insn & 7) << 6), 0, shift);
P
pbrook 已提交
8913 8914 8915
            }
            break;

B
bellard 已提交
8916 8917 8918 8919 8920 8921 8922 8923
        default:
            goto undef;
        }
        break;

    case 12:
        /* load/store multiple */
        rn = (insn >> 8) & 0x7;
P
pbrook 已提交
8924
        addr = load_reg(s, rn);
B
bellard 已提交
8925 8926 8927 8928
        for (i = 0; i < 8; i++) {
            if (insn & (1 << i)) {
                if (insn & (1 << 11)) {
                    /* load */
P
pbrook 已提交
8929 8930
                    tmp = gen_ld32(addr, IS_USER(s));
                    store_reg(s, i, tmp);
B
bellard 已提交
8931 8932
                } else {
                    /* store */
P
pbrook 已提交
8933 8934
                    tmp = load_reg(s, i);
                    gen_st32(tmp, addr, IS_USER(s));
B
bellard 已提交
8935
                }
B
bellard 已提交
8936
                /* advance to the next address */
P
pbrook 已提交
8937
                tcg_gen_addi_i32(addr, addr, 4);
B
bellard 已提交
8938 8939
            }
        }
B
bellard 已提交
8940
        /* Base register writeback.  */
P
pbrook 已提交
8941 8942 8943 8944 8945
        if ((insn & (1 << rn)) == 0) {
            store_reg(s, rn, addr);
        } else {
            dead_tmp(addr);
        }
B
bellard 已提交
8946 8947 8948 8949 8950 8951 8952 8953 8954 8955
        break;

    case 13:
        /* conditional branch or swi */
        cond = (insn >> 8) & 0xf;
        if (cond == 0xe)
            goto undef;

        if (cond == 0xf) {
            /* swi */
P
pbrook 已提交
8956
            gen_set_condexec(s);
8957
            gen_set_pc_im(s->pc);
P
pbrook 已提交
8958
            s->is_jmp = DISAS_SWI;
B
bellard 已提交
8959 8960 8961
            break;
        }
        /* generate a conditional jump to next instruction */
8962
        s->condlabel = gen_new_label();
P
pbrook 已提交
8963
        gen_test_cc(cond ^ 1, s->condlabel);
8964
        s->condjmp = 1;
B
bellard 已提交
8965 8966

        /* jump to the offset */
B
bellard 已提交
8967
        val = (uint32_t)s->pc + 2;
B
bellard 已提交
8968
        offset = ((int32_t)insn << 24) >> 24;
B
bellard 已提交
8969
        val += offset << 1;
B
bellard 已提交
8970
        gen_jmp(s, val);
B
bellard 已提交
8971 8972 8973
        break;

    case 14:
P
pbrook 已提交
8974
        if (insn & (1 << 11)) {
P
pbrook 已提交
8975 8976
            if (disas_thumb2_insn(env, s, insn))
              goto undef32;
P
pbrook 已提交
8977 8978
            break;
        }
P
pbrook 已提交
8979
        /* unconditional branch */
B
bellard 已提交
8980 8981 8982
        val = (uint32_t)s->pc;
        offset = ((int32_t)insn << 21) >> 21;
        val += (offset << 1) + 2;
B
bellard 已提交
8983
        gen_jmp(s, val);
B
bellard 已提交
8984 8985 8986
        break;

    case 15:
P
pbrook 已提交
8987
        if (disas_thumb2_insn(env, s, insn))
B
balrog 已提交
8988
            goto undef32;
P
pbrook 已提交
8989
        break;
B
bellard 已提交
8990 8991
    }
    return;
P
pbrook 已提交
8992 8993
undef32:
    gen_set_condexec(s);
P
pbrook 已提交
8994
    gen_set_pc_im(s->pc - 4);
P
pbrook 已提交
8995
    gen_exception(EXCP_UDEF);
P
pbrook 已提交
8996 8997 8998
    s->is_jmp = DISAS_JUMP;
    return;
illegal_op:
B
bellard 已提交
8999
undef:
P
pbrook 已提交
9000
    gen_set_condexec(s);
P
pbrook 已提交
9001
    gen_set_pc_im(s->pc - 2);
P
pbrook 已提交
9002
    gen_exception(EXCP_UDEF);
B
bellard 已提交
9003 9004 9005
    s->is_jmp = DISAS_JUMP;
}

B
bellard 已提交
9006 9007 9008
/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
   basic block 'tb'. If search_pc is TRUE, also generate PC
   information for each intermediate instruction. */
9009 9010 9011
static inline void gen_intermediate_code_internal(CPUState *env,
                                                  TranslationBlock *tb,
                                                  int search_pc)
B
bellard 已提交
9012 9013
{
    DisasContext dc1, *dc = &dc1;
9014
    CPUBreakpoint *bp;
B
bellard 已提交
9015 9016
    uint16_t *gen_opc_end;
    int j, lj;
B
bellard 已提交
9017
    target_ulong pc_start;
B
bellard 已提交
9018
    uint32_t next_page_start;
P
pbrook 已提交
9019 9020
    int num_insns;
    int max_insns;
9021

B
bellard 已提交
9022
    /* generate intermediate code */
P
pbrook 已提交
9023 9024
    num_temps = 0;

B
bellard 已提交
9025
    pc_start = tb->pc;
9026

B
bellard 已提交
9027 9028 9029 9030 9031 9032
    dc->tb = tb;

    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;

    dc->is_jmp = DISAS_NEXT;
    dc->pc = pc_start;
B
bellard 已提交
9033
    dc->singlestep_enabled = env->singlestep_enabled;
9034
    dc->condjmp = 0;
B
bellard 已提交
9035
    dc->thumb = env->thumb;
P
pbrook 已提交
9036 9037
    dc->condexec_mask = (env->condexec_bits & 0xf) << 1;
    dc->condexec_cond = env->condexec_bits >> 4;
B
bellard 已提交
9038
#if !defined(CONFIG_USER_ONLY)
P
pbrook 已提交
9039 9040 9041 9042 9043
    if (IS_M(env)) {
        dc->user = ((env->v7m.exception == 0) && (env->v7m.control & 1));
    } else {
        dc->user = (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_USR;
    }
B
bellard 已提交
9044
#endif
P
pbrook 已提交
9045 9046 9047 9048
    cpu_F0s = tcg_temp_new_i32();
    cpu_F1s = tcg_temp_new_i32();
    cpu_F0d = tcg_temp_new_i64();
    cpu_F1d = tcg_temp_new_i64();
P
pbrook 已提交
9049 9050
    cpu_V0 = cpu_F0d;
    cpu_V1 = cpu_F1d;
P
pbrook 已提交
9051
    /* FIXME: cpu_M0 can probably be the same as cpu_V0.  */
P
pbrook 已提交
9052
    cpu_M0 = tcg_temp_new_i64();
B
bellard 已提交
9053
    next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
B
bellard 已提交
9054
    lj = -1;
P
pbrook 已提交
9055 9056 9057 9058 9059 9060
    num_insns = 0;
    max_insns = tb->cflags & CF_COUNT_MASK;
    if (max_insns == 0)
        max_insns = CF_COUNT_MASK;

    gen_icount_start();
P
pbrook 已提交
9061 9062 9063
    /* Reset the conditional execution bits immediately. This avoids
       complications trying to do it at the end of the block.  */
    if (env->condexec_bits)
P
pbrook 已提交
9064 9065 9066
      {
        TCGv tmp = new_tmp();
        tcg_gen_movi_i32(tmp, 0);
P
pbrook 已提交
9067
        store_cpu_field(tmp, condexec_bits);
P
pbrook 已提交
9068
      }
B
bellard 已提交
9069
    do {
9070 9071 9072 9073 9074 9075 9076 9077 9078 9079
#ifdef CONFIG_USER_ONLY
        /* Intercept jump to the magic kernel page.  */
        if (dc->pc >= 0xffff0000) {
            /* We always get here via a jump, so know we are not in a
               conditional execution block.  */
            gen_exception(EXCP_KERNEL_TRAP);
            dc->is_jmp = DISAS_UPDATE;
            break;
        }
#else
P
pbrook 已提交
9080 9081 9082
        if (dc->pc >= 0xfffffff0 && IS_M(env)) {
            /* We always get here via a jump, so know we are not in a
               conditional execution block.  */
P
pbrook 已提交
9083
            gen_exception(EXCP_EXCEPTION_EXIT);
9084 9085
            dc->is_jmp = DISAS_UPDATE;
            break;
P
pbrook 已提交
9086 9087 9088
        }
#endif

B
Blue Swirl 已提交
9089 9090
        if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
            QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
9091
                if (bp->pc == dc->pc) {
P
pbrook 已提交
9092
                    gen_set_condexec(dc);
P
pbrook 已提交
9093
                    gen_set_pc_im(dc->pc);
P
pbrook 已提交
9094
                    gen_exception(EXCP_DEBUG);
B
bellard 已提交
9095
                    dc->is_jmp = DISAS_JUMP;
P
pbrook 已提交
9096 9097 9098 9099
                    /* Advance PC so that clearing the breakpoint will
                       invalidate this TB.  */
                    dc->pc += 2;
                    goto done_generating;
B
bellard 已提交
9100 9101 9102 9103
                    break;
                }
            }
        }
B
bellard 已提交
9104 9105 9106 9107 9108 9109 9110
        if (search_pc) {
            j = gen_opc_ptr - gen_opc_buf;
            if (lj < j) {
                lj++;
                while (lj < j)
                    gen_opc_instr_start[lj++] = 0;
            }
B
bellard 已提交
9111
            gen_opc_pc[lj] = dc->pc;
B
bellard 已提交
9112
            gen_opc_instr_start[lj] = 1;
P
pbrook 已提交
9113
            gen_opc_icount[lj] = num_insns;
B
bellard 已提交
9114
        }
9115

P
pbrook 已提交
9116 9117 9118
        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
            gen_io_start();

P
pbrook 已提交
9119 9120 9121 9122 9123 9124 9125 9126 9127 9128 9129 9130 9131
        if (env->thumb) {
            disas_thumb_insn(env, dc);
            if (dc->condexec_mask) {
                dc->condexec_cond = (dc->condexec_cond & 0xe)
                                   | ((dc->condexec_mask >> 4) & 1);
                dc->condexec_mask = (dc->condexec_mask << 1) & 0x1f;
                if (dc->condexec_mask == 0) {
                    dc->condexec_cond = 0;
                }
            }
        } else {
            disas_arm_insn(env, dc);
        }
P
pbrook 已提交
9132 9133 9134 9135
        if (num_temps) {
            fprintf(stderr, "Internal resource leak before %08x\n", dc->pc);
            num_temps = 0;
        }
9136 9137 9138 9139 9140

        if (dc->condjmp && !dc->is_jmp) {
            gen_set_label(dc->condlabel);
            dc->condjmp = 0;
        }
B
balrog 已提交
9141
        /* Translation stops when a conditional branch is encountered.
9142
         * Otherwise the subsequent code could get translated several times.
B
bellard 已提交
9143
         * Also stop translation when a page boundary is reached.  This
T
ths 已提交
9144
         * ensures prefetch aborts occur at the right place.  */
P
pbrook 已提交
9145
        num_insns ++;
B
bellard 已提交
9146 9147
    } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
             !env->singlestep_enabled &&
9148
             !singlestep &&
P
pbrook 已提交
9149 9150 9151 9152 9153 9154 9155 9156 9157 9158 9159
             dc->pc < next_page_start &&
             num_insns < max_insns);

    if (tb->cflags & CF_LAST_IO) {
        if (dc->condjmp) {
            /* FIXME:  This can theoretically happen with self-modifying
               code.  */
            cpu_abort(env, "IO on conditional branch instruction");
        }
        gen_io_end();
    }
P
pbrook 已提交
9160

B
bellard 已提交
9161
    /* At this stage dc->condjmp will only be set when the skipped
P
pbrook 已提交
9162 9163
       instruction was a conditional branch or trap, and the PC has
       already been written.  */
9164
    if (unlikely(env->singlestep_enabled)) {
B
bellard 已提交
9165
        /* Make sure the pc is updated, and raise a debug exception.  */
9166
        if (dc->condjmp) {
P
pbrook 已提交
9167 9168
            gen_set_condexec(dc);
            if (dc->is_jmp == DISAS_SWI) {
P
pbrook 已提交
9169
                gen_exception(EXCP_SWI);
P
pbrook 已提交
9170
            } else {
P
pbrook 已提交
9171
                gen_exception(EXCP_DEBUG);
P
pbrook 已提交
9172
            }
9173 9174 9175
            gen_set_label(dc->condlabel);
        }
        if (dc->condjmp || !dc->is_jmp) {
P
pbrook 已提交
9176
            gen_set_pc_im(dc->pc);
9177
            dc->condjmp = 0;
B
bellard 已提交
9178
        }
P
pbrook 已提交
9179 9180
        gen_set_condexec(dc);
        if (dc->is_jmp == DISAS_SWI && !dc->condjmp) {
P
pbrook 已提交
9181
            gen_exception(EXCP_SWI);
P
pbrook 已提交
9182 9183 9184
        } else {
            /* FIXME: Single stepping a WFI insn will not halt
               the CPU.  */
P
pbrook 已提交
9185
            gen_exception(EXCP_DEBUG);
P
pbrook 已提交
9186
        }
B
bellard 已提交
9187
    } else {
P
pbrook 已提交
9188 9189 9190 9191 9192 9193 9194 9195 9196
        /* While branches must always occur at the end of an IT block,
           there are a few other things that can cause us to terminate
           the TB in the middel of an IT block:
            - Exception generating instructions (bkpt, swi, undefined).
            - Page boundaries.
            - Hardware watchpoints.
           Hardware breakpoints have already been handled and skip this code.
         */
        gen_set_condexec(dc);
B
bellard 已提交
9197 9198
        switch(dc->is_jmp) {
        case DISAS_NEXT:
9199
            gen_goto_tb(dc, 1, dc->pc);
B
bellard 已提交
9200 9201 9202 9203 9204
            break;
        default:
        case DISAS_JUMP:
        case DISAS_UPDATE:
            /* indicate that the hash table must be used to find the next TB */
B
bellard 已提交
9205
            tcg_gen_exit_tb(0);
B
bellard 已提交
9206 9207 9208 9209
            break;
        case DISAS_TB_JUMP:
            /* nothing more to generate */
            break;
P
pbrook 已提交
9210
        case DISAS_WFI:
P
pbrook 已提交
9211
            gen_helper_wfi();
P
pbrook 已提交
9212 9213
            break;
        case DISAS_SWI:
P
pbrook 已提交
9214
            gen_exception(EXCP_SWI);
P
pbrook 已提交
9215
            break;
B
bellard 已提交
9216
        }
9217 9218
        if (dc->condjmp) {
            gen_set_label(dc->condlabel);
P
pbrook 已提交
9219
            gen_set_condexec(dc);
9220
            gen_goto_tb(dc, 1, dc->pc);
9221 9222
            dc->condjmp = 0;
        }
B
bellard 已提交
9223
    }
P
pbrook 已提交
9224

P
pbrook 已提交
9225
done_generating:
P
pbrook 已提交
9226
    gen_icount_end(tb, num_insns);
B
bellard 已提交
9227 9228 9229
    *gen_opc_ptr = INDEX_op_end;

#ifdef DEBUG_DISAS
9230
    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
9231 9232 9233 9234
        qemu_log("----------------\n");
        qemu_log("IN: %s\n", lookup_symbol(pc_start));
        log_target_disas(pc_start, dc->pc - pc_start, env->thumb);
        qemu_log("\n");
B
bellard 已提交
9235 9236
    }
#endif
B
bellard 已提交
9237 9238 9239 9240 9241 9242
    if (search_pc) {
        j = gen_opc_ptr - gen_opc_buf;
        lj++;
        while (lj <= j)
            gen_opc_instr_start[lj++] = 0;
    } else {
B
bellard 已提交
9243
        tb->size = dc->pc - pc_start;
P
pbrook 已提交
9244
        tb->icount = num_insns;
B
bellard 已提交
9245
    }
B
bellard 已提交
9246 9247
}

9248
void gen_intermediate_code(CPUState *env, TranslationBlock *tb)
B
bellard 已提交
9249
{
9250
    gen_intermediate_code_internal(env, tb, 0);
B
bellard 已提交
9251 9252
}

9253
void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
B
bellard 已提交
9254
{
9255
    gen_intermediate_code_internal(env, tb, 1);
B
bellard 已提交
9256 9257
}

B
bellard 已提交
9258 9259 9260 9261
static const char *cpu_mode_names[16] = {
  "usr", "fiq", "irq", "svc", "???", "???", "???", "abt",
  "???", "???", "???", "und", "???", "???", "???", "sys"
};
P
pbrook 已提交
9262

9263
void cpu_dump_state(CPUState *env, FILE *f,
B
bellard 已提交
9264 9265
                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
                    int flags)
B
bellard 已提交
9266 9267
{
    int i;
T
ths 已提交
9268
#if 0
B
bellard 已提交
9269
    union {
B
bellard 已提交
9270 9271 9272 9273
        uint32_t i;
        float s;
    } s0, s1;
    CPU_DoubleU d;
P
pbrook 已提交
9274 9275 9276 9277 9278 9279
    /* ??? This assumes float64 and double have the same layout.
       Oh well, it's only debug dumps.  */
    union {
        float64 f64;
        double d;
    } d0;
T
ths 已提交
9280
#endif
B
bellard 已提交
9281
    uint32_t psr;
B
bellard 已提交
9282 9283

    for(i=0;i<16;i++) {
B
bellard 已提交
9284
        cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
B
bellard 已提交
9285
        if ((i % 4) == 3)
B
bellard 已提交
9286
            cpu_fprintf(f, "\n");
B
bellard 已提交
9287
        else
B
bellard 已提交
9288
            cpu_fprintf(f, " ");
B
bellard 已提交
9289
    }
B
bellard 已提交
9290
    psr = cpsr_read(env);
9291 9292
    cpu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%d\n",
                psr,
B
bellard 已提交
9293 9294 9295 9296
                psr & (1 << 31) ? 'N' : '-',
                psr & (1 << 30) ? 'Z' : '-',
                psr & (1 << 29) ? 'C' : '-',
                psr & (1 << 28) ? 'V' : '-',
9297
                psr & CPSR_T ? 'T' : 'A',
B
bellard 已提交
9298
                cpu_mode_names[psr & 0xf], (psr & 0x10) ? 32 : 26);
B
bellard 已提交
9299

P
pbrook 已提交
9300
#if 0
B
bellard 已提交
9301
    for (i = 0; i < 16; i++) {
B
bellard 已提交
9302 9303 9304
        d.d = env->vfp.regs[i];
        s0.i = d.l.lower;
        s1.i = d.l.upper;
P
pbrook 已提交
9305 9306
        d0.f64 = d.d;
        cpu_fprintf(f, "s%02d=%08x(%8g) s%02d=%08x(%8g) d%02d=%08x%08x(%8g)\n",
B
bellard 已提交
9307
                    i * 2, (int)s0.i, s0.s,
P
pbrook 已提交
9308
                    i * 2 + 1, (int)s1.i, s1.s,
B
bellard 已提交
9309
                    i, (int)(uint32_t)d.l.upper, (int)(uint32_t)d.l.lower,
P
pbrook 已提交
9310
                    d0.d);
B
bellard 已提交
9311
    }
P
pbrook 已提交
9312
    cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.xregs[ARM_VFP_FPSCR]);
P
pbrook 已提交
9313
#endif
B
bellard 已提交
9314
}
B
bellard 已提交
9315

A
aurel32 已提交
9316 9317 9318 9319 9320
void gen_pc_load(CPUState *env, TranslationBlock *tb,
                unsigned long searched_pc, int pc_pos, void *puc)
{
    env->regs[15] = gen_opc_pc[pc_pos];
}