translate.c 299.4 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

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

P
pbrook 已提交
38 39 40 41 42
#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 已提交
43

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

B
bellard 已提交
46 47
/* internal defines */
typedef struct DisasContext {
B
bellard 已提交
48
    target_ulong pc;
B
bellard 已提交
49
    int is_jmp;
50 51 52 53
    /* 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 已提交
54 55 56
    /* Thumb-2 condtional execution bits.  */
    int condexec_mask;
    int condexec_cond;
B
bellard 已提交
57
    struct TranslationBlock *tb;
B
bellard 已提交
58
    int singlestep_enabled;
B
bellard 已提交
59
    int thumb;
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_ptr cpu_env;
P
pbrook 已提交
77
/* We reuse the same 64-bit temporaries for efficiency.  */
P
pbrook 已提交
78
static TCGv_i64 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 83
static TCGv cpu_F0s, cpu_F1s;
static TCGv_i64 cpu_F0d, cpu_F1d;
P
pbrook 已提交
84

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

P
pbrook 已提交
88 89 90
/* initialize TCG globals.  */
void arm_translate_init(void)
{
P
pbrook 已提交
91 92 93 94
    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");

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

P
pbrook 已提交
96 97
#define GEN_HELPER 2
#include "helpers.h"
P
pbrook 已提交
98 99 100 101 102 103 104 105 106
}

/* 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.  */
P
pbrook 已提交
107
static TCGv_i32 new_tmp(void)
P
pbrook 已提交
108 109 110 111 112
{
    TCGv tmp;
    if (num_temps == MAX_TEMPS)
        abort();

P
pbrook 已提交
113
    if (GET_TCGV_I32(temps[num_temps]))
P
pbrook 已提交
114 115
      return temps[num_temps++];

P
pbrook 已提交
116
    tmp = tcg_temp_new_i32();
P
pbrook 已提交
117 118 119 120 121 122 123 124 125 126
    temps[num_temps++] = tmp;
    return tmp;
}

/* Release a temporary variable.  */
static void dead_tmp(TCGv tmp)
{
    int i;
    num_temps--;
    i = num_temps;
P
pbrook 已提交
127
    if (TCGV_EQUAL(temps[i], tmp))
P
pbrook 已提交
128 129 130
        return;

    /* Shuffle this temp to the last slot.  */
P
pbrook 已提交
131
    while (!TCGV_EQUAL(temps[i], tmp))
P
pbrook 已提交
132 133 134 135 136 137 138 139
        i--;
    while (i < num_temps) {
        temps[i] = temps[i + 1];
        i++;
    }
    temps[i] = tmp;
}

P
pbrook 已提交
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
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 已提交
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 202 203 204
/* 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_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 已提交
205 206 207 208 209 210 211
#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 已提交
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_T1_im(im) tcg_gen_shli_i32(cpu_T[1], cpu_T[1], im)
#define gen_op_shrl_T1_im(im) tcg_gen_shri_i32(cpu_T[1], cpu_T[1], im)

/* Value extensions.  */
P
pbrook 已提交
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
/* 32x32->64 multiply.  Marks inputs as dead.  */
P
pbrook 已提交
327
static TCGv_i64 gen_mulu_i64_i32(TCGv a, TCGv b)
P
pbrook 已提交
328
{
P
pbrook 已提交
329 330
    TCGv_i64 tmp1 = tcg_temp_new_i64();
    TCGv_i64 tmp2 = tcg_temp_new_i64();
P
pbrook 已提交
331 332 333 334 335 336 337 338 339

    tcg_gen_extu_i32_i64(tmp1, a);
    dead_tmp(a);
    tcg_gen_extu_i32_i64(tmp2, b);
    dead_tmp(b);
    tcg_gen_mul_i64(tmp1, tmp1, tmp2);
    return tmp1;
}

P
pbrook 已提交
340
static TCGv_i64 gen_muls_i64_i32(TCGv a, TCGv b)
P
pbrook 已提交
341
{
P
pbrook 已提交
342 343
    TCGv_i64 tmp1 = tcg_temp_new_i64();
    TCGv_i64 tmp2 = tcg_temp_new_i64();
P
pbrook 已提交
344 345 346 347 348 349 350 351 352

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

    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
{
P
pbrook 已提交
370 371
    TCGv_i64 tmp1 = tcg_temp_new_i64();
    TCGv_i64 tmp2 = tcg_temp_new_i64();
P
pbrook 已提交
372

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
    tcg_gen_trunc_i64_i32(b, tmp1);
}

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

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

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

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

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

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

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

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

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

P
pbrook 已提交
550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570
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 已提交
571 572 573 574 575 576 577 578 579
#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 已提交
580
static void gen_arm_parallel_addsub(int op1, int op2, TCGv a, TCGv b)
P
pbrook 已提交
581
{
P
pbrook 已提交
582
    TCGv_ptr tmp;
P
pbrook 已提交
583 584 585 586

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

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

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

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

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

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

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

P
pbrook 已提交
782 783
    s->is_jmp = DISAS_UPDATE;
    tmp = new_tmp();
P
pbrook 已提交
784 785 786 787 788 789
    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 已提交
790
    dead_tmp(tmp);
P
pbrook 已提交
791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811
}

/* 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 已提交
812
}
B
bellard 已提交
813

P
pbrook 已提交
814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858
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 已提交
859

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

static inline void gen_movl_T1_reg(DisasContext *s, int reg)
{
P
pbrook 已提交
867
    load_reg_var(s, cpu_T[1], reg);
B
bellard 已提交
868 869 870 871
}

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

P
pbrook 已提交
875 876 877 878 879 880 881
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 已提交
882 883
static inline void gen_movl_reg_TN(DisasContext *s, int reg, int t)
{
P
pbrook 已提交
884 885 886 887 888 889 890 891
    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 已提交
892
    if (reg == 15) {
P
pbrook 已提交
893
        dead_tmp(tmp);
B
bellard 已提交
894 895 896 897 898 899 900 901 902 903 904 905 906 907
        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 已提交
908 909 910 911 912 913 914 915
/* 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 已提交
916 917
static inline void gen_add_data_offset(DisasContext *s, unsigned int insn,
                                       TCGv var)
B
bellard 已提交
918
{
B
bellard 已提交
919
    int val, rm, shift, shiftop;
P
pbrook 已提交
920
    TCGv offset;
B
bellard 已提交
921 922 923 924 925 926

    if (!(insn & (1 << 25))) {
        /* immediate */
        val = insn & 0xfff;
        if (!(insn & (1 << 23)))
            val = -val;
B
bellard 已提交
927
        if (val != 0)
P
pbrook 已提交
928
            tcg_gen_addi_i32(var, var, val);
B
bellard 已提交
929 930 931 932
    } else {
        /* shift/register */
        rm = (insn) & 0xf;
        shift = (insn >> 7) & 0x1f;
B
bellard 已提交
933
        shiftop = (insn >> 5) & 3;
P
pbrook 已提交
934
        offset = load_reg(s, rm);
P
pbrook 已提交
935
        gen_arm_shift_im(offset, shiftop, shift, 0);
B
bellard 已提交
936
        if (!(insn & (1 << 23)))
P
pbrook 已提交
937
            tcg_gen_sub_i32(var, var, offset);
B
bellard 已提交
938
        else
P
pbrook 已提交
939
            tcg_gen_add_i32(var, var, offset);
P
pbrook 已提交
940
        dead_tmp(offset);
B
bellard 已提交
941 942 943
    }
}

P
pbrook 已提交
944
static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn,
P
pbrook 已提交
945
                                        int extra, TCGv var)
B
bellard 已提交
946 947
{
    int val, rm;
P
pbrook 已提交
948
    TCGv offset;
949

B
bellard 已提交
950 951 952 953 954
    if (insn & (1 << 22)) {
        /* immediate */
        val = (insn & 0xf) | ((insn >> 4) & 0xf0);
        if (!(insn & (1 << 23)))
            val = -val;
955
        val += extra;
B
bellard 已提交
956
        if (val != 0)
P
pbrook 已提交
957
            tcg_gen_addi_i32(var, var, val);
B
bellard 已提交
958 959
    } else {
        /* register */
P
pbrook 已提交
960
        if (extra)
P
pbrook 已提交
961
            tcg_gen_addi_i32(var, var, extra);
B
bellard 已提交
962
        rm = (insn) & 0xf;
P
pbrook 已提交
963
        offset = load_reg(s, rm);
B
bellard 已提交
964
        if (!(insn & (1 << 23)))
P
pbrook 已提交
965
            tcg_gen_sub_i32(var, var, offset);
B
bellard 已提交
966
        else
P
pbrook 已提交
967
            tcg_gen_add_i32(var, var, offset);
P
pbrook 已提交
968
        dead_tmp(offset);
B
bellard 已提交
969 970 971
    }
}

P
pbrook 已提交
972 973 974 975 976 977 978
#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 已提交
979 980
}

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

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)
1047
        gen_helper_vfp_sitod(cpu_F0d, cpu_F0s, cpu_env);
P
pbrook 已提交
1048
    else
1049
        gen_helper_vfp_sitos(cpu_F0s, cpu_F0s, cpu_env);
P
pbrook 已提交
1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076
}

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 已提交
1077 1078
{
    if (dp)
P
pbrook 已提交
1079
        gen_helper_vfp_tosizd(cpu_F0s, cpu_F0d, cpu_env);
P
pbrook 已提交
1080
    else
P
pbrook 已提交
1081 1082 1083 1084 1085 1086 1087 1088 1089 1090
        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 已提交
1091
}
P
pbrook 已提交
1092 1093 1094 1095 1096 1097 1098 1099 1100
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 已提交
1101

B
bellard 已提交
1102 1103 1104
static inline void gen_vfp_ld(DisasContext *s, int dp)
{
    if (dp)
P
pbrook 已提交
1105
        tcg_gen_qemu_ld64(cpu_F0d, cpu_T[1], IS_USER(s));
B
bellard 已提交
1106
    else
P
pbrook 已提交
1107
        tcg_gen_qemu_ld32u(cpu_F0s, cpu_T[1], IS_USER(s));
B
bellard 已提交
1108 1109 1110 1111 1112
}

static inline void gen_vfp_st(DisasContext *s, int dp)
{
    if (dp)
P
pbrook 已提交
1113
        tcg_gen_qemu_st64(cpu_F0d, cpu_T[1], IS_USER(s));
B
bellard 已提交
1114
    else
P
pbrook 已提交
1115
        tcg_gen_qemu_st32(cpu_F0s, cpu_T[1], IS_USER(s));
B
bellard 已提交
1116 1117
}

B
bellard 已提交
1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130
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 已提交
1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141

/* 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 已提交
1142 1143 1144 1145 1146 1147 1148
/* 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 已提交
1149

P
pbrook 已提交
1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162
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 已提交
1163
static inline void neon_load_reg64(TCGv_i64 var, int reg)
P
pbrook 已提交
1164 1165 1166 1167
{
    tcg_gen_ld_i64(var, cpu_env, vfp_reg_offset(1, reg));
}

P
pbrook 已提交
1168
static inline void neon_store_reg64(TCGv_i64 var, int reg)
P
pbrook 已提交
1169 1170 1171 1172
{
    tcg_gen_st_i64(var, cpu_env, vfp_reg_offset(1, reg));
}

P
pbrook 已提交
1173 1174 1175 1176 1177
#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 已提交
1178 1179 1180
static inline void gen_mov_F0_vreg(int dp, int reg)
{
    if (dp)
P
pbrook 已提交
1181
        tcg_gen_ld_f64(cpu_F0d, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1182
    else
P
pbrook 已提交
1183
        tcg_gen_ld_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1184 1185 1186 1187 1188
}

static inline void gen_mov_F1_vreg(int dp, int reg)
{
    if (dp)
P
pbrook 已提交
1189
        tcg_gen_ld_f64(cpu_F1d, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1190
    else
P
pbrook 已提交
1191
        tcg_gen_ld_f32(cpu_F1s, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1192 1193 1194 1195 1196
}

static inline void gen_mov_vreg_F0(int dp, int reg)
{
    if (dp)
P
pbrook 已提交
1197
        tcg_gen_st_f64(cpu_F0d, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1198
    else
P
pbrook 已提交
1199
        tcg_gen_st_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1200 1201
}

1202 1203
#define ARM_CP_RW_BIT	(1 << 20)

P
pbrook 已提交
1204
static inline void iwmmxt_load_reg(TCGv_i64 var, int reg)
P
pbrook 已提交
1205 1206 1207 1208
{
    tcg_gen_ld_i64(var, cpu_env, offsetof(CPUState, iwmmxt.regs[reg]));
}

P
pbrook 已提交
1209
static inline void iwmmxt_store_reg(TCGv_i64 var, int reg)
P
pbrook 已提交
1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413
{
    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 已提交
1414
    tcg_gen_ext32u_i64(cpu_V1, cpu_V1);
P
pbrook 已提交
1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428
    tcg_gen_add_i64(cpu_M0, cpu_M0, cpu_V1);
}


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

static void gen_iwmmxt_movl_wRn_T0_T1(int rn)
{
P
pbrook 已提交
1429
    tcg_gen_concat_i32_i64(cpu_V0, cpu_T[0], cpu_T[1]);
P
pbrook 已提交
1430 1431 1432
    iwmmxt_store_reg(cpu_V0, rn);
}

1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473
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 已提交
1474
        gen_iwmmxt_movl_T0_T1_wRn(rd);
1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486

    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 已提交
1487
    TCGv tmp;
1488 1489 1490 1491 1492 1493 1494

    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 已提交
1495
                gen_iwmmxt_movl_T0_T1_wRn(wrd);
1496 1497 1498 1499 1500
                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 已提交
1501
                gen_iwmmxt_movl_wRn_T0_T1(wrd);
1502 1503 1504 1505 1506 1507 1508 1509 1510 1511
                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 已提交
1512 1513 1514
                tmp = gen_ld32(cpu_T[1], IS_USER(s));
                tcg_gen_mov_i32(cpu_T[0], tmp);
                dead_tmp(tmp);
1515 1516
                gen_op_iwmmxt_movl_wCx_T0(wrd);
            } else {
P
pbrook 已提交
1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535
                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);
                }
1536 1537 1538 1539 1540
                gen_op_iwmmxt_movq_wRn_M0(wrd);
            }
        } else {
            if ((insn >> 28) == 0xf) {			/* WSTRW wCx */
                gen_op_iwmmxt_movl_T0_wCx(wrd);
P
pbrook 已提交
1541 1542 1543
                tmp = new_tmp();
                tcg_gen_mov_i32(tmp, cpu_T[0]);
                gen_st32(tmp, cpu_T[1], IS_USER(s));
1544 1545
            } else {
                gen_op_iwmmxt_movq_M0_wRn(wrd);
P
pbrook 已提交
1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563
                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));
                    }
                }
1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637
            }
        }
        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 已提交
1638
        tcg_gen_neg_i64(cpu_M0, cpu_M0);
1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730
        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 已提交
1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741
        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);
        }
1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754
        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 已提交
1755 1756
            iwmmxt_load_reg(cpu_V1, wrd);
            tcg_gen_add_i64(cpu_M0, cpu_M0, cpu_V1);
1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787
        }
        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 已提交
1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798
        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);
        }
1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849
        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 已提交
1850
                gen_op_iwmmxt_extru_T0_M0((insn & 7) << 3, 0xff);
1851 1852 1853 1854 1855 1856
            }
            break;
        case 1:
            if (insn & 8)
                gen_op_iwmmxt_extrsw_T0_M0((insn & 3) << 4);
            else {
P
pbrook 已提交
1857
                gen_op_iwmmxt_extru_T0_M0((insn & 3) << 4, 0xffff);
1858 1859 1860
            }
            break;
        case 2:
P
pbrook 已提交
1861
            gen_op_iwmmxt_extru_T0_M0((insn & 1) << 5, ~0u);
1862 1863 1864 1865
            break;
        case 3:
            return 1;
        }
P
pbrook 已提交
1866
        gen_movl_reg_T0(s, rd);
1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885
        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 已提交
1886
        gen_set_nzcv(cpu_T[1]);
1887 1888 1889 1890 1891 1892 1893
        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 已提交
1894
            gen_helper_iwmmxt_bcstb(cpu_M0, cpu_T[0]);
1895 1896
            break;
        case 1:
P
pbrook 已提交
1897
            gen_helper_iwmmxt_bcstw(cpu_M0, cpu_T[0]);
1898 1899
            break;
        case 2:
P
pbrook 已提交
1900
            gen_helper_iwmmxt_bcstl(cpu_M0, cpu_T[0]);
1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931
            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 已提交
1932
        gen_set_nzcv(cpu_T[0]);
1933 1934 1935 1936 1937 1938 1939
        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 已提交
1940
            gen_helper_iwmmxt_addcb(cpu_M0, cpu_M0);
1941 1942
            break;
        case 1:
P
pbrook 已提交
1943
            gen_helper_iwmmxt_addcw(cpu_M0, cpu_M0);
1944 1945
            break;
        case 2:
P
pbrook 已提交
1946
            gen_helper_iwmmxt_addcl(cpu_M0, cpu_M0);
1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977
            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 已提交
1978
        gen_set_nzcv(cpu_T[0]);
1979 1980 1981 1982 1983 1984 1985 1986 1987
        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 已提交
1988
            gen_helper_iwmmxt_msbb(cpu_T[0], cpu_M0);
1989 1990
            break;
        case 1:
P
pbrook 已提交
1991
            gen_helper_iwmmxt_msbw(cpu_T[0], cpu_M0);
1992 1993
            break;
        case 2:
P
pbrook 已提交
1994
            gen_helper_iwmmxt_msbl(cpu_T[0], cpu_M0);
1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105
            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 已提交
2106
            gen_helper_iwmmxt_srlw(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2107 2108
            break;
        case 2:
P
pbrook 已提交
2109
            gen_helper_iwmmxt_srll(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2110 2111
            break;
        case 3:
P
pbrook 已提交
2112
            gen_helper_iwmmxt_srlq(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129
            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 已提交
2130
            gen_helper_iwmmxt_sraw(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2131 2132
            break;
        case 2:
P
pbrook 已提交
2133
            gen_helper_iwmmxt_sral(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2134 2135
            break;
        case 3:
P
pbrook 已提交
2136
            gen_helper_iwmmxt_sraq(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 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 已提交
2154
            gen_helper_iwmmxt_sllw(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2155 2156
            break;
        case 2:
P
pbrook 已提交
2157
            gen_helper_iwmmxt_slll(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2158 2159
            break;
        case 3:
P
pbrook 已提交
2160
            gen_helper_iwmmxt_sllq(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 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 已提交
2178
            gen_helper_iwmmxt_rorw(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2179 2180 2181 2182
            break;
        case 2:
            if (gen_iwmmxt_shift(insn, 0x1f))
                return 1;
P
pbrook 已提交
2183
            gen_helper_iwmmxt_rorl(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2184 2185 2186 2187
            break;
        case 3:
            if (gen_iwmmxt_shift(insn, 0x3f))
                return 1;
P
pbrook 已提交
2188
            gen_helper_iwmmxt_rorq(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318
            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 已提交
2319
        gen_helper_iwmmxt_shufh(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414
        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 已提交
2415 2416
            gen_movl_T0_reg(s, rd0);
            gen_movl_T1_reg(s, rd1);
2417 2418 2419
            gen_op_iwmmxt_muladdsl_M0_T0_T1();
            break;
        case 0x8:					/* TMIAPH */
P
pbrook 已提交
2420 2421
            gen_movl_T0_reg(s, rd0);
            gen_movl_T1_reg(s, rd1);
2422 2423 2424
            gen_op_iwmmxt_muladdsw_M0_T0_T1();
            break;
        case 0xc: case 0xd: case 0xe: case 0xf:		/* TMIAxy */
P
pbrook 已提交
2425
            gen_movl_T1_reg(s, rd0);
2426 2427 2428
            if (insn & (1 << 16))
                gen_op_shrl_T1_im(16);
            gen_op_movl_T0_T1();
P
pbrook 已提交
2429
            gen_movl_T1_reg(s, rd1);
2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463
            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 已提交
2464 2465
            gen_movl_T0_reg(s, rd0);
            gen_movl_T1_reg(s, rd1);
2466 2467 2468
            gen_op_iwmmxt_muladdsl_M0_T0_T1();
            break;
        case 0x8:					/* MIAPH */
P
pbrook 已提交
2469 2470
            gen_movl_T0_reg(s, rd0);
            gen_movl_T1_reg(s, rd1);
2471 2472 2473 2474 2475 2476
            gen_op_iwmmxt_muladdsw_M0_T0_T1();
            break;
        case 0xc:					/* MIABB */
        case 0xd:					/* MIABT */
        case 0xe:					/* MIATB */
        case 0xf:					/* MIATT */
P
pbrook 已提交
2477
            gen_movl_T1_reg(s, rd0);
2478 2479 2480
            if (insn & (1 << 16))
                gen_op_shrl_T1_im(16);
            gen_op_movl_T0_T1();
P
pbrook 已提交
2481
            gen_movl_T1_reg(s, rd1);
2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503
            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 已提交
2504
            gen_iwmmxt_movl_T0_T1_wRn(acc);
P
pbrook 已提交
2505
            gen_movl_reg_T0(s, rdlo);
2506 2507
            gen_op_movl_T0_im((1 << (40 - 32)) - 1);
            gen_op_andl_T0_T1();
P
pbrook 已提交
2508
            gen_movl_reg_T0(s, rdhi);
2509
        } else {					/* MAR */
P
pbrook 已提交
2510 2511
            gen_movl_T0_reg(s, rdlo);
            gen_movl_T1_reg(s, rdhi);
P
pbrook 已提交
2512
            gen_iwmmxt_movl_wRn_T0_T1(acc);
2513 2514 2515 2516 2517 2518 2519
        }
        return 0;
    }

    return 1;
}

2520 2521 2522 2523
/* 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 已提交
2524
    TCGv tmp;
2525 2526 2527 2528 2529 2530
    uint32_t rd = (insn >> 12) & 0xf;
    uint32_t cp = (insn >> 8) & 0xf;
    if (IS_USER(s)) {
        return 1;
    }

2531
    if (insn & ARM_CP_RW_BIT) {
2532 2533
        if (!env->cp[cp].cp_read)
            return 1;
P
pbrook 已提交
2534 2535 2536 2537
        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);
2538 2539 2540
    } else {
        if (!env->cp[cp].cp_write)
            return 1;
P
pbrook 已提交
2541 2542 2543
        gen_set_pc_im(s->pc);
        tmp = load_reg(s, rd);
        gen_helper_set_cp(cpu_env, tcg_const_i32(insn), tmp);
B
balrog 已提交
2544
        dead_tmp(tmp);
2545 2546 2547 2548
    }
    return 0;
}

P
pbrook 已提交
2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568
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 已提交
2569 2570
/* Disassemble system coprocessor (cp15) instruction.  Return nonzero if
   instruction is not defined.  */
2571
static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn)
B
bellard 已提交
2572 2573
{
    uint32_t rd;
P
pbrook 已提交
2574
    TCGv tmp;
B
bellard 已提交
2575

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

P
pbrook 已提交
2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644
#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 已提交
2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658
/* 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 已提交
2659 2660 2661 2662 2663 2664
static inline int
vfp_enabled(CPUState * env)
{
    return ((env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) != 0);
}

P
pbrook 已提交
2665 2666 2667 2668 2669
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 已提交
2670
    tcg_gen_ext8u_i32(var, var);
P
pbrook 已提交
2671 2672 2673 2674 2675 2676 2677 2678 2679 2680
    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 已提交
2681
    tcg_gen_ext16u_i32(var, var);
P
pbrook 已提交
2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695
    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 已提交
2696 2697 2698 2699 2700 2701
/* 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 已提交
2702
    TCGv tmp;
P
pbrook 已提交
2703
    TCGv tmp2;
B
bellard 已提交
2704

P
pbrook 已提交
2705 2706 2707
    if (!arm_feature(env, ARM_FEATURE_VFP))
        return 1;

P
pbrook 已提交
2708 2709
    if (!vfp_enabled(env)) {
        /* VFP disabled.  Only allow fmxr/fmrx to/from some control regs.  */
P
pbrook 已提交
2710 2711 2712
        if ((insn & 0x0fe00fff) != 0x0ee00a10)
            return 1;
        rn = (insn >> 16) & 0xf;
P
pbrook 已提交
2713 2714
        if (rn != ARM_VFP_FPSID && rn != ARM_VFP_FPEXC
            && rn != ARM_VFP_MVFR1 && rn != ARM_VFP_MVFR0)
P
pbrook 已提交
2715 2716
            return 1;
    }
B
bellard 已提交
2717 2718 2719 2720 2721 2722 2723
    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 已提交
2724 2725 2726 2727 2728
                int size;
                int pass;

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

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

                if (op == 15 && (rn == 15 || rn > 17)) {
                    /* Integer or single precision destination.  */
P
pbrook 已提交
2923
                    rd = VFP_SREG_D(insn);
B
bellard 已提交
2924
                } else {
P
pbrook 已提交
2925
                    VFP_DREG_D(rd, insn);
B
bellard 已提交
2926 2927 2928 2929 2930 2931
                }

                if (op == 15 && (rn == 16 || rn == 17)) {
                    /* Integer source.  */
                    rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1);
                } else {
P
pbrook 已提交
2932
                    VFP_DREG_M(rm, insn);
B
bellard 已提交
2933 2934
                }
            } else {
P
pbrook 已提交
2935
                rn = VFP_SREG_N(insn);
B
bellard 已提交
2936 2937
                if (op == 15 && rn == 15) {
                    /* Double precision destination.  */
P
pbrook 已提交
2938 2939 2940 2941 2942
                    VFP_DREG_D(rd, insn);
                } else {
                    rd = VFP_SREG_D(insn);
                }
                rm = VFP_SREG_M(insn);
B
bellard 已提交
2943 2944 2945 2946 2947 2948 2949 2950 2951 2952
            }

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

B
bellard 已提交
2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999
            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 已提交
3000 3001 3002 3003
                case 20:
                case 21:
                case 22:
                case 23:
P
pbrook 已提交
3004 3005 3006 3007
                case 28:
                case 29:
                case 30:
                case 31:
P
pbrook 已提交
3008 3009 3010
                    /* Source and destination the same.  */
                    gen_mov_F0_vreg(dp, rd);
                    break;
B
bellard 已提交
3011 3012 3013
                default:
                    /* One source operand.  */
                    gen_mov_F0_vreg(dp, rm);
P
pbrook 已提交
3014
                    break;
B
bellard 已提交
3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043
                }
            } else {
                /* Two source operands.  */
                gen_mov_F0_vreg(dp, rn);
                gen_mov_F1_vreg(dp, rm);
            }

            for (;;) {
                /* Perform the calculation.  */
                switch (op) {
                case 0: /* mac: fd + (fn * fm) */
                    gen_vfp_mul(dp);
                    gen_mov_F1_vreg(dp, rd);
                    gen_vfp_add(dp);
                    break;
                case 1: /* nmac: fd - (fn * fm) */
                    gen_vfp_mul(dp);
                    gen_vfp_neg(dp);
                    gen_mov_F1_vreg(dp, rd);
                    gen_vfp_add(dp);
                    break;
                case 2: /* msc: -fd + (fn * fm) */
                    gen_vfp_mul(dp);
                    gen_mov_F1_vreg(dp, rd);
                    gen_vfp_sub(dp);
                    break;
                case 3: /* nmsc: -fd - (fn * fm)  */
                    gen_vfp_mul(dp);
                    gen_vfp_neg(dp);
P
pbrook 已提交
3044 3045
                    gen_mov_F1_vreg(dp, rd);
                    gen_vfp_sub(dp);
B
bellard 已提交
3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062
                    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 已提交
3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074
                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 已提交
3075
                        tcg_gen_movi_i64(cpu_F0d, ((uint64_t)n) << 32);
P
pbrook 已提交
3076 3077 3078 3079 3080 3081
                    } else {
                        if (i & 0x40)
                            i |= 0x780;
                        else
                            i |= 0x800;
                        n |= i << 19;
B
balrog 已提交
3082
                        tcg_gen_movi_i32(cpu_F0s, n);
P
pbrook 已提交
3083 3084
                    }
                    break;
B
bellard 已提交
3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113
                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 已提交
3114
                            gen_helper_vfp_fcvtsd(cpu_F0s, cpu_F0d, cpu_env);
B
bellard 已提交
3115
                        else
P
pbrook 已提交
3116
                            gen_helper_vfp_fcvtds(cpu_F0d, cpu_F0s, cpu_env);
B
bellard 已提交
3117 3118 3119 3120 3121 3122 3123
                        break;
                    case 16: /* fuito */
                        gen_vfp_uito(dp);
                        break;
                    case 17: /* fsito */
                        gen_vfp_sito(dp);
                        break;
P
pbrook 已提交
3124 3125 3126
                    case 20: /* fshto */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
P
pbrook 已提交
3127
                        gen_vfp_shto(dp, 16 - rm);
P
pbrook 已提交
3128 3129 3130 3131
                        break;
                    case 21: /* fslto */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
P
pbrook 已提交
3132
                        gen_vfp_slto(dp, 32 - rm);
P
pbrook 已提交
3133 3134 3135 3136
                        break;
                    case 22: /* fuhto */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
P
pbrook 已提交
3137
                        gen_vfp_uhto(dp, 16 - rm);
P
pbrook 已提交
3138 3139 3140 3141
                        break;
                    case 23: /* fulto */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
P
pbrook 已提交
3142
                        gen_vfp_ulto(dp, 32 - rm);
P
pbrook 已提交
3143
                        break;
B
bellard 已提交
3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155
                    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 已提交
3156 3157 3158
                    case 28: /* ftosh */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
P
pbrook 已提交
3159
                        gen_vfp_tosh(dp, 16 - rm);
P
pbrook 已提交
3160 3161 3162 3163
                        break;
                    case 29: /* ftosl */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
P
pbrook 已提交
3164
                        gen_vfp_tosl(dp, 32 - rm);
P
pbrook 已提交
3165 3166 3167 3168
                        break;
                    case 30: /* ftouh */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
P
pbrook 已提交
3169
                        gen_vfp_touh(dp, 16 - rm);
P
pbrook 已提交
3170 3171 3172 3173
                        break;
                    case 31: /* ftoul */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
P
pbrook 已提交
3174
                        gen_vfp_toul(dp, 32 - rm);
P
pbrook 已提交
3175
                        break;
B
bellard 已提交
3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236
                    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 已提交
3237
        if (dp && (insn & 0x03e00000) == 0x00400000) {
B
bellard 已提交
3238 3239 3240 3241
            /* two-register transfer */
            rn = (insn >> 16) & 0xf;
            rd = (insn >> 12) & 0xf;
            if (dp) {
P
pbrook 已提交
3242 3243 3244 3245
                VFP_DREG_M(rm, insn);
            } else {
                rm = VFP_SREG_M(insn);
            }
B
bellard 已提交
3246

3247
            if (insn & ARM_CP_RW_BIT) {
B
bellard 已提交
3248 3249
                /* vfp->arm */
                if (dp) {
P
pbrook 已提交
3250 3251 3252 3253 3254 3255
                    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 已提交
3256 3257
                } else {
                    gen_mov_F0_vreg(0, rm);
P
pbrook 已提交
3258 3259
                    tmp = gen_vfp_mrs();
                    store_reg(s, rn, tmp);
B
bellard 已提交
3260
                    gen_mov_F0_vreg(0, rm + 1);
P
pbrook 已提交
3261 3262
                    tmp = gen_vfp_mrs();
                    store_reg(s, rd, tmp);
B
bellard 已提交
3263 3264 3265 3266
                }
            } else {
                /* arm->vfp */
                if (dp) {
P
pbrook 已提交
3267 3268 3269 3270 3271 3272
                    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 已提交
3273
                } else {
P
pbrook 已提交
3274 3275
                    tmp = load_reg(s, rn);
                    gen_vfp_msr(tmp);
B
bellard 已提交
3276
                    gen_mov_vreg_F0(0, rm);
P
pbrook 已提交
3277 3278
                    tmp = load_reg(s, rd);
                    gen_vfp_msr(tmp);
B
bellard 已提交
3279 3280 3281 3282 3283 3284 3285
                    gen_mov_vreg_F0(0, rm + 1);
                }
            }
        } else {
            /* Load/store */
            rn = (insn >> 16) & 0xf;
            if (dp)
P
pbrook 已提交
3286
                VFP_DREG_D(rd, insn);
B
bellard 已提交
3287
            else
P
pbrook 已提交
3288 3289 3290 3291 3292 3293
                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 已提交
3294 3295 3296 3297 3298 3299 3300
            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 已提交
3301
                    gen_vfp_ld(s, dp);
B
bellard 已提交
3302 3303 3304
                    gen_mov_vreg_F0(dp, rd);
                } else {
                    gen_mov_F0_vreg(dp, rd);
B
bellard 已提交
3305
                    gen_vfp_st(s, dp);
B
bellard 已提交
3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321
                }
            } 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++) {
3322
                    if (insn & ARM_CP_RW_BIT) {
B
bellard 已提交
3323
                        /* load */
B
bellard 已提交
3324
                        gen_vfp_ld(s, dp);
B
bellard 已提交
3325 3326 3327 3328
                        gen_mov_vreg_F0(dp, rd + i);
                    } else {
                        /* store */
                        gen_mov_F0_vreg(dp, rd + i);
B
bellard 已提交
3329
                        gen_vfp_st(s, dp);
B
bellard 已提交
3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355
                    }
                    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;
}

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

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

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

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

/* Return the mask of PSR bits set by a MSR instruction.  */
P
pbrook 已提交
3398
static uint32_t msr_mask(CPUState *env, DisasContext *s, int flags, int spsr) {
B
bellard 已提交
3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409
    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 已提交
3410

P
pbrook 已提交
3411
    /* Mask out undefined bits.  */
P
pbrook 已提交
3412 3413
    mask &= ~CPSR_RESERVED;
    if (!arm_feature(env, ARM_FEATURE_V6))
P
pbrook 已提交
3414
        mask &= ~(CPSR_E | CPSR_GE);
P
pbrook 已提交
3415
    if (!arm_feature(env, ARM_FEATURE_THUMB2))
P
pbrook 已提交
3416
        mask &= ~CPSR_IT;
P
pbrook 已提交
3417
    /* Mask out execution state bits.  */
P
pbrook 已提交
3418
    if (!spsr)
P
pbrook 已提交
3419
        mask &= ~CPSR_EXEC;
B
bellard 已提交
3420 3421
    /* Mask out privileged bits.  */
    if (IS_USER(s))
P
pbrook 已提交
3422
        mask &= CPSR_USER;
B
bellard 已提交
3423 3424 3425 3426 3427 3428
    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 已提交
3429
    TCGv tmp;
B
bellard 已提交
3430 3431 3432 3433
    if (spsr) {
        /* ??? This is also undefined in system mode.  */
        if (IS_USER(s))
            return 1;
P
pbrook 已提交
3434 3435 3436 3437 3438 3439

        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 已提交
3440
    } else {
P
pbrook 已提交
3441
        gen_set_cpsr(cpu_T[0], mask);
B
bellard 已提交
3442 3443 3444 3445 3446
    }
    gen_lookup_tb(s);
    return 0;
}

P
pbrook 已提交
3447
/* Generate an old-style exception return.  */
B
bellard 已提交
3448 3449
static void gen_exception_return(DisasContext *s)
{
P
pbrook 已提交
3450
    TCGv tmp;
3451
    gen_movl_reg_T0(s, 15);
P
pbrook 已提交
3452 3453 3454
    tmp = load_cpu_field(spsr);
    gen_set_cpsr(tmp, 0xffffffff);
    dead_tmp(tmp);
B
bellard 已提交
3455 3456 3457
    s->is_jmp = DISAS_UPDATE;
}

P
pbrook 已提交
3458 3459
/* Generate a v6 exception return.  Marks both values as dead.  */
static void gen_rfe(DisasContext *s, TCGv pc, TCGv cpsr)
B
bellard 已提交
3460
{
P
pbrook 已提交
3461 3462 3463
    gen_set_cpsr(cpsr, 0xffffffff);
    dead_tmp(cpsr);
    store_reg(s, 15, pc);
P
pbrook 已提交
3464 3465
    s->is_jmp = DISAS_UPDATE;
}
3466

P
pbrook 已提交
3467 3468 3469 3470
static inline void
gen_set_condexec (DisasContext *s)
{
    if (s->condexec_mask) {
P
pbrook 已提交
3471 3472 3473
        uint32_t val = (s->condexec_cond << 4) | (s->condexec_mask >> 1);
        TCGv tmp = new_tmp();
        tcg_gen_movi_i32(tmp, val);
P
pbrook 已提交
3474
        store_cpu_field(tmp, condexec_bits);
P
pbrook 已提交
3475 3476
    }
}
3477

P
pbrook 已提交
3478 3479 3480 3481
static void gen_nop_hint(DisasContext *s, int val)
{
    switch (val) {
    case 3: /* wfi */
P
pbrook 已提交
3482
        gen_set_pc_im(s->pc);
P
pbrook 已提交
3483 3484 3485 3486 3487 3488 3489 3490 3491
        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 已提交
3492

P
pbrook 已提交
3493 3494 3495 3496 3497
/* 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 已提交
3498

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

static inline int gen_neon_add(int size)
{
    switch (size) {
P
pbrook 已提交
3504 3505
    case 0: gen_helper_neon_add_u8(CPU_T001); break;
    case 1: gen_helper_neon_add_u16(CPU_T001); break;
P
pbrook 已提交
3506 3507 3508 3509 3510 3511
    case 2: gen_op_addl_T0_T1(); break;
    default: return 1;
    }
    return 0;
}

P
pbrook 已提交
3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555
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 已提交
3556 3557 3558

#define GEN_NEON_INTEGER_OP(name) do { \
    switch ((size << 1) | u) { \
P
pbrook 已提交
3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576
    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 已提交
3577 3578 3579 3580 3581 3582 3583 3584 3585
    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 已提交
3586
  tcg_gen_st_i32(cpu_T[0], cpu_env, offset);
P
pbrook 已提交
3587 3588 3589 3590 3591 3592 3593 3594
}

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

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

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

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

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

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

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 已提交
3623
            gen_neon_dup_low16(cpu_T[0]);
P
pbrook 已提交
3624
        else
P
pbrook 已提交
3625
            gen_neon_dup_high16(cpu_T[0]);
P
pbrook 已提交
3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636
    }
}

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 已提交
3637 3638
        case 0: gen_helper_neon_unzip_u8(); break;
        case 1: gen_helper_neon_zip_u16(); break; /* zip and unzip are the same.  */
P
pbrook 已提交
3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679
        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 已提交
3680
    TCGv tmp;
P
pbrook 已提交
3681
    TCGv tmp2;
P
pbrook 已提交
3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709

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

        base = load_reg(s, rn);
P
pbrook 已提交
3872
        if (rm == 13) {
P
pbrook 已提交
3873
            tcg_gen_addi_i32(base, base, stride);
P
pbrook 已提交
3874
        } else {
P
pbrook 已提交
3875 3876 3877 3878
            TCGv index;
            index = load_reg(s, rm);
            tcg_gen_add_i32(base, base, index);
            dead_tmp(index);
P
pbrook 已提交
3879
        }
P
pbrook 已提交
3880
        store_reg(s, rn, base);
P
pbrook 已提交
3881 3882 3883
    }
    return 0;
}
3884

P
pbrook 已提交
3885 3886 3887 3888 3889 3890 3891 3892
/* 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 已提交
3893
static inline void gen_neon_narrow(int size, TCGv dest, TCGv_i64 src)
P
pbrook 已提交
3894 3895 3896 3897 3898 3899 3900 3901 3902
{
    switch (size) {
    case 0: gen_helper_neon_narrow_u8(dest, src); break;
    case 1: gen_helper_neon_narrow_u16(dest, src); break;
    case 2: tcg_gen_trunc_i64_i32(dest, src); break;
    default: abort();
    }
}

P
pbrook 已提交
3903
static inline void gen_neon_narrow_sats(int size, TCGv dest, TCGv_i64 src)
P
pbrook 已提交
3904 3905 3906 3907 3908 3909 3910 3911 3912
{
    switch (size) {
    case 0: gen_helper_neon_narrow_sat_s8(dest, cpu_env, src); break;
    case 1: gen_helper_neon_narrow_sat_s16(dest, cpu_env, src); break;
    case 2: gen_helper_neon_narrow_sat_s32(dest, cpu_env, src); break;
    default: abort();
    }
}

P
pbrook 已提交
3913
static inline void gen_neon_narrow_satu(int size, TCGv dest, TCGv_i64 src)
P
pbrook 已提交
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
{
    switch (size) {
    case 0: gen_helper_neon_narrow_sat_u8(dest, cpu_env, src); break;
    case 1: gen_helper_neon_narrow_sat_u16(dest, cpu_env, src); break;
    case 2: gen_helper_neon_narrow_sat_u32(dest, cpu_env, src); break;
    default: abort();
    }
}

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

P
pbrook 已提交
3957
static inline void gen_neon_widen(TCGv_i64 dest, TCGv src, int size, int u)
P
pbrook 已提交
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
{
    if (u) {
        switch (size) {
        case 0: gen_helper_neon_widen_u8(dest, src); break;
        case 1: gen_helper_neon_widen_u16(dest, src); break;
        case 2: tcg_gen_extu_i32_i64(dest, src); break;
        default: abort();
        }
    } else {
        switch (size) {
        case 0: gen_helper_neon_widen_s8(dest, src); break;
        case 1: gen_helper_neon_widen_s16(dest, src); break;
        case 2: tcg_gen_ext_i32_i64(dest, src); break;
        default: abort();
        }
    }
    dead_tmp(src);
}

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

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

P
pbrook 已提交
3997
static inline void gen_neon_negl(TCGv_i64 var, int size)
P
pbrook 已提交
3998 3999 4000 4001 4002 4003 4004 4005 4006
{
    switch (size) {
    case 0: gen_helper_neon_negl_u16(var, var); break;
    case 1: gen_helper_neon_negl_u32(var, var); break;
    case 2: gen_helper_neon_negl_u64(var, var); break;
    default: abort();
    }
}

P
pbrook 已提交
4007
static inline void gen_neon_addl_saturate(TCGv_i64 op0, TCGv_i64 op1, int size)
P
pbrook 已提交
4008 4009 4010 4011 4012 4013 4014 4015
{
    switch (size) {
    case 1: gen_helper_neon_addl_saturate_s32(op0, cpu_env, op0, op1); break;
    case 2: gen_helper_neon_addl_saturate_s64(op0, cpu_env, op0, op1); break;
    default: abort();
    }
}

P
pbrook 已提交
4016
static inline void gen_neon_mull(TCGv_i64 dest, TCGv a, TCGv b, int size, int u)
P
pbrook 已提交
4017
{
P
pbrook 已提交
4018
    TCGv_i64 tmp;
P
pbrook 已提交
4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040

    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 已提交
4041 4042
/* Translate a NEON data processing instruction.  Return nonzero if the
   instruction is invalid.
P
pbrook 已提交
4043 4044
   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 已提交
4045

P
pbrook 已提交
4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058
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 已提交
4059 4060 4061
    TCGv tmp;
    TCGv tmp2;
    TCGv tmp3;
P
pbrook 已提交
4062
    TCGv_i64 tmp64;
P
pbrook 已提交
4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074

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

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

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

                    gen_neon_widen(cpu_V0, tmp, size, u);
P
pbrook 已提交
4684 4685 4686

                    if (shift != 0) {
                        /* The shift is less than the width of the source
P
pbrook 已提交
4687 4688 4689 4690 4691 4692 4693 4694 4695
                           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 已提交
4696
                            }
P
pbrook 已提交
4697 4698
                            imm64 = imm | (((uint64_t)imm) << 32);
                            tcg_gen_andi_i64(cpu_V0, cpu_V0, imm64);
P
pbrook 已提交
4699 4700
                        }
                    }
P
pbrook 已提交
4701
                    neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
4702 4703 4704 4705
                }
            } else if (op == 15 || op == 16) {
                /* VCVT fixed-point.  */
                for (pass = 0; pass < (q ? 4 : 2); pass++) {
P
pbrook 已提交
4706
                    tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, pass));
P
pbrook 已提交
4707 4708
                    if (op & 1) {
                        if (u)
P
pbrook 已提交
4709
                            gen_vfp_ulto(0, shift);
P
pbrook 已提交
4710
                        else
P
pbrook 已提交
4711
                            gen_vfp_slto(0, shift);
P
pbrook 已提交
4712 4713
                    } else {
                        if (u)
P
pbrook 已提交
4714
                            gen_vfp_toul(0, shift);
P
pbrook 已提交
4715
                        else
P
pbrook 已提交
4716
                            gen_vfp_tosl(0, shift);
B
bellard 已提交
4717
                    }
P
pbrook 已提交
4718
                    tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, pass));
B
bellard 已提交
4719 4720
                }
            } else {
P
pbrook 已提交
4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772
                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 已提交
4773
                    tmp = neon_load_reg(rd, pass);
P
pbrook 已提交
4774 4775 4776
                    if (invert) {
                        /* The immediate value has already been inverted, so
                           BIC becomes AND.  */
P
pbrook 已提交
4777
                        tcg_gen_andi_i32(tmp, tmp, imm);
P
pbrook 已提交
4778
                    } else {
P
pbrook 已提交
4779
                        tcg_gen_ori_i32(tmp, tmp, imm);
P
pbrook 已提交
4780 4781
                    }
                } else {
P
pbrook 已提交
4782 4783
                    /* VMOV, VMVN.  */
                    tmp = new_tmp();
P
pbrook 已提交
4784
                    if (op == 14 && invert) {
P
pbrook 已提交
4785 4786
                        uint32_t val;
                        val = 0;
P
pbrook 已提交
4787 4788
                        for (n = 0; n < 4; n++) {
                            if (imm & (1 << (n + (pass & 1) * 4)))
P
pbrook 已提交
4789
                                val |= 0xff << (n * 8);
P
pbrook 已提交
4790
                        }
P
pbrook 已提交
4791 4792 4793
                        tcg_gen_movi_i32(tmp, val);
                    } else {
                        tcg_gen_movi_i32(tmp, imm);
P
pbrook 已提交
4794 4795
                    }
                }
P
pbrook 已提交
4796
                neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
4797 4798
            }
        }
P
pbrook 已提交
4799
    } else { /* (insn & 0x00800010 == 0x00800000) */
P
pbrook 已提交
4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829
        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 已提交
4830 4831 4832
                if (size == 0 && (op == 9 || op == 11 || op == 13))
                    return 1;

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

                        if (op != 13) {
P
pbrook 已提交
4924
                            neon_load_reg64(cpu_V1, rd + pass);
P
pbrook 已提交
4925 4926 4927 4928
                        }

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

P
pbrook 已提交
5058
                    gen_neon_get_scalar(size, rm);
P
pbrook 已提交
5059 5060
                    NEON_GET_REG(T1, rn, 1);

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

5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603
static int disas_cp14_read(CPUState * env, DisasContext *s, uint32_t insn)
{
    int crn = (insn >> 16) & 0xf;
    int crm = insn & 0xf;
    int op1 = (insn >> 21) & 7;
    int op2 = (insn >> 5) & 7;
    int rt = (insn >> 12) & 0xf;
    TCGv tmp;

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

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

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

P
pbrook 已提交
5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624
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);
5625 5626 5627 5628 5629 5630 5631 5632 5633
    case 14:
        /* Coprocessors 7-15 are architecturally reserved by ARM.
           Unfortunately Intel decided to ignore this.  */
        if (arm_feature(env, ARM_FEATURE_XSCALE))
            goto board;
        if (insn & (1 << 20))
            return disas_cp14_read(env, s, insn);
        else
            return disas_cp14_write(env, s, insn);
P
pbrook 已提交
5634 5635 5636
    case 15:
	return disas_cp15_insn (env, s, insn);
    default:
5637
    board:
P
pbrook 已提交
5638 5639 5640 5641 5642
	/* Unknown coprocessor.  See if the board has hooked it.  */
	return disas_cp_insn (env, s, insn);
    }
}

P
pbrook 已提交
5643 5644

/* Store a 64-bit value to a register pair.  Clobbers val.  */
P
pbrook 已提交
5645
static void gen_storeq_reg(DisasContext *s, int rlow, int rhigh, TCGv_i64 val)
P
pbrook 已提交
5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657
{
    TCGv tmp;
    tmp = new_tmp();
    tcg_gen_trunc_i64_i32(tmp, val);
    store_reg(s, rlow, tmp);
    tmp = new_tmp();
    tcg_gen_shri_i64(val, val, 32);
    tcg_gen_trunc_i64_i32(tmp, val);
    store_reg(s, rhigh, tmp);
}

/* load a 32-bit value from a register and perform a 64-bit accumulate.  */
P
pbrook 已提交
5658
static void gen_addq_lo(DisasContext *s, TCGv_i64 val, int rlow)
P
pbrook 已提交
5659
{
P
pbrook 已提交
5660
    TCGv_i64 tmp;
P
pbrook 已提交
5661 5662
    TCGv tmp2;

P
pbrook 已提交
5663
    /* Load value and extend to 64 bits.  */
P
pbrook 已提交
5664
    tmp = tcg_temp_new_i64();
P
pbrook 已提交
5665 5666 5667 5668 5669 5670 5671
    tmp2 = load_reg(s, rlow);
    tcg_gen_extu_i32_i64(tmp, tmp2);
    dead_tmp(tmp2);
    tcg_gen_add_i64(val, val, tmp);
}

/* load and add a 64-bit value from a register pair.  */
P
pbrook 已提交
5672
static void gen_addq(DisasContext *s, TCGv_i64 val, int rlow, int rhigh)
P
pbrook 已提交
5673
{
P
pbrook 已提交
5674
    TCGv_i64 tmp;
P
pbrook 已提交
5675 5676
    TCGv tmpl;
    TCGv tmph;
P
pbrook 已提交
5677 5678

    /* Load 64-bit value rd:rn.  */
P
pbrook 已提交
5679 5680
    tmpl = load_reg(s, rlow);
    tmph = load_reg(s, rhigh);
P
pbrook 已提交
5681
    tmp = tcg_temp_new_i64();
P
pbrook 已提交
5682 5683 5684
    tcg_gen_concat_i32_i64(tmp, tmpl, tmph);
    dead_tmp(tmpl);
    dead_tmp(tmph);
P
pbrook 已提交
5685 5686 5687 5688
    tcg_gen_add_i64(val, val, tmp);
}

/* Set N and Z flags from a 64-bit value.  */
P
pbrook 已提交
5689
static void gen_logicq_cc(TCGv_i64 val)
P
pbrook 已提交
5690 5691 5692
{
    TCGv tmp = new_tmp();
    gen_helper_logicq_cc(tmp, val);
P
pbrook 已提交
5693 5694
    gen_logic_CC(tmp);
    dead_tmp(tmp);
P
pbrook 已提交
5695 5696
}

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

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

            val = (uint32_t)s->pc;
P
pbrook 已提交
5849 5850 5851
            tmp = new_tmp();
            tcg_gen_movi_i32(tmp, val);
            store_reg(s, 14, tmp);
P
pbrook 已提交
5852 5853 5854 5855 5856 5857
            /* 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 已提交
5858
            gen_bx_im(s, val);
P
pbrook 已提交
5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870
            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 已提交
5871
        } else if ((insn & 0x0ff10020) == 0x01000000) {
P
pbrook 已提交
5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887
            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 已提交
5888
            if (insn & (1 << 17)) {
P
pbrook 已提交
5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901 5902 5903
                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 已提交
5904
        gen_test_cc(cond ^ 1, s->condlabel);
P
pbrook 已提交
5905 5906 5907 5908 5909 5910 5911 5912 5913
        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 已提交
5914 5915
                tmp = new_tmp();
                tcg_gen_movi_i32(tmp, val);
P
pbrook 已提交
5916 5917
            } else {
                /* MOVT */
P
pbrook 已提交
5918
                tmp = load_reg(s, rd);
P
pbrook 已提交
5919
                tcg_gen_ext16u_i32(tmp, tmp);
P
pbrook 已提交
5920
                tcg_gen_ori_i32(tmp, tmp, val << 16);
P
pbrook 已提交
5921
            }
P
pbrook 已提交
5922
            store_reg(s, rd, tmp);
P
pbrook 已提交
5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959
        } 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 已提交
5960
                    tmp = load_cpu_field(spsr);
P
pbrook 已提交
5961
                } else {
P
pbrook 已提交
5962 5963
                    tmp = new_tmp();
                    gen_helper_cpsr_read(tmp);
P
pbrook 已提交
5964
                }
P
pbrook 已提交
5965
                store_reg(s, rd, tmp);
P
pbrook 已提交
5966 5967 5968 5969 5970
            }
            break;
        case 0x1:
            if (op1 == 1) {
                /* branch/exchange thumb (bx).  */
P
pbrook 已提交
5971 5972
                tmp = load_reg(s, rm);
                gen_bx(s, tmp);
P
pbrook 已提交
5973 5974 5975
            } else if (op1 == 3) {
                /* clz */
                rd = (insn >> 12) & 0xf;
P
pbrook 已提交
5976 5977 5978
                tmp = load_reg(s, rm);
                gen_helper_clz(tmp, tmp);
                store_reg(s, rd, tmp);
P
pbrook 已提交
5979 5980 5981 5982 5983 5984 5985 5986
            } else {
                goto illegal_op;
            }
            break;
        case 0x2:
            if (op1 == 1) {
                ARCH(5J); /* bxj */
                /* Trivial implementation equivalent to bx.  */
P
pbrook 已提交
5987 5988
                tmp = load_reg(s, rm);
                gen_bx(s, tmp);
P
pbrook 已提交
5989 5990 5991 5992 5993 5994 5995 5996 5997
            } else {
                goto illegal_op;
            }
            break;
        case 0x3:
            if (op1 != 1)
              goto illegal_op;

            /* branch link/exchange thumb (blx) */
P
pbrook 已提交
5998 5999 6000 6001 6002
            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 已提交
6003 6004 6005 6006
            break;
        case 0x5: /* saturating add/subtract */
            rd = (insn >> 12) & 0xf;
            rn = (insn >> 16) & 0xf;
6007
            tmp = load_reg(s, rm);
P
pbrook 已提交
6008
            tmp2 = load_reg(s, rn);
P
pbrook 已提交
6009
            if (op1 & 2)
P
pbrook 已提交
6010
                gen_helper_double_saturate(tmp2, tmp2);
P
pbrook 已提交
6011
            if (op1 & 1)
P
pbrook 已提交
6012
                gen_helper_sub_saturate(tmp, tmp, tmp2);
P
pbrook 已提交
6013
            else
P
pbrook 已提交
6014 6015 6016
                gen_helper_add_saturate(tmp, tmp, tmp2);
            dead_tmp(tmp2);
            store_reg(s, rd, tmp);
P
pbrook 已提交
6017 6018 6019
            break;
        case 7: /* bkpt */
            gen_set_condexec(s);
P
pbrook 已提交
6020
            gen_set_pc_im(s->pc - 4);
P
pbrook 已提交
6021
            gen_exception(EXCP_BKPT);
P
pbrook 已提交
6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032
            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 已提交
6033 6034
                tmp = load_reg(s, rm);
                tmp2 = load_reg(s, rs);
P
pbrook 已提交
6035
                if (sh & 4)
P
pbrook 已提交
6036
                    tcg_gen_sari_i32(tmp2, tmp2, 16);
P
pbrook 已提交
6037
                else
P
pbrook 已提交
6038
                    gen_sxth(tmp2);
P
pbrook 已提交
6039 6040
                tmp64 = gen_muls_i64_i32(tmp, tmp2);
                tcg_gen_shri_i64(tmp64, tmp64, 16);
P
pbrook 已提交
6041
                tmp = new_tmp();
P
pbrook 已提交
6042
                tcg_gen_trunc_i64_i32(tmp, tmp64);
P
pbrook 已提交
6043
                if ((sh & 2) == 0) {
P
pbrook 已提交
6044 6045 6046
                    tmp2 = load_reg(s, rn);
                    gen_helper_add_setq(tmp, tmp, tmp2);
                    dead_tmp(tmp2);
P
pbrook 已提交
6047
                }
P
pbrook 已提交
6048
                store_reg(s, rd, tmp);
P
pbrook 已提交
6049 6050
            } else {
                /* 16 * 16 */
P
pbrook 已提交
6051 6052 6053 6054
                tmp = load_reg(s, rm);
                tmp2 = load_reg(s, rs);
                gen_mulxy(tmp, tmp2, sh & 2, sh & 4);
                dead_tmp(tmp2);
P
pbrook 已提交
6055
                if (op1 == 2) {
P
pbrook 已提交
6056 6057
                    tmp64 = tcg_temp_new_i64();
                    tcg_gen_ext_i32_i64(tmp64, tmp);
6058
                    dead_tmp(tmp);
P
pbrook 已提交
6059 6060
                    gen_addq(s, tmp64, rn, rd);
                    gen_storeq_reg(s, rn, rd, tmp64);
P
pbrook 已提交
6061 6062
                } else {
                    if (op1 == 0) {
P
pbrook 已提交
6063 6064 6065
                        tmp2 = load_reg(s, rn);
                        gen_helper_add_setq(tmp, tmp, tmp2);
                        dead_tmp(tmp2);
P
pbrook 已提交
6066
                    }
P
pbrook 已提交
6067
                    store_reg(s, rd, tmp);
P
pbrook 已提交
6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091
                }
            }
            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 已提交
6092
                gen_set_CF_bit31(cpu_T[1]);
P
pbrook 已提交
6093 6094 6095 6096 6097 6098 6099
        } 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 已提交
6100
                gen_arm_shift_im(cpu_T[1], shiftop, shift, logic_cc);
P
pbrook 已提交
6101 6102
            } else {
                rs = (insn >> 8) & 0xf;
P
pbrook 已提交
6103 6104
                tmp = load_reg(s, rs);
                gen_arm_shift_reg(cpu_T[1], shiftop, tmp, logic_cc);
P
pbrook 已提交
6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 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
            }
        }
        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 已提交
6158
                gen_adc_T0_T1();
P
pbrook 已提交
6159 6160 6161 6162 6163 6164
            gen_movl_reg_T0(s, rd);
            break;
        case 0x06:
            if (set_cc)
                gen_op_sbcl_T0_T1_cc();
            else
P
pbrook 已提交
6165
                gen_sbc_T0_T1();
P
pbrook 已提交
6166 6167 6168 6169 6170 6171
            gen_movl_reg_T0(s, rd);
            break;
        case 0x07:
            if (set_cc)
                gen_op_rscl_T0_T1_cc();
            else
P
pbrook 已提交
6172
                gen_rsc_T0_T1();
P
pbrook 已提交
6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247
            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 已提交
6248 6249 6250 6251
                        tmp = load_reg(s, rs);
                        tmp2 = load_reg(s, rm);
                        tcg_gen_mul_i32(tmp, tmp, tmp2);
                        dead_tmp(tmp2);
P
pbrook 已提交
6252 6253 6254
                        if (insn & (1 << 22)) {
                            /* Subtract (mls) */
                            ARCH(6T2);
P
pbrook 已提交
6255 6256 6257
                            tmp2 = load_reg(s, rn);
                            tcg_gen_sub_i32(tmp, tmp2, tmp);
                            dead_tmp(tmp2);
P
pbrook 已提交
6258 6259
                        } else if (insn & (1 << 21)) {
                            /* Add */
P
pbrook 已提交
6260 6261 6262
                            tmp2 = load_reg(s, rn);
                            tcg_gen_add_i32(tmp, tmp, tmp2);
                            dead_tmp(tmp2);
P
pbrook 已提交
6263 6264
                        }
                        if (insn & (1 << 20))
P
pbrook 已提交
6265 6266
                            gen_logic_CC(tmp);
                        store_reg(s, rd, tmp);
P
pbrook 已提交
6267 6268 6269
                        break;
                    default:
                        /* 64 bit mul */
P
pbrook 已提交
6270 6271
                        tmp = load_reg(s, rs);
                        tmp2 = load_reg(s, rm);
P
pbrook 已提交
6272
                        if (insn & (1 << 22))
P
pbrook 已提交
6273
                            tmp64 = gen_muls_i64_i32(tmp, tmp2);
P
pbrook 已提交
6274
                        else
P
pbrook 已提交
6275
                            tmp64 = gen_mulu_i64_i32(tmp, tmp2);
P
pbrook 已提交
6276
                        if (insn & (1 << 21)) /* mult accumulate */
P
pbrook 已提交
6277
                            gen_addq(s, tmp64, rn, rd);
P
pbrook 已提交
6278 6279
                        if (!(insn & (1 << 23))) { /* double accumulate */
                            ARCH(6);
P
pbrook 已提交
6280 6281
                            gen_addq_lo(s, tmp64, rn);
                            gen_addq_lo(s, tmp64, rd);
P
pbrook 已提交
6282 6283
                        }
                        if (insn & (1 << 20))
P
pbrook 已提交
6284 6285
                            gen_logicq_cc(tmp64);
                        gen_storeq_reg(s, rn, rd, tmp64);
P
pbrook 已提交
6286 6287 6288 6289 6290 6291 6292
                        break;
                    }
                } else {
                    rn = (insn >> 16) & 0xf;
                    rd = (insn >> 12) & 0xf;
                    if (insn & (1 << 23)) {
                        /* load/store exclusive */
P
pbrook 已提交
6293 6294
                        op1 = (insn >> 21) & 0x3;
                        if (op1)
6295
                            ARCH(6K);
P
pbrook 已提交
6296 6297
                        else
                            ARCH(6);
P
pbrook 已提交
6298
                        gen_movl_T1_reg(s, rn);
B
balrog 已提交
6299
                        addr = cpu_T[1];
P
pbrook 已提交
6300
                        if (insn & (1 << 20)) {
P
pbrook 已提交
6301
                            gen_helper_mark_exclusive(cpu_env, cpu_T[1]);
P
pbrook 已提交
6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321
                            switch (op1) {
                            case 0: /* ldrex */
                                tmp = gen_ld32(addr, IS_USER(s));
                                break;
                            case 1: /* ldrexd */
                                tmp = gen_ld32(addr, IS_USER(s));
                                store_reg(s, rd, tmp);
                                tcg_gen_addi_i32(addr, addr, 4);
                                tmp = gen_ld32(addr, IS_USER(s));
                                rd++;
                                break;
                            case 2: /* ldrexb */
                                tmp = gen_ld8u(addr, IS_USER(s));
                                break;
                            case 3: /* ldrexh */
                                tmp = gen_ld16u(addr, IS_USER(s));
                                break;
                            default:
                                abort();
                            }
P
pbrook 已提交
6322
                            store_reg(s, rd, tmp);
P
pbrook 已提交
6323
                        } else {
P
pbrook 已提交
6324
                            int label = gen_new_label();
P
pbrook 已提交
6325
                            rm = insn & 0xf;
P
pbrook 已提交
6326
                            gen_helper_test_exclusive(cpu_T[0], cpu_env, addr);
P
pbrook 已提交
6327 6328
                            tcg_gen_brcondi_i32(TCG_COND_NE, cpu_T[0],
                                                0, label);
P
pbrook 已提交
6329
                            tmp = load_reg(s,rm);
P
pbrook 已提交
6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348
                            switch (op1) {
                            case 0:  /*  strex */
                                gen_st32(tmp, addr, IS_USER(s));
                                break;
                            case 1: /*  strexd */
                                gen_st32(tmp, addr, IS_USER(s));
                                tcg_gen_addi_i32(addr, addr, 4);
                                tmp = load_reg(s, rm + 1);
                                gen_st32(tmp, addr, IS_USER(s));
                                break;
                            case 2: /*  strexb */
                                gen_st8(tmp, addr, IS_USER(s));
                                break;
                            case 3: /* strexh */
                                gen_st16(tmp, addr, IS_USER(s));
                                break;
                            default:
                                abort();
                            }
B
balrog 已提交
6349
                            gen_set_label(label);
P
pbrook 已提交
6350
                            gen_movl_reg_T0(s, rd);
P
pbrook 已提交
6351 6352 6353 6354 6355
                        }
                    } else {
                        /* SWP instruction */
                        rm = (insn) & 0xf;

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

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

    if (!(arm_feature(env, ARM_FEATURE_THUMB2)
          || arm_feature (env, ARM_FEATURE_M))) {
6993
        /* Thumb-1 cores may need to treat bl and blx as a pair of
P
pbrook 已提交
6994 6995 6996 6997 6998
           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 已提交
6999 7000 7001
            tmp = load_reg(s, 14);
            tcg_gen_addi_i32(tmp, tmp, offset);
            tcg_gen_andi_i32(tmp, tmp, 0xfffffffc);
P
pbrook 已提交
7002

P
pbrook 已提交
7003
            tmp2 = new_tmp();
P
pbrook 已提交
7004
            tcg_gen_movi_i32(tmp2, s->pc | 1);
P
pbrook 已提交
7005 7006
            store_reg(s, 14, tmp2);
            gen_bx(s, tmp);
P
pbrook 已提交
7007 7008 7009 7010 7011
            return 0;
        }
        if (insn & (1 << 11)) {
            /* Second half of bl.  */
            offset = ((insn & 0x7ff) << 1) | 1;
P
pbrook 已提交
7012
            tmp = load_reg(s, 14);
B
balrog 已提交
7013
            tcg_gen_addi_i32(tmp, tmp, offset);
P
pbrook 已提交
7014

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

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

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

P
pbrook 已提交
7996
static void disas_thumb_insn(CPUState *env, DisasContext *s)
B
bellard 已提交
7997 7998 7999 8000
{
    uint32_t val, insn, op, rm, rn, rd, shift, cond;
    int32_t offset;
    int i;
P
pbrook 已提交
8001
    TCGv tmp;
P
pbrook 已提交
8002
    TCGv tmp2;
P
pbrook 已提交
8003
    TCGv addr;
B
bellard 已提交
8004

P
pbrook 已提交
8005 8006 8007
    if (s->condexec_mask) {
        cond = s->condexec_cond;
        s->condlabel = gen_new_label();
P
pbrook 已提交
8008
        gen_test_cc(cond ^ 1, s->condlabel);
P
pbrook 已提交
8009 8010 8011
        s->condjmp = 1;
    }

B
bellard 已提交
8012
    insn = lduw_code(s->pc);
B
bellard 已提交
8013
    s->pc += 2;
B
bellard 已提交
8014

B
bellard 已提交
8015 8016 8017 8018 8019 8020 8021 8022 8023 8024 8025 8026 8027 8028 8029 8030
    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 已提交
8031 8032 8033 8034 8035 8036 8037 8038 8039 8040 8041
            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 已提交
8042 8043 8044 8045 8046
            gen_movl_reg_T0(s, rd);
        } else {
            /* shift immediate */
            rm = (insn >> 3) & 7;
            shift = (insn >> 6) & 0x1f;
P
pbrook 已提交
8047 8048 8049 8050 8051
            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 已提交
8052 8053 8054 8055 8056 8057 8058 8059 8060 8061 8062 8063 8064 8065
        }
        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 已提交
8066 8067
            if (!s->condexec_mask)
                gen_op_logic_T0_cc();
B
bellard 已提交
8068 8069 8070 8071 8072
            break;
        case 1: /* cmp */
            gen_op_subl_T0_T1_cc();
            break;
        case 2: /* add */
P
pbrook 已提交
8073 8074 8075 8076
            if (s->condexec_mask)
                gen_op_addl_T0_T1();
            else
                gen_op_addl_T0_T1_cc();
B
bellard 已提交
8077 8078
            break;
        case 3: /* sub */
P
pbrook 已提交
8079 8080 8081 8082
            if (s->condexec_mask)
                gen_op_subl_T0_T1();
            else
                gen_op_subl_T0_T1_cc();
B
bellard 已提交
8083 8084 8085 8086 8087 8088 8089 8090
            break;
        }
        if (op != 1)
            gen_movl_reg_T0(s, rd);
        break;
    case 4:
        if (insn & (1 << 11)) {
            rd = (insn >> 8) & 7;
B
bellard 已提交
8091 8092 8093
            /* load pc-relative.  Bit 1 of PC is ignored.  */
            val = s->pc + 2 + ((insn & 0xff) * 4);
            val &= ~(uint32_t)2;
P
pbrook 已提交
8094 8095 8096 8097 8098
            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 已提交
8099 8100 8101 8102 8103 8104 8105 8106 8107 8108 8109 8110 8111 8112 8113 8114 8115 8116 8117 8118 8119 8120 8121 8122
            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 已提交
8123
                tmp = load_reg(s, rm);
B
bellard 已提交
8124 8125
                if (insn & (1 << 7)) {
                    val = (uint32_t)s->pc | 1;
P
pbrook 已提交
8126 8127 8128
                    tmp2 = new_tmp();
                    tcg_gen_movi_i32(tmp2, val);
                    store_reg(s, 14, tmp2);
B
bellard 已提交
8129
                }
P
pbrook 已提交
8130
                gen_bx(s, tmp);
B
bellard 已提交
8131 8132 8133 8134 8135 8136 8137 8138 8139 8140 8141 8142 8143 8144 8145 8146 8147 8148 8149 8150 8151 8152 8153 8154 8155
                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 已提交
8156
        switch (op) {
B
bellard 已提交
8157 8158
        case 0x0: /* and */
            gen_op_andl_T0_T1();
P
pbrook 已提交
8159 8160
            if (!s->condexec_mask)
                gen_op_logic_T0_cc();
B
bellard 已提交
8161 8162 8163
            break;
        case 0x1: /* eor */
            gen_op_xorl_T0_T1();
P
pbrook 已提交
8164 8165
            if (!s->condexec_mask)
                gen_op_logic_T0_cc();
B
bellard 已提交
8166 8167
            break;
        case 0x2: /* lsl */
P
pbrook 已提交
8168
            if (s->condexec_mask) {
P
pbrook 已提交
8169
                gen_helper_shl(cpu_T[1], cpu_T[1], cpu_T[0]);
P
pbrook 已提交
8170
            } else {
P
pbrook 已提交
8171
                gen_helper_shl_cc(cpu_T[1], cpu_T[1], cpu_T[0]);
P
pbrook 已提交
8172 8173
                gen_op_logic_T1_cc();
            }
B
bellard 已提交
8174 8175
            break;
        case 0x3: /* lsr */
P
pbrook 已提交
8176
            if (s->condexec_mask) {
P
pbrook 已提交
8177
                gen_helper_shr(cpu_T[1], cpu_T[1], cpu_T[0]);
P
pbrook 已提交
8178
            } else {
P
pbrook 已提交
8179
                gen_helper_shr_cc(cpu_T[1], cpu_T[1], cpu_T[0]);
P
pbrook 已提交
8180 8181
                gen_op_logic_T1_cc();
            }
B
bellard 已提交
8182 8183
            break;
        case 0x4: /* asr */
P
pbrook 已提交
8184
            if (s->condexec_mask) {
P
pbrook 已提交
8185
                gen_helper_sar(cpu_T[1], cpu_T[1], cpu_T[0]);
P
pbrook 已提交
8186
            } else {
P
pbrook 已提交
8187
                gen_helper_sar_cc(cpu_T[1], cpu_T[1], cpu_T[0]);
P
pbrook 已提交
8188 8189
                gen_op_logic_T1_cc();
            }
B
bellard 已提交
8190 8191
            break;
        case 0x5: /* adc */
P
pbrook 已提交
8192
            if (s->condexec_mask)
P
pbrook 已提交
8193
                gen_adc_T0_T1();
P
pbrook 已提交
8194 8195
            else
                gen_op_adcl_T0_T1_cc();
B
bellard 已提交
8196 8197
            break;
        case 0x6: /* sbc */
P
pbrook 已提交
8198
            if (s->condexec_mask)
P
pbrook 已提交
8199
                gen_sbc_T0_T1();
P
pbrook 已提交
8200 8201
            else
                gen_op_sbcl_T0_T1_cc();
B
bellard 已提交
8202 8203
            break;
        case 0x7: /* ror */
P
pbrook 已提交
8204
            if (s->condexec_mask) {
P
pbrook 已提交
8205
                gen_helper_ror(cpu_T[1], cpu_T[1], cpu_T[0]);
P
pbrook 已提交
8206
            } else {
P
pbrook 已提交
8207
                gen_helper_ror_cc(cpu_T[1], cpu_T[1], cpu_T[0]);
P
pbrook 已提交
8208 8209
                gen_op_logic_T1_cc();
            }
B
bellard 已提交
8210 8211 8212 8213 8214
            break;
        case 0x8: /* tst */
            gen_op_andl_T0_T1();
            gen_op_logic_T0_cc();
            rd = 16;
B
bellard 已提交
8215
            break;
B
bellard 已提交
8216
        case 0x9: /* neg */
P
pbrook 已提交
8217
            if (s->condexec_mask)
P
pbrook 已提交
8218
                tcg_gen_neg_i32(cpu_T[0], cpu_T[1]);
P
pbrook 已提交
8219 8220
            else
                gen_op_subl_T0_T1_cc();
B
bellard 已提交
8221 8222 8223 8224 8225 8226 8227 8228 8229 8230 8231
            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 已提交
8232 8233
            if (!s->condexec_mask)
                gen_op_logic_T0_cc();
B
bellard 已提交
8234 8235 8236
            break;
        case 0xd: /* mul */
            gen_op_mull_T0_T1();
P
pbrook 已提交
8237 8238
            if (!s->condexec_mask)
                gen_op_logic_T0_cc();
B
bellard 已提交
8239 8240 8241
            break;
        case 0xe: /* bic */
            gen_op_bicl_T0_T1();
P
pbrook 已提交
8242 8243
            if (!s->condexec_mask)
                gen_op_logic_T0_cc();
B
bellard 已提交
8244 8245 8246
            break;
        case 0xf: /* mvn */
            gen_op_notl_T1();
P
pbrook 已提交
8247 8248
            if (!s->condexec_mask)
                gen_op_logic_T1_cc();
B
bellard 已提交
8249
            val = 1;
B
bellard 已提交
8250
            rm = rd;
B
bellard 已提交
8251 8252 8253 8254
            break;
        }
        if (rd != 16) {
            if (val)
B
bellard 已提交
8255
                gen_movl_reg_T1(s, rm);
B
bellard 已提交
8256 8257 8258 8259 8260 8261 8262 8263 8264 8265 8266
            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 已提交
8267
        addr = load_reg(s, rn);
P
pbrook 已提交
8268
        tmp = load_reg(s, rm);
P
pbrook 已提交
8269
        tcg_gen_add_i32(addr, addr, tmp);
P
pbrook 已提交
8270
        dead_tmp(tmp);
B
bellard 已提交
8271 8272

        if (op < 3) /* store */
P
pbrook 已提交
8273
            tmp = load_reg(s, rd);
B
bellard 已提交
8274 8275 8276

        switch (op) {
        case 0: /* str */
P
pbrook 已提交
8277
            gen_st32(tmp, addr, IS_USER(s));
B
bellard 已提交
8278 8279
            break;
        case 1: /* strh */
P
pbrook 已提交
8280
            gen_st16(tmp, addr, IS_USER(s));
B
bellard 已提交
8281 8282
            break;
        case 2: /* strb */
P
pbrook 已提交
8283
            gen_st8(tmp, addr, IS_USER(s));
B
bellard 已提交
8284 8285
            break;
        case 3: /* ldrsb */
P
pbrook 已提交
8286
            tmp = gen_ld8s(addr, IS_USER(s));
B
bellard 已提交
8287 8288
            break;
        case 4: /* ldr */
P
pbrook 已提交
8289
            tmp = gen_ld32(addr, IS_USER(s));
B
bellard 已提交
8290 8291
            break;
        case 5: /* ldrh */
P
pbrook 已提交
8292
            tmp = gen_ld16u(addr, IS_USER(s));
B
bellard 已提交
8293 8294
            break;
        case 6: /* ldrb */
P
pbrook 已提交
8295
            tmp = gen_ld8u(addr, IS_USER(s));
B
bellard 已提交
8296 8297
            break;
        case 7: /* ldrsh */
P
pbrook 已提交
8298
            tmp = gen_ld16s(addr, IS_USER(s));
B
bellard 已提交
8299 8300 8301
            break;
        }
        if (op >= 3) /* load */
P
pbrook 已提交
8302 8303
            store_reg(s, rd, tmp);
        dead_tmp(addr);
B
bellard 已提交
8304 8305 8306 8307 8308 8309
        break;

    case 6:
        /* load/store word immediate offset */
        rd = insn & 7;
        rn = (insn >> 3) & 7;
P
pbrook 已提交
8310
        addr = load_reg(s, rn);
B
bellard 已提交
8311
        val = (insn >> 4) & 0x7c;
P
pbrook 已提交
8312
        tcg_gen_addi_i32(addr, addr, val);
B
bellard 已提交
8313 8314 8315

        if (insn & (1 << 11)) {
            /* load */
P
pbrook 已提交
8316 8317
            tmp = gen_ld32(addr, IS_USER(s));
            store_reg(s, rd, tmp);
B
bellard 已提交
8318 8319
        } else {
            /* store */
P
pbrook 已提交
8320 8321
            tmp = load_reg(s, rd);
            gen_st32(tmp, addr, IS_USER(s));
B
bellard 已提交
8322
        }
P
pbrook 已提交
8323
        dead_tmp(addr);
B
bellard 已提交
8324 8325 8326 8327 8328 8329
        break;

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

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

    case 8:
        /* load/store halfword immediate offset */
        rd = insn & 7;
        rn = (insn >> 3) & 7;
P
pbrook 已提交
8350
        addr = load_reg(s, rn);
B
bellard 已提交
8351
        val = (insn >> 5) & 0x3e;
P
pbrook 已提交
8352
        tcg_gen_addi_i32(addr, addr, val);
B
bellard 已提交
8353 8354 8355

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

    case 9:
        /* load/store from stack */
        rd = (insn >> 8) & 7;
P
pbrook 已提交
8369
        addr = load_reg(s, 13);
B
bellard 已提交
8370
        val = (insn & 0xff) * 4;
P
pbrook 已提交
8371
        tcg_gen_addi_i32(addr, addr, val);
B
bellard 已提交
8372 8373 8374

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

    case 10:
        /* add to high reg */
        rd = (insn >> 8) & 7;
B
bellard 已提交
8388 8389
        if (insn & (1 << 11)) {
            /* SP */
P
pbrook 已提交
8390
            tmp = load_reg(s, 13);
B
bellard 已提交
8391 8392
        } else {
            /* PC. bit 1 is ignored.  */
P
pbrook 已提交
8393 8394
            tmp = new_tmp();
            tcg_gen_movi_i32(tmp, (s->pc + 2) & ~(uint32_t)2);
B
bellard 已提交
8395
        }
B
bellard 已提交
8396
        val = (insn & 0xff) * 4;
P
pbrook 已提交
8397 8398
        tcg_gen_addi_i32(tmp, tmp, val);
        store_reg(s, rd, tmp);
B
bellard 已提交
8399 8400 8401 8402 8403 8404 8405 8406
        break;

    case 11:
        /* misc */
        op = (insn >> 8) & 0xf;
        switch (op) {
        case 0:
            /* adjust stack pointer */
P
pbrook 已提交
8407
            tmp = load_reg(s, 13);
B
bellard 已提交
8408 8409
            val = (insn & 0x7f) * 4;
            if (insn & (1 << 7))
B
balrog 已提交
8410
                val = -(int32_t)val;
P
pbrook 已提交
8411 8412
            tcg_gen_addi_i32(tmp, tmp, val);
            store_reg(s, 13, tmp);
B
bellard 已提交
8413 8414
            break;

P
pbrook 已提交
8415 8416 8417 8418
        case 2: /* sign/zero extend.  */
            ARCH(6);
            rd = insn & 7;
            rm = (insn >> 3) & 7;
P
pbrook 已提交
8419
            tmp = load_reg(s, rm);
P
pbrook 已提交
8420
            switch ((insn >> 6) & 3) {
P
pbrook 已提交
8421 8422 8423 8424
            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 已提交
8425
            }
P
pbrook 已提交
8426
            store_reg(s, rd, tmp);
P
pbrook 已提交
8427
            break;
B
bellard 已提交
8428 8429
        case 4: case 5: case 0xc: case 0xd:
            /* push/pop */
P
pbrook 已提交
8430
            addr = load_reg(s, 13);
B
bellard 已提交
8431 8432
            if (insn & (1 << 8))
                offset = 4;
B
bellard 已提交
8433
            else
B
bellard 已提交
8434 8435 8436 8437 8438 8439
                offset = 0;
            for (i = 0; i < 8; i++) {
                if (insn & (1 << i))
                    offset += 4;
            }
            if ((insn & (1 << 11)) == 0) {
P
pbrook 已提交
8440
                tcg_gen_addi_i32(addr, addr, -offset);
B
bellard 已提交
8441
            }
B
bellard 已提交
8442 8443 8444 8445
            for (i = 0; i < 8; i++) {
                if (insn & (1 << i)) {
                    if (insn & (1 << 11)) {
                        /* pop */
P
pbrook 已提交
8446 8447
                        tmp = gen_ld32(addr, IS_USER(s));
                        store_reg(s, i, tmp);
B
bellard 已提交
8448 8449
                    } else {
                        /* push */
P
pbrook 已提交
8450 8451
                        tmp = load_reg(s, i);
                        gen_st32(tmp, addr, IS_USER(s));
B
bellard 已提交
8452
                    }
B
bellard 已提交
8453
                    /* advance to the next address.  */
P
pbrook 已提交
8454
                    tcg_gen_addi_i32(addr, addr, 4);
B
bellard 已提交
8455 8456
                }
            }
P
pbrook 已提交
8457
            TCGV_UNUSED(tmp);
B
bellard 已提交
8458 8459 8460
            if (insn & (1 << 8)) {
                if (insn & (1 << 11)) {
                    /* pop pc */
P
pbrook 已提交
8461
                    tmp = gen_ld32(addr, IS_USER(s));
B
bellard 已提交
8462 8463 8464 8465
                    /* don't set the pc until the rest of the instruction
                       has completed */
                } else {
                    /* push lr */
P
pbrook 已提交
8466 8467
                    tmp = load_reg(s, 14);
                    gen_st32(tmp, addr, IS_USER(s));
B
bellard 已提交
8468
                }
P
pbrook 已提交
8469
                tcg_gen_addi_i32(addr, addr, 4);
B
bellard 已提交
8470
            }
B
bellard 已提交
8471
            if ((insn & (1 << 11)) == 0) {
P
pbrook 已提交
8472
                tcg_gen_addi_i32(addr, addr, -offset);
B
bellard 已提交
8473
            }
B
bellard 已提交
8474
            /* write back the new stack pointer */
P
pbrook 已提交
8475
            store_reg(s, 13, addr);
B
bellard 已提交
8476 8477
            /* set the new PC value */
            if ((insn & 0x0900) == 0x0900)
P
pbrook 已提交
8478
                gen_bx(s, tmp);
B
bellard 已提交
8479 8480
            break;

P
pbrook 已提交
8481 8482
        case 1: case 3: case 9: case 11: /* czb */
            rm = insn & 7;
P
pbrook 已提交
8483
            tmp = load_reg(s, rm);
P
pbrook 已提交
8484 8485 8486
            s->condlabel = gen_new_label();
            s->condjmp = 1;
            if (insn & (1 << 11))
P
pbrook 已提交
8487
                tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, s->condlabel);
P
pbrook 已提交
8488
            else
P
pbrook 已提交
8489
                tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, s->condlabel);
P
pbrook 已提交
8490
            dead_tmp(tmp);
P
pbrook 已提交
8491 8492 8493 8494 8495 8496 8497 8498 8499 8500 8501 8502 8503 8504 8505 8506 8507
            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 已提交
8508
        case 0xe: /* bkpt */
P
pbrook 已提交
8509
            gen_set_condexec(s);
P
pbrook 已提交
8510
            gen_set_pc_im(s->pc - 2);
P
pbrook 已提交
8511
            gen_exception(EXCP_BKPT);
P
pbrook 已提交
8512 8513 8514
            s->is_jmp = DISAS_JUMP;
            break;

P
pbrook 已提交
8515 8516 8517 8518
        case 0xa: /* rev */
            ARCH(6);
            rn = (insn >> 3) & 0x7;
            rd = insn & 0x7;
P
pbrook 已提交
8519
            tmp = load_reg(s, rn);
P
pbrook 已提交
8520
            switch ((insn >> 6) & 3) {
P
pbrook 已提交
8521 8522 8523
            case 0: tcg_gen_bswap_i32(tmp, tmp); break;
            case 1: gen_rev16(tmp); break;
            case 3: gen_revsh(tmp); break;
P
pbrook 已提交
8524 8525
            default: goto illegal_op;
            }
P
pbrook 已提交
8526
            store_reg(s, rd, tmp);
P
pbrook 已提交
8527 8528 8529 8530 8531 8532 8533
            break;

        case 6: /* cps */
            ARCH(6);
            if (IS_USER(s))
                break;
            if (IS_M(env)) {
P
pbrook 已提交
8534
                tmp = tcg_const_i32((insn & (1 << 4)) != 0);
P
pbrook 已提交
8535
                /* PRIMASK */
P
pbrook 已提交
8536 8537 8538 8539
                if (insn & 1) {
                    addr = tcg_const_i32(16);
                    gen_helper_v7m_msr(cpu_env, addr, tmp);
                }
P
pbrook 已提交
8540
                /* FAULTMASK */
P
pbrook 已提交
8541 8542 8543 8544
                if (insn & 2) {
                    addr = tcg_const_i32(17);
                    gen_helper_v7m_msr(cpu_env, addr, tmp);
                }
P
pbrook 已提交
8545 8546 8547 8548 8549 8550 8551 8552 8553 8554 8555 8556 8557
                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 已提交
8558 8559 8560 8561 8562 8563 8564 8565
        default:
            goto undef;
        }
        break;

    case 12:
        /* load/store multiple */
        rn = (insn >> 8) & 0x7;
P
pbrook 已提交
8566
        addr = load_reg(s, rn);
B
bellard 已提交
8567 8568 8569 8570
        for (i = 0; i < 8; i++) {
            if (insn & (1 << i)) {
                if (insn & (1 << 11)) {
                    /* load */
P
pbrook 已提交
8571 8572
                    tmp = gen_ld32(addr, IS_USER(s));
                    store_reg(s, i, tmp);
B
bellard 已提交
8573 8574
                } else {
                    /* store */
P
pbrook 已提交
8575 8576
                    tmp = load_reg(s, i);
                    gen_st32(tmp, addr, IS_USER(s));
B
bellard 已提交
8577
                }
B
bellard 已提交
8578
                /* advance to the next address */
P
pbrook 已提交
8579
                tcg_gen_addi_i32(addr, addr, 4);
B
bellard 已提交
8580 8581
            }
        }
B
bellard 已提交
8582
        /* Base register writeback.  */
P
pbrook 已提交
8583 8584 8585 8586 8587
        if ((insn & (1 << rn)) == 0) {
            store_reg(s, rn, addr);
        } else {
            dead_tmp(addr);
        }
B
bellard 已提交
8588 8589 8590 8591 8592 8593 8594 8595 8596 8597
        break;

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

        if (cond == 0xf) {
            /* swi */
P
pbrook 已提交
8598
            gen_set_condexec(s);
8599
            gen_set_pc_im(s->pc);
P
pbrook 已提交
8600
            s->is_jmp = DISAS_SWI;
B
bellard 已提交
8601 8602 8603
            break;
        }
        /* generate a conditional jump to next instruction */
8604
        s->condlabel = gen_new_label();
P
pbrook 已提交
8605
        gen_test_cc(cond ^ 1, s->condlabel);
8606
        s->condjmp = 1;
B
bellard 已提交
8607 8608 8609
        gen_movl_T1_reg(s, 15);

        /* jump to the offset */
B
bellard 已提交
8610
        val = (uint32_t)s->pc + 2;
B
bellard 已提交
8611
        offset = ((int32_t)insn << 24) >> 24;
B
bellard 已提交
8612
        val += offset << 1;
B
bellard 已提交
8613
        gen_jmp(s, val);
B
bellard 已提交
8614 8615 8616
        break;

    case 14:
P
pbrook 已提交
8617
        if (insn & (1 << 11)) {
P
pbrook 已提交
8618 8619
            if (disas_thumb2_insn(env, s, insn))
              goto undef32;
P
pbrook 已提交
8620 8621
            break;
        }
P
pbrook 已提交
8622
        /* unconditional branch */
B
bellard 已提交
8623 8624 8625
        val = (uint32_t)s->pc;
        offset = ((int32_t)insn << 21) >> 21;
        val += (offset << 1) + 2;
B
bellard 已提交
8626
        gen_jmp(s, val);
B
bellard 已提交
8627 8628 8629
        break;

    case 15:
P
pbrook 已提交
8630
        if (disas_thumb2_insn(env, s, insn))
B
balrog 已提交
8631
            goto undef32;
P
pbrook 已提交
8632
        break;
B
bellard 已提交
8633 8634
    }
    return;
P
pbrook 已提交
8635 8636
undef32:
    gen_set_condexec(s);
P
pbrook 已提交
8637
    gen_set_pc_im(s->pc - 4);
P
pbrook 已提交
8638
    gen_exception(EXCP_UDEF);
P
pbrook 已提交
8639 8640 8641
    s->is_jmp = DISAS_JUMP;
    return;
illegal_op:
B
bellard 已提交
8642
undef:
P
pbrook 已提交
8643
    gen_set_condexec(s);
P
pbrook 已提交
8644
    gen_set_pc_im(s->pc - 2);
P
pbrook 已提交
8645
    gen_exception(EXCP_UDEF);
B
bellard 已提交
8646 8647 8648
    s->is_jmp = DISAS_JUMP;
}

B
bellard 已提交
8649 8650 8651
/* 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. */
8652 8653 8654
static inline void gen_intermediate_code_internal(CPUState *env,
                                                  TranslationBlock *tb,
                                                  int search_pc)
B
bellard 已提交
8655 8656
{
    DisasContext dc1, *dc = &dc1;
8657
    CPUBreakpoint *bp;
B
bellard 已提交
8658 8659
    uint16_t *gen_opc_end;
    int j, lj;
B
bellard 已提交
8660
    target_ulong pc_start;
B
bellard 已提交
8661
    uint32_t next_page_start;
P
pbrook 已提交
8662 8663
    int num_insns;
    int max_insns;
8664

B
bellard 已提交
8665
    /* generate intermediate code */
P
pbrook 已提交
8666 8667 8668
    num_temps = 0;
    memset(temps, 0, sizeof(temps));

B
bellard 已提交
8669
    pc_start = tb->pc;
8670

B
bellard 已提交
8671 8672 8673 8674 8675 8676
    dc->tb = tb;

    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;

    dc->is_jmp = DISAS_NEXT;
    dc->pc = pc_start;
B
bellard 已提交
8677
    dc->singlestep_enabled = env->singlestep_enabled;
8678
    dc->condjmp = 0;
B
bellard 已提交
8679
    dc->thumb = env->thumb;
P
pbrook 已提交
8680 8681
    dc->condexec_mask = (env->condexec_bits & 0xf) << 1;
    dc->condexec_cond = env->condexec_bits >> 4;
B
bellard 已提交
8682
#if !defined(CONFIG_USER_ONLY)
P
pbrook 已提交
8683 8684 8685 8686 8687
    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 已提交
8688
#endif
P
pbrook 已提交
8689 8690 8691 8692
    cpu_F0s = tcg_temp_new_i32();
    cpu_F1s = tcg_temp_new_i32();
    cpu_F0d = tcg_temp_new_i64();
    cpu_F1d = tcg_temp_new_i64();
P
pbrook 已提交
8693 8694
    cpu_V0 = cpu_F0d;
    cpu_V1 = cpu_F1d;
P
pbrook 已提交
8695
    /* FIXME: cpu_M0 can probably be the same as cpu_V0.  */
P
pbrook 已提交
8696
    cpu_M0 = tcg_temp_new_i64();
B
bellard 已提交
8697
    next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
B
bellard 已提交
8698
    lj = -1;
P
pbrook 已提交
8699 8700 8701 8702 8703 8704
    num_insns = 0;
    max_insns = tb->cflags & CF_COUNT_MASK;
    if (max_insns == 0)
        max_insns = CF_COUNT_MASK;

    gen_icount_start();
P
pbrook 已提交
8705 8706 8707
    /* 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 已提交
8708 8709 8710
      {
        TCGv tmp = new_tmp();
        tcg_gen_movi_i32(tmp, 0);
P
pbrook 已提交
8711
        store_cpu_field(tmp, condexec_bits);
P
pbrook 已提交
8712
      }
B
bellard 已提交
8713
    do {
8714 8715 8716 8717 8718 8719 8720 8721 8722 8723
#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 已提交
8724 8725 8726
        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 已提交
8727
            gen_exception(EXCP_EXCEPTION_EXIT);
8728 8729
            dc->is_jmp = DISAS_UPDATE;
            break;
P
pbrook 已提交
8730 8731 8732
        }
#endif

8733 8734
        if (unlikely(!TAILQ_EMPTY(&env->breakpoints))) {
            TAILQ_FOREACH(bp, &env->breakpoints, entry) {
8735
                if (bp->pc == dc->pc) {
P
pbrook 已提交
8736
                    gen_set_condexec(dc);
P
pbrook 已提交
8737
                    gen_set_pc_im(dc->pc);
P
pbrook 已提交
8738
                    gen_exception(EXCP_DEBUG);
B
bellard 已提交
8739
                    dc->is_jmp = DISAS_JUMP;
P
pbrook 已提交
8740 8741 8742 8743
                    /* Advance PC so that clearing the breakpoint will
                       invalidate this TB.  */
                    dc->pc += 2;
                    goto done_generating;
B
bellard 已提交
8744 8745 8746 8747
                    break;
                }
            }
        }
B
bellard 已提交
8748 8749 8750 8751 8752 8753 8754
        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 已提交
8755
            gen_opc_pc[lj] = dc->pc;
B
bellard 已提交
8756
            gen_opc_instr_start[lj] = 1;
P
pbrook 已提交
8757
            gen_opc_icount[lj] = num_insns;
B
bellard 已提交
8758
        }
8759

P
pbrook 已提交
8760 8761 8762
        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
            gen_io_start();

P
pbrook 已提交
8763 8764 8765 8766 8767 8768 8769 8770 8771 8772 8773 8774 8775
        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 已提交
8776 8777 8778 8779
        if (num_temps) {
            fprintf(stderr, "Internal resource leak before %08x\n", dc->pc);
            num_temps = 0;
        }
8780 8781 8782 8783 8784

        if (dc->condjmp && !dc->is_jmp) {
            gen_set_label(dc->condlabel);
            dc->condjmp = 0;
        }
B
balrog 已提交
8785
        /* Translation stops when a conditional branch is encountered.
8786
         * Otherwise the subsequent code could get translated several times.
B
bellard 已提交
8787
         * Also stop translation when a page boundary is reached.  This
T
ths 已提交
8788
         * ensures prefetch aborts occur at the right place.  */
P
pbrook 已提交
8789
        num_insns ++;
B
bellard 已提交
8790 8791
    } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
             !env->singlestep_enabled &&
P
pbrook 已提交
8792 8793 8794 8795 8796 8797 8798 8799 8800 8801 8802
             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 已提交
8803

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

P
pbrook 已提交
8868
done_generating:
P
pbrook 已提交
8869
    gen_icount_end(tb, num_insns);
B
bellard 已提交
8870 8871 8872
    *gen_opc_ptr = INDEX_op_end;

#ifdef DEBUG_DISAS
B
bellard 已提交
8873
    if (loglevel & CPU_LOG_TB_IN_ASM) {
B
bellard 已提交
8874 8875
        fprintf(logfile, "----------------\n");
        fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
B
bellard 已提交
8876
        target_disas(logfile, pc_start, dc->pc - pc_start, env->thumb);
B
bellard 已提交
8877 8878 8879
        fprintf(logfile, "\n");
    }
#endif
B
bellard 已提交
8880 8881 8882 8883 8884 8885
    if (search_pc) {
        j = gen_opc_ptr - gen_opc_buf;
        lj++;
        while (lj <= j)
            gen_opc_instr_start[lj++] = 0;
    } else {
B
bellard 已提交
8886
        tb->size = dc->pc - pc_start;
P
pbrook 已提交
8887
        tb->icount = num_insns;
B
bellard 已提交
8888
    }
B
bellard 已提交
8889 8890
}

8891
void gen_intermediate_code(CPUState *env, TranslationBlock *tb)
B
bellard 已提交
8892
{
8893
    gen_intermediate_code_internal(env, tb, 0);
B
bellard 已提交
8894 8895
}

8896
void gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
B
bellard 已提交
8897
{
8898
    gen_intermediate_code_internal(env, tb, 1);
B
bellard 已提交
8899 8900
}

B
bellard 已提交
8901 8902 8903 8904
static const char *cpu_mode_names[16] = {
  "usr", "fiq", "irq", "svc", "???", "???", "???", "abt",
  "???", "???", "???", "und", "???", "???", "???", "sys"
};
P
pbrook 已提交
8905

8906
void cpu_dump_state(CPUState *env, FILE *f,
B
bellard 已提交
8907 8908
                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
                    int flags)
B
bellard 已提交
8909 8910
{
    int i;
T
ths 已提交
8911
#if 0
B
bellard 已提交
8912
    union {
B
bellard 已提交
8913 8914 8915 8916
        uint32_t i;
        float s;
    } s0, s1;
    CPU_DoubleU d;
P
pbrook 已提交
8917 8918 8919 8920 8921 8922
    /* ??? This assumes float64 and double have the same layout.
       Oh well, it's only debug dumps.  */
    union {
        float64 f64;
        double d;
    } d0;
T
ths 已提交
8923
#endif
B
bellard 已提交
8924
    uint32_t psr;
B
bellard 已提交
8925 8926

    for(i=0;i<16;i++) {
B
bellard 已提交
8927
        cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
B
bellard 已提交
8928
        if ((i % 4) == 3)
B
bellard 已提交
8929
            cpu_fprintf(f, "\n");
B
bellard 已提交
8930
        else
B
bellard 已提交
8931
            cpu_fprintf(f, " ");
B
bellard 已提交
8932
    }
B
bellard 已提交
8933
    psr = cpsr_read(env);
8934 8935
    cpu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%d\n",
                psr,
B
bellard 已提交
8936 8937 8938 8939
                psr & (1 << 31) ? 'N' : '-',
                psr & (1 << 30) ? 'Z' : '-',
                psr & (1 << 29) ? 'C' : '-',
                psr & (1 << 28) ? 'V' : '-',
8940
                psr & CPSR_T ? 'T' : 'A',
B
bellard 已提交
8941
                cpu_mode_names[psr & 0xf], (psr & 0x10) ? 32 : 26);
B
bellard 已提交
8942

P
pbrook 已提交
8943
#if 0
B
bellard 已提交
8944
    for (i = 0; i < 16; i++) {
B
bellard 已提交
8945 8946 8947
        d.d = env->vfp.regs[i];
        s0.i = d.l.lower;
        s1.i = d.l.upper;
P
pbrook 已提交
8948 8949
        d0.f64 = d.d;
        cpu_fprintf(f, "s%02d=%08x(%8g) s%02d=%08x(%8g) d%02d=%08x%08x(%8g)\n",
B
bellard 已提交
8950
                    i * 2, (int)s0.i, s0.s,
P
pbrook 已提交
8951
                    i * 2 + 1, (int)s1.i, s1.s,
B
bellard 已提交
8952
                    i, (int)(uint32_t)d.l.upper, (int)(uint32_t)d.l.lower,
P
pbrook 已提交
8953
                    d0.d);
B
bellard 已提交
8954
    }
P
pbrook 已提交
8955
    cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.xregs[ARM_VFP_FPSCR]);
P
pbrook 已提交
8956
#endif
B
bellard 已提交
8957
}
B
bellard 已提交
8958

A
aurel32 已提交
8959 8960 8961 8962 8963
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];
}