translate.c 300.0 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
pbrook 已提交
79

P
pbrook 已提交
80
/* FIXME:  These should be removed.  */
P
pbrook 已提交
81
static TCGv cpu_T[2];
P
pbrook 已提交
82 83
static TCGv cpu_F0s, cpu_F1s;
static TCGv_i64 cpu_F0d, cpu_F1d;
P
pbrook 已提交
84

P
pbrook 已提交
85 86 87
#define ICOUNT_TEMP cpu_T[0]
#include "gen-icount.h"

88 89 90 91
static const char *regnames[] =
    { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
      "r8", "r9", "r10", "r11", "r12", "r13", "r14", "pc" };

P
pbrook 已提交
92 93 94
/* initialize TCG globals.  */
void arm_translate_init(void)
{
95 96
    int i;

P
pbrook 已提交
97 98 99 100
    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");

    cpu_T[0] = tcg_global_reg_new_i32(TCG_AREG1, "T0");
    cpu_T[1] = tcg_global_reg_new_i32(TCG_AREG2, "T1");
P
pbrook 已提交
101

102 103 104 105 106 107
    for (i = 0; i < 16; i++) {
        cpu_R[i] = tcg_global_mem_new_i32(TCG_AREG0,
                                          offsetof(CPUState, regs[i]),
                                          regnames[i]);
    }

P
pbrook 已提交
108 109
#define GEN_HELPER 2
#include "helpers.h"
P
pbrook 已提交
110 111 112 113 114
}

static int num_temps;

/* Allocate a temporary variable.  */
P
pbrook 已提交
115
static TCGv_i32 new_tmp(void)
P
pbrook 已提交
116
{
117 118
    num_temps++;
    return tcg_temp_new_i32();
P
pbrook 已提交
119 120 121 122 123
}

/* Release a temporary variable.  */
static void dead_tmp(TCGv tmp)
{
124
    tcg_temp_free(tmp);
P
pbrook 已提交
125 126 127
    num_temps--;
}

P
pbrook 已提交
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
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 已提交
146 147 148 149 150 151 152 153 154 155 156 157
/* 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 {
158
        tcg_gen_mov_i32(var, cpu_R[reg]);
P
pbrook 已提交
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
    }
}

/* 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;
    }
178
    tcg_gen_mov_i32(cpu_R[reg], var);
P
pbrook 已提交
179 180 181 182 183 184 185 186 187 188 189 190 191 192
    dead_tmp(var);
}


/* Basic operations.  */
#define gen_op_movl_T0_T1() tcg_gen_mov_i32(cpu_T[0], cpu_T[1])
#define gen_op_movl_T0_im(im) tcg_gen_movi_i32(cpu_T[0], im)
#define gen_op_movl_T1_im(im) tcg_gen_movi_i32(cpu_T[1], im)

#define gen_op_addl_T1_im(im) tcg_gen_addi_i32(cpu_T[1], cpu_T[1], im)
#define gen_op_addl_T0_T1() tcg_gen_add_i32(cpu_T[0], cpu_T[0], cpu_T[1])
#define gen_op_subl_T0_T1() tcg_gen_sub_i32(cpu_T[0], cpu_T[0], cpu_T[1])
#define gen_op_rsbl_T0_T1() tcg_gen_sub_i32(cpu_T[0], cpu_T[1], cpu_T[0])

P
pbrook 已提交
193 194 195 196 197 198
#define gen_op_addl_T0_T1_cc() gen_helper_add_cc(cpu_T[0], cpu_T[0], cpu_T[1])
#define gen_op_adcl_T0_T1_cc() gen_helper_adc_cc(cpu_T[0], cpu_T[0], cpu_T[1])
#define gen_op_subl_T0_T1_cc() gen_helper_sub_cc(cpu_T[0], cpu_T[0], cpu_T[1])
#define gen_op_sbcl_T0_T1_cc() gen_helper_sbc_cc(cpu_T[0], cpu_T[0], cpu_T[1])
#define gen_op_rsbl_T0_T1_cc() gen_helper_sub_cc(cpu_T[0], cpu_T[1], cpu_T[0])

P
pbrook 已提交
199 200 201 202 203 204 205 206 207 208 209 210
#define gen_op_andl_T0_T1() tcg_gen_and_i32(cpu_T[0], cpu_T[0], cpu_T[1])
#define gen_op_xorl_T0_T1() tcg_gen_xor_i32(cpu_T[0], cpu_T[0], cpu_T[1])
#define gen_op_orl_T0_T1() tcg_gen_or_i32(cpu_T[0], cpu_T[0], cpu_T[1])
#define gen_op_notl_T0() tcg_gen_not_i32(cpu_T[0], cpu_T[0])
#define gen_op_notl_T1() tcg_gen_not_i32(cpu_T[1], cpu_T[1])
#define gen_op_logic_T0_cc() gen_logic_CC(cpu_T[0]);
#define gen_op_logic_T1_cc() gen_logic_CC(cpu_T[1]);

#define gen_op_shll_T1_im(im) tcg_gen_shli_i32(cpu_T[1], cpu_T[1], im)
#define gen_op_shrl_T1_im(im) tcg_gen_shri_i32(cpu_T[1], cpu_T[1], im)

/* Value extensions.  */
P
pbrook 已提交
211 212
#define gen_uxtb(var) tcg_gen_ext8u_i32(var, var)
#define gen_uxth(var) tcg_gen_ext16u_i32(var, var)
P
pbrook 已提交
213 214 215
#define gen_sxtb(var) tcg_gen_ext8s_i32(var, var)
#define gen_sxth(var) tcg_gen_ext16s_i32(var, var)

P
pbrook 已提交
216 217
#define gen_sxtb16(var) gen_helper_sxtb16(var, var)
#define gen_uxtb16(var) gen_helper_uxtb16(var, var)
P
pbrook 已提交
218 219

#define gen_op_mul_T0_T1() tcg_gen_mul_i32(cpu_T[0], cpu_T[0], cpu_T[1])
P
pbrook 已提交
220

P
pbrook 已提交
221 222 223 224 225 226 227 228 229 230 231 232
#define gen_set_cpsr(var, mask) gen_helper_cpsr_write(var, tcg_const_i32(mask))
/* 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 已提交
233 234 235 236
static void gen_smul_dual(TCGv a, TCGv b)
{
    TCGv tmp1 = new_tmp();
    TCGv tmp2 = new_tmp();
237 238
    tcg_gen_ext16s_i32(tmp1, a);
    tcg_gen_ext16s_i32(tmp2, b);
P
pbrook 已提交
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 289 290 291 292 293 294 295 296 297 298
    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 已提交
299 300
    tcg_gen_shli_i32(val, val, shift);
    tcg_gen_andi_i32(base, base, ~(mask << shift));
P
pbrook 已提交
301 302 303
    tcg_gen_or_i32(dest, base, val);
}

P
pbrook 已提交
304 305
/* Round the top 32 bits of a 64-bit value.  */
static void gen_roundqd(TCGv a, TCGv b)
P
pbrook 已提交
306
{
P
pbrook 已提交
307 308
    tcg_gen_shri_i32(a, a, 31);
    tcg_gen_add_i32(a, a, b);
P
pbrook 已提交
309 310
}

P
pbrook 已提交
311 312
/* FIXME: Most targets have native widening multiplication.
   It would be good to use that instead of a full wide multiply.  */
P
pbrook 已提交
313
/* 32x32->64 multiply.  Marks inputs as dead.  */
P
pbrook 已提交
314
static TCGv_i64 gen_mulu_i64_i32(TCGv a, TCGv b)
P
pbrook 已提交
315
{
P
pbrook 已提交
316 317
    TCGv_i64 tmp1 = tcg_temp_new_i64();
    TCGv_i64 tmp2 = tcg_temp_new_i64();
P
pbrook 已提交
318 319 320 321 322 323 324 325 326

    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);
    return tmp1;
}

P
pbrook 已提交
327
static TCGv_i64 gen_muls_i64_i32(TCGv a, TCGv b)
P
pbrook 已提交
328
{
P
pbrook 已提交
329 330
    TCGv_i64 tmp1 = tcg_temp_new_i64();
    TCGv_i64 tmp2 = tcg_temp_new_i64();
P
pbrook 已提交
331 332 333 334 335 336 337 338 339

    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);
    return tmp1;
}

P
pbrook 已提交
340 341 342
/* Unsigned 32x32->64 multiply.  */
static void gen_op_mull_T0_T1(void)
{
P
pbrook 已提交
343 344
    TCGv_i64 tmp1 = tcg_temp_new_i64();
    TCGv_i64 tmp2 = tcg_temp_new_i64();
P
pbrook 已提交
345 346 347 348 349 350 351 352 353 354

    tcg_gen_extu_i32_i64(tmp1, cpu_T[0]);
    tcg_gen_extu_i32_i64(tmp2, cpu_T[1]);
    tcg_gen_mul_i64(tmp1, tmp1, tmp2);
    tcg_gen_trunc_i64_i32(cpu_T[0], tmp1);
    tcg_gen_shri_i64(tmp1, tmp1, 32);
    tcg_gen_trunc_i64_i32(cpu_T[1], tmp1);
}

/* Signed 32x32->64 multiply.  */
P
pbrook 已提交
355
static void gen_imull(TCGv a, TCGv b)
P
pbrook 已提交
356
{
P
pbrook 已提交
357 358
    TCGv_i64 tmp1 = tcg_temp_new_i64();
    TCGv_i64 tmp2 = tcg_temp_new_i64();
P
pbrook 已提交
359

P
pbrook 已提交
360 361
    tcg_gen_ext_i32_i64(tmp1, a);
    tcg_gen_ext_i32_i64(tmp2, b);
P
pbrook 已提交
362
    tcg_gen_mul_i64(tmp1, tmp1, tmp2);
P
pbrook 已提交
363
    tcg_gen_trunc_i64_i32(a, tmp1);
P
pbrook 已提交
364
    tcg_gen_shri_i64(tmp1, tmp1, 32);
P
pbrook 已提交
365 366 367
    tcg_gen_trunc_i64_i32(b, tmp1);
}

P
pbrook 已提交
368 369 370 371 372 373 374
/* 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 已提交
375
    dead_tmp(tmp);
P
pbrook 已提交
376 377
}

P
pbrook 已提交
378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
/* 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 已提交
398 399
#define gen_set_CF(var) tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, CF))

P
pbrook 已提交
400 401 402 403 404
/* 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);
405
    gen_set_CF(tmp);
P
pbrook 已提交
406 407 408 409 410 411
    dead_tmp(tmp);
}

/* Set N and Z flags from var.  */
static inline void gen_logic_CC(TCGv var)
{
P
pbrook 已提交
412 413
    tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, NF));
    tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, ZF));
P
pbrook 已提交
414 415 416 417 418
}

/* T0 += T1 + CF.  */
static void gen_adc_T0_T1(void)
{
P
pbrook 已提交
419
    TCGv tmp;
P
pbrook 已提交
420
    gen_op_addl_T0_T1();
P
pbrook 已提交
421
    tmp = load_cpu_field(CF);
P
pbrook 已提交
422 423 424 425
    tcg_gen_add_i32(cpu_T[0], cpu_T[0], tmp);
    dead_tmp(tmp);
}

426 427 428 429 430 431 432 433 434 435
/* 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 已提交
436 437 438
/* dest = T0 - T1 + CF - 1.  */
static void gen_sub_carry(TCGv dest, TCGv t0, TCGv t1)
{
P
pbrook 已提交
439
    TCGv tmp;
P
pbrook 已提交
440
    tcg_gen_sub_i32(dest, t0, t1);
P
pbrook 已提交
441
    tmp = load_cpu_field(CF);
P
pbrook 已提交
442 443 444 445 446 447 448 449
    tcg_gen_add_i32(dest, dest, tmp);
    tcg_gen_subi_i32(dest, dest, 1);
    dead_tmp(tmp);
}

#define gen_sbc_T0_T1() gen_sub_carry(cpu_T[0], cpu_T[0], cpu_T[1])
#define gen_rsc_T0_T1() gen_sub_carry(cpu_T[0], cpu_T[1], cpu_T[0])

P
pbrook 已提交
450 451
/* T0 &= ~T1.  Clobbers T1.  */
/* FIXME: Implement bic natively.  */
P
pbrook 已提交
452 453 454 455 456 457 458
static inline void tcg_gen_bic_i32(TCGv dest, TCGv t0, TCGv t1)
{
    TCGv tmp = new_tmp();
    tcg_gen_not_i32(tmp, t1);
    tcg_gen_and_i32(dest, t0, tmp);
    dead_tmp(tmp);
}
P
pbrook 已提交
459 460 461 462 463 464
static inline void gen_op_bicl_T0_T1(void)
{
    gen_op_notl_T1();
    gen_op_andl_T0_T1();
}

P
pbrook 已提交
465 466 467
/* FIXME:  Implement this natively.  */
#define tcg_gen_abs_i32(t0, t1) gen_helper_abs(t0, t1)

P
pbrook 已提交
468 469 470 471 472 473 474 475 476 477 478 479 480 481 482
/* FIXME:  Implement this natively.  */
static void tcg_gen_rori_i32(TCGv t0, TCGv t1, int i)
{
    TCGv tmp;

    if (i == 0)
        return;

    tmp = new_tmp();
    tcg_gen_shri_i32(tmp, t1, i);
    tcg_gen_shli_i32(t1, t1, 32 - i);
    tcg_gen_or_i32(t0, t1, tmp);
    dead_tmp(tmp);
}

P
pbrook 已提交
483
static void shifter_out_im(TCGv var, int shift)
P
pbrook 已提交
484
{
P
pbrook 已提交
485 486 487
    TCGv tmp = new_tmp();
    if (shift == 0) {
        tcg_gen_andi_i32(tmp, var, 1);
P
pbrook 已提交
488
    } else {
P
pbrook 已提交
489
        tcg_gen_shri_i32(tmp, var, shift);
490
        if (shift != 31)
P
pbrook 已提交
491 492 493 494 495
            tcg_gen_andi_i32(tmp, tmp, 1);
    }
    gen_set_CF(tmp);
    dead_tmp(tmp);
}
P
pbrook 已提交
496

P
pbrook 已提交
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535
/* 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);
            tcg_gen_rori_i32(var, var, shift); break;
        } else {
P
pbrook 已提交
536
            TCGv tmp = load_cpu_field(CF);
P
pbrook 已提交
537 538 539
            if (flags)
                shifter_out_im(var, 0);
            tcg_gen_shri_i32(var, var, 1);
P
pbrook 已提交
540 541 542 543 544 545 546
            tcg_gen_shli_i32(tmp, tmp, 31);
            tcg_gen_or_i32(var, var, tmp);
            dead_tmp(tmp);
        }
    }
};

P
pbrook 已提交
547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567
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;
        case 3: gen_helper_ror(var, var, shift); break;
        }
    }
    dead_tmp(shift);
}

P
pbrook 已提交
568 569 570 571 572 573 574 575 576
#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 已提交
577
static void gen_arm_parallel_addsub(int op1, int op2, TCGv a, TCGv b)
P
pbrook 已提交
578
{
P
pbrook 已提交
579
    TCGv_ptr tmp;
P
pbrook 已提交
580 581 582 583

    switch (op1) {
#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp)
    case 1:
P
pbrook 已提交
584
        tmp = tcg_temp_new_ptr();
P
pbrook 已提交
585 586 587 588
        tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
        PAS_OP(s)
        break;
    case 5:
P
pbrook 已提交
589
        tmp = tcg_temp_new_ptr();
P
pbrook 已提交
590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609
        tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
        PAS_OP(u)
        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 已提交
610 611
#undef PAS_OP

P
pbrook 已提交
612 613 614 615 616 617 618 619 620 621
/* 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 已提交
622
static void gen_thumb2_parallel_addsub(int op1, int op2, TCGv a, TCGv b)
P
pbrook 已提交
623
{
P
pbrook 已提交
624
    TCGv_ptr tmp;
P
pbrook 已提交
625 626 627 628

    switch (op1) {
#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp)
    case 0:
P
pbrook 已提交
629
        tmp = tcg_temp_new_ptr();
P
pbrook 已提交
630 631 632 633
        tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
        PAS_OP(s)
        break;
    case 4:
P
pbrook 已提交
634
        tmp = tcg_temp_new_ptr();
P
pbrook 已提交
635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654
        tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
        PAS_OP(u)
        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 已提交
655 656
#undef PAS_OP

P
pbrook 已提交
657 658 659 660 661 662 663 664
static void gen_test_cc(int cc, int label)
{
    TCGv tmp;
    TCGv tmp2;
    int inv;

    switch (cc) {
    case 0: /* eq: Z */
P
pbrook 已提交
665
        tmp = load_cpu_field(ZF);
P
pbrook 已提交
666
        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
P
pbrook 已提交
667 668
        break;
    case 1: /* ne: !Z */
P
pbrook 已提交
669
        tmp = load_cpu_field(ZF);
P
pbrook 已提交
670
        tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label);
P
pbrook 已提交
671 672 673
        break;
    case 2: /* cs: C */
        tmp = load_cpu_field(CF);
P
pbrook 已提交
674
        tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label);
P
pbrook 已提交
675 676 677
        break;
    case 3: /* cc: !C */
        tmp = load_cpu_field(CF);
P
pbrook 已提交
678
        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
P
pbrook 已提交
679 680
        break;
    case 4: /* mi: N */
P
pbrook 已提交
681
        tmp = load_cpu_field(NF);
P
pbrook 已提交
682
        tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
P
pbrook 已提交
683 684
        break;
    case 5: /* pl: !N */
P
pbrook 已提交
685
        tmp = load_cpu_field(NF);
P
pbrook 已提交
686
        tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
P
pbrook 已提交
687 688 689
        break;
    case 6: /* vs: V */
        tmp = load_cpu_field(VF);
P
pbrook 已提交
690
        tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
P
pbrook 已提交
691 692 693
        break;
    case 7: /* vc: !V */
        tmp = load_cpu_field(VF);
P
pbrook 已提交
694
        tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
P
pbrook 已提交
695 696 697 698
        break;
    case 8: /* hi: C && !Z */
        inv = gen_new_label();
        tmp = load_cpu_field(CF);
P
pbrook 已提交
699
        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv);
P
pbrook 已提交
700
        dead_tmp(tmp);
P
pbrook 已提交
701
        tmp = load_cpu_field(ZF);
P
pbrook 已提交
702
        tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, label);
P
pbrook 已提交
703 704 705 706
        gen_set_label(inv);
        break;
    case 9: /* ls: !C || Z */
        tmp = load_cpu_field(CF);
P
pbrook 已提交
707
        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
P
pbrook 已提交
708
        dead_tmp(tmp);
P
pbrook 已提交
709
        tmp = load_cpu_field(ZF);
P
pbrook 已提交
710
        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
P
pbrook 已提交
711 712 713
        break;
    case 10: /* ge: N == V -> N ^ V == 0 */
        tmp = load_cpu_field(VF);
P
pbrook 已提交
714
        tmp2 = load_cpu_field(NF);
P
pbrook 已提交
715 716
        tcg_gen_xor_i32(tmp, tmp, tmp2);
        dead_tmp(tmp2);
P
pbrook 已提交
717
        tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
P
pbrook 已提交
718 719 720
        break;
    case 11: /* lt: N != V -> N ^ V != 0 */
        tmp = load_cpu_field(VF);
P
pbrook 已提交
721
        tmp2 = load_cpu_field(NF);
P
pbrook 已提交
722 723
        tcg_gen_xor_i32(tmp, tmp, tmp2);
        dead_tmp(tmp2);
P
pbrook 已提交
724
        tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
P
pbrook 已提交
725 726 727
        break;
    case 12: /* gt: !Z && N == V */
        inv = gen_new_label();
P
pbrook 已提交
728
        tmp = load_cpu_field(ZF);
P
pbrook 已提交
729
        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, inv);
P
pbrook 已提交
730 731
        dead_tmp(tmp);
        tmp = load_cpu_field(VF);
P
pbrook 已提交
732
        tmp2 = load_cpu_field(NF);
P
pbrook 已提交
733 734
        tcg_gen_xor_i32(tmp, tmp, tmp2);
        dead_tmp(tmp2);
P
pbrook 已提交
735
        tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
P
pbrook 已提交
736 737 738
        gen_set_label(inv);
        break;
    case 13: /* le: Z || N != V */
P
pbrook 已提交
739
        tmp = load_cpu_field(ZF);
P
pbrook 已提交
740
        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label);
P
pbrook 已提交
741 742
        dead_tmp(tmp);
        tmp = load_cpu_field(VF);
P
pbrook 已提交
743
        tmp2 = load_cpu_field(NF);
P
pbrook 已提交
744 745
        tcg_gen_xor_i32(tmp, tmp, tmp2);
        dead_tmp(tmp2);
P
pbrook 已提交
746
        tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
P
pbrook 已提交
747 748 749 750 751 752 753
        break;
    default:
        fprintf(stderr, "Bad condition code 0x%x\n", cc);
        abort();
    }
    dead_tmp(tmp);
}
B
bellard 已提交
754

755
static const uint8_t table_logic_cc[16] = {
B
bellard 已提交
756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772
    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 */
};
773

P
pbrook 已提交
774 775
/* Set PC and Thumb state from an immediate address.  */
static inline void gen_bx_im(DisasContext *s, uint32_t addr)
B
bellard 已提交
776
{
P
pbrook 已提交
777
    TCGv tmp;
B
bellard 已提交
778

P
pbrook 已提交
779
    s->is_jmp = DISAS_UPDATE;
P
pbrook 已提交
780
    if (s->thumb != (addr & 1)) {
781
        tmp = new_tmp();
P
pbrook 已提交
782 783
        tcg_gen_movi_i32(tmp, addr & 1);
        tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, thumb));
784
        dead_tmp(tmp);
P
pbrook 已提交
785
    }
786
    tcg_gen_movi_i32(cpu_R[15], addr & ~1);
P
pbrook 已提交
787 788 789 790 791 792
}

/* 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;
793 794 795
    tcg_gen_andi_i32(cpu_R[15], var, ~1);
    tcg_gen_andi_i32(var, var, 1);
    store_cpu_field(var, thumb);
P
pbrook 已提交
796 797
}

798 799 800 801 802 803 804 805 806 807 808 809 810
/* 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 已提交
811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855
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;
}
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);
}
B
bellard 已提交
856

B
bellard 已提交
857 858
static inline void gen_movl_T0_reg(DisasContext *s, int reg)
{
P
pbrook 已提交
859
    load_reg_var(s, cpu_T[0], reg);
B
bellard 已提交
860 861 862 863
}

static inline void gen_movl_T1_reg(DisasContext *s, int reg)
{
P
pbrook 已提交
864
    load_reg_var(s, cpu_T[1], reg);
B
bellard 已提交
865 866
}

P
pbrook 已提交
867 868
static inline void gen_set_pc_im(uint32_t val)
{
869
    tcg_gen_movi_i32(cpu_R[15], val);
P
pbrook 已提交
870 871
}

B
bellard 已提交
872 873
static inline void gen_movl_reg_TN(DisasContext *s, int reg, int t)
{
P
pbrook 已提交
874 875 876 877 878 879 880
    TCGv tmp;
    if (reg == 15) {
        tmp = new_tmp();
        tcg_gen_andi_i32(tmp, cpu_T[t], ~1);
    } else {
        tmp = cpu_T[t];
    }
881
    tcg_gen_mov_i32(cpu_R[reg], tmp);
B
bellard 已提交
882
    if (reg == 15) {
P
pbrook 已提交
883
        dead_tmp(tmp);
B
bellard 已提交
884 885 886 887 888 889 890 891 892 893 894 895 896 897
        s->is_jmp = DISAS_JUMP;
    }
}

static inline void gen_movl_reg_T0(DisasContext *s, int reg)
{
    gen_movl_reg_TN(s, reg, 0);
}

static inline void gen_movl_reg_T1(DisasContext *s, int reg)
{
    gen_movl_reg_TN(s, reg, 1);
}

B
bellard 已提交
898 899 900 901 902 903 904 905
/* Force a TB lookup after an instruction that changes the CPU state.  */
static inline void gen_lookup_tb(DisasContext *s)
{
    gen_op_movl_T0_im(s->pc);
    gen_movl_reg_T0(s, 15);
    s->is_jmp = DISAS_UPDATE;
}

P
pbrook 已提交
906 907
static inline void gen_add_data_offset(DisasContext *s, unsigned int insn,
                                       TCGv var)
B
bellard 已提交
908
{
B
bellard 已提交
909
    int val, rm, shift, shiftop;
P
pbrook 已提交
910
    TCGv offset;
B
bellard 已提交
911 912 913 914 915 916

    if (!(insn & (1 << 25))) {
        /* immediate */
        val = insn & 0xfff;
        if (!(insn & (1 << 23)))
            val = -val;
B
bellard 已提交
917
        if (val != 0)
P
pbrook 已提交
918
            tcg_gen_addi_i32(var, var, val);
B
bellard 已提交
919 920 921 922
    } else {
        /* shift/register */
        rm = (insn) & 0xf;
        shift = (insn >> 7) & 0x1f;
B
bellard 已提交
923
        shiftop = (insn >> 5) & 3;
P
pbrook 已提交
924
        offset = load_reg(s, rm);
P
pbrook 已提交
925
        gen_arm_shift_im(offset, shiftop, shift, 0);
B
bellard 已提交
926
        if (!(insn & (1 << 23)))
P
pbrook 已提交
927
            tcg_gen_sub_i32(var, var, offset);
B
bellard 已提交
928
        else
P
pbrook 已提交
929
            tcg_gen_add_i32(var, var, offset);
P
pbrook 已提交
930
        dead_tmp(offset);
B
bellard 已提交
931 932 933
    }
}

P
pbrook 已提交
934
static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn,
P
pbrook 已提交
935
                                        int extra, TCGv var)
B
bellard 已提交
936 937
{
    int val, rm;
P
pbrook 已提交
938
    TCGv offset;
939

B
bellard 已提交
940 941 942 943 944
    if (insn & (1 << 22)) {
        /* immediate */
        val = (insn & 0xf) | ((insn >> 4) & 0xf0);
        if (!(insn & (1 << 23)))
            val = -val;
945
        val += extra;
B
bellard 已提交
946
        if (val != 0)
P
pbrook 已提交
947
            tcg_gen_addi_i32(var, var, val);
B
bellard 已提交
948 949
    } else {
        /* register */
P
pbrook 已提交
950
        if (extra)
P
pbrook 已提交
951
            tcg_gen_addi_i32(var, var, extra);
B
bellard 已提交
952
        rm = (insn) & 0xf;
P
pbrook 已提交
953
        offset = load_reg(s, rm);
B
bellard 已提交
954
        if (!(insn & (1 << 23)))
P
pbrook 已提交
955
            tcg_gen_sub_i32(var, var, offset);
B
bellard 已提交
956
        else
P
pbrook 已提交
957
            tcg_gen_add_i32(var, var, offset);
P
pbrook 已提交
958
        dead_tmp(offset);
B
bellard 已提交
959 960 961
    }
}

P
pbrook 已提交
962 963 964 965 966 967 968
#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 已提交
969 970
}

P
pbrook 已提交
971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020
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 已提交
1021
        tcg_gen_movi_i64(cpu_F1d, 0);
P
pbrook 已提交
1022
    else
B
balrog 已提交
1023
        tcg_gen_movi_i32(cpu_F1s, 0);
P
pbrook 已提交
1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036
}

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)
1037
        gen_helper_vfp_sitod(cpu_F0d, cpu_F0s, cpu_env);
P
pbrook 已提交
1038
    else
1039
        gen_helper_vfp_sitos(cpu_F0s, cpu_F0s, cpu_env);
P
pbrook 已提交
1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066
}

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 已提交
1067 1068
{
    if (dp)
P
pbrook 已提交
1069
        gen_helper_vfp_tosizd(cpu_F0s, cpu_F0d, cpu_env);
P
pbrook 已提交
1070
    else
P
pbrook 已提交
1071 1072 1073 1074 1075 1076 1077 1078 1079 1080
        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) \
{ \
    if (dp) \
        gen_helper_vfp_##name##d(cpu_F0d, cpu_F0d, tcg_const_i32(shift), cpu_env);\
    else \
        gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, tcg_const_i32(shift), cpu_env);\
P
pbrook 已提交
1081
}
P
pbrook 已提交
1082 1083 1084 1085 1086 1087 1088 1089 1090
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 已提交
1091

B
bellard 已提交
1092 1093 1094
static inline void gen_vfp_ld(DisasContext *s, int dp)
{
    if (dp)
P
pbrook 已提交
1095
        tcg_gen_qemu_ld64(cpu_F0d, cpu_T[1], IS_USER(s));
B
bellard 已提交
1096
    else
P
pbrook 已提交
1097
        tcg_gen_qemu_ld32u(cpu_F0s, cpu_T[1], IS_USER(s));
B
bellard 已提交
1098 1099 1100 1101 1102
}

static inline void gen_vfp_st(DisasContext *s, int dp)
{
    if (dp)
P
pbrook 已提交
1103
        tcg_gen_qemu_st64(cpu_F0d, cpu_T[1], IS_USER(s));
B
bellard 已提交
1104
    else
P
pbrook 已提交
1105
        tcg_gen_qemu_st32(cpu_F0s, cpu_T[1], IS_USER(s));
B
bellard 已提交
1106 1107
}

B
bellard 已提交
1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120
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 已提交
1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131

/* 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 已提交
1132 1133 1134 1135 1136 1137 1138
/* FIXME: Remove these.  */
#define neon_T0 cpu_T[0]
#define neon_T1 cpu_T[1]
#define NEON_GET_REG(T, reg, n) \
  tcg_gen_ld_i32(neon_##T, cpu_env, neon_reg_offset(reg, n))
#define NEON_SET_REG(T, reg, n) \
  tcg_gen_st_i32(neon_##T, cpu_env, neon_reg_offset(reg, n))
P
pbrook 已提交
1139

P
pbrook 已提交
1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152
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 已提交
1153
static inline void neon_load_reg64(TCGv_i64 var, int reg)
P
pbrook 已提交
1154 1155 1156 1157
{
    tcg_gen_ld_i64(var, cpu_env, vfp_reg_offset(1, reg));
}

P
pbrook 已提交
1158
static inline void neon_store_reg64(TCGv_i64 var, int reg)
P
pbrook 已提交
1159 1160 1161 1162
{
    tcg_gen_st_i64(var, cpu_env, vfp_reg_offset(1, reg));
}

P
pbrook 已提交
1163 1164 1165 1166 1167
#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 已提交
1168 1169 1170
static inline void gen_mov_F0_vreg(int dp, int reg)
{
    if (dp)
P
pbrook 已提交
1171
        tcg_gen_ld_f64(cpu_F0d, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1172
    else
P
pbrook 已提交
1173
        tcg_gen_ld_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1174 1175 1176 1177 1178
}

static inline void gen_mov_F1_vreg(int dp, int reg)
{
    if (dp)
P
pbrook 已提交
1179
        tcg_gen_ld_f64(cpu_F1d, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1180
    else
P
pbrook 已提交
1181
        tcg_gen_ld_f32(cpu_F1s, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1182 1183 1184 1185 1186
}

static inline void gen_mov_vreg_F0(int dp, int reg)
{
    if (dp)
P
pbrook 已提交
1187
        tcg_gen_st_f64(cpu_F0d, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1188
    else
P
pbrook 已提交
1189
        tcg_gen_st_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1190 1191
}

1192 1193
#define ARM_CP_RW_BIT	(1 << 20)

P
pbrook 已提交
1194
static inline void iwmmxt_load_reg(TCGv_i64 var, int reg)
P
pbrook 已提交
1195 1196 1197 1198
{
    tcg_gen_ld_i64(var, cpu_env, offsetof(CPUState, iwmmxt.regs[reg]));
}

P
pbrook 已提交
1199
static inline void iwmmxt_store_reg(TCGv_i64 var, int reg)
P
pbrook 已提交
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 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403
{
    tcg_gen_st_i64(var, cpu_env, offsetof(CPUState, iwmmxt.regs[reg]));
}

static inline void gen_op_iwmmxt_movl_wCx_T0(int reg)
{
    tcg_gen_st_i32(cpu_T[0], cpu_env, offsetof(CPUState, iwmmxt.cregs[reg]));
}

static inline void gen_op_iwmmxt_movl_T0_wCx(int reg)
{
    tcg_gen_ld_i32(cpu_T[0], cpu_env, offsetof(CPUState, iwmmxt.cregs[reg]));
}

static inline void gen_op_iwmmxt_movl_T1_wCx(int reg)
{
    tcg_gen_ld_i32(cpu_T[1], cpu_env, offsetof(CPUState, iwmmxt.cregs[reg]));
}

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 inline void gen_op_iwmmxt_muladdsl_M0_T0_T1(void)
{
    gen_helper_iwmmxt_muladdsl(cpu_M0, cpu_M0, cpu_T[0], cpu_T[1]);
}

static inline void gen_op_iwmmxt_muladdsw_M0_T0_T1(void)
{
    gen_helper_iwmmxt_muladdsw(cpu_M0, cpu_M0, cpu_T[0], cpu_T[1]);
}

static inline void gen_op_iwmmxt_muladdswl_M0_T0_T1(void)
{
    gen_helper_iwmmxt_muladdswl(cpu_M0, cpu_M0, cpu_T[0], cpu_T[1]);
}

static inline void gen_op_iwmmxt_align_M0_T0_wRn(int rn)
{
    iwmmxt_load_reg(cpu_V1, rn);
    gen_helper_iwmmxt_align(cpu_M0, cpu_M0, cpu_V1, cpu_T[0]);
}

static inline void gen_op_iwmmxt_insr_M0_T0_T1(int shift)
{
    TCGv tmp = tcg_const_i32(shift);
    gen_helper_iwmmxt_insr(cpu_M0, cpu_M0, cpu_T[0], cpu_T[1], tmp);
}

static inline void gen_op_iwmmxt_extrsb_T0_M0(int shift)
{
    tcg_gen_shri_i64(cpu_M0, cpu_M0, shift);
    tcg_gen_trunc_i64_i32(cpu_T[0], cpu_M0);
    tcg_gen_ext8s_i32(cpu_T[0], cpu_T[0]);
}

static inline void gen_op_iwmmxt_extrsw_T0_M0(int shift)
{
    tcg_gen_shri_i64(cpu_M0, cpu_M0, shift);
    tcg_gen_trunc_i64_i32(cpu_T[0], cpu_M0);
    tcg_gen_ext16s_i32(cpu_T[0], cpu_T[0]);
}

static inline void gen_op_iwmmxt_extru_T0_M0(int shift, uint32_t mask)
{
    tcg_gen_shri_i64(cpu_M0, cpu_M0, shift);
    tcg_gen_trunc_i64_i32(cpu_T[0], cpu_M0);
    if (mask != ~0u)
        tcg_gen_andi_i32(cpu_T[0], cpu_T[0], mask);
}

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 已提交
1404
    tcg_gen_ext32u_i64(cpu_V1, cpu_V1);
P
pbrook 已提交
1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418
    tcg_gen_add_i64(cpu_M0, cpu_M0, cpu_V1);
}


static void gen_iwmmxt_movl_T0_T1_wRn(int rn)
{
    iwmmxt_load_reg(cpu_V0, rn);
    tcg_gen_trunc_i64_i32(cpu_T[0], cpu_V0);
    tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
    tcg_gen_trunc_i64_i32(cpu_T[1], cpu_V0);
}

static void gen_iwmmxt_movl_wRn_T0_T1(int rn)
{
P
pbrook 已提交
1419
    tcg_gen_concat_i32_i64(cpu_V0, cpu_T[0], cpu_T[1]);
P
pbrook 已提交
1420 1421 1422
    iwmmxt_store_reg(cpu_V0, rn);
}

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 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463
static inline int gen_iwmmxt_address(DisasContext *s, uint32_t insn)
{
    int rd;
    uint32_t offset;

    rd = (insn >> 16) & 0xf;
    gen_movl_T1_reg(s, rd);

    offset = (insn & 0xff) << ((insn >> 7) & 2);
    if (insn & (1 << 24)) {
        /* Pre indexed */
        if (insn & (1 << 23))
            gen_op_addl_T1_im(offset);
        else
            gen_op_addl_T1_im(-offset);

        if (insn & (1 << 21))
            gen_movl_reg_T1(s, rd);
    } else if (insn & (1 << 21)) {
        /* Post indexed */
        if (insn & (1 << 23))
            gen_op_movl_T0_im(offset);
        else
            gen_op_movl_T0_im(- offset);
        gen_op_addl_T0_T1();
        gen_movl_reg_T0(s, rd);
    } else if (!(insn & (1 << 23)))
        return 1;
    return 0;
}

static inline int gen_iwmmxt_shift(uint32_t insn, uint32_t mask)
{
    int rd = (insn >> 0) & 0xf;

    if (insn & (1 << 8))
        if (rd < ARM_IWMMXT_wCGR0 || rd > ARM_IWMMXT_wCGR3)
            return 1;
        else
            gen_op_iwmmxt_movl_T0_wCx(rd);
    else
P
pbrook 已提交
1464
        gen_iwmmxt_movl_T0_T1_wRn(rd);
1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476

    gen_op_movl_T1_im(mask);
    gen_op_andl_T0_T1();
    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;
P
pbrook 已提交
1477
    TCGv tmp;
1478 1479 1480 1481 1482 1483 1484

    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 */
P
pbrook 已提交
1485
                gen_iwmmxt_movl_T0_T1_wRn(wrd);
1486 1487 1488 1489 1490
                gen_movl_reg_T0(s, rdlo);
                gen_movl_reg_T1(s, rdhi);
            } else {					/* TMCRR */
                gen_movl_T0_reg(s, rdlo);
                gen_movl_T1_reg(s, rdhi);
P
pbrook 已提交
1491
                gen_iwmmxt_movl_wRn_T0_T1(wrd);
1492 1493 1494 1495 1496 1497 1498 1499 1500 1501
                gen_op_iwmmxt_set_mup();
            }
            return 0;
        }

        wrd = (insn >> 12) & 0xf;
        if (gen_iwmmxt_address(s, insn))
            return 1;
        if (insn & ARM_CP_RW_BIT) {
            if ((insn >> 28) == 0xf) {			/* WLDRW wCx */
P
pbrook 已提交
1502 1503 1504
                tmp = gen_ld32(cpu_T[1], IS_USER(s));
                tcg_gen_mov_i32(cpu_T[0], tmp);
                dead_tmp(tmp);
1505 1506
                gen_op_iwmmxt_movl_wCx_T0(wrd);
            } else {
P
pbrook 已提交
1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525
                i = 1;
                if (insn & (1 << 8)) {
                    if (insn & (1 << 22)) {		/* WLDRD */
                        tcg_gen_qemu_ld64(cpu_M0, cpu_T[1], IS_USER(s));
                        i = 0;
                    } else {				/* WLDRW wRd */
                        tmp = gen_ld32(cpu_T[1], IS_USER(s));
                    }
                } else {
                    if (insn & (1 << 22)) {		/* WLDRH */
                        tmp = gen_ld16u(cpu_T[1], IS_USER(s));
                    } else {				/* WLDRB */
                        tmp = gen_ld8u(cpu_T[1], IS_USER(s));
                    }
                }
                if (i) {
                    tcg_gen_extu_i32_i64(cpu_M0, tmp);
                    dead_tmp(tmp);
                }
1526 1527 1528 1529 1530
                gen_op_iwmmxt_movq_wRn_M0(wrd);
            }
        } else {
            if ((insn >> 28) == 0xf) {			/* WSTRW wCx */
                gen_op_iwmmxt_movl_T0_wCx(wrd);
P
pbrook 已提交
1531 1532 1533
                tmp = new_tmp();
                tcg_gen_mov_i32(tmp, cpu_T[0]);
                gen_st32(tmp, cpu_T[1], IS_USER(s));
1534 1535
            } else {
                gen_op_iwmmxt_movq_M0_wRn(wrd);
P
pbrook 已提交
1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553
                tmp = new_tmp();
                if (insn & (1 << 8)) {
                    if (insn & (1 << 22)) {		/* WSTRD */
                        dead_tmp(tmp);
                        tcg_gen_qemu_st64(cpu_M0, cpu_T[1], IS_USER(s));
                    } else {				/* WSTRW wRd */
                        tcg_gen_trunc_i64_i32(tmp, cpu_M0);
                        gen_st32(tmp, cpu_T[1], IS_USER(s));
                    }
                } else {
                    if (insn & (1 << 22)) {		/* WSTRH */
                        tcg_gen_trunc_i64_i32(tmp, cpu_M0);
                        gen_st16(tmp, cpu_T[1], IS_USER(s));
                    } else {				/* WSTRB */
                        tcg_gen_trunc_i64_i32(tmp, cpu_M0);
                        gen_st8(tmp, cpu_T[1], IS_USER(s));
                    }
                }
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 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627
            }
        }
        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:
            gen_op_iwmmxt_movl_T0_wCx(wrd);
            gen_movl_T1_reg(s, rd);
            gen_op_bicl_T0_T1();
            gen_op_iwmmxt_movl_wCx_T0(wrd);
            break;
        case ARM_IWMMXT_wCGR0:
        case ARM_IWMMXT_wCGR1:
        case ARM_IWMMXT_wCGR2:
        case ARM_IWMMXT_wCGR3:
            gen_op_iwmmxt_set_cup();
            gen_movl_reg_T0(s, rd);
            gen_op_iwmmxt_movl_wCx_T0(wrd);
            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;
        gen_op_iwmmxt_movl_T0_wCx(wrd);
        gen_movl_reg_T0(s, rd);
        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 已提交
1628
        tcg_gen_neg_i64(cpu_M0, cpu_M0);
1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720
        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 已提交
1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731
        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);
        }
1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744
        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 已提交
1745 1746
            iwmmxt_load_reg(cpu_V1, wrd);
            tcg_gen_add_i64(cpu_M0, cpu_M0, cpu_V1);
1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777
        }
        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 已提交
1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788
        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);
        }
1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839
        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);
        gen_op_iwmmxt_movl_T0_wCx(ARM_IWMMXT_wCGR0 + ((insn >> 20) & 3));
        gen_op_movl_T1_im(7);
        gen_op_andl_T0_T1();
        gen_op_iwmmxt_align_M0_T0_wRn(rd1);
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        break;
    case 0x601: case 0x605: case 0x609: case 0x60d:	/* TINSR */
        rd = (insn >> 12) & 0xf;
        wrd = (insn >> 16) & 0xf;
        gen_movl_T0_reg(s, rd);
        gen_op_iwmmxt_movq_M0_wRn(wrd);
        switch ((insn >> 6) & 3) {
        case 0:
            gen_op_movl_T1_im(0xff);
            gen_op_iwmmxt_insr_M0_T0_T1((insn & 7) << 3);
            break;
        case 1:
            gen_op_movl_T1_im(0xffff);
            gen_op_iwmmxt_insr_M0_T0_T1((insn & 3) << 4);
            break;
        case 2:
            gen_op_movl_T1_im(0xffffffff);
            gen_op_iwmmxt_insr_M0_T0_T1((insn & 1) << 5);
            break;
        case 3:
            return 1;
        }
        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;
        if (rd == 15)
            return 1;
        gen_op_iwmmxt_movq_M0_wRn(wrd);
        switch ((insn >> 22) & 3) {
        case 0:
            if (insn & 8)
                gen_op_iwmmxt_extrsb_T0_M0((insn & 7) << 3);
            else {
P
pbrook 已提交
1840
                gen_op_iwmmxt_extru_T0_M0((insn & 7) << 3, 0xff);
1841 1842 1843 1844 1845 1846
            }
            break;
        case 1:
            if (insn & 8)
                gen_op_iwmmxt_extrsw_T0_M0((insn & 3) << 4);
            else {
P
pbrook 已提交
1847
                gen_op_iwmmxt_extru_T0_M0((insn & 3) << 4, 0xffff);
1848 1849 1850
            }
            break;
        case 2:
P
pbrook 已提交
1851
            gen_op_iwmmxt_extru_T0_M0((insn & 1) << 5, ~0u);
1852 1853 1854 1855
            break;
        case 3:
            return 1;
        }
P
pbrook 已提交
1856
        gen_movl_reg_T0(s, rd);
1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875
        break;
    case 0x117: case 0x517: case 0x917: case 0xd17:	/* TEXTRC */
        if ((insn & 0x000ff008) != 0x0003f000)
            return 1;
        gen_op_iwmmxt_movl_T1_wCx(ARM_IWMMXT_wCASF);
        switch ((insn >> 22) & 3) {
        case 0:
            gen_op_shrl_T1_im(((insn & 7) << 2) + 0);
            break;
        case 1:
            gen_op_shrl_T1_im(((insn & 3) << 3) + 4);
            break;
        case 2:
            gen_op_shrl_T1_im(((insn & 1) << 4) + 12);
            break;
        case 3:
            return 1;
        }
        gen_op_shll_T1_im(28);
P
pbrook 已提交
1876
        gen_set_nzcv(cpu_T[1]);
1877 1878 1879 1880 1881 1882 1883
        break;
    case 0x401: case 0x405: case 0x409: case 0x40d:	/* TBCST */
        rd = (insn >> 12) & 0xf;
        wrd = (insn >> 16) & 0xf;
        gen_movl_T0_reg(s, rd);
        switch ((insn >> 6) & 3) {
        case 0:
P
pbrook 已提交
1884
            gen_helper_iwmmxt_bcstb(cpu_M0, cpu_T[0]);
1885 1886
            break;
        case 1:
P
pbrook 已提交
1887
            gen_helper_iwmmxt_bcstw(cpu_M0, cpu_T[0]);
1888 1889
            break;
        case 2:
P
pbrook 已提交
1890
            gen_helper_iwmmxt_bcstl(cpu_M0, cpu_T[0]);
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
            break;
        case 3:
            return 1;
        }
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        break;
    case 0x113: case 0x513: case 0x913: case 0xd13:	/* TANDC */
        if ((insn & 0x000ff00f) != 0x0003f000)
            return 1;
        gen_op_iwmmxt_movl_T1_wCx(ARM_IWMMXT_wCASF);
        switch ((insn >> 22) & 3) {
        case 0:
            for (i = 0; i < 7; i ++) {
                gen_op_shll_T1_im(4);
                gen_op_andl_T0_T1();
            }
            break;
        case 1:
            for (i = 0; i < 3; i ++) {
                gen_op_shll_T1_im(8);
                gen_op_andl_T0_T1();
            }
            break;
        case 2:
            gen_op_shll_T1_im(16);
            gen_op_andl_T0_T1();
            break;
        case 3:
            return 1;
        }
P
pbrook 已提交
1922
        gen_set_nzcv(cpu_T[0]);
1923 1924 1925 1926 1927 1928 1929
        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 已提交
1930
            gen_helper_iwmmxt_addcb(cpu_M0, cpu_M0);
1931 1932
            break;
        case 1:
P
pbrook 已提交
1933
            gen_helper_iwmmxt_addcw(cpu_M0, cpu_M0);
1934 1935
            break;
        case 2:
P
pbrook 已提交
1936
            gen_helper_iwmmxt_addcl(cpu_M0, cpu_M0);
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 1967
            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 */
        if ((insn & 0x000ff00f) != 0x0003f000)
            return 1;
        gen_op_iwmmxt_movl_T1_wCx(ARM_IWMMXT_wCASF);
        switch ((insn >> 22) & 3) {
        case 0:
            for (i = 0; i < 7; i ++) {
                gen_op_shll_T1_im(4);
                gen_op_orl_T0_T1();
            }
            break;
        case 1:
            for (i = 0; i < 3; i ++) {
                gen_op_shll_T1_im(8);
                gen_op_orl_T0_T1();
            }
            break;
        case 2:
            gen_op_shll_T1_im(16);
            gen_op_orl_T0_T1();
            break;
        case 3:
            return 1;
        }
P
pbrook 已提交
1968
        gen_set_nzcv(cpu_T[0]);
1969 1970 1971 1972 1973 1974 1975 1976 1977
        break;
    case 0x103: case 0x503: case 0x903: case 0xd03:	/* TMOVMSK */
        rd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        if ((insn & 0xf) != 0)
            return 1;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
        switch ((insn >> 22) & 3) {
        case 0:
P
pbrook 已提交
1978
            gen_helper_iwmmxt_msbb(cpu_T[0], cpu_M0);
1979 1980
            break;
        case 1:
P
pbrook 已提交
1981
            gen_helper_iwmmxt_msbw(cpu_T[0], cpu_M0);
1982 1983
            break;
        case 2:
P
pbrook 已提交
1984
            gen_helper_iwmmxt_msbl(cpu_T[0], cpu_M0);
1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095
            break;
        case 3:
            return 1;
        }
        gen_movl_reg_T0(s, rd);
        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:
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
        if (gen_iwmmxt_shift(insn, 0xff))
            return 1;
        switch ((insn >> 22) & 3) {
        case 0:
            return 1;
        case 1:
P
pbrook 已提交
2096
            gen_helper_iwmmxt_srlw(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2097 2098
            break;
        case 2:
P
pbrook 已提交
2099
            gen_helper_iwmmxt_srll(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2100 2101
            break;
        case 3:
P
pbrook 已提交
2102
            gen_helper_iwmmxt_srlq(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119
            break;
        }
        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:
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
        if (gen_iwmmxt_shift(insn, 0xff))
            return 1;
        switch ((insn >> 22) & 3) {
        case 0:
            return 1;
        case 1:
P
pbrook 已提交
2120
            gen_helper_iwmmxt_sraw(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2121 2122
            break;
        case 2:
P
pbrook 已提交
2123
            gen_helper_iwmmxt_sral(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2124 2125
            break;
        case 3:
P
pbrook 已提交
2126
            gen_helper_iwmmxt_sraq(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143
            break;
        }
        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:
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
        if (gen_iwmmxt_shift(insn, 0xff))
            return 1;
        switch ((insn >> 22) & 3) {
        case 0:
            return 1;
        case 1:
P
pbrook 已提交
2144
            gen_helper_iwmmxt_sllw(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2145 2146
            break;
        case 2:
P
pbrook 已提交
2147
            gen_helper_iwmmxt_slll(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2148 2149
            break;
        case 3:
P
pbrook 已提交
2150
            gen_helper_iwmmxt_sllq(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167
            break;
        }
        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:
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
        switch ((insn >> 22) & 3) {
        case 0:
            return 1;
        case 1:
            if (gen_iwmmxt_shift(insn, 0xf))
                return 1;
P
pbrook 已提交
2168
            gen_helper_iwmmxt_rorw(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2169 2170 2171 2172
            break;
        case 2:
            if (gen_iwmmxt_shift(insn, 0x1f))
                return 1;
P
pbrook 已提交
2173
            gen_helper_iwmmxt_rorl(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2174 2175 2176 2177
            break;
        case 3:
            if (gen_iwmmxt_shift(insn, 0x3f))
                return 1;
P
pbrook 已提交
2178
            gen_helper_iwmmxt_rorq(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
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 2210 2211 2212 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 2264 2265 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 2304 2305 2306 2307 2308
            break;
        }
        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);
        gen_op_movl_T0_im((insn >> 20) & 3);
        gen_op_iwmmxt_align_M0_T0_wRn(rd1);
        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);
        gen_op_movl_T0_im(((insn >> 16) & 0xf0) | (insn & 0x0f));
P
pbrook 已提交
2309
        gen_helper_iwmmxt_shufh(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404
        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:
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        rd1 = (insn >> 0) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
        if (!(insn & (1 << 20)))
            return 1;
        switch ((insn >> 22) & 3) {
        case 0:
            return 1;
        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);
        switch ((insn >> 16) & 0xf) {
        case 0x0:					/* TMIA */
P
pbrook 已提交
2405 2406
            gen_movl_T0_reg(s, rd0);
            gen_movl_T1_reg(s, rd1);
2407 2408 2409
            gen_op_iwmmxt_muladdsl_M0_T0_T1();
            break;
        case 0x8:					/* TMIAPH */
P
pbrook 已提交
2410 2411
            gen_movl_T0_reg(s, rd0);
            gen_movl_T1_reg(s, rd1);
2412 2413 2414
            gen_op_iwmmxt_muladdsw_M0_T0_T1();
            break;
        case 0xc: case 0xd: case 0xe: case 0xf:		/* TMIAxy */
P
pbrook 已提交
2415
            gen_movl_T1_reg(s, rd0);
2416 2417 2418
            if (insn & (1 << 16))
                gen_op_shrl_T1_im(16);
            gen_op_movl_T0_T1();
P
pbrook 已提交
2419
            gen_movl_T1_reg(s, rd1);
2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453
            if (insn & (1 << 17))
                gen_op_shrl_T1_im(16);
            gen_op_iwmmxt_muladdswl_M0_T0_T1();
            break;
        default:
            return 1;
        }
        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;

    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;

        switch ((insn >> 16) & 0xf) {
        case 0x0:					/* MIA */
P
pbrook 已提交
2454 2455
            gen_movl_T0_reg(s, rd0);
            gen_movl_T1_reg(s, rd1);
2456 2457 2458
            gen_op_iwmmxt_muladdsl_M0_T0_T1();
            break;
        case 0x8:					/* MIAPH */
P
pbrook 已提交
2459 2460
            gen_movl_T0_reg(s, rd0);
            gen_movl_T1_reg(s, rd1);
2461 2462 2463 2464 2465 2466
            gen_op_iwmmxt_muladdsw_M0_T0_T1();
            break;
        case 0xc:					/* MIABB */
        case 0xd:					/* MIABT */
        case 0xe:					/* MIATB */
        case 0xf:					/* MIATT */
P
pbrook 已提交
2467
            gen_movl_T1_reg(s, rd0);
2468 2469 2470
            if (insn & (1 << 16))
                gen_op_shrl_T1_im(16);
            gen_op_movl_T0_T1();
P
pbrook 已提交
2471
            gen_movl_T1_reg(s, rd1);
2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493
            if (insn & (1 << 17))
                gen_op_shrl_T1_im(16);
            gen_op_iwmmxt_muladdswl_M0_T0_T1();
            break;
        default:
            return 1;
        }

        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 */
P
pbrook 已提交
2494
            gen_iwmmxt_movl_T0_T1_wRn(acc);
P
pbrook 已提交
2495
            gen_movl_reg_T0(s, rdlo);
2496 2497
            gen_op_movl_T0_im((1 << (40 - 32)) - 1);
            gen_op_andl_T0_T1();
P
pbrook 已提交
2498
            gen_movl_reg_T0(s, rdhi);
2499
        } else {					/* MAR */
P
pbrook 已提交
2500 2501
            gen_movl_T0_reg(s, rdlo);
            gen_movl_T1_reg(s, rdhi);
P
pbrook 已提交
2502
            gen_iwmmxt_movl_wRn_T0_T1(acc);
2503 2504 2505 2506 2507 2508 2509
        }
        return 0;
    }

    return 1;
}

2510 2511 2512 2513
/* Disassemble system coprocessor instruction.  Return nonzero if
   instruction is not defined.  */
static int disas_cp_insn(CPUState *env, DisasContext *s, uint32_t insn)
{
P
pbrook 已提交
2514
    TCGv tmp;
2515 2516 2517 2518 2519 2520
    uint32_t rd = (insn >> 12) & 0xf;
    uint32_t cp = (insn >> 8) & 0xf;
    if (IS_USER(s)) {
        return 1;
    }

2521
    if (insn & ARM_CP_RW_BIT) {
2522 2523
        if (!env->cp[cp].cp_read)
            return 1;
P
pbrook 已提交
2524 2525 2526 2527
        gen_set_pc_im(s->pc);
        tmp = new_tmp();
        gen_helper_get_cp(tmp, cpu_env, tcg_const_i32(insn));
        store_reg(s, rd, tmp);
2528 2529 2530
    } else {
        if (!env->cp[cp].cp_write)
            return 1;
P
pbrook 已提交
2531 2532 2533
        gen_set_pc_im(s->pc);
        tmp = load_reg(s, rd);
        gen_helper_set_cp(cpu_env, tcg_const_i32(insn), tmp);
B
balrog 已提交
2534
        dead_tmp(tmp);
2535 2536 2537 2538
    }
    return 0;
}

P
pbrook 已提交
2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558
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;
}

B
bellard 已提交
2559 2560
/* Disassemble system coprocessor (cp15) instruction.  Return nonzero if
   instruction is not defined.  */
2561
static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn)
B
bellard 已提交
2562 2563
{
    uint32_t rd;
P
pbrook 已提交
2564
    TCGv tmp;
B
bellard 已提交
2565

P
pbrook 已提交
2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582
    /* 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 已提交
2583 2584
        return 1;
    }
B
bellard 已提交
2585 2586 2587
    if ((insn & 0x0fff0fff) == 0x0e070f90
        || (insn & 0x0fff0fff) == 0x0e070f58) {
        /* Wait for interrupt.  */
P
pbrook 已提交
2588
        gen_set_pc_im(s->pc);
P
pbrook 已提交
2589
        s->is_jmp = DISAS_WFI;
B
bellard 已提交
2590 2591
        return 0;
    }
B
bellard 已提交
2592
    rd = (insn >> 12) & 0xf;
2593
    if (insn & ARM_CP_RW_BIT) {
P
pbrook 已提交
2594 2595
        tmp = new_tmp();
        gen_helper_get_cp15(tmp, cpu_env, tcg_const_i32(insn));
B
bellard 已提交
2596 2597
        /* If the destination register is r15 then sets condition codes.  */
        if (rd != 15)
P
pbrook 已提交
2598 2599 2600
            store_reg(s, rd, tmp);
        else
            dead_tmp(tmp);
B
bellard 已提交
2601
    } else {
P
pbrook 已提交
2602 2603 2604
        tmp = load_reg(s, rd);
        gen_helper_set_cp15(cpu_env, tcg_const_i32(insn), tmp);
        dead_tmp(tmp);
2605 2606 2607 2608 2609 2610
        /* 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 已提交
2611 2612 2613 2614
    }
    return 0;
}

P
pbrook 已提交
2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634
#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 已提交
2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648
/* 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 已提交
2649 2650 2651 2652 2653 2654
static inline int
vfp_enabled(CPUState * env)
{
    return ((env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) != 0);
}

P
pbrook 已提交
2655 2656 2657 2658 2659
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 已提交
2660
    tcg_gen_ext8u_i32(var, var);
P
pbrook 已提交
2661 2662 2663 2664 2665 2666 2667 2668 2669 2670
    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 已提交
2671
    tcg_gen_ext16u_i32(var, var);
P
pbrook 已提交
2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685
    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 已提交
2686 2687 2688 2689 2690 2691
/* 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;
P
pbrook 已提交
2692
    TCGv tmp;
P
pbrook 已提交
2693
    TCGv tmp2;
B
bellard 已提交
2694

P
pbrook 已提交
2695 2696 2697
    if (!arm_feature(env, ARM_FEATURE_VFP))
        return 1;

P
pbrook 已提交
2698 2699
    if (!vfp_enabled(env)) {
        /* VFP disabled.  Only allow fmxr/fmrx to/from some control regs.  */
P
pbrook 已提交
2700 2701 2702
        if ((insn & 0x0fe00fff) != 0x0ee00a10)
            return 1;
        rn = (insn >> 16) & 0xf;
P
pbrook 已提交
2703 2704
        if (rn != ARM_VFP_FPSID && rn != ARM_VFP_FPEXC
            && rn != ARM_VFP_MVFR1 && rn != ARM_VFP_MVFR0)
P
pbrook 已提交
2705 2706
            return 1;
    }
B
bellard 已提交
2707 2708 2709 2710 2711 2712 2713
    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 已提交
2714 2715 2716 2717 2718
                int size;
                int pass;

                VFP_DREG_N(rn, insn);
                if (insn & 0xf)
B
bellard 已提交
2719
                    return 1;
P
pbrook 已提交
2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734
                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;
                }
2735
                if (insn & ARM_CP_RW_BIT) {
B
bellard 已提交
2736
                    /* vfp->arm */
P
pbrook 已提交
2737
                    tmp = neon_load_reg(rn, pass);
P
pbrook 已提交
2738 2739 2740
                    switch (size) {
                    case 0:
                        if (offset)
P
pbrook 已提交
2741
                            tcg_gen_shri_i32(tmp, tmp, offset);
P
pbrook 已提交
2742
                        if (insn & (1 << 23))
P
pbrook 已提交
2743
                            gen_uxtb(tmp);
P
pbrook 已提交
2744
                        else
P
pbrook 已提交
2745
                            gen_sxtb(tmp);
P
pbrook 已提交
2746 2747 2748 2749
                        break;
                    case 1:
                        if (insn & (1 << 23)) {
                            if (offset) {
P
pbrook 已提交
2750
                                tcg_gen_shri_i32(tmp, tmp, 16);
P
pbrook 已提交
2751
                            } else {
P
pbrook 已提交
2752
                                gen_uxth(tmp);
P
pbrook 已提交
2753 2754 2755
                            }
                        } else {
                            if (offset) {
P
pbrook 已提交
2756
                                tcg_gen_sari_i32(tmp, tmp, 16);
P
pbrook 已提交
2757
                            } else {
P
pbrook 已提交
2758
                                gen_sxth(tmp);
P
pbrook 已提交
2759 2760 2761 2762 2763 2764
                            }
                        }
                        break;
                    case 2:
                        break;
                    }
P
pbrook 已提交
2765
                    store_reg(s, rd, tmp);
B
bellard 已提交
2766 2767
                } else {
                    /* arm->vfp */
P
pbrook 已提交
2768
                    tmp = load_reg(s, rd);
P
pbrook 已提交
2769 2770 2771
                    if (insn & (1 << 23)) {
                        /* VDUP */
                        if (size == 0) {
P
pbrook 已提交
2772
                            gen_neon_dup_u8(tmp, 0);
P
pbrook 已提交
2773
                        } else if (size == 1) {
P
pbrook 已提交
2774
                            gen_neon_dup_low16(tmp);
P
pbrook 已提交
2775
                        }
P
pbrook 已提交
2776 2777 2778 2779 2780 2781
                        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 已提交
2782 2783 2784 2785
                    } else {
                        /* VMOV */
                        switch (size) {
                        case 0:
P
pbrook 已提交
2786 2787 2788
                            tmp2 = neon_load_reg(rn, pass);
                            gen_bfi(tmp, tmp2, tmp, offset, 0xff);
                            dead_tmp(tmp2);
P
pbrook 已提交
2789 2790
                            break;
                        case 1:
P
pbrook 已提交
2791 2792 2793
                            tmp2 = neon_load_reg(rn, pass);
                            gen_bfi(tmp, tmp2, tmp, offset, 0xffff);
                            dead_tmp(tmp2);
P
pbrook 已提交
2794 2795 2796 2797
                            break;
                        case 2:
                            break;
                        }
P
pbrook 已提交
2798
                        neon_store_reg(rn, pass, tmp);
P
pbrook 已提交
2799
                    }
B
bellard 已提交
2800
                }
P
pbrook 已提交
2801 2802 2803 2804
            } else { /* !dp */
                if ((insn & 0x6f) != 0x00)
                    return 1;
                rn = VFP_SREG_N(insn);
2805
                if (insn & ARM_CP_RW_BIT) {
B
bellard 已提交
2806 2807 2808
                    /* vfp->arm */
                    if (insn & (1 << 21)) {
                        /* system register */
P
pbrook 已提交
2809
                        rn >>= 1;
P
pbrook 已提交
2810

B
bellard 已提交
2811
                        switch (rn) {
P
pbrook 已提交
2812
                        case ARM_VFP_FPSID:
P
pbrook 已提交
2813
                            /* VFP2 allows access to FSID from userspace.
P
pbrook 已提交
2814 2815 2816 2817 2818
                               VFP3 restricts all id registers to privileged
                               accesses.  */
                            if (IS_USER(s)
                                && arm_feature(env, ARM_FEATURE_VFP3))
                                return 1;
P
pbrook 已提交
2819
                            tmp = load_cpu_field(vfp.xregs[rn]);
P
pbrook 已提交
2820
                            break;
P
pbrook 已提交
2821
                        case ARM_VFP_FPEXC:
P
pbrook 已提交
2822 2823
                            if (IS_USER(s))
                                return 1;
P
pbrook 已提交
2824
                            tmp = load_cpu_field(vfp.xregs[rn]);
P
pbrook 已提交
2825
                            break;
P
pbrook 已提交
2826 2827
                        case ARM_VFP_FPINST:
                        case ARM_VFP_FPINST2:
P
pbrook 已提交
2828 2829 2830 2831
                            /* Not present in VFP3.  */
                            if (IS_USER(s)
                                || arm_feature(env, ARM_FEATURE_VFP3))
                                return 1;
P
pbrook 已提交
2832
                            tmp = load_cpu_field(vfp.xregs[rn]);
B
bellard 已提交
2833
                            break;
P
pbrook 已提交
2834
                        case ARM_VFP_FPSCR:
2835
                            if (rd == 15) {
P
pbrook 已提交
2836 2837 2838 2839 2840 2841
                                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 已提交
2842
                            break;
P
pbrook 已提交
2843 2844 2845 2846 2847
                        case ARM_VFP_MVFR0:
                        case ARM_VFP_MVFR1:
                            if (IS_USER(s)
                                || !arm_feature(env, ARM_FEATURE_VFP3))
                                return 1;
P
pbrook 已提交
2848
                            tmp = load_cpu_field(vfp.xregs[rn]);
P
pbrook 已提交
2849
                            break;
B
bellard 已提交
2850 2851 2852 2853 2854
                        default:
                            return 1;
                        }
                    } else {
                        gen_mov_F0_vreg(0, rn);
P
pbrook 已提交
2855
                        tmp = gen_vfp_mrs();
B
bellard 已提交
2856 2857
                    }
                    if (rd == 15) {
B
bellard 已提交
2858
                        /* Set the 4 flag bits in the CPSR.  */
P
pbrook 已提交
2859 2860 2861 2862 2863
                        gen_set_nzcv(tmp);
                        dead_tmp(tmp);
                    } else {
                        store_reg(s, rd, tmp);
                    }
B
bellard 已提交
2864 2865
                } else {
                    /* arm->vfp */
P
pbrook 已提交
2866
                    tmp = load_reg(s, rd);
B
bellard 已提交
2867
                    if (insn & (1 << 21)) {
P
pbrook 已提交
2868
                        rn >>= 1;
B
bellard 已提交
2869 2870
                        /* system register */
                        switch (rn) {
P
pbrook 已提交
2871
                        case ARM_VFP_FPSID:
P
pbrook 已提交
2872 2873
                        case ARM_VFP_MVFR0:
                        case ARM_VFP_MVFR1:
B
bellard 已提交
2874 2875
                            /* Writes are ignored.  */
                            break;
P
pbrook 已提交
2876
                        case ARM_VFP_FPSCR:
P
pbrook 已提交
2877 2878
                            gen_helper_vfp_set_fpscr(cpu_env, tmp);
                            dead_tmp(tmp);
B
bellard 已提交
2879
                            gen_lookup_tb(s);
B
bellard 已提交
2880
                            break;
P
pbrook 已提交
2881
                        case ARM_VFP_FPEXC:
P
pbrook 已提交
2882 2883
                            if (IS_USER(s))
                                return 1;
P
pbrook 已提交
2884
                            store_cpu_field(tmp, vfp.xregs[rn]);
P
pbrook 已提交
2885 2886 2887 2888
                            gen_lookup_tb(s);
                            break;
                        case ARM_VFP_FPINST:
                        case ARM_VFP_FPINST2:
P
pbrook 已提交
2889
                            store_cpu_field(tmp, vfp.xregs[rn]);
P
pbrook 已提交
2890
                            break;
B
bellard 已提交
2891 2892 2893 2894
                        default:
                            return 1;
                        }
                    } else {
P
pbrook 已提交
2895
                        gen_vfp_msr(tmp);
B
bellard 已提交
2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909
                        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 已提交
2910
                    VFP_DREG_N(rn, insn);
B
bellard 已提交
2911 2912 2913 2914
                }

                if (op == 15 && (rn == 15 || rn > 17)) {
                    /* Integer or single precision destination.  */
P
pbrook 已提交
2915
                    rd = VFP_SREG_D(insn);
B
bellard 已提交
2916
                } else {
P
pbrook 已提交
2917
                    VFP_DREG_D(rd, insn);
B
bellard 已提交
2918 2919 2920 2921 2922 2923
                }

                if (op == 15 && (rn == 16 || rn == 17)) {
                    /* Integer source.  */
                    rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1);
                } else {
P
pbrook 已提交
2924
                    VFP_DREG_M(rm, insn);
B
bellard 已提交
2925 2926
                }
            } else {
P
pbrook 已提交
2927
                rn = VFP_SREG_N(insn);
B
bellard 已提交
2928 2929
                if (op == 15 && rn == 15) {
                    /* Double precision destination.  */
P
pbrook 已提交
2930 2931 2932 2933 2934
                    VFP_DREG_D(rd, insn);
                } else {
                    rd = VFP_SREG_D(insn);
                }
                rm = VFP_SREG_M(insn);
B
bellard 已提交
2935 2936 2937 2938 2939 2940 2941 2942 2943 2944
            }

            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;
2945

B
bellard 已提交
2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 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
            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 已提交
2992 2993 2994 2995
                case 20:
                case 21:
                case 22:
                case 23:
P
pbrook 已提交
2996 2997 2998 2999
                case 28:
                case 29:
                case 30:
                case 31:
P
pbrook 已提交
3000 3001 3002
                    /* Source and destination the same.  */
                    gen_mov_F0_vreg(dp, rd);
                    break;
B
bellard 已提交
3003 3004 3005
                default:
                    /* One source operand.  */
                    gen_mov_F0_vreg(dp, rm);
P
pbrook 已提交
3006
                    break;
B
bellard 已提交
3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035
                }
            } 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 已提交
3036 3037
                    gen_mov_F1_vreg(dp, rd);
                    gen_vfp_sub(dp);
B
bellard 已提交
3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054
                    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 已提交
3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066
                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 已提交
3067
                        tcg_gen_movi_i64(cpu_F0d, ((uint64_t)n) << 32);
P
pbrook 已提交
3068 3069 3070 3071 3072 3073
                    } else {
                        if (i & 0x40)
                            i |= 0x780;
                        else
                            i |= 0x800;
                        n |= i << 19;
B
balrog 已提交
3074
                        tcg_gen_movi_i32(cpu_F0s, n);
P
pbrook 已提交
3075 3076
                    }
                    break;
B
bellard 已提交
3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105
                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;
                    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 已提交
3106
                            gen_helper_vfp_fcvtsd(cpu_F0s, cpu_F0d, cpu_env);
B
bellard 已提交
3107
                        else
P
pbrook 已提交
3108
                            gen_helper_vfp_fcvtds(cpu_F0d, cpu_F0s, cpu_env);
B
bellard 已提交
3109 3110 3111 3112 3113 3114 3115
                        break;
                    case 16: /* fuito */
                        gen_vfp_uito(dp);
                        break;
                    case 17: /* fsito */
                        gen_vfp_sito(dp);
                        break;
P
pbrook 已提交
3116 3117 3118
                    case 20: /* fshto */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
P
pbrook 已提交
3119
                        gen_vfp_shto(dp, 16 - rm);
P
pbrook 已提交
3120 3121 3122 3123
                        break;
                    case 21: /* fslto */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
P
pbrook 已提交
3124
                        gen_vfp_slto(dp, 32 - rm);
P
pbrook 已提交
3125 3126 3127 3128
                        break;
                    case 22: /* fuhto */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
P
pbrook 已提交
3129
                        gen_vfp_uhto(dp, 16 - rm);
P
pbrook 已提交
3130 3131 3132 3133
                        break;
                    case 23: /* fulto */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
P
pbrook 已提交
3134
                        gen_vfp_ulto(dp, 32 - rm);
P
pbrook 已提交
3135
                        break;
B
bellard 已提交
3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147
                    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 已提交
3148 3149 3150
                    case 28: /* ftosh */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
P
pbrook 已提交
3151
                        gen_vfp_tosh(dp, 16 - rm);
P
pbrook 已提交
3152 3153 3154 3155
                        break;
                    case 29: /* ftosl */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
P
pbrook 已提交
3156
                        gen_vfp_tosl(dp, 32 - rm);
P
pbrook 已提交
3157 3158 3159 3160
                        break;
                    case 30: /* ftouh */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
P
pbrook 已提交
3161
                        gen_vfp_touh(dp, 16 - rm);
P
pbrook 已提交
3162 3163 3164 3165
                        break;
                    case 31: /* ftoul */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
P
pbrook 已提交
3166
                        gen_vfp_toul(dp, 32 - rm);
P
pbrook 已提交
3167
                        break;
B
bellard 已提交
3168 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
                    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 已提交
3229
        if (dp && (insn & 0x03e00000) == 0x00400000) {
B
bellard 已提交
3230 3231 3232 3233
            /* two-register transfer */
            rn = (insn >> 16) & 0xf;
            rd = (insn >> 12) & 0xf;
            if (dp) {
P
pbrook 已提交
3234 3235 3236 3237
                VFP_DREG_M(rm, insn);
            } else {
                rm = VFP_SREG_M(insn);
            }
B
bellard 已提交
3238

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

                if (insn & (1 << 24)) /* pre-decrement */
                    gen_op_addl_T1_im(-((insn & 0xff) << 2));

                if (dp)
                    offset = 8;
                else
                    offset = 4;
                for (i = 0; i < n; i++) {
3314
                    if (insn & ARM_CP_RW_BIT) {
B
bellard 已提交
3315
                        /* load */
B
bellard 已提交
3316
                        gen_vfp_ld(s, dp);
B
bellard 已提交
3317 3318 3319 3320
                        gen_mov_vreg_F0(dp, rd + i);
                    } else {
                        /* store */
                        gen_mov_F0_vreg(dp, rd + i);
B
bellard 已提交
3321
                        gen_vfp_st(s, dp);
B
bellard 已提交
3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347
                    }
                    gen_op_addl_T1_im(offset);
                }
                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)
                        gen_op_addl_T1_im(offset);
                    gen_movl_reg_T1(s, rn);
                }
            }
        }
        break;
    default:
        /* Should never happen.  */
        return 1;
    }
    return 0;
}

3348
static inline void gen_goto_tb(DisasContext *s, int n, uint32_t dest)
B
bellard 已提交
3349
{
3350 3351 3352 3353
    TranslationBlock *tb;

    tb = s->tb;
    if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
B
bellard 已提交
3354
        tcg_gen_goto_tb(n);
P
pbrook 已提交
3355
        gen_set_pc_im(dest);
B
bellard 已提交
3356
        tcg_gen_exit_tb((long)tb + n);
3357
    } else {
P
pbrook 已提交
3358
        gen_set_pc_im(dest);
B
bellard 已提交
3359
        tcg_gen_exit_tb(0);
3360
    }
B
bellard 已提交
3361 3362
}

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

P
pbrook 已提交
3376
static inline void gen_mulxy(TCGv t0, TCGv t1, int x, int y)
B
bellard 已提交
3377
{
B
bellard 已提交
3378
    if (x)
P
pbrook 已提交
3379
        tcg_gen_sari_i32(t0, t0, 16);
B
bellard 已提交
3380
    else
P
pbrook 已提交
3381
        gen_sxth(t0);
B
bellard 已提交
3382
    if (y)
P
pbrook 已提交
3383
        tcg_gen_sari_i32(t1, t1, 16);
B
bellard 已提交
3384
    else
P
pbrook 已提交
3385 3386
        gen_sxth(t1);
    tcg_gen_mul_i32(t0, t0, t1);
B
bellard 已提交
3387 3388 3389
}

/* Return the mask of PSR bits set by a MSR instruction.  */
P
pbrook 已提交
3390
static uint32_t msr_mask(CPUState *env, DisasContext *s, int flags, int spsr) {
B
bellard 已提交
3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401
    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 已提交
3402

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

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

        tmp = load_cpu_field(spsr);
        tcg_gen_andi_i32(tmp, tmp, ~mask);
        tcg_gen_andi_i32(cpu_T[0], cpu_T[0], mask);
        tcg_gen_or_i32(tmp, tmp, cpu_T[0]);
        store_cpu_field(tmp, spsr);
B
bellard 已提交
3432
    } else {
P
pbrook 已提交
3433
        gen_set_cpsr(cpu_T[0], mask);
B
bellard 已提交
3434 3435 3436 3437 3438
    }
    gen_lookup_tb(s);
    return 0;
}

3439 3440
/* Generate an old-style exception return. Marks pc as dead. */
static void gen_exception_return(DisasContext *s, TCGv pc)
B
bellard 已提交
3441
{
P
pbrook 已提交
3442
    TCGv tmp;
3443
    store_reg(s, 15, pc);
P
pbrook 已提交
3444 3445 3446
    tmp = load_cpu_field(spsr);
    gen_set_cpsr(tmp, 0xffffffff);
    dead_tmp(tmp);
B
bellard 已提交
3447 3448 3449
    s->is_jmp = DISAS_UPDATE;
}

P
pbrook 已提交
3450 3451
/* Generate a v6 exception return.  Marks both values as dead.  */
static void gen_rfe(DisasContext *s, TCGv pc, TCGv cpsr)
B
bellard 已提交
3452
{
P
pbrook 已提交
3453 3454 3455
    gen_set_cpsr(cpsr, 0xffffffff);
    dead_tmp(cpsr);
    store_reg(s, 15, pc);
P
pbrook 已提交
3456 3457
    s->is_jmp = DISAS_UPDATE;
}
3458

P
pbrook 已提交
3459 3460 3461 3462
static inline void
gen_set_condexec (DisasContext *s)
{
    if (s->condexec_mask) {
P
pbrook 已提交
3463 3464 3465
        uint32_t val = (s->condexec_cond << 4) | (s->condexec_mask >> 1);
        TCGv tmp = new_tmp();
        tcg_gen_movi_i32(tmp, val);
P
pbrook 已提交
3466
        store_cpu_field(tmp, condexec_bits);
P
pbrook 已提交
3467 3468
    }
}
3469

P
pbrook 已提交
3470 3471 3472 3473
static void gen_nop_hint(DisasContext *s, int val)
{
    switch (val) {
    case 3: /* wfi */
P
pbrook 已提交
3474
        gen_set_pc_im(s->pc);
P
pbrook 已提交
3475 3476 3477 3478 3479 3480 3481 3482 3483
        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 已提交
3484

P
pbrook 已提交
3485 3486 3487 3488 3489
/* These macros help make the code more readable when migrating from the
   old dyngen helpers.  They should probably be removed when
   T0/T1 are removed.  */
#define CPU_T001 cpu_T[0], cpu_T[0], cpu_T[1]
#define CPU_T0E01 cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]
P
pbrook 已提交
3490

P
pbrook 已提交
3491
#define CPU_V001 cpu_V0, cpu_V0, cpu_V1
P
pbrook 已提交
3492 3493 3494 3495

static inline int gen_neon_add(int size)
{
    switch (size) {
P
pbrook 已提交
3496 3497
    case 0: gen_helper_neon_add_u8(CPU_T001); break;
    case 1: gen_helper_neon_add_u16(CPU_T001); break;
P
pbrook 已提交
3498 3499 3500 3501 3502 3503
    case 2: gen_op_addl_T0_T1(); break;
    default: return 1;
    }
    return 0;
}

P
pbrook 已提交
3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547
static inline void gen_neon_rsb(int size)
{
    switch (size) {
    case 0: gen_helper_neon_sub_u8(cpu_T[0], cpu_T[1], cpu_T[0]); break;
    case 1: gen_helper_neon_sub_u16(cpu_T[0], cpu_T[1], cpu_T[0]); break;
    case 2: gen_op_rsbl_T0_T1(); break;
    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: \
        gen_helper_neon_##name##_s8(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]); \
        break; \
    case 1: \
        gen_helper_neon_##name##_u8(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]); \
        break; \
    case 2: \
        gen_helper_neon_##name##_s16(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]); \
        break; \
    case 3: \
        gen_helper_neon_##name##_u16(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]); \
        break; \
    case 4: \
        gen_helper_neon_##name##_s32(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]); \
        break; \
    case 5: \
        gen_helper_neon_##name##_u32(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]); \
        break; \
    default: return 1; \
    }} while (0)
P
pbrook 已提交
3548 3549 3550

#define GEN_NEON_INTEGER_OP(name) do { \
    switch ((size << 1) | u) { \
P
pbrook 已提交
3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568
    case 0: \
        gen_helper_neon_##name##_s8(cpu_T[0], cpu_T[0], cpu_T[1]); \
        break; \
    case 1: \
        gen_helper_neon_##name##_u8(cpu_T[0], cpu_T[0], cpu_T[1]); \
        break; \
    case 2: \
        gen_helper_neon_##name##_s16(cpu_T[0], cpu_T[0], cpu_T[1]); \
        break; \
    case 3: \
        gen_helper_neon_##name##_u16(cpu_T[0], cpu_T[0], cpu_T[1]); \
        break; \
    case 4: \
        gen_helper_neon_##name##_s32(cpu_T[0], cpu_T[0], cpu_T[1]); \
        break; \
    case 5: \
        gen_helper_neon_##name##_u32(cpu_T[0], cpu_T[0], cpu_T[1]); \
        break; \
P
pbrook 已提交
3569 3570 3571 3572 3573 3574 3575 3576 3577
    default: return 1; \
    }} while (0)

static inline void
gen_neon_movl_scratch_T0(int scratch)
{
  uint32_t offset;

  offset = offsetof(CPUARMState, vfp.scratch[scratch]);
P
pbrook 已提交
3578
  tcg_gen_st_i32(cpu_T[0], cpu_env, offset);
P
pbrook 已提交
3579 3580 3581 3582 3583 3584 3585 3586
}

static inline void
gen_neon_movl_scratch_T1(int scratch)
{
  uint32_t offset;

  offset = offsetof(CPUARMState, vfp.scratch[scratch]);
P
pbrook 已提交
3587
  tcg_gen_st_i32(cpu_T[1], cpu_env, offset);
P
pbrook 已提交
3588 3589 3590 3591 3592 3593 3594 3595
}

static inline void
gen_neon_movl_T0_scratch(int scratch)
{
  uint32_t offset;

  offset = offsetof(CPUARMState, vfp.scratch[scratch]);
P
pbrook 已提交
3596
  tcg_gen_ld_i32(cpu_T[0], cpu_env, offset);
P
pbrook 已提交
3597 3598 3599 3600 3601 3602 3603 3604
}

static inline void
gen_neon_movl_T1_scratch(int scratch)
{
  uint32_t offset;

  offset = offsetof(CPUARMState, vfp.scratch[scratch]);
P
pbrook 已提交
3605
  tcg_gen_ld_i32(cpu_T[1], cpu_env, offset);
P
pbrook 已提交
3606 3607 3608 3609 3610 3611 3612 3613 3614
}

static inline void gen_neon_get_scalar(int size, int reg)
{
    if (size == 1) {
        NEON_GET_REG(T0, reg >> 1, reg & 1);
    } else {
        NEON_GET_REG(T0, reg >> 2, (reg >> 1) & 1);
        if (reg & 1)
P
pbrook 已提交
3615
            gen_neon_dup_low16(cpu_T[0]);
P
pbrook 已提交
3616
        else
P
pbrook 已提交
3617
            gen_neon_dup_high16(cpu_T[0]);
P
pbrook 已提交
3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628
    }
}

static void gen_neon_unzip(int reg, int q, int tmp, int size)
{
    int n;

    for (n = 0; n < q + 1; n += 2) {
        NEON_GET_REG(T0, reg, n);
        NEON_GET_REG(T0, reg, n + n);
        switch (size) {
P
pbrook 已提交
3629 3630
        case 0: gen_helper_neon_unzip_u8(); break;
        case 1: gen_helper_neon_zip_u16(); break; /* zip and unzip are the same.  */
P
pbrook 已提交
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
        case 2: /* no-op */; break;
        default: abort();
        }
        gen_neon_movl_scratch_T0(tmp + n);
        gen_neon_movl_scratch_T1(tmp + n + 1);
    }
}

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;
    int stride;
    int size;
    int reg;
    int pass;
    int load;
    int shift;
    int n;
P
pbrook 已提交
3672
    TCGv tmp;
P
pbrook 已提交
3673
    TCGv tmp2;
P
pbrook 已提交
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 3701

    if (!vfp_enabled(env))
      return 1;
    VFP_DREG_D(rd, insn);
    rn = (insn >> 16) & 0xf;
    rm = insn & 0xf;
    load = (insn & (1 << 21)) != 0;
    if ((insn & (1 << 23)) == 0) {
        /* Load store all elements.  */
        op = (insn >> 8) & 0xf;
        size = (insn >> 6) & 3;
        if (op > 10 || size == 3)
            return 1;
        nregs = neon_ls_element_type[op].nregs;
        interleave = neon_ls_element_type[op].interleave;
        gen_movl_T1_reg(s, rn);
        stride = (1 << size) * interleave;
        for (reg = 0; reg < nregs; reg++) {
            if (interleave > 2 || (interleave == 2 && nregs == 2)) {
                gen_movl_T1_reg(s, rn);
                gen_op_addl_T1_im((1 << size) * reg);
            } else if (interleave == 2 && nregs == 4 && reg == 2) {
                gen_movl_T1_reg(s, rn);
                gen_op_addl_T1_im(1 << size);
            }
            for (pass = 0; pass < 2; pass++) {
                if (size == 2) {
                    if (load) {
P
pbrook 已提交
3702
                        tmp = gen_ld32(cpu_T[1], IS_USER(s));
P
pbrook 已提交
3703
                        neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
3704
                    } else {
P
pbrook 已提交
3705
                        tmp = neon_load_reg(rd, pass);
P
pbrook 已提交
3706
                        gen_st32(tmp, cpu_T[1], IS_USER(s));
P
pbrook 已提交
3707 3708 3709 3710
                    }
                    gen_op_addl_T1_im(stride);
                } else if (size == 1) {
                    if (load) {
P
pbrook 已提交
3711
                        tmp = gen_ld16u(cpu_T[1], IS_USER(s));
P
pbrook 已提交
3712
                        gen_op_addl_T1_im(stride);
P
pbrook 已提交
3713
                        tmp2 = gen_ld16u(cpu_T[1], IS_USER(s));
P
pbrook 已提交
3714
                        gen_op_addl_T1_im(stride);
P
pbrook 已提交
3715 3716 3717
                        gen_bfi(tmp, tmp, tmp2, 16, 0xffff);
                        dead_tmp(tmp2);
                        neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
3718
                    } else {
P
pbrook 已提交
3719 3720 3721
                        tmp = neon_load_reg(rd, pass);
                        tmp2 = new_tmp();
                        tcg_gen_shri_i32(tmp2, tmp, 16);
P
pbrook 已提交
3722
                        gen_st16(tmp, cpu_T[1], IS_USER(s));
P
pbrook 已提交
3723
                        gen_op_addl_T1_im(stride);
P
pbrook 已提交
3724
                        gen_st16(tmp2, cpu_T[1], IS_USER(s));
P
pbrook 已提交
3725 3726 3727 3728
                        gen_op_addl_T1_im(stride);
                    }
                } else /* size == 0 */ {
                    if (load) {
P
pbrook 已提交
3729
                        TCGV_UNUSED(tmp2);
P
pbrook 已提交
3730
                        for (n = 0; n < 4; n++) {
P
pbrook 已提交
3731
                            tmp = gen_ld8u(cpu_T[1], IS_USER(s));
P
pbrook 已提交
3732 3733
                            gen_op_addl_T1_im(stride);
                            if (n == 0) {
P
pbrook 已提交
3734
                                tmp2 = tmp;
P
pbrook 已提交
3735
                            } else {
P
pbrook 已提交
3736 3737
                                gen_bfi(tmp2, tmp2, tmp, n * 8, 0xff);
                                dead_tmp(tmp);
P
pbrook 已提交
3738 3739
                            }
                        }
P
pbrook 已提交
3740
                        neon_store_reg(rd, pass, tmp2);
P
pbrook 已提交
3741
                    } else {
P
pbrook 已提交
3742
                        tmp2 = neon_load_reg(rd, pass);
P
pbrook 已提交
3743
                        for (n = 0; n < 4; n++) {
P
pbrook 已提交
3744
                            tmp = new_tmp();
P
pbrook 已提交
3745
                            if (n == 0) {
P
pbrook 已提交
3746
                                tcg_gen_mov_i32(tmp, tmp2);
P
pbrook 已提交
3747
                            } else {
P
pbrook 已提交
3748
                                tcg_gen_shri_i32(tmp, tmp2, n * 8);
P
pbrook 已提交
3749
                            }
P
pbrook 已提交
3750
                            gen_st8(tmp, cpu_T[1], IS_USER(s));
P
pbrook 已提交
3751 3752
                            gen_op_addl_T1_im(stride);
                        }
P
pbrook 已提交
3753
                        dead_tmp(tmp2);
P
pbrook 已提交
3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768
                    }
                }
            }
            rd += neon_ls_element_type[op].spacing;
        }
        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;
3769
            gen_movl_T1_reg(s, rn);
P
pbrook 已提交
3770 3771 3772
            for (reg = 0; reg < nregs; reg++) {
                switch (size) {
                case 0:
P
pbrook 已提交
3773
                    tmp = gen_ld8u(cpu_T[1], IS_USER(s));
P
pbrook 已提交
3774
                    gen_neon_dup_u8(tmp, 0);
P
pbrook 已提交
3775 3776
                    break;
                case 1:
P
pbrook 已提交
3777
                    tmp = gen_ld16u(cpu_T[1], IS_USER(s));
P
pbrook 已提交
3778
                    gen_neon_dup_low16(tmp);
P
pbrook 已提交
3779 3780
                    break;
                case 2:
P
pbrook 已提交
3781
                    tmp = gen_ld32(cpu_T[0], IS_USER(s));
P
pbrook 已提交
3782 3783 3784
                    break;
                case 3:
                    return 1;
P
pbrook 已提交
3785 3786
                default: /* Avoid compiler warnings.  */
                    abort();
B
bellard 已提交
3787
                }
P
pbrook 已提交
3788
                gen_op_addl_T1_im(1 << size);
P
pbrook 已提交
3789 3790 3791
                tmp2 = new_tmp();
                tcg_gen_mov_i32(tmp2, tmp);
                neon_store_reg(rd, 0, tmp2);
P
pbrook 已提交
3792
                neon_store_reg(rd, 1, tmp);
P
pbrook 已提交
3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820
                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;
            gen_movl_T1_reg(s, rn);
            for (reg = 0; reg < nregs; reg++) {
                if (load) {
                    switch (size) {
                    case 0:
P
pbrook 已提交
3821
                        tmp = gen_ld8u(cpu_T[1], IS_USER(s));
P
pbrook 已提交
3822 3823
                        break;
                    case 1:
P
pbrook 已提交
3824
                        tmp = gen_ld16u(cpu_T[1], IS_USER(s));
P
pbrook 已提交
3825 3826
                        break;
                    case 2:
P
pbrook 已提交
3827
                        tmp = gen_ld32(cpu_T[1], IS_USER(s));
P
pbrook 已提交
3828
                        break;
P
pbrook 已提交
3829 3830
                    default: /* Avoid compiler warnings.  */
                        abort();
P
pbrook 已提交
3831 3832
                    }
                    if (size != 2) {
P
pbrook 已提交
3833 3834 3835
                        tmp2 = neon_load_reg(rd, pass);
                        gen_bfi(tmp, tmp2, tmp, shift, size ? 0xffff : 0xff);
                        dead_tmp(tmp2);
P
pbrook 已提交
3836
                    }
P
pbrook 已提交
3837
                    neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
3838
                } else { /* Store */
P
pbrook 已提交
3839 3840 3841
                    tmp = neon_load_reg(rd, pass);
                    if (shift)
                        tcg_gen_shri_i32(tmp, tmp, shift);
P
pbrook 已提交
3842 3843
                    switch (size) {
                    case 0:
P
pbrook 已提交
3844
                        gen_st8(tmp, cpu_T[1], IS_USER(s));
P
pbrook 已提交
3845 3846
                        break;
                    case 1:
P
pbrook 已提交
3847
                        gen_st16(tmp, cpu_T[1], IS_USER(s));
P
pbrook 已提交
3848 3849
                        break;
                    case 2:
P
pbrook 已提交
3850
                        gen_st32(tmp, cpu_T[1], IS_USER(s));
P
pbrook 已提交
3851
                        break;
B
bellard 已提交
3852 3853
                    }
                }
P
pbrook 已提交
3854 3855
                rd += stride;
                gen_op_addl_T1_im(1 << size);
B
bellard 已提交
3856
            }
P
pbrook 已提交
3857
            stride = nregs * (1 << size);
B
bellard 已提交
3858
        }
P
pbrook 已提交
3859 3860
    }
    if (rm != 15) {
P
pbrook 已提交
3861 3862 3863
        TCGv base;

        base = load_reg(s, rn);
P
pbrook 已提交
3864
        if (rm == 13) {
P
pbrook 已提交
3865
            tcg_gen_addi_i32(base, base, stride);
P
pbrook 已提交
3866
        } else {
P
pbrook 已提交
3867 3868 3869 3870
            TCGv index;
            index = load_reg(s, rm);
            tcg_gen_add_i32(base, base, index);
            dead_tmp(index);
P
pbrook 已提交
3871
        }
P
pbrook 已提交
3872
        store_reg(s, rn, base);
P
pbrook 已提交
3873 3874 3875
    }
    return 0;
}
3876

P
pbrook 已提交
3877 3878 3879 3880 3881 3882 3883 3884
/* 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);
    tcg_gen_bic_i32(f, f, c);
    tcg_gen_or_i32(dest, t, f);
}

P
pbrook 已提交
3885
static inline void gen_neon_narrow(int size, TCGv dest, TCGv_i64 src)
P
pbrook 已提交
3886 3887 3888 3889 3890 3891 3892 3893 3894
{
    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 已提交
3895
static inline void gen_neon_narrow_sats(int size, TCGv dest, TCGv_i64 src)
P
pbrook 已提交
3896 3897 3898 3899 3900 3901 3902 3903 3904
{
    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 已提交
3905
static inline void gen_neon_narrow_satu(int size, TCGv dest, TCGv_i64 src)
P
pbrook 已提交
3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948
{
    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 已提交
3949
static inline void gen_neon_widen(TCGv_i64 dest, TCGv src, int size, int u)
P
pbrook 已提交
3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988
{
    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 已提交
3989
static inline void gen_neon_negl(TCGv_i64 var, int size)
P
pbrook 已提交
3990 3991 3992 3993 3994 3995 3996 3997 3998
{
    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 已提交
3999
static inline void gen_neon_addl_saturate(TCGv_i64 op0, TCGv_i64 op1, int size)
P
pbrook 已提交
4000 4001 4002 4003 4004 4005 4006 4007
{
    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 已提交
4008
static inline void gen_neon_mull(TCGv_i64 dest, TCGv a, TCGv b, int size, int u)
P
pbrook 已提交
4009
{
P
pbrook 已提交
4010
    TCGv_i64 tmp;
P
pbrook 已提交
4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032

    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();
    }
    if (size < 2) {
        dead_tmp(b);
        dead_tmp(a);
    }
}

P
pbrook 已提交
4033 4034
/* Translate a NEON data processing instruction.  Return nonzero if the
   instruction is invalid.
P
pbrook 已提交
4035 4036
   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 已提交
4037

P
pbrook 已提交
4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050
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;
    uint32_t imm;
P
pbrook 已提交
4051 4052 4053
    TCGv tmp;
    TCGv tmp2;
    TCGv tmp3;
P
pbrook 已提交
4054
    TCGv_i64 tmp64;
P
pbrook 已提交
4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066

    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 已提交
4067 4068 4069
        if (size == 3 && (op == 1 || op == 5 || op == 8 || op == 9
                          || op == 10 || op  == 11 || op == 16)) {
            /* 64-bit element instructions.  */
P
pbrook 已提交
4070
            for (pass = 0; pass < (q ? 2 : 1); pass++) {
P
pbrook 已提交
4071 4072
                neon_load_reg64(cpu_V0, rn + pass);
                neon_load_reg64(cpu_V1, rm + pass);
P
pbrook 已提交
4073 4074 4075
                switch (op) {
                case 1: /* VQADD */
                    if (u) {
P
pbrook 已提交
4076
                        gen_helper_neon_add_saturate_u64(CPU_V001);
B
bellard 已提交
4077
                    } else {
P
pbrook 已提交
4078
                        gen_helper_neon_add_saturate_s64(CPU_V001);
B
bellard 已提交
4079
                    }
P
pbrook 已提交
4080 4081 4082
                    break;
                case 5: /* VQSUB */
                    if (u) {
P
pbrook 已提交
4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106
                        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 已提交
4107
                    } else {
P
pbrook 已提交
4108 4109 4110 4111 4112 4113 4114 4115 4116 4117
                        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 已提交
4118
                    }
P
pbrook 已提交
4119 4120 4121
                    break;
                case 16:
                    if (u) {
P
pbrook 已提交
4122
                        tcg_gen_sub_i64(CPU_V001);
P
pbrook 已提交
4123
                    } else {
P
pbrook 已提交
4124
                        tcg_gen_add_i64(CPU_V001);
P
pbrook 已提交
4125 4126 4127 4128
                    }
                    break;
                default:
                    abort();
B
bellard 已提交
4129
                }
P
pbrook 已提交
4130
                neon_store_reg64(cpu_V0, rd + pass);
B
bellard 已提交
4131
            }
P
pbrook 已提交
4132
            return 0;
B
bellard 已提交
4133
        }
P
pbrook 已提交
4134 4135 4136 4137
        switch (op) {
        case 8: /* VSHL */
        case 9: /* VQSHL */
        case 10: /* VRSHL */
P
pbrook 已提交
4138
        case 11: /* VQRSHL */
P
pbrook 已提交
4139
            {
P
pbrook 已提交
4140 4141 4142
                int rtmp;
                /* Shift instruction operands are reversed.  */
                rtmp = rn;
P
pbrook 已提交
4143
                rn = rm;
P
pbrook 已提交
4144
                rm = rtmp;
P
pbrook 已提交
4145 4146
                pairwise = 0;
            }
B
bellard 已提交
4147
            break;
P
pbrook 已提交
4148 4149 4150 4151
        case 20: /* VPMAX */
        case 21: /* VPMIN */
        case 23: /* VPADD */
            pairwise = 1;
B
bellard 已提交
4152
            break;
P
pbrook 已提交
4153 4154
        case 26: /* VPADD (float) */
            pairwise = (u && size < 2);
B
bellard 已提交
4155
            break;
P
pbrook 已提交
4156 4157
        case 30: /* VPMIN/VPMAX (float) */
            pairwise = u;
B
bellard 已提交
4158
            break;
P
pbrook 已提交
4159 4160
        default:
            pairwise = 0;
B
bellard 已提交
4161
            break;
P
pbrook 已提交
4162 4163 4164 4165 4166 4167 4168
        }
        for (pass = 0; pass < (q ? 4 : 2); pass++) {

        if (pairwise) {
            /* Pairwise.  */
            if (q)
                n = (pass & 1) * 2;
B
bellard 已提交
4169
            else
P
pbrook 已提交
4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187
                n = 0;
            if (pass < q + 1) {
                NEON_GET_REG(T0, rn, n);
                NEON_GET_REG(T1, rn, n + 1);
            } else {
                NEON_GET_REG(T0, rm, n);
                NEON_GET_REG(T1, rm, n + 1);
            }
        } else {
            /* Elementwise.  */
            NEON_GET_REG(T0, rn, pass);
            NEON_GET_REG(T1, rm, pass);
        }
        switch (op) {
        case 0: /* VHADD */
            GEN_NEON_INTEGER_OP(hadd);
            break;
        case 1: /* VQADD */
P
pbrook 已提交
4188
            GEN_NEON_INTEGER_OP_ENV(qadd);
B
bellard 已提交
4189
            break;
P
pbrook 已提交
4190 4191
        case 2: /* VRHADD */
            GEN_NEON_INTEGER_OP(rhadd);
B
bellard 已提交
4192
            break;
P
pbrook 已提交
4193 4194 4195
        case 3: /* Logic ops.  */
            switch ((u << 2) | size) {
            case 0: /* VAND */
B
bellard 已提交
4196
                gen_op_andl_T0_T1();
P
pbrook 已提交
4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211
                break;
            case 1: /* BIC */
                gen_op_bicl_T0_T1();
                break;
            case 2: /* VORR */
                gen_op_orl_T0_T1();
                break;
            case 3: /* VORN */
                gen_op_notl_T1();
                gen_op_orl_T0_T1();
                break;
            case 4: /* VEOR */
                gen_op_xorl_T0_T1();
                break;
            case 5: /* VBSL */
P
pbrook 已提交
4212 4213 4214
                tmp = neon_load_reg(rd, pass);
                gen_neon_bsl(cpu_T[0], cpu_T[0], cpu_T[1], tmp);
                dead_tmp(tmp);
P
pbrook 已提交
4215 4216
                break;
            case 6: /* VBIT */
P
pbrook 已提交
4217 4218 4219
                tmp = neon_load_reg(rd, pass);
                gen_neon_bsl(cpu_T[0], cpu_T[0], tmp, cpu_T[1]);
                dead_tmp(tmp);
P
pbrook 已提交
4220 4221
                break;
            case 7: /* VBIF */
P
pbrook 已提交
4222 4223 4224
                tmp = neon_load_reg(rd, pass);
                gen_neon_bsl(cpu_T[0], tmp, cpu_T[0], cpu_T[1]);
                dead_tmp(tmp);
P
pbrook 已提交
4225
                break;
B
bellard 已提交
4226 4227
            }
            break;
P
pbrook 已提交
4228 4229 4230 4231
        case 4: /* VHSUB */
            GEN_NEON_INTEGER_OP(hsub);
            break;
        case 5: /* VQSUB */
P
pbrook 已提交
4232
            GEN_NEON_INTEGER_OP_ENV(qsub);
B
bellard 已提交
4233
            break;
P
pbrook 已提交
4234 4235 4236 4237 4238 4239 4240
        case 6: /* VCGT */
            GEN_NEON_INTEGER_OP(cgt);
            break;
        case 7: /* VCGE */
            GEN_NEON_INTEGER_OP(cge);
            break;
        case 8: /* VSHL */
P
pbrook 已提交
4241
            GEN_NEON_INTEGER_OP(shl);
B
bellard 已提交
4242
            break;
P
pbrook 已提交
4243
        case 9: /* VQSHL */
P
pbrook 已提交
4244
            GEN_NEON_INTEGER_OP_ENV(qshl);
B
bellard 已提交
4245
            break;
P
pbrook 已提交
4246
        case 10: /* VRSHL */
P
pbrook 已提交
4247
            GEN_NEON_INTEGER_OP(rshl);
B
bellard 已提交
4248
            break;
P
pbrook 已提交
4249
        case 11: /* VQRSHL */
P
pbrook 已提交
4250
            GEN_NEON_INTEGER_OP_ENV(qrshl);
P
pbrook 已提交
4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271
            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);
            NEON_GET_REG(T1, rd, pass);
            gen_neon_add(size);
            break;
        case 16:
            if (!u) { /* VADD */
                if (gen_neon_add(size))
                    return 1;
            } else { /* VSUB */
                switch (size) {
P
pbrook 已提交
4272 4273
                case 0: gen_helper_neon_sub_u8(CPU_T001); break;
                case 1: gen_helper_neon_sub_u16(CPU_T001); break;
P
pbrook 已提交
4274 4275 4276 4277 4278 4279 4280 4281
                case 2: gen_op_subl_T0_T1(); break;
                default: return 1;
                }
            }
            break;
        case 17:
            if (!u) { /* VTST */
                switch (size) {
P
pbrook 已提交
4282 4283 4284
                case 0: gen_helper_neon_tst_u8(CPU_T001); break;
                case 1: gen_helper_neon_tst_u16(CPU_T001); break;
                case 2: gen_helper_neon_tst_u32(CPU_T001); break;
P
pbrook 已提交
4285 4286 4287 4288
                default: return 1;
                }
            } else { /* VCEQ */
                switch (size) {
P
pbrook 已提交
4289 4290 4291
                case 0: gen_helper_neon_ceq_u8(CPU_T001); break;
                case 1: gen_helper_neon_ceq_u16(CPU_T001); break;
                case 2: gen_helper_neon_ceq_u32(CPU_T001); break;
P
pbrook 已提交
4292 4293 4294 4295 4296 4297
                default: return 1;
                }
            }
            break;
        case 18: /* Multiply.  */
            switch (size) {
P
pbrook 已提交
4298 4299
            case 0: gen_helper_neon_mul_u8(CPU_T001); break;
            case 1: gen_helper_neon_mul_u16(CPU_T001); break;
P
pbrook 已提交
4300 4301 4302 4303 4304
            case 2: gen_op_mul_T0_T1(); break;
            default: return 1;
            }
            NEON_GET_REG(T1, rd, pass);
            if (u) { /* VMLS */
P
pbrook 已提交
4305
                gen_neon_rsb(size);
P
pbrook 已提交
4306 4307 4308 4309 4310 4311
            } else { /* VMLA */
                gen_neon_add(size);
            }
            break;
        case 19: /* VMUL */
            if (u) { /* polynomial */
P
pbrook 已提交
4312
                gen_helper_neon_mul_p8(CPU_T001);
P
pbrook 已提交
4313 4314
            } else { /* Integer */
                switch (size) {
P
pbrook 已提交
4315 4316
                case 0: gen_helper_neon_mul_u8(CPU_T001); break;
                case 1: gen_helper_neon_mul_u16(CPU_T001); break;
P
pbrook 已提交
4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330
                case 2: gen_op_mul_T0_T1(); break;
                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) {
P
pbrook 已提交
4331 4332
                case 1: gen_helper_neon_qdmulh_s16(CPU_T0E01); break;
                case 2: gen_helper_neon_qdmulh_s32(CPU_T0E01); break;
P
pbrook 已提交
4333 4334 4335 4336
                default: return 1;
                }
            } else { /* VQRDHMUL */
                switch (size) {
P
pbrook 已提交
4337 4338
                case 1: gen_helper_neon_qrdmulh_s16(CPU_T0E01); break;
                case 2: gen_helper_neon_qrdmulh_s32(CPU_T0E01); break;
P
pbrook 已提交
4339 4340 4341 4342 4343 4344 4345 4346
                default: return 1;
                }
            }
            break;
        case 23: /* VPADD */
            if (u)
                return 1;
            switch (size) {
P
pbrook 已提交
4347 4348
            case 0: gen_helper_neon_padd_u8(CPU_T001); break;
            case 1: gen_helper_neon_padd_u16(CPU_T001); break;
P
pbrook 已提交
4349 4350 4351 4352 4353 4354 4355
            case 2: gen_op_addl_T0_T1(); break;
            default: return 1;
            }
            break;
        case 26: /* Floating point arithnetic.  */
            switch ((u << 2) | size) {
            case 0: /* VADD */
P
pbrook 已提交
4356
                gen_helper_neon_add_f32(CPU_T001);
P
pbrook 已提交
4357 4358
                break;
            case 2: /* VSUB */
P
pbrook 已提交
4359
                gen_helper_neon_sub_f32(CPU_T001);
P
pbrook 已提交
4360 4361
                break;
            case 4: /* VPADD */
P
pbrook 已提交
4362
                gen_helper_neon_add_f32(CPU_T001);
P
pbrook 已提交
4363 4364
                break;
            case 6: /* VABD */
P
pbrook 已提交
4365
                gen_helper_neon_abd_f32(CPU_T001);
P
pbrook 已提交
4366 4367 4368 4369 4370 4371
                break;
            default:
                return 1;
            }
            break;
        case 27: /* Float multiply.  */
P
pbrook 已提交
4372
            gen_helper_neon_mul_f32(CPU_T001);
P
pbrook 已提交
4373 4374 4375
            if (!u) {
                NEON_GET_REG(T1, rd, pass);
                if (size == 0) {
P
pbrook 已提交
4376
                    gen_helper_neon_add_f32(CPU_T001);
P
pbrook 已提交
4377
                } else {
P
pbrook 已提交
4378
                    gen_helper_neon_sub_f32(cpu_T[0], cpu_T[1], cpu_T[0]);
P
pbrook 已提交
4379 4380 4381 4382 4383
                }
            }
            break;
        case 28: /* Float compare.  */
            if (!u) {
P
pbrook 已提交
4384
                gen_helper_neon_ceq_f32(CPU_T001);
B
bellard 已提交
4385
            } else {
P
pbrook 已提交
4386
                if (size == 0)
P
pbrook 已提交
4387
                    gen_helper_neon_cge_f32(CPU_T001);
P
pbrook 已提交
4388
                else
P
pbrook 已提交
4389
                    gen_helper_neon_cgt_f32(CPU_T001);
B
bellard 已提交
4390
            }
B
bellard 已提交
4391
            break;
P
pbrook 已提交
4392 4393 4394 4395
        case 29: /* Float compare absolute.  */
            if (!u)
                return 1;
            if (size == 0)
P
pbrook 已提交
4396
                gen_helper_neon_acge_f32(CPU_T001);
P
pbrook 已提交
4397
            else
P
pbrook 已提交
4398
                gen_helper_neon_acgt_f32(CPU_T001);
B
bellard 已提交
4399
            break;
P
pbrook 已提交
4400 4401
        case 30: /* Float min/max.  */
            if (size == 0)
P
pbrook 已提交
4402
                gen_helper_neon_max_f32(CPU_T001);
P
pbrook 已提交
4403
            else
P
pbrook 已提交
4404
                gen_helper_neon_min_f32(CPU_T001);
P
pbrook 已提交
4405 4406 4407
            break;
        case 31:
            if (size == 0)
P
pbrook 已提交
4408
                gen_helper_recps_f32(cpu_T[0], cpu_T[0], cpu_T[1], cpu_env);
P
pbrook 已提交
4409
            else
P
pbrook 已提交
4410
                gen_helper_rsqrts_f32(cpu_T[0], cpu_T[0], cpu_T[1], cpu_env);
B
bellard 已提交
4411
            break;
P
pbrook 已提交
4412 4413
        default:
            abort();
B
bellard 已提交
4414
        }
P
pbrook 已提交
4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430
        /* 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) {
            gen_neon_movl_scratch_T0(pass);
        } else {
            NEON_SET_REG(T0, rd, pass);
        }

        } /* for pass */
        if (pairwise && rd == rm) {
            for (pass = 0; pass < (q ? 4 : 2); pass++) {
                gen_neon_movl_T0_scratch(pass);
                NEON_SET_REG(T0, rd, pass);
            }
        }
P
pbrook 已提交
4431
        /* End of 3 register same size operations.  */
P
pbrook 已提交
4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477
    } 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 已提交
4478 4479 4480 4481 4482 4483 4484 4485
                    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 已提交
4486
                            else
P
pbrook 已提交
4487
                                gen_helper_neon_shl_s64(cpu_V0, cpu_V0, cpu_V1);
P
pbrook 已提交
4488
                            break;
P
pbrook 已提交
4489 4490 4491 4492
                        case 2: /* VRSHR */
                        case 3: /* VRSRA */
                            if (u)
                                gen_helper_neon_rshl_u64(cpu_V0, cpu_V0, cpu_V1);
P
pbrook 已提交
4493
                            else
P
pbrook 已提交
4494
                                gen_helper_neon_rshl_s64(cpu_V0, cpu_V0, cpu_V1);
P
pbrook 已提交
4495
                            break;
P
pbrook 已提交
4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506
                        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 已提交
4507
                            else
P
pbrook 已提交
4508 4509 4510 4511
                                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 已提交
4512 4513
                            break;
                        }
P
pbrook 已提交
4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597
                        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.  */
                        gen_op_movl_T1_im(imm);
                        NEON_GET_REG(T0, rm, pass);
                        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) {
                            case 0: gen_helper_neon_shl_u8(CPU_T001); break;
                            case 1: gen_helper_neon_shl_u16(CPU_T001); break;
                            case 2: gen_helper_neon_shl_u32(CPU_T001); break;
                            default: return 1;
                            }
                            break;
                        case 6: /* VQSHL */
                            GEN_NEON_INTEGER_OP_ENV(qshl);
                            break;
                        case 7: /* VQSHLU */
                            switch (size) {
                            case 0: gen_helper_neon_qshl_u8(CPU_T0E01); break;
                            case 1: gen_helper_neon_qshl_u16(CPU_T0E01); break;
                            case 2: gen_helper_neon_qshl_u32(CPU_T0E01); break;
                            default: return 1;
                            }
                            break;
                        }

                        if (op == 1 || op == 3) {
                            /* Accumulate.  */
                            NEON_GET_REG(T1, rd, pass);
                            gen_neon_add(size);
                        } else if (op == 4 || (op == 5 && u)) {
                            /* Insert */
                            switch (size) {
                            case 0:
                                if (op == 4)
                                    imm = 0xff >> -shift;
                                else
                                    imm = (uint8_t)(0xff << shift);
                                imm |= imm << 8;
                                imm |= imm << 16;
                                break;
                            case 1:
                                if (op == 4)
                                    imm = 0xffff >> -shift;
                                else
                                    imm = (uint16_t)(0xffff << shift);
                                imm |= imm << 16;
                                break;
                            case 2:
                                if (op == 4)
                                    imm = 0xffffffffu >> -shift;
                                else
                                    imm = 0xffffffffu << shift;
                                break;
                            default:
                                abort();
                            }
                            tmp = neon_load_reg(rd, pass);
                            tcg_gen_andi_i32(cpu_T[0], cpu_T[0], imm);
                            tcg_gen_andi_i32(tmp, tmp, ~imm);
                            tcg_gen_or_i32(cpu_T[0], cpu_T[0], tmp);
                        }
P
pbrook 已提交
4598 4599 4600 4601
                        NEON_SET_REG(T0, rd, pass);
                    }
                } /* for pass */
            } else if (op < 10) {
P
pbrook 已提交
4602
                /* Shift by immediate and narrow:
P
pbrook 已提交
4603 4604 4605 4606 4607
                   VSHRN, VRSHRN, VQSHRN, VQRSHRN.  */
                shift = shift - (1 << (size + 3));
                size++;
                switch (size) {
                case 1:
P
pbrook 已提交
4608
                    imm = (uint16_t)shift;
P
pbrook 已提交
4609
                    imm |= imm << 16;
P
pbrook 已提交
4610
                    tmp2 = tcg_const_i32(imm);
P
pbrook 已提交
4611
                    TCGV_UNUSED_I64(tmp64);
P
pbrook 已提交
4612 4613
                    break;
                case 2:
P
pbrook 已提交
4614 4615
                    imm = (uint32_t)shift;
                    tmp2 = tcg_const_i32(imm);
P
pbrook 已提交
4616
                    TCGV_UNUSED_I64(tmp64);
4617
                    break;
P
pbrook 已提交
4618
                case 3:
P
pbrook 已提交
4619 4620
                    tmp64 = tcg_const_i64(shift);
                    TCGV_UNUSED(tmp2);
P
pbrook 已提交
4621 4622 4623 4624 4625
                    break;
                default:
                    abort();
                }

P
pbrook 已提交
4626 4627 4628 4629 4630
                for (pass = 0; pass < 2; pass++) {
                    if (size == 3) {
                        neon_load_reg64(cpu_V0, rm + pass);
                        if (q) {
                          if (u)
P
pbrook 已提交
4631
                            gen_helper_neon_rshl_u64(cpu_V0, cpu_V0, tmp64);
P
pbrook 已提交
4632
                          else
P
pbrook 已提交
4633
                            gen_helper_neon_rshl_s64(cpu_V0, cpu_V0, tmp64);
P
pbrook 已提交
4634 4635
                        } else {
                          if (u)
P
pbrook 已提交
4636
                            gen_helper_neon_shl_u64(cpu_V0, cpu_V0, tmp64);
P
pbrook 已提交
4637
                          else
P
pbrook 已提交
4638
                            gen_helper_neon_shl_s64(cpu_V0, cpu_V0, tmp64);
P
pbrook 已提交
4639
                        }
B
bellard 已提交
4640
                    } else {
P
pbrook 已提交
4641 4642
                        tmp = neon_load_reg(rm + pass, 0);
                        gen_neon_shift_narrow(size, tmp, tmp2, q, u);
P
pbrook 已提交
4643 4644 4645
                        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 已提交
4646
                        dead_tmp(tmp);
P
pbrook 已提交
4647
                        dead_tmp(tmp3);
P
pbrook 已提交
4648
                    }
P
pbrook 已提交
4649 4650 4651
                    tmp = new_tmp();
                    if (op == 8 && !u) {
                        gen_neon_narrow(size - 1, tmp, cpu_V0);
P
pbrook 已提交
4652
                    } else {
P
pbrook 已提交
4653 4654
                        if (op == 8)
                            gen_neon_narrow_sats(size - 1, tmp, cpu_V0);
P
pbrook 已提交
4655
                        else
P
pbrook 已提交
4656 4657 4658 4659 4660 4661 4662
                            gen_neon_narrow_satu(size - 1, tmp, cpu_V0);
                    }
                    if (pass == 0) {
                        tmp2 = tmp;
                    } else {
                        neon_store_reg(rd, 0, tmp2);
                        neon_store_reg(rd, 1, tmp);
P
pbrook 已提交
4663 4664 4665 4666
                    }
                } /* for pass */
            } else if (op == 10) {
                /* VSHLL */
P
pbrook 已提交
4667
                if (q || size == 3)
P
pbrook 已提交
4668
                    return 1;
P
pbrook 已提交
4669 4670
                tmp = neon_load_reg(rm, 0);
                tmp2 = neon_load_reg(rm, 1);
P
pbrook 已提交
4671
                for (pass = 0; pass < 2; pass++) {
P
pbrook 已提交
4672 4673 4674 4675
                    if (pass == 1)
                        tmp = tmp2;

                    gen_neon_widen(cpu_V0, tmp, size, u);
P
pbrook 已提交
4676 4677 4678

                    if (shift != 0) {
                        /* The shift is less than the width of the source
P
pbrook 已提交
4679 4680 4681 4682 4683 4684 4685 4686 4687
                           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 已提交
4688
                            }
P
pbrook 已提交
4689 4690
                            imm64 = imm | (((uint64_t)imm) << 32);
                            tcg_gen_andi_i64(cpu_V0, cpu_V0, imm64);
P
pbrook 已提交
4691 4692
                        }
                    }
P
pbrook 已提交
4693
                    neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
4694 4695 4696 4697
                }
            } else if (op == 15 || op == 16) {
                /* VCVT fixed-point.  */
                for (pass = 0; pass < (q ? 4 : 2); pass++) {
P
pbrook 已提交
4698
                    tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, pass));
P
pbrook 已提交
4699 4700
                    if (op & 1) {
                        if (u)
P
pbrook 已提交
4701
                            gen_vfp_ulto(0, shift);
P
pbrook 已提交
4702
                        else
P
pbrook 已提交
4703
                            gen_vfp_slto(0, shift);
P
pbrook 已提交
4704 4705
                    } else {
                        if (u)
P
pbrook 已提交
4706
                            gen_vfp_toul(0, shift);
P
pbrook 已提交
4707
                        else
P
pbrook 已提交
4708
                            gen_vfp_tosl(0, shift);
B
bellard 已提交
4709
                    }
P
pbrook 已提交
4710
                    tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, pass));
B
bellard 已提交
4711 4712
                }
            } else {
P
pbrook 已提交
4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764
                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:
                imm = (imm < 8) | 0xff;
                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;

            if (op != 14 || !invert)
                gen_op_movl_T1_im(imm);

            for (pass = 0; pass < (q ? 4 : 2); pass++) {
                if (op & 1 && op < 12) {
P
pbrook 已提交
4765
                    tmp = neon_load_reg(rd, pass);
P
pbrook 已提交
4766 4767 4768
                    if (invert) {
                        /* The immediate value has already been inverted, so
                           BIC becomes AND.  */
P
pbrook 已提交
4769
                        tcg_gen_andi_i32(tmp, tmp, imm);
P
pbrook 已提交
4770
                    } else {
P
pbrook 已提交
4771
                        tcg_gen_ori_i32(tmp, tmp, imm);
P
pbrook 已提交
4772 4773
                    }
                } else {
P
pbrook 已提交
4774 4775
                    /* VMOV, VMVN.  */
                    tmp = new_tmp();
P
pbrook 已提交
4776
                    if (op == 14 && invert) {
P
pbrook 已提交
4777 4778
                        uint32_t val;
                        val = 0;
P
pbrook 已提交
4779 4780
                        for (n = 0; n < 4; n++) {
                            if (imm & (1 << (n + (pass & 1) * 4)))
P
pbrook 已提交
4781
                                val |= 0xff << (n * 8);
P
pbrook 已提交
4782
                        }
P
pbrook 已提交
4783 4784 4785
                        tcg_gen_movi_i32(tmp, val);
                    } else {
                        tcg_gen_movi_i32(tmp, imm);
P
pbrook 已提交
4786 4787
                    }
                }
P
pbrook 已提交
4788
                neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
4789 4790
            }
        }
P
pbrook 已提交
4791
    } else { /* (insn & 0x00800010 == 0x00800000) */
P
pbrook 已提交
4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821
        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 已提交
4822 4823 4824
                if (size == 0 && (op == 9 || op == 11 || op == 13))
                    return 1;

P
pbrook 已提交
4825 4826 4827
                /* Avoid overlapping operands.  Wide source operands are
                   always aligned so will never overlap with wide
                   destinations in problematic ways.  */
P
pbrook 已提交
4828 4829 4830 4831 4832 4833
                if (rd == rm && !src2_wide) {
                    NEON_GET_REG(T0, rm, 1);
                    gen_neon_movl_scratch_T0(2);
                } else if (rd == rn && !src1_wide) {
                    NEON_GET_REG(T0, rn, 1);
                    gen_neon_movl_scratch_T0(2);
P
pbrook 已提交
4834
                }
P
pbrook 已提交
4835
                TCGV_UNUSED(tmp3);
P
pbrook 已提交
4836
                for (pass = 0; pass < 2; pass++) {
P
pbrook 已提交
4837 4838
                    if (src1_wide) {
                        neon_load_reg64(cpu_V0, rn + pass);
P
pbrook 已提交
4839
                        TCGV_UNUSED(tmp);
P
pbrook 已提交
4840
                    } else {
P
pbrook 已提交
4841 4842 4843 4844
                        if (pass == 1 && rd == rn) {
                            gen_neon_movl_T0_scratch(2);
                            tmp = new_tmp();
                            tcg_gen_mov_i32(tmp, cpu_T[0]);
P
pbrook 已提交
4845
                        } else {
P
pbrook 已提交
4846 4847 4848 4849
                            tmp = neon_load_reg(rn, pass);
                        }
                        if (prewiden) {
                            gen_neon_widen(cpu_V0, tmp, size, u);
P
pbrook 已提交
4850 4851
                        }
                    }
P
pbrook 已提交
4852 4853
                    if (src2_wide) {
                        neon_load_reg64(cpu_V1, rm + pass);
P
pbrook 已提交
4854
                        TCGV_UNUSED(tmp2);
P
pbrook 已提交
4855
                    } else {
P
pbrook 已提交
4856
                        if (pass == 1 && rd == rm) {
P
pbrook 已提交
4857
                            gen_neon_movl_T0_scratch(2);
P
pbrook 已提交
4858 4859
                            tmp2 = new_tmp();
                            tcg_gen_mov_i32(tmp2, cpu_T[0]);
P
pbrook 已提交
4860
                        } else {
P
pbrook 已提交
4861 4862 4863 4864
                            tmp2 = neon_load_reg(rm, pass);
                        }
                        if (prewiden) {
                            gen_neon_widen(cpu_V1, tmp2, size, u);
P
pbrook 已提交
4865 4866 4867 4868
                        }
                    }
                    switch (op) {
                    case 0: case 1: case 4: /* VADDL, VADDW, VADDHN, VRADDHN */
P
pbrook 已提交
4869
                        gen_neon_addl(size);
P
pbrook 已提交
4870 4871
                        break;
                    case 2: case 3: case 6: /* VSUBL, VSUBW, VSUBHL, VRSUBHL */
P
pbrook 已提交
4872
                        gen_neon_subl(size);
P
pbrook 已提交
4873 4874 4875
                        break;
                    case 5: case 7: /* VABAL, VABDL */
                        switch ((size << 1) | u) {
P
pbrook 已提交
4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893
                        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 已提交
4894 4895
                        default: abort();
                        }
P
pbrook 已提交
4896 4897
                        dead_tmp(tmp2);
                        dead_tmp(tmp);
P
pbrook 已提交
4898 4899 4900
                        break;
                    case 8: case 9: case 10: case 11: case 12: case 13:
                        /* VMLAL, VQDMLAL, VMLSL, VQDMLSL, VMULL, VQDMULL */
P
pbrook 已提交
4901
                        gen_neon_mull(cpu_V0, tmp, tmp2, size, u);
P
pbrook 已提交
4902 4903 4904 4905 4906 4907 4908 4909 4910 4911
                        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 已提交
4912
                            gen_neon_negl(cpu_V0, size);
P
pbrook 已提交
4913 4914 4915
                        }

                        if (op != 13) {
P
pbrook 已提交
4916
                            neon_load_reg64(cpu_V1, rd + pass);
P
pbrook 已提交
4917 4918 4919 4920
                        }

                        switch (op) {
                        case 5: case 8: case 10: /* VABAL, VMLAL, VMLSL */
P
pbrook 已提交
4921
                            gen_neon_addl(size);
P
pbrook 已提交
4922 4923
                            break;
                        case 9: case 11: /* VQDMLAL, VQDMLSL */
P
pbrook 已提交
4924 4925 4926
                            gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
                            gen_neon_addl_saturate(cpu_V0, cpu_V1, size);
                            break;
P
pbrook 已提交
4927 4928
                            /* Fall through.  */
                        case 13: /* VQDMULL */
P
pbrook 已提交
4929
                            gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
P
pbrook 已提交
4930 4931 4932 4933
                            break;
                        default:
                            abort();
                        }
P
pbrook 已提交
4934
                        neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
4935 4936
                    } else if (op == 4 || op == 6) {
                        /* Narrowing operation.  */
P
pbrook 已提交
4937
                        tmp = new_tmp();
P
pbrook 已提交
4938 4939
                        if (u) {
                            switch (size) {
P
pbrook 已提交
4940 4941 4942 4943 4944 4945 4946 4947 4948 4949
                            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 已提交
4950 4951 4952 4953
                            default: abort();
                            }
                        } else {
                            switch (size) {
P
pbrook 已提交
4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964
                            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 已提交
4965 4966 4967
                            default: abort();
                            }
                        }
P
pbrook 已提交
4968 4969 4970 4971 4972 4973
                        if (pass == 0) {
                            tmp3 = tmp;
                        } else {
                            neon_store_reg(rd, 0, tmp3);
                            neon_store_reg(rd, 1, tmp);
                        }
P
pbrook 已提交
4974 4975
                    } else {
                        /* Write back the result.  */
P
pbrook 已提交
4976
                        neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990
                    }
                }
            } 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 */
                    gen_neon_get_scalar(size, rm);
P
pbrook 已提交
4991
                    gen_neon_movl_scratch_T0(0);
P
pbrook 已提交
4992 4993
                    for (pass = 0; pass < (u ? 4 : 2); pass++) {
                        if (pass != 0)
P
pbrook 已提交
4994
                            gen_neon_movl_T0_scratch(0);
P
pbrook 已提交
4995 4996 4997
                        NEON_GET_REG(T1, rn, pass);
                        if (op == 12) {
                            if (size == 1) {
P
pbrook 已提交
4998
                                gen_helper_neon_qdmulh_s16(CPU_T0E01);
P
pbrook 已提交
4999
                            } else {
P
pbrook 已提交
5000
                                gen_helper_neon_qdmulh_s32(CPU_T0E01);
P
pbrook 已提交
5001 5002 5003
                            }
                        } else if (op == 13) {
                            if (size == 1) {
P
pbrook 已提交
5004
                                gen_helper_neon_qrdmulh_s16(CPU_T0E01);
P
pbrook 已提交
5005
                            } else {
P
pbrook 已提交
5006
                                gen_helper_neon_qrdmulh_s32(CPU_T0E01);
P
pbrook 已提交
5007 5008
                            }
                        } else if (op & 1) {
P
pbrook 已提交
5009
                            gen_helper_neon_mul_f32(CPU_T001);
P
pbrook 已提交
5010 5011
                        } else {
                            switch (size) {
P
pbrook 已提交
5012 5013
                            case 0: gen_helper_neon_mul_u8(CPU_T001); break;
                            case 1: gen_helper_neon_mul_u16(CPU_T001); break;
P
pbrook 已提交
5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025
                            case 2: gen_op_mul_T0_T1(); break;
                            default: return 1;
                            }
                        }
                        if (op < 8) {
                            /* Accumulate.  */
                            NEON_GET_REG(T1, rd, pass);
                            switch (op) {
                            case 0:
                                gen_neon_add(size);
                                break;
                            case 1:
P
pbrook 已提交
5026
                                gen_helper_neon_add_f32(CPU_T001);
P
pbrook 已提交
5027 5028
                                break;
                            case 4:
P
pbrook 已提交
5029
                                gen_neon_rsb(size);
P
pbrook 已提交
5030 5031
                                break;
                            case 5:
P
pbrook 已提交
5032
                                gen_helper_neon_sub_f32(cpu_T[0], cpu_T[1], cpu_T[0]);
P
pbrook 已提交
5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046
                                break;
                            default:
                                abort();
                            }
                        }
                        NEON_SET_REG(T0, rd, pass);
                    }
                    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 已提交
5047 5048 5049
                    if (size == 0 && (op == 3 || op == 7 || op == 11))
                        return 1;

P
pbrook 已提交
5050
                    gen_neon_get_scalar(size, rm);
P
pbrook 已提交
5051 5052
                    NEON_GET_REG(T1, rn, 1);

P
pbrook 已提交
5053
                    for (pass = 0; pass < 2; pass++) {
P
pbrook 已提交
5054 5055
                        if (pass == 0) {
                            tmp = neon_load_reg(rn, 0);
P
pbrook 已提交
5056
                        } else {
P
pbrook 已提交
5057 5058
                            tmp = new_tmp();
                            tcg_gen_mov_i32(tmp, cpu_T[1]);
P
pbrook 已提交
5059
                        }
P
pbrook 已提交
5060 5061 5062
                        tmp2 = new_tmp();
                        tcg_gen_mov_i32(tmp2, cpu_T[0]);
                        gen_neon_mull(cpu_V0, tmp, tmp2, size, u);
P
pbrook 已提交
5063
                        if (op == 6 || op == 7) {
P
pbrook 已提交
5064 5065 5066 5067
                            gen_neon_negl(cpu_V0, size);
                        }
                        if (op != 11) {
                            neon_load_reg64(cpu_V1, rd + pass);
P
pbrook 已提交
5068 5069 5070
                        }
                        switch (op) {
                        case 2: case 6:
P
pbrook 已提交
5071
                            gen_neon_addl(size);
P
pbrook 已提交
5072 5073
                            break;
                        case 3: case 7:
P
pbrook 已提交
5074 5075
                            gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
                            gen_neon_addl_saturate(cpu_V0, cpu_V1, size);
P
pbrook 已提交
5076 5077 5078 5079 5080
                            break;
                        case 10:
                            /* no-op */
                            break;
                        case 11:
P
pbrook 已提交
5081
                            gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
P
pbrook 已提交
5082 5083 5084 5085
                            break;
                        default:
                            abort();
                        }
P
pbrook 已提交
5086
                        neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
5087 5088 5089 5090 5091 5092 5093 5094 5095 5096
                    }
                    break;
                default: /* 14 and 15 are RESERVED */
                    return 1;
                }
            }
        } else { /* size == 3 */
            if (!u) {
                /* Extract.  */
                imm = (insn >> 8) & 0xf;
P
pbrook 已提交
5097 5098 5099 5100 5101 5102 5103 5104 5105
                count = q + 1;

                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 已提交
5106
                    }
P
pbrook 已提交
5107 5108 5109 5110
                } else if (imm == 8) {
                    neon_load_reg64(cpu_V0, rn + 1);
                    if (q) {
                        neon_load_reg64(cpu_V1, rm);
P
pbrook 已提交
5111
                    }
P
pbrook 已提交
5112
                } else if (q) {
P
pbrook 已提交
5113
                    tmp64 = tcg_temp_new_i64();
P
pbrook 已提交
5114 5115
                    if (imm < 8) {
                        neon_load_reg64(cpu_V0, rn);
P
pbrook 已提交
5116
                        neon_load_reg64(tmp64, rn + 1);
P
pbrook 已提交
5117 5118
                    } else {
                        neon_load_reg64(cpu_V0, rn + 1);
P
pbrook 已提交
5119
                        neon_load_reg64(tmp64, rm);
P
pbrook 已提交
5120 5121
                    }
                    tcg_gen_shri_i64(cpu_V0, cpu_V0, (imm & 7) * 8);
P
pbrook 已提交
5122
                    tcg_gen_shli_i64(cpu_V1, tmp64, 64 - ((imm & 7) * 8));
P
pbrook 已提交
5123 5124 5125
                    tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1);
                    if (imm < 8) {
                        neon_load_reg64(cpu_V1, rm);
P
pbrook 已提交
5126
                    } else {
P
pbrook 已提交
5127 5128
                        neon_load_reg64(cpu_V1, rm + 1);
                        imm -= 8;
P
pbrook 已提交
5129
                    }
P
pbrook 已提交
5130
                    tcg_gen_shli_i64(cpu_V1, cpu_V1, 64 - (imm * 8));
P
pbrook 已提交
5131 5132
                    tcg_gen_shri_i64(tmp64, tmp64, imm * 8);
                    tcg_gen_or_i64(cpu_V1, cpu_V1, tmp64);
P
pbrook 已提交
5133
                } else {
P
pbrook 已提交
5134
                    /* BUGFIX */
P
pbrook 已提交
5135
                    neon_load_reg64(cpu_V0, rn);
P
pbrook 已提交
5136
                    tcg_gen_shri_i64(cpu_V0, cpu_V0, imm * 8);
P
pbrook 已提交
5137
                    neon_load_reg64(cpu_V1, rm);
P
pbrook 已提交
5138
                    tcg_gen_shli_i64(cpu_V1, cpu_V1, 64 - (imm * 8));
P
pbrook 已提交
5139 5140 5141 5142 5143
                    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 已提交
5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156
                }
            } 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++) {
                        NEON_GET_REG(T0, rm, pass * 2);
                        NEON_GET_REG(T1, rm, pass * 2 + 1);
                        switch (size) {
A
aurel32 已提交
5157
                        case 0: tcg_gen_bswap32_i32(cpu_T[0], cpu_T[0]); break;
P
pbrook 已提交
5158
                        case 1: gen_swap_half(cpu_T[0]); break;
P
pbrook 已提交
5159 5160 5161 5162 5163 5164 5165 5166 5167
                        case 2: /* no-op */ break;
                        default: abort();
                        }
                        NEON_SET_REG(T0, rd, pass * 2 + 1);
                        if (size == 2) {
                            NEON_SET_REG(T1, rd, pass * 2);
                        } else {
                            gen_op_movl_T0_T1();
                            switch (size) {
A
aurel32 已提交
5168
                            case 0: tcg_gen_bswap32_i32(cpu_T[0], cpu_T[0]); break;
P
pbrook 已提交
5169
                            case 1: gen_swap_half(cpu_T[0]); break;
P
pbrook 已提交
5170 5171 5172 5173 5174 5175 5176 5177 5178 5179
                            default: abort();
                            }
                            NEON_SET_REG(T0, rd, pass * 2);
                        }
                    }
                    break;
                case 4: case 5: /* VPADDL */
                case 12: case 13: /* VPADAL */
                    if (size == 3)
                        return 1;
P
pbrook 已提交
5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190
                    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 已提交
5191 5192
                        if (op >= 12) {
                            /* Accumulate.  */
P
pbrook 已提交
5193 5194
                            neon_load_reg64(cpu_V1, rd + pass);
                            gen_neon_addl(size);
P
pbrook 已提交
5195
                        }
P
pbrook 已提交
5196
                        neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249
                    }
                    break;
                case 33: /* VTRN */
                    if (size == 2) {
                        for (n = 0; n < (q ? 4 : 2); n += 2) {
                            NEON_GET_REG(T0, rm, n);
                            NEON_GET_REG(T1, rd, n + 1);
                            NEON_SET_REG(T1, rm, n);
                            NEON_SET_REG(T0, rd, n + 1);
                        }
                    } 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;
                            gen_neon_movl_T0_scratch(unzip_order_q[n]);
                            NEON_SET_REG(T0, reg, n % 4);
                        }
                    } else {
                        static int unzip_order[4] =
                            {0, 4, 1, 5};
                        for (n = 0; n < 4; n++) {
                            int reg = (n < 2) ? rd : rm;
                            gen_neon_movl_T0_scratch(unzip_order[n]);
                            NEON_SET_REG(T0, reg, n % 2);
                        }
                    }
                    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++) {
                        NEON_GET_REG(T0, rd, n);
                        NEON_GET_REG(T1, rd, n);
                        switch (size) {
P
pbrook 已提交
5250 5251
                        case 0: gen_helper_neon_zip_u8(); break;
                        case 1: gen_helper_neon_zip_u16(); break;
P
pbrook 已提交
5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264
                        case 2: /* no-op */; break;
                        default: abort();
                        }
                        gen_neon_movl_scratch_T0(n * 2);
                        gen_neon_movl_scratch_T1(n * 2 + 1);
                    }
                    for (n = 0; n < count * 2; n++) {
                        int reg = (n < count) ? rd : rm;
                        gen_neon_movl_T0_scratch(n);
                        NEON_SET_REG(T0, reg, n % count);
                    }
                    break;
                case 36: case 37: /* VMOVN, VQMOVUN, VQMOVN */
P
pbrook 已提交
5265 5266
                    if (size == 3)
                        return 1;
P
pbrook 已提交
5267
                    TCGV_UNUSED(tmp2);
P
pbrook 已提交
5268
                    for (pass = 0; pass < 2; pass++) {
P
pbrook 已提交
5269 5270
                        neon_load_reg64(cpu_V0, rm + pass);
                        tmp = new_tmp();
P
pbrook 已提交
5271
                        if (op == 36 && q == 0) {
P
pbrook 已提交
5272
                            gen_neon_narrow(size, tmp, cpu_V0);
P
pbrook 已提交
5273
                        } else if (q) {
P
pbrook 已提交
5274
                            gen_neon_narrow_satu(size, tmp, cpu_V0);
P
pbrook 已提交
5275
                        } else {
P
pbrook 已提交
5276 5277 5278 5279 5280 5281 5282
                            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 已提交
5283 5284 5285 5286
                        }
                    }
                    break;
                case 38: /* VSHLL */
P
pbrook 已提交
5287
                    if (q || size == 3)
P
pbrook 已提交
5288
                        return 1;
P
pbrook 已提交
5289 5290
                    tmp = neon_load_reg(rm, 0);
                    tmp2 = neon_load_reg(rm, 1);
P
pbrook 已提交
5291
                    for (pass = 0; pass < 2; pass++) {
P
pbrook 已提交
5292 5293 5294 5295
                        if (pass == 1)
                            tmp = tmp2;
                        gen_neon_widen(cpu_V0, tmp, size, 1);
                        neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
5296 5297 5298 5299 5300 5301
                    }
                    break;
                default:
                elementwise:
                    for (pass = 0; pass < (q ? 4 : 2); pass++) {
                        if (op == 30 || op == 31 || op >= 58) {
P
pbrook 已提交
5302 5303
                            tcg_gen_ld_f32(cpu_F0s, cpu_env,
                                           neon_reg_offset(rm, pass));
P
pbrook 已提交
5304 5305 5306 5307 5308 5309
                        } else {
                            NEON_GET_REG(T0, rm, pass);
                        }
                        switch (op) {
                        case 1: /* VREV32 */
                            switch (size) {
A
aurel32 已提交
5310
                            case 0: tcg_gen_bswap32_i32(cpu_T[0], cpu_T[0]); break;
P
pbrook 已提交
5311
                            case 1: gen_swap_half(cpu_T[0]); break;
P
pbrook 已提交
5312 5313 5314 5315 5316 5317
                            default: return 1;
                            }
                            break;
                        case 2: /* VREV16 */
                            if (size != 0)
                                return 1;
P
pbrook 已提交
5318
                            gen_rev16(cpu_T[0]);
P
pbrook 已提交
5319 5320 5321
                            break;
                        case 8: /* CLS */
                            switch (size) {
P
pbrook 已提交
5322 5323 5324
                            case 0: gen_helper_neon_cls_s8(cpu_T[0], cpu_T[0]); break;
                            case 1: gen_helper_neon_cls_s16(cpu_T[0], cpu_T[0]); break;
                            case 2: gen_helper_neon_cls_s32(cpu_T[0], cpu_T[0]); break;
P
pbrook 已提交
5325 5326 5327 5328 5329
                            default: return 1;
                            }
                            break;
                        case 9: /* CLZ */
                            switch (size) {
P
pbrook 已提交
5330 5331
                            case 0: gen_helper_neon_clz_u8(cpu_T[0], cpu_T[0]); break;
                            case 1: gen_helper_neon_clz_u16(cpu_T[0], cpu_T[0]); break;
P
pbrook 已提交
5332
                            case 2: gen_helper_clz(cpu_T[0], cpu_T[0]); break;
P
pbrook 已提交
5333 5334 5335 5336 5337 5338
                            default: return 1;
                            }
                            break;
                        case 10: /* CNT */
                            if (size != 0)
                                return 1;
P
pbrook 已提交
5339
                            gen_helper_neon_cnt_u8(cpu_T[0], cpu_T[0]);
P
pbrook 已提交
5340 5341 5342 5343 5344 5345 5346 5347
                            break;
                        case 11: /* VNOT */
                            if (size != 0)
                                return 1;
                            gen_op_notl_T0();
                            break;
                        case 14: /* VQABS */
                            switch (size) {
P
pbrook 已提交
5348 5349 5350
                            case 0: gen_helper_neon_qabs_s8(cpu_T[0], cpu_env, cpu_T[0]); break;
                            case 1: gen_helper_neon_qabs_s16(cpu_T[0], cpu_env, cpu_T[0]); break;
                            case 2: gen_helper_neon_qabs_s32(cpu_T[0], cpu_env, cpu_T[0]); break;
P
pbrook 已提交
5351 5352 5353 5354 5355
                            default: return 1;
                            }
                            break;
                        case 15: /* VQNEG */
                            switch (size) {
P
pbrook 已提交
5356 5357 5358
                            case 0: gen_helper_neon_qneg_s8(cpu_T[0], cpu_env, cpu_T[0]); break;
                            case 1: gen_helper_neon_qneg_s16(cpu_T[0], cpu_env, cpu_T[0]); break;
                            case 2: gen_helper_neon_qneg_s32(cpu_T[0], cpu_env, cpu_T[0]); break;
P
pbrook 已提交
5359 5360 5361 5362 5363 5364
                            default: return 1;
                            }
                            break;
                        case 16: case 19: /* VCGT #0, VCLE #0 */
                            gen_op_movl_T1_im(0);
                            switch(size) {
P
pbrook 已提交
5365 5366 5367
                            case 0: gen_helper_neon_cgt_s8(CPU_T001); break;
                            case 1: gen_helper_neon_cgt_s16(CPU_T001); break;
                            case 2: gen_helper_neon_cgt_s32(CPU_T001); break;
P
pbrook 已提交
5368 5369 5370 5371 5372 5373 5374 5375
                            default: return 1;
                            }
                            if (op == 19)
                                gen_op_notl_T0();
                            break;
                        case 17: case 20: /* VCGE #0, VCLT #0 */
                            gen_op_movl_T1_im(0);
                            switch(size) {
P
pbrook 已提交
5376 5377 5378
                            case 0: gen_helper_neon_cge_s8(CPU_T001); break;
                            case 1: gen_helper_neon_cge_s16(CPU_T001); break;
                            case 2: gen_helper_neon_cge_s32(CPU_T001); break;
P
pbrook 已提交
5379 5380 5381 5382 5383 5384 5385 5386
                            default: return 1;
                            }
                            if (op == 20)
                                gen_op_notl_T0();
                            break;
                        case 18: /* VCEQ #0 */
                            gen_op_movl_T1_im(0);
                            switch(size) {
P
pbrook 已提交
5387 5388 5389
                            case 0: gen_helper_neon_ceq_u8(CPU_T001); break;
                            case 1: gen_helper_neon_ceq_u16(CPU_T001); break;
                            case 2: gen_helper_neon_ceq_u32(CPU_T001); break;
P
pbrook 已提交
5390 5391 5392 5393 5394
                            default: return 1;
                            }
                            break;
                        case 22: /* VABS */
                            switch(size) {
P
pbrook 已提交
5395 5396 5397
                            case 0: gen_helper_neon_abs_s8(cpu_T[0], cpu_T[0]); break;
                            case 1: gen_helper_neon_abs_s16(cpu_T[0], cpu_T[0]); break;
                            case 2: tcg_gen_abs_i32(cpu_T[0], cpu_T[0]); break;
P
pbrook 已提交
5398 5399 5400 5401 5402
                            default: return 1;
                            }
                            break;
                        case 23: /* VNEG */
                            gen_op_movl_T1_im(0);
P
pbrook 已提交
5403 5404 5405
                            if (size == 3)
                                return 1;
                            gen_neon_rsb(size);
P
pbrook 已提交
5406 5407 5408
                            break;
                        case 24: case 27: /* Float VCGT #0, Float VCLE #0 */
                            gen_op_movl_T1_im(0);
P
pbrook 已提交
5409
                            gen_helper_neon_cgt_f32(CPU_T001);
P
pbrook 已提交
5410 5411 5412 5413 5414
                            if (op == 27)
                                gen_op_notl_T0();
                            break;
                        case 25: case 28: /* Float VCGE #0, Float VCLT #0 */
                            gen_op_movl_T1_im(0);
P
pbrook 已提交
5415
                            gen_helper_neon_cge_f32(CPU_T001);
P
pbrook 已提交
5416 5417 5418 5419 5420
                            if (op == 28)
                                gen_op_notl_T0();
                            break;
                        case 26: /* Float VCEQ #0 */
                            gen_op_movl_T1_im(0);
P
pbrook 已提交
5421
                            gen_helper_neon_ceq_f32(CPU_T001);
P
pbrook 已提交
5422 5423
                            break;
                        case 30: /* Float VABS */
P
pbrook 已提交
5424
                            gen_vfp_abs(0);
P
pbrook 已提交
5425 5426
                            break;
                        case 31: /* Float VNEG */
P
pbrook 已提交
5427
                            gen_vfp_neg(0);
P
pbrook 已提交
5428 5429 5430 5431 5432 5433 5434 5435
                            break;
                        case 32: /* VSWP */
                            NEON_GET_REG(T1, rd, pass);
                            NEON_SET_REG(T1, rm, pass);
                            break;
                        case 33: /* VTRN */
                            NEON_GET_REG(T1, rd, pass);
                            switch (size) {
P
pbrook 已提交
5436 5437
                            case 0: gen_helper_neon_trn_u8(); break;
                            case 1: gen_helper_neon_trn_u16(); break;
P
pbrook 已提交
5438 5439 5440 5441 5442 5443
                            case 2: abort();
                            default: return 1;
                            }
                            NEON_SET_REG(T1, rm, pass);
                            break;
                        case 56: /* Integer VRECPE */
P
pbrook 已提交
5444
                            gen_helper_recpe_u32(cpu_T[0], cpu_T[0], cpu_env);
P
pbrook 已提交
5445 5446
                            break;
                        case 57: /* Integer VRSQRTE */
P
pbrook 已提交
5447
                            gen_helper_rsqrte_u32(cpu_T[0], cpu_T[0], cpu_env);
P
pbrook 已提交
5448 5449
                            break;
                        case 58: /* Float VRECPE */
P
pbrook 已提交
5450
                            gen_helper_recpe_f32(cpu_F0s, cpu_F0s, cpu_env);
P
pbrook 已提交
5451 5452
                            break;
                        case 59: /* Float VRSQRTE */
P
pbrook 已提交
5453
                            gen_helper_rsqrte_f32(cpu_F0s, cpu_F0s, cpu_env);
P
pbrook 已提交
5454 5455
                            break;
                        case 60: /* VCVT.F32.S32 */
P
pbrook 已提交
5456
                            gen_vfp_tosiz(0);
P
pbrook 已提交
5457 5458
                            break;
                        case 61: /* VCVT.F32.U32 */
P
pbrook 已提交
5459
                            gen_vfp_touiz(0);
P
pbrook 已提交
5460 5461
                            break;
                        case 62: /* VCVT.S32.F32 */
P
pbrook 已提交
5462
                            gen_vfp_sito(0);
P
pbrook 已提交
5463 5464
                            break;
                        case 63: /* VCVT.U32.F32 */
P
pbrook 已提交
5465
                            gen_vfp_uito(0);
P
pbrook 已提交
5466 5467 5468 5469 5470 5471
                            break;
                        default:
                            /* Reserved: 21, 29, 39-56 */
                            return 1;
                        }
                        if (op == 30 || op == 31 || op >= 58) {
P
pbrook 已提交
5472 5473
                            tcg_gen_st_f32(cpu_F0s, cpu_env,
                                           neon_reg_offset(rd, pass));
P
pbrook 已提交
5474 5475 5476 5477 5478 5479 5480 5481
                        } else {
                            NEON_SET_REG(T0, rd, pass);
                        }
                    }
                    break;
                }
            } else if ((insn & (1 << 10)) == 0) {
                /* VTBL, VTBX.  */
P
pbrook 已提交
5482
                n = ((insn >> 5) & 0x18) + 8;
P
pbrook 已提交
5483
                if (insn & (1 << 6)) {
P
pbrook 已提交
5484
                    tmp = neon_load_reg(rd, 0);
P
pbrook 已提交
5485
                } else {
P
pbrook 已提交
5486 5487
                    tmp = new_tmp();
                    tcg_gen_movi_i32(tmp, 0);
P
pbrook 已提交
5488
                }
P
pbrook 已提交
5489 5490 5491
                tmp2 = neon_load_reg(rm, 0);
                gen_helper_neon_tbl(tmp2, tmp2, tmp, tcg_const_i32(rn),
                                    tcg_const_i32(n));
P
pbrook 已提交
5492
                dead_tmp(tmp);
P
pbrook 已提交
5493
                if (insn & (1 << 6)) {
P
pbrook 已提交
5494
                    tmp = neon_load_reg(rd, 1);
P
pbrook 已提交
5495
                } else {
P
pbrook 已提交
5496 5497
                    tmp = new_tmp();
                    tcg_gen_movi_i32(tmp, 0);
P
pbrook 已提交
5498
                }
P
pbrook 已提交
5499 5500 5501 5502
                tmp3 = neon_load_reg(rm, 1);
                gen_helper_neon_tbl(tmp3, tmp3, tmp, tcg_const_i32(rn),
                                    tcg_const_i32(n));
                neon_store_reg(rd, 0, tmp2);
P
pbrook 已提交
5503 5504
                neon_store_reg(rd, 1, tmp3);
                dead_tmp(tmp);
P
pbrook 已提交
5505 5506 5507 5508 5509 5510 5511 5512
            } else if ((insn & 0x380) == 0) {
                /* VDUP */
                if (insn & (1 << 19)) {
                    NEON_SET_REG(T0, rm, 1);
                } else {
                    NEON_SET_REG(T0, rm, 0);
                }
                if (insn & (1 << 16)) {
P
pbrook 已提交
5513
                    gen_neon_dup_u8(cpu_T[0], ((insn >> 17) & 3) * 8);
P
pbrook 已提交
5514 5515
                } else if (insn & (1 << 17)) {
                    if ((insn >> 18) & 1)
P
pbrook 已提交
5516
                        gen_neon_dup_high16(cpu_T[0]);
P
pbrook 已提交
5517
                    else
P
pbrook 已提交
5518
                        gen_neon_dup_low16(cpu_T[0]);
P
pbrook 已提交
5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530
                }
                for (pass = 0; pass < (q ? 4 : 2); pass++) {
                    NEON_SET_REG(T0, rd, pass);
                }
            } else {
                return 1;
            }
        }
    }
    return 0;
}

5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595
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 已提交
5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616
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);
5617 5618 5619 5620 5621 5622 5623 5624 5625
    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 已提交
5626 5627 5628
    case 15:
	return disas_cp15_insn (env, s, insn);
    default:
5629
    board:
P
pbrook 已提交
5630 5631 5632 5633 5634
	/* Unknown coprocessor.  See if the board has hooked it.  */
	return disas_cp_insn (env, s, insn);
    }
}

P
pbrook 已提交
5635 5636

/* Store a 64-bit value to a register pair.  Clobbers val.  */
P
pbrook 已提交
5637
static void gen_storeq_reg(DisasContext *s, int rlow, int rhigh, TCGv_i64 val)
P
pbrook 已提交
5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649
{
    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 已提交
5650
static void gen_addq_lo(DisasContext *s, TCGv_i64 val, int rlow)
P
pbrook 已提交
5651
{
P
pbrook 已提交
5652
    TCGv_i64 tmp;
P
pbrook 已提交
5653 5654
    TCGv tmp2;

P
pbrook 已提交
5655
    /* Load value and extend to 64 bits.  */
P
pbrook 已提交
5656
    tmp = tcg_temp_new_i64();
P
pbrook 已提交
5657 5658 5659 5660 5661 5662 5663
    tmp2 = load_reg(s, rlow);
    tcg_gen_extu_i32_i64(tmp, tmp2);
    dead_tmp(tmp2);
    tcg_gen_add_i64(val, val, tmp);
}

/* load and add a 64-bit value from a register pair.  */
P
pbrook 已提交
5664
static void gen_addq(DisasContext *s, TCGv_i64 val, int rlow, int rhigh)
P
pbrook 已提交
5665
{
P
pbrook 已提交
5666
    TCGv_i64 tmp;
P
pbrook 已提交
5667 5668
    TCGv tmpl;
    TCGv tmph;
P
pbrook 已提交
5669 5670

    /* Load 64-bit value rd:rn.  */
P
pbrook 已提交
5671 5672
    tmpl = load_reg(s, rlow);
    tmph = load_reg(s, rhigh);
P
pbrook 已提交
5673
    tmp = tcg_temp_new_i64();
P
pbrook 已提交
5674 5675 5676
    tcg_gen_concat_i32_i64(tmp, tmpl, tmph);
    dead_tmp(tmpl);
    dead_tmp(tmph);
P
pbrook 已提交
5677 5678 5679 5680
    tcg_gen_add_i64(val, val, tmp);
}

/* Set N and Z flags from a 64-bit value.  */
P
pbrook 已提交
5681
static void gen_logicq_cc(TCGv_i64 val)
P
pbrook 已提交
5682 5683 5684
{
    TCGv tmp = new_tmp();
    gen_helper_logicq_cc(tmp, val);
P
pbrook 已提交
5685 5686
    gen_logic_CC(tmp);
    dead_tmp(tmp);
P
pbrook 已提交
5687 5688
}

P
pbrook 已提交
5689 5690 5691
static void disas_arm_insn(CPUState * env, DisasContext *s)
{
    unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;
P
pbrook 已提交
5692
    TCGv tmp;
P
pbrook 已提交
5693
    TCGv tmp2;
P
pbrook 已提交
5694
    TCGv tmp3;
P
pbrook 已提交
5695
    TCGv addr;
P
pbrook 已提交
5696
    TCGv_i64 tmp64;
P
pbrook 已提交
5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738

    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
pbrook 已提交
5739
                gen_helper_clrex(cpu_env);
P
pbrook 已提交
5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751
                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 */
5752
            int32_t offset;
P
pbrook 已提交
5753 5754 5755 5756 5757
            if (IS_USER(s))
                goto illegal_op;
            ARCH(6);
            op1 = (insn & 0x1f);
            if (op1 == (env->uncached_cpsr & CPSR_M)) {
P
pbrook 已提交
5758
                addr = load_reg(s, 13);
P
pbrook 已提交
5759
            } else {
P
pbrook 已提交
5760 5761
                addr = new_tmp();
                gen_helper_get_r13_banked(addr, cpu_env, tcg_const_i32(op1));
P
pbrook 已提交
5762 5763 5764 5765
            }
            i = (insn >> 23) & 3;
            switch (i) {
            case 0: offset = -4; break; /* DA */
5766 5767
            case 1: offset = 0; break; /* IA */
            case 2: offset = -8; break; /* DB */
P
pbrook 已提交
5768 5769 5770 5771
            case 3: offset = 4; break; /* IB */
            default: abort();
            }
            if (offset)
P
pbrook 已提交
5772 5773 5774
                tcg_gen_addi_i32(addr, addr, offset);
            tmp = load_reg(s, 14);
            gen_st32(tmp, addr, 0);
5775
            tmp = load_cpu_field(spsr);
P
pbrook 已提交
5776 5777
            tcg_gen_addi_i32(addr, addr, 4);
            gen_st32(tmp, addr, 0);
P
pbrook 已提交
5778 5779 5780 5781
            if (insn & (1 << 21)) {
                /* Base writeback.  */
                switch (i) {
                case 0: offset = -8; break;
5782 5783
                case 1: offset = 4; break;
                case 2: offset = -4; break;
P
pbrook 已提交
5784 5785 5786 5787
                case 3: offset = 0; break;
                default: abort();
                }
                if (offset)
5788
                    tcg_gen_addi_i32(addr, addr, offset);
P
pbrook 已提交
5789
                if (op1 == (env->uncached_cpsr & CPSR_M)) {
5790
                    store_reg(s, 13, addr);
P
pbrook 已提交
5791
                } else {
5792 5793
                    gen_helper_set_r13_banked(cpu_env, tcg_const_i32(op1), addr);
                    dead_tmp(addr);
P
pbrook 已提交
5794
                }
P
pbrook 已提交
5795 5796
            } else {
                dead_tmp(addr);
P
pbrook 已提交
5797 5798 5799
            }
        } else if ((insn & 0x0e5fffe0) == 0x081d0a00) {
            /* rfe */
5800
            int32_t offset;
P
pbrook 已提交
5801 5802 5803 5804
            if (IS_USER(s))
                goto illegal_op;
            ARCH(6);
            rn = (insn >> 16) & 0xf;
P
pbrook 已提交
5805
            addr = load_reg(s, rn);
P
pbrook 已提交
5806 5807
            i = (insn >> 23) & 3;
            switch (i) {
P
pbrook 已提交
5808
            case 0: offset = -4; break; /* DA */
5809 5810
            case 1: offset = 0; break; /* IA */
            case 2: offset = -8; break; /* DB */
P
pbrook 已提交
5811
            case 3: offset = 4; break; /* IB */
P
pbrook 已提交
5812 5813 5814
            default: abort();
            }
            if (offset)
P
pbrook 已提交
5815 5816 5817 5818 5819
                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 已提交
5820 5821 5822
            if (insn & (1 << 21)) {
                /* Base writeback.  */
                switch (i) {
P
pbrook 已提交
5823
                case 0: offset = -8; break;
5824 5825
                case 1: offset = 4; break;
                case 2: offset = -4; break;
P
pbrook 已提交
5826
                case 3: offset = 0; break;
P
pbrook 已提交
5827 5828 5829
                default: abort();
                }
                if (offset)
P
pbrook 已提交
5830 5831 5832 5833
                    tcg_gen_addi_i32(addr, addr, offset);
                store_reg(s, rn, addr);
            } else {
                dead_tmp(addr);
P
pbrook 已提交
5834
            }
P
pbrook 已提交
5835
            gen_rfe(s, tmp, tmp2);
5836
            return;
P
pbrook 已提交
5837 5838 5839 5840 5841
        } else if ((insn & 0x0e000000) == 0x0a000000) {
            /* branch link and change to thumb (blx <offset>) */
            int32_t offset;

            val = (uint32_t)s->pc;
P
pbrook 已提交
5842 5843 5844
            tmp = new_tmp();
            tcg_gen_movi_i32(tmp, val);
            store_reg(s, 14, tmp);
P
pbrook 已提交
5845 5846 5847 5848 5849 5850
            /* 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 已提交
5851
            gen_bx_im(s, val);
P
pbrook 已提交
5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863
            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 已提交
5864
        } else if ((insn & 0x0ff10020) == 0x01000000) {
P
pbrook 已提交
5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880
            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 已提交
5881
            if (insn & (1 << 17)) {
P
pbrook 已提交
5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896
                mask |= CPSR_M;
                val |= (insn & 0x1f);
            }
            if (mask) {
                gen_op_movl_T0_im(val);
                gen_set_psr_T0(s, mask, 0);
            }
            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 已提交
5897
        gen_test_cc(cond ^ 1, s->condlabel);
P
pbrook 已提交
5898 5899 5900 5901 5902 5903 5904 5905 5906
        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 已提交
5907 5908
                tmp = new_tmp();
                tcg_gen_movi_i32(tmp, val);
P
pbrook 已提交
5909 5910
            } else {
                /* MOVT */
P
pbrook 已提交
5911
                tmp = load_reg(s, rd);
P
pbrook 已提交
5912
                tcg_gen_ext16u_i32(tmp, tmp);
P
pbrook 已提交
5913
                tcg_gen_ori_i32(tmp, tmp, val << 16);
P
pbrook 已提交
5914
            }
P
pbrook 已提交
5915
            store_reg(s, rd, tmp);
P
pbrook 已提交
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
        } 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));
                gen_op_movl_T0_im(val);
                i = ((insn & (1 << 22)) != 0);
                if (gen_set_psr_T0(s, msr_mask(env, s, (insn >> 16) & 0xf, i), i))
                    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 */
                gen_movl_T0_reg(s, rm);
                i = ((op1 & 2) != 0);
                if (gen_set_psr_T0(s, msr_mask(env, s, (insn >> 16) & 0xf, i), i))
                    goto illegal_op;
            } else {
                /* reg = PSR */
                rd = (insn >> 12) & 0xf;
                if (op1 & 2) {
                    if (IS_USER(s))
                        goto illegal_op;
P
pbrook 已提交
5953
                    tmp = load_cpu_field(spsr);
P
pbrook 已提交
5954
                } else {
P
pbrook 已提交
5955 5956
                    tmp = new_tmp();
                    gen_helper_cpsr_read(tmp);
P
pbrook 已提交
5957
                }
P
pbrook 已提交
5958
                store_reg(s, rd, tmp);
P
pbrook 已提交
5959 5960 5961 5962 5963
            }
            break;
        case 0x1:
            if (op1 == 1) {
                /* branch/exchange thumb (bx).  */
P
pbrook 已提交
5964 5965
                tmp = load_reg(s, rm);
                gen_bx(s, tmp);
P
pbrook 已提交
5966 5967 5968
            } else if (op1 == 3) {
                /* clz */
                rd = (insn >> 12) & 0xf;
P
pbrook 已提交
5969 5970 5971
                tmp = load_reg(s, rm);
                gen_helper_clz(tmp, tmp);
                store_reg(s, rd, tmp);
P
pbrook 已提交
5972 5973 5974 5975 5976 5977 5978 5979
            } else {
                goto illegal_op;
            }
            break;
        case 0x2:
            if (op1 == 1) {
                ARCH(5J); /* bxj */
                /* Trivial implementation equivalent to bx.  */
P
pbrook 已提交
5980 5981
                tmp = load_reg(s, rm);
                gen_bx(s, tmp);
P
pbrook 已提交
5982 5983 5984 5985 5986 5987 5988 5989 5990
            } else {
                goto illegal_op;
            }
            break;
        case 0x3:
            if (op1 != 1)
              goto illegal_op;

            /* branch link/exchange thumb (blx) */
P
pbrook 已提交
5991 5992 5993 5994 5995
            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 已提交
5996 5997 5998 5999
            break;
        case 0x5: /* saturating add/subtract */
            rd = (insn >> 12) & 0xf;
            rn = (insn >> 16) & 0xf;
6000
            tmp = load_reg(s, rm);
P
pbrook 已提交
6001
            tmp2 = load_reg(s, rn);
P
pbrook 已提交
6002
            if (op1 & 2)
P
pbrook 已提交
6003
                gen_helper_double_saturate(tmp2, tmp2);
P
pbrook 已提交
6004
            if (op1 & 1)
P
pbrook 已提交
6005
                gen_helper_sub_saturate(tmp, tmp, tmp2);
P
pbrook 已提交
6006
            else
P
pbrook 已提交
6007 6008 6009
                gen_helper_add_saturate(tmp, tmp, tmp2);
            dead_tmp(tmp2);
            store_reg(s, rd, tmp);
P
pbrook 已提交
6010 6011 6012
            break;
        case 7: /* bkpt */
            gen_set_condexec(s);
P
pbrook 已提交
6013
            gen_set_pc_im(s->pc - 4);
P
pbrook 已提交
6014
            gen_exception(EXCP_BKPT);
P
pbrook 已提交
6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025
            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 已提交
6026 6027
                tmp = load_reg(s, rm);
                tmp2 = load_reg(s, rs);
P
pbrook 已提交
6028
                if (sh & 4)
P
pbrook 已提交
6029
                    tcg_gen_sari_i32(tmp2, tmp2, 16);
P
pbrook 已提交
6030
                else
P
pbrook 已提交
6031
                    gen_sxth(tmp2);
P
pbrook 已提交
6032 6033
                tmp64 = gen_muls_i64_i32(tmp, tmp2);
                tcg_gen_shri_i64(tmp64, tmp64, 16);
P
pbrook 已提交
6034
                tmp = new_tmp();
P
pbrook 已提交
6035
                tcg_gen_trunc_i64_i32(tmp, tmp64);
P
pbrook 已提交
6036
                if ((sh & 2) == 0) {
P
pbrook 已提交
6037 6038 6039
                    tmp2 = load_reg(s, rn);
                    gen_helper_add_setq(tmp, tmp, tmp2);
                    dead_tmp(tmp2);
P
pbrook 已提交
6040
                }
P
pbrook 已提交
6041
                store_reg(s, rd, tmp);
P
pbrook 已提交
6042 6043
            } else {
                /* 16 * 16 */
P
pbrook 已提交
6044 6045 6046 6047
                tmp = load_reg(s, rm);
                tmp2 = load_reg(s, rs);
                gen_mulxy(tmp, tmp2, sh & 2, sh & 4);
                dead_tmp(tmp2);
P
pbrook 已提交
6048
                if (op1 == 2) {
P
pbrook 已提交
6049 6050
                    tmp64 = tcg_temp_new_i64();
                    tcg_gen_ext_i32_i64(tmp64, tmp);
6051
                    dead_tmp(tmp);
P
pbrook 已提交
6052 6053
                    gen_addq(s, tmp64, rn, rd);
                    gen_storeq_reg(s, rn, rd, tmp64);
P
pbrook 已提交
6054 6055
                } else {
                    if (op1 == 0) {
P
pbrook 已提交
6056 6057 6058
                        tmp2 = load_reg(s, rn);
                        gen_helper_add_setq(tmp, tmp, tmp2);
                        dead_tmp(tmp2);
P
pbrook 已提交
6059
                    }
P
pbrook 已提交
6060
                    store_reg(s, rd, tmp);
P
pbrook 已提交
6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080
                }
            }
            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;
6081
            if (shift) {
P
pbrook 已提交
6082
                val = (val >> shift) | (val << (32 - shift));
6083 6084 6085 6086 6087 6088
            }
            tmp2 = new_tmp();
            tcg_gen_movi_i32(tmp2, val);
            if (logic_cc && shift) {
                gen_set_CF_bit31(tmp2);
            }
P
pbrook 已提交
6089 6090 6091
        } else {
            /* register */
            rm = (insn) & 0xf;
6092
            tmp2 = load_reg(s, rm);
P
pbrook 已提交
6093 6094 6095
            shiftop = (insn >> 5) & 3;
            if (!(insn & (1 << 4))) {
                shift = (insn >> 7) & 0x1f;
6096
                gen_arm_shift_im(tmp2, shiftop, shift, logic_cc);
P
pbrook 已提交
6097 6098
            } else {
                rs = (insn >> 8) & 0xf;
P
pbrook 已提交
6099
                tmp = load_reg(s, rs);
6100
                gen_arm_shift_reg(tmp2, shiftop, tmp, logic_cc);
P
pbrook 已提交
6101 6102 6103 6104
            }
        }
        if (op1 != 0x0f && op1 != 0x0d) {
            rn = (insn >> 16) & 0xf;
6105 6106 6107
            tmp = load_reg(s, rn);
        } else {
            TCGV_UNUSED(tmp);
P
pbrook 已提交
6108 6109 6110 6111
        }
        rd = (insn >> 12) & 0xf;
        switch(op1) {
        case 0x00:
6112 6113 6114 6115
            tcg_gen_and_i32(tmp, tmp, tmp2);
            if (logic_cc) {
                gen_logic_CC(tmp);
            }
6116
            store_reg_bx(env, s, rd, tmp);
P
pbrook 已提交
6117 6118
            break;
        case 0x01:
6119 6120 6121 6122
            tcg_gen_xor_i32(tmp, tmp, tmp2);
            if (logic_cc) {
                gen_logic_CC(tmp);
            }
6123
            store_reg_bx(env, s, rd, tmp);
P
pbrook 已提交
6124 6125 6126 6127
            break;
        case 0x02:
            if (set_cc && rd == 15) {
                /* SUBS r15, ... is used for exception return.  */
6128
                if (IS_USER(s)) {
P
pbrook 已提交
6129
                    goto illegal_op;
6130 6131 6132
                }
                gen_helper_sub_cc(tmp, tmp, tmp2);
                gen_exception_return(s, tmp);
P
pbrook 已提交
6133
            } else {
6134 6135 6136 6137 6138
                if (set_cc) {
                    gen_helper_sub_cc(tmp, tmp, tmp2);
                } else {
                    tcg_gen_sub_i32(tmp, tmp, tmp2);
                }
6139
                store_reg_bx(env, s, rd, tmp);
P
pbrook 已提交
6140 6141 6142
            }
            break;
        case 0x03:
6143 6144 6145 6146 6147
            if (set_cc) {
                gen_helper_sub_cc(tmp, tmp2, tmp);
            } else {
                tcg_gen_sub_i32(tmp, tmp2, tmp);
            }
6148
            store_reg_bx(env, s, rd, tmp);
P
pbrook 已提交
6149 6150
            break;
        case 0x04:
6151 6152 6153 6154 6155
            if (set_cc) {
                gen_helper_add_cc(tmp, tmp, tmp2);
            } else {
                tcg_gen_add_i32(tmp, tmp, tmp2);
            }
6156
            store_reg_bx(env, s, rd, tmp);
P
pbrook 已提交
6157 6158
            break;
        case 0x05:
6159 6160 6161 6162 6163
            if (set_cc) {
                gen_helper_adc_cc(tmp, tmp, tmp2);
            } else {
                gen_add_carry(tmp, tmp, tmp2);
            }
6164
            store_reg_bx(env, s, rd, tmp);
P
pbrook 已提交
6165 6166
            break;
        case 0x06:
6167 6168 6169 6170 6171
            if (set_cc) {
                gen_helper_sbc_cc(tmp, tmp, tmp2);
            } else {
                gen_sub_carry(tmp, tmp, tmp2);
            }
6172
            store_reg_bx(env, s, rd, tmp);
P
pbrook 已提交
6173 6174
            break;
        case 0x07:
6175 6176 6177 6178 6179
            if (set_cc) {
                gen_helper_sbc_cc(tmp, tmp2, tmp);
            } else {
                gen_sub_carry(tmp, tmp2, tmp);
            }
6180
            store_reg_bx(env, s, rd, tmp);
P
pbrook 已提交
6181 6182 6183
            break;
        case 0x08:
            if (set_cc) {
6184 6185
                tcg_gen_and_i32(tmp, tmp, tmp2);
                gen_logic_CC(tmp);
P
pbrook 已提交
6186
            }
6187
            dead_tmp(tmp);
P
pbrook 已提交
6188 6189 6190
            break;
        case 0x09:
            if (set_cc) {
6191 6192
                tcg_gen_xor_i32(tmp, tmp, tmp2);
                gen_logic_CC(tmp);
P
pbrook 已提交
6193
            }
6194
            dead_tmp(tmp);
P
pbrook 已提交
6195 6196 6197
            break;
        case 0x0a:
            if (set_cc) {
6198
                gen_helper_sub_cc(tmp, tmp, tmp2);
P
pbrook 已提交
6199
            }
6200
            dead_tmp(tmp);
P
pbrook 已提交
6201 6202 6203
            break;
        case 0x0b:
            if (set_cc) {
6204
                gen_helper_add_cc(tmp, tmp, tmp2);
P
pbrook 已提交
6205
            }
6206
            dead_tmp(tmp);
P
pbrook 已提交
6207 6208
            break;
        case 0x0c:
6209 6210 6211 6212
            tcg_gen_or_i32(tmp, tmp, tmp2);
            if (logic_cc) {
                gen_logic_CC(tmp);
            }
6213
            store_reg_bx(env, s, rd, tmp);
P
pbrook 已提交
6214 6215 6216 6217
            break;
        case 0x0d:
            if (logic_cc && rd == 15) {
                /* MOVS r15, ... is used for exception return.  */
6218
                if (IS_USER(s)) {
P
pbrook 已提交
6219
                    goto illegal_op;
6220 6221
                }
                gen_exception_return(s, tmp2);
P
pbrook 已提交
6222
            } else {
6223 6224 6225
                if (logic_cc) {
                    gen_logic_CC(tmp2);
                }
6226
                store_reg_bx(env, s, rd, tmp2);
P
pbrook 已提交
6227 6228 6229
            }
            break;
        case 0x0e:
6230 6231 6232 6233
            tcg_gen_bic_i32(tmp, tmp, tmp2);
            if (logic_cc) {
                gen_logic_CC(tmp);
            }
6234
            store_reg_bx(env, s, rd, tmp);
P
pbrook 已提交
6235 6236 6237
            break;
        default:
        case 0x0f:
6238 6239 6240 6241
            tcg_gen_not_i32(tmp2, tmp2);
            if (logic_cc) {
                gen_logic_CC(tmp2);
            }
6242
            store_reg_bx(env, s, rd, tmp2);
P
pbrook 已提交
6243 6244
            break;
        }
6245 6246 6247
        if (op1 != 0x0f && op1 != 0x0d) {
            dead_tmp(tmp2);
        }
P
pbrook 已提交
6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265
    } 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 已提交
6266 6267 6268 6269
                        tmp = load_reg(s, rs);
                        tmp2 = load_reg(s, rm);
                        tcg_gen_mul_i32(tmp, tmp, tmp2);
                        dead_tmp(tmp2);
P
pbrook 已提交
6270 6271 6272
                        if (insn & (1 << 22)) {
                            /* Subtract (mls) */
                            ARCH(6T2);
P
pbrook 已提交
6273 6274 6275
                            tmp2 = load_reg(s, rn);
                            tcg_gen_sub_i32(tmp, tmp2, tmp);
                            dead_tmp(tmp2);
P
pbrook 已提交
6276 6277
                        } else if (insn & (1 << 21)) {
                            /* Add */
P
pbrook 已提交
6278 6279 6280
                            tmp2 = load_reg(s, rn);
                            tcg_gen_add_i32(tmp, tmp, tmp2);
                            dead_tmp(tmp2);
P
pbrook 已提交
6281 6282
                        }
                        if (insn & (1 << 20))
P
pbrook 已提交
6283 6284
                            gen_logic_CC(tmp);
                        store_reg(s, rd, tmp);
P
pbrook 已提交
6285 6286 6287
                        break;
                    default:
                        /* 64 bit mul */
P
pbrook 已提交
6288 6289
                        tmp = load_reg(s, rs);
                        tmp2 = load_reg(s, rm);
P
pbrook 已提交
6290
                        if (insn & (1 << 22))
P
pbrook 已提交
6291
                            tmp64 = gen_muls_i64_i32(tmp, tmp2);
P
pbrook 已提交
6292
                        else
P
pbrook 已提交
6293
                            tmp64 = gen_mulu_i64_i32(tmp, tmp2);
P
pbrook 已提交
6294
                        if (insn & (1 << 21)) /* mult accumulate */
P
pbrook 已提交
6295
                            gen_addq(s, tmp64, rn, rd);
P
pbrook 已提交
6296 6297
                        if (!(insn & (1 << 23))) { /* double accumulate */
                            ARCH(6);
P
pbrook 已提交
6298 6299
                            gen_addq_lo(s, tmp64, rn);
                            gen_addq_lo(s, tmp64, rd);
P
pbrook 已提交
6300 6301
                        }
                        if (insn & (1 << 20))
P
pbrook 已提交
6302 6303
                            gen_logicq_cc(tmp64);
                        gen_storeq_reg(s, rn, rd, tmp64);
P
pbrook 已提交
6304 6305 6306 6307 6308 6309 6310
                        break;
                    }
                } else {
                    rn = (insn >> 16) & 0xf;
                    rd = (insn >> 12) & 0xf;
                    if (insn & (1 << 23)) {
                        /* load/store exclusive */
P
pbrook 已提交
6311 6312
                        op1 = (insn >> 21) & 0x3;
                        if (op1)
6313
                            ARCH(6K);
P
pbrook 已提交
6314 6315
                        else
                            ARCH(6);
P
pbrook 已提交
6316
                        gen_movl_T1_reg(s, rn);
B
balrog 已提交
6317
                        addr = cpu_T[1];
P
pbrook 已提交
6318
                        if (insn & (1 << 20)) {
P
pbrook 已提交
6319
                            gen_helper_mark_exclusive(cpu_env, cpu_T[1]);
P
pbrook 已提交
6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339
                            switch (op1) {
                            case 0: /* ldrex */
                                tmp = gen_ld32(addr, IS_USER(s));
                                break;
                            case 1: /* ldrexd */
                                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));
                                rd++;
                                break;
                            case 2: /* ldrexb */
                                tmp = gen_ld8u(addr, IS_USER(s));
                                break;
                            case 3: /* ldrexh */
                                tmp = gen_ld16u(addr, IS_USER(s));
                                break;
                            default:
                                abort();
                            }
P
pbrook 已提交
6340
                            store_reg(s, rd, tmp);
P
pbrook 已提交
6341
                        } else {
P
pbrook 已提交
6342
                            int label = gen_new_label();
P
pbrook 已提交
6343
                            rm = insn & 0xf;
P
pbrook 已提交
6344
                            gen_helper_test_exclusive(cpu_T[0], cpu_env, addr);
P
pbrook 已提交
6345 6346
                            tcg_gen_brcondi_i32(TCG_COND_NE, cpu_T[0],
                                                0, label);
P
pbrook 已提交
6347
                            tmp = load_reg(s,rm);
P
pbrook 已提交
6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366
                            switch (op1) {
                            case 0:  /*  strex */
                                gen_st32(tmp, addr, IS_USER(s));
                                break;
                            case 1: /*  strexd */
                                gen_st32(tmp, addr, IS_USER(s));
                                tcg_gen_addi_i32(addr, addr, 4);
                                tmp = load_reg(s, rm + 1);
                                gen_st32(tmp, addr, IS_USER(s));
                                break;
                            case 2: /*  strexb */
                                gen_st8(tmp, addr, IS_USER(s));
                                break;
                            case 3: /* strexh */
                                gen_st16(tmp, addr, IS_USER(s));
                                break;
                            default:
                                abort();
                            }
B
balrog 已提交
6367
                            gen_set_label(label);
P
pbrook 已提交
6368
                            gen_movl_reg_T0(s, rd);
P
pbrook 已提交
6369 6370 6371 6372 6373
                        }
                    } else {
                        /* SWP instruction */
                        rm = (insn) & 0xf;

P
pbrook 已提交
6374 6375 6376 6377 6378
                        /* ??? 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 已提交
6379
                        if (insn & (1 << 22)) {
P
pbrook 已提交
6380 6381
                            tmp2 = gen_ld8u(addr, IS_USER(s));
                            gen_st8(tmp, addr, IS_USER(s));
P
pbrook 已提交
6382
                        } else {
P
pbrook 已提交
6383 6384
                            tmp2 = gen_ld32(addr, IS_USER(s));
                            gen_st32(tmp, addr, IS_USER(s));
P
pbrook 已提交
6385
                        }
P
pbrook 已提交
6386 6387
                        dead_tmp(addr);
                        store_reg(s, rd, tmp2);
P
pbrook 已提交
6388 6389 6390 6391 6392 6393 6394 6395
                    }
                }
            } else {
                int address_offset;
                int load;
                /* Misc load/store */
                rn = (insn >> 16) & 0xf;
                rd = (insn >> 12) & 0xf;
P
pbrook 已提交
6396
                addr = load_reg(s, rn);
P
pbrook 已提交
6397
                if (insn & (1 << 24))
P
pbrook 已提交
6398
                    gen_add_datah_offset(s, insn, 0, addr);
P
pbrook 已提交
6399 6400 6401 6402 6403
                address_offset = 0;
                if (insn & (1 << 20)) {
                    /* load */
                    switch(sh) {
                    case 1:
P
pbrook 已提交
6404
                        tmp = gen_ld16u(addr, IS_USER(s));
P
pbrook 已提交
6405 6406
                        break;
                    case 2:
P
pbrook 已提交
6407
                        tmp = gen_ld8s(addr, IS_USER(s));
P
pbrook 已提交
6408 6409 6410
                        break;
                    default:
                    case 3:
P
pbrook 已提交
6411
                        tmp = gen_ld16s(addr, IS_USER(s));
P
pbrook 已提交
6412 6413 6414 6415 6416 6417 6418
                        break;
                    }
                    load = 1;
                } else if (sh & 2) {
                    /* doubleword */
                    if (sh & 1) {
                        /* store */
P
pbrook 已提交
6419 6420 6421 6422 6423
                        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 已提交
6424 6425 6426
                        load = 0;
                    } else {
                        /* load */
P
pbrook 已提交
6427 6428 6429 6430
                        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 已提交
6431 6432 6433 6434 6435 6436
                        rd++;
                        load = 1;
                    }
                    address_offset = -4;
                } else {
                    /* store */
P
pbrook 已提交
6437 6438
                    tmp = load_reg(s, rd);
                    gen_st16(tmp, addr, IS_USER(s));
P
pbrook 已提交
6439 6440 6441 6442 6443 6444 6445
                    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 已提交
6446 6447
                    gen_add_datah_offset(s, insn, address_offset, addr);
                    store_reg(s, rn, addr);
P
pbrook 已提交
6448 6449
                } else if (insn & (1 << 21)) {
                    if (address_offset)
P
pbrook 已提交
6450 6451 6452 6453
                        tcg_gen_addi_i32(addr, addr, address_offset);
                    store_reg(s, rn, addr);
                } else {
                    dead_tmp(addr);
P
pbrook 已提交
6454 6455 6456
                }
                if (load) {
                    /* Complete the load.  */
P
pbrook 已提交
6457
                    store_reg(s, rd, tmp);
P
pbrook 已提交
6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470
                }
            }
            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 已提交
6471
                rd = (insn >> 12) & 0xf;
P
pbrook 已提交
6472 6473 6474 6475
                rs = (insn >> 8) & 0xf;
                switch ((insn >> 23) & 3) {
                case 0: /* Parallel add/subtract.  */
                    op1 = (insn >> 20) & 7;
P
pbrook 已提交
6476 6477
                    tmp = load_reg(s, rn);
                    tmp2 = load_reg(s, rm);
P
pbrook 已提交
6478 6479 6480
                    sh = (insn >> 5) & 7;
                    if ((op1 & 3) == 0 || sh == 5 || sh == 6)
                        goto illegal_op;
P
pbrook 已提交
6481 6482 6483
                    gen_arm_parallel_addsub(op1, sh, tmp, tmp2);
                    dead_tmp(tmp2);
                    store_reg(s, rd, tmp);
P
pbrook 已提交
6484 6485 6486
                    break;
                case 1:
                    if ((insn & 0x00700020) == 0) {
B
balrog 已提交
6487
                        /* Halfword pack.  */
P
pbrook 已提交
6488 6489
                        tmp = load_reg(s, rn);
                        tmp2 = load_reg(s, rm);
P
pbrook 已提交
6490
                        shift = (insn >> 7) & 0x1f;
P
pbrook 已提交
6491 6492
                        if (insn & (1 << 6)) {
                            /* pkhtb */
6493 6494 6495
                            if (shift == 0)
                                shift = 31;
                            tcg_gen_sari_i32(tmp2, tmp2, shift);
P
pbrook 已提交
6496
                            tcg_gen_andi_i32(tmp, tmp, 0xffff0000);
P
pbrook 已提交
6497
                            tcg_gen_ext16u_i32(tmp2, tmp2);
P
pbrook 已提交
6498 6499
                        } else {
                            /* pkhbt */
6500 6501
                            if (shift)
                                tcg_gen_shli_i32(tmp2, tmp2, shift);
P
pbrook 已提交
6502
                            tcg_gen_ext16u_i32(tmp, tmp);
P
pbrook 已提交
6503 6504 6505
                            tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000);
                        }
                        tcg_gen_or_i32(tmp, tmp, tmp2);
6506
                        dead_tmp(tmp2);
P
pbrook 已提交
6507
                        store_reg(s, rd, tmp);
P
pbrook 已提交
6508 6509
                    } else if ((insn & 0x00200020) == 0x00200000) {
                        /* [us]sat */
P
pbrook 已提交
6510
                        tmp = load_reg(s, rm);
P
pbrook 已提交
6511 6512 6513 6514
                        shift = (insn >> 7) & 0x1f;
                        if (insn & (1 << 6)) {
                            if (shift == 0)
                                shift = 31;
P
pbrook 已提交
6515
                            tcg_gen_sari_i32(tmp, tmp, shift);
P
pbrook 已提交
6516
                        } else {
P
pbrook 已提交
6517
                            tcg_gen_shli_i32(tmp, tmp, shift);
P
pbrook 已提交
6518 6519 6520 6521
                        }
                        sh = (insn >> 16) & 0x1f;
                        if (sh != 0) {
                            if (insn & (1 << 22))
P
pbrook 已提交
6522
                                gen_helper_usat(tmp, tmp, tcg_const_i32(sh));
P
pbrook 已提交
6523
                            else
P
pbrook 已提交
6524
                                gen_helper_ssat(tmp, tmp, tcg_const_i32(sh));
P
pbrook 已提交
6525
                        }
P
pbrook 已提交
6526
                        store_reg(s, rd, tmp);
P
pbrook 已提交
6527 6528
                    } else if ((insn & 0x00300fe0) == 0x00200f20) {
                        /* [us]sat16 */
P
pbrook 已提交
6529
                        tmp = load_reg(s, rm);
P
pbrook 已提交
6530 6531 6532
                        sh = (insn >> 16) & 0x1f;
                        if (sh != 0) {
                            if (insn & (1 << 22))
P
pbrook 已提交
6533
                                gen_helper_usat16(tmp, tmp, tcg_const_i32(sh));
P
pbrook 已提交
6534
                            else
P
pbrook 已提交
6535
                                gen_helper_ssat16(tmp, tmp, tcg_const_i32(sh));
P
pbrook 已提交
6536
                        }
P
pbrook 已提交
6537
                        store_reg(s, rd, tmp);
P
pbrook 已提交
6538 6539
                    } else if ((insn & 0x00700fe0) == 0x00000fa0) {
                        /* Select bytes.  */
P
pbrook 已提交
6540 6541 6542 6543 6544 6545 6546 6547
                        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 已提交
6548
                    } else if ((insn & 0x000003e0) == 0x00000060) {
P
pbrook 已提交
6549
                        tmp = load_reg(s, rm);
P
pbrook 已提交
6550 6551 6552 6553
                        shift = (insn >> 10) & 3;
                        /* ??? In many cases it's not neccessary to do a
                           rotate, a shift is sufficient.  */
                        if (shift != 0)
P
pbrook 已提交
6554
                            tcg_gen_rori_i32(tmp, tmp, shift * 8);
P
pbrook 已提交
6555 6556
                        op1 = (insn >> 20) & 7;
                        switch (op1) {
P
pbrook 已提交
6557 6558 6559 6560 6561 6562
                        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 已提交
6563 6564 6565
                        default: goto illegal_op;
                        }
                        if (rn != 15) {
P
pbrook 已提交
6566
                            tmp2 = load_reg(s, rn);
P
pbrook 已提交
6567
                            if ((op1 & 3) == 0) {
P
pbrook 已提交
6568
                                gen_add16(tmp, tmp2);
P
pbrook 已提交
6569
                            } else {
P
pbrook 已提交
6570 6571
                                tcg_gen_add_i32(tmp, tmp, tmp2);
                                dead_tmp(tmp2);
P
pbrook 已提交
6572 6573
                            }
                        }
B
balrog 已提交
6574
                        store_reg(s, rd, tmp);
P
pbrook 已提交
6575 6576
                    } else if ((insn & 0x003f0f60) == 0x003f0f20) {
                        /* rev */
P
pbrook 已提交
6577
                        tmp = load_reg(s, rm);
P
pbrook 已提交
6578 6579
                        if (insn & (1 << 22)) {
                            if (insn & (1 << 7)) {
P
pbrook 已提交
6580
                                gen_revsh(tmp);
P
pbrook 已提交
6581 6582
                            } else {
                                ARCH(6T2);
P
pbrook 已提交
6583
                                gen_helper_rbit(tmp, tmp);
P
pbrook 已提交
6584 6585 6586
                            }
                        } else {
                            if (insn & (1 << 7))
P
pbrook 已提交
6587
                                gen_rev16(tmp);
P
pbrook 已提交
6588
                            else
A
aurel32 已提交
6589
                                tcg_gen_bswap32_i32(tmp, tmp);
P
pbrook 已提交
6590
                        }
P
pbrook 已提交
6591
                        store_reg(s, rd, tmp);
P
pbrook 已提交
6592 6593 6594 6595 6596
                    } else {
                        goto illegal_op;
                    }
                    break;
                case 2: /* Multiplies (Type 3).  */
P
pbrook 已提交
6597 6598
                    tmp = load_reg(s, rm);
                    tmp2 = load_reg(s, rs);
P
pbrook 已提交
6599 6600
                    if (insn & (1 << 20)) {
                        /* Signed multiply most significant [accumulate].  */
P
pbrook 已提交
6601
                        tmp64 = gen_muls_i64_i32(tmp, tmp2);
P
pbrook 已提交
6602
                        if (insn & (1 << 5))
P
pbrook 已提交
6603 6604
                            tcg_gen_addi_i64(tmp64, tmp64, 0x80000000u);
                        tcg_gen_shri_i64(tmp64, tmp64, 32);
P
pbrook 已提交
6605
                        tmp = new_tmp();
P
pbrook 已提交
6606
                        tcg_gen_trunc_i64_i32(tmp, tmp64);
6607 6608
                        if (rd != 15) {
                            tmp2 = load_reg(s, rd);
P
pbrook 已提交
6609
                            if (insn & (1 << 6)) {
P
pbrook 已提交
6610
                                tcg_gen_sub_i32(tmp, tmp, tmp2);
P
pbrook 已提交
6611
                            } else {
P
pbrook 已提交
6612
                                tcg_gen_add_i32(tmp, tmp, tmp2);
P
pbrook 已提交
6613
                            }
P
pbrook 已提交
6614
                            dead_tmp(tmp2);
P
pbrook 已提交
6615
                        }
6616
                        store_reg(s, rn, tmp);
P
pbrook 已提交
6617 6618
                    } else {
                        if (insn & (1 << 5))
P
pbrook 已提交
6619 6620 6621 6622 6623 6624 6625 6626 6627
                            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 已提交
6628
                        if (insn & (1 << 22)) {
P
pbrook 已提交
6629
                            /* smlald, smlsld */
P
pbrook 已提交
6630 6631
                            tmp64 = tcg_temp_new_i64();
                            tcg_gen_ext_i32_i64(tmp64, tmp);
P
pbrook 已提交
6632
                            dead_tmp(tmp);
P
pbrook 已提交
6633 6634
                            gen_addq(s, tmp64, rd, rn);
                            gen_storeq_reg(s, rd, rn, tmp64);
P
pbrook 已提交
6635
                        } else {
P
pbrook 已提交
6636
                            /* smuad, smusd, smlad, smlsd */
6637
                            if (rd != 15)
P
pbrook 已提交
6638
                              {
6639
                                tmp2 = load_reg(s, rd);
P
pbrook 已提交
6640 6641
                                gen_helper_add_setq(tmp, tmp, tmp2);
                                dead_tmp(tmp2);
P
pbrook 已提交
6642
                              }
6643
                            store_reg(s, rn, tmp);
P
pbrook 已提交
6644 6645 6646 6647 6648 6649 6650
                        }
                    }
                    break;
                case 3:
                    op1 = ((insn >> 17) & 0x38) | ((insn >> 5) & 7);
                    switch (op1) {
                    case 0: /* Unsigned sum of absolute differences.  */
P
pbrook 已提交
6651 6652 6653 6654 6655
                        ARCH(6);
                        tmp = load_reg(s, rm);
                        tmp2 = load_reg(s, rs);
                        gen_helper_usad8(tmp, tmp, tmp2);
                        dead_tmp(tmp2);
6656 6657
                        if (rd != 15) {
                            tmp2 = load_reg(s, rd);
P
pbrook 已提交
6658 6659
                            tcg_gen_add_i32(tmp, tmp, tmp2);
                            dead_tmp(tmp2);
P
pbrook 已提交
6660
                        }
6661
                        store_reg(s, rn, tmp);
P
pbrook 已提交
6662 6663 6664 6665 6666 6667 6668 6669
                        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 已提交
6670 6671
                            tmp = new_tmp();
                            tcg_gen_movi_i32(tmp, 0);
P
pbrook 已提交
6672
                        } else {
P
pbrook 已提交
6673
                            tmp = load_reg(s, rm);
P
pbrook 已提交
6674 6675
                        }
                        if (i != 32) {
P
pbrook 已提交
6676
                            tmp2 = load_reg(s, rd);
P
pbrook 已提交
6677
                            gen_bfi(tmp, tmp2, tmp, shift, (1u << i) - 1);
P
pbrook 已提交
6678
                            dead_tmp(tmp2);
P
pbrook 已提交
6679
                        }
P
pbrook 已提交
6680
                        store_reg(s, rd, tmp);
P
pbrook 已提交
6681 6682 6683
                        break;
                    case 0x12: case 0x16: case 0x1a: case 0x1e: /* sbfx */
                    case 0x32: case 0x36: case 0x3a: case 0x3e: /* ubfx */
6684
                        ARCH(6T2);
P
pbrook 已提交
6685
                        tmp = load_reg(s, rm);
P
pbrook 已提交
6686 6687 6688 6689 6690 6691
                        shift = (insn >> 7) & 0x1f;
                        i = ((insn >> 16) & 0x1f) + 1;
                        if (shift + i > 32)
                            goto illegal_op;
                        if (i < 32) {
                            if (op1 & 0x20) {
P
pbrook 已提交
6692
                                gen_ubfx(tmp, shift, (1u << i) - 1);
P
pbrook 已提交
6693
                            } else {
P
pbrook 已提交
6694
                                gen_sbfx(tmp, shift, i);
P
pbrook 已提交
6695 6696
                            }
                        }
P
pbrook 已提交
6697
                        store_reg(s, rd, tmp);
P
pbrook 已提交
6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 6717 6718
                        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 已提交
6719
            tmp2 = load_reg(s, rn);
P
pbrook 已提交
6720 6721
            i = (IS_USER(s) || (insn & 0x01200000) == 0x00200000);
            if (insn & (1 << 24))
P
pbrook 已提交
6722
                gen_add_data_offset(s, insn, tmp2);
P
pbrook 已提交
6723 6724 6725
            if (insn & (1 << 20)) {
                /* load */
                if (insn & (1 << 22)) {
P
pbrook 已提交
6726
                    tmp = gen_ld8u(tmp2, i);
P
pbrook 已提交
6727
                } else {
P
pbrook 已提交
6728
                    tmp = gen_ld32(tmp2, i);
P
pbrook 已提交
6729 6730 6731
                }
            } else {
                /* store */
P
pbrook 已提交
6732
                tmp = load_reg(s, rd);
P
pbrook 已提交
6733
                if (insn & (1 << 22))
P
pbrook 已提交
6734
                    gen_st8(tmp, tmp2, i);
P
pbrook 已提交
6735
                else
P
pbrook 已提交
6736
                    gen_st32(tmp, tmp2, i);
P
pbrook 已提交
6737 6738
            }
            if (!(insn & (1 << 24))) {
P
pbrook 已提交
6739 6740 6741 6742 6743 6744
                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 已提交
6745 6746 6747 6748
            }
            if (insn & (1 << 20)) {
                /* Complete the load.  */
                if (rd == 15)
P
pbrook 已提交
6749
                    gen_bx(s, tmp);
P
pbrook 已提交
6750
                else
P
pbrook 已提交
6751
                    store_reg(s, rd, tmp);
P
pbrook 已提交
6752 6753 6754 6755 6756 6757
            }
            break;
        case 0x08:
        case 0x09:
            {
                int j, n, user, loaded_base;
P
pbrook 已提交
6758
                TCGv loaded_var;
P
pbrook 已提交
6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769
                /* 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 已提交
6770
                addr = load_reg(s, rn);
P
pbrook 已提交
6771 6772 6773

                /* compute total size */
                loaded_base = 0;
P
pbrook 已提交
6774
                TCGV_UNUSED(loaded_var);
P
pbrook 已提交
6775 6776 6777 6778 6779 6780 6781 6782 6783
                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 已提交
6784
                        tcg_gen_addi_i32(addr, addr, 4);
P
pbrook 已提交
6785 6786 6787 6788 6789 6790
                    } else {
                        /* post increment */
                    }
                } else {
                    if (insn & (1 << 24)) {
                        /* pre decrement */
P
pbrook 已提交
6791
                        tcg_gen_addi_i32(addr, addr, -(n * 4));
P
pbrook 已提交
6792 6793 6794
                    } else {
                        /* post decrement */
                        if (n != 1)
P
pbrook 已提交
6795
                        tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
P
pbrook 已提交
6796 6797 6798 6799 6800 6801 6802
                    }
                }
                j = 0;
                for(i=0;i<16;i++) {
                    if (insn & (1 << i)) {
                        if (insn & (1 << 20)) {
                            /* load */
P
pbrook 已提交
6803
                            tmp = gen_ld32(addr, IS_USER(s));
P
pbrook 已提交
6804
                            if (i == 15) {
P
pbrook 已提交
6805
                                gen_bx(s, tmp);
P
pbrook 已提交
6806
                            } else if (user) {
P
pbrook 已提交
6807 6808
                                gen_helper_set_user_reg(tcg_const_i32(i), tmp);
                                dead_tmp(tmp);
P
pbrook 已提交
6809
                            } else if (i == rn) {
P
pbrook 已提交
6810
                                loaded_var = tmp;
P
pbrook 已提交
6811 6812
                                loaded_base = 1;
                            } else {
P
pbrook 已提交
6813
                                store_reg(s, i, tmp);
P
pbrook 已提交
6814 6815 6816 6817 6818 6819
                            }
                        } else {
                            /* store */
                            if (i == 15) {
                                /* special case: r15 = PC + 8 */
                                val = (long)s->pc + 4;
P
pbrook 已提交
6820 6821
                                tmp = new_tmp();
                                tcg_gen_movi_i32(tmp, val);
P
pbrook 已提交
6822
                            } else if (user) {
P
pbrook 已提交
6823 6824
                                tmp = new_tmp();
                                gen_helper_get_user_reg(tmp, tcg_const_i32(i));
P
pbrook 已提交
6825
                            } else {
P
pbrook 已提交
6826
                                tmp = load_reg(s, i);
P
pbrook 已提交
6827
                            }
P
pbrook 已提交
6828
                            gen_st32(tmp, addr, IS_USER(s));
P
pbrook 已提交
6829 6830 6831 6832
                        }
                        j++;
                        /* no need to add after the last transfer */
                        if (j != n)
P
pbrook 已提交
6833
                            tcg_gen_addi_i32(addr, addr, 4);
P
pbrook 已提交
6834 6835 6836 6837 6838 6839 6840 6841 6842
                    }
                }
                if (insn & (1 << 21)) {
                    /* write back */
                    if (insn & (1 << 23)) {
                        if (insn & (1 << 24)) {
                            /* pre increment */
                        } else {
                            /* post increment */
P
pbrook 已提交
6843
                            tcg_gen_addi_i32(addr, addr, 4);
P
pbrook 已提交
6844 6845 6846 6847 6848
                        }
                    } else {
                        if (insn & (1 << 24)) {
                            /* pre decrement */
                            if (n != 1)
P
pbrook 已提交
6849
                                tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
P
pbrook 已提交
6850 6851
                        } else {
                            /* post decrement */
P
pbrook 已提交
6852
                            tcg_gen_addi_i32(addr, addr, -(n * 4));
P
pbrook 已提交
6853 6854
                        }
                    }
P
pbrook 已提交
6855 6856 6857
                    store_reg(s, rn, addr);
                } else {
                    dead_tmp(addr);
P
pbrook 已提交
6858 6859
                }
                if (loaded_base) {
P
pbrook 已提交
6860
                    store_reg(s, rn, loaded_var);
P
pbrook 已提交
6861 6862 6863
                }
                if ((insn & (1 << 22)) && !user) {
                    /* Restore CPSR from SPSR.  */
P
pbrook 已提交
6864 6865 6866
                    tmp = load_cpu_field(spsr);
                    gen_set_cpsr(tmp, 0xffffffff);
                    dead_tmp(tmp);
P
pbrook 已提交
6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877 6878
                    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 已提交
6879 6880 6881
                    tmp = new_tmp();
                    tcg_gen_movi_i32(tmp, val);
                    store_reg(s, 14, tmp);
P
pbrook 已提交
6882 6883 6884 6885 6886 6887 6888 6889 6890 6891 6892 6893 6894 6895 6896
                }
                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 已提交
6897
            gen_set_pc_im(s->pc);
P
pbrook 已提交
6898 6899 6900 6901 6902
            s->is_jmp = DISAS_SWI;
            break;
        default:
        illegal_op:
            gen_set_condexec(s);
P
pbrook 已提交
6903
            gen_set_pc_im(s->pc - 4);
P
pbrook 已提交
6904
            gen_exception(EXCP_UDEF);
P
pbrook 已提交
6905 6906 6907 6908 6909 6910 6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 6928 6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939 6940 6941 6942 6943 6944 6945 6946 6947 6948 6949 6950 6951 6952 6953 6954 6955 6956 6957 6958 6959 6960 6961
            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
gen_thumb2_data_op(DisasContext *s, int op, int conds, uint32_t shifter_out)
{
    int logic_cc;

    logic_cc = 0;
    switch (op) {
    case 0: /* and */
        gen_op_andl_T0_T1();
        logic_cc = conds;
        break;
    case 1: /* bic */
        gen_op_bicl_T0_T1();
        logic_cc = conds;
        break;
    case 2: /* orr */
        gen_op_orl_T0_T1();
        logic_cc = conds;
        break;
    case 3: /* orn */
        gen_op_notl_T1();
        gen_op_orl_T0_T1();
        logic_cc = conds;
        break;
    case 4: /* eor */
        gen_op_xorl_T0_T1();
        logic_cc = conds;
        break;
    case 8: /* add */
        if (conds)
            gen_op_addl_T0_T1_cc();
        else
            gen_op_addl_T0_T1();
        break;
    case 10: /* adc */
        if (conds)
            gen_op_adcl_T0_T1_cc();
        else
P
pbrook 已提交
6962
            gen_adc_T0_T1();
P
pbrook 已提交
6963 6964 6965 6966 6967
        break;
    case 11: /* sbc */
        if (conds)
            gen_op_sbcl_T0_T1_cc();
        else
P
pbrook 已提交
6968
            gen_sbc_T0_T1();
P
pbrook 已提交
6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 6987
        break;
    case 13: /* sub */
        if (conds)
            gen_op_subl_T0_T1_cc();
        else
            gen_op_subl_T0_T1();
        break;
    case 14: /* rsb */
        if (conds)
            gen_op_rsbl_T0_T1_cc();
        else
            gen_op_rsbl_T0_T1();
        break;
    default: /* 5, 6, 7, 9, 12, 15. */
        return 1;
    }
    if (logic_cc) {
        gen_op_logic_T0_cc();
        if (shifter_out)
P
pbrook 已提交
6988
            gen_set_CF_bit31(cpu_T[1]);
P
pbrook 已提交
6989 6990 6991 6992 6993 6994 6995 6996
    }
    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 已提交
6997
    uint32_t insn, imm, shift, offset;
P
pbrook 已提交
6998
    uint32_t rd, rn, rm, rs;
P
pbrook 已提交
6999
    TCGv tmp;
P
pbrook 已提交
7000 7001
    TCGv tmp2;
    TCGv tmp3;
P
pbrook 已提交
7002
    TCGv addr;
P
pbrook 已提交
7003
    TCGv_i64 tmp64;
P
pbrook 已提交
7004 7005 7006 7007 7008 7009 7010
    int op;
    int shiftop;
    int conds;
    int logic_cc;

    if (!(arm_feature(env, ARM_FEATURE_THUMB2)
          || arm_feature (env, ARM_FEATURE_M))) {
7011
        /* Thumb-1 cores may need to treat bl and blx as a pair of
P
pbrook 已提交
7012 7013 7014 7015 7016
           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 已提交
7017 7018 7019
            tmp = load_reg(s, 14);
            tcg_gen_addi_i32(tmp, tmp, offset);
            tcg_gen_andi_i32(tmp, tmp, 0xfffffffc);
P
pbrook 已提交
7020

P
pbrook 已提交
7021
            tmp2 = new_tmp();
P
pbrook 已提交
7022
            tcg_gen_movi_i32(tmp2, s->pc | 1);
P
pbrook 已提交
7023 7024
            store_reg(s, 14, tmp2);
            gen_bx(s, tmp);
P
pbrook 已提交
7025 7026 7027 7028 7029
            return 0;
        }
        if (insn & (1 << 11)) {
            /* Second half of bl.  */
            offset = ((insn & 0x7ff) << 1) | 1;
P
pbrook 已提交
7030
            tmp = load_reg(s, 14);
B
balrog 已提交
7031
            tcg_gen_addi_i32(tmp, tmp, offset);
P
pbrook 已提交
7032

P
pbrook 已提交
7033
            tmp2 = new_tmp();
P
pbrook 已提交
7034
            tcg_gen_movi_i32(tmp2, s->pc | 1);
P
pbrook 已提交
7035 7036
            store_reg(s, 14, tmp2);
            gen_bx(s, tmp);
P
pbrook 已提交
7037 7038 7039 7040 7041 7042 7043
            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;
P
pbrook 已提交
7044
            gen_op_movl_T0_im(s->pc + 2 + offset);
P
pbrook 已提交
7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066 7067 7068 7069 7070 7071 7072
            gen_movl_reg_T0(s, 14);
            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 已提交
7073 7074
                    addr = new_tmp();
                    tcg_gen_movi_i32(addr, s->pc & ~3);
P
pbrook 已提交
7075
                } else {
P
pbrook 已提交
7076
                    addr = load_reg(s, rn);
P
pbrook 已提交
7077 7078 7079 7080 7081
                }
                offset = (insn & 0xff) * 4;
                if ((insn & (1 << 23)) == 0)
                    offset = -offset;
                if (insn & (1 << 24)) {
P
pbrook 已提交
7082
                    tcg_gen_addi_i32(addr, addr, offset);
P
pbrook 已提交
7083 7084 7085 7086
                    offset = 0;
                }
                if (insn & (1 << 20)) {
                    /* ldrd */
P
pbrook 已提交
7087 7088 7089 7090 7091
                    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 已提交
7092 7093
                } else {
                    /* strd */
P
pbrook 已提交
7094 7095 7096 7097 7098
                    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 已提交
7099 7100 7101 7102 7103
                }
                if (insn & (1 << 21)) {
                    /* Base writeback.  */
                    if (rn == 15)
                        goto illegal_op;
P
pbrook 已提交
7104 7105 7106 7107
                    tcg_gen_addi_i32(addr, addr, offset - 4);
                    store_reg(s, rn, addr);
                } else {
                    dead_tmp(addr);
P
pbrook 已提交
7108 7109 7110
                }
            } else if ((insn & (1 << 23)) == 0) {
                /* Load/store exclusive word.  */
B
bellard 已提交
7111
                gen_movl_T1_reg(s, rn);
B
balrog 已提交
7112
                addr = cpu_T[1];
B
bellard 已提交
7113
                if (insn & (1 << 20)) {
P
pbrook 已提交
7114 7115 7116
                    gen_helper_mark_exclusive(cpu_env, cpu_T[1]);
                    tmp = gen_ld32(addr, IS_USER(s));
                    store_reg(s, rd, tmp);
P
pbrook 已提交
7117
                } else {
P
pbrook 已提交
7118 7119
                    int label = gen_new_label();
                    gen_helper_test_exclusive(cpu_T[0], cpu_env, addr);
P
pbrook 已提交
7120 7121
                    tcg_gen_brcondi_i32(TCG_COND_NE, cpu_T[0],
                                        0, label);
P
pbrook 已提交
7122 7123 7124 7125
                    tmp = load_reg(s, rs);
                    gen_st32(tmp, cpu_T[1], IS_USER(s));
                    gen_set_label(label);
                    gen_movl_reg_T0(s, rd);
P
pbrook 已提交
7126 7127 7128 7129
                }
            } else if ((insn & (1 << 6)) == 0) {
                /* Table Branch.  */
                if (rn == 15) {
P
pbrook 已提交
7130 7131
                    addr = new_tmp();
                    tcg_gen_movi_i32(addr, s->pc);
P
pbrook 已提交
7132
                } else {
P
pbrook 已提交
7133
                    addr = load_reg(s, rn);
P
pbrook 已提交
7134
                }
P
pbrook 已提交
7135
                tmp = load_reg(s, rm);
P
pbrook 已提交
7136
                tcg_gen_add_i32(addr, addr, tmp);
P
pbrook 已提交
7137 7138
                if (insn & (1 << 4)) {
                    /* tbh */
P
pbrook 已提交
7139
                    tcg_gen_add_i32(addr, addr, tmp);
P
pbrook 已提交
7140
                    dead_tmp(tmp);
P
pbrook 已提交
7141
                    tmp = gen_ld16u(addr, IS_USER(s));
P
pbrook 已提交
7142
                } else { /* tbb */
P
pbrook 已提交
7143
                    dead_tmp(tmp);
P
pbrook 已提交
7144
                    tmp = gen_ld8u(addr, IS_USER(s));
P
pbrook 已提交
7145
                }
P
pbrook 已提交
7146 7147 7148 7149
                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 已提交
7150 7151
            } else {
                /* Load/store exclusive byte/halfword/doubleword.  */
P
pbrook 已提交
7152 7153 7154
                /* ??? These are not really atomic.  However we know
                   we never have multiple CPUs running in parallel,
                   so it is good enough.  */
P
pbrook 已提交
7155
                op = (insn >> 4) & 0x3;
P
pbrook 已提交
7156 7157
                /* Must use a global reg for the address because we have
                   a conditional branch in the store instruction.  */
P
pbrook 已提交
7158
                gen_movl_T1_reg(s, rn);
P
pbrook 已提交
7159
                addr = cpu_T[1];
P
pbrook 已提交
7160
                if (insn & (1 << 20)) {
P
pbrook 已提交
7161
                    gen_helper_mark_exclusive(cpu_env, addr);
P
pbrook 已提交
7162 7163
                    switch (op) {
                    case 0:
P
pbrook 已提交
7164
                        tmp = gen_ld8u(addr, IS_USER(s));
P
pbrook 已提交
7165
                        break;
B
bellard 已提交
7166
                    case 1:
P
pbrook 已提交
7167
                        tmp = gen_ld16u(addr, IS_USER(s));
B
bellard 已提交
7168
                        break;
P
pbrook 已提交
7169
                    case 3:
P
pbrook 已提交
7170 7171 7172 7173
                        tmp = gen_ld32(addr, IS_USER(s));
                        tcg_gen_addi_i32(addr, addr, 4);
                        tmp2 = gen_ld32(addr, IS_USER(s));
                        store_reg(s, rd, tmp2);
B
bellard 已提交
7174 7175
                        break;
                    default:
P
pbrook 已提交
7176 7177
                        goto illegal_op;
                    }
P
pbrook 已提交
7178
                    store_reg(s, rs, tmp);
P
pbrook 已提交
7179
                } else {
P
pbrook 已提交
7180 7181 7182
                    int label = gen_new_label();
                    /* Must use a global that is not killed by the branch.  */
                    gen_helper_test_exclusive(cpu_T[0], cpu_env, addr);
P
pbrook 已提交
7183
                    tcg_gen_brcondi_i32(TCG_COND_NE, cpu_T[0], 0, label);
P
pbrook 已提交
7184
                    tmp = load_reg(s, rs);
P
pbrook 已提交
7185 7186
                    switch (op) {
                    case 0:
P
pbrook 已提交
7187
                        gen_st8(tmp, addr, IS_USER(s));
P
pbrook 已提交
7188 7189
                        break;
                    case 1:
P
pbrook 已提交
7190
                        gen_st16(tmp, addr, IS_USER(s));
P
pbrook 已提交
7191
                        break;
B
bellard 已提交
7192
                    case 3:
P
pbrook 已提交
7193 7194 7195 7196
                        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));
B
bellard 已提交
7197
                        break;
P
pbrook 已提交
7198 7199
                    default:
                        goto illegal_op;
B
bellard 已提交
7200
                    }
P
pbrook 已提交
7201
                    gen_set_label(label);
P
pbrook 已提交
7202 7203 7204 7205 7206 7207 7208
                    gen_movl_reg_T0(s, rm);
                }
            }
        } else {
            /* Load/store multiple, RFE, SRS.  */
            if (((insn >> 23) & 1) == ((insn >> 24) & 1)) {
                /* Not available in user mode.  */
P
pbrook 已提交
7209
                if (IS_USER(s))
P
pbrook 已提交
7210 7211 7212
                    goto illegal_op;
                if (insn & (1 << 20)) {
                    /* rfe */
P
pbrook 已提交
7213 7214 7215 7216 7217 7218 7219
                    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 已提交
7220 7221
                    if (insn & (1 << 21)) {
                        /* Base writeback.  */
P
pbrook 已提交
7222 7223 7224 7225 7226 7227 7228 7229
                        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 已提交
7230
                    }
P
pbrook 已提交
7231
                    gen_rfe(s, tmp, tmp2);
P
pbrook 已提交
7232 7233 7234 7235
                } else {
                    /* srs */
                    op = (insn & 0x1f);
                    if (op == (env->uncached_cpsr & CPSR_M)) {
P
pbrook 已提交
7236
                        addr = load_reg(s, 13);
P
pbrook 已提交
7237
                    } else {
P
pbrook 已提交
7238 7239
                        addr = new_tmp();
                        gen_helper_get_r13_banked(addr, cpu_env, tcg_const_i32(op));
P
pbrook 已提交
7240 7241
                    }
                    if ((insn & (1 << 24)) == 0) {
P
pbrook 已提交
7242
                        tcg_gen_addi_i32(addr, addr, -8);
P
pbrook 已提交
7243
                    }
P
pbrook 已提交
7244 7245 7246 7247 7248 7249
                    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 已提交
7250 7251
                    if (insn & (1 << 21)) {
                        if ((insn & (1 << 24)) == 0) {
P
pbrook 已提交
7252
                            tcg_gen_addi_i32(addr, addr, -4);
P
pbrook 已提交
7253
                        } else {
P
pbrook 已提交
7254
                            tcg_gen_addi_i32(addr, addr, 4);
P
pbrook 已提交
7255 7256
                        }
                        if (op == (env->uncached_cpsr & CPSR_M)) {
P
pbrook 已提交
7257
                            store_reg(s, 13, addr);
P
pbrook 已提交
7258
                        } else {
P
pbrook 已提交
7259 7260
                            gen_helper_set_r13_banked(cpu_env,
                                tcg_const_i32(op), addr);
P
pbrook 已提交
7261
                        }
P
pbrook 已提交
7262 7263
                    } else {
                        dead_tmp(addr);
P
pbrook 已提交
7264 7265 7266 7267 7268
                    }
                }
            } else {
                int i;
                /* Load/store multiple.  */
P
pbrook 已提交
7269
                addr = load_reg(s, rn);
P
pbrook 已提交
7270 7271 7272 7273 7274 7275
                offset = 0;
                for (i = 0; i < 16; i++) {
                    if (insn & (1 << i))
                        offset += 4;
                }
                if (insn & (1 << 24)) {
P
pbrook 已提交
7276
                    tcg_gen_addi_i32(addr, addr, -offset);
P
pbrook 已提交
7277 7278 7279 7280 7281 7282 7283
                }

                for (i = 0; i < 16; i++) {
                    if ((insn & (1 << i)) == 0)
                        continue;
                    if (insn & (1 << 20)) {
                        /* Load.  */
P
pbrook 已提交
7284
                        tmp = gen_ld32(addr, IS_USER(s));
P
pbrook 已提交
7285
                        if (i == 15) {
P
pbrook 已提交
7286
                            gen_bx(s, tmp);
P
pbrook 已提交
7287
                        } else {
P
pbrook 已提交
7288
                            store_reg(s, i, tmp);
P
pbrook 已提交
7289 7290 7291
                        }
                    } else {
                        /* Store.  */
P
pbrook 已提交
7292 7293
                        tmp = load_reg(s, i);
                        gen_st32(tmp, addr, IS_USER(s));
P
pbrook 已提交
7294
                    }
P
pbrook 已提交
7295
                    tcg_gen_addi_i32(addr, addr, 4);
P
pbrook 已提交
7296 7297 7298 7299
                }
                if (insn & (1 << 21)) {
                    /* Base register writeback.  */
                    if (insn & (1 << 24)) {
P
pbrook 已提交
7300
                        tcg_gen_addi_i32(addr, addr, -offset);
P
pbrook 已提交
7301 7302 7303 7304
                    }
                    /* Fault if writeback register is in register list.  */
                    if (insn & (1 << rn))
                        goto illegal_op;
P
pbrook 已提交
7305 7306 7307
                    store_reg(s, rn, addr);
                } else {
                    dead_tmp(addr);
P
pbrook 已提交
7308 7309 7310 7311 7312 7313 7314 7315 7316 7317 7318 7319 7320 7321 7322
                }
            }
        }
        break;
    case 5: /* Data processing register constant shift.  */
        if (rn == 15)
            gen_op_movl_T0_im(0);
        else
            gen_movl_T0_reg(s, rn);
        gen_movl_T1_reg(s, rm);
        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));
P
pbrook 已提交
7323
        gen_arm_shift_im(cpu_T[1], shiftop, shift, logic_cc);
P
pbrook 已提交
7324 7325 7326 7327 7328 7329 7330 7331 7332 7333 7334
        if (gen_thumb2_data_op(s, op, conds, 0))
            goto illegal_op;
        if (rd != 15)
            gen_movl_reg_T0(s, rd);
        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 已提交
7335 7336
            tmp = load_reg(s, rn);
            tmp2 = load_reg(s, rm);
P
pbrook 已提交
7337 7338 7339
            if ((insn & 0x70) != 0)
                goto illegal_op;
            op = (insn >> 21) & 3;
P
pbrook 已提交
7340 7341 7342 7343
            logic_cc = (insn & (1 << 20)) != 0;
            gen_arm_shift_reg(tmp, op, tmp2, logic_cc);
            if (logic_cc)
                gen_logic_CC(tmp);
7344
            store_reg_bx(env, s, rd, tmp);
P
pbrook 已提交
7345 7346
            break;
        case 1: /* Sign/zero extend.  */
P
pbrook 已提交
7347
            tmp = load_reg(s, rm);
P
pbrook 已提交
7348 7349 7350 7351
            shift = (insn >> 4) & 3;
            /* ??? In many cases it's not neccessary to do a
               rotate, a shift is sufficient.  */
            if (shift != 0)
P
pbrook 已提交
7352
                tcg_gen_rori_i32(tmp, tmp, shift * 8);
P
pbrook 已提交
7353 7354
            op = (insn >> 20) & 7;
            switch (op) {
P
pbrook 已提交
7355 7356 7357 7358 7359 7360
            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 已提交
7361 7362 7363
            default: goto illegal_op;
            }
            if (rn != 15) {
P
pbrook 已提交
7364
                tmp2 = load_reg(s, rn);
P
pbrook 已提交
7365
                if ((op >> 1) == 1) {
P
pbrook 已提交
7366
                    gen_add16(tmp, tmp2);
P
pbrook 已提交
7367
                } else {
P
pbrook 已提交
7368 7369
                    tcg_gen_add_i32(tmp, tmp, tmp2);
                    dead_tmp(tmp2);
P
pbrook 已提交
7370 7371
                }
            }
P
pbrook 已提交
7372
            store_reg(s, rd, tmp);
P
pbrook 已提交
7373 7374 7375 7376 7377 7378
            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 已提交
7379 7380 7381 7382 7383
            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 已提交
7384 7385 7386 7387 7388
            break;
        case 3: /* Other data processing.  */
            op = ((insn >> 17) & 0x38) | ((insn >> 4) & 7);
            if (op < 4) {
                /* Saturating add/subtract.  */
P
pbrook 已提交
7389 7390
                tmp = load_reg(s, rn);
                tmp2 = load_reg(s, rm);
P
pbrook 已提交
7391
                if (op & 2)
P
pbrook 已提交
7392
                    gen_helper_double_saturate(tmp, tmp);
P
pbrook 已提交
7393
                if (op & 1)
P
pbrook 已提交
7394
                    gen_helper_sub_saturate(tmp, tmp2, tmp);
P
pbrook 已提交
7395
                else
P
pbrook 已提交
7396 7397
                    gen_helper_add_saturate(tmp, tmp, tmp2);
                dead_tmp(tmp2);
P
pbrook 已提交
7398
            } else {
P
pbrook 已提交
7399
                tmp = load_reg(s, rn);
P
pbrook 已提交
7400 7401
                switch (op) {
                case 0x0a: /* rbit */
P
pbrook 已提交
7402
                    gen_helper_rbit(tmp, tmp);
P
pbrook 已提交
7403 7404
                    break;
                case 0x08: /* rev */
A
aurel32 已提交
7405
                    tcg_gen_bswap32_i32(tmp, tmp);
P
pbrook 已提交
7406 7407
                    break;
                case 0x09: /* rev16 */
P
pbrook 已提交
7408
                    gen_rev16(tmp);
P
pbrook 已提交
7409 7410
                    break;
                case 0x0b: /* revsh */
P
pbrook 已提交
7411
                    gen_revsh(tmp);
P
pbrook 已提交
7412 7413
                    break;
                case 0x10: /* sel */
P
pbrook 已提交
7414
                    tmp2 = load_reg(s, rm);
P
pbrook 已提交
7415 7416
                    tmp3 = new_tmp();
                    tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUState, GE));
P
pbrook 已提交
7417
                    gen_helper_sel_flags(tmp, tmp3, tmp, tmp2);
P
pbrook 已提交
7418
                    dead_tmp(tmp3);
P
pbrook 已提交
7419
                    dead_tmp(tmp2);
P
pbrook 已提交
7420 7421
                    break;
                case 0x18: /* clz */
P
pbrook 已提交
7422
                    gen_helper_clz(tmp, tmp);
P
pbrook 已提交
7423 7424 7425 7426 7427
                    break;
                default:
                    goto illegal_op;
                }
            }
P
pbrook 已提交
7428
            store_reg(s, rd, tmp);
P
pbrook 已提交
7429 7430 7431
            break;
        case 4: case 5: /* 32-bit multiply.  Sum of absolute differences.  */
            op = (insn >> 4) & 0xf;
P
pbrook 已提交
7432 7433
            tmp = load_reg(s, rn);
            tmp2 = load_reg(s, rm);
P
pbrook 已提交
7434 7435
            switch ((insn >> 20) & 7) {
            case 0: /* 32 x 32 -> 32 */
P
pbrook 已提交
7436 7437
                tcg_gen_mul_i32(tmp, tmp, tmp2);
                dead_tmp(tmp2);
P
pbrook 已提交
7438
                if (rs != 15) {
P
pbrook 已提交
7439
                    tmp2 = load_reg(s, rs);
P
pbrook 已提交
7440
                    if (op)
P
pbrook 已提交
7441
                        tcg_gen_sub_i32(tmp, tmp2, tmp);
P
pbrook 已提交
7442
                    else
P
pbrook 已提交
7443 7444
                        tcg_gen_add_i32(tmp, tmp, tmp2);
                    dead_tmp(tmp2);
P
pbrook 已提交
7445 7446 7447
                }
                break;
            case 1: /* 16 x 16 -> 32 */
P
pbrook 已提交
7448 7449
                gen_mulxy(tmp, tmp2, op & 2, op & 1);
                dead_tmp(tmp2);
P
pbrook 已提交
7450
                if (rs != 15) {
P
pbrook 已提交
7451 7452 7453
                    tmp2 = load_reg(s, rs);
                    gen_helper_add_setq(tmp, tmp, tmp2);
                    dead_tmp(tmp2);
P
pbrook 已提交
7454 7455 7456 7457 7458
                }
                break;
            case 2: /* Dual multiply add.  */
            case 4: /* Dual multiply subtract.  */
                if (op)
P
pbrook 已提交
7459 7460
                    gen_swap_half(tmp2);
                gen_smul_dual(tmp, tmp2);
P
pbrook 已提交
7461 7462
                /* This addition cannot overflow.  */
                if (insn & (1 << 22)) {
P
pbrook 已提交
7463
                    tcg_gen_sub_i32(tmp, tmp, tmp2);
P
pbrook 已提交
7464
                } else {
P
pbrook 已提交
7465
                    tcg_gen_add_i32(tmp, tmp, tmp2);
P
pbrook 已提交
7466
                }
P
pbrook 已提交
7467
                dead_tmp(tmp2);
P
pbrook 已提交
7468 7469
                if (rs != 15)
                  {
P
pbrook 已提交
7470 7471 7472
                    tmp2 = load_reg(s, rs);
                    gen_helper_add_setq(tmp, tmp, tmp2);
                    dead_tmp(tmp2);
P
pbrook 已提交
7473 7474 7475 7476
                  }
                break;
            case 3: /* 32 * 16 -> 32msb */
                if (op)
P
pbrook 已提交
7477
                    tcg_gen_sari_i32(tmp2, tmp2, 16);
P
pbrook 已提交
7478
                else
P
pbrook 已提交
7479
                    gen_sxth(tmp2);
P
pbrook 已提交
7480 7481
                tmp64 = gen_muls_i64_i32(tmp, tmp2);
                tcg_gen_shri_i64(tmp64, tmp64, 16);
P
pbrook 已提交
7482
                tmp = new_tmp();
P
pbrook 已提交
7483
                tcg_gen_trunc_i64_i32(tmp, tmp64);
P
pbrook 已提交
7484 7485
                if (rs != 15)
                  {
P
pbrook 已提交
7486 7487 7488
                    tmp2 = load_reg(s, rs);
                    gen_helper_add_setq(tmp, tmp, tmp2);
                    dead_tmp(tmp2);
P
pbrook 已提交
7489 7490 7491
                  }
                break;
            case 5: case 6: /* 32 * 32 -> 32msb */
P
pbrook 已提交
7492 7493 7494 7495 7496 7497 7498 7499
                gen_imull(tmp, tmp2);
                if (insn & (1 << 5)) {
                    gen_roundqd(tmp, tmp2);
                    dead_tmp(tmp2);
                } else {
                    dead_tmp(tmp);
                    tmp = tmp2;
                }
P
pbrook 已提交
7500
                if (rs != 15) {
P
pbrook 已提交
7501
                    tmp2 = load_reg(s, rs);
P
pbrook 已提交
7502
                    if (insn & (1 << 21)) {
P
pbrook 已提交
7503
                        tcg_gen_add_i32(tmp, tmp, tmp2);
B
bellard 已提交
7504
                    } else {
P
pbrook 已提交
7505
                        tcg_gen_sub_i32(tmp, tmp2, tmp);
B
bellard 已提交
7506
                    }
P
pbrook 已提交
7507
                    dead_tmp(tmp2);
B
bellard 已提交
7508
                }
P
pbrook 已提交
7509 7510
                break;
            case 7: /* Unsigned sum of absolute differences.  */
P
pbrook 已提交
7511 7512
                gen_helper_usad8(tmp, tmp, tmp2);
                dead_tmp(tmp2);
P
pbrook 已提交
7513
                if (rs != 15) {
P
pbrook 已提交
7514 7515 7516
                    tmp2 = load_reg(s, rs);
                    tcg_gen_add_i32(tmp, tmp, tmp2);
                    dead_tmp(tmp2);
7517
                }
P
pbrook 已提交
7518
                break;
B
bellard 已提交
7519
            }
P
pbrook 已提交
7520
            store_reg(s, rd, tmp);
B
bellard 已提交
7521
            break;
P
pbrook 已提交
7522 7523
        case 6: case 7: /* 64-bit multiply, Divide.  */
            op = ((insn >> 4) & 0xf) | ((insn >> 16) & 0x70);
P
pbrook 已提交
7524 7525
            tmp = load_reg(s, rn);
            tmp2 = load_reg(s, rm);
P
pbrook 已提交
7526 7527 7528 7529 7530
            if ((op & 0x50) == 0x10) {
                /* sdiv, udiv */
                if (!arm_feature(env, ARM_FEATURE_DIV))
                    goto illegal_op;
                if (op & 0x20)
P
pbrook 已提交
7531
                    gen_helper_udiv(tmp, tmp, tmp2);
B
bellard 已提交
7532
                else
P
pbrook 已提交
7533 7534 7535
                    gen_helper_sdiv(tmp, tmp, tmp2);
                dead_tmp(tmp2);
                store_reg(s, rd, tmp);
P
pbrook 已提交
7536 7537 7538
            } else if ((op & 0xe) == 0xc) {
                /* Dual multiply accumulate long.  */
                if (op & 1)
P
pbrook 已提交
7539 7540
                    gen_swap_half(tmp2);
                gen_smul_dual(tmp, tmp2);
P
pbrook 已提交
7541
                if (op & 0x10) {
P
pbrook 已提交
7542
                    tcg_gen_sub_i32(tmp, tmp, tmp2);
B
bellard 已提交
7543
                } else {
P
pbrook 已提交
7544
                    tcg_gen_add_i32(tmp, tmp, tmp2);
B
bellard 已提交
7545
                }
P
pbrook 已提交
7546
                dead_tmp(tmp2);
P
pbrook 已提交
7547 7548 7549 7550 7551 7552
                /* 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);
B
bellard 已提交
7553
            } else {
P
pbrook 已提交
7554 7555
                if (op & 0x20) {
                    /* Unsigned 64-bit multiply  */
P
pbrook 已提交
7556
                    tmp64 = gen_mulu_i64_i32(tmp, tmp2);
B
bellard 已提交
7557
                } else {
P
pbrook 已提交
7558 7559
                    if (op & 8) {
                        /* smlalxy */
P
pbrook 已提交
7560 7561
                        gen_mulxy(tmp, tmp2, op & 2, op & 1);
                        dead_tmp(tmp2);
P
pbrook 已提交
7562 7563
                        tmp64 = tcg_temp_new_i64();
                        tcg_gen_ext_i32_i64(tmp64, tmp);
P
pbrook 已提交
7564
                        dead_tmp(tmp);
P
pbrook 已提交
7565 7566
                    } else {
                        /* Signed 64-bit multiply  */
P
pbrook 已提交
7567
                        tmp64 = gen_muls_i64_i32(tmp, tmp2);
P
pbrook 已提交
7568
                    }
B
bellard 已提交
7569
                }
P
pbrook 已提交
7570 7571
                if (op & 4) {
                    /* umaal */
P
pbrook 已提交
7572 7573
                    gen_addq_lo(s, tmp64, rs);
                    gen_addq_lo(s, tmp64, rd);
P
pbrook 已提交
7574 7575
                } else if (op & 0x40) {
                    /* 64-bit accumulate.  */
P
pbrook 已提交
7576
                    gen_addq(s, tmp64, rs, rd);
P
pbrook 已提交
7577
                }
P
pbrook 已提交
7578
                gen_storeq_reg(s, rs, rd, tmp64);
7579
            }
B
bellard 已提交
7580
            break;
P
pbrook 已提交
7581 7582 7583 7584 7585 7586 7587 7588 7589 7590 7591 7592 7593 7594 7595 7596 7597 7598 7599 7600 7601 7602 7603 7604 7605 7606 7607 7608 7609 7610 7611 7612 7613
        }
        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.  */
P
pbrook 已提交
7614
                    gen_op_movl_T1_im(s->pc | 1);
P
pbrook 已提交
7615
                    gen_movl_reg_T1(s, 14);
B
bellard 已提交
7616
                }
7617

P
pbrook 已提交
7618
                offset += s->pc;
P
pbrook 已提交
7619 7620
                if (insn & (1 << 12)) {
                    /* b/bl */
P
pbrook 已提交
7621
                    gen_jmp(s, offset);
P
pbrook 已提交
7622 7623
                } else {
                    /* blx */
P
pbrook 已提交
7624 7625
                    offset &= ~(uint32_t)2;
                    gen_bx_im(s, offset);
B
bellard 已提交
7626
                }
P
pbrook 已提交
7627 7628 7629 7630 7631 7632 7633 7634
            } 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 已提交
7635
                } else {
P
pbrook 已提交
7636 7637 7638 7639
                    op = (insn >> 20) & 7;
                    switch (op) {
                    case 0: /* msr cpsr.  */
                        if (IS_M(env)) {
P
pbrook 已提交
7640 7641 7642
                            tmp = load_reg(s, rn);
                            addr = tcg_const_i32(insn & 0xff);
                            gen_helper_v7m_msr(cpu_env, addr, tmp);
P
pbrook 已提交
7643 7644 7645 7646 7647 7648 7649 7650 7651 7652 7653 7654 7655 7656 7657 7658 7659 7660 7661 7662 7663 7664 7665 7666 7667 7668 7669 7670 7671 7672 7673 7674 7675 7676 7677 7678 7679 7680 7681 7682 7683 7684 7685 7686 7687
                            gen_lookup_tb(s);
                            break;
                        }
                        /* fall through */
                    case 1: /* msr spsr.  */
                        if (IS_M(env))
                            goto illegal_op;
                        gen_movl_T0_reg(s, rn);
                        if (gen_set_psr_T0(s,
                              msr_mask(env, s, (insn >> 8) & 0xf, op == 1),
                              op == 1))
                            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) {
                            gen_op_movl_T0_im(imm);
                            gen_set_psr_T0(s, offset, 0);
                        }
                        break;
                    case 3: /* Special control operations.  */
                        op = (insn >> 4) & 0xf;
                        switch (op) {
                        case 2: /* clrex */
P
pbrook 已提交
7688
                            gen_helper_clrex(cpu_env);
P
pbrook 已提交
7689 7690 7691 7692 7693 7694 7695 7696 7697 7698 7699 7700 7701
                            break;
                        case 4: /* dsb */
                        case 5: /* dmb */
                        case 6: /* isb */
                            /* These execute as NOPs.  */
                            ARCH(7);
                            break;
                        default:
                            goto illegal_op;
                        }
                        break;
                    case 4: /* bxj */
                        /* Trivial implementation equivalent to bx.  */
P
pbrook 已提交
7702 7703
                        tmp = load_reg(s, rn);
                        gen_bx(s, tmp);
P
pbrook 已提交
7704 7705 7706 7707 7708
                        break;
                    case 5: /* Exception return.  */
                        /* Unpredictable in user mode.  */
                        goto illegal_op;
                    case 6: /* mrs cpsr.  */
P
pbrook 已提交
7709
                        tmp = new_tmp();
P
pbrook 已提交
7710
                        if (IS_M(env)) {
P
pbrook 已提交
7711 7712
                            addr = tcg_const_i32(insn & 0xff);
                            gen_helper_v7m_mrs(tmp, cpu_env, addr);
P
pbrook 已提交
7713
                        } else {
P
pbrook 已提交
7714
                            gen_helper_cpsr_read(tmp);
P
pbrook 已提交
7715
                        }
P
pbrook 已提交
7716
                        store_reg(s, rd, tmp);
P
pbrook 已提交
7717 7718 7719 7720 7721
                        break;
                    case 7: /* mrs spsr.  */
                        /* Not accessible in user mode.  */
                        if (IS_USER(s) || IS_M(env))
                            goto illegal_op;
P
pbrook 已提交
7722 7723
                        tmp = load_cpu_field(spsr);
                        store_reg(s, rd, tmp);
P
pbrook 已提交
7724
                        break;
B
bellard 已提交
7725 7726
                    }
                }
P
pbrook 已提交
7727 7728 7729 7730 7731
            } else {
                /* Conditional branch.  */
                op = (insn >> 22) & 0xf;
                /* Generate a conditional jump to next instruction.  */
                s->condlabel = gen_new_label();
P
pbrook 已提交
7732
                gen_test_cc(op ^ 1, s->condlabel);
P
pbrook 已提交
7733 7734 7735 7736 7737 7738 7739 7740 7741 7742 7743 7744 7745 7746
                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 已提交
7747
                gen_jmp(s, s->pc + offset);
P
pbrook 已提交
7748 7749 7750 7751 7752 7753 7754 7755 7756 7757 7758
            }
        } 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 已提交
7759 7760 7761 7762 7763 7764
                    if (rn == 15) {
                        tmp = new_tmp();
                        tcg_gen_movi_i32(tmp, 0);
                    } else {
                        tmp = load_reg(s, rn);
                    }
P
pbrook 已提交
7765 7766 7767 7768 7769 7770
                    switch (op) {
                    case 2: /* Signed bitfield extract.  */
                        imm++;
                        if (shift + imm > 32)
                            goto illegal_op;
                        if (imm < 32)
P
pbrook 已提交
7771
                            gen_sbfx(tmp, shift, imm);
P
pbrook 已提交
7772 7773 7774 7775 7776 7777
                        break;
                    case 6: /* Unsigned bitfield extract.  */
                        imm++;
                        if (shift + imm > 32)
                            goto illegal_op;
                        if (imm < 32)
P
pbrook 已提交
7778
                            gen_ubfx(tmp, shift, (1u << imm) - 1);
P
pbrook 已提交
7779 7780 7781 7782 7783 7784
                        break;
                    case 3: /* Bitfield insert/clear.  */
                        if (imm < shift)
                            goto illegal_op;
                        imm = imm + 1 - shift;
                        if (imm != 32) {
P
pbrook 已提交
7785
                            tmp2 = load_reg(s, rd);
P
pbrook 已提交
7786
                            gen_bfi(tmp, tmp2, tmp, shift, (1u << imm) - 1);
P
pbrook 已提交
7787
                            dead_tmp(tmp2);
P
pbrook 已提交
7788 7789 7790 7791 7792 7793 7794
                        }
                        break;
                    case 7:
                        goto illegal_op;
                    default: /* Saturate.  */
                        if (shift) {
                            if (op & 1)
P
pbrook 已提交
7795
                                tcg_gen_sari_i32(tmp, tmp, shift);
P
pbrook 已提交
7796
                            else
P
pbrook 已提交
7797
                                tcg_gen_shli_i32(tmp, tmp, shift);
P
pbrook 已提交
7798
                        }
P
pbrook 已提交
7799
                        tmp2 = tcg_const_i32(imm);
P
pbrook 已提交
7800 7801 7802
                        if (op & 4) {
                            /* Unsigned.  */
                            if ((op & 1) && shift == 0)
P
pbrook 已提交
7803
                                gen_helper_usat16(tmp, tmp, tmp2);
P
pbrook 已提交
7804
                            else
P
pbrook 已提交
7805
                                gen_helper_usat(tmp, tmp, tmp2);
B
bellard 已提交
7806
                        } else {
P
pbrook 已提交
7807 7808
                            /* Signed.  */
                            if ((op & 1) && shift == 0)
P
pbrook 已提交
7809
                                gen_helper_ssat16(tmp, tmp, tmp2);
P
pbrook 已提交
7810
                            else
P
pbrook 已提交
7811
                                gen_helper_ssat(tmp, tmp, tmp2);
B
bellard 已提交
7812
                        }
P
pbrook 已提交
7813
                        break;
B
bellard 已提交
7814
                    }
P
pbrook 已提交
7815
                    store_reg(s, rd, tmp);
P
pbrook 已提交
7816 7817 7818 7819 7820 7821 7822 7823
                } 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 已提交
7824
                            tmp = load_reg(s, rd);
P
pbrook 已提交
7825
                            tcg_gen_ext16u_i32(tmp, tmp);
P
pbrook 已提交
7826
                            tcg_gen_ori_i32(tmp, tmp, imm << 16);
B
bellard 已提交
7827
                        } else {
P
pbrook 已提交
7828
                            /* movw */
P
pbrook 已提交
7829 7830
                            tmp = new_tmp();
                            tcg_gen_movi_i32(tmp, imm);
B
bellard 已提交
7831 7832
                        }
                    } else {
P
pbrook 已提交
7833 7834
                        /* Add/sub 12-bit immediate.  */
                        if (rn == 15) {
P
pbrook 已提交
7835
                            offset = s->pc & ~(uint32_t)3;
P
pbrook 已提交
7836
                            if (insn & (1 << 23))
P
pbrook 已提交
7837
                                offset -= imm;
P
pbrook 已提交
7838
                            else
P
pbrook 已提交
7839
                                offset += imm;
P
pbrook 已提交
7840 7841
                            tmp = new_tmp();
                            tcg_gen_movi_i32(tmp, offset);
B
bellard 已提交
7842
                        } else {
P
pbrook 已提交
7843
                            tmp = load_reg(s, rn);
P
pbrook 已提交
7844
                            if (insn & (1 << 23))
P
pbrook 已提交
7845
                                tcg_gen_subi_i32(tmp, tmp, imm);
P
pbrook 已提交
7846
                            else
P
pbrook 已提交
7847
                                tcg_gen_addi_i32(tmp, tmp, imm);
B
bellard 已提交
7848
                        }
P
pbrook 已提交
7849
                    }
P
pbrook 已提交
7850
                    store_reg(s, rd, tmp);
P
pbrook 已提交
7851
                }
P
pbrook 已提交
7852 7853 7854 7855 7856 7857 7858 7859 7860 7861 7862 7863 7864 7865 7866 7867 7868 7869 7870 7871 7872 7873 7874 7875 7876 7877
            } 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 已提交
7878
                }
P
pbrook 已提交
7879 7880 7881 7882 7883 7884 7885 7886 7887 7888 7889 7890 7891
                gen_op_movl_T1_im(imm);
                rn = (insn >> 16) & 0xf;
                if (rn == 15)
                    gen_op_movl_T0_im(0);
                else
                    gen_movl_T0_reg(s, rn);
                op = (insn >> 21) & 0xf;
                if (gen_thumb2_data_op(s, op, (insn & (1 << 20)) != 0,
                                       shifter_out))
                    goto illegal_op;
                rd = (insn >> 8) & 0xf;
                if (rd != 15) {
                    gen_movl_reg_T0(s, rd);
B
bellard 已提交
7892 7893
                }
            }
P
pbrook 已提交
7894 7895 7896 7897 7898 7899
        }
        break;
    case 12: /* Load/store single data item.  */
        {
        int postinc = 0;
        int writeback = 0;
P
pbrook 已提交
7900
        int user;
P
pbrook 已提交
7901 7902
        if ((insn & 0x01100000) == 0x01000000) {
            if (disas_neon_ls_insn(env, s, insn))
7903
                goto illegal_op;
P
pbrook 已提交
7904 7905
            break;
        }
P
pbrook 已提交
7906
        user = IS_USER(s);
P
pbrook 已提交
7907
        if (rn == 15) {
P
pbrook 已提交
7908
            addr = new_tmp();
P
pbrook 已提交
7909 7910 7911 7912 7913 7914 7915
            /* 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 已提交
7916
            tcg_gen_movi_i32(addr, imm);
P
pbrook 已提交
7917
        } else {
P
pbrook 已提交
7918
            addr = load_reg(s, rn);
P
pbrook 已提交
7919 7920 7921
            if (insn & (1 << 23)) {
                /* Positive offset.  */
                imm = insn & 0xfff;
P
pbrook 已提交
7922
                tcg_gen_addi_i32(addr, addr, imm);
P
pbrook 已提交
7923 7924 7925 7926 7927 7928 7929
            } else {
                op = (insn >> 8) & 7;
                imm = insn & 0xff;
                switch (op) {
                case 0: case 8: /* Shifted Register.  */
                    shift = (insn >> 4) & 0xf;
                    if (shift > 3)
7930
                        goto illegal_op;
P
pbrook 已提交
7931
                    tmp = load_reg(s, rm);
P
pbrook 已提交
7932
                    if (shift)
P
pbrook 已提交
7933
                        tcg_gen_shli_i32(tmp, tmp, shift);
P
pbrook 已提交
7934
                    tcg_gen_add_i32(addr, addr, tmp);
P
pbrook 已提交
7935
                    dead_tmp(tmp);
P
pbrook 已提交
7936 7937
                    break;
                case 4: /* Negative offset.  */
P
pbrook 已提交
7938
                    tcg_gen_addi_i32(addr, addr, -imm);
P
pbrook 已提交
7939 7940
                    break;
                case 6: /* User privilege.  */
P
pbrook 已提交
7941 7942
                    tcg_gen_addi_i32(addr, addr, imm);
                    user = 1;
P
pbrook 已提交
7943 7944 7945 7946 7947 7948 7949 7950 7951 7952 7953 7954
                    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 已提交
7955
                    tcg_gen_addi_i32(addr, addr, imm);
P
pbrook 已提交
7956 7957 7958
                    writeback = 1;
                    break;
                default:
B
bellard 已提交
7959
                    goto illegal_op;
P
pbrook 已提交
7960 7961 7962 7963 7964 7965 7966 7967
                }
            }
        }
        op = ((insn >> 21) & 3) | ((insn >> 22) & 4);
        if (insn & (1 << 20)) {
            /* Load.  */
            if (rs == 15 && op != 2) {
                if (op & 2)
B
bellard 已提交
7968
                    goto illegal_op;
P
pbrook 已提交
7969 7970 7971
                /* Memory hint.  Implemented as NOP.  */
            } else {
                switch (op) {
P
pbrook 已提交
7972 7973 7974 7975 7976
                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 已提交
7977 7978 7979
                default: goto illegal_op;
                }
                if (rs == 15) {
P
pbrook 已提交
7980
                    gen_bx(s, tmp);
P
pbrook 已提交
7981
                } else {
P
pbrook 已提交
7982
                    store_reg(s, rs, tmp);
P
pbrook 已提交
7983 7984 7985 7986 7987
                }
            }
        } else {
            /* Store.  */
            if (rs == 15)
B
bellard 已提交
7988
                goto illegal_op;
P
pbrook 已提交
7989
            tmp = load_reg(s, rs);
P
pbrook 已提交
7990
            switch (op) {
P
pbrook 已提交
7991 7992 7993
            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 已提交
7994
            default: goto illegal_op;
B
bellard 已提交
7995
            }
B
bellard 已提交
7996
        }
P
pbrook 已提交
7997
        if (postinc)
P
pbrook 已提交
7998 7999 8000 8001 8002 8003
            tcg_gen_addi_i32(addr, addr, imm);
        if (writeback) {
            store_reg(s, rn, addr);
        } else {
            dead_tmp(addr);
        }
P
pbrook 已提交
8004 8005 8006 8007
        }
        break;
    default:
        goto illegal_op;
B
bellard 已提交
8008
    }
P
pbrook 已提交
8009 8010 8011
    return 0;
illegal_op:
    return 1;
B
bellard 已提交
8012 8013
}

P
pbrook 已提交
8014
static void disas_thumb_insn(CPUState *env, DisasContext *s)
B
bellard 已提交
8015 8016 8017 8018
{
    uint32_t val, insn, op, rm, rn, rd, shift, cond;
    int32_t offset;
    int i;
P
pbrook 已提交
8019
    TCGv tmp;
P
pbrook 已提交
8020
    TCGv tmp2;
P
pbrook 已提交
8021
    TCGv addr;
B
bellard 已提交
8022

P
pbrook 已提交
8023 8024 8025
    if (s->condexec_mask) {
        cond = s->condexec_cond;
        s->condlabel = gen_new_label();
P
pbrook 已提交
8026
        gen_test_cc(cond ^ 1, s->condlabel);
P
pbrook 已提交
8027 8028 8029
        s->condjmp = 1;
    }

B
bellard 已提交
8030
    insn = lduw_code(s->pc);
B
bellard 已提交
8031
    s->pc += 2;
B
bellard 已提交
8032

B
bellard 已提交
8033 8034 8035 8036 8037 8038 8039 8040 8041 8042 8043 8044 8045 8046 8047 8048
    switch (insn >> 12) {
    case 0: case 1:
        rd = insn & 7;
        op = (insn >> 11) & 3;
        if (op == 3) {
            /* add/subtract */
            rn = (insn >> 3) & 7;
            gen_movl_T0_reg(s, rn);
            if (insn & (1 << 10)) {
                /* immediate */
                gen_op_movl_T1_im((insn >> 6) & 7);
            } else {
                /* reg */
                rm = (insn >> 6) & 7;
                gen_movl_T1_reg(s, rm);
            }
P
pbrook 已提交
8049 8050 8051 8052 8053 8054 8055 8056 8057 8058 8059
            if (insn & (1 << 9)) {
                if (s->condexec_mask)
                    gen_op_subl_T0_T1();
                else
                    gen_op_subl_T0_T1_cc();
            } else {
                if (s->condexec_mask)
                    gen_op_addl_T0_T1();
                else
                    gen_op_addl_T0_T1_cc();
            }
B
bellard 已提交
8060 8061 8062 8063 8064
            gen_movl_reg_T0(s, rd);
        } else {
            /* shift immediate */
            rm = (insn >> 3) & 7;
            shift = (insn >> 6) & 0x1f;
P
pbrook 已提交
8065 8066 8067 8068 8069
            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 已提交
8070 8071 8072 8073 8074 8075 8076 8077 8078 8079 8080 8081 8082 8083
        }
        break;
    case 2: case 3:
        /* arithmetic large immediate */
        op = (insn >> 11) & 3;
        rd = (insn >> 8) & 0x7;
        if (op == 0) {
            gen_op_movl_T0_im(insn & 0xff);
        } else {
            gen_movl_T0_reg(s, rd);
            gen_op_movl_T1_im(insn & 0xff);
        }
        switch (op) {
        case 0: /* mov */
P
pbrook 已提交
8084 8085
            if (!s->condexec_mask)
                gen_op_logic_T0_cc();
B
bellard 已提交
8086 8087 8088 8089 8090
            break;
        case 1: /* cmp */
            gen_op_subl_T0_T1_cc();
            break;
        case 2: /* add */
P
pbrook 已提交
8091 8092 8093 8094
            if (s->condexec_mask)
                gen_op_addl_T0_T1();
            else
                gen_op_addl_T0_T1_cc();
B
bellard 已提交
8095 8096
            break;
        case 3: /* sub */
P
pbrook 已提交
8097 8098 8099 8100
            if (s->condexec_mask)
                gen_op_subl_T0_T1();
            else
                gen_op_subl_T0_T1_cc();
B
bellard 已提交
8101 8102 8103 8104 8105 8106 8107 8108
            break;
        }
        if (op != 1)
            gen_movl_reg_T0(s, rd);
        break;
    case 4:
        if (insn & (1 << 11)) {
            rd = (insn >> 8) & 7;
B
bellard 已提交
8109 8110 8111
            /* load pc-relative.  Bit 1 of PC is ignored.  */
            val = s->pc + 2 + ((insn & 0xff) * 4);
            val &= ~(uint32_t)2;
P
pbrook 已提交
8112 8113 8114 8115 8116
            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 已提交
8117 8118 8119 8120 8121 8122 8123 8124 8125 8126 8127 8128 8129 8130 8131 8132 8133 8134 8135 8136 8137 8138 8139 8140
            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 */
                gen_movl_T0_reg(s, rd);
                gen_movl_T1_reg(s, rm);
                gen_op_addl_T0_T1();
                gen_movl_reg_T0(s, rd);
                break;
            case 1: /* cmp */
                gen_movl_T0_reg(s, rd);
                gen_movl_T1_reg(s, rm);
                gen_op_subl_T0_T1_cc();
                break;
            case 2: /* mov/cpy */
                gen_movl_T0_reg(s, rm);
                gen_movl_reg_T0(s, rd);
                break;
            case 3:/* branch [and link] exchange thumb register */
P
pbrook 已提交
8141
                tmp = load_reg(s, rm);
B
bellard 已提交
8142 8143
                if (insn & (1 << 7)) {
                    val = (uint32_t)s->pc | 1;
P
pbrook 已提交
8144 8145 8146
                    tmp2 = new_tmp();
                    tcg_gen_movi_i32(tmp2, val);
                    store_reg(s, 14, tmp2);
B
bellard 已提交
8147
                }
P
pbrook 已提交
8148
                gen_bx(s, tmp);
B
bellard 已提交
8149 8150 8151 8152 8153 8154 8155 8156 8157 8158 8159 8160 8161 8162 8163 8164 8165 8166 8167 8168 8169 8170 8171 8172 8173
                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;
        }

        if (op == 9) /* neg */
            gen_op_movl_T0_im(0);
        else if (op != 0xf) /* mvn doesn't read its first operand */
            gen_movl_T0_reg(s, rd);

        gen_movl_T1_reg(s, rm);
B
bellard 已提交
8174
        switch (op) {
B
bellard 已提交
8175 8176
        case 0x0: /* and */
            gen_op_andl_T0_T1();
P
pbrook 已提交
8177 8178
            if (!s->condexec_mask)
                gen_op_logic_T0_cc();
B
bellard 已提交
8179 8180 8181
            break;
        case 0x1: /* eor */
            gen_op_xorl_T0_T1();
P
pbrook 已提交
8182 8183
            if (!s->condexec_mask)
                gen_op_logic_T0_cc();
B
bellard 已提交
8184 8185
            break;
        case 0x2: /* lsl */
P
pbrook 已提交
8186
            if (s->condexec_mask) {
P
pbrook 已提交
8187
                gen_helper_shl(cpu_T[1], cpu_T[1], cpu_T[0]);
P
pbrook 已提交
8188
            } else {
P
pbrook 已提交
8189
                gen_helper_shl_cc(cpu_T[1], cpu_T[1], cpu_T[0]);
P
pbrook 已提交
8190 8191
                gen_op_logic_T1_cc();
            }
B
bellard 已提交
8192 8193
            break;
        case 0x3: /* lsr */
P
pbrook 已提交
8194
            if (s->condexec_mask) {
P
pbrook 已提交
8195
                gen_helper_shr(cpu_T[1], cpu_T[1], cpu_T[0]);
P
pbrook 已提交
8196
            } else {
P
pbrook 已提交
8197
                gen_helper_shr_cc(cpu_T[1], cpu_T[1], cpu_T[0]);
P
pbrook 已提交
8198 8199
                gen_op_logic_T1_cc();
            }
B
bellard 已提交
8200 8201
            break;
        case 0x4: /* asr */
P
pbrook 已提交
8202
            if (s->condexec_mask) {
P
pbrook 已提交
8203
                gen_helper_sar(cpu_T[1], cpu_T[1], cpu_T[0]);
P
pbrook 已提交
8204
            } else {
P
pbrook 已提交
8205
                gen_helper_sar_cc(cpu_T[1], cpu_T[1], cpu_T[0]);
P
pbrook 已提交
8206 8207
                gen_op_logic_T1_cc();
            }
B
bellard 已提交
8208 8209
            break;
        case 0x5: /* adc */
P
pbrook 已提交
8210
            if (s->condexec_mask)
P
pbrook 已提交
8211
                gen_adc_T0_T1();
P
pbrook 已提交
8212 8213
            else
                gen_op_adcl_T0_T1_cc();
B
bellard 已提交
8214 8215
            break;
        case 0x6: /* sbc */
P
pbrook 已提交
8216
            if (s->condexec_mask)
P
pbrook 已提交
8217
                gen_sbc_T0_T1();
P
pbrook 已提交
8218 8219
            else
                gen_op_sbcl_T0_T1_cc();
B
bellard 已提交
8220 8221
            break;
        case 0x7: /* ror */
P
pbrook 已提交
8222
            if (s->condexec_mask) {
P
pbrook 已提交
8223
                gen_helper_ror(cpu_T[1], cpu_T[1], cpu_T[0]);
P
pbrook 已提交
8224
            } else {
P
pbrook 已提交
8225
                gen_helper_ror_cc(cpu_T[1], cpu_T[1], cpu_T[0]);
P
pbrook 已提交
8226 8227
                gen_op_logic_T1_cc();
            }
B
bellard 已提交
8228 8229 8230 8231 8232
            break;
        case 0x8: /* tst */
            gen_op_andl_T0_T1();
            gen_op_logic_T0_cc();
            rd = 16;
B
bellard 已提交
8233
            break;
B
bellard 已提交
8234
        case 0x9: /* neg */
P
pbrook 已提交
8235
            if (s->condexec_mask)
P
pbrook 已提交
8236
                tcg_gen_neg_i32(cpu_T[0], cpu_T[1]);
P
pbrook 已提交
8237 8238
            else
                gen_op_subl_T0_T1_cc();
B
bellard 已提交
8239 8240 8241 8242 8243 8244 8245 8246 8247 8248 8249
            break;
        case 0xa: /* cmp */
            gen_op_subl_T0_T1_cc();
            rd = 16;
            break;
        case 0xb: /* cmn */
            gen_op_addl_T0_T1_cc();
            rd = 16;
            break;
        case 0xc: /* orr */
            gen_op_orl_T0_T1();
P
pbrook 已提交
8250 8251
            if (!s->condexec_mask)
                gen_op_logic_T0_cc();
B
bellard 已提交
8252 8253 8254
            break;
        case 0xd: /* mul */
            gen_op_mull_T0_T1();
P
pbrook 已提交
8255 8256
            if (!s->condexec_mask)
                gen_op_logic_T0_cc();
B
bellard 已提交
8257 8258 8259
            break;
        case 0xe: /* bic */
            gen_op_bicl_T0_T1();
P
pbrook 已提交
8260 8261
            if (!s->condexec_mask)
                gen_op_logic_T0_cc();
B
bellard 已提交
8262 8263 8264
            break;
        case 0xf: /* mvn */
            gen_op_notl_T1();
P
pbrook 已提交
8265 8266
            if (!s->condexec_mask)
                gen_op_logic_T1_cc();
B
bellard 已提交
8267
            val = 1;
B
bellard 已提交
8268
            rm = rd;
B
bellard 已提交
8269 8270 8271 8272
            break;
        }
        if (rd != 16) {
            if (val)
B
bellard 已提交
8273
                gen_movl_reg_T1(s, rm);
B
bellard 已提交
8274 8275 8276 8277 8278 8279 8280 8281 8282 8283 8284
            else
                gen_movl_reg_T0(s, rd);
        }
        break;

    case 5:
        /* load/store register offset.  */
        rd = insn & 7;
        rn = (insn >> 3) & 7;
        rm = (insn >> 6) & 7;
        op = (insn >> 9) & 7;
P
pbrook 已提交
8285
        addr = load_reg(s, rn);
P
pbrook 已提交
8286
        tmp = load_reg(s, rm);
P
pbrook 已提交
8287
        tcg_gen_add_i32(addr, addr, tmp);
P
pbrook 已提交
8288
        dead_tmp(tmp);
B
bellard 已提交
8289 8290

        if (op < 3) /* store */
P
pbrook 已提交
8291
            tmp = load_reg(s, rd);
B
bellard 已提交
8292 8293 8294

        switch (op) {
        case 0: /* str */
P
pbrook 已提交
8295
            gen_st32(tmp, addr, IS_USER(s));
B
bellard 已提交
8296 8297
            break;
        case 1: /* strh */
P
pbrook 已提交
8298
            gen_st16(tmp, addr, IS_USER(s));
B
bellard 已提交
8299 8300
            break;
        case 2: /* strb */
P
pbrook 已提交
8301
            gen_st8(tmp, addr, IS_USER(s));
B
bellard 已提交
8302 8303
            break;
        case 3: /* ldrsb */
P
pbrook 已提交
8304
            tmp = gen_ld8s(addr, IS_USER(s));
B
bellard 已提交
8305 8306
            break;
        case 4: /* ldr */
P
pbrook 已提交
8307
            tmp = gen_ld32(addr, IS_USER(s));
B
bellard 已提交
8308 8309
            break;
        case 5: /* ldrh */
P
pbrook 已提交
8310
            tmp = gen_ld16u(addr, IS_USER(s));
B
bellard 已提交
8311 8312
            break;
        case 6: /* ldrb */
P
pbrook 已提交
8313
            tmp = gen_ld8u(addr, IS_USER(s));
B
bellard 已提交
8314 8315
            break;
        case 7: /* ldrsh */
P
pbrook 已提交
8316
            tmp = gen_ld16s(addr, IS_USER(s));
B
bellard 已提交
8317 8318 8319
            break;
        }
        if (op >= 3) /* load */
P
pbrook 已提交
8320 8321
            store_reg(s, rd, tmp);
        dead_tmp(addr);
B
bellard 已提交
8322 8323 8324 8325 8326 8327
        break;

    case 6:
        /* load/store word immediate offset */
        rd = insn & 7;
        rn = (insn >> 3) & 7;
P
pbrook 已提交
8328
        addr = load_reg(s, rn);
B
bellard 已提交
8329
        val = (insn >> 4) & 0x7c;
P
pbrook 已提交
8330
        tcg_gen_addi_i32(addr, addr, val);
B
bellard 已提交
8331 8332 8333

        if (insn & (1 << 11)) {
            /* load */
P
pbrook 已提交
8334 8335
            tmp = gen_ld32(addr, IS_USER(s));
            store_reg(s, rd, tmp);
B
bellard 已提交
8336 8337
        } else {
            /* store */
P
pbrook 已提交
8338 8339
            tmp = load_reg(s, rd);
            gen_st32(tmp, addr, IS_USER(s));
B
bellard 已提交
8340
        }
P
pbrook 已提交
8341
        dead_tmp(addr);
B
bellard 已提交
8342 8343 8344 8345 8346 8347
        break;

    case 7:
        /* load/store byte immediate offset */
        rd = insn & 7;
        rn = (insn >> 3) & 7;
P
pbrook 已提交
8348
        addr = load_reg(s, rn);
B
bellard 已提交
8349
        val = (insn >> 6) & 0x1f;
P
pbrook 已提交
8350
        tcg_gen_addi_i32(addr, addr, val);
B
bellard 已提交
8351 8352 8353

        if (insn & (1 << 11)) {
            /* load */
P
pbrook 已提交
8354 8355
            tmp = gen_ld8u(addr, IS_USER(s));
            store_reg(s, rd, tmp);
B
bellard 已提交
8356 8357
        } else {
            /* store */
P
pbrook 已提交
8358 8359
            tmp = load_reg(s, rd);
            gen_st8(tmp, addr, IS_USER(s));
B
bellard 已提交
8360
        }
P
pbrook 已提交
8361
        dead_tmp(addr);
B
bellard 已提交
8362 8363 8364 8365 8366 8367
        break;

    case 8:
        /* load/store halfword immediate offset */
        rd = insn & 7;
        rn = (insn >> 3) & 7;
P
pbrook 已提交
8368
        addr = load_reg(s, rn);
B
bellard 已提交
8369
        val = (insn >> 5) & 0x3e;
P
pbrook 已提交
8370
        tcg_gen_addi_i32(addr, addr, val);
B
bellard 已提交
8371 8372 8373

        if (insn & (1 << 11)) {
            /* load */
P
pbrook 已提交
8374 8375
            tmp = gen_ld16u(addr, IS_USER(s));
            store_reg(s, rd, tmp);
B
bellard 已提交
8376 8377
        } else {
            /* store */
P
pbrook 已提交
8378 8379
            tmp = load_reg(s, rd);
            gen_st16(tmp, addr, IS_USER(s));
B
bellard 已提交
8380
        }
P
pbrook 已提交
8381
        dead_tmp(addr);
B
bellard 已提交
8382 8383 8384 8385 8386
        break;

    case 9:
        /* load/store from stack */
        rd = (insn >> 8) & 7;
P
pbrook 已提交
8387
        addr = load_reg(s, 13);
B
bellard 已提交
8388
        val = (insn & 0xff) * 4;
P
pbrook 已提交
8389
        tcg_gen_addi_i32(addr, addr, val);
B
bellard 已提交
8390 8391 8392

        if (insn & (1 << 11)) {
            /* load */
P
pbrook 已提交
8393 8394
            tmp = gen_ld32(addr, IS_USER(s));
            store_reg(s, rd, tmp);
B
bellard 已提交
8395 8396
        } else {
            /* store */
P
pbrook 已提交
8397 8398
            tmp = load_reg(s, rd);
            gen_st32(tmp, addr, IS_USER(s));
B
bellard 已提交
8399
        }
P
pbrook 已提交
8400
        dead_tmp(addr);
B
bellard 已提交
8401 8402 8403 8404 8405
        break;

    case 10:
        /* add to high reg */
        rd = (insn >> 8) & 7;
B
bellard 已提交
8406 8407
        if (insn & (1 << 11)) {
            /* SP */
P
pbrook 已提交
8408
            tmp = load_reg(s, 13);
B
bellard 已提交
8409 8410
        } else {
            /* PC. bit 1 is ignored.  */
P
pbrook 已提交
8411 8412
            tmp = new_tmp();
            tcg_gen_movi_i32(tmp, (s->pc + 2) & ~(uint32_t)2);
B
bellard 已提交
8413
        }
B
bellard 已提交
8414
        val = (insn & 0xff) * 4;
P
pbrook 已提交
8415 8416
        tcg_gen_addi_i32(tmp, tmp, val);
        store_reg(s, rd, tmp);
B
bellard 已提交
8417 8418 8419 8420 8421 8422 8423 8424
        break;

    case 11:
        /* misc */
        op = (insn >> 8) & 0xf;
        switch (op) {
        case 0:
            /* adjust stack pointer */
P
pbrook 已提交
8425
            tmp = load_reg(s, 13);
B
bellard 已提交
8426 8427
            val = (insn & 0x7f) * 4;
            if (insn & (1 << 7))
B
balrog 已提交
8428
                val = -(int32_t)val;
P
pbrook 已提交
8429 8430
            tcg_gen_addi_i32(tmp, tmp, val);
            store_reg(s, 13, tmp);
B
bellard 已提交
8431 8432
            break;

P
pbrook 已提交
8433 8434 8435 8436
        case 2: /* sign/zero extend.  */
            ARCH(6);
            rd = insn & 7;
            rm = (insn >> 3) & 7;
P
pbrook 已提交
8437
            tmp = load_reg(s, rm);
P
pbrook 已提交
8438
            switch ((insn >> 6) & 3) {
P
pbrook 已提交
8439 8440 8441 8442
            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 已提交
8443
            }
P
pbrook 已提交
8444
            store_reg(s, rd, tmp);
P
pbrook 已提交
8445
            break;
B
bellard 已提交
8446 8447
        case 4: case 5: case 0xc: case 0xd:
            /* push/pop */
P
pbrook 已提交
8448
            addr = load_reg(s, 13);
B
bellard 已提交
8449 8450
            if (insn & (1 << 8))
                offset = 4;
B
bellard 已提交
8451
            else
B
bellard 已提交
8452 8453 8454 8455 8456 8457
                offset = 0;
            for (i = 0; i < 8; i++) {
                if (insn & (1 << i))
                    offset += 4;
            }
            if ((insn & (1 << 11)) == 0) {
P
pbrook 已提交
8458
                tcg_gen_addi_i32(addr, addr, -offset);
B
bellard 已提交
8459
            }
B
bellard 已提交
8460 8461 8462 8463
            for (i = 0; i < 8; i++) {
                if (insn & (1 << i)) {
                    if (insn & (1 << 11)) {
                        /* pop */
P
pbrook 已提交
8464 8465
                        tmp = gen_ld32(addr, IS_USER(s));
                        store_reg(s, i, tmp);
B
bellard 已提交
8466 8467
                    } else {
                        /* push */
P
pbrook 已提交
8468 8469
                        tmp = load_reg(s, i);
                        gen_st32(tmp, addr, IS_USER(s));
B
bellard 已提交
8470
                    }
B
bellard 已提交
8471
                    /* advance to the next address.  */
P
pbrook 已提交
8472
                    tcg_gen_addi_i32(addr, addr, 4);
B
bellard 已提交
8473 8474
                }
            }
P
pbrook 已提交
8475
            TCGV_UNUSED(tmp);
B
bellard 已提交
8476 8477 8478
            if (insn & (1 << 8)) {
                if (insn & (1 << 11)) {
                    /* pop pc */
P
pbrook 已提交
8479
                    tmp = gen_ld32(addr, IS_USER(s));
B
bellard 已提交
8480 8481 8482 8483
                    /* don't set the pc until the rest of the instruction
                       has completed */
                } else {
                    /* push lr */
P
pbrook 已提交
8484 8485
                    tmp = load_reg(s, 14);
                    gen_st32(tmp, addr, IS_USER(s));
B
bellard 已提交
8486
                }
P
pbrook 已提交
8487
                tcg_gen_addi_i32(addr, addr, 4);
B
bellard 已提交
8488
            }
B
bellard 已提交
8489
            if ((insn & (1 << 11)) == 0) {
P
pbrook 已提交
8490
                tcg_gen_addi_i32(addr, addr, -offset);
B
bellard 已提交
8491
            }
B
bellard 已提交
8492
            /* write back the new stack pointer */
P
pbrook 已提交
8493
            store_reg(s, 13, addr);
B
bellard 已提交
8494 8495
            /* set the new PC value */
            if ((insn & 0x0900) == 0x0900)
P
pbrook 已提交
8496
                gen_bx(s, tmp);
B
bellard 已提交
8497 8498
            break;

P
pbrook 已提交
8499 8500
        case 1: case 3: case 9: case 11: /* czb */
            rm = insn & 7;
P
pbrook 已提交
8501
            tmp = load_reg(s, rm);
P
pbrook 已提交
8502 8503 8504
            s->condlabel = gen_new_label();
            s->condjmp = 1;
            if (insn & (1 << 11))
P
pbrook 已提交
8505
                tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, s->condlabel);
P
pbrook 已提交
8506
            else
P
pbrook 已提交
8507
                tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, s->condlabel);
P
pbrook 已提交
8508
            dead_tmp(tmp);
P
pbrook 已提交
8509 8510 8511 8512 8513 8514 8515 8516 8517 8518 8519 8520 8521 8522 8523 8524 8525
            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 已提交
8526
        case 0xe: /* bkpt */
P
pbrook 已提交
8527
            gen_set_condexec(s);
P
pbrook 已提交
8528
            gen_set_pc_im(s->pc - 2);
P
pbrook 已提交
8529
            gen_exception(EXCP_BKPT);
P
pbrook 已提交
8530 8531 8532
            s->is_jmp = DISAS_JUMP;
            break;

P
pbrook 已提交
8533 8534 8535 8536
        case 0xa: /* rev */
            ARCH(6);
            rn = (insn >> 3) & 0x7;
            rd = insn & 0x7;
P
pbrook 已提交
8537
            tmp = load_reg(s, rn);
P
pbrook 已提交
8538
            switch ((insn >> 6) & 3) {
A
aurel32 已提交
8539
            case 0: tcg_gen_bswap32_i32(tmp, tmp); break;
P
pbrook 已提交
8540 8541
            case 1: gen_rev16(tmp); break;
            case 3: gen_revsh(tmp); break;
P
pbrook 已提交
8542 8543
            default: goto illegal_op;
            }
P
pbrook 已提交
8544
            store_reg(s, rd, tmp);
P
pbrook 已提交
8545 8546 8547 8548 8549 8550 8551
            break;

        case 6: /* cps */
            ARCH(6);
            if (IS_USER(s))
                break;
            if (IS_M(env)) {
P
pbrook 已提交
8552
                tmp = tcg_const_i32((insn & (1 << 4)) != 0);
P
pbrook 已提交
8553
                /* PRIMASK */
P
pbrook 已提交
8554 8555 8556 8557
                if (insn & 1) {
                    addr = tcg_const_i32(16);
                    gen_helper_v7m_msr(cpu_env, addr, tmp);
                }
P
pbrook 已提交
8558
                /* FAULTMASK */
P
pbrook 已提交
8559 8560 8561 8562
                if (insn & 2) {
                    addr = tcg_const_i32(17);
                    gen_helper_v7m_msr(cpu_env, addr, tmp);
                }
P
pbrook 已提交
8563 8564 8565 8566 8567 8568 8569 8570 8571 8572 8573 8574 8575
                gen_lookup_tb(s);
            } else {
                if (insn & (1 << 4))
                    shift = CPSR_A | CPSR_I | CPSR_F;
                else
                    shift = 0;

                val = ((insn & 7) << 6) & shift;
                gen_op_movl_T0_im(val);
                gen_set_psr_T0(s, shift, 0);
            }
            break;

B
bellard 已提交
8576 8577 8578 8579 8580 8581 8582 8583
        default:
            goto undef;
        }
        break;

    case 12:
        /* load/store multiple */
        rn = (insn >> 8) & 0x7;
P
pbrook 已提交
8584
        addr = load_reg(s, rn);
B
bellard 已提交
8585 8586 8587 8588
        for (i = 0; i < 8; i++) {
            if (insn & (1 << i)) {
                if (insn & (1 << 11)) {
                    /* load */
P
pbrook 已提交
8589 8590
                    tmp = gen_ld32(addr, IS_USER(s));
                    store_reg(s, i, tmp);
B
bellard 已提交
8591 8592
                } else {
                    /* store */
P
pbrook 已提交
8593 8594
                    tmp = load_reg(s, i);
                    gen_st32(tmp, addr, IS_USER(s));
B
bellard 已提交
8595
                }
B
bellard 已提交
8596
                /* advance to the next address */
P
pbrook 已提交
8597
                tcg_gen_addi_i32(addr, addr, 4);
B
bellard 已提交
8598 8599
            }
        }
B
bellard 已提交
8600
        /* Base register writeback.  */
P
pbrook 已提交
8601 8602 8603 8604 8605
        if ((insn & (1 << rn)) == 0) {
            store_reg(s, rn, addr);
        } else {
            dead_tmp(addr);
        }
B
bellard 已提交
8606 8607 8608 8609 8610 8611 8612 8613 8614 8615
        break;

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

        if (cond == 0xf) {
            /* swi */
P
pbrook 已提交
8616
            gen_set_condexec(s);
8617
            gen_set_pc_im(s->pc);
P
pbrook 已提交
8618
            s->is_jmp = DISAS_SWI;
B
bellard 已提交
8619 8620 8621
            break;
        }
        /* generate a conditional jump to next instruction */
8622
        s->condlabel = gen_new_label();
P
pbrook 已提交
8623
        gen_test_cc(cond ^ 1, s->condlabel);
8624
        s->condjmp = 1;
B
bellard 已提交
8625 8626

        /* jump to the offset */
B
bellard 已提交
8627
        val = (uint32_t)s->pc + 2;
B
bellard 已提交
8628
        offset = ((int32_t)insn << 24) >> 24;
B
bellard 已提交
8629
        val += offset << 1;
B
bellard 已提交
8630
        gen_jmp(s, val);
B
bellard 已提交
8631 8632 8633
        break;

    case 14:
P
pbrook 已提交
8634
        if (insn & (1 << 11)) {
P
pbrook 已提交
8635 8636
            if (disas_thumb2_insn(env, s, insn))
              goto undef32;
P
pbrook 已提交
8637 8638
            break;
        }
P
pbrook 已提交
8639
        /* unconditional branch */
B
bellard 已提交
8640 8641 8642
        val = (uint32_t)s->pc;
        offset = ((int32_t)insn << 21) >> 21;
        val += (offset << 1) + 2;
B
bellard 已提交
8643
        gen_jmp(s, val);
B
bellard 已提交
8644 8645 8646
        break;

    case 15:
P
pbrook 已提交
8647
        if (disas_thumb2_insn(env, s, insn))
B
balrog 已提交
8648
            goto undef32;
P
pbrook 已提交
8649
        break;
B
bellard 已提交
8650 8651
    }
    return;
P
pbrook 已提交
8652 8653
undef32:
    gen_set_condexec(s);
P
pbrook 已提交
8654
    gen_set_pc_im(s->pc - 4);
P
pbrook 已提交
8655
    gen_exception(EXCP_UDEF);
P
pbrook 已提交
8656 8657 8658
    s->is_jmp = DISAS_JUMP;
    return;
illegal_op:
B
bellard 已提交
8659
undef:
P
pbrook 已提交
8660
    gen_set_condexec(s);
P
pbrook 已提交
8661
    gen_set_pc_im(s->pc - 2);
P
pbrook 已提交
8662
    gen_exception(EXCP_UDEF);
B
bellard 已提交
8663 8664 8665
    s->is_jmp = DISAS_JUMP;
}

B
bellard 已提交
8666 8667 8668
/* 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. */
8669 8670 8671
static inline void gen_intermediate_code_internal(CPUState *env,
                                                  TranslationBlock *tb,
                                                  int search_pc)
B
bellard 已提交
8672 8673
{
    DisasContext dc1, *dc = &dc1;
8674
    CPUBreakpoint *bp;
B
bellard 已提交
8675 8676
    uint16_t *gen_opc_end;
    int j, lj;
B
bellard 已提交
8677
    target_ulong pc_start;
B
bellard 已提交
8678
    uint32_t next_page_start;
P
pbrook 已提交
8679 8680
    int num_insns;
    int max_insns;
8681

B
bellard 已提交
8682
    /* generate intermediate code */
P
pbrook 已提交
8683 8684
    num_temps = 0;

B
bellard 已提交
8685
    pc_start = tb->pc;
8686

B
bellard 已提交
8687 8688 8689 8690 8691 8692
    dc->tb = tb;

    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;

    dc->is_jmp = DISAS_NEXT;
    dc->pc = pc_start;
B
bellard 已提交
8693
    dc->singlestep_enabled = env->singlestep_enabled;
8694
    dc->condjmp = 0;
B
bellard 已提交
8695
    dc->thumb = env->thumb;
P
pbrook 已提交
8696 8697
    dc->condexec_mask = (env->condexec_bits & 0xf) << 1;
    dc->condexec_cond = env->condexec_bits >> 4;
B
bellard 已提交
8698
#if !defined(CONFIG_USER_ONLY)
P
pbrook 已提交
8699 8700 8701 8702 8703
    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 已提交
8704
#endif
P
pbrook 已提交
8705 8706 8707 8708
    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 已提交
8709 8710
    cpu_V0 = cpu_F0d;
    cpu_V1 = cpu_F1d;
P
pbrook 已提交
8711
    /* FIXME: cpu_M0 can probably be the same as cpu_V0.  */
P
pbrook 已提交
8712
    cpu_M0 = tcg_temp_new_i64();
B
bellard 已提交
8713
    next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
B
bellard 已提交
8714
    lj = -1;
P
pbrook 已提交
8715 8716 8717 8718 8719 8720
    num_insns = 0;
    max_insns = tb->cflags & CF_COUNT_MASK;
    if (max_insns == 0)
        max_insns = CF_COUNT_MASK;

    gen_icount_start();
P
pbrook 已提交
8721 8722 8723
    /* 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 已提交
8724 8725 8726
      {
        TCGv tmp = new_tmp();
        tcg_gen_movi_i32(tmp, 0);
P
pbrook 已提交
8727
        store_cpu_field(tmp, condexec_bits);
P
pbrook 已提交
8728
      }
B
bellard 已提交
8729
    do {
8730 8731 8732 8733 8734 8735 8736 8737 8738 8739
#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 已提交
8740 8741 8742
        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 已提交
8743
            gen_exception(EXCP_EXCEPTION_EXIT);
8744 8745
            dc->is_jmp = DISAS_UPDATE;
            break;
P
pbrook 已提交
8746 8747 8748
        }
#endif

B
Blue Swirl 已提交
8749 8750
        if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
            QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
8751
                if (bp->pc == dc->pc) {
P
pbrook 已提交
8752
                    gen_set_condexec(dc);
P
pbrook 已提交
8753
                    gen_set_pc_im(dc->pc);
P
pbrook 已提交
8754
                    gen_exception(EXCP_DEBUG);
B
bellard 已提交
8755
                    dc->is_jmp = DISAS_JUMP;
P
pbrook 已提交
8756 8757 8758 8759
                    /* Advance PC so that clearing the breakpoint will
                       invalidate this TB.  */
                    dc->pc += 2;
                    goto done_generating;
B
bellard 已提交
8760 8761 8762 8763
                    break;
                }
            }
        }
B
bellard 已提交
8764 8765 8766 8767 8768 8769 8770
        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 已提交
8771
            gen_opc_pc[lj] = dc->pc;
B
bellard 已提交
8772
            gen_opc_instr_start[lj] = 1;
P
pbrook 已提交
8773
            gen_opc_icount[lj] = num_insns;
B
bellard 已提交
8774
        }
8775

P
pbrook 已提交
8776 8777 8778
        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
            gen_io_start();

P
pbrook 已提交
8779 8780 8781 8782 8783 8784 8785 8786 8787 8788 8789 8790 8791
        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 已提交
8792 8793 8794 8795
        if (num_temps) {
            fprintf(stderr, "Internal resource leak before %08x\n", dc->pc);
            num_temps = 0;
        }
8796 8797 8798 8799 8800

        if (dc->condjmp && !dc->is_jmp) {
            gen_set_label(dc->condlabel);
            dc->condjmp = 0;
        }
B
balrog 已提交
8801
        /* Translation stops when a conditional branch is encountered.
8802
         * Otherwise the subsequent code could get translated several times.
B
bellard 已提交
8803
         * Also stop translation when a page boundary is reached.  This
T
ths 已提交
8804
         * ensures prefetch aborts occur at the right place.  */
P
pbrook 已提交
8805
        num_insns ++;
B
bellard 已提交
8806 8807
    } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
             !env->singlestep_enabled &&
8808
             !singlestep &&
P
pbrook 已提交
8809 8810 8811 8812 8813 8814 8815 8816 8817 8818 8819
             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 已提交
8820

B
bellard 已提交
8821
    /* At this stage dc->condjmp will only be set when the skipped
P
pbrook 已提交
8822 8823
       instruction was a conditional branch or trap, and the PC has
       already been written.  */
8824
    if (unlikely(env->singlestep_enabled)) {
B
bellard 已提交
8825
        /* Make sure the pc is updated, and raise a debug exception.  */
8826
        if (dc->condjmp) {
P
pbrook 已提交
8827 8828
            gen_set_condexec(dc);
            if (dc->is_jmp == DISAS_SWI) {
P
pbrook 已提交
8829
                gen_exception(EXCP_SWI);
P
pbrook 已提交
8830
            } else {
P
pbrook 已提交
8831
                gen_exception(EXCP_DEBUG);
P
pbrook 已提交
8832
            }
8833 8834 8835
            gen_set_label(dc->condlabel);
        }
        if (dc->condjmp || !dc->is_jmp) {
P
pbrook 已提交
8836
            gen_set_pc_im(dc->pc);
8837
            dc->condjmp = 0;
B
bellard 已提交
8838
        }
P
pbrook 已提交
8839 8840
        gen_set_condexec(dc);
        if (dc->is_jmp == DISAS_SWI && !dc->condjmp) {
P
pbrook 已提交
8841
            gen_exception(EXCP_SWI);
P
pbrook 已提交
8842 8843 8844
        } else {
            /* FIXME: Single stepping a WFI insn will not halt
               the CPU.  */
P
pbrook 已提交
8845
            gen_exception(EXCP_DEBUG);
P
pbrook 已提交
8846
        }
B
bellard 已提交
8847
    } else {
P
pbrook 已提交
8848 8849 8850 8851 8852 8853 8854 8855 8856
        /* 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 已提交
8857 8858
        switch(dc->is_jmp) {
        case DISAS_NEXT:
8859
            gen_goto_tb(dc, 1, dc->pc);
B
bellard 已提交
8860 8861 8862 8863 8864
            break;
        default:
        case DISAS_JUMP:
        case DISAS_UPDATE:
            /* indicate that the hash table must be used to find the next TB */
B
bellard 已提交
8865
            tcg_gen_exit_tb(0);
B
bellard 已提交
8866 8867 8868 8869
            break;
        case DISAS_TB_JUMP:
            /* nothing more to generate */
            break;
P
pbrook 已提交
8870
        case DISAS_WFI:
P
pbrook 已提交
8871
            gen_helper_wfi();
P
pbrook 已提交
8872 8873
            break;
        case DISAS_SWI:
P
pbrook 已提交
8874
            gen_exception(EXCP_SWI);
P
pbrook 已提交
8875
            break;
B
bellard 已提交
8876
        }
8877 8878
        if (dc->condjmp) {
            gen_set_label(dc->condlabel);
P
pbrook 已提交
8879
            gen_set_condexec(dc);
8880
            gen_goto_tb(dc, 1, dc->pc);
8881 8882
            dc->condjmp = 0;
        }
B
bellard 已提交
8883
    }
P
pbrook 已提交
8884

P
pbrook 已提交
8885
done_generating:
P
pbrook 已提交
8886
    gen_icount_end(tb, num_insns);
B
bellard 已提交
8887 8888 8889
    *gen_opc_ptr = INDEX_op_end;

#ifdef DEBUG_DISAS
8890
    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
8891 8892 8893 8894
        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 已提交
8895 8896
    }
#endif
B
bellard 已提交
8897 8898 8899 8900 8901 8902
    if (search_pc) {
        j = gen_opc_ptr - gen_opc_buf;
        lj++;
        while (lj <= j)
            gen_opc_instr_start[lj++] = 0;
    } else {
B
bellard 已提交
8903
        tb->size = dc->pc - pc_start;
P
pbrook 已提交
8904
        tb->icount = num_insns;
B
bellard 已提交
8905
    }
B
bellard 已提交
8906 8907
}

8908
void gen_intermediate_code(CPUState *env, TranslationBlock *tb)
B
bellard 已提交
8909
{
8910
    gen_intermediate_code_internal(env, tb, 0);
B
bellard 已提交
8911 8912
}

8913
void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
B
bellard 已提交
8914
{
8915
    gen_intermediate_code_internal(env, tb, 1);
B
bellard 已提交
8916 8917
}

B
bellard 已提交
8918 8919 8920 8921
static const char *cpu_mode_names[16] = {
  "usr", "fiq", "irq", "svc", "???", "???", "???", "abt",
  "???", "???", "???", "und", "???", "???", "???", "sys"
};
P
pbrook 已提交
8922

8923
void cpu_dump_state(CPUState *env, FILE *f,
B
bellard 已提交
8924 8925
                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
                    int flags)
B
bellard 已提交
8926 8927
{
    int i;
T
ths 已提交
8928
#if 0
B
bellard 已提交
8929
    union {
B
bellard 已提交
8930 8931 8932 8933
        uint32_t i;
        float s;
    } s0, s1;
    CPU_DoubleU d;
P
pbrook 已提交
8934 8935 8936 8937 8938 8939
    /* ??? This assumes float64 and double have the same layout.
       Oh well, it's only debug dumps.  */
    union {
        float64 f64;
        double d;
    } d0;
T
ths 已提交
8940
#endif
B
bellard 已提交
8941
    uint32_t psr;
B
bellard 已提交
8942 8943

    for(i=0;i<16;i++) {
B
bellard 已提交
8944
        cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
B
bellard 已提交
8945
        if ((i % 4) == 3)
B
bellard 已提交
8946
            cpu_fprintf(f, "\n");
B
bellard 已提交
8947
        else
B
bellard 已提交
8948
            cpu_fprintf(f, " ");
B
bellard 已提交
8949
    }
B
bellard 已提交
8950
    psr = cpsr_read(env);
8951 8952
    cpu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%d\n",
                psr,
B
bellard 已提交
8953 8954 8955 8956
                psr & (1 << 31) ? 'N' : '-',
                psr & (1 << 30) ? 'Z' : '-',
                psr & (1 << 29) ? 'C' : '-',
                psr & (1 << 28) ? 'V' : '-',
8957
                psr & CPSR_T ? 'T' : 'A',
B
bellard 已提交
8958
                cpu_mode_names[psr & 0xf], (psr & 0x10) ? 32 : 26);
B
bellard 已提交
8959

P
pbrook 已提交
8960
#if 0
B
bellard 已提交
8961
    for (i = 0; i < 16; i++) {
B
bellard 已提交
8962 8963 8964
        d.d = env->vfp.regs[i];
        s0.i = d.l.lower;
        s1.i = d.l.upper;
P
pbrook 已提交
8965 8966
        d0.f64 = d.d;
        cpu_fprintf(f, "s%02d=%08x(%8g) s%02d=%08x(%8g) d%02d=%08x%08x(%8g)\n",
B
bellard 已提交
8967
                    i * 2, (int)s0.i, s0.s,
P
pbrook 已提交
8968
                    i * 2 + 1, (int)s1.i, s1.s,
B
bellard 已提交
8969
                    i, (int)(uint32_t)d.l.upper, (int)(uint32_t)d.l.lower,
P
pbrook 已提交
8970
                    d0.d);
B
bellard 已提交
8971
    }
P
pbrook 已提交
8972
    cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.xregs[ARM_VFP_FPSCR]);
P
pbrook 已提交
8973
#endif
B
bellard 已提交
8974
}
B
bellard 已提交
8975

A
aurel32 已提交
8976 8977 8978 8979 8980
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];
}