translate.c 296.1 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 19 20 21 22 23 24 25 26 27 28 29 30
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
#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 已提交
31
#include "tcg-op.h"
32
#include "qemu-log.h"
P
pbrook 已提交
33 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 43 44

#define ARCH(x) if (!ENABLE_ARCH_##x) goto illegal_op;

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;
59
    int is_mem;
B
bellard 已提交
60 61 62
#if !defined(CONFIG_USER_ONLY)
    int user;
#endif
B
bellard 已提交
63 64
} DisasContext;

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

P
pbrook 已提交
71 72 73 74
/* 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 已提交
75

P
pbrook 已提交
76
static TCGv cpu_env;
P
pbrook 已提交
77
/* We reuse the same 64-bit temporaries for efficiency.  */
P
pbrook 已提交
78
static TCGv cpu_V0, cpu_V1, cpu_M0;
P
pbrook 已提交
79

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

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

P
pbrook 已提交
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
/* initialize TCG globals.  */
void arm_translate_init(void)
{
    cpu_env = tcg_global_reg_new(TCG_TYPE_PTR, TCG_AREG0, "env");

    cpu_T[0] = tcg_global_reg_new(TCG_TYPE_I32, TCG_AREG1, "T0");
    cpu_T[1] = tcg_global_reg_new(TCG_TYPE_I32, TCG_AREG2, "T1");
}

/* The code generator doesn't like lots of temporaries, so maintain our own
   cache for reuse within a function.  */
#define MAX_TEMPS 8
static int num_temps;
static TCGv temps[MAX_TEMPS];

/* Allocate a temporary variable.  */
static TCGv new_tmp(void)
{
    TCGv tmp;
    if (num_temps == MAX_TEMPS)
        abort();

    if (GET_TCGV(temps[num_temps]))
      return temps[num_temps++];

    tmp = tcg_temp_new(TCG_TYPE_I32);
    temps[num_temps++] = tmp;
    return tmp;
}

/* Release a temporary variable.  */
static void dead_tmp(TCGv tmp)
{
    int i;
    num_temps--;
    i = num_temps;
    if (GET_TCGV(temps[i]) == GET_TCGV(tmp))
        return;

    /* Shuffle this temp to the last slot.  */
    while (GET_TCGV(temps[i]) != GET_TCGV(tmp))
        i--;
    while (i < num_temps) {
        temps[i] = temps[i + 1];
        i++;
    }
    temps[i] = tmp;
}

P
pbrook 已提交
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
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 已提交
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
/* 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 {
        tcg_gen_ld_i32(var, cpu_env, offsetof(CPUState, regs[reg]));
    }
}

/* 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;
    }
    tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, regs[reg]));
    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_T1_T0() tcg_gen_mov_i32(cpu_T[1], cpu_T[0])
#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 已提交
202 203 204 205 206 207 208
#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])
#define gen_op_rscl_T0_T1_cc() gen_helper_sbc_cc(cpu_T[0], cpu_T[1], cpu_T[0])

P
pbrook 已提交
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
#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_T0_im(im) tcg_gen_shli_i32(cpu_T[0], cpu_T[0], im)
#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)
#define gen_op_sarl_T1_im(im) tcg_gen_sari_i32(cpu_T[1], cpu_T[1], im)
#define gen_op_rorl_T1_im(im) tcg_gen_rori_i32(cpu_T[1], cpu_T[1], im)

/* Value extensions.  */
P
pbrook 已提交
224 225
#define gen_uxtb(var) tcg_gen_ext8u_i32(var, var)
#define gen_uxth(var) tcg_gen_ext16u_i32(var, var)
P
pbrook 已提交
226 227 228
#define gen_sxtb(var) tcg_gen_ext8s_i32(var, var)
#define gen_sxth(var) tcg_gen_ext16s_i32(var, var)

P
pbrook 已提交
229 230
#define gen_sxtb16(var) gen_helper_sxtb16(var, var)
#define gen_uxtb16(var) gen_helper_uxtb16(var, var)
P
pbrook 已提交
231 232

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

P
pbrook 已提交
234 235 236 237 238 239 240 241 242 243 244 245
#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 已提交
246 247 248 249
static void gen_smul_dual(TCGv a, TCGv b)
{
    TCGv tmp1 = new_tmp();
    TCGv tmp2 = new_tmp();
250 251
    tcg_gen_ext16s_i32(tmp1, a);
    tcg_gen_ext16s_i32(tmp2, b);
P
pbrook 已提交
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 299 300 301 302 303 304 305 306 307 308 309 310 311
    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 已提交
312 313
    tcg_gen_shli_i32(val, val, shift);
    tcg_gen_andi_i32(base, base, ~(mask << shift));
P
pbrook 已提交
314 315 316
    tcg_gen_or_i32(dest, base, val);
}

P
pbrook 已提交
317 318
/* Round the top 32 bits of a 64-bit value.  */
static void gen_roundqd(TCGv a, TCGv b)
P
pbrook 已提交
319
{
P
pbrook 已提交
320 321
    tcg_gen_shri_i32(a, a, 31);
    tcg_gen_add_i32(a, a, b);
P
pbrook 已提交
322 323
}

P
pbrook 已提交
324 325
/* FIXME: Most targets have native widening multiplication.
   It would be good to use that instead of a full wide multiply.  */
P
pbrook 已提交
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352
/* 32x32->64 multiply.  Marks inputs as dead.  */
static TCGv gen_mulu_i64_i32(TCGv a, TCGv b)
{
    TCGv tmp1 = tcg_temp_new(TCG_TYPE_I64);
    TCGv tmp2 = tcg_temp_new(TCG_TYPE_I64);

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

static TCGv gen_muls_i64_i32(TCGv a, TCGv b)
{
    TCGv tmp1 = tcg_temp_new(TCG_TYPE_I64);
    TCGv tmp2 = tcg_temp_new(TCG_TYPE_I64);

    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 已提交
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
/* Unsigned 32x32->64 multiply.  */
static void gen_op_mull_T0_T1(void)
{
    TCGv tmp1 = tcg_temp_new(TCG_TYPE_I64);
    TCGv tmp2 = tcg_temp_new(TCG_TYPE_I64);

    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 已提交
368
static void gen_imull(TCGv a, TCGv b)
P
pbrook 已提交
369 370 371 372
{
    TCGv tmp1 = tcg_temp_new(TCG_TYPE_I64);
    TCGv tmp2 = tcg_temp_new(TCG_TYPE_I64);

P
pbrook 已提交
373 374
    tcg_gen_ext_i32_i64(tmp1, a);
    tcg_gen_ext_i32_i64(tmp2, b);
P
pbrook 已提交
375
    tcg_gen_mul_i64(tmp1, tmp1, tmp2);
P
pbrook 已提交
376
    tcg_gen_trunc_i64_i32(a, tmp1);
P
pbrook 已提交
377
    tcg_gen_shri_i64(tmp1, tmp1, 32);
P
pbrook 已提交
378 379 380 381
    tcg_gen_trunc_i64_i32(b, tmp1);
}
#define gen_op_imull_T0_T1() gen_imull(cpu_T[0], cpu_T[1])

P
pbrook 已提交
382 383 384 385 386 387 388
/* 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 已提交
389
    dead_tmp(tmp);
P
pbrook 已提交
390 391
}

P
pbrook 已提交
392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411
/* 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 已提交
412 413
#define gen_set_CF(var) tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, CF))

P
pbrook 已提交
414 415 416 417 418
/* 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);
P
pbrook 已提交
419
    gen_set_CF(var);
P
pbrook 已提交
420 421 422 423 424 425
    dead_tmp(tmp);
}

/* Set N and Z flags from var.  */
static inline void gen_logic_CC(TCGv var)
{
P
pbrook 已提交
426 427
    tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, NF));
    tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, ZF));
P
pbrook 已提交
428 429 430 431 432
}

/* T0 += T1 + CF.  */
static void gen_adc_T0_T1(void)
{
P
pbrook 已提交
433
    TCGv tmp;
P
pbrook 已提交
434
    gen_op_addl_T0_T1();
P
pbrook 已提交
435
    tmp = load_cpu_field(CF);
P
pbrook 已提交
436 437 438 439
    tcg_gen_add_i32(cpu_T[0], cpu_T[0], tmp);
    dead_tmp(tmp);
}

P
pbrook 已提交
440 441 442
/* dest = T0 - T1 + CF - 1.  */
static void gen_sub_carry(TCGv dest, TCGv t0, TCGv t1)
{
P
pbrook 已提交
443
    TCGv tmp;
P
pbrook 已提交
444
    tcg_gen_sub_i32(dest, t0, t1);
P
pbrook 已提交
445
    tmp = load_cpu_field(CF);
P
pbrook 已提交
446 447 448 449 450 451 452 453
    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 已提交
454 455
/* T0 &= ~T1.  Clobbers T1.  */
/* FIXME: Implement bic natively.  */
P
pbrook 已提交
456 457 458 459 460 461 462
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 已提交
463 464 465 466 467 468
static inline void gen_op_bicl_T0_T1(void)
{
    gen_op_notl_T1();
    gen_op_andl_T0_T1();
}

P
pbrook 已提交
469 470 471
/* FIXME:  Implement this natively.  */
#define tcg_gen_abs_i32(t0, t1) gen_helper_abs(t0, t1)

P
pbrook 已提交
472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
/* 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 已提交
487
static void shifter_out_im(TCGv var, int shift)
P
pbrook 已提交
488
{
P
pbrook 已提交
489 490 491
    TCGv tmp = new_tmp();
    if (shift == 0) {
        tcg_gen_andi_i32(tmp, var, 1);
P
pbrook 已提交
492
    } else {
P
pbrook 已提交
493 494 495 496 497 498 499
        tcg_gen_shri_i32(tmp, var, shift);
        if (shift != 31);
            tcg_gen_andi_i32(tmp, tmp, 1);
    }
    gen_set_CF(tmp);
    dead_tmp(tmp);
}
P
pbrook 已提交
500

P
pbrook 已提交
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 536 537 538 539
/* 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 已提交
540
            TCGv tmp = load_cpu_field(CF);
P
pbrook 已提交
541 542 543
            if (flags)
                shifter_out_im(var, 0);
            tcg_gen_shri_i32(var, var, 1);
P
pbrook 已提交
544 545 546 547 548 549 550
            tcg_gen_shli_i32(tmp, tmp, 31);
            tcg_gen_or_i32(var, var, tmp);
            dead_tmp(tmp);
        }
    }
};

P
pbrook 已提交
551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571
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 已提交
572 573 574 575 576 577 578 579 580
#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 已提交
581
static void gen_arm_parallel_addsub(int op1, int op2, TCGv a, TCGv b)
P
pbrook 已提交
582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613
{
    TCGv tmp;

    switch (op1) {
#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp)
    case 1:
        tmp = tcg_temp_new(TCG_TYPE_PTR);
        tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
        PAS_OP(s)
        break;
    case 5:
        tmp = tcg_temp_new(TCG_TYPE_PTR);
        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 已提交
614 615
#undef PAS_OP

P
pbrook 已提交
616 617 618 619 620 621 622 623 624 625
/* 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 已提交
626
static void gen_thumb2_parallel_addsub(int op1, int op2, TCGv a, TCGv b)
P
pbrook 已提交
627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658
{
    TCGv tmp;

    switch (op1) {
#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp)
    case 0:
        tmp = tcg_temp_new(TCG_TYPE_PTR);
        tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
        PAS_OP(s)
        break;
    case 4:
        tmp = tcg_temp_new(TCG_TYPE_PTR);
        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 已提交
659 660
#undef PAS_OP

P
pbrook 已提交
661 662 663 664 665 666 667 668
static void gen_test_cc(int cc, int label)
{
    TCGv tmp;
    TCGv tmp2;
    int inv;

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

const uint8_t table_logic_cc[16] = {
    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 */
};
777

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

P
pbrook 已提交
783 784
    s->is_jmp = DISAS_UPDATE;
    tmp = new_tmp();
P
pbrook 已提交
785 786 787 788 789 790
    if (s->thumb != (addr & 1)) {
        tcg_gen_movi_i32(tmp, addr & 1);
        tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, thumb));
    }
    tcg_gen_movi_i32(tmp, addr & ~1);
    tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, regs[15]));
P
pbrook 已提交
791
    dead_tmp(tmp);
P
pbrook 已提交
792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812
}

/* Set PC and Thumb state from var.  var is marked as dead.  */
static inline void gen_bx(DisasContext *s, TCGv var)
{
    TCGv tmp;

    s->is_jmp = DISAS_UPDATE;
    tmp = new_tmp();
    tcg_gen_andi_i32(tmp, var, 1);
    store_cpu_field(tmp, thumb);
    tcg_gen_andi_i32(var, var, ~1);
    store_cpu_field(var, regs[15]);
}

/* TODO: This should be removed.  Use gen_bx instead.  */
static inline void gen_bx_T0(DisasContext *s)
{
    TCGv tmp = new_tmp();
    tcg_gen_mov_i32(tmp, cpu_T[0]);
    gen_bx(s, tmp);
P
pbrook 已提交
813
}
B
bellard 已提交
814 815 816 817 818

#if defined(CONFIG_USER_ONLY)
#define gen_ldst(name, s) gen_op_##name##_raw()
#else
#define gen_ldst(name, s) do { \
819
    s->is_mem = 1; \
B
bellard 已提交
820 821 822 823 824 825
    if (IS_USER(s)) \
        gen_op_##name##_user(); \
    else \
        gen_op_##name##_kernel(); \
    } while (0)
#endif
P
pbrook 已提交
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 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870
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 已提交
871

B
bellard 已提交
872 873
static inline void gen_movl_T0_reg(DisasContext *s, int reg)
{
P
pbrook 已提交
874
    load_reg_var(s, cpu_T[0], reg);
B
bellard 已提交
875 876 877 878
}

static inline void gen_movl_T1_reg(DisasContext *s, int reg)
{
P
pbrook 已提交
879
    load_reg_var(s, cpu_T[1], reg);
B
bellard 已提交
880 881 882 883
}

static inline void gen_movl_T2_reg(DisasContext *s, int reg)
{
P
pbrook 已提交
884 885 886
    load_reg_var(s, cpu_T[2], reg);
}

P
pbrook 已提交
887 888 889 890 891 892 893
static inline void gen_set_pc_im(uint32_t val)
{
    TCGv tmp = new_tmp();
    tcg_gen_movi_i32(tmp, val);
    store_cpu_field(tmp, regs[15]);
}

B
bellard 已提交
894 895
static inline void gen_movl_reg_TN(DisasContext *s, int reg, int t)
{
P
pbrook 已提交
896 897 898 899 900 901 902 903
    TCGv tmp;
    if (reg == 15) {
        tmp = new_tmp();
        tcg_gen_andi_i32(tmp, cpu_T[t], ~1);
    } else {
        tmp = cpu_T[t];
    }
    tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, regs[reg]));
B
bellard 已提交
904
    if (reg == 15) {
P
pbrook 已提交
905
        dead_tmp(tmp);
B
bellard 已提交
906 907 908 909 910 911 912 913 914 915 916 917 918 919
        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 已提交
920 921 922 923 924 925 926 927
/* 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 已提交
928 929
static inline void gen_add_data_offset(DisasContext *s, unsigned int insn,
                                       TCGv var)
B
bellard 已提交
930
{
B
bellard 已提交
931
    int val, rm, shift, shiftop;
P
pbrook 已提交
932
    TCGv offset;
B
bellard 已提交
933 934 935 936 937 938

    if (!(insn & (1 << 25))) {
        /* immediate */
        val = insn & 0xfff;
        if (!(insn & (1 << 23)))
            val = -val;
B
bellard 已提交
939
        if (val != 0)
P
pbrook 已提交
940
            tcg_gen_addi_i32(var, var, val);
B
bellard 已提交
941 942 943 944
    } else {
        /* shift/register */
        rm = (insn) & 0xf;
        shift = (insn >> 7) & 0x1f;
B
bellard 已提交
945
        shiftop = (insn >> 5) & 3;
P
pbrook 已提交
946
        offset = load_reg(s, rm);
P
pbrook 已提交
947
        gen_arm_shift_im(offset, shiftop, shift, 0);
B
bellard 已提交
948
        if (!(insn & (1 << 23)))
P
pbrook 已提交
949
            tcg_gen_sub_i32(var, var, offset);
B
bellard 已提交
950
        else
P
pbrook 已提交
951
            tcg_gen_add_i32(var, var, offset);
P
pbrook 已提交
952
        dead_tmp(offset);
B
bellard 已提交
953 954 955
    }
}

P
pbrook 已提交
956
static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn,
P
pbrook 已提交
957
                                        int extra, TCGv var)
B
bellard 已提交
958 959
{
    int val, rm;
P
pbrook 已提交
960
    TCGv offset;
961

B
bellard 已提交
962 963 964 965 966
    if (insn & (1 << 22)) {
        /* immediate */
        val = (insn & 0xf) | ((insn >> 4) & 0xf0);
        if (!(insn & (1 << 23)))
            val = -val;
967
        val += extra;
B
bellard 已提交
968
        if (val != 0)
P
pbrook 已提交
969
            tcg_gen_addi_i32(var, var, val);
B
bellard 已提交
970 971
    } else {
        /* register */
P
pbrook 已提交
972
        if (extra)
P
pbrook 已提交
973
            tcg_gen_addi_i32(var, var, extra);
B
bellard 已提交
974
        rm = (insn) & 0xf;
P
pbrook 已提交
975
        offset = load_reg(s, rm);
B
bellard 已提交
976
        if (!(insn & (1 << 23)))
P
pbrook 已提交
977
            tcg_gen_sub_i32(var, var, offset);
B
bellard 已提交
978
        else
P
pbrook 已提交
979
            tcg_gen_add_i32(var, var, offset);
P
pbrook 已提交
980
        dead_tmp(offset);
B
bellard 已提交
981 982 983
    }
}

P
pbrook 已提交
984 985 986 987 988 989 990
#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 已提交
991 992
}

B
balrog 已提交
993
#define VFP_OP1(name)                               \
P
pbrook 已提交
994 995 996 997 998 999 1000 1001
static inline void gen_vfp_##name(int dp, int arg)  \
{                                                   \
    if (dp)                                         \
        gen_op_vfp_##name##d(arg);                  \
    else                                            \
        gen_op_vfp_##name##s(arg);                  \
}

P
pbrook 已提交
1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051
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 已提交
1052
        tcg_gen_movi_i64(cpu_F1d, 0);
P
pbrook 已提交
1053
    else
B
balrog 已提交
1054
        tcg_gen_movi_i32(cpu_F1s, 0);
P
pbrook 已提交
1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067
}

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)
1068
        gen_helper_vfp_sitod(cpu_F0d, cpu_F0s, cpu_env);
P
pbrook 已提交
1069
    else
1070
        gen_helper_vfp_sitos(cpu_F0s, cpu_F0s, cpu_env);
P
pbrook 已提交
1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097
}

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 已提交
1098 1099
{
    if (dp)
P
pbrook 已提交
1100
        gen_helper_vfp_tosizd(cpu_F0s, cpu_F0d, cpu_env);
P
pbrook 已提交
1101
    else
P
pbrook 已提交
1102 1103 1104 1105 1106 1107 1108 1109 1110 1111
        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 已提交
1112
}
P
pbrook 已提交
1113 1114 1115 1116 1117 1118 1119 1120 1121
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 已提交
1122

B
bellard 已提交
1123 1124 1125
static inline void gen_vfp_ld(DisasContext *s, int dp)
{
    if (dp)
P
pbrook 已提交
1126
        tcg_gen_qemu_ld64(cpu_F0d, cpu_T[1], IS_USER(s));
B
bellard 已提交
1127
    else
P
pbrook 已提交
1128
        tcg_gen_qemu_ld32u(cpu_F0s, cpu_T[1], IS_USER(s));
B
bellard 已提交
1129 1130 1131 1132 1133
}

static inline void gen_vfp_st(DisasContext *s, int dp)
{
    if (dp)
P
pbrook 已提交
1134
        tcg_gen_qemu_st64(cpu_F0d, cpu_T[1], IS_USER(s));
B
bellard 已提交
1135
    else
P
pbrook 已提交
1136
        tcg_gen_qemu_st32(cpu_F0s, cpu_T[1], IS_USER(s));
B
bellard 已提交
1137 1138
}

B
bellard 已提交
1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151
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 已提交
1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162

/* 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 已提交
1163 1164 1165 1166 1167 1168 1169
/* 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 已提交
1170

P
pbrook 已提交
1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183
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 已提交
1184 1185 1186 1187 1188 1189 1190 1191 1192 1193
static inline void neon_load_reg64(TCGv var, int reg)
{
    tcg_gen_ld_i64(var, cpu_env, vfp_reg_offset(1, reg));
}

static inline void neon_store_reg64(TCGv var, int reg)
{
    tcg_gen_st_i64(var, cpu_env, vfp_reg_offset(1, reg));
}

P
pbrook 已提交
1194 1195 1196 1197 1198
#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 已提交
1199 1200 1201
static inline void gen_mov_F0_vreg(int dp, int reg)
{
    if (dp)
P
pbrook 已提交
1202
        tcg_gen_ld_f64(cpu_F0d, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1203
    else
P
pbrook 已提交
1204
        tcg_gen_ld_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1205 1206 1207 1208 1209
}

static inline void gen_mov_F1_vreg(int dp, int reg)
{
    if (dp)
P
pbrook 已提交
1210
        tcg_gen_ld_f64(cpu_F1d, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1211
    else
P
pbrook 已提交
1212
        tcg_gen_ld_f32(cpu_F1s, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1213 1214 1215 1216 1217
}

static inline void gen_mov_vreg_F0(int dp, int reg)
{
    if (dp)
P
pbrook 已提交
1218
        tcg_gen_st_f64(cpu_F0d, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1219
    else
P
pbrook 已提交
1220
        tcg_gen_st_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1221 1222
}

1223 1224
#define ARM_CP_RW_BIT	(1 << 20)

P
pbrook 已提交
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 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434
static inline void iwmmxt_load_reg(TCGv var, int reg)
{
    tcg_gen_ld_i64(var, cpu_env, offsetof(CPUState, iwmmxt.regs[reg]));
}

static inline void iwmmxt_store_reg(TCGv var, int reg)
{
    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 已提交
1435
    tcg_gen_ext32u_i64(cpu_V1, cpu_V1);
P
pbrook 已提交
1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456
    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)
{
    tcg_gen_extu_i32_i64(cpu_V0, cpu_T[0]);
    tcg_gen_extu_i32_i64(cpu_V1, cpu_T[0]);
    tcg_gen_shli_i64(cpu_V1, cpu_V1, 32);
    tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1);
    iwmmxt_store_reg(cpu_V0, rn);
}

1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497
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 已提交
1498
        gen_iwmmxt_movl_T0_T1_wRn(rd);
1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510

    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 已提交
1511
    TCGv tmp;
1512 1513 1514 1515 1516 1517 1518

    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 已提交
1519
                gen_iwmmxt_movl_T0_T1_wRn(wrd);
1520 1521 1522 1523 1524
                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 已提交
1525
                gen_iwmmxt_movl_wRn_T0_T1(wrd);
1526 1527 1528 1529 1530 1531 1532 1533 1534 1535
                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 已提交
1536 1537 1538
                tmp = gen_ld32(cpu_T[1], IS_USER(s));
                tcg_gen_mov_i32(cpu_T[0], tmp);
                dead_tmp(tmp);
1539 1540
                gen_op_iwmmxt_movl_wCx_T0(wrd);
            } else {
P
pbrook 已提交
1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559
                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);
                }
1560 1561 1562 1563 1564
                gen_op_iwmmxt_movq_wRn_M0(wrd);
            }
        } else {
            if ((insn >> 28) == 0xf) {			/* WSTRW wCx */
                gen_op_iwmmxt_movl_T0_wCx(wrd);
P
pbrook 已提交
1565 1566 1567
                tmp = new_tmp();
                tcg_gen_mov_i32(tmp, cpu_T[0]);
                gen_st32(tmp, cpu_T[1], IS_USER(s));
1568 1569
            } else {
                gen_op_iwmmxt_movq_M0_wRn(wrd);
P
pbrook 已提交
1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587
                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));
                    }
                }
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 1628 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
            }
        }
        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 已提交
1662
        tcg_gen_neg_i64(cpu_M0, cpu_M0);
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 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754
        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 已提交
1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765
        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);
        }
1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778
        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 已提交
1779 1780
            iwmmxt_load_reg(cpu_V1, wrd);
            tcg_gen_add_i64(cpu_M0, cpu_M0, cpu_V1);
1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811
        }
        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 已提交
1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822
        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);
        }
1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873
        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 已提交
1874
                gen_op_iwmmxt_extru_T0_M0((insn & 7) << 3, 0xff);
1875 1876 1877 1878 1879 1880
            }
            break;
        case 1:
            if (insn & 8)
                gen_op_iwmmxt_extrsw_T0_M0((insn & 3) << 4);
            else {
P
pbrook 已提交
1881
                gen_op_iwmmxt_extru_T0_M0((insn & 3) << 4, 0xffff);
1882 1883 1884
            }
            break;
        case 2:
P
pbrook 已提交
1885
            gen_op_iwmmxt_extru_T0_M0((insn & 1) << 5, ~0u);
1886 1887 1888 1889
            break;
        case 3:
            return 1;
        }
P
pbrook 已提交
1890
        gen_movl_reg_T0(s, rd);
1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909
        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 已提交
1910
        gen_set_nzcv(cpu_T[1]);
1911 1912 1913 1914 1915 1916 1917
        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 已提交
1918
            gen_helper_iwmmxt_bcstb(cpu_M0, cpu_T[0]);
1919 1920
            break;
        case 1:
P
pbrook 已提交
1921
            gen_helper_iwmmxt_bcstw(cpu_M0, cpu_T[0]);
1922 1923
            break;
        case 2:
P
pbrook 已提交
1924
            gen_helper_iwmmxt_bcstl(cpu_M0, cpu_T[0]);
1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955
            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 已提交
1956
        gen_set_nzcv(cpu_T[0]);
1957 1958 1959 1960 1961 1962 1963
        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 已提交
1964
            gen_helper_iwmmxt_addcb(cpu_M0, cpu_M0);
1965 1966
            break;
        case 1:
P
pbrook 已提交
1967
            gen_helper_iwmmxt_addcw(cpu_M0, cpu_M0);
1968 1969
            break;
        case 2:
P
pbrook 已提交
1970
            gen_helper_iwmmxt_addcl(cpu_M0, cpu_M0);
1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001
            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 已提交
2002
        gen_set_nzcv(cpu_T[0]);
2003 2004 2005 2006 2007 2008 2009 2010 2011
        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 已提交
2012
            gen_helper_iwmmxt_msbb(cpu_T[0], cpu_M0);
2013 2014
            break;
        case 1:
P
pbrook 已提交
2015
            gen_helper_iwmmxt_msbw(cpu_T[0], cpu_M0);
2016 2017
            break;
        case 2:
P
pbrook 已提交
2018
            gen_helper_iwmmxt_msbl(cpu_T[0], cpu_M0);
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 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129
            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 已提交
2130
            gen_helper_iwmmxt_srlw(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2131 2132
            break;
        case 2:
P
pbrook 已提交
2133
            gen_helper_iwmmxt_srll(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2134 2135
            break;
        case 3:
P
pbrook 已提交
2136
            gen_helper_iwmmxt_srlq(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153
            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 已提交
2154
            gen_helper_iwmmxt_sraw(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2155 2156
            break;
        case 2:
P
pbrook 已提交
2157
            gen_helper_iwmmxt_sral(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2158 2159
            break;
        case 3:
P
pbrook 已提交
2160
            gen_helper_iwmmxt_sraq(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177
            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 已提交
2178
            gen_helper_iwmmxt_sllw(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2179 2180
            break;
        case 2:
P
pbrook 已提交
2181
            gen_helper_iwmmxt_slll(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2182 2183
            break;
        case 3:
P
pbrook 已提交
2184
            gen_helper_iwmmxt_sllq(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201
            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 已提交
2202
            gen_helper_iwmmxt_rorw(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2203 2204 2205 2206
            break;
        case 2:
            if (gen_iwmmxt_shift(insn, 0x1f))
                return 1;
P
pbrook 已提交
2207
            gen_helper_iwmmxt_rorl(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2208 2209 2210 2211
            break;
        case 3:
            if (gen_iwmmxt_shift(insn, 0x3f))
                return 1;
P
pbrook 已提交
2212
            gen_helper_iwmmxt_rorq(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
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 2309 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
            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 已提交
2343
        gen_helper_iwmmxt_shufh(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
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 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438
        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 已提交
2439 2440
            gen_movl_T0_reg(s, rd0);
            gen_movl_T1_reg(s, rd1);
2441 2442 2443
            gen_op_iwmmxt_muladdsl_M0_T0_T1();
            break;
        case 0x8:					/* TMIAPH */
P
pbrook 已提交
2444 2445
            gen_movl_T0_reg(s, rd0);
            gen_movl_T1_reg(s, rd1);
2446 2447 2448
            gen_op_iwmmxt_muladdsw_M0_T0_T1();
            break;
        case 0xc: case 0xd: case 0xe: case 0xf:		/* TMIAxy */
P
pbrook 已提交
2449
            gen_movl_T1_reg(s, rd0);
2450 2451 2452
            if (insn & (1 << 16))
                gen_op_shrl_T1_im(16);
            gen_op_movl_T0_T1();
P
pbrook 已提交
2453
            gen_movl_T1_reg(s, rd1);
2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487
            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 已提交
2488 2489
            gen_movl_T0_reg(s, rd0);
            gen_movl_T1_reg(s, rd1);
2490 2491 2492
            gen_op_iwmmxt_muladdsl_M0_T0_T1();
            break;
        case 0x8:					/* MIAPH */
P
pbrook 已提交
2493 2494
            gen_movl_T0_reg(s, rd0);
            gen_movl_T1_reg(s, rd1);
2495 2496 2497 2498 2499 2500
            gen_op_iwmmxt_muladdsw_M0_T0_T1();
            break;
        case 0xc:					/* MIABB */
        case 0xd:					/* MIABT */
        case 0xe:					/* MIATB */
        case 0xf:					/* MIATT */
P
pbrook 已提交
2501
            gen_movl_T1_reg(s, rd0);
2502 2503 2504
            if (insn & (1 << 16))
                gen_op_shrl_T1_im(16);
            gen_op_movl_T0_T1();
P
pbrook 已提交
2505
            gen_movl_T1_reg(s, rd1);
2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527
            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 已提交
2528
            gen_iwmmxt_movl_T0_T1_wRn(acc);
P
pbrook 已提交
2529
            gen_movl_reg_T0(s, rdlo);
2530 2531
            gen_op_movl_T0_im((1 << (40 - 32)) - 1);
            gen_op_andl_T0_T1();
P
pbrook 已提交
2532
            gen_movl_reg_T0(s, rdhi);
2533
        } else {					/* MAR */
P
pbrook 已提交
2534 2535
            gen_movl_T0_reg(s, rdlo);
            gen_movl_T1_reg(s, rdhi);
P
pbrook 已提交
2536
            gen_iwmmxt_movl_wRn_T0_T1(acc);
2537 2538 2539 2540 2541 2542 2543
        }
        return 0;
    }

    return 1;
}

2544 2545 2546 2547
/* 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 已提交
2548
    TCGv tmp;
2549 2550 2551 2552 2553 2554
    uint32_t rd = (insn >> 12) & 0xf;
    uint32_t cp = (insn >> 8) & 0xf;
    if (IS_USER(s)) {
        return 1;
    }

2555
    if (insn & ARM_CP_RW_BIT) {
2556 2557
        if (!env->cp[cp].cp_read)
            return 1;
P
pbrook 已提交
2558 2559 2560 2561
        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);
2562 2563 2564
    } else {
        if (!env->cp[cp].cp_write)
            return 1;
P
pbrook 已提交
2565 2566 2567
        gen_set_pc_im(s->pc);
        tmp = load_reg(s, rd);
        gen_helper_set_cp(cpu_env, tcg_const_i32(insn), tmp);
B
balrog 已提交
2568
        dead_tmp(tmp);
2569 2570 2571 2572
    }
    return 0;
}

P
pbrook 已提交
2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592
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 已提交
2593 2594
/* Disassemble system coprocessor (cp15) instruction.  Return nonzero if
   instruction is not defined.  */
2595
static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn)
B
bellard 已提交
2596 2597
{
    uint32_t rd;
P
pbrook 已提交
2598
    TCGv tmp;
B
bellard 已提交
2599

P
pbrook 已提交
2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616
    /* 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 已提交
2617 2618
        return 1;
    }
B
bellard 已提交
2619 2620 2621
    if ((insn & 0x0fff0fff) == 0x0e070f90
        || (insn & 0x0fff0fff) == 0x0e070f58) {
        /* Wait for interrupt.  */
P
pbrook 已提交
2622
        gen_set_pc_im(s->pc);
P
pbrook 已提交
2623
        s->is_jmp = DISAS_WFI;
B
bellard 已提交
2624 2625
        return 0;
    }
B
bellard 已提交
2626
    rd = (insn >> 12) & 0xf;
2627
    if (insn & ARM_CP_RW_BIT) {
P
pbrook 已提交
2628 2629
        tmp = new_tmp();
        gen_helper_get_cp15(tmp, cpu_env, tcg_const_i32(insn));
B
bellard 已提交
2630 2631
        /* If the destination register is r15 then sets condition codes.  */
        if (rd != 15)
P
pbrook 已提交
2632 2633 2634
            store_reg(s, rd, tmp);
        else
            dead_tmp(tmp);
B
bellard 已提交
2635
    } else {
P
pbrook 已提交
2636 2637 2638
        tmp = load_reg(s, rd);
        gen_helper_set_cp15(cpu_env, tcg_const_i32(insn), tmp);
        dead_tmp(tmp);
2639 2640 2641 2642 2643 2644
        /* 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 已提交
2645 2646 2647 2648
    }
    return 0;
}

P
pbrook 已提交
2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668
#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 已提交
2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682
/* 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 已提交
2683 2684 2685 2686 2687 2688
static inline int
vfp_enabled(CPUState * env)
{
    return ((env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) != 0);
}

P
pbrook 已提交
2689 2690 2691 2692 2693
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 已提交
2694
    tcg_gen_ext8u_i32(var, var);
P
pbrook 已提交
2695 2696 2697 2698 2699 2700 2701 2702 2703 2704
    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 已提交
2705
    tcg_gen_ext16u_i32(var, var);
P
pbrook 已提交
2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719
    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 已提交
2720 2721 2722 2723 2724 2725
/* 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 已提交
2726
    TCGv tmp;
P
pbrook 已提交
2727
    TCGv tmp2;
B
bellard 已提交
2728

P
pbrook 已提交
2729 2730 2731
    if (!arm_feature(env, ARM_FEATURE_VFP))
        return 1;

P
pbrook 已提交
2732 2733
    if (!vfp_enabled(env)) {
        /* VFP disabled.  Only allow fmxr/fmrx to/from some control regs.  */
P
pbrook 已提交
2734 2735 2736
        if ((insn & 0x0fe00fff) != 0x0ee00a10)
            return 1;
        rn = (insn >> 16) & 0xf;
P
pbrook 已提交
2737 2738
        if (rn != ARM_VFP_FPSID && rn != ARM_VFP_FPEXC
            && rn != ARM_VFP_MVFR1 && rn != ARM_VFP_MVFR0)
P
pbrook 已提交
2739 2740
            return 1;
    }
B
bellard 已提交
2741 2742 2743 2744 2745 2746 2747
    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 已提交
2748 2749 2750 2751 2752
                int size;
                int pass;

                VFP_DREG_N(rn, insn);
                if (insn & 0xf)
B
bellard 已提交
2753
                    return 1;
P
pbrook 已提交
2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768
                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;
                }
2769
                if (insn & ARM_CP_RW_BIT) {
B
bellard 已提交
2770
                    /* vfp->arm */
P
pbrook 已提交
2771
                    tmp = neon_load_reg(rn, pass);
P
pbrook 已提交
2772 2773 2774
                    switch (size) {
                    case 0:
                        if (offset)
P
pbrook 已提交
2775
                            tcg_gen_shri_i32(tmp, tmp, offset);
P
pbrook 已提交
2776
                        if (insn & (1 << 23))
P
pbrook 已提交
2777
                            gen_uxtb(tmp);
P
pbrook 已提交
2778
                        else
P
pbrook 已提交
2779
                            gen_sxtb(tmp);
P
pbrook 已提交
2780 2781 2782 2783
                        break;
                    case 1:
                        if (insn & (1 << 23)) {
                            if (offset) {
P
pbrook 已提交
2784
                                tcg_gen_shri_i32(tmp, tmp, 16);
P
pbrook 已提交
2785
                            } else {
P
pbrook 已提交
2786
                                gen_uxth(tmp);
P
pbrook 已提交
2787 2788 2789
                            }
                        } else {
                            if (offset) {
P
pbrook 已提交
2790
                                tcg_gen_sari_i32(tmp, tmp, 16);
P
pbrook 已提交
2791
                            } else {
P
pbrook 已提交
2792
                                gen_sxth(tmp);
P
pbrook 已提交
2793 2794 2795 2796 2797 2798
                            }
                        }
                        break;
                    case 2:
                        break;
                    }
P
pbrook 已提交
2799
                    store_reg(s, rd, tmp);
B
bellard 已提交
2800 2801
                } else {
                    /* arm->vfp */
P
pbrook 已提交
2802
                    tmp = load_reg(s, rd);
P
pbrook 已提交
2803 2804 2805
                    if (insn & (1 << 23)) {
                        /* VDUP */
                        if (size == 0) {
P
pbrook 已提交
2806
                            gen_neon_dup_u8(tmp, 0);
P
pbrook 已提交
2807
                        } else if (size == 1) {
P
pbrook 已提交
2808
                            gen_neon_dup_low16(tmp);
P
pbrook 已提交
2809
                        }
P
pbrook 已提交
2810 2811 2812 2813
                        tmp2 = new_tmp();
                        tcg_gen_mov_i32(tmp2, tmp);
                        neon_store_reg(rn, 0, tmp2);
                        neon_store_reg(rn, 0, tmp);
P
pbrook 已提交
2814 2815 2816 2817
                    } else {
                        /* VMOV */
                        switch (size) {
                        case 0:
P
pbrook 已提交
2818 2819 2820
                            tmp2 = neon_load_reg(rn, pass);
                            gen_bfi(tmp, tmp2, tmp, offset, 0xff);
                            dead_tmp(tmp2);
P
pbrook 已提交
2821 2822
                            break;
                        case 1:
P
pbrook 已提交
2823 2824 2825
                            tmp2 = neon_load_reg(rn, pass);
                            gen_bfi(tmp, tmp2, tmp, offset, 0xffff);
                            dead_tmp(tmp2);
P
pbrook 已提交
2826 2827 2828 2829
                            break;
                        case 2:
                            break;
                        }
P
pbrook 已提交
2830
                        neon_store_reg(rn, pass, tmp);
P
pbrook 已提交
2831
                    }
B
bellard 已提交
2832
                }
P
pbrook 已提交
2833 2834 2835 2836
            } else { /* !dp */
                if ((insn & 0x6f) != 0x00)
                    return 1;
                rn = VFP_SREG_N(insn);
2837
                if (insn & ARM_CP_RW_BIT) {
B
bellard 已提交
2838 2839 2840
                    /* vfp->arm */
                    if (insn & (1 << 21)) {
                        /* system register */
P
pbrook 已提交
2841
                        rn >>= 1;
P
pbrook 已提交
2842

B
bellard 已提交
2843
                        switch (rn) {
P
pbrook 已提交
2844
                        case ARM_VFP_FPSID:
P
pbrook 已提交
2845
                            /* VFP2 allows access to FSID from userspace.
P
pbrook 已提交
2846 2847 2848 2849 2850
                               VFP3 restricts all id registers to privileged
                               accesses.  */
                            if (IS_USER(s)
                                && arm_feature(env, ARM_FEATURE_VFP3))
                                return 1;
P
pbrook 已提交
2851
                            tmp = load_cpu_field(vfp.xregs[rn]);
P
pbrook 已提交
2852
                            break;
P
pbrook 已提交
2853
                        case ARM_VFP_FPEXC:
P
pbrook 已提交
2854 2855
                            if (IS_USER(s))
                                return 1;
P
pbrook 已提交
2856
                            tmp = load_cpu_field(vfp.xregs[rn]);
P
pbrook 已提交
2857
                            break;
P
pbrook 已提交
2858 2859
                        case ARM_VFP_FPINST:
                        case ARM_VFP_FPINST2:
P
pbrook 已提交
2860 2861 2862 2863
                            /* Not present in VFP3.  */
                            if (IS_USER(s)
                                || arm_feature(env, ARM_FEATURE_VFP3))
                                return 1;
P
pbrook 已提交
2864
                            tmp = load_cpu_field(vfp.xregs[rn]);
B
bellard 已提交
2865
                            break;
P
pbrook 已提交
2866
                        case ARM_VFP_FPSCR:
2867
                            if (rd == 15) {
P
pbrook 已提交
2868 2869 2870 2871 2872 2873
                                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 已提交
2874
                            break;
P
pbrook 已提交
2875 2876 2877 2878 2879
                        case ARM_VFP_MVFR0:
                        case ARM_VFP_MVFR1:
                            if (IS_USER(s)
                                || !arm_feature(env, ARM_FEATURE_VFP3))
                                return 1;
P
pbrook 已提交
2880
                            tmp = load_cpu_field(vfp.xregs[rn]);
P
pbrook 已提交
2881
                            break;
B
bellard 已提交
2882 2883 2884 2885 2886
                        default:
                            return 1;
                        }
                    } else {
                        gen_mov_F0_vreg(0, rn);
P
pbrook 已提交
2887
                        tmp = gen_vfp_mrs();
B
bellard 已提交
2888 2889
                    }
                    if (rd == 15) {
B
bellard 已提交
2890
                        /* Set the 4 flag bits in the CPSR.  */
P
pbrook 已提交
2891 2892 2893 2894 2895
                        gen_set_nzcv(tmp);
                        dead_tmp(tmp);
                    } else {
                        store_reg(s, rd, tmp);
                    }
B
bellard 已提交
2896 2897
                } else {
                    /* arm->vfp */
P
pbrook 已提交
2898
                    tmp = load_reg(s, rd);
B
bellard 已提交
2899
                    if (insn & (1 << 21)) {
P
pbrook 已提交
2900
                        rn >>= 1;
B
bellard 已提交
2901 2902
                        /* system register */
                        switch (rn) {
P
pbrook 已提交
2903
                        case ARM_VFP_FPSID:
P
pbrook 已提交
2904 2905
                        case ARM_VFP_MVFR0:
                        case ARM_VFP_MVFR1:
B
bellard 已提交
2906 2907
                            /* Writes are ignored.  */
                            break;
P
pbrook 已提交
2908
                        case ARM_VFP_FPSCR:
P
pbrook 已提交
2909 2910
                            gen_helper_vfp_set_fpscr(cpu_env, tmp);
                            dead_tmp(tmp);
B
bellard 已提交
2911
                            gen_lookup_tb(s);
B
bellard 已提交
2912
                            break;
P
pbrook 已提交
2913
                        case ARM_VFP_FPEXC:
P
pbrook 已提交
2914 2915
                            if (IS_USER(s))
                                return 1;
P
pbrook 已提交
2916
                            store_cpu_field(tmp, vfp.xregs[rn]);
P
pbrook 已提交
2917 2918 2919 2920
                            gen_lookup_tb(s);
                            break;
                        case ARM_VFP_FPINST:
                        case ARM_VFP_FPINST2:
P
pbrook 已提交
2921
                            store_cpu_field(tmp, vfp.xregs[rn]);
P
pbrook 已提交
2922
                            break;
B
bellard 已提交
2923 2924 2925 2926
                        default:
                            return 1;
                        }
                    } else {
P
pbrook 已提交
2927
                        gen_vfp_msr(tmp);
B
bellard 已提交
2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941
                        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 已提交
2942
                    VFP_DREG_N(rn, insn);
B
bellard 已提交
2943 2944 2945 2946
                }

                if (op == 15 && (rn == 15 || rn > 17)) {
                    /* Integer or single precision destination.  */
P
pbrook 已提交
2947
                    rd = VFP_SREG_D(insn);
B
bellard 已提交
2948
                } else {
P
pbrook 已提交
2949
                    VFP_DREG_D(rd, insn);
B
bellard 已提交
2950 2951 2952 2953 2954 2955
                }

                if (op == 15 && (rn == 16 || rn == 17)) {
                    /* Integer source.  */
                    rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1);
                } else {
P
pbrook 已提交
2956
                    VFP_DREG_M(rm, insn);
B
bellard 已提交
2957 2958
                }
            } else {
P
pbrook 已提交
2959
                rn = VFP_SREG_N(insn);
B
bellard 已提交
2960 2961
                if (op == 15 && rn == 15) {
                    /* Double precision destination.  */
P
pbrook 已提交
2962 2963 2964 2965 2966
                    VFP_DREG_D(rd, insn);
                } else {
                    rd = VFP_SREG_D(insn);
                }
                rm = VFP_SREG_M(insn);
B
bellard 已提交
2967 2968 2969 2970 2971 2972 2973 2974 2975 2976
            }

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

B
bellard 已提交
2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023
            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 已提交
3024 3025 3026 3027 3028 3029 3030
                case 20:
                case 21:
                case 22:
                case 23:
                    /* Source and destination the same.  */
                    gen_mov_F0_vreg(dp, rd);
                    break;
B
bellard 已提交
3031 3032 3033
                default:
                    /* One source operand.  */
                    gen_mov_F0_vreg(dp, rm);
P
pbrook 已提交
3034
                    break;
B
bellard 已提交
3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082
                }
            } 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_mov_F1_vreg(dp, rd);
                    gen_vfp_add(dp);
                    gen_vfp_neg(dp);
                    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 已提交
3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094
                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 已提交
3095
                        tcg_gen_movi_i64(cpu_F0d, ((uint64_t)n) << 32);
P
pbrook 已提交
3096 3097 3098 3099 3100 3101
                    } else {
                        if (i & 0x40)
                            i |= 0x780;
                        else
                            i |= 0x800;
                        n |= i << 19;
B
balrog 已提交
3102
                        tcg_gen_movi_i32(cpu_F0s, n);
P
pbrook 已提交
3103 3104
                    }
                    break;
B
bellard 已提交
3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133
                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 已提交
3134
                            gen_helper_vfp_fcvtsd(cpu_F0s, cpu_F0d, cpu_env);
B
bellard 已提交
3135
                        else
P
pbrook 已提交
3136
                            gen_helper_vfp_fcvtds(cpu_F0d, cpu_F0s, cpu_env);
B
bellard 已提交
3137 3138 3139 3140 3141 3142 3143
                        break;
                    case 16: /* fuito */
                        gen_vfp_uito(dp);
                        break;
                    case 17: /* fsito */
                        gen_vfp_sito(dp);
                        break;
P
pbrook 已提交
3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163
                    case 20: /* fshto */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
                        gen_vfp_shto(dp, rm);
                        break;
                    case 21: /* fslto */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
                        gen_vfp_slto(dp, rm);
                        break;
                    case 22: /* fuhto */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
                        gen_vfp_uhto(dp, rm);
                        break;
                    case 23: /* fulto */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
                        gen_vfp_ulto(dp, rm);
                        break;
B
bellard 已提交
3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175
                    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 已提交
3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195
                    case 28: /* ftosh */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
                        gen_vfp_tosh(dp, rm);
                        break;
                    case 29: /* ftosl */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
                        gen_vfp_tosl(dp, rm);
                        break;
                    case 30: /* ftouh */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
                        gen_vfp_touh(dp, rm);
                        break;
                    case 31: /* ftoul */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
                        gen_vfp_toul(dp, rm);
                        break;
B
bellard 已提交
3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256
                    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 已提交
3257
        if (dp && (insn & 0x03e00000) == 0x00400000) {
B
bellard 已提交
3258 3259 3260 3261
            /* two-register transfer */
            rn = (insn >> 16) & 0xf;
            rd = (insn >> 12) & 0xf;
            if (dp) {
P
pbrook 已提交
3262 3263 3264 3265
                VFP_DREG_M(rm, insn);
            } else {
                rm = VFP_SREG_M(insn);
            }
B
bellard 已提交
3266

3267
            if (insn & ARM_CP_RW_BIT) {
B
bellard 已提交
3268 3269
                /* vfp->arm */
                if (dp) {
P
pbrook 已提交
3270 3271 3272 3273 3274 3275
                    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 已提交
3276 3277
                } else {
                    gen_mov_F0_vreg(0, rm);
P
pbrook 已提交
3278 3279
                    tmp = gen_vfp_mrs();
                    store_reg(s, rn, tmp);
B
bellard 已提交
3280
                    gen_mov_F0_vreg(0, rm + 1);
P
pbrook 已提交
3281 3282
                    tmp = gen_vfp_mrs();
                    store_reg(s, rd, tmp);
B
bellard 已提交
3283 3284 3285 3286
                }
            } else {
                /* arm->vfp */
                if (dp) {
P
pbrook 已提交
3287 3288 3289 3290 3291 3292
                    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 已提交
3293
                } else {
P
pbrook 已提交
3294 3295
                    tmp = load_reg(s, rn);
                    gen_vfp_msr(tmp);
B
bellard 已提交
3296
                    gen_mov_vreg_F0(0, rm);
P
pbrook 已提交
3297 3298
                    tmp = load_reg(s, rd);
                    gen_vfp_msr(tmp);
B
bellard 已提交
3299 3300 3301 3302 3303 3304 3305
                    gen_mov_vreg_F0(0, rm + 1);
                }
            }
        } else {
            /* Load/store */
            rn = (insn >> 16) & 0xf;
            if (dp)
P
pbrook 已提交
3306
                VFP_DREG_D(rd, insn);
B
bellard 已提交
3307
            else
P
pbrook 已提交
3308 3309 3310 3311 3312 3313
                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 已提交
3314 3315 3316 3317 3318 3319 3320
            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 已提交
3321
                    gen_vfp_ld(s, dp);
B
bellard 已提交
3322 3323 3324
                    gen_mov_vreg_F0(dp, rd);
                } else {
                    gen_mov_F0_vreg(dp, rd);
B
bellard 已提交
3325
                    gen_vfp_st(s, dp);
B
bellard 已提交
3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341
                }
            } 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++) {
3342
                    if (insn & ARM_CP_RW_BIT) {
B
bellard 已提交
3343
                        /* load */
B
bellard 已提交
3344
                        gen_vfp_ld(s, dp);
B
bellard 已提交
3345 3346 3347 3348
                        gen_mov_vreg_F0(dp, rd + i);
                    } else {
                        /* store */
                        gen_mov_F0_vreg(dp, rd + i);
B
bellard 已提交
3349
                        gen_vfp_st(s, dp);
B
bellard 已提交
3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375
                    }
                    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;
}

3376
static inline void gen_goto_tb(DisasContext *s, int n, uint32_t dest)
B
bellard 已提交
3377
{
3378 3379 3380 3381
    TranslationBlock *tb;

    tb = s->tb;
    if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
B
bellard 已提交
3382
        tcg_gen_goto_tb(n);
P
pbrook 已提交
3383
        gen_set_pc_im(dest);
B
bellard 已提交
3384
        tcg_gen_exit_tb((long)tb + n);
3385
    } else {
P
pbrook 已提交
3386
        gen_set_pc_im(dest);
B
bellard 已提交
3387
        tcg_gen_exit_tb(0);
3388
    }
B
bellard 已提交
3389 3390
}

B
bellard 已提交
3391 3392
static inline void gen_jmp (DisasContext *s, uint32_t dest)
{
3393
    if (unlikely(s->singlestep_enabled)) {
B
bellard 已提交
3394
        /* An indirect jump so that we still trigger the debug exception.  */
B
bellard 已提交
3395
        if (s->thumb)
P
pbrook 已提交
3396 3397
            dest |= 1;
        gen_bx_im(s, dest);
B
bellard 已提交
3398
    } else {
3399
        gen_goto_tb(s, 0, dest);
B
bellard 已提交
3400 3401 3402 3403
        s->is_jmp = DISAS_TB_JUMP;
    }
}

P
pbrook 已提交
3404
static inline void gen_mulxy(TCGv t0, TCGv t1, int x, int y)
B
bellard 已提交
3405
{
B
bellard 已提交
3406
    if (x)
P
pbrook 已提交
3407
        tcg_gen_sari_i32(t0, t0, 16);
B
bellard 已提交
3408
    else
P
pbrook 已提交
3409
        gen_sxth(t0);
B
bellard 已提交
3410
    if (y)
P
pbrook 已提交
3411
        tcg_gen_sari_i32(t1, t1, 16);
B
bellard 已提交
3412
    else
P
pbrook 已提交
3413 3414
        gen_sxth(t1);
    tcg_gen_mul_i32(t0, t0, t1);
B
bellard 已提交
3415 3416 3417
}

/* Return the mask of PSR bits set by a MSR instruction.  */
P
pbrook 已提交
3418
static uint32_t msr_mask(CPUState *env, DisasContext *s, int flags, int spsr) {
B
bellard 已提交
3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429
    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 已提交
3430

P
pbrook 已提交
3431
    /* Mask out undefined bits.  */
P
pbrook 已提交
3432 3433
    mask &= ~CPSR_RESERVED;
    if (!arm_feature(env, ARM_FEATURE_V6))
P
pbrook 已提交
3434
        mask &= ~(CPSR_E | CPSR_GE);
P
pbrook 已提交
3435
    if (!arm_feature(env, ARM_FEATURE_THUMB2))
P
pbrook 已提交
3436
        mask &= ~CPSR_IT;
P
pbrook 已提交
3437
    /* Mask out execution state bits.  */
P
pbrook 已提交
3438
    if (!spsr)
P
pbrook 已提交
3439
        mask &= ~CPSR_EXEC;
B
bellard 已提交
3440 3441
    /* Mask out privileged bits.  */
    if (IS_USER(s))
P
pbrook 已提交
3442
        mask &= CPSR_USER;
B
bellard 已提交
3443 3444 3445 3446 3447 3448
    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 已提交
3449
    TCGv tmp;
B
bellard 已提交
3450 3451 3452 3453
    if (spsr) {
        /* ??? This is also undefined in system mode.  */
        if (IS_USER(s))
            return 1;
P
pbrook 已提交
3454 3455 3456 3457 3458 3459

        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 已提交
3460
    } else {
P
pbrook 已提交
3461
        gen_set_cpsr(cpu_T[0], mask);
B
bellard 已提交
3462 3463 3464 3465 3466
    }
    gen_lookup_tb(s);
    return 0;
}

P
pbrook 已提交
3467
/* Generate an old-style exception return.  */
B
bellard 已提交
3468 3469
static void gen_exception_return(DisasContext *s)
{
P
pbrook 已提交
3470
    TCGv tmp;
3471
    gen_movl_reg_T0(s, 15);
P
pbrook 已提交
3472 3473 3474
    tmp = load_cpu_field(spsr);
    gen_set_cpsr(tmp, 0xffffffff);
    dead_tmp(tmp);
B
bellard 已提交
3475 3476 3477
    s->is_jmp = DISAS_UPDATE;
}

P
pbrook 已提交
3478 3479
/* Generate a v6 exception return.  Marks both values as dead.  */
static void gen_rfe(DisasContext *s, TCGv pc, TCGv cpsr)
B
bellard 已提交
3480
{
P
pbrook 已提交
3481 3482 3483
    gen_set_cpsr(cpsr, 0xffffffff);
    dead_tmp(cpsr);
    store_reg(s, 15, pc);
P
pbrook 已提交
3484 3485
    s->is_jmp = DISAS_UPDATE;
}
3486

P
pbrook 已提交
3487 3488 3489 3490
static inline void
gen_set_condexec (DisasContext *s)
{
    if (s->condexec_mask) {
P
pbrook 已提交
3491 3492 3493
        uint32_t val = (s->condexec_cond << 4) | (s->condexec_mask >> 1);
        TCGv tmp = new_tmp();
        tcg_gen_movi_i32(tmp, val);
P
pbrook 已提交
3494
        store_cpu_field(tmp, condexec_bits);
P
pbrook 已提交
3495 3496
    }
}
3497

P
pbrook 已提交
3498 3499 3500 3501
static void gen_nop_hint(DisasContext *s, int val)
{
    switch (val) {
    case 3: /* wfi */
P
pbrook 已提交
3502
        gen_set_pc_im(s->pc);
P
pbrook 已提交
3503 3504 3505 3506 3507 3508 3509 3510 3511
        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 已提交
3512

P
pbrook 已提交
3513 3514 3515 3516 3517
/* 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 已提交
3518

P
pbrook 已提交
3519
#define CPU_V001 cpu_V0, cpu_V0, cpu_V1
P
pbrook 已提交
3520 3521 3522 3523

static inline int gen_neon_add(int size)
{
    switch (size) {
P
pbrook 已提交
3524 3525
    case 0: gen_helper_neon_add_u8(CPU_T001); break;
    case 1: gen_helper_neon_add_u16(CPU_T001); break;
P
pbrook 已提交
3526 3527 3528 3529 3530 3531
    case 2: gen_op_addl_T0_T1(); break;
    default: return 1;
    }
    return 0;
}

P
pbrook 已提交
3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575
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 已提交
3576 3577 3578

#define GEN_NEON_INTEGER_OP(name) do { \
    switch ((size << 1) | u) { \
P
pbrook 已提交
3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596
    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 已提交
3597 3598 3599 3600 3601 3602 3603 3604 3605
    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 已提交
3606
  tcg_gen_st_i32(cpu_T[0], cpu_env, offset);
P
pbrook 已提交
3607 3608 3609 3610 3611 3612 3613 3614
}

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

  offset = offsetof(CPUARMState, vfp.scratch[scratch]);
P
pbrook 已提交
3615
  tcg_gen_st_i32(cpu_T[1], cpu_env, offset);
P
pbrook 已提交
3616 3617 3618 3619 3620 3621 3622 3623
}

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

  offset = offsetof(CPUARMState, vfp.scratch[scratch]);
P
pbrook 已提交
3624
  tcg_gen_ld_i32(cpu_T[0], cpu_env, offset);
P
pbrook 已提交
3625 3626 3627 3628 3629 3630 3631 3632
}

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

  offset = offsetof(CPUARMState, vfp.scratch[scratch]);
P
pbrook 已提交
3633
  tcg_gen_ld_i32(cpu_T[1], cpu_env, offset);
P
pbrook 已提交
3634 3635 3636 3637 3638 3639 3640 3641 3642
}

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 已提交
3643
            gen_neon_dup_low16(cpu_T[0]);
P
pbrook 已提交
3644
        else
P
pbrook 已提交
3645
            gen_neon_dup_high16(cpu_T[0]);
P
pbrook 已提交
3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656
    }
}

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 已提交
3657 3658
        case 0: gen_helper_neon_unzip_u8(); break;
        case 1: gen_helper_neon_zip_u16(); break; /* zip and unzip are the same.  */
P
pbrook 已提交
3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699
        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 已提交
3700
    TCGv tmp;
P
pbrook 已提交
3701
    TCGv tmp2;
P
pbrook 已提交
3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729

    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 已提交
3730
                        tmp = gen_ld32(cpu_T[1], IS_USER(s));
P
pbrook 已提交
3731
                        neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
3732
                    } else {
P
pbrook 已提交
3733
                        tmp = neon_load_reg(rd, pass);
P
pbrook 已提交
3734
                        gen_st32(tmp, cpu_T[1], IS_USER(s));
P
pbrook 已提交
3735 3736 3737 3738
                    }
                    gen_op_addl_T1_im(stride);
                } else if (size == 1) {
                    if (load) {
P
pbrook 已提交
3739
                        tmp = gen_ld16u(cpu_T[1], IS_USER(s));
P
pbrook 已提交
3740
                        gen_op_addl_T1_im(stride);
P
pbrook 已提交
3741
                        tmp2 = gen_ld16u(cpu_T[1], IS_USER(s));
P
pbrook 已提交
3742
                        gen_op_addl_T1_im(stride);
P
pbrook 已提交
3743 3744 3745
                        gen_bfi(tmp, tmp, tmp2, 16, 0xffff);
                        dead_tmp(tmp2);
                        neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
3746
                    } else {
P
pbrook 已提交
3747 3748 3749
                        tmp = neon_load_reg(rd, pass);
                        tmp2 = new_tmp();
                        tcg_gen_shri_i32(tmp2, tmp, 16);
P
pbrook 已提交
3750
                        gen_st16(tmp, cpu_T[1], IS_USER(s));
P
pbrook 已提交
3751
                        gen_op_addl_T1_im(stride);
P
pbrook 已提交
3752
                        gen_st16(tmp2, cpu_T[1], IS_USER(s));
P
pbrook 已提交
3753 3754 3755 3756
                        gen_op_addl_T1_im(stride);
                    }
                } else /* size == 0 */ {
                    if (load) {
P
pbrook 已提交
3757
                        TCGV_UNUSED(tmp2);
P
pbrook 已提交
3758
                        for (n = 0; n < 4; n++) {
P
pbrook 已提交
3759
                            tmp = gen_ld8u(cpu_T[1], IS_USER(s));
P
pbrook 已提交
3760 3761
                            gen_op_addl_T1_im(stride);
                            if (n == 0) {
P
pbrook 已提交
3762
                                tmp2 = tmp;
P
pbrook 已提交
3763
                            } else {
P
pbrook 已提交
3764 3765
                                gen_bfi(tmp2, tmp2, tmp, n * 8, 0xff);
                                dead_tmp(tmp);
P
pbrook 已提交
3766 3767
                            }
                        }
P
pbrook 已提交
3768
                        neon_store_reg(rd, pass, tmp2);
P
pbrook 已提交
3769
                    } else {
P
pbrook 已提交
3770
                        tmp2 = neon_load_reg(rd, pass);
P
pbrook 已提交
3771
                        for (n = 0; n < 4; n++) {
P
pbrook 已提交
3772
                            tmp = new_tmp();
P
pbrook 已提交
3773
                            if (n == 0) {
P
pbrook 已提交
3774
                                tcg_gen_mov_i32(tmp, tmp2);
P
pbrook 已提交
3775
                            } else {
P
pbrook 已提交
3776
                                tcg_gen_shri_i32(tmp, tmp2, n * 8);
P
pbrook 已提交
3777
                            }
P
pbrook 已提交
3778
                            gen_st8(tmp, cpu_T[1], IS_USER(s));
P
pbrook 已提交
3779 3780
                            gen_op_addl_T1_im(stride);
                        }
P
pbrook 已提交
3781
                        dead_tmp(tmp2);
P
pbrook 已提交
3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796
                    }
                }
            }
            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;
3797
            gen_movl_T1_reg(s, rn);
P
pbrook 已提交
3798 3799 3800
            for (reg = 0; reg < nregs; reg++) {
                switch (size) {
                case 0:
P
pbrook 已提交
3801
                    tmp = gen_ld8u(cpu_T[1], IS_USER(s));
P
pbrook 已提交
3802
                    gen_neon_dup_u8(tmp, 0);
P
pbrook 已提交
3803 3804
                    break;
                case 1:
P
pbrook 已提交
3805
                    tmp = gen_ld16u(cpu_T[1], IS_USER(s));
P
pbrook 已提交
3806
                    gen_neon_dup_low16(tmp);
P
pbrook 已提交
3807 3808
                    break;
                case 2:
P
pbrook 已提交
3809
                    tmp = gen_ld32(cpu_T[0], IS_USER(s));
P
pbrook 已提交
3810 3811 3812
                    break;
                case 3:
                    return 1;
P
pbrook 已提交
3813 3814
                default: /* Avoid compiler warnings.  */
                    abort();
B
bellard 已提交
3815
                }
P
pbrook 已提交
3816
                gen_op_addl_T1_im(1 << size);
P
pbrook 已提交
3817 3818 3819 3820
                tmp2 = new_tmp();
                tcg_gen_mov_i32(tmp2, tmp);
                neon_store_reg(rd, 0, tmp2);
                neon_store_reg(rd, 0, tmp);
P
pbrook 已提交
3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848
                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 已提交
3849
                        tmp = gen_ld8u(cpu_T[1], IS_USER(s));
P
pbrook 已提交
3850 3851
                        break;
                    case 1:
P
pbrook 已提交
3852
                        tmp = gen_ld16u(cpu_T[1], IS_USER(s));
P
pbrook 已提交
3853 3854
                        break;
                    case 2:
P
pbrook 已提交
3855
                        tmp = gen_ld32(cpu_T[1], IS_USER(s));
P
pbrook 已提交
3856
                        break;
P
pbrook 已提交
3857 3858
                    default: /* Avoid compiler warnings.  */
                        abort();
P
pbrook 已提交
3859 3860
                    }
                    if (size != 2) {
P
pbrook 已提交
3861 3862 3863
                        tmp2 = neon_load_reg(rd, pass);
                        gen_bfi(tmp, tmp2, tmp, shift, size ? 0xffff : 0xff);
                        dead_tmp(tmp2);
P
pbrook 已提交
3864
                    }
P
pbrook 已提交
3865
                    neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
3866
                } else { /* Store */
P
pbrook 已提交
3867 3868 3869
                    tmp = neon_load_reg(rd, pass);
                    if (shift)
                        tcg_gen_shri_i32(tmp, tmp, shift);
P
pbrook 已提交
3870 3871
                    switch (size) {
                    case 0:
P
pbrook 已提交
3872
                        gen_st8(tmp, cpu_T[1], IS_USER(s));
P
pbrook 已提交
3873 3874
                        break;
                    case 1:
P
pbrook 已提交
3875
                        gen_st16(tmp, cpu_T[1], IS_USER(s));
P
pbrook 已提交
3876 3877
                        break;
                    case 2:
P
pbrook 已提交
3878
                        gen_st32(tmp, cpu_T[1], IS_USER(s));
P
pbrook 已提交
3879
                        break;
B
bellard 已提交
3880 3881
                    }
                }
P
pbrook 已提交
3882 3883
                rd += stride;
                gen_op_addl_T1_im(1 << size);
B
bellard 已提交
3884
            }
P
pbrook 已提交
3885
            stride = nregs * (1 << size);
B
bellard 已提交
3886
        }
P
pbrook 已提交
3887 3888
    }
    if (rm != 15) {
P
pbrook 已提交
3889 3890 3891
        TCGv base;

        base = load_reg(s, rn);
P
pbrook 已提交
3892
        if (rm == 13) {
P
pbrook 已提交
3893
            tcg_gen_addi_i32(base, base, stride);
P
pbrook 已提交
3894
        } else {
P
pbrook 已提交
3895 3896 3897 3898
            TCGv index;
            index = load_reg(s, rm);
            tcg_gen_add_i32(base, base, index);
            dead_tmp(index);
P
pbrook 已提交
3899
        }
P
pbrook 已提交
3900
        store_reg(s, rn, base);
P
pbrook 已提交
3901 3902 3903
    }
    return 0;
}
3904

P
pbrook 已提交
3905 3906 3907 3908 3909 3910 3911 3912
/* 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 已提交
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 3949 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 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060
static inline void gen_neon_narrow(int size, TCGv dest, TCGv src)
{
    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();
    }
}

static inline void gen_neon_narrow_sats(int size, TCGv dest, TCGv src)
{
    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();
    }
}

static inline void gen_neon_narrow_satu(int size, TCGv dest, TCGv src)
{
    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();
            }
        }
    }
}

static inline void gen_neon_widen(TCGv dest, TCGv src, int size, int u)
{
    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();
    }
}

static inline void gen_neon_negl(TCGv var, int size)
{
    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();
    }
}

static inline void gen_neon_addl_saturate(TCGv op0, TCGv op1, int size)
{
    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();
    }
}

static inline void gen_neon_mull(TCGv dest, TCGv a, TCGv b, int size, int u)
{
    TCGv tmp;

    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 已提交
4061 4062
/* Translate a NEON data processing instruction.  Return nonzero if the
   instruction is invalid.
P
pbrook 已提交
4063 4064
   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 已提交
4065

P
pbrook 已提交
4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078
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 已提交
4079 4080 4081
    TCGv tmp;
    TCGv tmp2;
    TCGv tmp3;
P
pbrook 已提交
4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093

    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 已提交
4094 4095 4096
        if (size == 3 && (op == 1 || op == 5 || op == 8 || op == 9
                          || op == 10 || op  == 11 || op == 16)) {
            /* 64-bit element instructions.  */
P
pbrook 已提交
4097
            for (pass = 0; pass < (q ? 2 : 1); pass++) {
P
pbrook 已提交
4098 4099
                neon_load_reg64(cpu_V0, rn + pass);
                neon_load_reg64(cpu_V1, rm + pass);
P
pbrook 已提交
4100 4101 4102
                switch (op) {
                case 1: /* VQADD */
                    if (u) {
P
pbrook 已提交
4103
                        gen_helper_neon_add_saturate_u64(CPU_V001);
B
bellard 已提交
4104
                    } else {
P
pbrook 已提交
4105
                        gen_helper_neon_add_saturate_s64(CPU_V001);
B
bellard 已提交
4106
                    }
P
pbrook 已提交
4107 4108 4109
                    break;
                case 5: /* VQSUB */
                    if (u) {
P
pbrook 已提交
4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133
                        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 已提交
4134
                    } else {
P
pbrook 已提交
4135 4136 4137 4138 4139 4140 4141 4142 4143 4144
                        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 已提交
4145
                    }
P
pbrook 已提交
4146 4147 4148
                    break;
                case 16:
                    if (u) {
P
pbrook 已提交
4149
                        tcg_gen_sub_i64(CPU_V001);
P
pbrook 已提交
4150
                    } else {
P
pbrook 已提交
4151
                        tcg_gen_add_i64(CPU_V001);
P
pbrook 已提交
4152 4153 4154 4155
                    }
                    break;
                default:
                    abort();
B
bellard 已提交
4156
                }
P
pbrook 已提交
4157
                neon_store_reg64(cpu_V0, rd + pass);
B
bellard 已提交
4158
            }
P
pbrook 已提交
4159
            return 0;
B
bellard 已提交
4160
        }
P
pbrook 已提交
4161 4162 4163 4164
        switch (op) {
        case 8: /* VSHL */
        case 9: /* VQSHL */
        case 10: /* VRSHL */
P
pbrook 已提交
4165
        case 11: /* VQRSHL */
P
pbrook 已提交
4166
            {
P
pbrook 已提交
4167 4168 4169
                int rtmp;
                /* Shift instruction operands are reversed.  */
                rtmp = rn;
P
pbrook 已提交
4170
                rn = rm;
P
pbrook 已提交
4171
                rm = rtmp;
P
pbrook 已提交
4172 4173
                pairwise = 0;
            }
B
bellard 已提交
4174
            break;
P
pbrook 已提交
4175 4176 4177 4178
        case 20: /* VPMAX */
        case 21: /* VPMIN */
        case 23: /* VPADD */
            pairwise = 1;
B
bellard 已提交
4179
            break;
P
pbrook 已提交
4180 4181
        case 26: /* VPADD (float) */
            pairwise = (u && size < 2);
B
bellard 已提交
4182
            break;
P
pbrook 已提交
4183 4184
        case 30: /* VPMIN/VPMAX (float) */
            pairwise = u;
B
bellard 已提交
4185
            break;
P
pbrook 已提交
4186 4187
        default:
            pairwise = 0;
B
bellard 已提交
4188
            break;
P
pbrook 已提交
4189 4190 4191 4192 4193 4194 4195
        }
        for (pass = 0; pass < (q ? 4 : 2); pass++) {

        if (pairwise) {
            /* Pairwise.  */
            if (q)
                n = (pass & 1) * 2;
B
bellard 已提交
4196
            else
P
pbrook 已提交
4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214
                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 已提交
4215
            GEN_NEON_INTEGER_OP_ENV(qadd);
B
bellard 已提交
4216
            break;
P
pbrook 已提交
4217 4218
        case 2: /* VRHADD */
            GEN_NEON_INTEGER_OP(rhadd);
B
bellard 已提交
4219
            break;
P
pbrook 已提交
4220 4221 4222
        case 3: /* Logic ops.  */
            switch ((u << 2) | size) {
            case 0: /* VAND */
B
bellard 已提交
4223
                gen_op_andl_T0_T1();
P
pbrook 已提交
4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238
                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 已提交
4239 4240 4241
                tmp = neon_load_reg(rd, pass);
                gen_neon_bsl(cpu_T[0], cpu_T[0], cpu_T[1], tmp);
                dead_tmp(tmp);
P
pbrook 已提交
4242 4243
                break;
            case 6: /* VBIT */
P
pbrook 已提交
4244 4245 4246
                tmp = neon_load_reg(rd, pass);
                gen_neon_bsl(cpu_T[0], cpu_T[0], tmp, cpu_T[1]);
                dead_tmp(tmp);
P
pbrook 已提交
4247 4248
                break;
            case 7: /* VBIF */
P
pbrook 已提交
4249 4250 4251
                tmp = neon_load_reg(rd, pass);
                gen_neon_bsl(cpu_T[0], tmp, cpu_T[0], cpu_T[1]);
                dead_tmp(tmp);
P
pbrook 已提交
4252
                break;
B
bellard 已提交
4253 4254
            }
            break;
P
pbrook 已提交
4255 4256 4257 4258
        case 4: /* VHSUB */
            GEN_NEON_INTEGER_OP(hsub);
            break;
        case 5: /* VQSUB */
P
pbrook 已提交
4259
            GEN_NEON_INTEGER_OP_ENV(qsub);
B
bellard 已提交
4260
            break;
P
pbrook 已提交
4261 4262 4263 4264 4265 4266 4267
        case 6: /* VCGT */
            GEN_NEON_INTEGER_OP(cgt);
            break;
        case 7: /* VCGE */
            GEN_NEON_INTEGER_OP(cge);
            break;
        case 8: /* VSHL */
P
pbrook 已提交
4268
            GEN_NEON_INTEGER_OP(shl);
B
bellard 已提交
4269
            break;
P
pbrook 已提交
4270
        case 9: /* VQSHL */
P
pbrook 已提交
4271
            GEN_NEON_INTEGER_OP_ENV(qshl);
B
bellard 已提交
4272
            break;
P
pbrook 已提交
4273
        case 10: /* VRSHL */
P
pbrook 已提交
4274
            GEN_NEON_INTEGER_OP(rshl);
B
bellard 已提交
4275
            break;
P
pbrook 已提交
4276
        case 11: /* VQRSHL */
P
pbrook 已提交
4277
            GEN_NEON_INTEGER_OP_ENV(qrshl);
P
pbrook 已提交
4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298
            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 已提交
4299 4300
                case 0: gen_helper_neon_sub_u8(CPU_T001); break;
                case 1: gen_helper_neon_sub_u16(CPU_T001); break;
P
pbrook 已提交
4301 4302 4303 4304 4305 4306 4307 4308
                case 2: gen_op_subl_T0_T1(); break;
                default: return 1;
                }
            }
            break;
        case 17:
            if (!u) { /* VTST */
                switch (size) {
P
pbrook 已提交
4309 4310 4311
                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 已提交
4312 4313 4314 4315
                default: return 1;
                }
            } else { /* VCEQ */
                switch (size) {
P
pbrook 已提交
4316 4317 4318
                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 已提交
4319 4320 4321 4322 4323 4324
                default: return 1;
                }
            }
            break;
        case 18: /* Multiply.  */
            switch (size) {
P
pbrook 已提交
4325 4326
            case 0: gen_helper_neon_mul_u8(CPU_T001); break;
            case 1: gen_helper_neon_mul_u16(CPU_T001); break;
P
pbrook 已提交
4327 4328 4329 4330 4331
            case 2: gen_op_mul_T0_T1(); break;
            default: return 1;
            }
            NEON_GET_REG(T1, rd, pass);
            if (u) { /* VMLS */
P
pbrook 已提交
4332
                gen_neon_rsb(size);
P
pbrook 已提交
4333 4334 4335 4336 4337 4338
            } else { /* VMLA */
                gen_neon_add(size);
            }
            break;
        case 19: /* VMUL */
            if (u) { /* polynomial */
P
pbrook 已提交
4339
                gen_helper_neon_mul_p8(CPU_T001);
P
pbrook 已提交
4340 4341
            } else { /* Integer */
                switch (size) {
P
pbrook 已提交
4342 4343
                case 0: gen_helper_neon_mul_u8(CPU_T001); break;
                case 1: gen_helper_neon_mul_u16(CPU_T001); break;
P
pbrook 已提交
4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357
                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 已提交
4358 4359
                case 1: gen_helper_neon_qdmulh_s16(CPU_T0E01); break;
                case 2: gen_helper_neon_qdmulh_s32(CPU_T0E01); break;
P
pbrook 已提交
4360 4361 4362 4363
                default: return 1;
                }
            } else { /* VQRDHMUL */
                switch (size) {
P
pbrook 已提交
4364 4365
                case 1: gen_helper_neon_qrdmulh_s16(CPU_T0E01); break;
                case 2: gen_helper_neon_qrdmulh_s32(CPU_T0E01); break;
P
pbrook 已提交
4366 4367 4368 4369 4370 4371 4372 4373
                default: return 1;
                }
            }
            break;
        case 23: /* VPADD */
            if (u)
                return 1;
            switch (size) {
P
pbrook 已提交
4374 4375
            case 0: gen_helper_neon_padd_u8(CPU_T001); break;
            case 1: gen_helper_neon_padd_u16(CPU_T001); break;
P
pbrook 已提交
4376 4377 4378 4379 4380 4381 4382
            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 已提交
4383
                gen_helper_neon_add_f32(CPU_T001);
P
pbrook 已提交
4384 4385
                break;
            case 2: /* VSUB */
P
pbrook 已提交
4386
                gen_helper_neon_sub_f32(CPU_T001);
P
pbrook 已提交
4387 4388
                break;
            case 4: /* VPADD */
P
pbrook 已提交
4389
                gen_helper_neon_add_f32(CPU_T001);
P
pbrook 已提交
4390 4391
                break;
            case 6: /* VABD */
P
pbrook 已提交
4392
                gen_helper_neon_abd_f32(CPU_T001);
P
pbrook 已提交
4393 4394 4395 4396 4397 4398
                break;
            default:
                return 1;
            }
            break;
        case 27: /* Float multiply.  */
P
pbrook 已提交
4399
            gen_helper_neon_mul_f32(CPU_T001);
P
pbrook 已提交
4400 4401 4402
            if (!u) {
                NEON_GET_REG(T1, rd, pass);
                if (size == 0) {
P
pbrook 已提交
4403
                    gen_helper_neon_add_f32(CPU_T001);
P
pbrook 已提交
4404
                } else {
P
pbrook 已提交
4405
                    gen_helper_neon_sub_f32(cpu_T[0], cpu_T[1], cpu_T[0]);
P
pbrook 已提交
4406 4407 4408 4409 4410
                }
            }
            break;
        case 28: /* Float compare.  */
            if (!u) {
P
pbrook 已提交
4411
                gen_helper_neon_ceq_f32(CPU_T001);
B
bellard 已提交
4412
            } else {
P
pbrook 已提交
4413
                if (size == 0)
P
pbrook 已提交
4414
                    gen_helper_neon_cge_f32(CPU_T001);
P
pbrook 已提交
4415
                else
P
pbrook 已提交
4416
                    gen_helper_neon_cgt_f32(CPU_T001);
B
bellard 已提交
4417
            }
B
bellard 已提交
4418
            break;
P
pbrook 已提交
4419 4420 4421 4422
        case 29: /* Float compare absolute.  */
            if (!u)
                return 1;
            if (size == 0)
P
pbrook 已提交
4423
                gen_helper_neon_acge_f32(CPU_T001);
P
pbrook 已提交
4424
            else
P
pbrook 已提交
4425
                gen_helper_neon_acgt_f32(CPU_T001);
B
bellard 已提交
4426
            break;
P
pbrook 已提交
4427 4428
        case 30: /* Float min/max.  */
            if (size == 0)
P
pbrook 已提交
4429
                gen_helper_neon_max_f32(CPU_T001);
P
pbrook 已提交
4430
            else
P
pbrook 已提交
4431
                gen_helper_neon_min_f32(CPU_T001);
P
pbrook 已提交
4432 4433 4434
            break;
        case 31:
            if (size == 0)
P
pbrook 已提交
4435
                gen_helper_recps_f32(cpu_T[0], cpu_T[0], cpu_T[1], cpu_env);
P
pbrook 已提交
4436
            else
P
pbrook 已提交
4437
                gen_helper_rsqrts_f32(cpu_T[0], cpu_T[0], cpu_T[1], cpu_env);
B
bellard 已提交
4438
            break;
P
pbrook 已提交
4439 4440
        default:
            abort();
B
bellard 已提交
4441
        }
P
pbrook 已提交
4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457
        /* 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 已提交
4458
        /* End of 3 register same size operations.  */
P
pbrook 已提交
4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504
    } 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 已提交
4505 4506 4507 4508 4509 4510 4511 4512
                    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 已提交
4513
                            else
P
pbrook 已提交
4514
                                gen_helper_neon_shl_s64(cpu_V0, cpu_V0, cpu_V1);
P
pbrook 已提交
4515
                            break;
P
pbrook 已提交
4516 4517 4518 4519
                        case 2: /* VRSHR */
                        case 3: /* VRSRA */
                            if (u)
                                gen_helper_neon_rshl_u64(cpu_V0, cpu_V0, cpu_V1);
P
pbrook 已提交
4520
                            else
P
pbrook 已提交
4521
                                gen_helper_neon_rshl_s64(cpu_V0, cpu_V0, cpu_V1);
P
pbrook 已提交
4522
                            break;
P
pbrook 已提交
4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533
                        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 已提交
4534
                            else
P
pbrook 已提交
4535 4536 4537 4538
                                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 已提交
4539 4540
                            break;
                        }
P
pbrook 已提交
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 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624
                        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 已提交
4625 4626 4627 4628
                        NEON_SET_REG(T0, rd, pass);
                    }
                } /* for pass */
            } else if (op < 10) {
P
pbrook 已提交
4629
                /* Shift by immediate and narrow:
P
pbrook 已提交
4630 4631 4632 4633 4634
                   VSHRN, VRSHRN, VQSHRN, VQRSHRN.  */
                shift = shift - (1 << (size + 3));
                size++;
                switch (size) {
                case 1:
P
pbrook 已提交
4635
                    imm = (uint16_t)shift;
P
pbrook 已提交
4636
                    imm |= imm << 16;
P
pbrook 已提交
4637
                    tmp2 = tcg_const_i32(imm);
P
pbrook 已提交
4638 4639
                    break;
                case 2:
P
pbrook 已提交
4640 4641
                    imm = (uint32_t)shift;
                    tmp2 = tcg_const_i32(imm);
P
pbrook 已提交
4642
                case 3:
P
pbrook 已提交
4643
                    tmp2 = tcg_const_i64(shift);
P
pbrook 已提交
4644 4645 4646 4647 4648
                    break;
                default:
                    abort();
                }

P
pbrook 已提交
4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662
                for (pass = 0; pass < 2; pass++) {
                    if (size == 3) {
                        neon_load_reg64(cpu_V0, rm + pass);
                        if (q) {
                          if (u)
                            gen_helper_neon_rshl_u64(cpu_V0, cpu_V0, tmp2);
                          else
                            gen_helper_neon_rshl_s64(cpu_V0, cpu_V0, tmp2);
                        } else {
                          if (u)
                            gen_helper_neon_shl_u64(cpu_V0, cpu_V0, tmp2);
                          else
                            gen_helper_neon_shl_s64(cpu_V0, cpu_V0, tmp2);
                        }
B
bellard 已提交
4663
                    } else {
P
pbrook 已提交
4664 4665 4666 4667 4668 4669 4670 4671 4672 4673
                        tmp = neon_load_reg(rm + pass, 0);
                        gen_neon_shift_narrow(size, tmp, tmp2, q, u);
                        tcg_gen_extu_i32_i64(cpu_V0, tmp);
                        dead_tmp(tmp);
                        tmp = neon_load_reg(rm + pass, 1);
                        gen_neon_shift_narrow(size, tmp, tmp2, q, u);
                        tcg_gen_extu_i32_i64(cpu_V1, tmp);
                        dead_tmp(tmp);
                        tcg_gen_shli_i64(cpu_V1, cpu_V1, 32);
                        tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1);
P
pbrook 已提交
4674
                    }
P
pbrook 已提交
4675 4676 4677
                    tmp = new_tmp();
                    if (op == 8 && !u) {
                        gen_neon_narrow(size - 1, tmp, cpu_V0);
P
pbrook 已提交
4678
                    } else {
P
pbrook 已提交
4679 4680
                        if (op == 8)
                            gen_neon_narrow_sats(size - 1, tmp, cpu_V0);
P
pbrook 已提交
4681
                        else
P
pbrook 已提交
4682 4683 4684 4685 4686 4687 4688
                            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 已提交
4689 4690 4691 4692
                    }
                } /* for pass */
            } else if (op == 10) {
                /* VSHLL */
P
pbrook 已提交
4693
                if (q || size == 3)
P
pbrook 已提交
4694
                    return 1;
P
pbrook 已提交
4695 4696
                tmp = neon_load_reg(rm, 0);
                tmp2 = neon_load_reg(rm, 1);
P
pbrook 已提交
4697
                for (pass = 0; pass < 2; pass++) {
P
pbrook 已提交
4698 4699 4700 4701
                    if (pass == 1)
                        tmp = tmp2;

                    gen_neon_widen(cpu_V0, tmp, size, u);
P
pbrook 已提交
4702 4703 4704

                    if (shift != 0) {
                        /* The shift is less than the width of the source
P
pbrook 已提交
4705 4706 4707 4708 4709 4710 4711 4712 4713
                           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 已提交
4714
                            }
P
pbrook 已提交
4715 4716
                            imm64 = imm | (((uint64_t)imm) << 32);
                            tcg_gen_andi_i64(cpu_V0, cpu_V0, imm64);
P
pbrook 已提交
4717 4718
                        }
                    }
P
pbrook 已提交
4719
                    neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
4720 4721 4722 4723
                }
            } else if (op == 15 || op == 16) {
                /* VCVT fixed-point.  */
                for (pass = 0; pass < (q ? 4 : 2); pass++) {
P
pbrook 已提交
4724
                    tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, pass));
P
pbrook 已提交
4725 4726
                    if (op & 1) {
                        if (u)
P
pbrook 已提交
4727
                            gen_vfp_ulto(0, shift);
P
pbrook 已提交
4728
                        else
P
pbrook 已提交
4729
                            gen_vfp_slto(0, shift);
P
pbrook 已提交
4730 4731
                    } else {
                        if (u)
P
pbrook 已提交
4732
                            gen_vfp_toul(0, shift);
P
pbrook 已提交
4733
                        else
P
pbrook 已提交
4734
                            gen_vfp_tosl(0, shift);
B
bellard 已提交
4735
                    }
P
pbrook 已提交
4736
                    tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, pass));
B
bellard 已提交
4737 4738
                }
            } else {
P
pbrook 已提交
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 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790
                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 已提交
4791
                    tmp = neon_load_reg(rd, pass);
P
pbrook 已提交
4792 4793 4794
                    if (invert) {
                        /* The immediate value has already been inverted, so
                           BIC becomes AND.  */
P
pbrook 已提交
4795
                        tcg_gen_andi_i32(tmp, tmp, imm);
P
pbrook 已提交
4796
                    } else {
P
pbrook 已提交
4797
                        tcg_gen_ori_i32(tmp, tmp, imm);
P
pbrook 已提交
4798 4799
                    }
                } else {
P
pbrook 已提交
4800 4801
                    /* VMOV, VMVN.  */
                    tmp = new_tmp();
P
pbrook 已提交
4802
                    if (op == 14 && invert) {
P
pbrook 已提交
4803 4804
                        uint32_t val;
                        val = 0;
P
pbrook 已提交
4805 4806
                        for (n = 0; n < 4; n++) {
                            if (imm & (1 << (n + (pass & 1) * 4)))
P
pbrook 已提交
4807
                                val |= 0xff << (n * 8);
P
pbrook 已提交
4808
                        }
P
pbrook 已提交
4809 4810 4811
                        tcg_gen_movi_i32(tmp, val);
                    } else {
                        tcg_gen_movi_i32(tmp, imm);
P
pbrook 已提交
4812 4813
                    }
                }
P
pbrook 已提交
4814
                neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847
            }
        }
    } else { /* (insn & 0x00800010 == 0x00800010) */
        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 已提交
4848 4849 4850
                if (size == 0 && (op == 9 || op == 11 || op == 13))
                    return 1;

P
pbrook 已提交
4851 4852 4853
                /* Avoid overlapping operands.  Wide source operands are
                   always aligned so will never overlap with wide
                   destinations in problematic ways.  */
P
pbrook 已提交
4854 4855 4856 4857 4858 4859
                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 已提交
4860
                }
P
pbrook 已提交
4861
                TCGV_UNUSED(tmp3);
P
pbrook 已提交
4862
                for (pass = 0; pass < 2; pass++) {
P
pbrook 已提交
4863 4864
                    if (src1_wide) {
                        neon_load_reg64(cpu_V0, rn + pass);
P
pbrook 已提交
4865
                        TCGV_UNUSED(tmp);
P
pbrook 已提交
4866
                    } else {
P
pbrook 已提交
4867 4868 4869 4870
                        if (pass == 1 && rd == rn) {
                            gen_neon_movl_T0_scratch(2);
                            tmp = new_tmp();
                            tcg_gen_mov_i32(tmp, cpu_T[0]);
P
pbrook 已提交
4871
                        } else {
P
pbrook 已提交
4872 4873 4874 4875
                            tmp = neon_load_reg(rn, pass);
                        }
                        if (prewiden) {
                            gen_neon_widen(cpu_V0, tmp, size, u);
P
pbrook 已提交
4876 4877
                        }
                    }
P
pbrook 已提交
4878 4879
                    if (src2_wide) {
                        neon_load_reg64(cpu_V1, rm + pass);
P
pbrook 已提交
4880
                        TCGV_UNUSED(tmp2);
P
pbrook 已提交
4881
                    } else {
P
pbrook 已提交
4882
                        if (pass == 1 && rd == rm) {
P
pbrook 已提交
4883
                            gen_neon_movl_T0_scratch(2);
P
pbrook 已提交
4884 4885
                            tmp2 = new_tmp();
                            tcg_gen_mov_i32(tmp2, cpu_T[0]);
P
pbrook 已提交
4886
                        } else {
P
pbrook 已提交
4887 4888 4889 4890
                            tmp2 = neon_load_reg(rm, pass);
                        }
                        if (prewiden) {
                            gen_neon_widen(cpu_V1, tmp2, size, u);
P
pbrook 已提交
4891 4892 4893 4894
                        }
                    }
                    switch (op) {
                    case 0: case 1: case 4: /* VADDL, VADDW, VADDHN, VRADDHN */
P
pbrook 已提交
4895
                        gen_neon_addl(size);
P
pbrook 已提交
4896 4897
                        break;
                    case 2: case 3: case 6: /* VSUBL, VSUBW, VSUBHL, VRSUBHL */
P
pbrook 已提交
4898
                        gen_neon_subl(size);
P
pbrook 已提交
4899 4900 4901
                        break;
                    case 5: case 7: /* VABAL, VABDL */
                        switch ((size << 1) | u) {
P
pbrook 已提交
4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919
                        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 已提交
4920 4921
                        default: abort();
                        }
P
pbrook 已提交
4922 4923
                        dead_tmp(tmp2);
                        dead_tmp(tmp);
P
pbrook 已提交
4924 4925 4926
                        break;
                    case 8: case 9: case 10: case 11: case 12: case 13:
                        /* VMLAL, VQDMLAL, VMLSL, VQDMLSL, VMULL, VQDMULL */
P
pbrook 已提交
4927
                        gen_neon_mull(cpu_V0, tmp, tmp2, size, u);
P
pbrook 已提交
4928 4929 4930 4931 4932 4933 4934 4935 4936 4937
                        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 已提交
4938
                            gen_neon_negl(cpu_V0, size);
P
pbrook 已提交
4939 4940 4941
                        }

                        if (op != 13) {
P
pbrook 已提交
4942
                            neon_load_reg64(cpu_V1, rd + pass);
P
pbrook 已提交
4943 4944 4945 4946
                        }

                        switch (op) {
                        case 5: case 8: case 10: /* VABAL, VMLAL, VMLSL */
P
pbrook 已提交
4947
                            gen_neon_addl(size);
P
pbrook 已提交
4948 4949
                            break;
                        case 9: case 11: /* VQDMLAL, VQDMLSL */
P
pbrook 已提交
4950 4951 4952
                            gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
                            gen_neon_addl_saturate(cpu_V0, cpu_V1, size);
                            break;
P
pbrook 已提交
4953 4954
                            /* Fall through.  */
                        case 13: /* VQDMULL */
P
pbrook 已提交
4955
                            gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
P
pbrook 已提交
4956 4957 4958 4959
                            break;
                        default:
                            abort();
                        }
P
pbrook 已提交
4960
                        neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
4961 4962
                    } else if (op == 4 || op == 6) {
                        /* Narrowing operation.  */
P
pbrook 已提交
4963
                        tmp = new_tmp();
P
pbrook 已提交
4964 4965
                        if (u) {
                            switch (size) {
P
pbrook 已提交
4966 4967 4968 4969 4970 4971 4972 4973 4974 4975
                            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 已提交
4976 4977 4978 4979
                            default: abort();
                            }
                        } else {
                            switch (size) {
P
pbrook 已提交
4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990
                            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 已提交
4991 4992 4993
                            default: abort();
                            }
                        }
P
pbrook 已提交
4994 4995 4996 4997 4998 4999
                        if (pass == 0) {
                            tmp3 = tmp;
                        } else {
                            neon_store_reg(rd, 0, tmp3);
                            neon_store_reg(rd, 1, tmp);
                        }
P
pbrook 已提交
5000 5001
                    } else {
                        /* Write back the result.  */
P
pbrook 已提交
5002
                        neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016
                    }
                }
            } 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 已提交
5017
                    gen_neon_movl_scratch_T0(0);
P
pbrook 已提交
5018 5019
                    for (pass = 0; pass < (u ? 4 : 2); pass++) {
                        if (pass != 0)
P
pbrook 已提交
5020
                            gen_neon_movl_T0_scratch(0);
P
pbrook 已提交
5021 5022 5023
                        NEON_GET_REG(T1, rn, pass);
                        if (op == 12) {
                            if (size == 1) {
P
pbrook 已提交
5024
                                gen_helper_neon_qdmulh_s16(CPU_T0E01);
P
pbrook 已提交
5025
                            } else {
P
pbrook 已提交
5026
                                gen_helper_neon_qdmulh_s32(CPU_T0E01);
P
pbrook 已提交
5027 5028 5029
                            }
                        } else if (op == 13) {
                            if (size == 1) {
P
pbrook 已提交
5030
                                gen_helper_neon_qrdmulh_s16(CPU_T0E01);
P
pbrook 已提交
5031
                            } else {
P
pbrook 已提交
5032
                                gen_helper_neon_qrdmulh_s32(CPU_T0E01);
P
pbrook 已提交
5033 5034
                            }
                        } else if (op & 1) {
P
pbrook 已提交
5035
                            gen_helper_neon_mul_f32(CPU_T001);
P
pbrook 已提交
5036 5037
                        } else {
                            switch (size) {
P
pbrook 已提交
5038 5039
                            case 0: gen_helper_neon_mul_u8(CPU_T001); break;
                            case 1: gen_helper_neon_mul_u16(CPU_T001); break;
P
pbrook 已提交
5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051
                            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 已提交
5052
                                gen_helper_neon_add_f32(CPU_T001);
P
pbrook 已提交
5053 5054
                                break;
                            case 4:
P
pbrook 已提交
5055
                                gen_neon_rsb(size);
P
pbrook 已提交
5056 5057
                                break;
                            case 5:
P
pbrook 已提交
5058
                                gen_helper_neon_sub_f32(cpu_T[0], cpu_T[1], cpu_T[0]);
P
pbrook 已提交
5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072
                                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 已提交
5073 5074 5075
                    if (size == 0 && (op == 3 || op == 7 || op == 11))
                        return 1;

P
pbrook 已提交
5076
                    gen_neon_get_scalar(size, rm);
P
pbrook 已提交
5077 5078
                    NEON_GET_REG(T1, rn, 1);

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

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);
    case 15:
	return disas_cp15_insn (env, s, insn);
    default:
	/* Unknown coprocessor.  See if the board has hooked it.  */
	return disas_cp_insn (env, s, insn);
    }
}

P
pbrook 已提交
5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635

/* Store a 64-bit value to a register pair.  Clobbers val.  */
static void gen_storeq_reg(DisasContext *s, int rlow, int rhigh, TCGv val)
{
    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.  */
static void gen_addq_lo(DisasContext *s, TCGv val, int rlow)
{
    TCGv tmp;
    TCGv tmp2;

    /* Load 64-bit value rd:rn.  */
    tmp = tcg_temp_new(TCG_TYPE_I64);
    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.  */
static void gen_addq(DisasContext *s, TCGv val, int rlow, int rhigh)
{
    TCGv tmp;
    TCGv tmp2;

    /* Load 64-bit value rd:rn.  */
    tmp = tcg_temp_new(TCG_TYPE_I64);
    tmp2 = load_reg(s, rhigh);
    tcg_gen_extu_i32_i64(tmp, tmp2);
    dead_tmp(tmp2);
    tcg_gen_shli_i64(tmp, tmp, 32);
    tcg_gen_add_i64(val, val, tmp);

    tmp2 = load_reg(s, rlow);
    tcg_gen_extu_i32_i64(tmp, tmp2);
    dead_tmp(tmp2);
    tcg_gen_add_i64(val, val, tmp);
}

/* Set N and Z flags from a 64-bit value.  */
static void gen_logicq_cc(TCGv val)
{
    TCGv tmp = new_tmp();
    gen_helper_logicq_cc(tmp, val);
P
pbrook 已提交
5636 5637
    gen_logic_CC(tmp);
    dead_tmp(tmp);
P
pbrook 已提交
5638 5639
}

P
pbrook 已提交
5640 5641 5642
static void disas_arm_insn(CPUState * env, DisasContext *s)
{
    unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;
P
pbrook 已提交
5643
    TCGv tmp;
P
pbrook 已提交
5644
    TCGv tmp2;
P
pbrook 已提交
5645
    TCGv tmp3;
P
pbrook 已提交
5646
    TCGv addr;
P
pbrook 已提交
5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688

    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 已提交
5689
                gen_helper_clrex(cpu_env);
P
pbrook 已提交
5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707
                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 */
            uint32_t offset;
            if (IS_USER(s))
                goto illegal_op;
            ARCH(6);
            op1 = (insn & 0x1f);
            if (op1 == (env->uncached_cpsr & CPSR_M)) {
P
pbrook 已提交
5708
                addr = load_reg(s, 13);
P
pbrook 已提交
5709
            } else {
P
pbrook 已提交
5710 5711
                addr = new_tmp();
                gen_helper_get_r13_banked(addr, cpu_env, tcg_const_i32(op1));
P
pbrook 已提交
5712 5713 5714 5715 5716 5717 5718 5719 5720 5721
            }
            i = (insn >> 23) & 3;
            switch (i) {
            case 0: offset = -4; break; /* DA */
            case 1: offset = -8; break; /* DB */
            case 2: offset = 0; break; /* IA */
            case 3: offset = 4; break; /* IB */
            default: abort();
            }
            if (offset)
P
pbrook 已提交
5722 5723 5724 5725 5726 5727 5728
                tcg_gen_addi_i32(addr, addr, offset);
            tmp = load_reg(s, 14);
            gen_st32(tmp, addr, 0);
            tmp = new_tmp();
            gen_helper_cpsr_read(tmp);
            tcg_gen_addi_i32(addr, addr, 4);
            gen_st32(tmp, addr, 0);
P
pbrook 已提交
5729 5730 5731 5732 5733 5734 5735 5736 5737 5738
            if (insn & (1 << 21)) {
                /* Base writeback.  */
                switch (i) {
                case 0: offset = -8; break;
                case 1: offset = -4; break;
                case 2: offset = 4; break;
                case 3: offset = 0; break;
                default: abort();
                }
                if (offset)
P
pbrook 已提交
5739
                    tcg_gen_addi_i32(addr, tmp, offset);
P
pbrook 已提交
5740 5741 5742
                if (op1 == (env->uncached_cpsr & CPSR_M)) {
                    gen_movl_reg_T1(s, 13);
                } else {
P
pbrook 已提交
5743
                    gen_helper_set_r13_banked(cpu_env, tcg_const_i32(op1), cpu_T[1]);
P
pbrook 已提交
5744
                }
P
pbrook 已提交
5745 5746
            } else {
                dead_tmp(addr);
P
pbrook 已提交
5747 5748 5749 5750 5751 5752 5753 5754
            }
        } else if ((insn & 0x0e5fffe0) == 0x081d0a00) {
            /* rfe */
            uint32_t offset;
            if (IS_USER(s))
                goto illegal_op;
            ARCH(6);
            rn = (insn >> 16) & 0xf;
P
pbrook 已提交
5755
            addr = load_reg(s, rn);
P
pbrook 已提交
5756 5757
            i = (insn >> 23) & 3;
            switch (i) {
P
pbrook 已提交
5758 5759 5760 5761
            case 0: offset = -4; break; /* DA */
            case 1: offset = -8; break; /* DB */
            case 2: offset = 0; break; /* IA */
            case 3: offset = 4; break; /* IB */
P
pbrook 已提交
5762 5763 5764
            default: abort();
            }
            if (offset)
P
pbrook 已提交
5765 5766 5767 5768 5769
                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 已提交
5770 5771 5772
            if (insn & (1 << 21)) {
                /* Base writeback.  */
                switch (i) {
P
pbrook 已提交
5773 5774 5775 5776
                case 0: offset = -8; break;
                case 1: offset = -4; break;
                case 2: offset = 4; break;
                case 3: offset = 0; break;
P
pbrook 已提交
5777 5778 5779
                default: abort();
                }
                if (offset)
P
pbrook 已提交
5780 5781 5782 5783
                    tcg_gen_addi_i32(addr, addr, offset);
                store_reg(s, rn, addr);
            } else {
                dead_tmp(addr);
P
pbrook 已提交
5784
            }
P
pbrook 已提交
5785
            gen_rfe(s, tmp, tmp2);
P
pbrook 已提交
5786 5787 5788 5789 5790
        } else if ((insn & 0x0e000000) == 0x0a000000) {
            /* branch link and change to thumb (blx <offset>) */
            int32_t offset;

            val = (uint32_t)s->pc;
P
pbrook 已提交
5791 5792 5793
            tmp = new_tmp();
            tcg_gen_movi_i32(tmp, val);
            store_reg(s, 14, tmp);
P
pbrook 已提交
5794 5795 5796 5797 5798 5799
            /* 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 已提交
5800
            gen_bx_im(s, val);
P
pbrook 已提交
5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812
            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 已提交
5813
        } else if ((insn & 0x0ff10020) == 0x01000000) {
P
pbrook 已提交
5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829
            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 已提交
5830
            if (insn & (1 << 17)) {
P
pbrook 已提交
5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845
                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 已提交
5846
        gen_test_cc(cond ^ 1, s->condlabel);
P
pbrook 已提交
5847 5848 5849 5850 5851 5852 5853 5854 5855
        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 已提交
5856 5857
                tmp = new_tmp();
                tcg_gen_movi_i32(tmp, val);
P
pbrook 已提交
5858 5859
            } else {
                /* MOVT */
P
pbrook 已提交
5860
                tmp = load_reg(s, rd);
P
pbrook 已提交
5861
                tcg_gen_ext16u_i32(tmp, tmp);
P
pbrook 已提交
5862
                tcg_gen_ori_i32(tmp, tmp, val << 16);
P
pbrook 已提交
5863
            }
P
pbrook 已提交
5864
            store_reg(s, rd, tmp);
P
pbrook 已提交
5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901
        } 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 已提交
5902
                    tmp = load_cpu_field(spsr);
P
pbrook 已提交
5903
                } else {
P
pbrook 已提交
5904 5905
                    tmp = new_tmp();
                    gen_helper_cpsr_read(tmp);
P
pbrook 已提交
5906
                }
P
pbrook 已提交
5907
                store_reg(s, rd, tmp);
P
pbrook 已提交
5908 5909 5910 5911 5912
            }
            break;
        case 0x1:
            if (op1 == 1) {
                /* branch/exchange thumb (bx).  */
P
pbrook 已提交
5913 5914
                tmp = load_reg(s, rm);
                gen_bx(s, tmp);
P
pbrook 已提交
5915 5916 5917
            } else if (op1 == 3) {
                /* clz */
                rd = (insn >> 12) & 0xf;
P
pbrook 已提交
5918 5919 5920
                tmp = load_reg(s, rm);
                gen_helper_clz(tmp, tmp);
                store_reg(s, rd, tmp);
P
pbrook 已提交
5921 5922 5923 5924 5925 5926 5927 5928
            } else {
                goto illegal_op;
            }
            break;
        case 0x2:
            if (op1 == 1) {
                ARCH(5J); /* bxj */
                /* Trivial implementation equivalent to bx.  */
P
pbrook 已提交
5929 5930
                tmp = load_reg(s, rm);
                gen_bx(s, tmp);
P
pbrook 已提交
5931 5932 5933 5934 5935 5936 5937 5938 5939
            } else {
                goto illegal_op;
            }
            break;
        case 0x3:
            if (op1 != 1)
              goto illegal_op;

            /* branch link/exchange thumb (blx) */
P
pbrook 已提交
5940 5941 5942 5943 5944
            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 已提交
5945 5946 5947 5948
            break;
        case 0x5: /* saturating add/subtract */
            rd = (insn >> 12) & 0xf;
            rn = (insn >> 16) & 0xf;
P
pbrook 已提交
5949 5950
            tmp = load_reg(s, rn);
            tmp2 = load_reg(s, rn);
P
pbrook 已提交
5951
            if (op1 & 2)
P
pbrook 已提交
5952
                gen_helper_double_saturate(tmp2, tmp2);
P
pbrook 已提交
5953
            if (op1 & 1)
P
pbrook 已提交
5954
                gen_helper_sub_saturate(tmp, tmp, tmp2);
P
pbrook 已提交
5955
            else
P
pbrook 已提交
5956 5957 5958
                gen_helper_add_saturate(tmp, tmp, tmp2);
            dead_tmp(tmp2);
            store_reg(s, rd, tmp);
P
pbrook 已提交
5959 5960 5961
            break;
        case 7: /* bkpt */
            gen_set_condexec(s);
P
pbrook 已提交
5962
            gen_set_pc_im(s->pc - 4);
P
pbrook 已提交
5963
            gen_exception(EXCP_BKPT);
P
pbrook 已提交
5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974
            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 已提交
5975 5976
                tmp = load_reg(s, rm);
                tmp2 = load_reg(s, rs);
P
pbrook 已提交
5977
                if (sh & 4)
P
pbrook 已提交
5978
                    tcg_gen_sari_i32(tmp2, tmp2, 16);
P
pbrook 已提交
5979
                else
P
pbrook 已提交
5980 5981 5982 5983 5984
                    gen_sxth(tmp2);
                tmp2 = gen_muls_i64_i32(tmp, tmp2);
                tcg_gen_shri_i64(tmp2, tmp2, 16);
                tmp = new_tmp();
                tcg_gen_trunc_i64_i32(tmp, tmp2);
P
pbrook 已提交
5985
                if ((sh & 2) == 0) {
P
pbrook 已提交
5986 5987 5988
                    tmp2 = load_reg(s, rn);
                    gen_helper_add_setq(tmp, tmp, tmp2);
                    dead_tmp(tmp2);
P
pbrook 已提交
5989
                }
P
pbrook 已提交
5990
                store_reg(s, rd, tmp);
P
pbrook 已提交
5991 5992
            } else {
                /* 16 * 16 */
P
pbrook 已提交
5993 5994 5995 5996
                tmp = load_reg(s, rm);
                tmp2 = load_reg(s, rs);
                gen_mulxy(tmp, tmp2, sh & 2, sh & 4);
                dead_tmp(tmp2);
P
pbrook 已提交
5997
                if (op1 == 2) {
5998 5999 6000 6001 6002
                    tmp2 = tcg_temp_new(TCG_TYPE_I64);
                    tcg_gen_ext_i32_i64(tmp2, tmp);
                    dead_tmp(tmp);
                    gen_addq(s, tmp2, rn, rd);
                    gen_storeq_reg(s, rn, rd, tmp2);
P
pbrook 已提交
6003 6004
                } else {
                    if (op1 == 0) {
P
pbrook 已提交
6005 6006 6007
                        tmp2 = load_reg(s, rn);
                        gen_helper_add_setq(tmp, tmp, tmp2);
                        dead_tmp(tmp2);
P
pbrook 已提交
6008
                    }
P
pbrook 已提交
6009
                    store_reg(s, rd, tmp);
P
pbrook 已提交
6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033
                }
            }
            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;
            if (shift)
                val = (val >> shift) | (val << (32 - shift));
            gen_op_movl_T1_im(val);
            if (logic_cc && shift)
P
pbrook 已提交
6034
                gen_set_CF_bit31(cpu_T[1]);
P
pbrook 已提交
6035 6036 6037 6038 6039 6040 6041
        } else {
            /* register */
            rm = (insn) & 0xf;
            gen_movl_T1_reg(s, rm);
            shiftop = (insn >> 5) & 3;
            if (!(insn & (1 << 4))) {
                shift = (insn >> 7) & 0x1f;
P
pbrook 已提交
6042
                gen_arm_shift_im(cpu_T[1], shiftop, shift, logic_cc);
P
pbrook 已提交
6043 6044
            } else {
                rs = (insn >> 8) & 0xf;
P
pbrook 已提交
6045 6046
                tmp = load_reg(s, rs);
                gen_arm_shift_reg(cpu_T[1], shiftop, tmp, logic_cc);
P
pbrook 已提交
6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099
            }
        }
        if (op1 != 0x0f && op1 != 0x0d) {
            rn = (insn >> 16) & 0xf;
            gen_movl_T0_reg(s, rn);
        }
        rd = (insn >> 12) & 0xf;
        switch(op1) {
        case 0x00:
            gen_op_andl_T0_T1();
            gen_movl_reg_T0(s, rd);
            if (logic_cc)
                gen_op_logic_T0_cc();
            break;
        case 0x01:
            gen_op_xorl_T0_T1();
            gen_movl_reg_T0(s, rd);
            if (logic_cc)
                gen_op_logic_T0_cc();
            break;
        case 0x02:
            if (set_cc && rd == 15) {
                /* SUBS r15, ... is used for exception return.  */
                if (IS_USER(s))
                    goto illegal_op;
                gen_op_subl_T0_T1_cc();
                gen_exception_return(s);
            } else {
                if (set_cc)
                    gen_op_subl_T0_T1_cc();
                else
                    gen_op_subl_T0_T1();
                gen_movl_reg_T0(s, rd);
            }
            break;
        case 0x03:
            if (set_cc)
                gen_op_rsbl_T0_T1_cc();
            else
                gen_op_rsbl_T0_T1();
            gen_movl_reg_T0(s, rd);
            break;
        case 0x04:
            if (set_cc)
                gen_op_addl_T0_T1_cc();
            else
                gen_op_addl_T0_T1();
            gen_movl_reg_T0(s, rd);
            break;
        case 0x05:
            if (set_cc)
                gen_op_adcl_T0_T1_cc();
            else
P
pbrook 已提交
6100
                gen_adc_T0_T1();
P
pbrook 已提交
6101 6102 6103 6104 6105 6106
            gen_movl_reg_T0(s, rd);
            break;
        case 0x06:
            if (set_cc)
                gen_op_sbcl_T0_T1_cc();
            else
P
pbrook 已提交
6107
                gen_sbc_T0_T1();
P
pbrook 已提交
6108 6109 6110 6111 6112 6113
            gen_movl_reg_T0(s, rd);
            break;
        case 0x07:
            if (set_cc)
                gen_op_rscl_T0_T1_cc();
            else
P
pbrook 已提交
6114
                gen_rsc_T0_T1();
P
pbrook 已提交
6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189
            gen_movl_reg_T0(s, rd);
            break;
        case 0x08:
            if (set_cc) {
                gen_op_andl_T0_T1();
                gen_op_logic_T0_cc();
            }
            break;
        case 0x09:
            if (set_cc) {
                gen_op_xorl_T0_T1();
                gen_op_logic_T0_cc();
            }
            break;
        case 0x0a:
            if (set_cc) {
                gen_op_subl_T0_T1_cc();
            }
            break;
        case 0x0b:
            if (set_cc) {
                gen_op_addl_T0_T1_cc();
            }
            break;
        case 0x0c:
            gen_op_orl_T0_T1();
            gen_movl_reg_T0(s, rd);
            if (logic_cc)
                gen_op_logic_T0_cc();
            break;
        case 0x0d:
            if (logic_cc && rd == 15) {
                /* MOVS r15, ... is used for exception return.  */
                if (IS_USER(s))
                    goto illegal_op;
                gen_op_movl_T0_T1();
                gen_exception_return(s);
            } else {
                gen_movl_reg_T1(s, rd);
                if (logic_cc)
                    gen_op_logic_T1_cc();
            }
            break;
        case 0x0e:
            gen_op_bicl_T0_T1();
            gen_movl_reg_T0(s, rd);
            if (logic_cc)
                gen_op_logic_T0_cc();
            break;
        default:
        case 0x0f:
            gen_op_notl_T1();
            gen_movl_reg_T1(s, rd);
            if (logic_cc)
                gen_op_logic_T1_cc();
            break;
        }
    } 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 已提交
6190 6191 6192 6193
                        tmp = load_reg(s, rs);
                        tmp2 = load_reg(s, rm);
                        tcg_gen_mul_i32(tmp, tmp, tmp2);
                        dead_tmp(tmp2);
P
pbrook 已提交
6194 6195 6196
                        if (insn & (1 << 22)) {
                            /* Subtract (mls) */
                            ARCH(6T2);
P
pbrook 已提交
6197 6198 6199
                            tmp2 = load_reg(s, rn);
                            tcg_gen_sub_i32(tmp, tmp2, tmp);
                            dead_tmp(tmp2);
P
pbrook 已提交
6200 6201
                        } else if (insn & (1 << 21)) {
                            /* Add */
P
pbrook 已提交
6202 6203 6204
                            tmp2 = load_reg(s, rn);
                            tcg_gen_add_i32(tmp, tmp, tmp2);
                            dead_tmp(tmp2);
P
pbrook 已提交
6205 6206
                        }
                        if (insn & (1 << 20))
P
pbrook 已提交
6207 6208
                            gen_logic_CC(tmp);
                        store_reg(s, rd, tmp);
P
pbrook 已提交
6209 6210 6211
                        break;
                    default:
                        /* 64 bit mul */
P
pbrook 已提交
6212 6213
                        tmp = load_reg(s, rs);
                        tmp2 = load_reg(s, rm);
P
pbrook 已提交
6214
                        if (insn & (1 << 22))
P
pbrook 已提交
6215
                            tmp = gen_muls_i64_i32(tmp, tmp2);
P
pbrook 已提交
6216
                        else
P
pbrook 已提交
6217
                            tmp = gen_mulu_i64_i32(tmp, tmp2);
P
pbrook 已提交
6218
                        if (insn & (1 << 21)) /* mult accumulate */
P
pbrook 已提交
6219
                            gen_addq(s, tmp, rn, rd);
P
pbrook 已提交
6220 6221
                        if (!(insn & (1 << 23))) { /* double accumulate */
                            ARCH(6);
P
pbrook 已提交
6222 6223
                            gen_addq_lo(s, tmp, rn);
                            gen_addq_lo(s, tmp, rd);
P
pbrook 已提交
6224 6225
                        }
                        if (insn & (1 << 20))
P
pbrook 已提交
6226 6227
                            gen_logicq_cc(tmp);
                        gen_storeq_reg(s, rn, rd, tmp);
P
pbrook 已提交
6228 6229 6230 6231 6232 6233 6234 6235
                        break;
                    }
                } else {
                    rn = (insn >> 16) & 0xf;
                    rd = (insn >> 12) & 0xf;
                    if (insn & (1 << 23)) {
                        /* load/store exclusive */
                        gen_movl_T1_reg(s, rn);
B
balrog 已提交
6236
                        addr = cpu_T[1];
P
pbrook 已提交
6237
                        if (insn & (1 << 20)) {
P
pbrook 已提交
6238 6239 6240
                            gen_helper_mark_exclusive(cpu_env, cpu_T[1]);
                            tmp = gen_ld32(addr, IS_USER(s));
                            store_reg(s, rd, tmp);
P
pbrook 已提交
6241
                        } else {
P
pbrook 已提交
6242
                            int label = gen_new_label();
P
pbrook 已提交
6243
                            rm = insn & 0xf;
P
pbrook 已提交
6244
                            gen_helper_test_exclusive(cpu_T[0], cpu_env, addr);
P
pbrook 已提交
6245 6246
                            tcg_gen_brcondi_i32(TCG_COND_NE, cpu_T[0],
                                                0, label);
P
pbrook 已提交
6247 6248
                            tmp = load_reg(s,rm);
                            gen_st32(tmp, cpu_T[1], IS_USER(s));
B
balrog 已提交
6249
                            gen_set_label(label);
P
pbrook 已提交
6250
                            gen_movl_reg_T0(s, rd);
P
pbrook 已提交
6251 6252 6253 6254 6255
                        }
                    } else {
                        /* SWP instruction */
                        rm = (insn) & 0xf;

P
pbrook 已提交
6256 6257 6258 6259 6260
                        /* ??? 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 已提交
6261
                        if (insn & (1 << 22)) {
P
pbrook 已提交
6262 6263
                            tmp2 = gen_ld8u(addr, IS_USER(s));
                            gen_st8(tmp, addr, IS_USER(s));
P
pbrook 已提交
6264
                        } else {
P
pbrook 已提交
6265 6266
                            tmp2 = gen_ld32(addr, IS_USER(s));
                            gen_st32(tmp, addr, IS_USER(s));
P
pbrook 已提交
6267
                        }
P
pbrook 已提交
6268 6269
                        dead_tmp(addr);
                        store_reg(s, rd, tmp2);
P
pbrook 已提交
6270 6271 6272 6273 6274 6275 6276 6277
                    }
                }
            } else {
                int address_offset;
                int load;
                /* Misc load/store */
                rn = (insn >> 16) & 0xf;
                rd = (insn >> 12) & 0xf;
P
pbrook 已提交
6278
                addr = load_reg(s, rn);
P
pbrook 已提交
6279
                if (insn & (1 << 24))
P
pbrook 已提交
6280
                    gen_add_datah_offset(s, insn, 0, addr);
P
pbrook 已提交
6281 6282 6283 6284 6285
                address_offset = 0;
                if (insn & (1 << 20)) {
                    /* load */
                    switch(sh) {
                    case 1:
P
pbrook 已提交
6286
                        tmp = gen_ld16u(addr, IS_USER(s));
P
pbrook 已提交
6287 6288
                        break;
                    case 2:
P
pbrook 已提交
6289
                        tmp = gen_ld8s(addr, IS_USER(s));
P
pbrook 已提交
6290 6291 6292
                        break;
                    default:
                    case 3:
P
pbrook 已提交
6293
                        tmp = gen_ld16s(addr, IS_USER(s));
P
pbrook 已提交
6294 6295 6296 6297 6298 6299 6300
                        break;
                    }
                    load = 1;
                } else if (sh & 2) {
                    /* doubleword */
                    if (sh & 1) {
                        /* store */
P
pbrook 已提交
6301 6302 6303 6304 6305
                        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 已提交
6306 6307 6308
                        load = 0;
                    } else {
                        /* load */
P
pbrook 已提交
6309 6310 6311 6312
                        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 已提交
6313 6314 6315 6316 6317 6318
                        rd++;
                        load = 1;
                    }
                    address_offset = -4;
                } else {
                    /* store */
P
pbrook 已提交
6319 6320
                    tmp = load_reg(s, rd);
                    gen_st16(tmp, addr, IS_USER(s));
P
pbrook 已提交
6321 6322 6323 6324 6325 6326 6327
                    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 已提交
6328 6329
                    gen_add_datah_offset(s, insn, address_offset, addr);
                    store_reg(s, rn, addr);
P
pbrook 已提交
6330 6331
                } else if (insn & (1 << 21)) {
                    if (address_offset)
P
pbrook 已提交
6332 6333 6334 6335
                        tcg_gen_addi_i32(addr, addr, address_offset);
                    store_reg(s, rn, addr);
                } else {
                    dead_tmp(addr);
P
pbrook 已提交
6336 6337 6338
                }
                if (load) {
                    /* Complete the load.  */
P
pbrook 已提交
6339
                    store_reg(s, rd, tmp);
P
pbrook 已提交
6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352
                }
            }
            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 已提交
6353
                rd = (insn >> 12) & 0xf;
P
pbrook 已提交
6354 6355 6356 6357
                rs = (insn >> 8) & 0xf;
                switch ((insn >> 23) & 3) {
                case 0: /* Parallel add/subtract.  */
                    op1 = (insn >> 20) & 7;
P
pbrook 已提交
6358 6359
                    tmp = load_reg(s, rn);
                    tmp2 = load_reg(s, rm);
P
pbrook 已提交
6360 6361 6362
                    sh = (insn >> 5) & 7;
                    if ((op1 & 3) == 0 || sh == 5 || sh == 6)
                        goto illegal_op;
P
pbrook 已提交
6363 6364 6365
                    gen_arm_parallel_addsub(op1, sh, tmp, tmp2);
                    dead_tmp(tmp2);
                    store_reg(s, rd, tmp);
P
pbrook 已提交
6366 6367 6368
                    break;
                case 1:
                    if ((insn & 0x00700020) == 0) {
B
balrog 已提交
6369
                        /* Halfword pack.  */
P
pbrook 已提交
6370 6371
                        tmp = load_reg(s, rn);
                        tmp2 = load_reg(s, rm);
P
pbrook 已提交
6372
                        shift = (insn >> 7) & 0x1f;
P
pbrook 已提交
6373 6374
                        if (insn & (1 << 6)) {
                            /* pkhtb */
6375 6376 6377
                            if (shift == 0)
                                shift = 31;
                            tcg_gen_sari_i32(tmp2, tmp2, shift);
P
pbrook 已提交
6378
                            tcg_gen_andi_i32(tmp, tmp, 0xffff0000);
P
pbrook 已提交
6379
                            tcg_gen_ext16u_i32(tmp2, tmp2);
P
pbrook 已提交
6380 6381
                        } else {
                            /* pkhbt */
6382 6383
                            if (shift)
                                tcg_gen_shli_i32(tmp2, tmp2, shift);
P
pbrook 已提交
6384
                            tcg_gen_ext16u_i32(tmp, tmp);
P
pbrook 已提交
6385 6386 6387
                            tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000);
                        }
                        tcg_gen_or_i32(tmp, tmp, tmp2);
6388
                        dead_tmp(tmp2);
P
pbrook 已提交
6389
                        store_reg(s, rd, tmp);
P
pbrook 已提交
6390 6391
                    } else if ((insn & 0x00200020) == 0x00200000) {
                        /* [us]sat */
P
pbrook 已提交
6392
                        tmp = load_reg(s, rm);
P
pbrook 已提交
6393 6394 6395 6396
                        shift = (insn >> 7) & 0x1f;
                        if (insn & (1 << 6)) {
                            if (shift == 0)
                                shift = 31;
P
pbrook 已提交
6397
                            tcg_gen_sari_i32(tmp, tmp, shift);
P
pbrook 已提交
6398
                        } else {
P
pbrook 已提交
6399
                            tcg_gen_shli_i32(tmp, tmp, shift);
P
pbrook 已提交
6400 6401 6402 6403
                        }
                        sh = (insn >> 16) & 0x1f;
                        if (sh != 0) {
                            if (insn & (1 << 22))
P
pbrook 已提交
6404
                                gen_helper_usat(tmp, tmp, tcg_const_i32(sh));
P
pbrook 已提交
6405
                            else
P
pbrook 已提交
6406
                                gen_helper_ssat(tmp, tmp, tcg_const_i32(sh));
P
pbrook 已提交
6407
                        }
P
pbrook 已提交
6408
                        store_reg(s, rd, tmp);
P
pbrook 已提交
6409 6410
                    } else if ((insn & 0x00300fe0) == 0x00200f20) {
                        /* [us]sat16 */
P
pbrook 已提交
6411
                        tmp = load_reg(s, rm);
P
pbrook 已提交
6412 6413 6414
                        sh = (insn >> 16) & 0x1f;
                        if (sh != 0) {
                            if (insn & (1 << 22))
P
pbrook 已提交
6415
                                gen_helper_usat16(tmp, tmp, tcg_const_i32(sh));
P
pbrook 已提交
6416
                            else
P
pbrook 已提交
6417
                                gen_helper_ssat16(tmp, tmp, tcg_const_i32(sh));
P
pbrook 已提交
6418
                        }
P
pbrook 已提交
6419
                        store_reg(s, rd, tmp);
P
pbrook 已提交
6420 6421
                    } else if ((insn & 0x00700fe0) == 0x00000fa0) {
                        /* Select bytes.  */
P
pbrook 已提交
6422 6423 6424 6425 6426 6427 6428 6429
                        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 已提交
6430
                    } else if ((insn & 0x000003e0) == 0x00000060) {
P
pbrook 已提交
6431
                        tmp = load_reg(s, rm);
P
pbrook 已提交
6432 6433 6434 6435
                        shift = (insn >> 10) & 3;
                        /* ??? In many cases it's not neccessary to do a
                           rotate, a shift is sufficient.  */
                        if (shift != 0)
P
pbrook 已提交
6436
                            tcg_gen_rori_i32(tmp, tmp, shift * 8);
P
pbrook 已提交
6437 6438
                        op1 = (insn >> 20) & 7;
                        switch (op1) {
P
pbrook 已提交
6439 6440 6441 6442 6443 6444
                        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 已提交
6445 6446 6447
                        default: goto illegal_op;
                        }
                        if (rn != 15) {
P
pbrook 已提交
6448
                            tmp2 = load_reg(s, rn);
P
pbrook 已提交
6449
                            if ((op1 & 3) == 0) {
P
pbrook 已提交
6450
                                gen_add16(tmp, tmp2);
P
pbrook 已提交
6451
                            } else {
P
pbrook 已提交
6452 6453
                                tcg_gen_add_i32(tmp, tmp, tmp2);
                                dead_tmp(tmp2);
P
pbrook 已提交
6454 6455
                            }
                        }
B
balrog 已提交
6456
                        store_reg(s, rd, tmp);
P
pbrook 已提交
6457 6458
                    } else if ((insn & 0x003f0f60) == 0x003f0f20) {
                        /* rev */
P
pbrook 已提交
6459
                        tmp = load_reg(s, rm);
P
pbrook 已提交
6460 6461
                        if (insn & (1 << 22)) {
                            if (insn & (1 << 7)) {
P
pbrook 已提交
6462
                                gen_revsh(tmp);
P
pbrook 已提交
6463 6464
                            } else {
                                ARCH(6T2);
P
pbrook 已提交
6465
                                gen_helper_rbit(tmp, tmp);
P
pbrook 已提交
6466 6467 6468
                            }
                        } else {
                            if (insn & (1 << 7))
P
pbrook 已提交
6469
                                gen_rev16(tmp);
P
pbrook 已提交
6470
                            else
P
pbrook 已提交
6471
                                tcg_gen_bswap_i32(tmp, tmp);
P
pbrook 已提交
6472
                        }
P
pbrook 已提交
6473
                        store_reg(s, rd, tmp);
P
pbrook 已提交
6474 6475 6476 6477 6478
                    } else {
                        goto illegal_op;
                    }
                    break;
                case 2: /* Multiplies (Type 3).  */
P
pbrook 已提交
6479 6480
                    tmp = load_reg(s, rm);
                    tmp2 = load_reg(s, rs);
P
pbrook 已提交
6481 6482
                    if (insn & (1 << 20)) {
                        /* Signed multiply most significant [accumulate].  */
P
pbrook 已提交
6483
                        tmp2 = gen_muls_i64_i32(tmp, tmp2);
P
pbrook 已提交
6484
                        if (insn & (1 << 5))
P
pbrook 已提交
6485 6486 6487 6488
                            tcg_gen_addi_i64(tmp2, tmp2, 0x80000000u);
                        tcg_gen_shri_i64(tmp2, tmp2, 32);
                        tmp = new_tmp();
                        tcg_gen_trunc_i64_i32(tmp, tmp2);
P
pbrook 已提交
6489
                        if (rn != 15) {
P
pbrook 已提交
6490
                            tmp2 = load_reg(s, rn);
P
pbrook 已提交
6491
                            if (insn & (1 << 6)) {
P
pbrook 已提交
6492
                                tcg_gen_sub_i32(tmp, tmp, tmp2);
P
pbrook 已提交
6493
                            } else {
P
pbrook 已提交
6494
                                tcg_gen_add_i32(tmp, tmp, tmp2);
P
pbrook 已提交
6495
                            }
P
pbrook 已提交
6496
                            dead_tmp(tmp2);
P
pbrook 已提交
6497
                        }
P
pbrook 已提交
6498
                        store_reg(s, rd, tmp);
P
pbrook 已提交
6499 6500
                    } else {
                        if (insn & (1 << 5))
P
pbrook 已提交
6501 6502 6503 6504 6505 6506 6507 6508 6509
                            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 已提交
6510
                        if (insn & (1 << 22)) {
P
pbrook 已提交
6511 6512 6513 6514
                            /* smlald, smlsld */
                            tmp2 = tcg_temp_new(TCG_TYPE_I64);
                            tcg_gen_ext_i32_i64(tmp2, tmp);
                            dead_tmp(tmp);
6515 6516
                            gen_addq(s, tmp2, rd, rn);
                            gen_storeq_reg(s, rd, rn, tmp2);
P
pbrook 已提交
6517
                        } else {
P
pbrook 已提交
6518
                            /* smuad, smusd, smlad, smlsd */
6519
                            if (rd != 15)
P
pbrook 已提交
6520
                              {
6521
                                tmp2 = load_reg(s, rd);
P
pbrook 已提交
6522 6523
                                gen_helper_add_setq(tmp, tmp, tmp2);
                                dead_tmp(tmp2);
P
pbrook 已提交
6524
                              }
6525
                            store_reg(s, rn, tmp);
P
pbrook 已提交
6526 6527 6528 6529 6530 6531 6532
                        }
                    }
                    break;
                case 3:
                    op1 = ((insn >> 17) & 0x38) | ((insn >> 5) & 7);
                    switch (op1) {
                    case 0: /* Unsigned sum of absolute differences.  */
P
pbrook 已提交
6533 6534 6535 6536 6537
                        ARCH(6);
                        tmp = load_reg(s, rm);
                        tmp2 = load_reg(s, rs);
                        gen_helper_usad8(tmp, tmp, tmp2);
                        dead_tmp(tmp2);
P
pbrook 已提交
6538
                        if (rn != 15) {
P
pbrook 已提交
6539 6540 6541
                            tmp2 = load_reg(s, rn);
                            tcg_gen_add_i32(tmp, tmp, tmp2);
                            dead_tmp(tmp2);
P
pbrook 已提交
6542
                        }
P
pbrook 已提交
6543
                        store_reg(s, rd, tmp);
P
pbrook 已提交
6544 6545 6546 6547 6548 6549 6550 6551
                        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 已提交
6552 6553
                            tmp = new_tmp();
                            tcg_gen_movi_i32(tmp, 0);
P
pbrook 已提交
6554
                        } else {
P
pbrook 已提交
6555
                            tmp = load_reg(s, rm);
P
pbrook 已提交
6556 6557
                        }
                        if (i != 32) {
P
pbrook 已提交
6558
                            tmp2 = load_reg(s, rd);
P
pbrook 已提交
6559
                            gen_bfi(tmp, tmp2, tmp, shift, (1u << i) - 1);
P
pbrook 已提交
6560
                            dead_tmp(tmp2);
P
pbrook 已提交
6561
                        }
P
pbrook 已提交
6562
                        store_reg(s, rd, tmp);
P
pbrook 已提交
6563 6564 6565
                        break;
                    case 0x12: case 0x16: case 0x1a: case 0x1e: /* sbfx */
                    case 0x32: case 0x36: case 0x3a: case 0x3e: /* ubfx */
P
pbrook 已提交
6566
                        tmp = load_reg(s, rm);
P
pbrook 已提交
6567 6568 6569 6570 6571 6572
                        shift = (insn >> 7) & 0x1f;
                        i = ((insn >> 16) & 0x1f) + 1;
                        if (shift + i > 32)
                            goto illegal_op;
                        if (i < 32) {
                            if (op1 & 0x20) {
P
pbrook 已提交
6573
                                gen_ubfx(tmp, shift, (1u << i) - 1);
P
pbrook 已提交
6574
                            } else {
P
pbrook 已提交
6575
                                gen_sbfx(tmp, shift, i);
P
pbrook 已提交
6576 6577
                            }
                        }
P
pbrook 已提交
6578
                        store_reg(s, rd, tmp);
P
pbrook 已提交
6579 6580 6581 6582 6583 6584 6585 6586 6587 6588 6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599
                        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 已提交
6600
            tmp2 = load_reg(s, rn);
P
pbrook 已提交
6601 6602
            i = (IS_USER(s) || (insn & 0x01200000) == 0x00200000);
            if (insn & (1 << 24))
P
pbrook 已提交
6603
                gen_add_data_offset(s, insn, tmp2);
P
pbrook 已提交
6604 6605 6606 6607
            if (insn & (1 << 20)) {
                /* load */
                s->is_mem = 1;
                if (insn & (1 << 22)) {
P
pbrook 已提交
6608
                    tmp = gen_ld8u(tmp2, i);
P
pbrook 已提交
6609
                } else {
P
pbrook 已提交
6610
                    tmp = gen_ld32(tmp2, i);
P
pbrook 已提交
6611 6612 6613
                }
            } else {
                /* store */
P
pbrook 已提交
6614
                tmp = load_reg(s, rd);
P
pbrook 已提交
6615
                if (insn & (1 << 22))
P
pbrook 已提交
6616
                    gen_st8(tmp, tmp2, i);
P
pbrook 已提交
6617
                else
P
pbrook 已提交
6618
                    gen_st32(tmp, tmp2, i);
P
pbrook 已提交
6619 6620
            }
            if (!(insn & (1 << 24))) {
P
pbrook 已提交
6621 6622 6623 6624 6625 6626
                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 已提交
6627 6628 6629 6630
            }
            if (insn & (1 << 20)) {
                /* Complete the load.  */
                if (rd == 15)
P
pbrook 已提交
6631
                    gen_bx(s, tmp);
P
pbrook 已提交
6632
                else
P
pbrook 已提交
6633
                    store_reg(s, rd, tmp);
P
pbrook 已提交
6634 6635 6636 6637 6638 6639
            }
            break;
        case 0x08:
        case 0x09:
            {
                int j, n, user, loaded_base;
P
pbrook 已提交
6640
                TCGv loaded_var;
P
pbrook 已提交
6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651
                /* 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 已提交
6652
                addr = load_reg(s, rn);
P
pbrook 已提交
6653 6654 6655

                /* compute total size */
                loaded_base = 0;
P
pbrook 已提交
6656
                TCGV_UNUSED(loaded_var);
P
pbrook 已提交
6657 6658 6659 6660 6661 6662 6663 6664 6665
                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 已提交
6666
                        tcg_gen_addi_i32(addr, addr, 4);
P
pbrook 已提交
6667 6668 6669 6670 6671 6672
                    } else {
                        /* post increment */
                    }
                } else {
                    if (insn & (1 << 24)) {
                        /* pre decrement */
P
pbrook 已提交
6673
                        tcg_gen_addi_i32(addr, addr, -(n * 4));
P
pbrook 已提交
6674 6675 6676
                    } else {
                        /* post decrement */
                        if (n != 1)
P
pbrook 已提交
6677
                        tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
P
pbrook 已提交
6678 6679 6680 6681 6682 6683 6684
                    }
                }
                j = 0;
                for(i=0;i<16;i++) {
                    if (insn & (1 << i)) {
                        if (insn & (1 << 20)) {
                            /* load */
P
pbrook 已提交
6685
                            tmp = gen_ld32(addr, IS_USER(s));
P
pbrook 已提交
6686
                            if (i == 15) {
P
pbrook 已提交
6687
                                gen_bx(s, tmp);
P
pbrook 已提交
6688
                            } else if (user) {
P
pbrook 已提交
6689 6690
                                gen_helper_set_user_reg(tcg_const_i32(i), tmp);
                                dead_tmp(tmp);
P
pbrook 已提交
6691
                            } else if (i == rn) {
P
pbrook 已提交
6692
                                loaded_var = tmp;
P
pbrook 已提交
6693 6694
                                loaded_base = 1;
                            } else {
P
pbrook 已提交
6695
                                store_reg(s, i, tmp);
P
pbrook 已提交
6696 6697 6698 6699 6700 6701
                            }
                        } else {
                            /* store */
                            if (i == 15) {
                                /* special case: r15 = PC + 8 */
                                val = (long)s->pc + 4;
P
pbrook 已提交
6702 6703
                                tmp = new_tmp();
                                tcg_gen_movi_i32(tmp, val);
P
pbrook 已提交
6704
                            } else if (user) {
P
pbrook 已提交
6705 6706
                                tmp = new_tmp();
                                gen_helper_get_user_reg(tmp, tcg_const_i32(i));
P
pbrook 已提交
6707
                            } else {
P
pbrook 已提交
6708
                                tmp = load_reg(s, i);
P
pbrook 已提交
6709
                            }
P
pbrook 已提交
6710
                            gen_st32(tmp, addr, IS_USER(s));
P
pbrook 已提交
6711 6712 6713 6714
                        }
                        j++;
                        /* no need to add after the last transfer */
                        if (j != n)
P
pbrook 已提交
6715
                            tcg_gen_addi_i32(addr, addr, 4);
P
pbrook 已提交
6716 6717 6718 6719 6720 6721 6722 6723 6724
                    }
                }
                if (insn & (1 << 21)) {
                    /* write back */
                    if (insn & (1 << 23)) {
                        if (insn & (1 << 24)) {
                            /* pre increment */
                        } else {
                            /* post increment */
P
pbrook 已提交
6725
                            tcg_gen_addi_i32(addr, addr, 4);
P
pbrook 已提交
6726 6727 6728 6729 6730
                        }
                    } else {
                        if (insn & (1 << 24)) {
                            /* pre decrement */
                            if (n != 1)
P
pbrook 已提交
6731
                                tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
P
pbrook 已提交
6732 6733
                        } else {
                            /* post decrement */
P
pbrook 已提交
6734
                            tcg_gen_addi_i32(addr, addr, -(n * 4));
P
pbrook 已提交
6735 6736
                        }
                    }
P
pbrook 已提交
6737 6738 6739
                    store_reg(s, rn, addr);
                } else {
                    dead_tmp(addr);
P
pbrook 已提交
6740 6741
                }
                if (loaded_base) {
P
pbrook 已提交
6742
                    store_reg(s, rn, loaded_var);
P
pbrook 已提交
6743 6744 6745
                }
                if ((insn & (1 << 22)) && !user) {
                    /* Restore CPSR from SPSR.  */
P
pbrook 已提交
6746 6747 6748
                    tmp = load_cpu_field(spsr);
                    gen_set_cpsr(tmp, 0xffffffff);
                    dead_tmp(tmp);
P
pbrook 已提交
6749 6750 6751 6752 6753 6754 6755 6756 6757 6758 6759 6760
                    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 已提交
6761 6762 6763
                    tmp = new_tmp();
                    tcg_gen_movi_i32(tmp, val);
                    store_reg(s, 14, tmp);
P
pbrook 已提交
6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778
                }
                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 已提交
6779
            gen_set_pc_im(s->pc);
P
pbrook 已提交
6780 6781 6782 6783 6784
            s->is_jmp = DISAS_SWI;
            break;
        default:
        illegal_op:
            gen_set_condexec(s);
P
pbrook 已提交
6785
            gen_set_pc_im(s->pc - 4);
P
pbrook 已提交
6786
            gen_exception(EXCP_UDEF);
P
pbrook 已提交
6787 6788 6789 6790 6791 6792 6793 6794 6795 6796 6797 6798 6799 6800 6801 6802 6803 6804 6805 6806 6807 6808 6809 6810 6811 6812 6813 6814 6815 6816 6817 6818 6819 6820 6821 6822 6823 6824 6825 6826 6827 6828 6829 6830 6831 6832 6833 6834 6835 6836 6837 6838 6839 6840 6841 6842 6843
            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 已提交
6844
            gen_adc_T0_T1();
P
pbrook 已提交
6845 6846 6847 6848 6849
        break;
    case 11: /* sbc */
        if (conds)
            gen_op_sbcl_T0_T1_cc();
        else
P
pbrook 已提交
6850
            gen_sbc_T0_T1();
P
pbrook 已提交
6851 6852 6853 6854 6855 6856 6857 6858 6859 6860 6861 6862 6863 6864 6865 6866 6867 6868 6869
        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 已提交
6870
            gen_set_CF_bit31(cpu_T[1]);
P
pbrook 已提交
6871 6872 6873 6874 6875 6876 6877 6878
    }
    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 已提交
6879
    uint32_t insn, imm, shift, offset;
P
pbrook 已提交
6880
    uint32_t rd, rn, rm, rs;
P
pbrook 已提交
6881
    TCGv tmp;
P
pbrook 已提交
6882 6883
    TCGv tmp2;
    TCGv tmp3;
P
pbrook 已提交
6884
    TCGv addr;
P
pbrook 已提交
6885 6886 6887 6888 6889 6890 6891
    int op;
    int shiftop;
    int conds;
    int logic_cc;

    if (!(arm_feature(env, ARM_FEATURE_THUMB2)
          || arm_feature (env, ARM_FEATURE_M))) {
6892
        /* Thumb-1 cores may need to treat bl and blx as a pair of
P
pbrook 已提交
6893 6894 6895 6896 6897
           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 已提交
6898 6899 6900
            tmp = load_reg(s, 14);
            tcg_gen_addi_i32(tmp, tmp, offset);
            tcg_gen_andi_i32(tmp, tmp, 0xfffffffc);
P
pbrook 已提交
6901

P
pbrook 已提交
6902
            tmp2 = new_tmp();
P
pbrook 已提交
6903
            tcg_gen_movi_i32(tmp2, s->pc | 1);
P
pbrook 已提交
6904 6905
            store_reg(s, 14, tmp2);
            gen_bx(s, tmp);
P
pbrook 已提交
6906 6907 6908 6909 6910
            return 0;
        }
        if (insn & (1 << 11)) {
            /* Second half of bl.  */
            offset = ((insn & 0x7ff) << 1) | 1;
P
pbrook 已提交
6911
            tmp = load_reg(s, 14);
B
balrog 已提交
6912
            tcg_gen_addi_i32(tmp, tmp, offset);
P
pbrook 已提交
6913

P
pbrook 已提交
6914
            tmp2 = new_tmp();
P
pbrook 已提交
6915
            tcg_gen_movi_i32(tmp2, s->pc | 1);
P
pbrook 已提交
6916 6917
            store_reg(s, 14, tmp2);
            gen_bx(s, tmp);
P
pbrook 已提交
6918 6919 6920 6921 6922 6923 6924
            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 已提交
6925
            gen_op_movl_T0_im(s->pc + 2 + offset);
P
pbrook 已提交
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
            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 已提交
6954 6955
                    addr = new_tmp();
                    tcg_gen_movi_i32(addr, s->pc & ~3);
P
pbrook 已提交
6956
                } else {
P
pbrook 已提交
6957
                    addr = load_reg(s, rn);
P
pbrook 已提交
6958 6959 6960 6961 6962
                }
                offset = (insn & 0xff) * 4;
                if ((insn & (1 << 23)) == 0)
                    offset = -offset;
                if (insn & (1 << 24)) {
P
pbrook 已提交
6963
                    tcg_gen_addi_i32(addr, addr, offset);
P
pbrook 已提交
6964 6965 6966 6967
                    offset = 0;
                }
                if (insn & (1 << 20)) {
                    /* ldrd */
P
pbrook 已提交
6968 6969 6970 6971 6972
                    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 已提交
6973 6974
                } else {
                    /* strd */
P
pbrook 已提交
6975 6976 6977 6978 6979
                    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 已提交
6980 6981 6982 6983 6984
                }
                if (insn & (1 << 21)) {
                    /* Base writeback.  */
                    if (rn == 15)
                        goto illegal_op;
P
pbrook 已提交
6985 6986 6987 6988
                    tcg_gen_addi_i32(addr, addr, offset - 4);
                    store_reg(s, rn, addr);
                } else {
                    dead_tmp(addr);
P
pbrook 已提交
6989 6990 6991
                }
            } else if ((insn & (1 << 23)) == 0) {
                /* Load/store exclusive word.  */
B
bellard 已提交
6992
                gen_movl_T1_reg(s, rn);
B
balrog 已提交
6993
                addr = cpu_T[1];
B
bellard 已提交
6994
                if (insn & (1 << 20)) {
P
pbrook 已提交
6995 6996 6997
                    gen_helper_mark_exclusive(cpu_env, cpu_T[1]);
                    tmp = gen_ld32(addr, IS_USER(s));
                    store_reg(s, rd, tmp);
P
pbrook 已提交
6998
                } else {
P
pbrook 已提交
6999 7000
                    int label = gen_new_label();
                    gen_helper_test_exclusive(cpu_T[0], cpu_env, addr);
P
pbrook 已提交
7001 7002
                    tcg_gen_brcondi_i32(TCG_COND_NE, cpu_T[0],
                                        0, label);
P
pbrook 已提交
7003 7004 7005 7006
                    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 已提交
7007 7008 7009 7010
                }
            } else if ((insn & (1 << 6)) == 0) {
                /* Table Branch.  */
                if (rn == 15) {
P
pbrook 已提交
7011 7012
                    addr = new_tmp();
                    tcg_gen_movi_i32(addr, s->pc);
P
pbrook 已提交
7013
                } else {
P
pbrook 已提交
7014
                    addr = load_reg(s, rn);
P
pbrook 已提交
7015
                }
P
pbrook 已提交
7016
                tmp = load_reg(s, rm);
P
pbrook 已提交
7017
                tcg_gen_add_i32(addr, addr, tmp);
P
pbrook 已提交
7018 7019
                if (insn & (1 << 4)) {
                    /* tbh */
P
pbrook 已提交
7020
                    tcg_gen_add_i32(addr, addr, tmp);
P
pbrook 已提交
7021
                    dead_tmp(tmp);
P
pbrook 已提交
7022
                    tmp = gen_ld16u(addr, IS_USER(s));
P
pbrook 已提交
7023
                } else { /* tbb */
P
pbrook 已提交
7024
                    dead_tmp(tmp);
P
pbrook 已提交
7025
                    tmp = gen_ld8u(addr, IS_USER(s));
P
pbrook 已提交
7026
                }
P
pbrook 已提交
7027 7028 7029 7030
                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 已提交
7031 7032
            } else {
                /* Load/store exclusive byte/halfword/doubleword.  */
P
pbrook 已提交
7033 7034 7035
                /* ??? These are not really atomic.  However we know
                   we never have multiple CPUs running in parallel,
                   so it is good enough.  */
P
pbrook 已提交
7036
                op = (insn >> 4) & 0x3;
P
pbrook 已提交
7037 7038
                /* Must use a global reg for the address because we have
                   a conditional branch in the store instruction.  */
P
pbrook 已提交
7039
                gen_movl_T1_reg(s, rn);
P
pbrook 已提交
7040
                addr = cpu_T[1];
P
pbrook 已提交
7041
                if (insn & (1 << 20)) {
P
pbrook 已提交
7042
                    gen_helper_mark_exclusive(cpu_env, addr);
P
pbrook 已提交
7043 7044
                    switch (op) {
                    case 0:
P
pbrook 已提交
7045
                        tmp = gen_ld8u(addr, IS_USER(s));
P
pbrook 已提交
7046
                        break;
B
bellard 已提交
7047
                    case 1:
P
pbrook 已提交
7048
                        tmp = gen_ld16u(addr, IS_USER(s));
B
bellard 已提交
7049
                        break;
P
pbrook 已提交
7050
                    case 3:
P
pbrook 已提交
7051 7052 7053 7054
                        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 已提交
7055 7056
                        break;
                    default:
P
pbrook 已提交
7057 7058
                        goto illegal_op;
                    }
P
pbrook 已提交
7059
                    store_reg(s, rs, tmp);
P
pbrook 已提交
7060
                } else {
P
pbrook 已提交
7061 7062 7063
                    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 已提交
7064
                    tcg_gen_brcondi_i32(TCG_COND_NE, cpu_T[0], 0, label);
P
pbrook 已提交
7065
                    tmp = load_reg(s, rs);
P
pbrook 已提交
7066 7067
                    switch (op) {
                    case 0:
P
pbrook 已提交
7068
                        gen_st8(tmp, addr, IS_USER(s));
P
pbrook 已提交
7069 7070
                        break;
                    case 1:
P
pbrook 已提交
7071
                        gen_st16(tmp, addr, IS_USER(s));
P
pbrook 已提交
7072
                        break;
B
bellard 已提交
7073
                    case 3:
P
pbrook 已提交
7074 7075 7076 7077
                        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 已提交
7078
                        break;
P
pbrook 已提交
7079 7080
                    default:
                        goto illegal_op;
B
bellard 已提交
7081
                    }
P
pbrook 已提交
7082
                    gen_set_label(label);
P
pbrook 已提交
7083 7084 7085 7086 7087 7088 7089
                    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 已提交
7090
                if (IS_USER(s))
P
pbrook 已提交
7091 7092 7093
                    goto illegal_op;
                if (insn & (1 << 20)) {
                    /* rfe */
P
pbrook 已提交
7094 7095 7096 7097 7098 7099 7100
                    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 已提交
7101 7102
                    if (insn & (1 << 21)) {
                        /* Base writeback.  */
P
pbrook 已提交
7103 7104 7105 7106 7107 7108 7109 7110
                        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 已提交
7111
                    }
P
pbrook 已提交
7112
                    gen_rfe(s, tmp, tmp2);
P
pbrook 已提交
7113 7114 7115 7116
                } else {
                    /* srs */
                    op = (insn & 0x1f);
                    if (op == (env->uncached_cpsr & CPSR_M)) {
P
pbrook 已提交
7117
                        addr = load_reg(s, 13);
P
pbrook 已提交
7118
                    } else {
P
pbrook 已提交
7119 7120
                        addr = new_tmp();
                        gen_helper_get_r13_banked(addr, cpu_env, tcg_const_i32(op));
P
pbrook 已提交
7121 7122
                    }
                    if ((insn & (1 << 24)) == 0) {
P
pbrook 已提交
7123
                        tcg_gen_addi_i32(addr, addr, -8);
P
pbrook 已提交
7124
                    }
P
pbrook 已提交
7125 7126 7127 7128 7129 7130
                    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 已提交
7131 7132
                    if (insn & (1 << 21)) {
                        if ((insn & (1 << 24)) == 0) {
P
pbrook 已提交
7133
                            tcg_gen_addi_i32(addr, addr, -4);
P
pbrook 已提交
7134
                        } else {
P
pbrook 已提交
7135
                            tcg_gen_addi_i32(addr, addr, 4);
P
pbrook 已提交
7136 7137
                        }
                        if (op == (env->uncached_cpsr & CPSR_M)) {
P
pbrook 已提交
7138
                            store_reg(s, 13, addr);
P
pbrook 已提交
7139
                        } else {
P
pbrook 已提交
7140 7141
                            gen_helper_set_r13_banked(cpu_env,
                                tcg_const_i32(op), addr);
P
pbrook 已提交
7142
                        }
P
pbrook 已提交
7143 7144
                    } else {
                        dead_tmp(addr);
P
pbrook 已提交
7145 7146 7147 7148 7149
                    }
                }
            } else {
                int i;
                /* Load/store multiple.  */
P
pbrook 已提交
7150
                addr = load_reg(s, rn);
P
pbrook 已提交
7151 7152 7153 7154 7155 7156
                offset = 0;
                for (i = 0; i < 16; i++) {
                    if (insn & (1 << i))
                        offset += 4;
                }
                if (insn & (1 << 24)) {
P
pbrook 已提交
7157
                    tcg_gen_addi_i32(addr, addr, -offset);
P
pbrook 已提交
7158 7159 7160 7161 7162 7163 7164
                }

                for (i = 0; i < 16; i++) {
                    if ((insn & (1 << i)) == 0)
                        continue;
                    if (insn & (1 << 20)) {
                        /* Load.  */
P
pbrook 已提交
7165
                        tmp = gen_ld32(addr, IS_USER(s));
P
pbrook 已提交
7166
                        if (i == 15) {
P
pbrook 已提交
7167
                            gen_bx(s, tmp);
P
pbrook 已提交
7168
                        } else {
P
pbrook 已提交
7169
                            store_reg(s, i, tmp);
P
pbrook 已提交
7170 7171 7172
                        }
                    } else {
                        /* Store.  */
P
pbrook 已提交
7173 7174
                        tmp = load_reg(s, i);
                        gen_st32(tmp, addr, IS_USER(s));
P
pbrook 已提交
7175
                    }
P
pbrook 已提交
7176
                    tcg_gen_addi_i32(addr, addr, 4);
P
pbrook 已提交
7177 7178 7179 7180
                }
                if (insn & (1 << 21)) {
                    /* Base register writeback.  */
                    if (insn & (1 << 24)) {
P
pbrook 已提交
7181
                        tcg_gen_addi_i32(addr, addr, -offset);
P
pbrook 已提交
7182 7183 7184 7185
                    }
                    /* Fault if writeback register is in register list.  */
                    if (insn & (1 << rn))
                        goto illegal_op;
P
pbrook 已提交
7186 7187 7188
                    store_reg(s, rn, addr);
                } else {
                    dead_tmp(addr);
P
pbrook 已提交
7189 7190 7191 7192 7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203
                }
            }
        }
        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 已提交
7204
        gen_arm_shift_im(cpu_T[1], shiftop, shift, logic_cc);
P
pbrook 已提交
7205 7206 7207 7208 7209 7210 7211 7212 7213 7214 7215
        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 已提交
7216 7217
            tmp = load_reg(s, rn);
            tmp2 = load_reg(s, rm);
P
pbrook 已提交
7218 7219 7220
            if ((insn & 0x70) != 0)
                goto illegal_op;
            op = (insn >> 21) & 3;
P
pbrook 已提交
7221 7222 7223 7224 7225
            logic_cc = (insn & (1 << 20)) != 0;
            gen_arm_shift_reg(tmp, op, tmp2, logic_cc);
            if (logic_cc)
                gen_logic_CC(tmp);
            store_reg(s, rd, tmp);
P
pbrook 已提交
7226 7227
            break;
        case 1: /* Sign/zero extend.  */
P
pbrook 已提交
7228
            tmp = load_reg(s, rm);
P
pbrook 已提交
7229 7230 7231 7232
            shift = (insn >> 4) & 3;
            /* ??? In many cases it's not neccessary to do a
               rotate, a shift is sufficient.  */
            if (shift != 0)
P
pbrook 已提交
7233
                tcg_gen_rori_i32(tmp, tmp, shift * 8);
P
pbrook 已提交
7234 7235
            op = (insn >> 20) & 7;
            switch (op) {
P
pbrook 已提交
7236 7237 7238 7239 7240 7241
            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 已提交
7242 7243 7244
            default: goto illegal_op;
            }
            if (rn != 15) {
P
pbrook 已提交
7245
                tmp2 = load_reg(s, rn);
P
pbrook 已提交
7246
                if ((op >> 1) == 1) {
P
pbrook 已提交
7247
                    gen_add16(tmp, tmp2);
P
pbrook 已提交
7248
                } else {
P
pbrook 已提交
7249 7250
                    tcg_gen_add_i32(tmp, tmp, tmp2);
                    dead_tmp(tmp2);
P
pbrook 已提交
7251 7252
                }
            }
P
pbrook 已提交
7253
            store_reg(s, rd, tmp);
P
pbrook 已提交
7254 7255 7256 7257 7258 7259
            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 已提交
7260 7261 7262 7263 7264
            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 已提交
7265 7266 7267 7268 7269
            break;
        case 3: /* Other data processing.  */
            op = ((insn >> 17) & 0x38) | ((insn >> 4) & 7);
            if (op < 4) {
                /* Saturating add/subtract.  */
P
pbrook 已提交
7270 7271
                tmp = load_reg(s, rn);
                tmp2 = load_reg(s, rm);
P
pbrook 已提交
7272
                if (op & 2)
P
pbrook 已提交
7273
                    gen_helper_double_saturate(tmp, tmp);
P
pbrook 已提交
7274
                if (op & 1)
P
pbrook 已提交
7275
                    gen_helper_sub_saturate(tmp, tmp2, tmp);
P
pbrook 已提交
7276
                else
P
pbrook 已提交
7277 7278
                    gen_helper_add_saturate(tmp, tmp, tmp2);
                dead_tmp(tmp2);
P
pbrook 已提交
7279
            } else {
P
pbrook 已提交
7280
                tmp = load_reg(s, rn);
P
pbrook 已提交
7281 7282
                switch (op) {
                case 0x0a: /* rbit */
P
pbrook 已提交
7283
                    gen_helper_rbit(tmp, tmp);
P
pbrook 已提交
7284 7285
                    break;
                case 0x08: /* rev */
P
pbrook 已提交
7286
                    tcg_gen_bswap_i32(tmp, tmp);
P
pbrook 已提交
7287 7288
                    break;
                case 0x09: /* rev16 */
P
pbrook 已提交
7289
                    gen_rev16(tmp);
P
pbrook 已提交
7290 7291
                    break;
                case 0x0b: /* revsh */
P
pbrook 已提交
7292
                    gen_revsh(tmp);
P
pbrook 已提交
7293 7294
                    break;
                case 0x10: /* sel */
P
pbrook 已提交
7295
                    tmp2 = load_reg(s, rm);
P
pbrook 已提交
7296 7297
                    tmp3 = new_tmp();
                    tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUState, GE));
P
pbrook 已提交
7298
                    gen_helper_sel_flags(tmp, tmp3, tmp, tmp2);
P
pbrook 已提交
7299
                    dead_tmp(tmp3);
P
pbrook 已提交
7300
                    dead_tmp(tmp2);
P
pbrook 已提交
7301 7302
                    break;
                case 0x18: /* clz */
P
pbrook 已提交
7303
                    gen_helper_clz(tmp, tmp);
P
pbrook 已提交
7304 7305 7306 7307 7308
                    break;
                default:
                    goto illegal_op;
                }
            }
P
pbrook 已提交
7309
            store_reg(s, rd, tmp);
P
pbrook 已提交
7310 7311 7312
            break;
        case 4: case 5: /* 32-bit multiply.  Sum of absolute differences.  */
            op = (insn >> 4) & 0xf;
P
pbrook 已提交
7313 7314
            tmp = load_reg(s, rn);
            tmp2 = load_reg(s, rm);
P
pbrook 已提交
7315 7316
            switch ((insn >> 20) & 7) {
            case 0: /* 32 x 32 -> 32 */
P
pbrook 已提交
7317 7318
                tcg_gen_mul_i32(tmp, tmp, tmp2);
                dead_tmp(tmp2);
P
pbrook 已提交
7319
                if (rs != 15) {
P
pbrook 已提交
7320
                    tmp2 = load_reg(s, rs);
P
pbrook 已提交
7321
                    if (op)
P
pbrook 已提交
7322
                        tcg_gen_sub_i32(tmp, tmp2, tmp);
P
pbrook 已提交
7323
                    else
P
pbrook 已提交
7324 7325
                        tcg_gen_add_i32(tmp, tmp, tmp2);
                    dead_tmp(tmp2);
P
pbrook 已提交
7326 7327 7328
                }
                break;
            case 1: /* 16 x 16 -> 32 */
P
pbrook 已提交
7329 7330
                gen_mulxy(tmp, tmp2, op & 2, op & 1);
                dead_tmp(tmp2);
P
pbrook 已提交
7331
                if (rs != 15) {
P
pbrook 已提交
7332 7333 7334
                    tmp2 = load_reg(s, rs);
                    gen_helper_add_setq(tmp, tmp, tmp2);
                    dead_tmp(tmp2);
P
pbrook 已提交
7335 7336 7337 7338 7339
                }
                break;
            case 2: /* Dual multiply add.  */
            case 4: /* Dual multiply subtract.  */
                if (op)
P
pbrook 已提交
7340 7341
                    gen_swap_half(tmp2);
                gen_smul_dual(tmp, tmp2);
P
pbrook 已提交
7342 7343
                /* This addition cannot overflow.  */
                if (insn & (1 << 22)) {
P
pbrook 已提交
7344
                    tcg_gen_sub_i32(tmp, tmp, tmp2);
P
pbrook 已提交
7345
                } else {
P
pbrook 已提交
7346
                    tcg_gen_add_i32(tmp, tmp, tmp2);
P
pbrook 已提交
7347
                }
P
pbrook 已提交
7348
                dead_tmp(tmp2);
P
pbrook 已提交
7349 7350
                if (rs != 15)
                  {
P
pbrook 已提交
7351 7352 7353
                    tmp2 = load_reg(s, rs);
                    gen_helper_add_setq(tmp, tmp, tmp2);
                    dead_tmp(tmp2);
P
pbrook 已提交
7354 7355 7356 7357
                  }
                break;
            case 3: /* 32 * 16 -> 32msb */
                if (op)
P
pbrook 已提交
7358
                    tcg_gen_sari_i32(tmp2, tmp2, 16);
P
pbrook 已提交
7359
                else
P
pbrook 已提交
7360
                    gen_sxth(tmp2);
P
pbrook 已提交
7361 7362 7363 7364
                tmp2 = gen_muls_i64_i32(tmp, tmp2);
                tcg_gen_shri_i64(tmp2, tmp2, 16);
                tmp = new_tmp();
                tcg_gen_trunc_i64_i32(tmp, tmp2);
P
pbrook 已提交
7365 7366
                if (rs != 15)
                  {
P
pbrook 已提交
7367 7368 7369
                    tmp2 = load_reg(s, rs);
                    gen_helper_add_setq(tmp, tmp, tmp2);
                    dead_tmp(tmp2);
P
pbrook 已提交
7370 7371 7372
                  }
                break;
            case 5: case 6: /* 32 * 32 -> 32msb */
P
pbrook 已提交
7373 7374 7375 7376 7377 7378 7379 7380
                gen_imull(tmp, tmp2);
                if (insn & (1 << 5)) {
                    gen_roundqd(tmp, tmp2);
                    dead_tmp(tmp2);
                } else {
                    dead_tmp(tmp);
                    tmp = tmp2;
                }
P
pbrook 已提交
7381
                if (rs != 15) {
P
pbrook 已提交
7382
                    tmp2 = load_reg(s, rs);
P
pbrook 已提交
7383
                    if (insn & (1 << 21)) {
P
pbrook 已提交
7384
                        tcg_gen_add_i32(tmp, tmp, tmp2);
B
bellard 已提交
7385
                    } else {
P
pbrook 已提交
7386
                        tcg_gen_sub_i32(tmp, tmp2, tmp);
B
bellard 已提交
7387
                    }
P
pbrook 已提交
7388
                    dead_tmp(tmp2);
B
bellard 已提交
7389
                }
P
pbrook 已提交
7390 7391
                break;
            case 7: /* Unsigned sum of absolute differences.  */
P
pbrook 已提交
7392 7393
                gen_helper_usad8(tmp, tmp, tmp2);
                dead_tmp(tmp2);
P
pbrook 已提交
7394
                if (rs != 15) {
P
pbrook 已提交
7395 7396 7397
                    tmp2 = load_reg(s, rs);
                    tcg_gen_add_i32(tmp, tmp, tmp2);
                    dead_tmp(tmp2);
7398
                }
P
pbrook 已提交
7399
                break;
B
bellard 已提交
7400
            }
P
pbrook 已提交
7401
            store_reg(s, rd, tmp);
B
bellard 已提交
7402
            break;
P
pbrook 已提交
7403 7404
        case 6: case 7: /* 64-bit multiply, Divide.  */
            op = ((insn >> 4) & 0xf) | ((insn >> 16) & 0x70);
P
pbrook 已提交
7405 7406
            tmp = load_reg(s, rn);
            tmp2 = load_reg(s, rm);
P
pbrook 已提交
7407 7408 7409 7410 7411
            if ((op & 0x50) == 0x10) {
                /* sdiv, udiv */
                if (!arm_feature(env, ARM_FEATURE_DIV))
                    goto illegal_op;
                if (op & 0x20)
P
pbrook 已提交
7412
                    gen_helper_udiv(tmp, tmp, tmp2);
B
bellard 已提交
7413
                else
P
pbrook 已提交
7414 7415 7416
                    gen_helper_sdiv(tmp, tmp, tmp2);
                dead_tmp(tmp2);
                store_reg(s, rd, tmp);
P
pbrook 已提交
7417 7418 7419
            } else if ((op & 0xe) == 0xc) {
                /* Dual multiply accumulate long.  */
                if (op & 1)
P
pbrook 已提交
7420 7421
                    gen_swap_half(tmp2);
                gen_smul_dual(tmp, tmp2);
P
pbrook 已提交
7422
                if (op & 0x10) {
P
pbrook 已提交
7423
                    tcg_gen_sub_i32(tmp, tmp, tmp2);
B
bellard 已提交
7424
                } else {
P
pbrook 已提交
7425
                    tcg_gen_add_i32(tmp, tmp, tmp2);
B
bellard 已提交
7426
                }
P
pbrook 已提交
7427 7428 7429 7430
                dead_tmp(tmp2);
                tmp2 = tcg_temp_new(TCG_TYPE_I64);
                gen_addq(s, tmp, rs, rd);
                gen_storeq_reg(s, rs, rd, tmp);
B
bellard 已提交
7431
            } else {
P
pbrook 已提交
7432 7433
                if (op & 0x20) {
                    /* Unsigned 64-bit multiply  */
P
pbrook 已提交
7434
                    tmp = gen_mulu_i64_i32(tmp, tmp2);
B
bellard 已提交
7435
                } else {
P
pbrook 已提交
7436 7437
                    if (op & 8) {
                        /* smlalxy */
P
pbrook 已提交
7438 7439 7440 7441 7442 7443
                        gen_mulxy(tmp, tmp2, op & 2, op & 1);
                        dead_tmp(tmp2);
                        tmp2 = tcg_temp_new(TCG_TYPE_I64);
                        tcg_gen_ext_i32_i64(tmp2, tmp);
                        dead_tmp(tmp);
                        tmp = tmp2;
P
pbrook 已提交
7444 7445
                    } else {
                        /* Signed 64-bit multiply  */
P
pbrook 已提交
7446
                        tmp = gen_muls_i64_i32(tmp, tmp2);
P
pbrook 已提交
7447
                    }
B
bellard 已提交
7448
                }
P
pbrook 已提交
7449 7450
                if (op & 4) {
                    /* umaal */
P
pbrook 已提交
7451 7452
                    gen_addq_lo(s, tmp, rs);
                    gen_addq_lo(s, tmp, rd);
P
pbrook 已提交
7453 7454
                } else if (op & 0x40) {
                    /* 64-bit accumulate.  */
P
pbrook 已提交
7455
                    gen_addq(s, tmp, rs, rd);
P
pbrook 已提交
7456
                }
P
pbrook 已提交
7457
                gen_storeq_reg(s, rs, rd, tmp);
7458
            }
B
bellard 已提交
7459
            break;
P
pbrook 已提交
7460 7461 7462 7463 7464 7465 7466 7467 7468 7469 7470 7471 7472 7473 7474 7475 7476 7477 7478 7479 7480 7481 7482 7483 7484 7485 7486 7487 7488 7489 7490 7491 7492
        }
        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 已提交
7493
                    gen_op_movl_T1_im(s->pc | 1);
P
pbrook 已提交
7494
                    gen_movl_reg_T1(s, 14);
B
bellard 已提交
7495
                }
7496

P
pbrook 已提交
7497
                offset += s->pc;
P
pbrook 已提交
7498 7499
                if (insn & (1 << 12)) {
                    /* b/bl */
P
pbrook 已提交
7500
                    gen_jmp(s, offset);
P
pbrook 已提交
7501 7502
                } else {
                    /* blx */
P
pbrook 已提交
7503 7504
                    offset &= ~(uint32_t)2;
                    gen_bx_im(s, offset);
B
bellard 已提交
7505
                }
P
pbrook 已提交
7506 7507 7508 7509 7510 7511 7512 7513
            } 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 已提交
7514
                } else {
P
pbrook 已提交
7515 7516 7517 7518
                    op = (insn >> 20) & 7;
                    switch (op) {
                    case 0: /* msr cpsr.  */
                        if (IS_M(env)) {
P
pbrook 已提交
7519 7520 7521
                            tmp = load_reg(s, rn);
                            addr = tcg_const_i32(insn & 0xff);
                            gen_helper_v7m_msr(cpu_env, addr, tmp);
P
pbrook 已提交
7522 7523 7524 7525 7526 7527 7528 7529 7530 7531 7532 7533 7534 7535 7536 7537 7538 7539 7540 7541 7542 7543 7544 7545 7546 7547 7548 7549 7550 7551 7552 7553 7554 7555 7556 7557 7558 7559 7560 7561 7562 7563 7564 7565 7566
                            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 已提交
7567
                            gen_helper_clrex(cpu_env);
P
pbrook 已提交
7568 7569 7570 7571 7572 7573 7574 7575 7576 7577 7578 7579 7580
                            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 已提交
7581 7582
                        tmp = load_reg(s, rn);
                        gen_bx(s, tmp);
P
pbrook 已提交
7583 7584 7585 7586 7587
                        break;
                    case 5: /* Exception return.  */
                        /* Unpredictable in user mode.  */
                        goto illegal_op;
                    case 6: /* mrs cpsr.  */
P
pbrook 已提交
7588
                        tmp = new_tmp();
P
pbrook 已提交
7589
                        if (IS_M(env)) {
P
pbrook 已提交
7590 7591
                            addr = tcg_const_i32(insn & 0xff);
                            gen_helper_v7m_mrs(tmp, cpu_env, addr);
P
pbrook 已提交
7592
                        } else {
P
pbrook 已提交
7593
                            gen_helper_cpsr_read(tmp);
P
pbrook 已提交
7594
                        }
P
pbrook 已提交
7595
                        store_reg(s, rd, tmp);
P
pbrook 已提交
7596 7597 7598 7599 7600
                        break;
                    case 7: /* mrs spsr.  */
                        /* Not accessible in user mode.  */
                        if (IS_USER(s) || IS_M(env))
                            goto illegal_op;
P
pbrook 已提交
7601 7602
                        tmp = load_cpu_field(spsr);
                        store_reg(s, rd, tmp);
P
pbrook 已提交
7603
                        break;
B
bellard 已提交
7604 7605
                    }
                }
P
pbrook 已提交
7606 7607 7608 7609 7610
            } else {
                /* Conditional branch.  */
                op = (insn >> 22) & 0xf;
                /* Generate a conditional jump to next instruction.  */
                s->condlabel = gen_new_label();
P
pbrook 已提交
7611
                gen_test_cc(op ^ 1, s->condlabel);
P
pbrook 已提交
7612 7613 7614 7615 7616 7617 7618 7619 7620 7621 7622 7623 7624 7625
                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 已提交
7626
                gen_jmp(s, s->pc + offset);
P
pbrook 已提交
7627 7628 7629 7630 7631 7632 7633 7634 7635 7636 7637
            }
        } 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 已提交
7638 7639 7640 7641 7642 7643
                    if (rn == 15) {
                        tmp = new_tmp();
                        tcg_gen_movi_i32(tmp, 0);
                    } else {
                        tmp = load_reg(s, rn);
                    }
P
pbrook 已提交
7644 7645 7646 7647 7648 7649
                    switch (op) {
                    case 2: /* Signed bitfield extract.  */
                        imm++;
                        if (shift + imm > 32)
                            goto illegal_op;
                        if (imm < 32)
P
pbrook 已提交
7650
                            gen_sbfx(tmp, shift, imm);
P
pbrook 已提交
7651 7652 7653 7654 7655 7656
                        break;
                    case 6: /* Unsigned bitfield extract.  */
                        imm++;
                        if (shift + imm > 32)
                            goto illegal_op;
                        if (imm < 32)
P
pbrook 已提交
7657
                            gen_ubfx(tmp, shift, (1u << imm) - 1);
P
pbrook 已提交
7658 7659 7660 7661 7662 7663
                        break;
                    case 3: /* Bitfield insert/clear.  */
                        if (imm < shift)
                            goto illegal_op;
                        imm = imm + 1 - shift;
                        if (imm != 32) {
P
pbrook 已提交
7664
                            tmp2 = load_reg(s, rd);
P
pbrook 已提交
7665
                            gen_bfi(tmp, tmp2, tmp, shift, (1u << imm) - 1);
P
pbrook 已提交
7666
                            dead_tmp(tmp2);
P
pbrook 已提交
7667 7668 7669 7670 7671 7672 7673
                        }
                        break;
                    case 7:
                        goto illegal_op;
                    default: /* Saturate.  */
                        if (shift) {
                            if (op & 1)
P
pbrook 已提交
7674
                                tcg_gen_sari_i32(tmp, tmp, shift);
P
pbrook 已提交
7675
                            else
P
pbrook 已提交
7676
                                tcg_gen_shli_i32(tmp, tmp, shift);
P
pbrook 已提交
7677
                        }
P
pbrook 已提交
7678
                        tmp2 = tcg_const_i32(imm);
P
pbrook 已提交
7679 7680 7681
                        if (op & 4) {
                            /* Unsigned.  */
                            if ((op & 1) && shift == 0)
P
pbrook 已提交
7682
                                gen_helper_usat16(tmp, tmp, tmp2);
P
pbrook 已提交
7683
                            else
P
pbrook 已提交
7684
                                gen_helper_usat(tmp, tmp, tmp2);
B
bellard 已提交
7685
                        } else {
P
pbrook 已提交
7686 7687
                            /* Signed.  */
                            if ((op & 1) && shift == 0)
P
pbrook 已提交
7688
                                gen_helper_ssat16(tmp, tmp, tmp2);
P
pbrook 已提交
7689
                            else
P
pbrook 已提交
7690
                                gen_helper_ssat(tmp, tmp, tmp2);
B
bellard 已提交
7691
                        }
P
pbrook 已提交
7692
                        break;
B
bellard 已提交
7693
                    }
P
pbrook 已提交
7694
                    store_reg(s, rd, tmp);
P
pbrook 已提交
7695 7696 7697 7698 7699 7700 7701 7702
                } 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 已提交
7703
                            tmp = load_reg(s, rd);
P
pbrook 已提交
7704
                            tcg_gen_ext16u_i32(tmp, tmp);
P
pbrook 已提交
7705
                            tcg_gen_ori_i32(tmp, tmp, imm << 16);
B
bellard 已提交
7706
                        } else {
P
pbrook 已提交
7707
                            /* movw */
P
pbrook 已提交
7708 7709
                            tmp = new_tmp();
                            tcg_gen_movi_i32(tmp, imm);
B
bellard 已提交
7710 7711
                        }
                    } else {
P
pbrook 已提交
7712 7713
                        /* Add/sub 12-bit immediate.  */
                        if (rn == 15) {
P
pbrook 已提交
7714
                            offset = s->pc & ~(uint32_t)3;
P
pbrook 已提交
7715
                            if (insn & (1 << 23))
P
pbrook 已提交
7716
                                offset -= imm;
P
pbrook 已提交
7717
                            else
P
pbrook 已提交
7718
                                offset += imm;
P
pbrook 已提交
7719 7720
                            tmp = new_tmp();
                            tcg_gen_movi_i32(tmp, offset);
B
bellard 已提交
7721
                        } else {
P
pbrook 已提交
7722
                            tmp = load_reg(s, rn);
P
pbrook 已提交
7723
                            if (insn & (1 << 23))
P
pbrook 已提交
7724
                                tcg_gen_subi_i32(tmp, tmp, imm);
P
pbrook 已提交
7725
                            else
P
pbrook 已提交
7726
                                tcg_gen_addi_i32(tmp, tmp, imm);
B
bellard 已提交
7727
                        }
P
pbrook 已提交
7728
                    }
P
pbrook 已提交
7729
                    store_reg(s, rd, tmp);
P
pbrook 已提交
7730
                }
P
pbrook 已提交
7731 7732 7733 7734 7735 7736 7737 7738 7739 7740 7741 7742 7743 7744 7745 7746 7747 7748 7749 7750 7751 7752 7753 7754 7755 7756
            } 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 已提交
7757
                }
P
pbrook 已提交
7758 7759 7760 7761 7762 7763 7764 7765 7766 7767 7768 7769 7770
                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 已提交
7771 7772
                }
            }
P
pbrook 已提交
7773 7774 7775 7776 7777 7778
        }
        break;
    case 12: /* Load/store single data item.  */
        {
        int postinc = 0;
        int writeback = 0;
P
pbrook 已提交
7779
        int user;
P
pbrook 已提交
7780 7781
        if ((insn & 0x01100000) == 0x01000000) {
            if (disas_neon_ls_insn(env, s, insn))
7782
                goto illegal_op;
P
pbrook 已提交
7783 7784
            break;
        }
P
pbrook 已提交
7785
        user = IS_USER(s);
P
pbrook 已提交
7786
        if (rn == 15) {
P
pbrook 已提交
7787
            addr = new_tmp();
P
pbrook 已提交
7788 7789 7790 7791 7792 7793 7794
            /* 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 已提交
7795
            tcg_gen_movi_i32(addr, imm);
P
pbrook 已提交
7796
        } else {
P
pbrook 已提交
7797
            addr = load_reg(s, rn);
P
pbrook 已提交
7798 7799 7800
            if (insn & (1 << 23)) {
                /* Positive offset.  */
                imm = insn & 0xfff;
P
pbrook 已提交
7801
                tcg_gen_addi_i32(addr, addr, imm);
P
pbrook 已提交
7802 7803 7804 7805 7806 7807 7808
            } else {
                op = (insn >> 8) & 7;
                imm = insn & 0xff;
                switch (op) {
                case 0: case 8: /* Shifted Register.  */
                    shift = (insn >> 4) & 0xf;
                    if (shift > 3)
7809
                        goto illegal_op;
P
pbrook 已提交
7810
                    tmp = load_reg(s, rm);
P
pbrook 已提交
7811
                    if (shift)
P
pbrook 已提交
7812
                        tcg_gen_shli_i32(tmp, tmp, shift);
P
pbrook 已提交
7813
                    tcg_gen_add_i32(addr, addr, tmp);
P
pbrook 已提交
7814
                    dead_tmp(tmp);
P
pbrook 已提交
7815 7816
                    break;
                case 4: /* Negative offset.  */
P
pbrook 已提交
7817
                    tcg_gen_addi_i32(addr, addr, -imm);
P
pbrook 已提交
7818 7819
                    break;
                case 6: /* User privilege.  */
P
pbrook 已提交
7820 7821
                    tcg_gen_addi_i32(addr, addr, imm);
                    user = 1;
P
pbrook 已提交
7822 7823 7824 7825 7826 7827 7828 7829 7830 7831 7832 7833
                    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 已提交
7834
                    tcg_gen_addi_i32(addr, addr, imm);
P
pbrook 已提交
7835 7836 7837
                    writeback = 1;
                    break;
                default:
B
bellard 已提交
7838
                    goto illegal_op;
P
pbrook 已提交
7839 7840 7841 7842 7843 7844 7845 7846
                }
            }
        }
        op = ((insn >> 21) & 3) | ((insn >> 22) & 4);
        if (insn & (1 << 20)) {
            /* Load.  */
            if (rs == 15 && op != 2) {
                if (op & 2)
B
bellard 已提交
7847
                    goto illegal_op;
P
pbrook 已提交
7848 7849 7850
                /* Memory hint.  Implemented as NOP.  */
            } else {
                switch (op) {
P
pbrook 已提交
7851 7852 7853 7854 7855
                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 已提交
7856 7857 7858
                default: goto illegal_op;
                }
                if (rs == 15) {
P
pbrook 已提交
7859
                    gen_bx(s, tmp);
P
pbrook 已提交
7860
                } else {
P
pbrook 已提交
7861
                    store_reg(s, rs, tmp);
P
pbrook 已提交
7862 7863 7864 7865 7866
                }
            }
        } else {
            /* Store.  */
            if (rs == 15)
B
bellard 已提交
7867
                goto illegal_op;
P
pbrook 已提交
7868
            tmp = load_reg(s, rs);
P
pbrook 已提交
7869
            switch (op) {
P
pbrook 已提交
7870 7871 7872
            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 已提交
7873
            default: goto illegal_op;
B
bellard 已提交
7874
            }
B
bellard 已提交
7875
        }
P
pbrook 已提交
7876
        if (postinc)
P
pbrook 已提交
7877 7878 7879 7880 7881 7882
            tcg_gen_addi_i32(addr, addr, imm);
        if (writeback) {
            store_reg(s, rn, addr);
        } else {
            dead_tmp(addr);
        }
P
pbrook 已提交
7883 7884 7885 7886
        }
        break;
    default:
        goto illegal_op;
B
bellard 已提交
7887
    }
P
pbrook 已提交
7888 7889 7890
    return 0;
illegal_op:
    return 1;
B
bellard 已提交
7891 7892
}

P
pbrook 已提交
7893
static void disas_thumb_insn(CPUState *env, DisasContext *s)
B
bellard 已提交
7894 7895 7896 7897
{
    uint32_t val, insn, op, rm, rn, rd, shift, cond;
    int32_t offset;
    int i;
P
pbrook 已提交
7898
    TCGv tmp;
P
pbrook 已提交
7899
    TCGv tmp2;
P
pbrook 已提交
7900
    TCGv addr;
B
bellard 已提交
7901

P
pbrook 已提交
7902 7903 7904
    if (s->condexec_mask) {
        cond = s->condexec_cond;
        s->condlabel = gen_new_label();
P
pbrook 已提交
7905
        gen_test_cc(cond ^ 1, s->condlabel);
P
pbrook 已提交
7906 7907 7908
        s->condjmp = 1;
    }

B
bellard 已提交
7909
    insn = lduw_code(s->pc);
B
bellard 已提交
7910
    s->pc += 2;
B
bellard 已提交
7911

B
bellard 已提交
7912 7913 7914 7915 7916 7917 7918 7919 7920 7921 7922 7923 7924 7925 7926 7927
    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 已提交
7928 7929 7930 7931 7932 7933 7934 7935 7936 7937 7938
            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 已提交
7939 7940 7941 7942 7943
            gen_movl_reg_T0(s, rd);
        } else {
            /* shift immediate */
            rm = (insn >> 3) & 7;
            shift = (insn >> 6) & 0x1f;
P
pbrook 已提交
7944 7945 7946 7947 7948
            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 已提交
7949 7950 7951 7952 7953 7954 7955 7956 7957 7958 7959 7960 7961 7962
        }
        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 已提交
7963 7964
            if (!s->condexec_mask)
                gen_op_logic_T0_cc();
B
bellard 已提交
7965 7966 7967 7968 7969
            break;
        case 1: /* cmp */
            gen_op_subl_T0_T1_cc();
            break;
        case 2: /* add */
P
pbrook 已提交
7970 7971 7972 7973
            if (s->condexec_mask)
                gen_op_addl_T0_T1();
            else
                gen_op_addl_T0_T1_cc();
B
bellard 已提交
7974 7975
            break;
        case 3: /* sub */
P
pbrook 已提交
7976 7977 7978 7979
            if (s->condexec_mask)
                gen_op_subl_T0_T1();
            else
                gen_op_subl_T0_T1_cc();
B
bellard 已提交
7980 7981 7982 7983 7984 7985 7986 7987
            break;
        }
        if (op != 1)
            gen_movl_reg_T0(s, rd);
        break;
    case 4:
        if (insn & (1 << 11)) {
            rd = (insn >> 8) & 7;
B
bellard 已提交
7988 7989 7990
            /* load pc-relative.  Bit 1 of PC is ignored.  */
            val = s->pc + 2 + ((insn & 0xff) * 4);
            val &= ~(uint32_t)2;
P
pbrook 已提交
7991 7992 7993 7994 7995
            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 已提交
7996 7997 7998 7999 8000 8001 8002 8003 8004 8005 8006 8007 8008 8009 8010 8011 8012 8013 8014 8015 8016 8017 8018 8019
            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 已提交
8020
                tmp = load_reg(s, rm);
B
bellard 已提交
8021 8022
                if (insn & (1 << 7)) {
                    val = (uint32_t)s->pc | 1;
P
pbrook 已提交
8023 8024 8025
                    tmp2 = new_tmp();
                    tcg_gen_movi_i32(tmp2, val);
                    store_reg(s, 14, tmp2);
B
bellard 已提交
8026
                }
P
pbrook 已提交
8027
                gen_bx(s, tmp);
B
bellard 已提交
8028 8029 8030 8031 8032 8033 8034 8035 8036 8037 8038 8039 8040 8041 8042 8043 8044 8045 8046 8047 8048 8049 8050 8051 8052
                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 已提交
8053
        switch (op) {
B
bellard 已提交
8054 8055
        case 0x0: /* and */
            gen_op_andl_T0_T1();
P
pbrook 已提交
8056 8057
            if (!s->condexec_mask)
                gen_op_logic_T0_cc();
B
bellard 已提交
8058 8059 8060
            break;
        case 0x1: /* eor */
            gen_op_xorl_T0_T1();
P
pbrook 已提交
8061 8062
            if (!s->condexec_mask)
                gen_op_logic_T0_cc();
B
bellard 已提交
8063 8064
            break;
        case 0x2: /* lsl */
P
pbrook 已提交
8065
            if (s->condexec_mask) {
P
pbrook 已提交
8066
                gen_helper_shl(cpu_T[1], cpu_T[1], cpu_T[0]);
P
pbrook 已提交
8067
            } else {
P
pbrook 已提交
8068
                gen_helper_shl_cc(cpu_T[1], cpu_T[1], cpu_T[0]);
P
pbrook 已提交
8069 8070
                gen_op_logic_T1_cc();
            }
B
bellard 已提交
8071 8072
            break;
        case 0x3: /* lsr */
P
pbrook 已提交
8073
            if (s->condexec_mask) {
P
pbrook 已提交
8074
                gen_helper_shr(cpu_T[1], cpu_T[1], cpu_T[0]);
P
pbrook 已提交
8075
            } else {
P
pbrook 已提交
8076
                gen_helper_shr_cc(cpu_T[1], cpu_T[1], cpu_T[0]);
P
pbrook 已提交
8077 8078
                gen_op_logic_T1_cc();
            }
B
bellard 已提交
8079 8080
            break;
        case 0x4: /* asr */
P
pbrook 已提交
8081
            if (s->condexec_mask) {
P
pbrook 已提交
8082
                gen_helper_sar(cpu_T[1], cpu_T[1], cpu_T[0]);
P
pbrook 已提交
8083
            } else {
P
pbrook 已提交
8084
                gen_helper_sar_cc(cpu_T[1], cpu_T[1], cpu_T[0]);
P
pbrook 已提交
8085 8086
                gen_op_logic_T1_cc();
            }
B
bellard 已提交
8087 8088
            break;
        case 0x5: /* adc */
P
pbrook 已提交
8089
            if (s->condexec_mask)
P
pbrook 已提交
8090
                gen_adc_T0_T1();
P
pbrook 已提交
8091 8092
            else
                gen_op_adcl_T0_T1_cc();
B
bellard 已提交
8093 8094
            break;
        case 0x6: /* sbc */
P
pbrook 已提交
8095
            if (s->condexec_mask)
P
pbrook 已提交
8096
                gen_sbc_T0_T1();
P
pbrook 已提交
8097 8098
            else
                gen_op_sbcl_T0_T1_cc();
B
bellard 已提交
8099 8100
            break;
        case 0x7: /* ror */
P
pbrook 已提交
8101
            if (s->condexec_mask) {
P
pbrook 已提交
8102
                gen_helper_ror(cpu_T[1], cpu_T[1], cpu_T[0]);
P
pbrook 已提交
8103
            } else {
P
pbrook 已提交
8104
                gen_helper_ror_cc(cpu_T[1], cpu_T[1], cpu_T[0]);
P
pbrook 已提交
8105 8106
                gen_op_logic_T1_cc();
            }
B
bellard 已提交
8107 8108 8109 8110 8111
            break;
        case 0x8: /* tst */
            gen_op_andl_T0_T1();
            gen_op_logic_T0_cc();
            rd = 16;
B
bellard 已提交
8112
            break;
B
bellard 已提交
8113
        case 0x9: /* neg */
P
pbrook 已提交
8114
            if (s->condexec_mask)
P
pbrook 已提交
8115
                tcg_gen_neg_i32(cpu_T[0], cpu_T[1]);
P
pbrook 已提交
8116 8117
            else
                gen_op_subl_T0_T1_cc();
B
bellard 已提交
8118 8119 8120 8121 8122 8123 8124 8125 8126 8127 8128
            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 已提交
8129 8130
            if (!s->condexec_mask)
                gen_op_logic_T0_cc();
B
bellard 已提交
8131 8132 8133
            break;
        case 0xd: /* mul */
            gen_op_mull_T0_T1();
P
pbrook 已提交
8134 8135
            if (!s->condexec_mask)
                gen_op_logic_T0_cc();
B
bellard 已提交
8136 8137 8138
            break;
        case 0xe: /* bic */
            gen_op_bicl_T0_T1();
P
pbrook 已提交
8139 8140
            if (!s->condexec_mask)
                gen_op_logic_T0_cc();
B
bellard 已提交
8141 8142 8143
            break;
        case 0xf: /* mvn */
            gen_op_notl_T1();
P
pbrook 已提交
8144 8145
            if (!s->condexec_mask)
                gen_op_logic_T1_cc();
B
bellard 已提交
8146
            val = 1;
B
bellard 已提交
8147
            rm = rd;
B
bellard 已提交
8148 8149 8150 8151
            break;
        }
        if (rd != 16) {
            if (val)
B
bellard 已提交
8152
                gen_movl_reg_T1(s, rm);
B
bellard 已提交
8153 8154 8155 8156 8157 8158 8159 8160 8161 8162 8163
            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 已提交
8164
        addr = load_reg(s, rn);
P
pbrook 已提交
8165
        tmp = load_reg(s, rm);
P
pbrook 已提交
8166
        tcg_gen_add_i32(addr, addr, tmp);
P
pbrook 已提交
8167
        dead_tmp(tmp);
B
bellard 已提交
8168 8169

        if (op < 3) /* store */
P
pbrook 已提交
8170
            tmp = load_reg(s, rd);
B
bellard 已提交
8171 8172 8173

        switch (op) {
        case 0: /* str */
P
pbrook 已提交
8174
            gen_st32(tmp, addr, IS_USER(s));
B
bellard 已提交
8175 8176
            break;
        case 1: /* strh */
P
pbrook 已提交
8177
            gen_st16(tmp, addr, IS_USER(s));
B
bellard 已提交
8178 8179
            break;
        case 2: /* strb */
P
pbrook 已提交
8180
            gen_st8(tmp, addr, IS_USER(s));
B
bellard 已提交
8181 8182
            break;
        case 3: /* ldrsb */
P
pbrook 已提交
8183
            tmp = gen_ld8s(addr, IS_USER(s));
B
bellard 已提交
8184 8185
            break;
        case 4: /* ldr */
P
pbrook 已提交
8186
            tmp = gen_ld32(addr, IS_USER(s));
B
bellard 已提交
8187 8188
            break;
        case 5: /* ldrh */
P
pbrook 已提交
8189
            tmp = gen_ld16u(addr, IS_USER(s));
B
bellard 已提交
8190 8191
            break;
        case 6: /* ldrb */
P
pbrook 已提交
8192
            tmp = gen_ld8u(addr, IS_USER(s));
B
bellard 已提交
8193 8194
            break;
        case 7: /* ldrsh */
P
pbrook 已提交
8195
            tmp = gen_ld16s(addr, IS_USER(s));
B
bellard 已提交
8196 8197 8198
            break;
        }
        if (op >= 3) /* load */
P
pbrook 已提交
8199 8200
            store_reg(s, rd, tmp);
        dead_tmp(addr);
B
bellard 已提交
8201 8202 8203 8204 8205 8206
        break;

    case 6:
        /* load/store word immediate offset */
        rd = insn & 7;
        rn = (insn >> 3) & 7;
P
pbrook 已提交
8207
        addr = load_reg(s, rn);
B
bellard 已提交
8208
        val = (insn >> 4) & 0x7c;
P
pbrook 已提交
8209
        tcg_gen_addi_i32(addr, addr, val);
B
bellard 已提交
8210 8211 8212

        if (insn & (1 << 11)) {
            /* load */
P
pbrook 已提交
8213 8214
            tmp = gen_ld32(addr, IS_USER(s));
            store_reg(s, rd, tmp);
B
bellard 已提交
8215 8216
        } else {
            /* store */
P
pbrook 已提交
8217 8218
            tmp = load_reg(s, rd);
            gen_st32(tmp, addr, IS_USER(s));
B
bellard 已提交
8219
        }
P
pbrook 已提交
8220
        dead_tmp(addr);
B
bellard 已提交
8221 8222 8223 8224 8225 8226
        break;

    case 7:
        /* load/store byte immediate offset */
        rd = insn & 7;
        rn = (insn >> 3) & 7;
P
pbrook 已提交
8227
        addr = load_reg(s, rn);
B
bellard 已提交
8228
        val = (insn >> 6) & 0x1f;
P
pbrook 已提交
8229
        tcg_gen_addi_i32(addr, addr, val);
B
bellard 已提交
8230 8231 8232

        if (insn & (1 << 11)) {
            /* load */
P
pbrook 已提交
8233 8234
            tmp = gen_ld8u(addr, IS_USER(s));
            store_reg(s, rd, tmp);
B
bellard 已提交
8235 8236
        } else {
            /* store */
P
pbrook 已提交
8237 8238
            tmp = load_reg(s, rd);
            gen_st8(tmp, addr, IS_USER(s));
B
bellard 已提交
8239
        }
P
pbrook 已提交
8240
        dead_tmp(addr);
B
bellard 已提交
8241 8242 8243 8244 8245 8246
        break;

    case 8:
        /* load/store halfword immediate offset */
        rd = insn & 7;
        rn = (insn >> 3) & 7;
P
pbrook 已提交
8247
        addr = load_reg(s, rn);
B
bellard 已提交
8248
        val = (insn >> 5) & 0x3e;
P
pbrook 已提交
8249
        tcg_gen_addi_i32(addr, addr, val);
B
bellard 已提交
8250 8251 8252

        if (insn & (1 << 11)) {
            /* load */
P
pbrook 已提交
8253 8254
            tmp = gen_ld16u(addr, IS_USER(s));
            store_reg(s, rd, tmp);
B
bellard 已提交
8255 8256
        } else {
            /* store */
P
pbrook 已提交
8257 8258
            tmp = load_reg(s, rd);
            gen_st16(tmp, addr, IS_USER(s));
B
bellard 已提交
8259
        }
P
pbrook 已提交
8260
        dead_tmp(addr);
B
bellard 已提交
8261 8262 8263 8264 8265
        break;

    case 9:
        /* load/store from stack */
        rd = (insn >> 8) & 7;
P
pbrook 已提交
8266
        addr = load_reg(s, 13);
B
bellard 已提交
8267
        val = (insn & 0xff) * 4;
P
pbrook 已提交
8268
        tcg_gen_addi_i32(addr, addr, val);
B
bellard 已提交
8269 8270 8271

        if (insn & (1 << 11)) {
            /* load */
P
pbrook 已提交
8272 8273
            tmp = gen_ld32(addr, IS_USER(s));
            store_reg(s, rd, tmp);
B
bellard 已提交
8274 8275
        } else {
            /* store */
P
pbrook 已提交
8276 8277
            tmp = load_reg(s, rd);
            gen_st32(tmp, addr, IS_USER(s));
B
bellard 已提交
8278
        }
P
pbrook 已提交
8279
        dead_tmp(addr);
B
bellard 已提交
8280 8281 8282 8283 8284
        break;

    case 10:
        /* add to high reg */
        rd = (insn >> 8) & 7;
B
bellard 已提交
8285 8286
        if (insn & (1 << 11)) {
            /* SP */
P
pbrook 已提交
8287
            tmp = load_reg(s, 13);
B
bellard 已提交
8288 8289
        } else {
            /* PC. bit 1 is ignored.  */
P
pbrook 已提交
8290 8291
            tmp = new_tmp();
            tcg_gen_movi_i32(tmp, (s->pc + 2) & ~(uint32_t)2);
B
bellard 已提交
8292
        }
B
bellard 已提交
8293
        val = (insn & 0xff) * 4;
P
pbrook 已提交
8294 8295
        tcg_gen_addi_i32(tmp, tmp, val);
        store_reg(s, rd, tmp);
B
bellard 已提交
8296 8297 8298 8299 8300 8301 8302 8303
        break;

    case 11:
        /* misc */
        op = (insn >> 8) & 0xf;
        switch (op) {
        case 0:
            /* adjust stack pointer */
P
pbrook 已提交
8304
            tmp = load_reg(s, 13);
B
bellard 已提交
8305 8306
            val = (insn & 0x7f) * 4;
            if (insn & (1 << 7))
B
balrog 已提交
8307
                val = -(int32_t)val;
P
pbrook 已提交
8308 8309
            tcg_gen_addi_i32(tmp, tmp, val);
            store_reg(s, 13, tmp);
B
bellard 已提交
8310 8311
            break;

P
pbrook 已提交
8312 8313 8314 8315
        case 2: /* sign/zero extend.  */
            ARCH(6);
            rd = insn & 7;
            rm = (insn >> 3) & 7;
P
pbrook 已提交
8316
            tmp = load_reg(s, rm);
P
pbrook 已提交
8317
            switch ((insn >> 6) & 3) {
P
pbrook 已提交
8318 8319 8320 8321
            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 已提交
8322
            }
P
pbrook 已提交
8323
            store_reg(s, rd, tmp);
P
pbrook 已提交
8324
            break;
B
bellard 已提交
8325 8326
        case 4: case 5: case 0xc: case 0xd:
            /* push/pop */
P
pbrook 已提交
8327
            addr = load_reg(s, 13);
B
bellard 已提交
8328 8329
            if (insn & (1 << 8))
                offset = 4;
B
bellard 已提交
8330
            else
B
bellard 已提交
8331 8332 8333 8334 8335 8336
                offset = 0;
            for (i = 0; i < 8; i++) {
                if (insn & (1 << i))
                    offset += 4;
            }
            if ((insn & (1 << 11)) == 0) {
P
pbrook 已提交
8337
                tcg_gen_addi_i32(addr, addr, -offset);
B
bellard 已提交
8338
            }
B
bellard 已提交
8339 8340 8341 8342
            for (i = 0; i < 8; i++) {
                if (insn & (1 << i)) {
                    if (insn & (1 << 11)) {
                        /* pop */
P
pbrook 已提交
8343 8344
                        tmp = gen_ld32(addr, IS_USER(s));
                        store_reg(s, i, tmp);
B
bellard 已提交
8345 8346
                    } else {
                        /* push */
P
pbrook 已提交
8347 8348
                        tmp = load_reg(s, i);
                        gen_st32(tmp, addr, IS_USER(s));
B
bellard 已提交
8349
                    }
B
bellard 已提交
8350
                    /* advance to the next address.  */
P
pbrook 已提交
8351
                    tcg_gen_addi_i32(addr, addr, 4);
B
bellard 已提交
8352 8353
                }
            }
P
pbrook 已提交
8354
            TCGV_UNUSED(tmp);
B
bellard 已提交
8355 8356 8357
            if (insn & (1 << 8)) {
                if (insn & (1 << 11)) {
                    /* pop pc */
P
pbrook 已提交
8358
                    tmp = gen_ld32(addr, IS_USER(s));
B
bellard 已提交
8359 8360 8361 8362
                    /* don't set the pc until the rest of the instruction
                       has completed */
                } else {
                    /* push lr */
P
pbrook 已提交
8363 8364
                    tmp = load_reg(s, 14);
                    gen_st32(tmp, addr, IS_USER(s));
B
bellard 已提交
8365
                }
P
pbrook 已提交
8366
                tcg_gen_addi_i32(addr, addr, 4);
B
bellard 已提交
8367
            }
B
bellard 已提交
8368
            if ((insn & (1 << 11)) == 0) {
P
pbrook 已提交
8369
                tcg_gen_addi_i32(addr, addr, -offset);
B
bellard 已提交
8370
            }
B
bellard 已提交
8371
            /* write back the new stack pointer */
P
pbrook 已提交
8372
            store_reg(s, 13, addr);
B
bellard 已提交
8373 8374
            /* set the new PC value */
            if ((insn & 0x0900) == 0x0900)
P
pbrook 已提交
8375
                gen_bx(s, tmp);
B
bellard 已提交
8376 8377
            break;

P
pbrook 已提交
8378 8379
        case 1: case 3: case 9: case 11: /* czb */
            rm = insn & 7;
P
pbrook 已提交
8380
            tmp = load_reg(s, rm);
P
pbrook 已提交
8381 8382 8383
            s->condlabel = gen_new_label();
            s->condjmp = 1;
            if (insn & (1 << 11))
P
pbrook 已提交
8384
                tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, s->condlabel);
P
pbrook 已提交
8385
            else
P
pbrook 已提交
8386
                tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, s->condlabel);
P
pbrook 已提交
8387
            dead_tmp(tmp);
P
pbrook 已提交
8388 8389 8390 8391 8392 8393 8394 8395 8396 8397 8398 8399 8400 8401 8402 8403 8404
            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 已提交
8405
        case 0xe: /* bkpt */
P
pbrook 已提交
8406
            gen_set_condexec(s);
P
pbrook 已提交
8407
            gen_set_pc_im(s->pc - 2);
P
pbrook 已提交
8408
            gen_exception(EXCP_BKPT);
P
pbrook 已提交
8409 8410 8411
            s->is_jmp = DISAS_JUMP;
            break;

P
pbrook 已提交
8412 8413 8414 8415
        case 0xa: /* rev */
            ARCH(6);
            rn = (insn >> 3) & 0x7;
            rd = insn & 0x7;
P
pbrook 已提交
8416
            tmp = load_reg(s, rn);
P
pbrook 已提交
8417
            switch ((insn >> 6) & 3) {
P
pbrook 已提交
8418 8419 8420
            case 0: tcg_gen_bswap_i32(tmp, tmp); break;
            case 1: gen_rev16(tmp); break;
            case 3: gen_revsh(tmp); break;
P
pbrook 已提交
8421 8422
            default: goto illegal_op;
            }
P
pbrook 已提交
8423
            store_reg(s, rd, tmp);
P
pbrook 已提交
8424 8425 8426 8427 8428 8429 8430
            break;

        case 6: /* cps */
            ARCH(6);
            if (IS_USER(s))
                break;
            if (IS_M(env)) {
P
pbrook 已提交
8431
                tmp = tcg_const_i32((insn & (1 << 4)) != 0);
P
pbrook 已提交
8432
                /* PRIMASK */
P
pbrook 已提交
8433 8434 8435 8436
                if (insn & 1) {
                    addr = tcg_const_i32(16);
                    gen_helper_v7m_msr(cpu_env, addr, tmp);
                }
P
pbrook 已提交
8437
                /* FAULTMASK */
P
pbrook 已提交
8438 8439 8440 8441
                if (insn & 2) {
                    addr = tcg_const_i32(17);
                    gen_helper_v7m_msr(cpu_env, addr, tmp);
                }
P
pbrook 已提交
8442 8443 8444 8445 8446 8447 8448 8449 8450 8451 8452 8453 8454
                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 已提交
8455 8456 8457 8458 8459 8460 8461 8462
        default:
            goto undef;
        }
        break;

    case 12:
        /* load/store multiple */
        rn = (insn >> 8) & 0x7;
P
pbrook 已提交
8463
        addr = load_reg(s, rn);
B
bellard 已提交
8464 8465 8466 8467
        for (i = 0; i < 8; i++) {
            if (insn & (1 << i)) {
                if (insn & (1 << 11)) {
                    /* load */
P
pbrook 已提交
8468 8469
                    tmp = gen_ld32(addr, IS_USER(s));
                    store_reg(s, i, tmp);
B
bellard 已提交
8470 8471
                } else {
                    /* store */
P
pbrook 已提交
8472 8473
                    tmp = load_reg(s, i);
                    gen_st32(tmp, addr, IS_USER(s));
B
bellard 已提交
8474
                }
B
bellard 已提交
8475
                /* advance to the next address */
P
pbrook 已提交
8476
                tcg_gen_addi_i32(addr, addr, 4);
B
bellard 已提交
8477 8478
            }
        }
B
bellard 已提交
8479
        /* Base register writeback.  */
P
pbrook 已提交
8480 8481 8482 8483 8484
        if ((insn & (1 << rn)) == 0) {
            store_reg(s, rn, addr);
        } else {
            dead_tmp(addr);
        }
B
bellard 已提交
8485 8486 8487 8488 8489 8490 8491 8492 8493 8494
        break;

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

        if (cond == 0xf) {
            /* swi */
P
pbrook 已提交
8495
            gen_set_condexec(s);
8496
            gen_set_pc_im(s->pc);
P
pbrook 已提交
8497
            s->is_jmp = DISAS_SWI;
B
bellard 已提交
8498 8499 8500
            break;
        }
        /* generate a conditional jump to next instruction */
8501
        s->condlabel = gen_new_label();
P
pbrook 已提交
8502
        gen_test_cc(cond ^ 1, s->condlabel);
8503
        s->condjmp = 1;
B
bellard 已提交
8504 8505 8506
        gen_movl_T1_reg(s, 15);

        /* jump to the offset */
B
bellard 已提交
8507
        val = (uint32_t)s->pc + 2;
B
bellard 已提交
8508
        offset = ((int32_t)insn << 24) >> 24;
B
bellard 已提交
8509
        val += offset << 1;
B
bellard 已提交
8510
        gen_jmp(s, val);
B
bellard 已提交
8511 8512 8513
        break;

    case 14:
P
pbrook 已提交
8514
        if (insn & (1 << 11)) {
P
pbrook 已提交
8515 8516
            if (disas_thumb2_insn(env, s, insn))
              goto undef32;
P
pbrook 已提交
8517 8518
            break;
        }
P
pbrook 已提交
8519
        /* unconditional branch */
B
bellard 已提交
8520 8521 8522
        val = (uint32_t)s->pc;
        offset = ((int32_t)insn << 21) >> 21;
        val += (offset << 1) + 2;
B
bellard 已提交
8523
        gen_jmp(s, val);
B
bellard 已提交
8524 8525 8526
        break;

    case 15:
P
pbrook 已提交
8527
        if (disas_thumb2_insn(env, s, insn))
B
balrog 已提交
8528
            goto undef32;
P
pbrook 已提交
8529
        break;
B
bellard 已提交
8530 8531
    }
    return;
P
pbrook 已提交
8532 8533
undef32:
    gen_set_condexec(s);
P
pbrook 已提交
8534
    gen_set_pc_im(s->pc - 4);
P
pbrook 已提交
8535
    gen_exception(EXCP_UDEF);
P
pbrook 已提交
8536 8537 8538
    s->is_jmp = DISAS_JUMP;
    return;
illegal_op:
B
bellard 已提交
8539
undef:
P
pbrook 已提交
8540
    gen_set_condexec(s);
P
pbrook 已提交
8541
    gen_set_pc_im(s->pc - 2);
P
pbrook 已提交
8542
    gen_exception(EXCP_UDEF);
B
bellard 已提交
8543 8544 8545
    s->is_jmp = DISAS_JUMP;
}

B
bellard 已提交
8546 8547 8548
/* 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. */
8549 8550 8551
static inline void gen_intermediate_code_internal(CPUState *env,
                                                  TranslationBlock *tb,
                                                  int search_pc)
B
bellard 已提交
8552 8553 8554 8555
{
    DisasContext dc1, *dc = &dc1;
    uint16_t *gen_opc_end;
    int j, lj;
B
bellard 已提交
8556
    target_ulong pc_start;
B
bellard 已提交
8557
    uint32_t next_page_start;
P
pbrook 已提交
8558 8559
    int num_insns;
    int max_insns;
8560

B
bellard 已提交
8561
    /* generate intermediate code */
P
pbrook 已提交
8562 8563 8564
    num_temps = 0;
    memset(temps, 0, sizeof(temps));

B
bellard 已提交
8565
    pc_start = tb->pc;
8566

B
bellard 已提交
8567 8568 8569 8570 8571 8572
    dc->tb = tb;

    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;

    dc->is_jmp = DISAS_NEXT;
    dc->pc = pc_start;
B
bellard 已提交
8573
    dc->singlestep_enabled = env->singlestep_enabled;
8574
    dc->condjmp = 0;
B
bellard 已提交
8575
    dc->thumb = env->thumb;
P
pbrook 已提交
8576 8577
    dc->condexec_mask = (env->condexec_bits & 0xf) << 1;
    dc->condexec_cond = env->condexec_bits >> 4;
8578
    dc->is_mem = 0;
B
bellard 已提交
8579
#if !defined(CONFIG_USER_ONLY)
P
pbrook 已提交
8580 8581 8582 8583 8584
    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 已提交
8585
#endif
P
pbrook 已提交
8586 8587 8588 8589
    cpu_F0s = tcg_temp_new(TCG_TYPE_I32);
    cpu_F1s = tcg_temp_new(TCG_TYPE_I32);
    cpu_F0d = tcg_temp_new(TCG_TYPE_I64);
    cpu_F1d = tcg_temp_new(TCG_TYPE_I64);
P
pbrook 已提交
8590 8591
    cpu_V0 = cpu_F0d;
    cpu_V1 = cpu_F1d;
P
pbrook 已提交
8592 8593
    /* FIXME: cpu_M0 can probably be the same as cpu_V0.  */
    cpu_M0 = tcg_temp_new(TCG_TYPE_I64);
B
bellard 已提交
8594
    next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
B
bellard 已提交
8595
    lj = -1;
P
pbrook 已提交
8596 8597 8598 8599 8600 8601
    num_insns = 0;
    max_insns = tb->cflags & CF_COUNT_MASK;
    if (max_insns == 0)
        max_insns = CF_COUNT_MASK;

    gen_icount_start();
P
pbrook 已提交
8602 8603 8604
    /* 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 已提交
8605 8606 8607
      {
        TCGv tmp = new_tmp();
        tcg_gen_movi_i32(tmp, 0);
P
pbrook 已提交
8608
        store_cpu_field(tmp, condexec_bits);
P
pbrook 已提交
8609
      }
B
bellard 已提交
8610
    do {
8611 8612 8613 8614 8615 8616 8617 8618 8619 8620
#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 已提交
8621 8622 8623
        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 已提交
8624
            gen_exception(EXCP_EXCEPTION_EXIT);
8625 8626
            dc->is_jmp = DISAS_UPDATE;
            break;
P
pbrook 已提交
8627 8628 8629
        }
#endif

B
bellard 已提交
8630 8631 8632
        if (env->nb_breakpoints > 0) {
            for(j = 0; j < env->nb_breakpoints; j++) {
                if (env->breakpoints[j] == dc->pc) {
P
pbrook 已提交
8633
                    gen_set_condexec(dc);
P
pbrook 已提交
8634
                    gen_set_pc_im(dc->pc);
P
pbrook 已提交
8635
                    gen_exception(EXCP_DEBUG);
B
bellard 已提交
8636
                    dc->is_jmp = DISAS_JUMP;
P
pbrook 已提交
8637 8638 8639 8640
                    /* Advance PC so that clearing the breakpoint will
                       invalidate this TB.  */
                    dc->pc += 2;
                    goto done_generating;
B
bellard 已提交
8641 8642 8643 8644
                    break;
                }
            }
        }
B
bellard 已提交
8645 8646 8647 8648 8649 8650 8651
        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 已提交
8652
            gen_opc_pc[lj] = dc->pc;
B
bellard 已提交
8653
            gen_opc_instr_start[lj] = 1;
P
pbrook 已提交
8654
            gen_opc_icount[lj] = num_insns;
B
bellard 已提交
8655
        }
8656

P
pbrook 已提交
8657 8658 8659
        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
            gen_io_start();

P
pbrook 已提交
8660 8661 8662 8663 8664 8665 8666 8667 8668 8669 8670 8671 8672
        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 已提交
8673 8674 8675 8676
        if (num_temps) {
            fprintf(stderr, "Internal resource leak before %08x\n", dc->pc);
            num_temps = 0;
        }
8677 8678 8679 8680 8681

        if (dc->condjmp && !dc->is_jmp) {
            gen_set_label(dc->condlabel);
            dc->condjmp = 0;
        }
8682 8683 8684 8685 8686 8687
        /* Terminate the TB on memory ops if watchpoints are present.  */
        /* FIXME: This should be replacd by the deterministic execution
         * IRQ raising bits.  */
        if (dc->is_mem && env->nb_watchpoints)
            break;

8688 8689
        /* Translation stops when a conditional branch is enoutered.
         * Otherwise the subsequent code could get translated several times.
B
bellard 已提交
8690
         * Also stop translation when a page boundary is reached.  This
T
ths 已提交
8691
         * ensures prefetch aborts occur at the right place.  */
P
pbrook 已提交
8692
        num_insns ++;
B
bellard 已提交
8693 8694
    } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
             !env->singlestep_enabled &&
P
pbrook 已提交
8695 8696 8697 8698 8699 8700 8701 8702 8703 8704 8705
             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 已提交
8706

B
bellard 已提交
8707
    /* At this stage dc->condjmp will only be set when the skipped
P
pbrook 已提交
8708 8709
       instruction was a conditional branch or trap, and the PC has
       already been written.  */
8710
    if (unlikely(env->singlestep_enabled)) {
B
bellard 已提交
8711
        /* Make sure the pc is updated, and raise a debug exception.  */
8712
        if (dc->condjmp) {
P
pbrook 已提交
8713 8714
            gen_set_condexec(dc);
            if (dc->is_jmp == DISAS_SWI) {
P
pbrook 已提交
8715
                gen_exception(EXCP_SWI);
P
pbrook 已提交
8716
            } else {
P
pbrook 已提交
8717
                gen_exception(EXCP_DEBUG);
P
pbrook 已提交
8718
            }
8719 8720 8721
            gen_set_label(dc->condlabel);
        }
        if (dc->condjmp || !dc->is_jmp) {
P
pbrook 已提交
8722
            gen_set_pc_im(dc->pc);
8723
            dc->condjmp = 0;
B
bellard 已提交
8724
        }
P
pbrook 已提交
8725 8726
        gen_set_condexec(dc);
        if (dc->is_jmp == DISAS_SWI && !dc->condjmp) {
P
pbrook 已提交
8727
            gen_exception(EXCP_SWI);
P
pbrook 已提交
8728 8729 8730
        } else {
            /* FIXME: Single stepping a WFI insn will not halt
               the CPU.  */
P
pbrook 已提交
8731
            gen_exception(EXCP_DEBUG);
P
pbrook 已提交
8732
        }
B
bellard 已提交
8733
    } else {
P
pbrook 已提交
8734 8735 8736 8737 8738 8739 8740 8741 8742
        /* 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 已提交
8743 8744
        switch(dc->is_jmp) {
        case DISAS_NEXT:
8745
            gen_goto_tb(dc, 1, dc->pc);
B
bellard 已提交
8746 8747 8748 8749 8750
            break;
        default:
        case DISAS_JUMP:
        case DISAS_UPDATE:
            /* indicate that the hash table must be used to find the next TB */
B
bellard 已提交
8751
            tcg_gen_exit_tb(0);
B
bellard 已提交
8752 8753 8754 8755
            break;
        case DISAS_TB_JUMP:
            /* nothing more to generate */
            break;
P
pbrook 已提交
8756
        case DISAS_WFI:
P
pbrook 已提交
8757
            gen_helper_wfi();
P
pbrook 已提交
8758 8759
            break;
        case DISAS_SWI:
P
pbrook 已提交
8760
            gen_exception(EXCP_SWI);
P
pbrook 已提交
8761
            break;
B
bellard 已提交
8762
        }
8763 8764
        if (dc->condjmp) {
            gen_set_label(dc->condlabel);
P
pbrook 已提交
8765
            gen_set_condexec(dc);
8766
            gen_goto_tb(dc, 1, dc->pc);
8767 8768
            dc->condjmp = 0;
        }
B
bellard 已提交
8769
    }
P
pbrook 已提交
8770

P
pbrook 已提交
8771
done_generating:
P
pbrook 已提交
8772
    gen_icount_end(tb, num_insns);
B
bellard 已提交
8773 8774 8775
    *gen_opc_ptr = INDEX_op_end;

#ifdef DEBUG_DISAS
B
bellard 已提交
8776
    if (loglevel & CPU_LOG_TB_IN_ASM) {
B
bellard 已提交
8777 8778
        fprintf(logfile, "----------------\n");
        fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
B
bellard 已提交
8779
        target_disas(logfile, pc_start, dc->pc - pc_start, env->thumb);
B
bellard 已提交
8780 8781 8782
        fprintf(logfile, "\n");
    }
#endif
B
bellard 已提交
8783 8784 8785 8786 8787 8788
    if (search_pc) {
        j = gen_opc_ptr - gen_opc_buf;
        lj++;
        while (lj <= j)
            gen_opc_instr_start[lj++] = 0;
    } else {
B
bellard 已提交
8789
        tb->size = dc->pc - pc_start;
P
pbrook 已提交
8790
        tb->icount = num_insns;
B
bellard 已提交
8791
    }
B
bellard 已提交
8792 8793
}

8794
void gen_intermediate_code(CPUState *env, TranslationBlock *tb)
B
bellard 已提交
8795
{
8796
    gen_intermediate_code_internal(env, tb, 0);
B
bellard 已提交
8797 8798
}

8799
void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
B
bellard 已提交
8800
{
8801
    gen_intermediate_code_internal(env, tb, 1);
B
bellard 已提交
8802 8803
}

B
bellard 已提交
8804 8805 8806 8807
static const char *cpu_mode_names[16] = {
  "usr", "fiq", "irq", "svc", "???", "???", "???", "abt",
  "???", "???", "???", "und", "???", "???", "???", "sys"
};
P
pbrook 已提交
8808

8809
void cpu_dump_state(CPUState *env, FILE *f,
B
bellard 已提交
8810 8811
                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
                    int flags)
B
bellard 已提交
8812 8813
{
    int i;
T
ths 已提交
8814
#if 0
B
bellard 已提交
8815
    union {
B
bellard 已提交
8816 8817 8818 8819
        uint32_t i;
        float s;
    } s0, s1;
    CPU_DoubleU d;
P
pbrook 已提交
8820 8821 8822 8823 8824 8825
    /* ??? This assumes float64 and double have the same layout.
       Oh well, it's only debug dumps.  */
    union {
        float64 f64;
        double d;
    } d0;
T
ths 已提交
8826
#endif
B
bellard 已提交
8827
    uint32_t psr;
B
bellard 已提交
8828 8829

    for(i=0;i<16;i++) {
B
bellard 已提交
8830
        cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
B
bellard 已提交
8831
        if ((i % 4) == 3)
B
bellard 已提交
8832
            cpu_fprintf(f, "\n");
B
bellard 已提交
8833
        else
B
bellard 已提交
8834
            cpu_fprintf(f, " ");
B
bellard 已提交
8835
    }
B
bellard 已提交
8836
    psr = cpsr_read(env);
8837 8838
    cpu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%d\n",
                psr,
B
bellard 已提交
8839 8840 8841 8842
                psr & (1 << 31) ? 'N' : '-',
                psr & (1 << 30) ? 'Z' : '-',
                psr & (1 << 29) ? 'C' : '-',
                psr & (1 << 28) ? 'V' : '-',
8843
                psr & CPSR_T ? 'T' : 'A',
B
bellard 已提交
8844
                cpu_mode_names[psr & 0xf], (psr & 0x10) ? 32 : 26);
B
bellard 已提交
8845

P
pbrook 已提交
8846
#if 0
B
bellard 已提交
8847
    for (i = 0; i < 16; i++) {
B
bellard 已提交
8848 8849 8850
        d.d = env->vfp.regs[i];
        s0.i = d.l.lower;
        s1.i = d.l.upper;
P
pbrook 已提交
8851 8852
        d0.f64 = d.d;
        cpu_fprintf(f, "s%02d=%08x(%8g) s%02d=%08x(%8g) d%02d=%08x%08x(%8g)\n",
B
bellard 已提交
8853
                    i * 2, (int)s0.i, s0.s,
P
pbrook 已提交
8854
                    i * 2 + 1, (int)s1.i, s1.s,
B
bellard 已提交
8855
                    i, (int)(uint32_t)d.l.upper, (int)(uint32_t)d.l.lower,
P
pbrook 已提交
8856
                    d0.d);
B
bellard 已提交
8857
    }
P
pbrook 已提交
8858
    cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.xregs[ARM_VFP_FPSCR]);
P
pbrook 已提交
8859
#endif
B
bellard 已提交
8860
}
B
bellard 已提交
8861

A
aurel32 已提交
8862 8863 8864 8865 8866
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];
}