translate.c 419.2 KB
Newer Older
B
bellard 已提交
1 2
/*
 *  ARM translation
3
 *
B
bellard 已提交
4
 *  Copyright (c) 2003 Fabrice Bellard
P
pbrook 已提交
5
 *  Copyright (c) 2005-2007 CodeSourcery
6
 *  Copyright (c) 2007 OpenedHand, Ltd.
B
bellard 已提交
7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
19
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
B
bellard 已提交
20
 */
P
Peter Maydell 已提交
21
#include "qemu/osdep.h"
B
bellard 已提交
22 23

#include "cpu.h"
24
#include "internals.h"
25
#include "disas/disas.h"
26
#include "exec/exec-all.h"
B
bellard 已提交
27
#include "tcg-op.h"
28
#include "qemu/log.h"
29
#include "qemu/bitops.h"
30
#include "arm_ldst.h"
31
#include "exec/semihost.h"
P
pbrook 已提交
32

33 34
#include "exec/helper-proto.h"
#include "exec/helper-gen.h"
B
bellard 已提交
35

36
#include "trace-tcg.h"
37
#include "exec/log.h"
38 39


40 41
#define ENABLE_ARCH_4T    arm_dc_feature(s, ARM_FEATURE_V4T)
#define ENABLE_ARCH_5     arm_dc_feature(s, ARM_FEATURE_V5)
42
/* currently all emulated v5 cores are also v5TE, so don't bother */
43
#define ENABLE_ARCH_5TE   arm_dc_feature(s, ARM_FEATURE_V5)
P
pbrook 已提交
44
#define ENABLE_ARCH_5J    0
45 46 47 48 49
#define ENABLE_ARCH_6     arm_dc_feature(s, ARM_FEATURE_V6)
#define ENABLE_ARCH_6K    arm_dc_feature(s, ARM_FEATURE_V6K)
#define ENABLE_ARCH_6T2   arm_dc_feature(s, ARM_FEATURE_THUMB2)
#define ENABLE_ARCH_7     arm_dc_feature(s, ARM_FEATURE_V7)
#define ENABLE_ARCH_8     arm_dc_feature(s, ARM_FEATURE_V8)
B
bellard 已提交
50

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

53
#include "translate.h"
54

B
bellard 已提交
55 56 57 58 59 60
#if defined(CONFIG_USER_ONLY)
#define IS_USER(s) 1
#else
#define IS_USER(s) (s->user)
#endif

61
TCGv_env cpu_env;
P
pbrook 已提交
62
/* We reuse the same 64-bit temporaries for efficiency.  */
P
pbrook 已提交
63
static TCGv_i64 cpu_V0, cpu_V1, cpu_M0;
64
static TCGv_i32 cpu_R[16];
65 66 67
TCGv_i32 cpu_CF, cpu_NF, cpu_VF, cpu_ZF;
TCGv_i64 cpu_exclusive_addr;
TCGv_i64 cpu_exclusive_val;
P
pbrook 已提交
68

P
pbrook 已提交
69
/* FIXME:  These should be removed.  */
70
static TCGv_i32 cpu_F0s, cpu_F1s;
P
pbrook 已提交
71
static TCGv_i64 cpu_F0d, cpu_F1d;
P
pbrook 已提交
72

73
#include "exec/gen-icount.h"
P
pbrook 已提交
74

75 76 77 78
static const char *regnames[] =
    { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
      "r8", "r9", "r10", "r11", "r12", "r13", "r14", "pc" };

P
pbrook 已提交
79 80 81
/* initialize TCG globals.  */
void arm_translate_init(void)
{
82 83
    int i;

P
pbrook 已提交
84
    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
85
    tcg_ctx.tcg_env = cpu_env;
P
pbrook 已提交
86

87
    for (i = 0; i < 16; i++) {
88
        cpu_R[i] = tcg_global_mem_new_i32(cpu_env,
89
                                          offsetof(CPUARMState, regs[i]),
90 91
                                          regnames[i]);
    }
92 93 94 95
    cpu_CF = tcg_global_mem_new_i32(cpu_env, offsetof(CPUARMState, CF), "CF");
    cpu_NF = tcg_global_mem_new_i32(cpu_env, offsetof(CPUARMState, NF), "NF");
    cpu_VF = tcg_global_mem_new_i32(cpu_env, offsetof(CPUARMState, VF), "VF");
    cpu_ZF = tcg_global_mem_new_i32(cpu_env, offsetof(CPUARMState, ZF), "ZF");
96

97
    cpu_exclusive_addr = tcg_global_mem_new_i64(cpu_env,
98
        offsetof(CPUARMState, exclusive_addr), "exclusive_addr");
99
    cpu_exclusive_val = tcg_global_mem_new_i64(cpu_env,
100
        offsetof(CPUARMState, exclusive_val), "exclusive_val");
101

102
    a64_translate_init();
P
pbrook 已提交
103 104
}

105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
static inline ARMMMUIdx get_a32_user_mem_index(DisasContext *s)
{
    /* Return the mmu_idx to use for A32/T32 "unprivileged load/store"
     * insns:
     *  if PL2, UNPREDICTABLE (we choose to implement as if PL0)
     *  otherwise, access as if at PL0.
     */
    switch (s->mmu_idx) {
    case ARMMMUIdx_S1E2:        /* this one is UNPREDICTABLE */
    case ARMMMUIdx_S12NSE0:
    case ARMMMUIdx_S12NSE1:
        return ARMMMUIdx_S12NSE0;
    case ARMMMUIdx_S1E3:
    case ARMMMUIdx_S1SE0:
    case ARMMMUIdx_S1SE1:
        return ARMMMUIdx_S1SE0;
    case ARMMMUIdx_S2NS:
    default:
        g_assert_not_reached();
    }
}

127
static inline TCGv_i32 load_cpu_offset(int offset)
P
pbrook 已提交
128
{
129
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
130 131 132 133
    tcg_gen_ld_i32(tmp, cpu_env, offset);
    return tmp;
}

134
#define load_cpu_field(name) load_cpu_offset(offsetof(CPUARMState, name))
P
pbrook 已提交
135

136
static inline void store_cpu_offset(TCGv_i32 var, int offset)
P
pbrook 已提交
137 138
{
    tcg_gen_st_i32(var, cpu_env, offset);
139
    tcg_temp_free_i32(var);
P
pbrook 已提交
140 141 142
}

#define store_cpu_field(var, name) \
143
    store_cpu_offset(var, offsetof(CPUARMState, name))
P
pbrook 已提交
144

P
pbrook 已提交
145
/* Set a variable to the value of a CPU register.  */
146
static void load_reg_var(DisasContext *s, TCGv_i32 var, int reg)
P
pbrook 已提交
147 148 149
{
    if (reg == 15) {
        uint32_t addr;
150
        /* normally, since we updated PC, we need only to add one insn */
P
pbrook 已提交
151 152 153 154 155 156
        if (s->thumb)
            addr = (long)s->pc + 2;
        else
            addr = (long)s->pc + 4;
        tcg_gen_movi_i32(var, addr);
    } else {
157
        tcg_gen_mov_i32(var, cpu_R[reg]);
P
pbrook 已提交
158 159 160 161
    }
}

/* Create a new temporary and set it to the value of a CPU register.  */
162
static inline TCGv_i32 load_reg(DisasContext *s, int reg)
P
pbrook 已提交
163
{
164
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
165 166 167 168 169 170
    load_reg_var(s, tmp, reg);
    return tmp;
}

/* Set a CPU register.  The source must be a temporary and will be
   marked as dead.  */
171
static void store_reg(DisasContext *s, int reg, TCGv_i32 var)
P
pbrook 已提交
172 173
{
    if (reg == 15) {
174 175 176 177 178 179
        /* In Thumb mode, we must ignore bit 0.
         * In ARM mode, for ARMv4 and ARMv5, it is UNPREDICTABLE if bits [1:0]
         * are not 0b00, but for ARMv6 and above, we must ignore bits [1:0].
         * We choose to ignore [1:0] in ARM mode for all architecture versions.
         */
        tcg_gen_andi_i32(var, var, s->thumb ? ~1 : ~3);
P
pbrook 已提交
180 181
        s->is_jmp = DISAS_JUMP;
    }
182
    tcg_gen_mov_i32(cpu_R[reg], var);
183
    tcg_temp_free_i32(var);
P
pbrook 已提交
184 185 186
}

/* Value extensions.  */
P
pbrook 已提交
187 188
#define gen_uxtb(var) tcg_gen_ext8u_i32(var, var)
#define gen_uxth(var) tcg_gen_ext16u_i32(var, var)
P
pbrook 已提交
189 190 191
#define gen_sxtb(var) tcg_gen_ext8s_i32(var, var)
#define gen_sxth(var) tcg_gen_ext16s_i32(var, var)

P
pbrook 已提交
192 193
#define gen_sxtb16(var) gen_helper_sxtb16(var, var)
#define gen_uxtb16(var) gen_helper_uxtb16(var, var)
P
pbrook 已提交
194

P
pbrook 已提交
195

196
static inline void gen_set_cpsr(TCGv_i32 var, uint32_t mask)
197
{
198
    TCGv_i32 tmp_mask = tcg_const_i32(mask);
B
Blue Swirl 已提交
199
    gen_helper_cpsr_write(cpu_env, var, tmp_mask);
200 201
    tcg_temp_free_i32(tmp_mask);
}
P
pbrook 已提交
202 203 204
/* Set NZCV flags from the high 4 bits of var.  */
#define gen_set_nzcv(var) gen_set_cpsr(var, CPSR_NZCV)

205
static void gen_exception_internal(int excp)
P
pbrook 已提交
206
{
207 208 209 210 211 212 213
    TCGv_i32 tcg_excp = tcg_const_i32(excp);

    assert(excp_is_internal(excp));
    gen_helper_exception_internal(cpu_env, tcg_excp);
    tcg_temp_free_i32(tcg_excp);
}

214
static void gen_exception(int excp, uint32_t syndrome, uint32_t target_el)
215 216 217
{
    TCGv_i32 tcg_excp = tcg_const_i32(excp);
    TCGv_i32 tcg_syn = tcg_const_i32(syndrome);
218
    TCGv_i32 tcg_el = tcg_const_i32(target_el);
219

220 221 222 223
    gen_helper_exception_with_syndrome(cpu_env, tcg_excp,
                                       tcg_syn, tcg_el);

    tcg_temp_free_i32(tcg_el);
224 225
    tcg_temp_free_i32(tcg_syn);
    tcg_temp_free_i32(tcg_excp);
P
pbrook 已提交
226 227
}

228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
static void gen_ss_advance(DisasContext *s)
{
    /* If the singlestep state is Active-not-pending, advance to
     * Active-pending.
     */
    if (s->ss_active) {
        s->pstate_ss = 0;
        gen_helper_clear_pstate_ss(cpu_env);
    }
}

static void gen_step_complete_exception(DisasContext *s)
{
    /* We just completed step of an insn. Move from Active-not-pending
     * to Active-pending, and then also take the swstep exception.
     * This corresponds to making the (IMPDEF) choice to prioritize
     * swstep exceptions over asynchronous exceptions taken to an exception
     * level where debug is disabled. This choice has the advantage that
     * we do not need to maintain internal state corresponding to the
     * ISV/EX syndrome bits between completion of the step and generation
     * of the exception, and our syndrome information is always correct.
     */
    gen_ss_advance(s);
251 252
    gen_exception(EXCP_UDEF, syn_swstep(s->ss_same_el, 1, s->is_ldex),
                  default_exception_el(s));
253 254 255
    s->is_jmp = DISAS_EXC;
}

256
static void gen_smul_dual(TCGv_i32 a, TCGv_i32 b)
P
pbrook 已提交
257
{
258 259
    TCGv_i32 tmp1 = tcg_temp_new_i32();
    TCGv_i32 tmp2 = tcg_temp_new_i32();
260 261
    tcg_gen_ext16s_i32(tmp1, a);
    tcg_gen_ext16s_i32(tmp2, b);
P
pbrook 已提交
262
    tcg_gen_mul_i32(tmp1, tmp1, tmp2);
263
    tcg_temp_free_i32(tmp2);
P
pbrook 已提交
264 265 266 267
    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);
268
    tcg_temp_free_i32(tmp1);
P
pbrook 已提交
269 270 271
}

/* Byteswap each halfword.  */
272
static void gen_rev16(TCGv_i32 var)
P
pbrook 已提交
273
{
274
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
275 276 277 278 279
    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);
280
    tcg_temp_free_i32(tmp);
P
pbrook 已提交
281 282 283
}

/* Byteswap low halfword and sign extend.  */
284
static void gen_revsh(TCGv_i32 var)
P
pbrook 已提交
285
{
286 287 288
    tcg_gen_ext16u_i32(var, var);
    tcg_gen_bswap16_i32(var, var);
    tcg_gen_ext16s_i32(var, var);
P
pbrook 已提交
289 290
}

291
/* Return (b << 32) + a. Mark inputs as dead */
292
static TCGv_i64 gen_addq_msw(TCGv_i64 a, TCGv_i32 b)
P
pbrook 已提交
293
{
294 295 296
    TCGv_i64 tmp64 = tcg_temp_new_i64();

    tcg_gen_extu_i32_i64(tmp64, b);
297
    tcg_temp_free_i32(b);
298 299 300 301 302 303 304 305
    tcg_gen_shli_i64(tmp64, tmp64, 32);
    tcg_gen_add_i64(a, tmp64, a);

    tcg_temp_free_i64(tmp64);
    return a;
}

/* Return (b << 32) - a. Mark inputs as dead. */
306
static TCGv_i64 gen_subq_msw(TCGv_i64 a, TCGv_i32 b)
307 308 309 310
{
    TCGv_i64 tmp64 = tcg_temp_new_i64();

    tcg_gen_extu_i32_i64(tmp64, b);
311
    tcg_temp_free_i32(b);
312 313 314 315 316
    tcg_gen_shli_i64(tmp64, tmp64, 32);
    tcg_gen_sub_i64(a, tmp64, a);

    tcg_temp_free_i64(tmp64);
    return a;
P
pbrook 已提交
317 318
}

P
pbrook 已提交
319
/* 32x32->64 multiply.  Marks inputs as dead.  */
320
static TCGv_i64 gen_mulu_i64_i32(TCGv_i32 a, TCGv_i32 b)
P
pbrook 已提交
321
{
322 323
    TCGv_i32 lo = tcg_temp_new_i32();
    TCGv_i32 hi = tcg_temp_new_i32();
324
    TCGv_i64 ret;
P
pbrook 已提交
325

326
    tcg_gen_mulu2_i32(lo, hi, a, b);
327 328
    tcg_temp_free_i32(a);
    tcg_temp_free_i32(b);
329 330 331

    ret = tcg_temp_new_i64();
    tcg_gen_concat_i32_i64(ret, lo, hi);
332 333
    tcg_temp_free_i32(lo);
    tcg_temp_free_i32(hi);
334 335

    return ret;
P
pbrook 已提交
336 337
}

338
static TCGv_i64 gen_muls_i64_i32(TCGv_i32 a, TCGv_i32 b)
P
pbrook 已提交
339
{
340 341
    TCGv_i32 lo = tcg_temp_new_i32();
    TCGv_i32 hi = tcg_temp_new_i32();
342
    TCGv_i64 ret;
P
pbrook 已提交
343

344
    tcg_gen_muls2_i32(lo, hi, a, b);
345 346
    tcg_temp_free_i32(a);
    tcg_temp_free_i32(b);
347 348 349

    ret = tcg_temp_new_i64();
    tcg_gen_concat_i32_i64(ret, lo, hi);
350 351
    tcg_temp_free_i32(lo);
    tcg_temp_free_i32(hi);
352 353

    return ret;
P
pbrook 已提交
354 355
}

P
pbrook 已提交
356
/* Swap low and high halfwords.  */
357
static void gen_swap_half(TCGv_i32 var)
P
pbrook 已提交
358
{
359
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
360 361 362
    tcg_gen_shri_i32(tmp, var, 16);
    tcg_gen_shli_i32(var, var, 16);
    tcg_gen_or_i32(var, var, tmp);
363
    tcg_temp_free_i32(tmp);
P
pbrook 已提交
364 365
}

P
pbrook 已提交
366 367 368 369 370 371 372
/* 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;
 */

373
static void gen_add16(TCGv_i32 t0, TCGv_i32 t1)
P
pbrook 已提交
374
{
375
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
376 377 378 379 380 381
    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);
382 383
    tcg_temp_free_i32(tmp);
    tcg_temp_free_i32(t1);
P
pbrook 已提交
384 385 386
}

/* Set CF to the top bit of var.  */
387
static void gen_set_CF_bit31(TCGv_i32 var)
P
pbrook 已提交
388
{
389
    tcg_gen_shri_i32(cpu_CF, var, 31);
P
pbrook 已提交
390 391 392
}

/* Set N and Z flags from var.  */
393
static inline void gen_logic_CC(TCGv_i32 var)
P
pbrook 已提交
394
{
395 396
    tcg_gen_mov_i32(cpu_NF, var);
    tcg_gen_mov_i32(cpu_ZF, var);
P
pbrook 已提交
397 398 399
}

/* T0 += T1 + CF.  */
400
static void gen_adc(TCGv_i32 t0, TCGv_i32 t1)
P
pbrook 已提交
401
{
402
    tcg_gen_add_i32(t0, t0, t1);
403
    tcg_gen_add_i32(t0, t0, cpu_CF);
P
pbrook 已提交
404 405
}

406
/* dest = T0 + T1 + CF. */
407
static void gen_add_carry(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)
408 409
{
    tcg_gen_add_i32(dest, t0, t1);
410
    tcg_gen_add_i32(dest, dest, cpu_CF);
411 412
}

P
pbrook 已提交
413
/* dest = T0 - T1 + CF - 1.  */
414
static void gen_sub_carry(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)
P
pbrook 已提交
415 416
{
    tcg_gen_sub_i32(dest, t0, t1);
417
    tcg_gen_add_i32(dest, dest, cpu_CF);
P
pbrook 已提交
418 419 420
    tcg_gen_subi_i32(dest, dest, 1);
}

421
/* dest = T0 + T1. Compute C, N, V and Z flags */
422
static void gen_add_CC(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)
423
{
424
    TCGv_i32 tmp = tcg_temp_new_i32();
425 426
    tcg_gen_movi_i32(tmp, 0);
    tcg_gen_add2_i32(cpu_NF, cpu_CF, t0, tmp, t1, tmp);
427 428 429 430 431 432 433 434
    tcg_gen_mov_i32(cpu_ZF, cpu_NF);
    tcg_gen_xor_i32(cpu_VF, cpu_NF, t0);
    tcg_gen_xor_i32(tmp, t0, t1);
    tcg_gen_andc_i32(cpu_VF, cpu_VF, tmp);
    tcg_temp_free_i32(tmp);
    tcg_gen_mov_i32(dest, cpu_NF);
}

435
/* dest = T0 + T1 + CF.  Compute C, N, V and Z flags */
436
static void gen_adc_CC(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)
437
{
438
    TCGv_i32 tmp = tcg_temp_new_i32();
439 440 441
    if (TCG_TARGET_HAS_add2_i32) {
        tcg_gen_movi_i32(tmp, 0);
        tcg_gen_add2_i32(cpu_NF, cpu_CF, t0, tmp, cpu_CF, tmp);
442
        tcg_gen_add2_i32(cpu_NF, cpu_CF, cpu_NF, cpu_CF, t1, tmp);
443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462
    } else {
        TCGv_i64 q0 = tcg_temp_new_i64();
        TCGv_i64 q1 = tcg_temp_new_i64();
        tcg_gen_extu_i32_i64(q0, t0);
        tcg_gen_extu_i32_i64(q1, t1);
        tcg_gen_add_i64(q0, q0, q1);
        tcg_gen_extu_i32_i64(q1, cpu_CF);
        tcg_gen_add_i64(q0, q0, q1);
        tcg_gen_extr_i64_i32(cpu_NF, cpu_CF, q0);
        tcg_temp_free_i64(q0);
        tcg_temp_free_i64(q1);
    }
    tcg_gen_mov_i32(cpu_ZF, cpu_NF);
    tcg_gen_xor_i32(cpu_VF, cpu_NF, t0);
    tcg_gen_xor_i32(tmp, t0, t1);
    tcg_gen_andc_i32(cpu_VF, cpu_VF, tmp);
    tcg_temp_free_i32(tmp);
    tcg_gen_mov_i32(dest, cpu_NF);
}

463
/* dest = T0 - T1. Compute C, N, V and Z flags */
464
static void gen_sub_CC(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)
465
{
466
    TCGv_i32 tmp;
467 468 469 470 471 472 473 474 475 476 477
    tcg_gen_sub_i32(cpu_NF, t0, t1);
    tcg_gen_mov_i32(cpu_ZF, cpu_NF);
    tcg_gen_setcond_i32(TCG_COND_GEU, cpu_CF, t0, t1);
    tcg_gen_xor_i32(cpu_VF, cpu_NF, t0);
    tmp = tcg_temp_new_i32();
    tcg_gen_xor_i32(tmp, t0, t1);
    tcg_gen_and_i32(cpu_VF, cpu_VF, tmp);
    tcg_temp_free_i32(tmp);
    tcg_gen_mov_i32(dest, cpu_NF);
}

R
Richard Henderson 已提交
478
/* dest = T0 + ~T1 + CF.  Compute C, N, V and Z flags */
479
static void gen_sbc_CC(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)
480
{
481
    TCGv_i32 tmp = tcg_temp_new_i32();
R
Richard Henderson 已提交
482 483
    tcg_gen_not_i32(tmp, t1);
    gen_adc_CC(dest, t0, tmp);
484
    tcg_temp_free_i32(tmp);
485 486
}

487
#define GEN_SHIFT(name)                                               \
488
static void gen_##name(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)       \
489
{                                                                     \
490
    TCGv_i32 tmp1, tmp2, tmp3;                                        \
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505
    tmp1 = tcg_temp_new_i32();                                        \
    tcg_gen_andi_i32(tmp1, t1, 0xff);                                 \
    tmp2 = tcg_const_i32(0);                                          \
    tmp3 = tcg_const_i32(0x1f);                                       \
    tcg_gen_movcond_i32(TCG_COND_GTU, tmp2, tmp1, tmp3, tmp2, t0);    \
    tcg_temp_free_i32(tmp3);                                          \
    tcg_gen_andi_i32(tmp1, tmp1, 0x1f);                               \
    tcg_gen_##name##_i32(dest, tmp2, tmp1);                           \
    tcg_temp_free_i32(tmp2);                                          \
    tcg_temp_free_i32(tmp1);                                          \
}
GEN_SHIFT(shl)
GEN_SHIFT(shr)
#undef GEN_SHIFT

506
static void gen_sar(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)
507
{
508
    TCGv_i32 tmp1, tmp2;
509 510 511 512 513 514 515 516 517
    tmp1 = tcg_temp_new_i32();
    tcg_gen_andi_i32(tmp1, t1, 0xff);
    tmp2 = tcg_const_i32(0x1f);
    tcg_gen_movcond_i32(TCG_COND_GTU, tmp1, tmp1, tmp2, tmp2, tmp1);
    tcg_temp_free_i32(tmp2);
    tcg_gen_sar_i32(dest, t0, tmp1);
    tcg_temp_free_i32(tmp1);
}

518
static void tcg_gen_abs_i32(TCGv_i32 dest, TCGv_i32 src)
519
{
520 521
    TCGv_i32 c0 = tcg_const_i32(0);
    TCGv_i32 tmp = tcg_temp_new_i32();
522 523 524 525 526
    tcg_gen_neg_i32(tmp, src);
    tcg_gen_movcond_i32(TCG_COND_GT, dest, src, c0, src, tmp);
    tcg_temp_free_i32(c0);
    tcg_temp_free_i32(tmp);
}
P
pbrook 已提交
527

528
static void shifter_out_im(TCGv_i32 var, int shift)
P
pbrook 已提交
529
{
P
pbrook 已提交
530
    if (shift == 0) {
531
        tcg_gen_andi_i32(cpu_CF, var, 1);
P
pbrook 已提交
532
    } else {
533 534 535 536
        tcg_gen_shri_i32(cpu_CF, var, shift);
        if (shift != 31) {
            tcg_gen_andi_i32(cpu_CF, cpu_CF, 1);
        }
P
pbrook 已提交
537 538
    }
}
P
pbrook 已提交
539

P
pbrook 已提交
540
/* Shift by immediate.  Includes special handling for shift == 0.  */
541 542
static inline void gen_arm_shift_im(TCGv_i32 var, int shiftop,
                                    int shift, int flags)
P
pbrook 已提交
543 544 545 546 547 548 549 550 551 552 553 554
{
    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) {
555
                tcg_gen_shri_i32(cpu_CF, var, 31);
P
pbrook 已提交
556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576
            }
            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);
577
            tcg_gen_rotri_i32(var, var, shift); break;
P
pbrook 已提交
578
        } else {
579
            TCGv_i32 tmp = tcg_temp_new_i32();
580
            tcg_gen_shli_i32(tmp, cpu_CF, 31);
P
pbrook 已提交
581 582 583
            if (flags)
                shifter_out_im(var, 0);
            tcg_gen_shri_i32(var, var, 1);
P
pbrook 已提交
584
            tcg_gen_or_i32(var, var, tmp);
585
            tcg_temp_free_i32(tmp);
P
pbrook 已提交
586 587 588 589
        }
    }
};

590 591
static inline void gen_arm_shift_reg(TCGv_i32 var, int shiftop,
                                     TCGv_i32 shift, int flags)
P
pbrook 已提交
592 593 594
{
    if (flags) {
        switch (shiftop) {
595 596 597 598
        case 0: gen_helper_shl_cc(var, cpu_env, var, shift); break;
        case 1: gen_helper_shr_cc(var, cpu_env, var, shift); break;
        case 2: gen_helper_sar_cc(var, cpu_env, var, shift); break;
        case 3: gen_helper_ror_cc(var, cpu_env, var, shift); break;
P
pbrook 已提交
599 600 601
        }
    } else {
        switch (shiftop) {
602 603 604 605 606 607 608 609 610
        case 0:
            gen_shl(var, var, shift);
            break;
        case 1:
            gen_shr(var, var, shift);
            break;
        case 2:
            gen_sar(var, var, shift);
            break;
611 612
        case 3: tcg_gen_andi_i32(shift, shift, 0x1f);
                tcg_gen_rotr_i32(var, var, shift); break;
P
pbrook 已提交
613 614
        }
    }
615
    tcg_temp_free_i32(shift);
P
pbrook 已提交
616 617
}

P
pbrook 已提交
618 619 620 621 622 623 624 625 626
#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; \
    }
627
static void gen_arm_parallel_addsub(int op1, int op2, TCGv_i32 a, TCGv_i32 b)
P
pbrook 已提交
628
{
P
pbrook 已提交
629
    TCGv_ptr tmp;
P
pbrook 已提交
630 631 632 633

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

P
pbrook 已提交
664 665
/* For unknown reasons Arm and Thumb-2 use arbitrarily different encodings.  */
#define PAS_OP(pfx) \
666
    switch (op1) {  \
P
pbrook 已提交
667 668 669 670 671 672 673
    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; \
    }
674
static void gen_thumb2_parallel_addsub(int op1, int op2, TCGv_i32 a, TCGv_i32 b)
P
pbrook 已提交
675
{
P
pbrook 已提交
676
    TCGv_ptr tmp;
P
pbrook 已提交
677

678
    switch (op2) {
P
pbrook 已提交
679 680
#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp)
    case 0:
P
pbrook 已提交
681
        tmp = tcg_temp_new_ptr();
682
        tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUARMState, GE));
P
pbrook 已提交
683
        PAS_OP(s)
684
        tcg_temp_free_ptr(tmp);
P
pbrook 已提交
685 686
        break;
    case 4:
P
pbrook 已提交
687
        tmp = tcg_temp_new_ptr();
688
        tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUARMState, GE));
P
pbrook 已提交
689
        PAS_OP(u)
690
        tcg_temp_free_ptr(tmp);
P
pbrook 已提交
691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708
        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 已提交
709 710
#undef PAS_OP

711
/*
712
 * Generate a conditional based on ARM condition code cc.
713 714
 * This is common between ARM and Aarch64 targets.
 */
715
void arm_test_cc(DisasCompare *cmp, int cc)
P
pbrook 已提交
716
{
717 718 719
    TCGv_i32 value;
    TCGCond cond;
    bool global = true;
P
pbrook 已提交
720 721 722 723

    switch (cc) {
    case 0: /* eq: Z */
    case 1: /* ne: !Z */
724 725
        cond = TCG_COND_EQ;
        value = cpu_ZF;
P
pbrook 已提交
726
        break;
727

P
pbrook 已提交
728 729
    case 2: /* cs: C */
    case 3: /* cc: !C */
730 731
        cond = TCG_COND_NE;
        value = cpu_CF;
P
pbrook 已提交
732
        break;
733

P
pbrook 已提交
734 735
    case 4: /* mi: N */
    case 5: /* pl: !N */
736 737
        cond = TCG_COND_LT;
        value = cpu_NF;
P
pbrook 已提交
738
        break;
739

P
pbrook 已提交
740 741
    case 6: /* vs: V */
    case 7: /* vc: !V */
742 743
        cond = TCG_COND_LT;
        value = cpu_VF;
P
pbrook 已提交
744
        break;
745

P
pbrook 已提交
746
    case 8: /* hi: C && !Z */
747 748 749 750 751 752 753 754
    case 9: /* ls: !C || Z -> !(C && !Z) */
        cond = TCG_COND_NE;
        value = tcg_temp_new_i32();
        global = false;
        /* CF is 1 for C, so -CF is an all-bits-set mask for C;
           ZF is non-zero for !Z; so AND the two subexpressions.  */
        tcg_gen_neg_i32(value, cpu_CF);
        tcg_gen_and_i32(value, value, cpu_ZF);
P
pbrook 已提交
755
        break;
756

P
pbrook 已提交
757 758
    case 10: /* ge: N == V -> N ^ V == 0 */
    case 11: /* lt: N != V -> N ^ V != 0 */
759 760 761 762 763
        /* Since we're only interested in the sign bit, == 0 is >= 0.  */
        cond = TCG_COND_GE;
        value = tcg_temp_new_i32();
        global = false;
        tcg_gen_xor_i32(value, cpu_VF, cpu_NF);
P
pbrook 已提交
764
        break;
765

P
pbrook 已提交
766 767
    case 12: /* gt: !Z && N == V */
    case 13: /* le: Z || N != V */
768 769 770 771 772 773 774 775
        cond = TCG_COND_NE;
        value = tcg_temp_new_i32();
        global = false;
        /* (N == V) is equal to the sign bit of ~(NF ^ VF).  Propagate
         * the sign bit then AND with ZF to yield the result.  */
        tcg_gen_xor_i32(value, cpu_VF, cpu_NF);
        tcg_gen_sari_i32(value, value, 31);
        tcg_gen_andc_i32(value, cpu_ZF, value);
P
pbrook 已提交
776
        break;
777

778 779 780 781 782 783 784 785
    case 14: /* always */
    case 15: /* always */
        /* Use the ALWAYS condition, which will fold early.
         * It doesn't matter what we use for the value.  */
        cond = TCG_COND_ALWAYS;
        value = cpu_ZF;
        goto no_invert;

P
pbrook 已提交
786 787 788 789
    default:
        fprintf(stderr, "Bad condition code 0x%x\n", cc);
        abort();
    }
790 791 792 793 794

    if (cc & 1) {
        cond = tcg_invert_cond(cond);
    }

795
 no_invert:
796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818
    cmp->cond = cond;
    cmp->value = value;
    cmp->value_global = global;
}

void arm_free_cc(DisasCompare *cmp)
{
    if (!cmp->value_global) {
        tcg_temp_free_i32(cmp->value);
    }
}

void arm_jump_cc(DisasCompare *cmp, TCGLabel *label)
{
    tcg_gen_brcondi_i32(cmp->cond, cmp->value, 0, label);
}

void arm_gen_test_cc(int cc, TCGLabel *label)
{
    DisasCompare cmp;
    arm_test_cc(&cmp, cc);
    arm_jump_cc(&cmp, label);
    arm_free_cc(&cmp);
P
pbrook 已提交
819
}
B
bellard 已提交
820

821
static const uint8_t table_logic_cc[16] = {
B
bellard 已提交
822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838
    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 */
};
839

P
pbrook 已提交
840 841
/* Set PC and Thumb state from an immediate address.  */
static inline void gen_bx_im(DisasContext *s, uint32_t addr)
B
bellard 已提交
842
{
843
    TCGv_i32 tmp;
B
bellard 已提交
844

845
    s->is_jmp = DISAS_JUMP;
P
pbrook 已提交
846
    if (s->thumb != (addr & 1)) {
847
        tmp = tcg_temp_new_i32();
P
pbrook 已提交
848
        tcg_gen_movi_i32(tmp, addr & 1);
849
        tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUARMState, thumb));
850
        tcg_temp_free_i32(tmp);
P
pbrook 已提交
851
    }
852
    tcg_gen_movi_i32(cpu_R[15], addr & ~1);
P
pbrook 已提交
853 854 855
}

/* Set PC and Thumb state from var.  var is marked as dead.  */
856
static inline void gen_bx(DisasContext *s, TCGv_i32 var)
P
pbrook 已提交
857
{
858
    s->is_jmp = DISAS_JUMP;
859 860 861
    tcg_gen_andi_i32(cpu_R[15], var, ~1);
    tcg_gen_andi_i32(var, var, 1);
    store_cpu_field(var, thumb);
P
pbrook 已提交
862 863
}

864 865 866
/* Variant of store_reg which uses branch&exchange logic when storing
   to r15 in ARM architecture v7 and above. The source must be a temporary
   and will be marked as dead. */
867
static inline void store_reg_bx(DisasContext *s, int reg, TCGv_i32 var)
868 869 870 871 872 873 874 875
{
    if (reg == 15 && ENABLE_ARCH_7) {
        gen_bx(s, var);
    } else {
        store_reg(s, reg, var);
    }
}

876 877 878 879
/* Variant of store_reg which uses branch&exchange logic when storing
 * to r15 in ARM architecture v5T and above. This is used for storing
 * the results of a LDR/LDM/POP into r15, and corresponds to the cases
 * in the ARM ARM which use the LoadWritePC() pseudocode function. */
880
static inline void store_reg_from_load(DisasContext *s, int reg, TCGv_i32 var)
881 882 883 884 885 886 887 888
{
    if (reg == 15 && ENABLE_ARCH_5) {
        gen_bx(s, var);
    } else {
        store_reg(s, reg, var);
    }
}

889 890 891 892 893 894
#ifdef CONFIG_USER_ONLY
#define IS_USER_ONLY 1
#else
#define IS_USER_ONLY 0
#endif

895 896 897 898 899
/* Abstractions of "generate code to do a guest load/store for
 * AArch32", where a vaddr is always 32 bits (and is zero
 * extended if we're a 64 bit core) and  data is also
 * 32 bits unless specifically doing a 64 bit access.
 * These functions work like tcg_gen_qemu_{ld,st}* except
900
 * that the address argument is TCGv_i32 rather than TCGv.
901 902
 */

903
static inline TCGv gen_aa32_addr(DisasContext *s, TCGv_i32 a32, TCGMemOp op)
904
{
905 906 907
    TCGv addr = tcg_temp_new();
    tcg_gen_extu_i32_tl(addr, a32);

908
    /* Not needed for user-mode BE32, where we use MO_BE instead.  */
909 910
    if (!IS_USER_ONLY && s->sctlr_b && (op & MO_SIZE) < MO_32) {
        tcg_gen_xori_tl(addr, addr, 4 - (1 << (op & MO_SIZE)));
911
    }
912
    return addr;
913 914
}

915 916
static void gen_aa32_ld_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32,
                            int index, TCGMemOp opc)
917
{
918 919 920
    TCGv addr = gen_aa32_addr(s, a32, opc);
    tcg_gen_qemu_ld_i32(val, addr, index, opc);
    tcg_temp_free(addr);
921 922
}

923 924 925 926 927 928 929
static void gen_aa32_st_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32,
                            int index, TCGMemOp opc)
{
    TCGv addr = gen_aa32_addr(s, a32, opc);
    tcg_gen_qemu_st_i32(val, addr, index, opc);
    tcg_temp_free(addr);
}
930

931
#define DO_GEN_LD(SUFF, OPC)                                             \
932
static inline void gen_aa32_ld##SUFF(DisasContext *s, TCGv_i32 val,      \
933
                                     TCGv_i32 a32, int index)            \
934
{                                                                        \
935
    gen_aa32_ld_i32(s, val, a32, index, OPC | s->be_data);               \
936 937
}

938
#define DO_GEN_ST(SUFF, OPC)                                             \
939
static inline void gen_aa32_st##SUFF(DisasContext *s, TCGv_i32 val,      \
940
                                     TCGv_i32 a32, int index)            \
941
{                                                                        \
942
    gen_aa32_st_i32(s, val, a32, index, OPC | s->be_data);               \
943 944
}

945
static inline void gen_aa32_frob64(DisasContext *s, TCGv_i64 val)
946
{
947 948 949 950
    /* Not needed for user-mode BE32, where we use MO_BE instead.  */
    if (!IS_USER_ONLY && s->sctlr_b) {
        tcg_gen_rotri_i64(val, val, 32);
    }
951 952
}

953 954
static void gen_aa32_ld_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32,
                            int index, TCGMemOp opc)
955
{
956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971
    TCGv addr = gen_aa32_addr(s, a32, opc);
    tcg_gen_qemu_ld_i64(val, addr, index, opc);
    gen_aa32_frob64(s, val);
    tcg_temp_free(addr);
}

static inline void gen_aa32_ld64(DisasContext *s, TCGv_i64 val,
                                 TCGv_i32 a32, int index)
{
    gen_aa32_ld_i64(s, val, a32, index, MO_Q | s->be_data);
}

static void gen_aa32_st_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32,
                            int index, TCGMemOp opc)
{
    TCGv addr = gen_aa32_addr(s, a32, opc);
972 973 974

    /* Not needed for user-mode BE32, where we use MO_BE instead.  */
    if (!IS_USER_ONLY && s->sctlr_b) {
975
        TCGv_i64 tmp = tcg_temp_new_i64();
976
        tcg_gen_rotri_i64(tmp, val, 32);
977 978
        tcg_gen_qemu_st_i64(tmp, addr, index, opc);
        tcg_temp_free_i64(tmp);
979
    } else {
980
        tcg_gen_qemu_st_i64(val, addr, index, opc);
981
    }
982
    tcg_temp_free(addr);
983 984
}

985 986 987 988 989
static inline void gen_aa32_st64(DisasContext *s, TCGv_i64 val,
                                 TCGv_i32 a32, int index)
{
    gen_aa32_st_i64(s, val, a32, index, MO_Q | s->be_data);
}
990

991 992 993 994 995 996 997 998
DO_GEN_LD(8s, MO_SB)
DO_GEN_LD(8u, MO_UB)
DO_GEN_LD(16s, MO_SW)
DO_GEN_LD(16u, MO_UW)
DO_GEN_LD(32u, MO_UL)
DO_GEN_ST(8, MO_UB)
DO_GEN_ST(16, MO_UW)
DO_GEN_ST(32, MO_UL)
999

1000
static inline void gen_set_pc_im(DisasContext *s, target_ulong val)
P
pbrook 已提交
1001
{
1002
    tcg_gen_movi_i32(cpu_R[15], val);
P
pbrook 已提交
1003 1004
}

1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037
static inline void gen_hvc(DisasContext *s, int imm16)
{
    /* The pre HVC helper handles cases when HVC gets trapped
     * as an undefined insn by runtime configuration (ie before
     * the insn really executes).
     */
    gen_set_pc_im(s, s->pc - 4);
    gen_helper_pre_hvc(cpu_env);
    /* Otherwise we will treat this as a real exception which
     * happens after execution of the insn. (The distinction matters
     * for the PC value reported to the exception handler and also
     * for single stepping.)
     */
    s->svc_imm = imm16;
    gen_set_pc_im(s, s->pc);
    s->is_jmp = DISAS_HVC;
}

static inline void gen_smc(DisasContext *s)
{
    /* As with HVC, we may take an exception either before or after
     * the insn executes.
     */
    TCGv_i32 tmp;

    gen_set_pc_im(s, s->pc - 4);
    tmp = tcg_const_i32(syn_aa32_smc());
    gen_helper_pre_smc(cpu_env, tmp);
    tcg_temp_free_i32(tmp);
    gen_set_pc_im(s, s->pc);
    s->is_jmp = DISAS_SMC;
}

1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056
static inline void
gen_set_condexec (DisasContext *s)
{
    if (s->condexec_mask) {
        uint32_t val = (s->condexec_cond << 4) | (s->condexec_mask >> 1);
        TCGv_i32 tmp = tcg_temp_new_i32();
        tcg_gen_movi_i32(tmp, val);
        store_cpu_field(tmp, condexec_bits);
    }
}

static void gen_exception_internal_insn(DisasContext *s, int offset, int excp)
{
    gen_set_condexec(s);
    gen_set_pc_im(s, s->pc - offset);
    gen_exception_internal(excp);
    s->is_jmp = DISAS_JUMP;
}

1057 1058
static void gen_exception_insn(DisasContext *s, int offset, int excp,
                               int syn, uint32_t target_el)
1059 1060 1061
{
    gen_set_condexec(s);
    gen_set_pc_im(s, s->pc - offset);
1062
    gen_exception(excp, syn, target_el);
1063 1064 1065
    s->is_jmp = DISAS_JUMP;
}

B
bellard 已提交
1066 1067 1068
/* Force a TB lookup after an instruction that changes the CPU state.  */
static inline void gen_lookup_tb(DisasContext *s)
{
1069
    tcg_gen_movi_i32(cpu_R[15], s->pc & ~1);
1070
    s->is_jmp = DISAS_JUMP;
B
bellard 已提交
1071 1072
}

1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099
static inline void gen_hlt(DisasContext *s, int imm)
{
    /* HLT. This has two purposes.
     * Architecturally, it is an external halting debug instruction.
     * Since QEMU doesn't implement external debug, we treat this as
     * it is required for halting debug disabled: it will UNDEF.
     * Secondly, "HLT 0x3C" is a T32 semihosting trap instruction,
     * and "HLT 0xF000" is an A32 semihosting syscall. These traps
     * must trigger semihosting even for ARMv7 and earlier, where
     * HLT was an undefined encoding.
     * In system mode, we don't allow userspace access to
     * semihosting, to provide some semblance of security
     * (and for consistency with our 32-bit semihosting).
     */
    if (semihosting_enabled() &&
#ifndef CONFIG_USER_ONLY
        s->current_el != 0 &&
#endif
        (imm == (s->thumb ? 0x3c : 0xf000))) {
        gen_exception_internal_insn(s, 0, EXCP_SEMIHOST);
        return;
    }

    gen_exception_insn(s, s->thumb ? 2 : 4, EXCP_UDEF, syn_uncategorized(),
                       default_exception_el(s));
}

P
pbrook 已提交
1100
static inline void gen_add_data_offset(DisasContext *s, unsigned int insn,
1101
                                       TCGv_i32 var)
B
bellard 已提交
1102
{
B
bellard 已提交
1103
    int val, rm, shift, shiftop;
1104
    TCGv_i32 offset;
B
bellard 已提交
1105 1106 1107 1108 1109 1110

    if (!(insn & (1 << 25))) {
        /* immediate */
        val = insn & 0xfff;
        if (!(insn & (1 << 23)))
            val = -val;
B
bellard 已提交
1111
        if (val != 0)
P
pbrook 已提交
1112
            tcg_gen_addi_i32(var, var, val);
B
bellard 已提交
1113 1114 1115 1116
    } else {
        /* shift/register */
        rm = (insn) & 0xf;
        shift = (insn >> 7) & 0x1f;
B
bellard 已提交
1117
        shiftop = (insn >> 5) & 3;
P
pbrook 已提交
1118
        offset = load_reg(s, rm);
P
pbrook 已提交
1119
        gen_arm_shift_im(offset, shiftop, shift, 0);
B
bellard 已提交
1120
        if (!(insn & (1 << 23)))
P
pbrook 已提交
1121
            tcg_gen_sub_i32(var, var, offset);
B
bellard 已提交
1122
        else
P
pbrook 已提交
1123
            tcg_gen_add_i32(var, var, offset);
1124
        tcg_temp_free_i32(offset);
B
bellard 已提交
1125 1126 1127
    }
}

P
pbrook 已提交
1128
static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn,
1129
                                        int extra, TCGv_i32 var)
B
bellard 已提交
1130 1131
{
    int val, rm;
1132
    TCGv_i32 offset;
1133

B
bellard 已提交
1134 1135 1136 1137 1138
    if (insn & (1 << 22)) {
        /* immediate */
        val = (insn & 0xf) | ((insn >> 4) & 0xf0);
        if (!(insn & (1 << 23)))
            val = -val;
1139
        val += extra;
B
bellard 已提交
1140
        if (val != 0)
P
pbrook 已提交
1141
            tcg_gen_addi_i32(var, var, val);
B
bellard 已提交
1142 1143
    } else {
        /* register */
P
pbrook 已提交
1144
        if (extra)
P
pbrook 已提交
1145
            tcg_gen_addi_i32(var, var, extra);
B
bellard 已提交
1146
        rm = (insn) & 0xf;
P
pbrook 已提交
1147
        offset = load_reg(s, rm);
B
bellard 已提交
1148
        if (!(insn & (1 << 23)))
P
pbrook 已提交
1149
            tcg_gen_sub_i32(var, var, offset);
B
bellard 已提交
1150
        else
P
pbrook 已提交
1151
            tcg_gen_add_i32(var, var, offset);
1152
        tcg_temp_free_i32(offset);
B
bellard 已提交
1153 1154 1155
    }
}

1156 1157 1158 1159 1160
static TCGv_ptr get_fpstatus_ptr(int neon)
{
    TCGv_ptr statusptr = tcg_temp_new_ptr();
    int offset;
    if (neon) {
1161
        offset = offsetof(CPUARMState, vfp.standard_fp_status);
1162
    } else {
1163
        offset = offsetof(CPUARMState, vfp.fp_status);
1164 1165 1166 1167 1168
    }
    tcg_gen_addi_ptr(statusptr, cpu_env, offset);
    return statusptr;
}

P
pbrook 已提交
1169 1170 1171
#define VFP_OP2(name)                                                 \
static inline void gen_vfp_##name(int dp)                             \
{                                                                     \
1172 1173 1174 1175 1176 1177 1178
    TCGv_ptr fpst = get_fpstatus_ptr(0);                              \
    if (dp) {                                                         \
        gen_helper_vfp_##name##d(cpu_F0d, cpu_F0d, cpu_F1d, fpst);    \
    } else {                                                          \
        gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, cpu_F1s, fpst);    \
    }                                                                 \
    tcg_temp_free_ptr(fpst);                                          \
B
bellard 已提交
1179 1180
}

P
pbrook 已提交
1181 1182 1183 1184 1185 1186 1187
VFP_OP2(add)
VFP_OP2(sub)
VFP_OP2(mul)
VFP_OP2(div)

#undef VFP_OP2

1188 1189 1190
static inline void gen_vfp_F1_mul(int dp)
{
    /* Like gen_vfp_mul() but put result in F1 */
1191
    TCGv_ptr fpst = get_fpstatus_ptr(0);
1192
    if (dp) {
1193
        gen_helper_vfp_muld(cpu_F1d, cpu_F0d, cpu_F1d, fpst);
1194
    } else {
1195
        gen_helper_vfp_muls(cpu_F1s, cpu_F0s, cpu_F1s, fpst);
1196
    }
1197
    tcg_temp_free_ptr(fpst);
1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209
}

static inline void gen_vfp_F1_neg(int dp)
{
    /* Like gen_vfp_neg() but put result in F1 */
    if (dp) {
        gen_helper_vfp_negd(cpu_F1d, cpu_F0d);
    } else {
        gen_helper_vfp_negs(cpu_F1s, cpu_F0s);
    }
}

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
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 已提交
1253
        tcg_gen_movi_i64(cpu_F1d, 0);
P
pbrook 已提交
1254
    else
B
balrog 已提交
1255
        tcg_gen_movi_i32(cpu_F1s, 0);
P
pbrook 已提交
1256 1257
}

1258 1259 1260
#define VFP_GEN_ITOF(name) \
static inline void gen_vfp_##name(int dp, int neon) \
{ \
1261
    TCGv_ptr statusptr = get_fpstatus_ptr(neon); \
1262 1263 1264 1265 1266
    if (dp) { \
        gen_helper_vfp_##name##d(cpu_F0d, cpu_F0s, statusptr); \
    } else { \
        gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, statusptr); \
    } \
1267
    tcg_temp_free_ptr(statusptr); \
P
pbrook 已提交
1268 1269
}

1270 1271 1272
VFP_GEN_ITOF(uito)
VFP_GEN_ITOF(sito)
#undef VFP_GEN_ITOF
P
pbrook 已提交
1273

1274 1275 1276
#define VFP_GEN_FTOI(name) \
static inline void gen_vfp_##name(int dp, int neon) \
{ \
1277
    TCGv_ptr statusptr = get_fpstatus_ptr(neon); \
1278 1279 1280 1281 1282
    if (dp) { \
        gen_helper_vfp_##name##d(cpu_F0s, cpu_F0d, statusptr); \
    } else { \
        gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, statusptr); \
    } \
1283
    tcg_temp_free_ptr(statusptr); \
P
pbrook 已提交
1284 1285
}

1286 1287 1288 1289 1290
VFP_GEN_FTOI(toui)
VFP_GEN_FTOI(touiz)
VFP_GEN_FTOI(tosi)
VFP_GEN_FTOI(tosiz)
#undef VFP_GEN_FTOI
P
pbrook 已提交
1291

1292
#define VFP_GEN_FIX(name, round) \
1293
static inline void gen_vfp_##name(int dp, int shift, int neon) \
P
pbrook 已提交
1294
{ \
1295
    TCGv_i32 tmp_shift = tcg_const_i32(shift); \
1296
    TCGv_ptr statusptr = get_fpstatus_ptr(neon); \
1297
    if (dp) { \
1298 1299
        gen_helper_vfp_##name##d##round(cpu_F0d, cpu_F0d, tmp_shift, \
                                        statusptr); \
1300
    } else { \
1301 1302
        gen_helper_vfp_##name##s##round(cpu_F0s, cpu_F0s, tmp_shift, \
                                        statusptr); \
1303
    } \
1304
    tcg_temp_free_i32(tmp_shift); \
1305
    tcg_temp_free_ptr(statusptr); \
P
pbrook 已提交
1306
}
1307 1308 1309 1310 1311 1312 1313 1314
VFP_GEN_FIX(tosh, _round_to_zero)
VFP_GEN_FIX(tosl, _round_to_zero)
VFP_GEN_FIX(touh, _round_to_zero)
VFP_GEN_FIX(toul, _round_to_zero)
VFP_GEN_FIX(shto, )
VFP_GEN_FIX(slto, )
VFP_GEN_FIX(uhto, )
VFP_GEN_FIX(ulto, )
P
pbrook 已提交
1315
#undef VFP_GEN_FIX
P
pbrook 已提交
1316

1317
static inline void gen_vfp_ld(DisasContext *s, int dp, TCGv_i32 addr)
B
bellard 已提交
1318
{
1319
    if (dp) {
1320
        gen_aa32_ld64(s, cpu_F0d, addr, get_mem_index(s));
1321
    } else {
1322
        gen_aa32_ld32u(s, cpu_F0s, addr, get_mem_index(s));
1323
    }
B
bellard 已提交
1324 1325
}

1326
static inline void gen_vfp_st(DisasContext *s, int dp, TCGv_i32 addr)
B
bellard 已提交
1327
{
1328
    if (dp) {
1329
        gen_aa32_st64(s, cpu_F0d, addr, get_mem_index(s));
1330
    } else {
1331
        gen_aa32_st32(s, cpu_F0s, addr, get_mem_index(s));
1332
    }
B
bellard 已提交
1333 1334
}

B
bellard 已提交
1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347
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 已提交
1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358

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

1359
static TCGv_i32 neon_load_reg(int reg, int pass)
P
pbrook 已提交
1360
{
1361
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
1362 1363 1364 1365
    tcg_gen_ld_i32(tmp, cpu_env, neon_reg_offset(reg, pass));
    return tmp;
}

1366
static void neon_store_reg(int reg, int pass, TCGv_i32 var)
P
pbrook 已提交
1367 1368
{
    tcg_gen_st_i32(var, cpu_env, neon_reg_offset(reg, pass));
1369
    tcg_temp_free_i32(var);
P
pbrook 已提交
1370 1371
}

P
pbrook 已提交
1372
static inline void neon_load_reg64(TCGv_i64 var, int reg)
P
pbrook 已提交
1373 1374 1375 1376
{
    tcg_gen_ld_i64(var, cpu_env, vfp_reg_offset(1, reg));
}

P
pbrook 已提交
1377
static inline void neon_store_reg64(TCGv_i64 var, int reg)
P
pbrook 已提交
1378 1379 1380 1381
{
    tcg_gen_st_i64(var, cpu_env, vfp_reg_offset(1, reg));
}

P
pbrook 已提交
1382 1383 1384 1385 1386
#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 已提交
1387 1388 1389
static inline void gen_mov_F0_vreg(int dp, int reg)
{
    if (dp)
P
pbrook 已提交
1390
        tcg_gen_ld_f64(cpu_F0d, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1391
    else
P
pbrook 已提交
1392
        tcg_gen_ld_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1393 1394 1395 1396 1397
}

static inline void gen_mov_F1_vreg(int dp, int reg)
{
    if (dp)
P
pbrook 已提交
1398
        tcg_gen_ld_f64(cpu_F1d, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1399
    else
P
pbrook 已提交
1400
        tcg_gen_ld_f32(cpu_F1s, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1401 1402 1403 1404 1405
}

static inline void gen_mov_vreg_F0(int dp, int reg)
{
    if (dp)
P
pbrook 已提交
1406
        tcg_gen_st_f64(cpu_F0d, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1407
    else
P
pbrook 已提交
1408
        tcg_gen_st_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1409 1410
}

1411 1412
#define ARM_CP_RW_BIT	(1 << 20)

P
pbrook 已提交
1413
static inline void iwmmxt_load_reg(TCGv_i64 var, int reg)
P
pbrook 已提交
1414
{
1415
    tcg_gen_ld_i64(var, cpu_env, offsetof(CPUARMState, iwmmxt.regs[reg]));
P
pbrook 已提交
1416 1417
}

P
pbrook 已提交
1418
static inline void iwmmxt_store_reg(TCGv_i64 var, int reg)
P
pbrook 已提交
1419
{
1420
    tcg_gen_st_i64(var, cpu_env, offsetof(CPUARMState, iwmmxt.regs[reg]));
P
pbrook 已提交
1421 1422
}

1423
static inline TCGv_i32 iwmmxt_load_creg(int reg)
P
pbrook 已提交
1424
{
1425
    TCGv_i32 var = tcg_temp_new_i32();
1426
    tcg_gen_ld_i32(var, cpu_env, offsetof(CPUARMState, iwmmxt.cregs[reg]));
1427
    return var;
P
pbrook 已提交
1428 1429
}

1430
static inline void iwmmxt_store_creg(int reg, TCGv_i32 var)
P
pbrook 已提交
1431
{
1432
    tcg_gen_st_i32(var, cpu_env, offsetof(CPUARMState, iwmmxt.cregs[reg]));
1433
    tcg_temp_free_i32(var);
P
pbrook 已提交
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
}

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

1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481
#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)
P
pbrook 已提交
1482

1483
#define IWMMXT_OP_ENV1(name) \
P
pbrook 已提交
1484 1485
static inline void gen_op_iwmmxt_##name##_M0(void) \
{ \
1486
    gen_helper_iwmmxt_##name(cpu_M0, cpu_env, cpu_M0); \
P
pbrook 已提交
1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499
}

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)

1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535
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)
P
pbrook 已提交
1536

1537 1538 1539 1540 1541 1542
IWMMXT_OP_ENV(packuw)
IWMMXT_OP_ENV(packul)
IWMMXT_OP_ENV(packuq)
IWMMXT_OP_ENV(packsw)
IWMMXT_OP_ENV(packsl)
IWMMXT_OP_ENV(packsq)
P
pbrook 已提交
1543 1544 1545

static void gen_op_iwmmxt_set_mup(void)
{
1546
    TCGv_i32 tmp;
P
pbrook 已提交
1547 1548 1549 1550 1551 1552 1553
    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)
{
1554
    TCGv_i32 tmp;
P
pbrook 已提交
1555 1556 1557 1558 1559 1560 1561
    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)
{
1562
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
1563 1564 1565 1566 1567 1568 1569
    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 已提交
1570
    tcg_gen_ext32u_i64(cpu_V1, cpu_V1);
P
pbrook 已提交
1571 1572 1573
    tcg_gen_add_i64(cpu_M0, cpu_M0, cpu_V1);
}

1574 1575
static inline int gen_iwmmxt_address(DisasContext *s, uint32_t insn,
                                     TCGv_i32 dest)
1576 1577 1578
{
    int rd;
    uint32_t offset;
1579
    TCGv_i32 tmp;
1580 1581

    rd = (insn >> 16) & 0xf;
1582
    tmp = load_reg(s, rd);
1583 1584 1585 1586 1587

    offset = (insn & 0xff) << ((insn >> 7) & 2);
    if (insn & (1 << 24)) {
        /* Pre indexed */
        if (insn & (1 << 23))
1588
            tcg_gen_addi_i32(tmp, tmp, offset);
1589
        else
1590 1591
            tcg_gen_addi_i32(tmp, tmp, -offset);
        tcg_gen_mov_i32(dest, tmp);
1592
        if (insn & (1 << 21))
1593 1594
            store_reg(s, rd, tmp);
        else
1595
            tcg_temp_free_i32(tmp);
1596 1597
    } else if (insn & (1 << 21)) {
        /* Post indexed */
1598
        tcg_gen_mov_i32(dest, tmp);
1599
        if (insn & (1 << 23))
1600
            tcg_gen_addi_i32(tmp, tmp, offset);
1601
        else
1602 1603
            tcg_gen_addi_i32(tmp, tmp, -offset);
        store_reg(s, rd, tmp);
1604 1605 1606 1607 1608
    } else if (!(insn & (1 << 23)))
        return 1;
    return 0;
}

1609
static inline int gen_iwmmxt_shift(uint32_t insn, uint32_t mask, TCGv_i32 dest)
1610 1611
{
    int rd = (insn >> 0) & 0xf;
1612
    TCGv_i32 tmp;
1613

1614 1615
    if (insn & (1 << 8)) {
        if (rd < ARM_IWMMXT_wCGR0 || rd > ARM_IWMMXT_wCGR3) {
1616
            return 1;
1617 1618 1619 1620
        } else {
            tmp = iwmmxt_load_creg(rd);
        }
    } else {
1621
        tmp = tcg_temp_new_i32();
1622
        iwmmxt_load_reg(cpu_V0, rd);
1623
        tcg_gen_extrl_i64_i32(tmp, cpu_V0);
1624 1625 1626
    }
    tcg_gen_andi_i32(tmp, tmp, mask);
    tcg_gen_mov_i32(dest, tmp);
1627
    tcg_temp_free_i32(tmp);
1628 1629 1630
    return 0;
}

1631
/* Disassemble an iwMMXt instruction.  Returns nonzero if an error occurred
1632
   (ie. an undefined instruction).  */
1633
static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
1634 1635 1636
{
    int rd, wrd;
    int rdhi, rdlo, rd0, rd1, i;
1637 1638
    TCGv_i32 addr;
    TCGv_i32 tmp, tmp2, tmp3;
1639 1640 1641 1642 1643 1644 1645

    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 */
1646
                iwmmxt_load_reg(cpu_V0, wrd);
1647
                tcg_gen_extrl_i64_i32(cpu_R[rdlo], cpu_V0);
1648
                tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
1649
                tcg_gen_extrl_i64_i32(cpu_R[rdhi], cpu_V0);
1650
            } else {					/* TMCRR */
1651 1652
                tcg_gen_concat_i32_i64(cpu_V0, cpu_R[rdlo], cpu_R[rdhi]);
                iwmmxt_store_reg(cpu_V0, wrd);
1653 1654 1655 1656 1657 1658
                gen_op_iwmmxt_set_mup();
            }
            return 0;
        }

        wrd = (insn >> 12) & 0xf;
1659
        addr = tcg_temp_new_i32();
1660
        if (gen_iwmmxt_address(s, insn, addr)) {
1661
            tcg_temp_free_i32(addr);
1662
            return 1;
1663
        }
1664 1665
        if (insn & ARM_CP_RW_BIT) {
            if ((insn >> 28) == 0xf) {			/* WLDRW wCx */
1666
                tmp = tcg_temp_new_i32();
1667
                gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
1668
                iwmmxt_store_creg(wrd, tmp);
1669
            } else {
P
pbrook 已提交
1670 1671 1672
                i = 1;
                if (insn & (1 << 8)) {
                    if (insn & (1 << 22)) {		/* WLDRD */
1673
                        gen_aa32_ld64(s, cpu_M0, addr, get_mem_index(s));
P
pbrook 已提交
1674 1675
                        i = 0;
                    } else {				/* WLDRW wRd */
1676
                        tmp = tcg_temp_new_i32();
1677
                        gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
1678 1679
                    }
                } else {
1680
                    tmp = tcg_temp_new_i32();
P
pbrook 已提交
1681
                    if (insn & (1 << 22)) {		/* WLDRH */
1682
                        gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
1683
                    } else {				/* WLDRB */
1684
                        gen_aa32_ld8u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
1685 1686 1687 1688
                    }
                }
                if (i) {
                    tcg_gen_extu_i32_i64(cpu_M0, tmp);
1689
                    tcg_temp_free_i32(tmp);
P
pbrook 已提交
1690
                }
1691 1692 1693 1694
                gen_op_iwmmxt_movq_wRn_M0(wrd);
            }
        } else {
            if ((insn >> 28) == 0xf) {			/* WSTRW wCx */
1695
                tmp = iwmmxt_load_creg(wrd);
1696
                gen_aa32_st32(s, tmp, addr, get_mem_index(s));
1697 1698
            } else {
                gen_op_iwmmxt_movq_M0_wRn(wrd);
1699
                tmp = tcg_temp_new_i32();
P
pbrook 已提交
1700 1701
                if (insn & (1 << 8)) {
                    if (insn & (1 << 22)) {		/* WSTRD */
1702
                        gen_aa32_st64(s, cpu_M0, addr, get_mem_index(s));
P
pbrook 已提交
1703
                    } else {				/* WSTRW wRd */
1704
                        tcg_gen_extrl_i64_i32(tmp, cpu_M0);
1705
                        gen_aa32_st32(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
1706 1707 1708
                    }
                } else {
                    if (insn & (1 << 22)) {		/* WSTRH */
1709
                        tcg_gen_extrl_i64_i32(tmp, cpu_M0);
1710
                        gen_aa32_st16(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
1711
                    } else {				/* WSTRB */
1712
                        tcg_gen_extrl_i64_i32(tmp, cpu_M0);
1713
                        gen_aa32_st8(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
1714 1715
                    }
                }
1716
            }
1717
            tcg_temp_free_i32(tmp);
1718
        }
1719
        tcg_temp_free_i32(addr);
1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750
        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:
1751 1752
            tmp = iwmmxt_load_creg(wrd);
            tmp2 = load_reg(s, rd);
1753
            tcg_gen_andc_i32(tmp, tmp, tmp2);
1754
            tcg_temp_free_i32(tmp2);
1755
            iwmmxt_store_creg(wrd, tmp);
1756 1757 1758 1759 1760 1761
            break;
        case ARM_IWMMXT_wCGR0:
        case ARM_IWMMXT_wCGR1:
        case ARM_IWMMXT_wCGR2:
        case ARM_IWMMXT_wCGR3:
            gen_op_iwmmxt_set_cup();
1762 1763
            tmp = load_reg(s, rd);
            iwmmxt_store_creg(wrd, tmp);
1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784
            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;
1785 1786
        tmp = iwmmxt_load_creg(wrd);
        store_reg(s, rd, tmp);
1787 1788 1789 1790 1791 1792
        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 已提交
1793
        tcg_gen_neg_i64(cpu_M0, cpu_M0);
1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885
        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 已提交
1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896
        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);
        }
1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909
        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 已提交
1910 1911
            iwmmxt_load_reg(cpu_V1, wrd);
            tcg_gen_add_i64(cpu_M0, cpu_M0, cpu_V1);
1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942
        }
        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 已提交
1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953
        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);
        }
1954 1955 1956 1957 1958 1959 1960 1961 1962
        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);
1963 1964 1965 1966
        tmp = iwmmxt_load_creg(ARM_IWMMXT_wCGR0 + ((insn >> 20) & 3));
        tcg_gen_andi_i32(tmp, tmp, 7);
        iwmmxt_load_reg(cpu_V1, rd1);
        gen_helper_iwmmxt_align(cpu_M0, cpu_M0, cpu_V1, tmp);
1967
        tcg_temp_free_i32(tmp);
1968 1969 1970 1971
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        break;
    case 0x601: case 0x605: case 0x609: case 0x60d:	/* TINSR */
1972 1973
        if (((insn >> 6) & 3) == 3)
            return 1;
1974 1975
        rd = (insn >> 12) & 0xf;
        wrd = (insn >> 16) & 0xf;
1976
        tmp = load_reg(s, rd);
1977 1978 1979
        gen_op_iwmmxt_movq_M0_wRn(wrd);
        switch ((insn >> 6) & 3) {
        case 0:
1980 1981
            tmp2 = tcg_const_i32(0xff);
            tmp3 = tcg_const_i32((insn & 7) << 3);
1982 1983
            break;
        case 1:
1984 1985
            tmp2 = tcg_const_i32(0xffff);
            tmp3 = tcg_const_i32((insn & 3) << 4);
1986 1987
            break;
        case 2:
1988 1989
            tmp2 = tcg_const_i32(0xffffffff);
            tmp3 = tcg_const_i32((insn & 1) << 5);
1990
            break;
1991
        default:
1992 1993
            TCGV_UNUSED_I32(tmp2);
            TCGV_UNUSED_I32(tmp3);
1994
        }
1995
        gen_helper_iwmmxt_insr(cpu_M0, cpu_M0, tmp, tmp2, tmp3);
1996 1997
        tcg_temp_free_i32(tmp3);
        tcg_temp_free_i32(tmp2);
1998
        tcg_temp_free_i32(tmp);
1999 2000 2001 2002 2003 2004
        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;
2005
        if (rd == 15 || ((insn >> 22) & 3) == 3)
2006 2007
            return 1;
        gen_op_iwmmxt_movq_M0_wRn(wrd);
2008
        tmp = tcg_temp_new_i32();
2009 2010
        switch ((insn >> 22) & 3) {
        case 0:
2011
            tcg_gen_shri_i64(cpu_M0, cpu_M0, (insn & 7) << 3);
2012
            tcg_gen_extrl_i64_i32(tmp, cpu_M0);
2013 2014 2015 2016
            if (insn & 8) {
                tcg_gen_ext8s_i32(tmp, tmp);
            } else {
                tcg_gen_andi_i32(tmp, tmp, 0xff);
2017 2018 2019
            }
            break;
        case 1:
2020
            tcg_gen_shri_i64(cpu_M0, cpu_M0, (insn & 3) << 4);
2021
            tcg_gen_extrl_i64_i32(tmp, cpu_M0);
2022 2023 2024 2025
            if (insn & 8) {
                tcg_gen_ext16s_i32(tmp, tmp);
            } else {
                tcg_gen_andi_i32(tmp, tmp, 0xffff);
2026 2027 2028
            }
            break;
        case 2:
2029
            tcg_gen_shri_i64(cpu_M0, cpu_M0, (insn & 1) << 5);
2030
            tcg_gen_extrl_i64_i32(tmp, cpu_M0);
2031 2032
            break;
        }
2033
        store_reg(s, rd, tmp);
2034 2035
        break;
    case 0x117: case 0x517: case 0x917: case 0xd17:	/* TEXTRC */
2036
        if ((insn & 0x000ff008) != 0x0003f000 || ((insn >> 22) & 3) == 3)
2037
            return 1;
2038
        tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF);
2039 2040
        switch ((insn >> 22) & 3) {
        case 0:
2041
            tcg_gen_shri_i32(tmp, tmp, ((insn & 7) << 2) + 0);
2042 2043
            break;
        case 1:
2044
            tcg_gen_shri_i32(tmp, tmp, ((insn & 3) << 3) + 4);
2045 2046
            break;
        case 2:
2047
            tcg_gen_shri_i32(tmp, tmp, ((insn & 1) << 4) + 12);
2048 2049
            break;
        }
2050 2051
        tcg_gen_shli_i32(tmp, tmp, 28);
        gen_set_nzcv(tmp);
2052
        tcg_temp_free_i32(tmp);
2053 2054
        break;
    case 0x401: case 0x405: case 0x409: case 0x40d:	/* TBCST */
2055 2056
        if (((insn >> 6) & 3) == 3)
            return 1;
2057 2058
        rd = (insn >> 12) & 0xf;
        wrd = (insn >> 16) & 0xf;
2059
        tmp = load_reg(s, rd);
2060 2061
        switch ((insn >> 6) & 3) {
        case 0:
2062
            gen_helper_iwmmxt_bcstb(cpu_M0, tmp);
2063 2064
            break;
        case 1:
2065
            gen_helper_iwmmxt_bcstw(cpu_M0, tmp);
2066 2067
            break;
        case 2:
2068
            gen_helper_iwmmxt_bcstl(cpu_M0, tmp);
2069 2070
            break;
        }
2071
        tcg_temp_free_i32(tmp);
2072 2073 2074 2075
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        break;
    case 0x113: case 0x513: case 0x913: case 0xd13:	/* TANDC */
2076
        if ((insn & 0x000ff00f) != 0x0003f000 || ((insn >> 22) & 3) == 3)
2077
            return 1;
2078
        tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF);
2079
        tmp2 = tcg_temp_new_i32();
2080
        tcg_gen_mov_i32(tmp2, tmp);
2081 2082 2083
        switch ((insn >> 22) & 3) {
        case 0:
            for (i = 0; i < 7; i ++) {
2084 2085
                tcg_gen_shli_i32(tmp2, tmp2, 4);
                tcg_gen_and_i32(tmp, tmp, tmp2);
2086 2087 2088 2089
            }
            break;
        case 1:
            for (i = 0; i < 3; i ++) {
2090 2091
                tcg_gen_shli_i32(tmp2, tmp2, 8);
                tcg_gen_and_i32(tmp, tmp, tmp2);
2092 2093 2094
            }
            break;
        case 2:
2095 2096
            tcg_gen_shli_i32(tmp2, tmp2, 16);
            tcg_gen_and_i32(tmp, tmp, tmp2);
2097 2098
            break;
        }
2099
        gen_set_nzcv(tmp);
2100 2101
        tcg_temp_free_i32(tmp2);
        tcg_temp_free_i32(tmp);
2102 2103 2104 2105 2106 2107 2108
        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 已提交
2109
            gen_helper_iwmmxt_addcb(cpu_M0, cpu_M0);
2110 2111
            break;
        case 1:
P
pbrook 已提交
2112
            gen_helper_iwmmxt_addcw(cpu_M0, cpu_M0);
2113 2114
            break;
        case 2:
P
pbrook 已提交
2115
            gen_helper_iwmmxt_addcl(cpu_M0, cpu_M0);
2116 2117 2118 2119 2120 2121 2122 2123
            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 */
2124
        if ((insn & 0x000ff00f) != 0x0003f000 || ((insn >> 22) & 3) == 3)
2125
            return 1;
2126
        tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF);
2127
        tmp2 = tcg_temp_new_i32();
2128
        tcg_gen_mov_i32(tmp2, tmp);
2129 2130 2131
        switch ((insn >> 22) & 3) {
        case 0:
            for (i = 0; i < 7; i ++) {
2132 2133
                tcg_gen_shli_i32(tmp2, tmp2, 4);
                tcg_gen_or_i32(tmp, tmp, tmp2);
2134 2135 2136 2137
            }
            break;
        case 1:
            for (i = 0; i < 3; i ++) {
2138 2139
                tcg_gen_shli_i32(tmp2, tmp2, 8);
                tcg_gen_or_i32(tmp, tmp, tmp2);
2140 2141 2142
            }
            break;
        case 2:
2143 2144
            tcg_gen_shli_i32(tmp2, tmp2, 16);
            tcg_gen_or_i32(tmp, tmp, tmp2);
2145 2146
            break;
        }
2147
        gen_set_nzcv(tmp);
2148 2149
        tcg_temp_free_i32(tmp2);
        tcg_temp_free_i32(tmp);
2150 2151 2152 2153
        break;
    case 0x103: case 0x503: case 0x903: case 0xd03:	/* TMOVMSK */
        rd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
2154
        if ((insn & 0xf) != 0 || ((insn >> 22) & 3) == 3)
2155 2156
            return 1;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
2157
        tmp = tcg_temp_new_i32();
2158 2159
        switch ((insn >> 22) & 3) {
        case 0:
2160
            gen_helper_iwmmxt_msbb(tmp, cpu_M0);
2161 2162
            break;
        case 1:
2163
            gen_helper_iwmmxt_msbw(tmp, cpu_M0);
2164 2165
            break;
        case 2:
2166
            gen_helper_iwmmxt_msbl(tmp, cpu_M0);
2167 2168
            break;
        }
2169
        store_reg(s, rd, tmp);
2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 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
        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:
2267 2268
        if (((insn >> 22) & 3) == 0)
            return 1;
2269 2270 2271
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
2272
        tmp = tcg_temp_new_i32();
2273
        if (gen_iwmmxt_shift(insn, 0xff, tmp)) {
2274
            tcg_temp_free_i32(tmp);
2275
            return 1;
2276
        }
2277 2278
        switch ((insn >> 22) & 3) {
        case 1:
2279
            gen_helper_iwmmxt_srlw(cpu_M0, cpu_env, cpu_M0, tmp);
2280 2281
            break;
        case 2:
2282
            gen_helper_iwmmxt_srll(cpu_M0, cpu_env, cpu_M0, tmp);
2283 2284
            break;
        case 3:
2285
            gen_helper_iwmmxt_srlq(cpu_M0, cpu_env, cpu_M0, tmp);
2286 2287
            break;
        }
2288
        tcg_temp_free_i32(tmp);
2289 2290 2291 2292 2293 2294
        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:
2295 2296
        if (((insn >> 22) & 3) == 0)
            return 1;
2297 2298 2299
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
2300
        tmp = tcg_temp_new_i32();
2301
        if (gen_iwmmxt_shift(insn, 0xff, tmp)) {
2302
            tcg_temp_free_i32(tmp);
2303
            return 1;
2304
        }
2305 2306
        switch ((insn >> 22) & 3) {
        case 1:
2307
            gen_helper_iwmmxt_sraw(cpu_M0, cpu_env, cpu_M0, tmp);
2308 2309
            break;
        case 2:
2310
            gen_helper_iwmmxt_sral(cpu_M0, cpu_env, cpu_M0, tmp);
2311 2312
            break;
        case 3:
2313
            gen_helper_iwmmxt_sraq(cpu_M0, cpu_env, cpu_M0, tmp);
2314 2315
            break;
        }
2316
        tcg_temp_free_i32(tmp);
2317 2318 2319 2320 2321 2322
        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:
2323 2324
        if (((insn >> 22) & 3) == 0)
            return 1;
2325 2326 2327
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
2328
        tmp = tcg_temp_new_i32();
2329
        if (gen_iwmmxt_shift(insn, 0xff, tmp)) {
2330
            tcg_temp_free_i32(tmp);
2331
            return 1;
2332
        }
2333 2334
        switch ((insn >> 22) & 3) {
        case 1:
2335
            gen_helper_iwmmxt_sllw(cpu_M0, cpu_env, cpu_M0, tmp);
2336 2337
            break;
        case 2:
2338
            gen_helper_iwmmxt_slll(cpu_M0, cpu_env, cpu_M0, tmp);
2339 2340
            break;
        case 3:
2341
            gen_helper_iwmmxt_sllq(cpu_M0, cpu_env, cpu_M0, tmp);
2342 2343
            break;
        }
2344
        tcg_temp_free_i32(tmp);
2345 2346 2347 2348 2349 2350
        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:
2351 2352
        if (((insn >> 22) & 3) == 0)
            return 1;
2353 2354 2355
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
2356
        tmp = tcg_temp_new_i32();
2357 2358
        switch ((insn >> 22) & 3) {
        case 1:
2359
            if (gen_iwmmxt_shift(insn, 0xf, tmp)) {
2360
                tcg_temp_free_i32(tmp);
2361
                return 1;
2362
            }
2363
            gen_helper_iwmmxt_rorw(cpu_M0, cpu_env, cpu_M0, tmp);
2364 2365
            break;
        case 2:
2366
            if (gen_iwmmxt_shift(insn, 0x1f, tmp)) {
2367
                tcg_temp_free_i32(tmp);
2368
                return 1;
2369
            }
2370
            gen_helper_iwmmxt_rorl(cpu_M0, cpu_env, cpu_M0, tmp);
2371 2372
            break;
        case 3:
2373
            if (gen_iwmmxt_shift(insn, 0x3f, tmp)) {
2374
                tcg_temp_free_i32(tmp);
2375
                return 1;
2376
            }
2377
            gen_helper_iwmmxt_rorq(cpu_M0, cpu_env, cpu_M0, tmp);
2378 2379
            break;
        }
2380
        tcg_temp_free_i32(tmp);
2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452
        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);
2453 2454 2455
        tmp = tcg_const_i32((insn >> 20) & 3);
        iwmmxt_load_reg(cpu_V1, rd1);
        gen_helper_iwmmxt_align(cpu_M0, cpu_M0, cpu_V1, tmp);
2456
        tcg_temp_free_i32(tmp);
2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509
        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);
2510
        tmp = tcg_const_i32(((insn >> 16) & 0xf0) | (insn & 0x0f));
2511
        gen_helper_iwmmxt_shufh(cpu_M0, cpu_env, cpu_M0, tmp);
2512
        tcg_temp_free_i32(tmp);
2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563
        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:
2564 2565
        if (!(insn & (1 << 20)) || ((insn >> 22) & 3) == 0)
            return 1;
2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        rd1 = (insn >> 0) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
        switch ((insn >> 22) & 3) {
        case 1:
            if (insn & (1 << 21))
                gen_op_iwmmxt_packsw_M0_wRn(rd1);
            else
                gen_op_iwmmxt_packuw_M0_wRn(rd1);
            break;
        case 2:
            if (insn & (1 << 21))
                gen_op_iwmmxt_packsl_M0_wRn(rd1);
            else
                gen_op_iwmmxt_packul_M0_wRn(rd1);
            break;
        case 3:
            if (insn & (1 << 21))
                gen_op_iwmmxt_packsq_M0_wRn(rd1);
            else
                gen_op_iwmmxt_packuq_M0_wRn(rd1);
            break;
        }
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        gen_op_iwmmxt_set_cup();
        break;
    case 0x201: case 0x203: case 0x205: case 0x207:
    case 0x209: case 0x20b: case 0x20d: case 0x20f:
    case 0x211: case 0x213: case 0x215: case 0x217:
    case 0x219: case 0x21b: case 0x21d: case 0x21f:
        wrd = (insn >> 5) & 0xf;
        rd0 = (insn >> 12) & 0xf;
        rd1 = (insn >> 0) & 0xf;
        if (rd0 == 0xf || rd1 == 0xf)
            return 1;
        gen_op_iwmmxt_movq_M0_wRn(wrd);
2604 2605
        tmp = load_reg(s, rd0);
        tmp2 = load_reg(s, rd1);
2606 2607
        switch ((insn >> 16) & 0xf) {
        case 0x0:					/* TMIA */
2608
            gen_helper_iwmmxt_muladdsl(cpu_M0, cpu_M0, tmp, tmp2);
2609 2610
            break;
        case 0x8:					/* TMIAPH */
2611
            gen_helper_iwmmxt_muladdsw(cpu_M0, cpu_M0, tmp, tmp2);
2612 2613 2614
            break;
        case 0xc: case 0xd: case 0xe: case 0xf:		/* TMIAxy */
            if (insn & (1 << 16))
2615
                tcg_gen_shri_i32(tmp, tmp, 16);
2616
            if (insn & (1 << 17))
2617 2618
                tcg_gen_shri_i32(tmp2, tmp2, 16);
            gen_helper_iwmmxt_muladdswl(cpu_M0, cpu_M0, tmp, tmp2);
2619 2620
            break;
        default:
2621 2622
            tcg_temp_free_i32(tmp2);
            tcg_temp_free_i32(tmp);
2623 2624
            return 1;
        }
2625 2626
        tcg_temp_free_i32(tmp2);
        tcg_temp_free_i32(tmp);
2627 2628 2629 2630 2631 2632 2633 2634 2635 2636
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        break;
    default:
        return 1;
    }

    return 0;
}

2637
/* Disassemble an XScale DSP instruction.  Returns nonzero if an error occurred
2638
   (ie. an undefined instruction).  */
2639
static int disas_dsp_insn(DisasContext *s, uint32_t insn)
2640 2641
{
    int acc, rd0, rd1, rdhi, rdlo;
2642
    TCGv_i32 tmp, tmp2;
2643 2644 2645 2646 2647 2648 2649 2650 2651 2652

    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;

2653 2654
        tmp = load_reg(s, rd0);
        tmp2 = load_reg(s, rd1);
2655 2656
        switch ((insn >> 16) & 0xf) {
        case 0x0:					/* MIA */
2657
            gen_helper_iwmmxt_muladdsl(cpu_M0, cpu_M0, tmp, tmp2);
2658 2659
            break;
        case 0x8:					/* MIAPH */
2660
            gen_helper_iwmmxt_muladdsw(cpu_M0, cpu_M0, tmp, tmp2);
2661 2662 2663 2664 2665 2666
            break;
        case 0xc:					/* MIABB */
        case 0xd:					/* MIABT */
        case 0xe:					/* MIATB */
        case 0xf:					/* MIATT */
            if (insn & (1 << 16))
2667
                tcg_gen_shri_i32(tmp, tmp, 16);
2668
            if (insn & (1 << 17))
2669 2670
                tcg_gen_shri_i32(tmp2, tmp2, 16);
            gen_helper_iwmmxt_muladdswl(cpu_M0, cpu_M0, tmp, tmp2);
2671 2672 2673 2674
            break;
        default:
            return 1;
        }
2675 2676
        tcg_temp_free_i32(tmp2);
        tcg_temp_free_i32(tmp);
2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691

        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 */
2692
            iwmmxt_load_reg(cpu_V0, acc);
2693
            tcg_gen_extrl_i64_i32(cpu_R[rdlo], cpu_V0);
2694
            tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
2695
            tcg_gen_extrl_i64_i32(cpu_R[rdhi], cpu_V0);
2696
            tcg_gen_andi_i32(cpu_R[rdhi], cpu_R[rdhi], (1 << (40 - 32)) - 1);
2697
        } else {					/* MAR */
2698 2699
            tcg_gen_concat_i32_i64(cpu_V0, cpu_R[rdlo], cpu_R[rdhi]);
            iwmmxt_store_reg(cpu_V0, acc);
2700 2701 2702 2703 2704 2705 2706
        }
        return 0;
    }

    return 1;
}

P
pbrook 已提交
2707 2708 2709 2710
#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 { \
2711
    if (arm_dc_feature(s, ARM_FEATURE_VFP3)) { \
P
pbrook 已提交
2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726
        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 已提交
2727
/* Move between integer and VFP cores.  */
2728
static TCGv_i32 gen_vfp_mrs(void)
P
pbrook 已提交
2729
{
2730
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
2731 2732 2733 2734
    tcg_gen_mov_i32(tmp, cpu_F0s);
    return tmp;
}

2735
static void gen_vfp_msr(TCGv_i32 tmp)
P
pbrook 已提交
2736 2737
{
    tcg_gen_mov_i32(cpu_F0s, tmp);
2738
    tcg_temp_free_i32(tmp);
P
pbrook 已提交
2739 2740
}

2741
static void gen_neon_dup_u8(TCGv_i32 var, int shift)
P
pbrook 已提交
2742
{
2743
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
2744 2745
    if (shift)
        tcg_gen_shri_i32(var, var, shift);
P
pbrook 已提交
2746
    tcg_gen_ext8u_i32(var, var);
P
pbrook 已提交
2747 2748 2749 2750
    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);
2751
    tcg_temp_free_i32(tmp);
P
pbrook 已提交
2752 2753
}

2754
static void gen_neon_dup_low16(TCGv_i32 var)
P
pbrook 已提交
2755
{
2756
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
2757
    tcg_gen_ext16u_i32(var, var);
P
pbrook 已提交
2758 2759
    tcg_gen_shli_i32(tmp, var, 16);
    tcg_gen_or_i32(var, var, tmp);
2760
    tcg_temp_free_i32(tmp);
P
pbrook 已提交
2761 2762
}

2763
static void gen_neon_dup_high16(TCGv_i32 var)
P
pbrook 已提交
2764
{
2765
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
2766 2767 2768
    tcg_gen_andi_i32(var, var, 0xffff0000);
    tcg_gen_shri_i32(tmp, var, 16);
    tcg_gen_or_i32(var, var, tmp);
2769
    tcg_temp_free_i32(tmp);
P
pbrook 已提交
2770 2771
}

2772
static TCGv_i32 gen_load_and_replicate(DisasContext *s, TCGv_i32 addr, int size)
2773 2774
{
    /* Load a single Neon element and replicate into a 32 bit TCG reg */
2775
    TCGv_i32 tmp = tcg_temp_new_i32();
2776 2777
    switch (size) {
    case 0:
2778
        gen_aa32_ld8u(s, tmp, addr, get_mem_index(s));
2779 2780 2781
        gen_neon_dup_u8(tmp, 0);
        break;
    case 1:
2782
        gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
2783 2784 2785
        gen_neon_dup_low16(tmp);
        break;
    case 2:
2786
        gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
2787 2788 2789 2790 2791 2792 2793
        break;
    default: /* Avoid compiler warnings.  */
        abort();
    }
    return tmp;
}

2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902
static int handle_vsel(uint32_t insn, uint32_t rd, uint32_t rn, uint32_t rm,
                       uint32_t dp)
{
    uint32_t cc = extract32(insn, 20, 2);

    if (dp) {
        TCGv_i64 frn, frm, dest;
        TCGv_i64 tmp, zero, zf, nf, vf;

        zero = tcg_const_i64(0);

        frn = tcg_temp_new_i64();
        frm = tcg_temp_new_i64();
        dest = tcg_temp_new_i64();

        zf = tcg_temp_new_i64();
        nf = tcg_temp_new_i64();
        vf = tcg_temp_new_i64();

        tcg_gen_extu_i32_i64(zf, cpu_ZF);
        tcg_gen_ext_i32_i64(nf, cpu_NF);
        tcg_gen_ext_i32_i64(vf, cpu_VF);

        tcg_gen_ld_f64(frn, cpu_env, vfp_reg_offset(dp, rn));
        tcg_gen_ld_f64(frm, cpu_env, vfp_reg_offset(dp, rm));
        switch (cc) {
        case 0: /* eq: Z */
            tcg_gen_movcond_i64(TCG_COND_EQ, dest, zf, zero,
                                frn, frm);
            break;
        case 1: /* vs: V */
            tcg_gen_movcond_i64(TCG_COND_LT, dest, vf, zero,
                                frn, frm);
            break;
        case 2: /* ge: N == V -> N ^ V == 0 */
            tmp = tcg_temp_new_i64();
            tcg_gen_xor_i64(tmp, vf, nf);
            tcg_gen_movcond_i64(TCG_COND_GE, dest, tmp, zero,
                                frn, frm);
            tcg_temp_free_i64(tmp);
            break;
        case 3: /* gt: !Z && N == V */
            tcg_gen_movcond_i64(TCG_COND_NE, dest, zf, zero,
                                frn, frm);
            tmp = tcg_temp_new_i64();
            tcg_gen_xor_i64(tmp, vf, nf);
            tcg_gen_movcond_i64(TCG_COND_GE, dest, tmp, zero,
                                dest, frm);
            tcg_temp_free_i64(tmp);
            break;
        }
        tcg_gen_st_f64(dest, cpu_env, vfp_reg_offset(dp, rd));
        tcg_temp_free_i64(frn);
        tcg_temp_free_i64(frm);
        tcg_temp_free_i64(dest);

        tcg_temp_free_i64(zf);
        tcg_temp_free_i64(nf);
        tcg_temp_free_i64(vf);

        tcg_temp_free_i64(zero);
    } else {
        TCGv_i32 frn, frm, dest;
        TCGv_i32 tmp, zero;

        zero = tcg_const_i32(0);

        frn = tcg_temp_new_i32();
        frm = tcg_temp_new_i32();
        dest = tcg_temp_new_i32();
        tcg_gen_ld_f32(frn, cpu_env, vfp_reg_offset(dp, rn));
        tcg_gen_ld_f32(frm, cpu_env, vfp_reg_offset(dp, rm));
        switch (cc) {
        case 0: /* eq: Z */
            tcg_gen_movcond_i32(TCG_COND_EQ, dest, cpu_ZF, zero,
                                frn, frm);
            break;
        case 1: /* vs: V */
            tcg_gen_movcond_i32(TCG_COND_LT, dest, cpu_VF, zero,
                                frn, frm);
            break;
        case 2: /* ge: N == V -> N ^ V == 0 */
            tmp = tcg_temp_new_i32();
            tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF);
            tcg_gen_movcond_i32(TCG_COND_GE, dest, tmp, zero,
                                frn, frm);
            tcg_temp_free_i32(tmp);
            break;
        case 3: /* gt: !Z && N == V */
            tcg_gen_movcond_i32(TCG_COND_NE, dest, cpu_ZF, zero,
                                frn, frm);
            tmp = tcg_temp_new_i32();
            tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF);
            tcg_gen_movcond_i32(TCG_COND_GE, dest, tmp, zero,
                                dest, frm);
            tcg_temp_free_i32(tmp);
            break;
        }
        tcg_gen_st_f32(dest, cpu_env, vfp_reg_offset(dp, rd));
        tcg_temp_free_i32(frn);
        tcg_temp_free_i32(frm);
        tcg_temp_free_i32(dest);

        tcg_temp_free_i32(zero);
    }

    return 0;
}

2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918
static int handle_vminmaxnm(uint32_t insn, uint32_t rd, uint32_t rn,
                            uint32_t rm, uint32_t dp)
{
    uint32_t vmin = extract32(insn, 6, 1);
    TCGv_ptr fpst = get_fpstatus_ptr(0);

    if (dp) {
        TCGv_i64 frn, frm, dest;

        frn = tcg_temp_new_i64();
        frm = tcg_temp_new_i64();
        dest = tcg_temp_new_i64();

        tcg_gen_ld_f64(frn, cpu_env, vfp_reg_offset(dp, rn));
        tcg_gen_ld_f64(frm, cpu_env, vfp_reg_offset(dp, rm));
        if (vmin) {
2919
            gen_helper_vfp_minnumd(dest, frn, frm, fpst);
2920
        } else {
2921
            gen_helper_vfp_maxnumd(dest, frn, frm, fpst);
2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936
        }
        tcg_gen_st_f64(dest, cpu_env, vfp_reg_offset(dp, rd));
        tcg_temp_free_i64(frn);
        tcg_temp_free_i64(frm);
        tcg_temp_free_i64(dest);
    } else {
        TCGv_i32 frn, frm, dest;

        frn = tcg_temp_new_i32();
        frm = tcg_temp_new_i32();
        dest = tcg_temp_new_i32();

        tcg_gen_ld_f32(frn, cpu_env, vfp_reg_offset(dp, rn));
        tcg_gen_ld_f32(frm, cpu_env, vfp_reg_offset(dp, rm));
        if (vmin) {
2937
            gen_helper_vfp_minnums(dest, frn, frm, fpst);
2938
        } else {
2939
            gen_helper_vfp_maxnums(dest, frn, frm, fpst);
2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950
        }
        tcg_gen_st_f32(dest, cpu_env, vfp_reg_offset(dp, rd));
        tcg_temp_free_i32(frn);
        tcg_temp_free_i32(frm);
        tcg_temp_free_i32(dest);
    }

    tcg_temp_free_ptr(fpst);
    return 0;
}

2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988
static int handle_vrint(uint32_t insn, uint32_t rd, uint32_t rm, uint32_t dp,
                        int rounding)
{
    TCGv_ptr fpst = get_fpstatus_ptr(0);
    TCGv_i32 tcg_rmode;

    tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rounding));
    gen_helper_set_rmode(tcg_rmode, tcg_rmode, cpu_env);

    if (dp) {
        TCGv_i64 tcg_op;
        TCGv_i64 tcg_res;
        tcg_op = tcg_temp_new_i64();
        tcg_res = tcg_temp_new_i64();
        tcg_gen_ld_f64(tcg_op, cpu_env, vfp_reg_offset(dp, rm));
        gen_helper_rintd(tcg_res, tcg_op, fpst);
        tcg_gen_st_f64(tcg_res, cpu_env, vfp_reg_offset(dp, rd));
        tcg_temp_free_i64(tcg_op);
        tcg_temp_free_i64(tcg_res);
    } else {
        TCGv_i32 tcg_op;
        TCGv_i32 tcg_res;
        tcg_op = tcg_temp_new_i32();
        tcg_res = tcg_temp_new_i32();
        tcg_gen_ld_f32(tcg_op, cpu_env, vfp_reg_offset(dp, rm));
        gen_helper_rints(tcg_res, tcg_op, fpst);
        tcg_gen_st_f32(tcg_res, cpu_env, vfp_reg_offset(dp, rd));
        tcg_temp_free_i32(tcg_op);
        tcg_temp_free_i32(tcg_res);
    }

    gen_helper_set_rmode(tcg_rmode, tcg_rmode, cpu_env);
    tcg_temp_free_i32(tcg_rmode);

    tcg_temp_free_ptr(fpst);
    return 0;
}

2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016
static int handle_vcvt(uint32_t insn, uint32_t rd, uint32_t rm, uint32_t dp,
                       int rounding)
{
    bool is_signed = extract32(insn, 7, 1);
    TCGv_ptr fpst = get_fpstatus_ptr(0);
    TCGv_i32 tcg_rmode, tcg_shift;

    tcg_shift = tcg_const_i32(0);

    tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rounding));
    gen_helper_set_rmode(tcg_rmode, tcg_rmode, cpu_env);

    if (dp) {
        TCGv_i64 tcg_double, tcg_res;
        TCGv_i32 tcg_tmp;
        /* Rd is encoded as a single precision register even when the source
         * is double precision.
         */
        rd = ((rd << 1) & 0x1e) | ((rd >> 4) & 0x1);
        tcg_double = tcg_temp_new_i64();
        tcg_res = tcg_temp_new_i64();
        tcg_tmp = tcg_temp_new_i32();
        tcg_gen_ld_f64(tcg_double, cpu_env, vfp_reg_offset(1, rm));
        if (is_signed) {
            gen_helper_vfp_tosld(tcg_res, tcg_double, tcg_shift, fpst);
        } else {
            gen_helper_vfp_tould(tcg_res, tcg_double, tcg_shift, fpst);
        }
3017
        tcg_gen_extrl_i64_i32(tcg_tmp, tcg_res);
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 3044 3045
        tcg_gen_st_f32(tcg_tmp, cpu_env, vfp_reg_offset(0, rd));
        tcg_temp_free_i32(tcg_tmp);
        tcg_temp_free_i64(tcg_res);
        tcg_temp_free_i64(tcg_double);
    } else {
        TCGv_i32 tcg_single, tcg_res;
        tcg_single = tcg_temp_new_i32();
        tcg_res = tcg_temp_new_i32();
        tcg_gen_ld_f32(tcg_single, cpu_env, vfp_reg_offset(0, rm));
        if (is_signed) {
            gen_helper_vfp_tosls(tcg_res, tcg_single, tcg_shift, fpst);
        } else {
            gen_helper_vfp_touls(tcg_res, tcg_single, tcg_shift, fpst);
        }
        tcg_gen_st_f32(tcg_res, cpu_env, vfp_reg_offset(0, rd));
        tcg_temp_free_i32(tcg_res);
        tcg_temp_free_i32(tcg_single);
    }

    gen_helper_set_rmode(tcg_rmode, tcg_rmode, cpu_env);
    tcg_temp_free_i32(tcg_rmode);

    tcg_temp_free_i32(tcg_shift);

    tcg_temp_free_ptr(fpst);

    return 0;
}
3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057

/* Table for converting the most common AArch32 encoding of
 * rounding mode to arm_fprounding order (which matches the
 * common AArch64 order); see ARM ARM pseudocode FPDecodeRM().
 */
static const uint8_t fp_decode_rm[] = {
    FPROUNDING_TIEAWAY,
    FPROUNDING_TIEEVEN,
    FPROUNDING_POSINF,
    FPROUNDING_NEGINF,
};

3058
static int disas_vfp_v8_insn(DisasContext *s, uint32_t insn)
3059 3060 3061
{
    uint32_t rd, rn, rm, dp = extract32(insn, 8, 1);

3062
    if (!arm_dc_feature(s, ARM_FEATURE_V8)) {
3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077
        return 1;
    }

    if (dp) {
        VFP_DREG_D(rd, insn);
        VFP_DREG_N(rn, insn);
        VFP_DREG_M(rm, insn);
    } else {
        rd = VFP_SREG_D(insn);
        rn = VFP_SREG_N(insn);
        rm = VFP_SREG_M(insn);
    }

    if ((insn & 0x0f800e50) == 0x0e000a00) {
        return handle_vsel(insn, rd, rn, rm, dp);
3078 3079
    } else if ((insn & 0x0fb00e10) == 0x0e800a00) {
        return handle_vminmaxnm(insn, rd, rn, rm, dp);
3080 3081 3082 3083
    } else if ((insn & 0x0fbc0ed0) == 0x0eb80a40) {
        /* VRINTA, VRINTN, VRINTP, VRINTM */
        int rounding = fp_decode_rm[extract32(insn, 16, 2)];
        return handle_vrint(insn, rd, rm, dp, rounding);
3084 3085 3086 3087
    } else if ((insn & 0x0fbc0e50) == 0x0ebc0a40) {
        /* VCVTA, VCVTN, VCVTP, VCVTM */
        int rounding = fp_decode_rm[extract32(insn, 16, 2)];
        return handle_vcvt(insn, rd, rm, dp, rounding);
3088 3089 3090 3091
    }
    return 1;
}

3092
/* Disassemble a VFP instruction.  Returns nonzero if an error occurred
B
bellard 已提交
3093
   (ie. an undefined instruction).  */
3094
static int disas_vfp_insn(DisasContext *s, uint32_t insn)
B
bellard 已提交
3095 3096 3097
{
    uint32_t rd, rn, rm, op, i, n, offset, delta_d, delta_m, bank_mask;
    int dp, veclen;
3098 3099 3100
    TCGv_i32 addr;
    TCGv_i32 tmp;
    TCGv_i32 tmp2;
B
bellard 已提交
3101

3102
    if (!arm_dc_feature(s, ARM_FEATURE_VFP)) {
P
pbrook 已提交
3103
        return 1;
3104
    }
P
pbrook 已提交
3105

3106 3107 3108 3109
    /* FIXME: this access check should not take precedence over UNDEF
     * for invalid encodings; we will generate incorrect syndrome information
     * for attempts to execute invalid vfp/neon encodings with FP disabled.
     */
3110
    if (s->fp_excp_el) {
3111
        gen_exception_insn(s, 4, EXCP_UDEF,
3112
                           syn_fp_access_trap(1, 0xe, false), s->fp_excp_el);
3113 3114 3115
        return 0;
    }

3116
    if (!s->vfp_enabled) {
P
pbrook 已提交
3117
        /* VFP disabled.  Only allow fmxr/fmrx to/from some control regs.  */
P
pbrook 已提交
3118 3119 3120
        if ((insn & 0x0fe00fff) != 0x0ee00a10)
            return 1;
        rn = (insn >> 16) & 0xf;
3121 3122
        if (rn != ARM_VFP_FPSID && rn != ARM_VFP_FPEXC && rn != ARM_VFP_MVFR2
            && rn != ARM_VFP_MVFR1 && rn != ARM_VFP_MVFR0) {
P
pbrook 已提交
3123
            return 1;
3124
        }
P
pbrook 已提交
3125
    }
3126 3127 3128 3129 3130

    if (extract32(insn, 28, 4) == 0xf) {
        /* Encodings with T=1 (Thumb) or unconditional (ARM):
         * only used in v8 and above.
         */
3131
        return disas_vfp_v8_insn(s, insn);
3132 3133
    }

B
bellard 已提交
3134 3135 3136 3137 3138 3139 3140
    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 已提交
3141 3142 3143 3144 3145
                int size;
                int pass;

                VFP_DREG_N(rn, insn);
                if (insn & 0xf)
B
bellard 已提交
3146
                    return 1;
P
pbrook 已提交
3147
                if (insn & 0x00c00060
3148
                    && !arm_dc_feature(s, ARM_FEATURE_NEON)) {
P
pbrook 已提交
3149
                    return 1;
3150
                }
P
pbrook 已提交
3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162

                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;
                }
3163
                if (insn & ARM_CP_RW_BIT) {
B
bellard 已提交
3164
                    /* vfp->arm */
P
pbrook 已提交
3165
                    tmp = neon_load_reg(rn, pass);
P
pbrook 已提交
3166 3167 3168
                    switch (size) {
                    case 0:
                        if (offset)
P
pbrook 已提交
3169
                            tcg_gen_shri_i32(tmp, tmp, offset);
P
pbrook 已提交
3170
                        if (insn & (1 << 23))
P
pbrook 已提交
3171
                            gen_uxtb(tmp);
P
pbrook 已提交
3172
                        else
P
pbrook 已提交
3173
                            gen_sxtb(tmp);
P
pbrook 已提交
3174 3175 3176 3177
                        break;
                    case 1:
                        if (insn & (1 << 23)) {
                            if (offset) {
P
pbrook 已提交
3178
                                tcg_gen_shri_i32(tmp, tmp, 16);
P
pbrook 已提交
3179
                            } else {
P
pbrook 已提交
3180
                                gen_uxth(tmp);
P
pbrook 已提交
3181 3182 3183
                            }
                        } else {
                            if (offset) {
P
pbrook 已提交
3184
                                tcg_gen_sari_i32(tmp, tmp, 16);
P
pbrook 已提交
3185
                            } else {
P
pbrook 已提交
3186
                                gen_sxth(tmp);
P
pbrook 已提交
3187 3188 3189 3190 3191 3192
                            }
                        }
                        break;
                    case 2:
                        break;
                    }
P
pbrook 已提交
3193
                    store_reg(s, rd, tmp);
B
bellard 已提交
3194 3195
                } else {
                    /* arm->vfp */
P
pbrook 已提交
3196
                    tmp = load_reg(s, rd);
P
pbrook 已提交
3197 3198 3199
                    if (insn & (1 << 23)) {
                        /* VDUP */
                        if (size == 0) {
P
pbrook 已提交
3200
                            gen_neon_dup_u8(tmp, 0);
P
pbrook 已提交
3201
                        } else if (size == 1) {
P
pbrook 已提交
3202
                            gen_neon_dup_low16(tmp);
P
pbrook 已提交
3203
                        }
P
pbrook 已提交
3204
                        for (n = 0; n <= pass * 2; n++) {
3205
                            tmp2 = tcg_temp_new_i32();
P
pbrook 已提交
3206 3207 3208 3209
                            tcg_gen_mov_i32(tmp2, tmp);
                            neon_store_reg(rn, n, tmp2);
                        }
                        neon_store_reg(rn, n, tmp);
P
pbrook 已提交
3210 3211 3212 3213
                    } else {
                        /* VMOV */
                        switch (size) {
                        case 0:
P
pbrook 已提交
3214
                            tmp2 = neon_load_reg(rn, pass);
3215
                            tcg_gen_deposit_i32(tmp, tmp2, tmp, offset, 8);
3216
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
3217 3218
                            break;
                        case 1:
P
pbrook 已提交
3219
                            tmp2 = neon_load_reg(rn, pass);
3220
                            tcg_gen_deposit_i32(tmp, tmp2, tmp, offset, 16);
3221
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
3222 3223 3224 3225
                            break;
                        case 2:
                            break;
                        }
P
pbrook 已提交
3226
                        neon_store_reg(rn, pass, tmp);
P
pbrook 已提交
3227
                    }
B
bellard 已提交
3228
                }
P
pbrook 已提交
3229 3230 3231 3232
            } else { /* !dp */
                if ((insn & 0x6f) != 0x00)
                    return 1;
                rn = VFP_SREG_N(insn);
3233
                if (insn & ARM_CP_RW_BIT) {
B
bellard 已提交
3234 3235 3236
                    /* vfp->arm */
                    if (insn & (1 << 21)) {
                        /* system register */
P
pbrook 已提交
3237
                        rn >>= 1;
P
pbrook 已提交
3238

B
bellard 已提交
3239
                        switch (rn) {
P
pbrook 已提交
3240
                        case ARM_VFP_FPSID:
P
pbrook 已提交
3241
                            /* VFP2 allows access to FSID from userspace.
P
pbrook 已提交
3242 3243 3244
                               VFP3 restricts all id registers to privileged
                               accesses.  */
                            if (IS_USER(s)
3245
                                && arm_dc_feature(s, ARM_FEATURE_VFP3)) {
P
pbrook 已提交
3246
                                return 1;
3247
                            }
P
pbrook 已提交
3248
                            tmp = load_cpu_field(vfp.xregs[rn]);
P
pbrook 已提交
3249
                            break;
P
pbrook 已提交
3250
                        case ARM_VFP_FPEXC:
P
pbrook 已提交
3251 3252
                            if (IS_USER(s))
                                return 1;
P
pbrook 已提交
3253
                            tmp = load_cpu_field(vfp.xregs[rn]);
P
pbrook 已提交
3254
                            break;
P
pbrook 已提交
3255 3256
                        case ARM_VFP_FPINST:
                        case ARM_VFP_FPINST2:
P
pbrook 已提交
3257 3258
                            /* Not present in VFP3.  */
                            if (IS_USER(s)
3259
                                || arm_dc_feature(s, ARM_FEATURE_VFP3)) {
P
pbrook 已提交
3260
                                return 1;
3261
                            }
P
pbrook 已提交
3262
                            tmp = load_cpu_field(vfp.xregs[rn]);
B
bellard 已提交
3263
                            break;
P
pbrook 已提交
3264
                        case ARM_VFP_FPSCR:
3265
                            if (rd == 15) {
P
pbrook 已提交
3266 3267 3268
                                tmp = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]);
                                tcg_gen_andi_i32(tmp, tmp, 0xf0000000);
                            } else {
3269
                                tmp = tcg_temp_new_i32();
P
pbrook 已提交
3270 3271
                                gen_helper_vfp_get_fpscr(tmp, cpu_env);
                            }
B
bellard 已提交
3272
                            break;
3273
                        case ARM_VFP_MVFR2:
3274
                            if (!arm_dc_feature(s, ARM_FEATURE_V8)) {
3275 3276 3277
                                return 1;
                            }
                            /* fall through */
P
pbrook 已提交
3278 3279 3280
                        case ARM_VFP_MVFR0:
                        case ARM_VFP_MVFR1:
                            if (IS_USER(s)
3281
                                || !arm_dc_feature(s, ARM_FEATURE_MVFR)) {
P
pbrook 已提交
3282
                                return 1;
3283
                            }
P
pbrook 已提交
3284
                            tmp = load_cpu_field(vfp.xregs[rn]);
P
pbrook 已提交
3285
                            break;
B
bellard 已提交
3286 3287 3288 3289 3290
                        default:
                            return 1;
                        }
                    } else {
                        gen_mov_F0_vreg(0, rn);
P
pbrook 已提交
3291
                        tmp = gen_vfp_mrs();
B
bellard 已提交
3292 3293
                    }
                    if (rd == 15) {
B
bellard 已提交
3294
                        /* Set the 4 flag bits in the CPSR.  */
P
pbrook 已提交
3295
                        gen_set_nzcv(tmp);
3296
                        tcg_temp_free_i32(tmp);
P
pbrook 已提交
3297 3298 3299
                    } else {
                        store_reg(s, rd, tmp);
                    }
B
bellard 已提交
3300 3301 3302
                } else {
                    /* arm->vfp */
                    if (insn & (1 << 21)) {
P
pbrook 已提交
3303
                        rn >>= 1;
B
bellard 已提交
3304 3305
                        /* system register */
                        switch (rn) {
P
pbrook 已提交
3306
                        case ARM_VFP_FPSID:
P
pbrook 已提交
3307 3308
                        case ARM_VFP_MVFR0:
                        case ARM_VFP_MVFR1:
B
bellard 已提交
3309 3310
                            /* Writes are ignored.  */
                            break;
P
pbrook 已提交
3311
                        case ARM_VFP_FPSCR:
3312
                            tmp = load_reg(s, rd);
P
pbrook 已提交
3313
                            gen_helper_vfp_set_fpscr(cpu_env, tmp);
3314
                            tcg_temp_free_i32(tmp);
B
bellard 已提交
3315
                            gen_lookup_tb(s);
B
bellard 已提交
3316
                            break;
P
pbrook 已提交
3317
                        case ARM_VFP_FPEXC:
P
pbrook 已提交
3318 3319
                            if (IS_USER(s))
                                return 1;
3320 3321
                            /* TODO: VFP subarchitecture support.
                             * For now, keep the EN bit only */
3322
                            tmp = load_reg(s, rd);
3323
                            tcg_gen_andi_i32(tmp, tmp, 1 << 30);
P
pbrook 已提交
3324
                            store_cpu_field(tmp, vfp.xregs[rn]);
P
pbrook 已提交
3325 3326 3327 3328
                            gen_lookup_tb(s);
                            break;
                        case ARM_VFP_FPINST:
                        case ARM_VFP_FPINST2:
3329 3330 3331
                            if (IS_USER(s)) {
                                return 1;
                            }
3332
                            tmp = load_reg(s, rd);
P
pbrook 已提交
3333
                            store_cpu_field(tmp, vfp.xregs[rn]);
P
pbrook 已提交
3334
                            break;
B
bellard 已提交
3335 3336 3337 3338
                        default:
                            return 1;
                        }
                    } else {
3339
                        tmp = load_reg(s, rd);
P
pbrook 已提交
3340
                        gen_vfp_msr(tmp);
B
bellard 已提交
3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354
                        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 已提交
3355
                    VFP_DREG_N(rn, insn);
B
bellard 已提交
3356 3357
                }

3358 3359 3360
                if (op == 15 && (rn == 15 || ((rn & 0x1c) == 0x18) ||
                                 ((rn & 0x1e) == 0x6))) {
                    /* Integer or single/half precision destination.  */
P
pbrook 已提交
3361
                    rd = VFP_SREG_D(insn);
B
bellard 已提交
3362
                } else {
P
pbrook 已提交
3363
                    VFP_DREG_D(rd, insn);
B
bellard 已提交
3364
                }
3365
                if (op == 15 &&
3366 3367 3368 3369 3370
                    (((rn & 0x1c) == 0x10) || ((rn & 0x14) == 0x14) ||
                     ((rn & 0x1e) == 0x4))) {
                    /* VCVT from int or half precision is always from S reg
                     * regardless of dp bit. VCVT with immediate frac_bits
                     * has same format as SREG_M.
3371 3372
                     */
                    rm = VFP_SREG_M(insn);
B
bellard 已提交
3373
                } else {
P
pbrook 已提交
3374
                    VFP_DREG_M(rm, insn);
B
bellard 已提交
3375 3376
                }
            } else {
P
pbrook 已提交
3377
                rn = VFP_SREG_N(insn);
B
bellard 已提交
3378 3379
                if (op == 15 && rn == 15) {
                    /* Double precision destination.  */
P
pbrook 已提交
3380 3381 3382 3383
                    VFP_DREG_D(rd, insn);
                } else {
                    rd = VFP_SREG_D(insn);
                }
3384 3385 3386
                /* NB that we implicitly rely on the encoding for the frac_bits
                 * in VCVT of fixed to float being the same as that of an SREG_M
                 */
P
pbrook 已提交
3387
                rm = VFP_SREG_M(insn);
B
bellard 已提交
3388 3389
            }

3390
            veclen = s->vec_len;
B
bellard 已提交
3391 3392 3393 3394 3395 3396 3397
            if (op == 15 && rn > 3)
                veclen = 0;

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

B
bellard 已提交
3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410
            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)
3411
                        delta_d = (s->vec_stride >> 1) + 1;
B
bellard 已提交
3412
                    else
3413
                        delta_d = s->vec_stride + 1;
B
bellard 已提交
3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444

                    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 已提交
3445 3446 3447 3448
                case 20:
                case 21:
                case 22:
                case 23:
P
pbrook 已提交
3449 3450 3451 3452
                case 28:
                case 29:
                case 30:
                case 31:
P
pbrook 已提交
3453 3454 3455
                    /* Source and destination the same.  */
                    gen_mov_F0_vreg(dp, rd);
                    break;
3456 3457 3458 3459
                case 4:
                case 5:
                case 6:
                case 7:
3460 3461 3462
                    /* VCVTB, VCVTT: only present with the halfprec extension
                     * UNPREDICTABLE if bit 8 is set prior to ARMv8
                     * (we choose to UNDEF)
3463
                     */
3464 3465
                    if ((dp && !arm_dc_feature(s, ARM_FEATURE_V8)) ||
                        !arm_dc_feature(s, ARM_FEATURE_VFP_FP16)) {
3466 3467
                        return 1;
                    }
3468 3469 3470 3471 3472
                    if (!extract32(rn, 1, 1)) {
                        /* Half precision source.  */
                        gen_mov_F0_vreg(0, rm);
                        break;
                    }
3473
                    /* Otherwise fall through */
B
bellard 已提交
3474 3475 3476
                default:
                    /* One source operand.  */
                    gen_mov_F0_vreg(dp, rm);
P
pbrook 已提交
3477
                    break;
B
bellard 已提交
3478 3479 3480 3481 3482 3483 3484 3485 3486 3487
                }
            } else {
                /* Two source operands.  */
                gen_mov_F0_vreg(dp, rn);
                gen_mov_F1_vreg(dp, rm);
            }

            for (;;) {
                /* Perform the calculation.  */
                switch (op) {
3488 3489 3490 3491
                case 0: /* VMLA: fd + (fn * fm) */
                    /* Note that order of inputs to the add matters for NaNs */
                    gen_vfp_F1_mul(dp);
                    gen_mov_F0_vreg(dp, rd);
B
bellard 已提交
3492 3493
                    gen_vfp_add(dp);
                    break;
3494
                case 1: /* VMLS: fd + -(fn * fm) */
B
bellard 已提交
3495
                    gen_vfp_mul(dp);
3496 3497
                    gen_vfp_F1_neg(dp);
                    gen_mov_F0_vreg(dp, rd);
B
bellard 已提交
3498 3499
                    gen_vfp_add(dp);
                    break;
3500 3501 3502 3503 3504 3505 3506 3507 3508
                case 2: /* VNMLS: -fd + (fn * fm) */
                    /* Note that it isn't valid to replace (-A + B) with (B - A)
                     * or similar plausible looking simplifications
                     * because this will give wrong results for NaNs.
                     */
                    gen_vfp_F1_mul(dp);
                    gen_mov_F0_vreg(dp, rd);
                    gen_vfp_neg(dp);
                    gen_vfp_add(dp);
B
bellard 已提交
3509
                    break;
3510
                case 3: /* VNMLA: -fd + -(fn * fm) */
B
bellard 已提交
3511
                    gen_vfp_mul(dp);
3512 3513
                    gen_vfp_F1_neg(dp);
                    gen_mov_F0_vreg(dp, rd);
B
bellard 已提交
3514
                    gen_vfp_neg(dp);
3515
                    gen_vfp_add(dp);
B
bellard 已提交
3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532
                    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;
3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543
                case 10: /* VFNMA : fd = muladd(-fd,  fn, fm) */
                case 11: /* VFNMS : fd = muladd(-fd, -fn, fm) */
                case 12: /* VFMA  : fd = muladd( fd,  fn, fm) */
                case 13: /* VFMS  : fd = muladd( fd, -fn, fm) */
                    /* These are fused multiply-add, and must be done as one
                     * floating point operation with no rounding between the
                     * multiplication and addition steps.
                     * NB that doing the negations here as separate steps is
                     * correct : an input NaN should come out with its sign bit
                     * flipped if it is a negated-input.
                     */
3544
                    if (!arm_dc_feature(s, ARM_FEATURE_VFP4)) {
3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583
                        return 1;
                    }
                    if (dp) {
                        TCGv_ptr fpst;
                        TCGv_i64 frd;
                        if (op & 1) {
                            /* VFNMS, VFMS */
                            gen_helper_vfp_negd(cpu_F0d, cpu_F0d);
                        }
                        frd = tcg_temp_new_i64();
                        tcg_gen_ld_f64(frd, cpu_env, vfp_reg_offset(dp, rd));
                        if (op & 2) {
                            /* VFNMA, VFNMS */
                            gen_helper_vfp_negd(frd, frd);
                        }
                        fpst = get_fpstatus_ptr(0);
                        gen_helper_vfp_muladdd(cpu_F0d, cpu_F0d,
                                               cpu_F1d, frd, fpst);
                        tcg_temp_free_ptr(fpst);
                        tcg_temp_free_i64(frd);
                    } else {
                        TCGv_ptr fpst;
                        TCGv_i32 frd;
                        if (op & 1) {
                            /* VFNMS, VFMS */
                            gen_helper_vfp_negs(cpu_F0s, cpu_F0s);
                        }
                        frd = tcg_temp_new_i32();
                        tcg_gen_ld_f32(frd, cpu_env, vfp_reg_offset(dp, rd));
                        if (op & 2) {
                            gen_helper_vfp_negs(frd, frd);
                        }
                        fpst = get_fpstatus_ptr(0);
                        gen_helper_vfp_muladds(cpu_F0s, cpu_F0s,
                                               cpu_F1s, frd, fpst);
                        tcg_temp_free_ptr(fpst);
                        tcg_temp_free_i32(frd);
                    }
                    break;
P
pbrook 已提交
3584
                case 14: /* fconst */
3585 3586 3587
                    if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
                        return 1;
                    }
P
pbrook 已提交
3588 3589 3590 3591 3592 3593 3594 3595 3596

                    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 已提交
3597
                        tcg_gen_movi_i64(cpu_F0d, ((uint64_t)n) << 32);
P
pbrook 已提交
3598 3599 3600 3601 3602 3603
                    } else {
                        if (i & 0x40)
                            i |= 0x780;
                        else
                            i |= 0x800;
                        n |= i << 19;
B
balrog 已提交
3604
                        tcg_gen_movi_i32(cpu_F0s, n);
P
pbrook 已提交
3605 3606
                    }
                    break;
B
bellard 已提交
3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620
                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;
3621
                    case 4: /* vcvtb.f32.f16, vcvtb.f64.f16 */
P
Paul Brook 已提交
3622 3623
                        tmp = gen_vfp_mrs();
                        tcg_gen_ext16u_i32(tmp, tmp);
3624 3625 3626 3627 3628 3629 3630
                        if (dp) {
                            gen_helper_vfp_fcvt_f16_to_f64(cpu_F0d, tmp,
                                                           cpu_env);
                        } else {
                            gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp,
                                                           cpu_env);
                        }
3631
                        tcg_temp_free_i32(tmp);
P
Paul Brook 已提交
3632
                        break;
3633
                    case 5: /* vcvtt.f32.f16, vcvtt.f64.f16 */
P
Paul Brook 已提交
3634 3635
                        tmp = gen_vfp_mrs();
                        tcg_gen_shri_i32(tmp, tmp, 16);
3636 3637 3638 3639 3640 3641 3642
                        if (dp) {
                            gen_helper_vfp_fcvt_f16_to_f64(cpu_F0d, tmp,
                                                           cpu_env);
                        } else {
                            gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp,
                                                           cpu_env);
                        }
3643
                        tcg_temp_free_i32(tmp);
P
Paul Brook 已提交
3644
                        break;
3645
                    case 6: /* vcvtb.f16.f32, vcvtb.f16.f64 */
3646
                        tmp = tcg_temp_new_i32();
3647 3648 3649 3650 3651 3652 3653
                        if (dp) {
                            gen_helper_vfp_fcvt_f64_to_f16(tmp, cpu_F0d,
                                                           cpu_env);
                        } else {
                            gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s,
                                                           cpu_env);
                        }
P
Paul Brook 已提交
3654 3655 3656 3657
                        gen_mov_F0_vreg(0, rd);
                        tmp2 = gen_vfp_mrs();
                        tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000);
                        tcg_gen_or_i32(tmp, tmp, tmp2);
3658
                        tcg_temp_free_i32(tmp2);
P
Paul Brook 已提交
3659 3660
                        gen_vfp_msr(tmp);
                        break;
3661
                    case 7: /* vcvtt.f16.f32, vcvtt.f16.f64 */
3662
                        tmp = tcg_temp_new_i32();
3663 3664 3665 3666 3667 3668 3669
                        if (dp) {
                            gen_helper_vfp_fcvt_f64_to_f16(tmp, cpu_F0d,
                                                           cpu_env);
                        } else {
                            gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s,
                                                           cpu_env);
                        }
P
Paul Brook 已提交
3670 3671 3672 3673 3674
                        tcg_gen_shli_i32(tmp, tmp, 16);
                        gen_mov_F0_vreg(0, rd);
                        tmp2 = gen_vfp_mrs();
                        tcg_gen_ext16u_i32(tmp2, tmp2);
                        tcg_gen_or_i32(tmp, tmp, tmp2);
3675
                        tcg_temp_free_i32(tmp2);
P
Paul Brook 已提交
3676 3677
                        gen_vfp_msr(tmp);
                        break;
B
bellard 已提交
3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690
                    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;
3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701
                    case 12: /* vrintr */
                    {
                        TCGv_ptr fpst = get_fpstatus_ptr(0);
                        if (dp) {
                            gen_helper_rintd(cpu_F0d, cpu_F0d, fpst);
                        } else {
                            gen_helper_rints(cpu_F0s, cpu_F0s, fpst);
                        }
                        tcg_temp_free_ptr(fpst);
                        break;
                    }
3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717
                    case 13: /* vrintz */
                    {
                        TCGv_ptr fpst = get_fpstatus_ptr(0);
                        TCGv_i32 tcg_rmode;
                        tcg_rmode = tcg_const_i32(float_round_to_zero);
                        gen_helper_set_rmode(tcg_rmode, tcg_rmode, cpu_env);
                        if (dp) {
                            gen_helper_rintd(cpu_F0d, cpu_F0d, fpst);
                        } else {
                            gen_helper_rints(cpu_F0s, cpu_F0s, fpst);
                        }
                        gen_helper_set_rmode(tcg_rmode, tcg_rmode, cpu_env);
                        tcg_temp_free_i32(tcg_rmode);
                        tcg_temp_free_ptr(fpst);
                        break;
                    }
3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728
                    case 14: /* vrintx */
                    {
                        TCGv_ptr fpst = get_fpstatus_ptr(0);
                        if (dp) {
                            gen_helper_rintd_exact(cpu_F0d, cpu_F0d, fpst);
                        } else {
                            gen_helper_rints_exact(cpu_F0s, cpu_F0s, fpst);
                        }
                        tcg_temp_free_ptr(fpst);
                        break;
                    }
B
bellard 已提交
3729 3730
                    case 15: /* single<->double conversion */
                        if (dp)
P
pbrook 已提交
3731
                            gen_helper_vfp_fcvtsd(cpu_F0s, cpu_F0d, cpu_env);
B
bellard 已提交
3732
                        else
P
pbrook 已提交
3733
                            gen_helper_vfp_fcvtds(cpu_F0d, cpu_F0s, cpu_env);
B
bellard 已提交
3734 3735
                        break;
                    case 16: /* fuito */
3736
                        gen_vfp_uito(dp, 0);
B
bellard 已提交
3737 3738
                        break;
                    case 17: /* fsito */
3739
                        gen_vfp_sito(dp, 0);
B
bellard 已提交
3740
                        break;
P
pbrook 已提交
3741
                    case 20: /* fshto */
3742 3743 3744
                        if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
                            return 1;
                        }
3745
                        gen_vfp_shto(dp, 16 - rm, 0);
P
pbrook 已提交
3746 3747
                        break;
                    case 21: /* fslto */
3748 3749 3750
                        if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
                            return 1;
                        }
3751
                        gen_vfp_slto(dp, 32 - rm, 0);
P
pbrook 已提交
3752 3753
                        break;
                    case 22: /* fuhto */
3754 3755 3756
                        if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
                            return 1;
                        }
3757
                        gen_vfp_uhto(dp, 16 - rm, 0);
P
pbrook 已提交
3758 3759
                        break;
                    case 23: /* fulto */
3760 3761 3762
                        if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
                            return 1;
                        }
3763
                        gen_vfp_ulto(dp, 32 - rm, 0);
P
pbrook 已提交
3764
                        break;
B
bellard 已提交
3765
                    case 24: /* ftoui */
3766
                        gen_vfp_toui(dp, 0);
B
bellard 已提交
3767 3768
                        break;
                    case 25: /* ftouiz */
3769
                        gen_vfp_touiz(dp, 0);
B
bellard 已提交
3770 3771
                        break;
                    case 26: /* ftosi */
3772
                        gen_vfp_tosi(dp, 0);
B
bellard 已提交
3773 3774
                        break;
                    case 27: /* ftosiz */
3775
                        gen_vfp_tosiz(dp, 0);
B
bellard 已提交
3776
                        break;
P
pbrook 已提交
3777
                    case 28: /* ftosh */
3778 3779 3780
                        if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
                            return 1;
                        }
3781
                        gen_vfp_tosh(dp, 16 - rm, 0);
P
pbrook 已提交
3782 3783
                        break;
                    case 29: /* ftosl */
3784 3785 3786
                        if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
                            return 1;
                        }
3787
                        gen_vfp_tosl(dp, 32 - rm, 0);
P
pbrook 已提交
3788 3789
                        break;
                    case 30: /* ftouh */
3790 3791 3792
                        if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
                            return 1;
                        }
3793
                        gen_vfp_touh(dp, 16 - rm, 0);
P
pbrook 已提交
3794 3795
                        break;
                    case 31: /* ftoul */
3796 3797 3798
                        if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
                            return 1;
                        }
3799
                        gen_vfp_toul(dp, 32 - rm, 0);
P
pbrook 已提交
3800
                        break;
B
bellard 已提交
3801 3802 3803 3804 3805 3806 3807 3808 3809
                    default: /* undefined */
                        return 1;
                    }
                    break;
                default: /* undefined */
                    return 1;
                }

                /* Write back the result.  */
3810 3811 3812 3813 3814 3815 3816 3817
                if (op == 15 && (rn >= 8 && rn <= 11)) {
                    /* Comparison, do nothing.  */
                } else if (op == 15 && dp && ((rn & 0x1c) == 0x18 ||
                                              (rn & 0x1e) == 0x6)) {
                    /* VCVT double to int: always integer result.
                     * VCVT double to half precision is always a single
                     * precision result.
                     */
B
bellard 已提交
3818
                    gen_mov_vreg_F0(0, rd);
3819
                } else if (op == 15 && rn == 15) {
B
bellard 已提交
3820 3821
                    /* conversion */
                    gen_mov_vreg_F0(!dp, rd);
3822
                } else {
B
bellard 已提交
3823
                    gen_mov_vreg_F0(dp, rd);
3824
                }
B
bellard 已提交
3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864

                /* 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:
3865
        if ((insn & 0x03e00000) == 0x00400000) {
B
bellard 已提交
3866 3867 3868 3869
            /* two-register transfer */
            rn = (insn >> 16) & 0xf;
            rd = (insn >> 12) & 0xf;
            if (dp) {
P
pbrook 已提交
3870 3871 3872 3873
                VFP_DREG_M(rm, insn);
            } else {
                rm = VFP_SREG_M(insn);
            }
B
bellard 已提交
3874

3875
            if (insn & ARM_CP_RW_BIT) {
B
bellard 已提交
3876 3877
                /* vfp->arm */
                if (dp) {
P
pbrook 已提交
3878 3879 3880 3881 3882 3883
                    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 已提交
3884 3885
                } else {
                    gen_mov_F0_vreg(0, rm);
P
pbrook 已提交
3886
                    tmp = gen_vfp_mrs();
3887
                    store_reg(s, rd, tmp);
B
bellard 已提交
3888
                    gen_mov_F0_vreg(0, rm + 1);
P
pbrook 已提交
3889
                    tmp = gen_vfp_mrs();
3890
                    store_reg(s, rn, tmp);
B
bellard 已提交
3891 3892 3893 3894
                }
            } else {
                /* arm->vfp */
                if (dp) {
P
pbrook 已提交
3895 3896 3897 3898 3899 3900
                    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 已提交
3901
                } else {
3902
                    tmp = load_reg(s, rd);
P
pbrook 已提交
3903
                    gen_vfp_msr(tmp);
B
bellard 已提交
3904
                    gen_mov_vreg_F0(0, rm);
3905
                    tmp = load_reg(s, rn);
P
pbrook 已提交
3906
                    gen_vfp_msr(tmp);
B
bellard 已提交
3907 3908 3909 3910 3911 3912 3913
                    gen_mov_vreg_F0(0, rm + 1);
                }
            }
        } else {
            /* Load/store */
            rn = (insn >> 16) & 0xf;
            if (dp)
P
pbrook 已提交
3914
                VFP_DREG_D(rd, insn);
B
bellard 已提交
3915
            else
P
pbrook 已提交
3916
                rd = VFP_SREG_D(insn);
B
bellard 已提交
3917 3918 3919 3920 3921
            if ((insn & 0x01200000) == 0x01000000) {
                /* Single load/store */
                offset = (insn & 0xff) << 2;
                if ((insn & (1 << 23)) == 0)
                    offset = -offset;
3922 3923 3924 3925 3926 3927 3928
                if (s->thumb && rn == 15) {
                    /* This is actually UNPREDICTABLE */
                    addr = tcg_temp_new_i32();
                    tcg_gen_movi_i32(addr, s->pc & ~2);
                } else {
                    addr = load_reg(s, rn);
                }
3929
                tcg_gen_addi_i32(addr, addr, offset);
B
bellard 已提交
3930
                if (insn & (1 << 20)) {
3931
                    gen_vfp_ld(s, dp, addr);
B
bellard 已提交
3932 3933 3934
                    gen_mov_vreg_F0(dp, rd);
                } else {
                    gen_mov_F0_vreg(dp, rd);
3935
                    gen_vfp_st(s, dp, addr);
B
bellard 已提交
3936
                }
3937
                tcg_temp_free_i32(addr);
B
bellard 已提交
3938 3939
            } else {
                /* load/store multiple */
3940
                int w = insn & (1 << 21);
B
bellard 已提交
3941 3942 3943 3944 3945
                if (dp)
                    n = (insn >> 1) & 0x7f;
                else
                    n = insn & 0xff;

3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967
                if (w && !(((insn >> 23) ^ (insn >> 24)) & 1)) {
                    /* P == U , W == 1  => UNDEF */
                    return 1;
                }
                if (n == 0 || (rd + n) > 32 || (dp && n > 16)) {
                    /* UNPREDICTABLE cases for bad immediates: we choose to
                     * UNDEF to avoid generating huge numbers of TCG ops
                     */
                    return 1;
                }
                if (rn == 15 && w) {
                    /* writeback to PC is UNPREDICTABLE, we choose to UNDEF */
                    return 1;
                }

                if (s->thumb && rn == 15) {
                    /* This is actually UNPREDICTABLE */
                    addr = tcg_temp_new_i32();
                    tcg_gen_movi_i32(addr, s->pc & ~2);
                } else {
                    addr = load_reg(s, rn);
                }
B
bellard 已提交
3968
                if (insn & (1 << 24)) /* pre-decrement */
3969
                    tcg_gen_addi_i32(addr, addr, -((insn & 0xff) << 2));
B
bellard 已提交
3970 3971 3972 3973 3974 3975

                if (dp)
                    offset = 8;
                else
                    offset = 4;
                for (i = 0; i < n; i++) {
3976
                    if (insn & ARM_CP_RW_BIT) {
B
bellard 已提交
3977
                        /* load */
3978
                        gen_vfp_ld(s, dp, addr);
B
bellard 已提交
3979 3980 3981 3982
                        gen_mov_vreg_F0(dp, rd + i);
                    } else {
                        /* store */
                        gen_mov_F0_vreg(dp, rd + i);
3983
                        gen_vfp_st(s, dp, addr);
B
bellard 已提交
3984
                    }
3985
                    tcg_gen_addi_i32(addr, addr, offset);
B
bellard 已提交
3986
                }
3987
                if (w) {
B
bellard 已提交
3988 3989 3990 3991 3992 3993 3994 3995 3996
                    /* writeback */
                    if (insn & (1 << 24))
                        offset = -offset * n;
                    else if (dp && (insn & 1))
                        offset = 4;
                    else
                        offset = 0;

                    if (offset != 0)
3997 3998 3999
                        tcg_gen_addi_i32(addr, addr, offset);
                    store_reg(s, rn, addr);
                } else {
4000
                    tcg_temp_free_i32(addr);
B
bellard 已提交
4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011
                }
            }
        }
        break;
    default:
        /* Should never happen.  */
        return 1;
    }
    return 0;
}

4012
static inline bool use_goto_tb(DisasContext *s, target_ulong dest)
B
bellard 已提交
4013
{
4014 4015 4016 4017 4018 4019 4020
#ifndef CONFIG_USER_ONLY
    return (s->tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) ||
           ((s->pc - 1) & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK);
#else
    return true;
#endif
}
4021

4022 4023 4024
static inline void gen_goto_tb(DisasContext *s, int n, target_ulong dest)
{
    if (use_goto_tb(s, dest)) {
B
bellard 已提交
4025
        tcg_gen_goto_tb(n);
4026
        gen_set_pc_im(s, dest);
4027
        tcg_gen_exit_tb((uintptr_t)s->tb + n);
4028
    } else {
4029
        gen_set_pc_im(s, dest);
B
bellard 已提交
4030
        tcg_gen_exit_tb(0);
4031
    }
B
bellard 已提交
4032 4033
}

B
bellard 已提交
4034 4035
static inline void gen_jmp (DisasContext *s, uint32_t dest)
{
4036
    if (unlikely(s->singlestep_enabled || s->ss_active)) {
B
bellard 已提交
4037
        /* An indirect jump so that we still trigger the debug exception.  */
B
bellard 已提交
4038
        if (s->thumb)
P
pbrook 已提交
4039 4040
            dest |= 1;
        gen_bx_im(s, dest);
B
bellard 已提交
4041
    } else {
4042
        gen_goto_tb(s, 0, dest);
B
bellard 已提交
4043 4044 4045 4046
        s->is_jmp = DISAS_TB_JUMP;
    }
}

4047
static inline void gen_mulxy(TCGv_i32 t0, TCGv_i32 t1, int x, int y)
B
bellard 已提交
4048
{
B
bellard 已提交
4049
    if (x)
P
pbrook 已提交
4050
        tcg_gen_sari_i32(t0, t0, 16);
B
bellard 已提交
4051
    else
P
pbrook 已提交
4052
        gen_sxth(t0);
B
bellard 已提交
4053
    if (y)
P
pbrook 已提交
4054
        tcg_gen_sari_i32(t1, t1, 16);
B
bellard 已提交
4055
    else
P
pbrook 已提交
4056 4057
        gen_sxth(t1);
    tcg_gen_mul_i32(t0, t0, t1);
B
bellard 已提交
4058 4059 4060
}

/* Return the mask of PSR bits set by a MSR instruction.  */
4061 4062
static uint32_t msr_mask(DisasContext *s, int flags, int spsr)
{
B
bellard 已提交
4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073
    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 已提交
4074

P
pbrook 已提交
4075
    /* Mask out undefined bits.  */
P
pbrook 已提交
4076
    mask &= ~CPSR_RESERVED;
4077
    if (!arm_dc_feature(s, ARM_FEATURE_V4T)) {
4078
        mask &= ~CPSR_T;
4079 4080
    }
    if (!arm_dc_feature(s, ARM_FEATURE_V5)) {
4081
        mask &= ~CPSR_Q; /* V5TE in reality*/
4082 4083
    }
    if (!arm_dc_feature(s, ARM_FEATURE_V6)) {
P
pbrook 已提交
4084
        mask &= ~(CPSR_E | CPSR_GE);
4085 4086
    }
    if (!arm_dc_feature(s, ARM_FEATURE_THUMB2)) {
P
pbrook 已提交
4087
        mask &= ~CPSR_IT;
4088
    }
4089 4090 4091 4092
    /* Mask out execution state and reserved bits.  */
    if (!spsr) {
        mask &= ~(CPSR_EXEC | CPSR_RESERVED);
    }
B
bellard 已提交
4093 4094
    /* Mask out privileged bits.  */
    if (IS_USER(s))
P
pbrook 已提交
4095
        mask &= CPSR_USER;
B
bellard 已提交
4096 4097 4098
    return mask;
}

4099
/* Returns nonzero if access to the PSR is not permitted. Marks t0 as dead. */
4100
static int gen_set_psr(DisasContext *s, uint32_t mask, int spsr, TCGv_i32 t0)
B
bellard 已提交
4101
{
4102
    TCGv_i32 tmp;
B
bellard 已提交
4103 4104 4105 4106
    if (spsr) {
        /* ??? This is also undefined in system mode.  */
        if (IS_USER(s))
            return 1;
P
pbrook 已提交
4107 4108 4109

        tmp = load_cpu_field(spsr);
        tcg_gen_andi_i32(tmp, tmp, ~mask);
4110 4111
        tcg_gen_andi_i32(t0, t0, mask);
        tcg_gen_or_i32(tmp, tmp, t0);
P
pbrook 已提交
4112
        store_cpu_field(tmp, spsr);
B
bellard 已提交
4113
    } else {
4114
        gen_set_cpsr(t0, mask);
B
bellard 已提交
4115
    }
4116
    tcg_temp_free_i32(t0);
B
bellard 已提交
4117 4118 4119 4120
    gen_lookup_tb(s);
    return 0;
}

4121 4122 4123
/* Returns nonzero if access to the PSR is not permitted.  */
static int gen_set_psr_im(DisasContext *s, uint32_t mask, int spsr, uint32_t val)
{
4124
    TCGv_i32 tmp;
4125
    tmp = tcg_temp_new_i32();
4126 4127 4128 4129
    tcg_gen_movi_i32(tmp, val);
    return gen_set_psr(s, mask, spsr, tmp);
}

4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318
static bool msr_banked_access_decode(DisasContext *s, int r, int sysm, int rn,
                                     int *tgtmode, int *regno)
{
    /* Decode the r and sysm fields of MSR/MRS banked accesses into
     * the target mode and register number, and identify the various
     * unpredictable cases.
     * MSR (banked) and MRS (banked) are CONSTRAINED UNPREDICTABLE if:
     *  + executed in user mode
     *  + using R15 as the src/dest register
     *  + accessing an unimplemented register
     *  + accessing a register that's inaccessible at current PL/security state*
     *  + accessing a register that you could access with a different insn
     * We choose to UNDEF in all these cases.
     * Since we don't know which of the various AArch32 modes we are in
     * we have to defer some checks to runtime.
     * Accesses to Monitor mode registers from Secure EL1 (which implies
     * that EL3 is AArch64) must trap to EL3.
     *
     * If the access checks fail this function will emit code to take
     * an exception and return false. Otherwise it will return true,
     * and set *tgtmode and *regno appropriately.
     */
    int exc_target = default_exception_el(s);

    /* These instructions are present only in ARMv8, or in ARMv7 with the
     * Virtualization Extensions.
     */
    if (!arm_dc_feature(s, ARM_FEATURE_V8) &&
        !arm_dc_feature(s, ARM_FEATURE_EL2)) {
        goto undef;
    }

    if (IS_USER(s) || rn == 15) {
        goto undef;
    }

    /* The table in the v8 ARM ARM section F5.2.3 describes the encoding
     * of registers into (r, sysm).
     */
    if (r) {
        /* SPSRs for other modes */
        switch (sysm) {
        case 0xe: /* SPSR_fiq */
            *tgtmode = ARM_CPU_MODE_FIQ;
            break;
        case 0x10: /* SPSR_irq */
            *tgtmode = ARM_CPU_MODE_IRQ;
            break;
        case 0x12: /* SPSR_svc */
            *tgtmode = ARM_CPU_MODE_SVC;
            break;
        case 0x14: /* SPSR_abt */
            *tgtmode = ARM_CPU_MODE_ABT;
            break;
        case 0x16: /* SPSR_und */
            *tgtmode = ARM_CPU_MODE_UND;
            break;
        case 0x1c: /* SPSR_mon */
            *tgtmode = ARM_CPU_MODE_MON;
            break;
        case 0x1e: /* SPSR_hyp */
            *tgtmode = ARM_CPU_MODE_HYP;
            break;
        default: /* unallocated */
            goto undef;
        }
        /* We arbitrarily assign SPSR a register number of 16. */
        *regno = 16;
    } else {
        /* general purpose registers for other modes */
        switch (sysm) {
        case 0x0 ... 0x6:   /* 0b00xxx : r8_usr ... r14_usr */
            *tgtmode = ARM_CPU_MODE_USR;
            *regno = sysm + 8;
            break;
        case 0x8 ... 0xe:   /* 0b01xxx : r8_fiq ... r14_fiq */
            *tgtmode = ARM_CPU_MODE_FIQ;
            *regno = sysm;
            break;
        case 0x10 ... 0x11: /* 0b1000x : r14_irq, r13_irq */
            *tgtmode = ARM_CPU_MODE_IRQ;
            *regno = sysm & 1 ? 13 : 14;
            break;
        case 0x12 ... 0x13: /* 0b1001x : r14_svc, r13_svc */
            *tgtmode = ARM_CPU_MODE_SVC;
            *regno = sysm & 1 ? 13 : 14;
            break;
        case 0x14 ... 0x15: /* 0b1010x : r14_abt, r13_abt */
            *tgtmode = ARM_CPU_MODE_ABT;
            *regno = sysm & 1 ? 13 : 14;
            break;
        case 0x16 ... 0x17: /* 0b1011x : r14_und, r13_und */
            *tgtmode = ARM_CPU_MODE_UND;
            *regno = sysm & 1 ? 13 : 14;
            break;
        case 0x1c ... 0x1d: /* 0b1110x : r14_mon, r13_mon */
            *tgtmode = ARM_CPU_MODE_MON;
            *regno = sysm & 1 ? 13 : 14;
            break;
        case 0x1e ... 0x1f: /* 0b1111x : elr_hyp, r13_hyp */
            *tgtmode = ARM_CPU_MODE_HYP;
            /* Arbitrarily pick 17 for ELR_Hyp (which is not a banked LR!) */
            *regno = sysm & 1 ? 13 : 17;
            break;
        default: /* unallocated */
            goto undef;
        }
    }

    /* Catch the 'accessing inaccessible register' cases we can detect
     * at translate time.
     */
    switch (*tgtmode) {
    case ARM_CPU_MODE_MON:
        if (!arm_dc_feature(s, ARM_FEATURE_EL3) || s->ns) {
            goto undef;
        }
        if (s->current_el == 1) {
            /* If we're in Secure EL1 (which implies that EL3 is AArch64)
             * then accesses to Mon registers trap to EL3
             */
            exc_target = 3;
            goto undef;
        }
        break;
    case ARM_CPU_MODE_HYP:
        /* Note that we can forbid accesses from EL2 here because they
         * must be from Hyp mode itself
         */
        if (!arm_dc_feature(s, ARM_FEATURE_EL2) || s->current_el < 3) {
            goto undef;
        }
        break;
    default:
        break;
    }

    return true;

undef:
    /* If we get here then some access check did not pass */
    gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized(), exc_target);
    return false;
}

static void gen_msr_banked(DisasContext *s, int r, int sysm, int rn)
{
    TCGv_i32 tcg_reg, tcg_tgtmode, tcg_regno;
    int tgtmode = 0, regno = 0;

    if (!msr_banked_access_decode(s, r, sysm, rn, &tgtmode, &regno)) {
        return;
    }

    /* Sync state because msr_banked() can raise exceptions */
    gen_set_condexec(s);
    gen_set_pc_im(s, s->pc - 4);
    tcg_reg = load_reg(s, rn);
    tcg_tgtmode = tcg_const_i32(tgtmode);
    tcg_regno = tcg_const_i32(regno);
    gen_helper_msr_banked(cpu_env, tcg_reg, tcg_tgtmode, tcg_regno);
    tcg_temp_free_i32(tcg_tgtmode);
    tcg_temp_free_i32(tcg_regno);
    tcg_temp_free_i32(tcg_reg);
    s->is_jmp = DISAS_UPDATE;
}

static void gen_mrs_banked(DisasContext *s, int r, int sysm, int rn)
{
    TCGv_i32 tcg_reg, tcg_tgtmode, tcg_regno;
    int tgtmode = 0, regno = 0;

    if (!msr_banked_access_decode(s, r, sysm, rn, &tgtmode, &regno)) {
        return;
    }

    /* Sync state because mrs_banked() can raise exceptions */
    gen_set_condexec(s);
    gen_set_pc_im(s, s->pc - 4);
    tcg_reg = tcg_temp_new_i32();
    tcg_tgtmode = tcg_const_i32(tgtmode);
    tcg_regno = tcg_const_i32(regno);
    gen_helper_mrs_banked(tcg_reg, cpu_env, tcg_tgtmode, tcg_regno);
    tcg_temp_free_i32(tcg_tgtmode);
    tcg_temp_free_i32(tcg_regno);
    store_reg(s, rn, tcg_reg);
    s->is_jmp = DISAS_UPDATE;
}

4319 4320 4321 4322 4323
/* Store value to PC as for an exception return (ie don't
 * mask bits). The subsequent call to gen_helper_cpsr_write_eret()
 * will do the masking based on the new value of the Thumb bit.
 */
static void store_pc_exc_ret(DisasContext *s, TCGv_i32 pc)
B
bellard 已提交
4324
{
4325 4326
    tcg_gen_mov_i32(cpu_R[15], pc);
    tcg_temp_free_i32(pc);
B
bellard 已提交
4327 4328
}

P
pbrook 已提交
4329
/* Generate a v6 exception return.  Marks both values as dead.  */
4330
static void gen_rfe(DisasContext *s, TCGv_i32 pc, TCGv_i32 cpsr)
B
bellard 已提交
4331
{
4332 4333 4334 4335 4336
    store_pc_exc_ret(s, pc);
    /* The cpsr_write_eret helper will mask the low bits of PC
     * appropriately depending on the new Thumb bit, so it must
     * be called after storing the new PC.
     */
4337
    gen_helper_cpsr_write_eret(cpu_env, cpsr);
4338
    tcg_temp_free_i32(cpsr);
4339
    s->is_jmp = DISAS_JUMP;
P
pbrook 已提交
4340
}
4341

4342 4343 4344 4345 4346 4347
/* Generate an old-style exception return. Marks pc as dead. */
static void gen_exception_return(DisasContext *s, TCGv_i32 pc)
{
    gen_rfe(s, pc, load_cpu_field(spsr));
}

P
pbrook 已提交
4348 4349 4350
static void gen_nop_hint(DisasContext *s, int val)
{
    switch (val) {
4351 4352 4353 4354
    case 1: /* yield */
        gen_set_pc_im(s, s->pc);
        s->is_jmp = DISAS_YIELD;
        break;
P
pbrook 已提交
4355
    case 3: /* wfi */
4356
        gen_set_pc_im(s, s->pc);
P
pbrook 已提交
4357 4358 4359
        s->is_jmp = DISAS_WFI;
        break;
    case 2: /* wfe */
4360 4361 4362
        gen_set_pc_im(s, s->pc);
        s->is_jmp = DISAS_WFE;
        break;
P
pbrook 已提交
4363
    case 4: /* sev */
4364 4365
    case 5: /* sevl */
        /* TODO: Implement SEV, SEVL and WFE.  May help SMP performance.  */
P
pbrook 已提交
4366 4367 4368 4369
    default: /* nop */
        break;
    }
}
B
bellard 已提交
4370

P
pbrook 已提交
4371
#define CPU_V001 cpu_V0, cpu_V0, cpu_V1
P
pbrook 已提交
4372

4373
static inline void gen_neon_add(int size, TCGv_i32 t0, TCGv_i32 t1)
P
pbrook 已提交
4374 4375
{
    switch (size) {
4376 4377 4378
    case 0: gen_helper_neon_add_u8(t0, t0, t1); break;
    case 1: gen_helper_neon_add_u16(t0, t0, t1); break;
    case 2: tcg_gen_add_i32(t0, t0, t1); break;
4379
    default: abort();
P
pbrook 已提交
4380 4381 4382
    }
}

4383
static inline void gen_neon_rsb(int size, TCGv_i32 t0, TCGv_i32 t1)
P
pbrook 已提交
4384 4385
{
    switch (size) {
4386 4387 4388
    case 0: gen_helper_neon_sub_u8(t0, t1, t0); break;
    case 1: gen_helper_neon_sub_u16(t0, t1, t0); break;
    case 2: tcg_gen_sub_i32(t0, t1, t0); break;
P
pbrook 已提交
4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401
    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

#define GEN_NEON_INTEGER_OP_ENV(name) do { \
    switch ((size << 1) | u) { \
    case 0: \
4402
        gen_helper_neon_##name##_s8(tmp, cpu_env, tmp, tmp2); \
P
pbrook 已提交
4403 4404
        break; \
    case 1: \
4405
        gen_helper_neon_##name##_u8(tmp, cpu_env, tmp, tmp2); \
P
pbrook 已提交
4406 4407
        break; \
    case 2: \
4408
        gen_helper_neon_##name##_s16(tmp, cpu_env, tmp, tmp2); \
P
pbrook 已提交
4409 4410
        break; \
    case 3: \
4411
        gen_helper_neon_##name##_u16(tmp, cpu_env, tmp, tmp2); \
P
pbrook 已提交
4412 4413
        break; \
    case 4: \
4414
        gen_helper_neon_##name##_s32(tmp, cpu_env, tmp, tmp2); \
P
pbrook 已提交
4415 4416
        break; \
    case 5: \
4417
        gen_helper_neon_##name##_u32(tmp, cpu_env, tmp, tmp2); \
P
pbrook 已提交
4418 4419 4420
        break; \
    default: return 1; \
    }} while (0)
P
pbrook 已提交
4421 4422 4423

#define GEN_NEON_INTEGER_OP(name) do { \
    switch ((size << 1) | u) { \
P
pbrook 已提交
4424
    case 0: \
4425
        gen_helper_neon_##name##_s8(tmp, tmp, tmp2); \
P
pbrook 已提交
4426 4427
        break; \
    case 1: \
4428
        gen_helper_neon_##name##_u8(tmp, tmp, tmp2); \
P
pbrook 已提交
4429 4430
        break; \
    case 2: \
4431
        gen_helper_neon_##name##_s16(tmp, tmp, tmp2); \
P
pbrook 已提交
4432 4433
        break; \
    case 3: \
4434
        gen_helper_neon_##name##_u16(tmp, tmp, tmp2); \
P
pbrook 已提交
4435 4436
        break; \
    case 4: \
4437
        gen_helper_neon_##name##_s32(tmp, tmp, tmp2); \
P
pbrook 已提交
4438 4439
        break; \
    case 5: \
4440
        gen_helper_neon_##name##_u32(tmp, tmp, tmp2); \
P
pbrook 已提交
4441
        break; \
P
pbrook 已提交
4442 4443 4444
    default: return 1; \
    }} while (0)

4445
static TCGv_i32 neon_load_scratch(int scratch)
P
pbrook 已提交
4446
{
4447
    TCGv_i32 tmp = tcg_temp_new_i32();
4448 4449
    tcg_gen_ld_i32(tmp, cpu_env, offsetof(CPUARMState, vfp.scratch[scratch]));
    return tmp;
P
pbrook 已提交
4450 4451
}

4452
static void neon_store_scratch(int scratch, TCGv_i32 var)
P
pbrook 已提交
4453
{
4454
    tcg_gen_st_i32(var, cpu_env, offsetof(CPUARMState, vfp.scratch[scratch]));
4455
    tcg_temp_free_i32(var);
P
pbrook 已提交
4456 4457
}

4458
static inline TCGv_i32 neon_get_scalar(int size, int reg)
P
pbrook 已提交
4459
{
4460
    TCGv_i32 tmp;
P
pbrook 已提交
4461
    if (size == 1) {
4462 4463
        tmp = neon_load_reg(reg & 7, reg >> 4);
        if (reg & 8) {
4464
            gen_neon_dup_high16(tmp);
4465 4466
        } else {
            gen_neon_dup_low16(tmp);
4467
        }
4468 4469
    } else {
        tmp = neon_load_reg(reg & 15, reg >> 4);
P
pbrook 已提交
4470
    }
4471
    return tmp;
P
pbrook 已提交
4472 4473
}

4474
static int gen_neon_unzip(int rd, int rm, int size, int q)
4475
{
4476
    TCGv_i32 tmp, tmp2;
4477
    if (!q && size == 2) {
4478 4479 4480 4481 4482 4483 4484
        return 1;
    }
    tmp = tcg_const_i32(rd);
    tmp2 = tcg_const_i32(rm);
    if (q) {
        switch (size) {
        case 0:
4485
            gen_helper_neon_qunzip8(cpu_env, tmp, tmp2);
4486 4487
            break;
        case 1:
4488
            gen_helper_neon_qunzip16(cpu_env, tmp, tmp2);
4489 4490
            break;
        case 2:
4491
            gen_helper_neon_qunzip32(cpu_env, tmp, tmp2);
4492 4493 4494 4495 4496 4497 4498
            break;
        default:
            abort();
        }
    } else {
        switch (size) {
        case 0:
4499
            gen_helper_neon_unzip8(cpu_env, tmp, tmp2);
4500 4501
            break;
        case 1:
4502
            gen_helper_neon_unzip16(cpu_env, tmp, tmp2);
4503 4504 4505 4506 4507 4508 4509 4510
            break;
        default:
            abort();
        }
    }
    tcg_temp_free_i32(tmp);
    tcg_temp_free_i32(tmp2);
    return 0;
4511 4512
}

4513
static int gen_neon_zip(int rd, int rm, int size, int q)
4514
{
4515
    TCGv_i32 tmp, tmp2;
4516
    if (!q && size == 2) {
4517 4518 4519 4520 4521 4522 4523
        return 1;
    }
    tmp = tcg_const_i32(rd);
    tmp2 = tcg_const_i32(rm);
    if (q) {
        switch (size) {
        case 0:
4524
            gen_helper_neon_qzip8(cpu_env, tmp, tmp2);
4525 4526
            break;
        case 1:
4527
            gen_helper_neon_qzip16(cpu_env, tmp, tmp2);
4528 4529
            break;
        case 2:
4530
            gen_helper_neon_qzip32(cpu_env, tmp, tmp2);
4531 4532 4533 4534 4535 4536 4537
            break;
        default:
            abort();
        }
    } else {
        switch (size) {
        case 0:
4538
            gen_helper_neon_zip8(cpu_env, tmp, tmp2);
4539 4540
            break;
        case 1:
4541
            gen_helper_neon_zip16(cpu_env, tmp, tmp2);
4542 4543 4544 4545 4546 4547 4548 4549
            break;
        default:
            abort();
        }
    }
    tcg_temp_free_i32(tmp);
    tcg_temp_free_i32(tmp2);
    return 0;
4550 4551
}

4552
static void gen_neon_trn_u8(TCGv_i32 t0, TCGv_i32 t1)
4553
{
4554
    TCGv_i32 rd, tmp;
4555

4556 4557
    rd = tcg_temp_new_i32();
    tmp = tcg_temp_new_i32();
4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569

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

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

4570 4571
    tcg_temp_free_i32(tmp);
    tcg_temp_free_i32(rd);
4572 4573
}

4574
static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1)
4575
{
4576
    TCGv_i32 rd, tmp;
4577

4578 4579
    rd = tcg_temp_new_i32();
    tmp = tcg_temp_new_i32();
4580 4581 4582 4583 4584 4585 4586 4587 4588

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

4589 4590
    tcg_temp_free_i32(tmp);
    tcg_temp_free_i32(rd);
4591 4592 4593
}


P
pbrook 已提交
4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613
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.  */
4614
static int disas_neon_ls_insn(DisasContext *s, uint32_t insn)
P
pbrook 已提交
4615 4616 4617 4618 4619
{
    int rd, rn, rm;
    int op;
    int nregs;
    int interleave;
4620
    int spacing;
P
pbrook 已提交
4621 4622 4623 4624 4625 4626 4627
    int stride;
    int size;
    int reg;
    int pass;
    int load;
    int shift;
    int n;
4628 4629 4630
    TCGv_i32 addr;
    TCGv_i32 tmp;
    TCGv_i32 tmp2;
4631
    TCGv_i64 tmp64;
P
pbrook 已提交
4632

4633 4634 4635 4636
    /* FIXME: this access check should not take precedence over UNDEF
     * for invalid encodings; we will generate incorrect syndrome information
     * for attempts to execute invalid vfp/neon encodings with FP disabled.
     */
4637
    if (s->fp_excp_el) {
4638
        gen_exception_insn(s, 4, EXCP_UDEF,
4639
                           syn_fp_access_trap(1, 0xe, false), s->fp_excp_el);
4640 4641 4642
        return 0;
    }

4643
    if (!s->vfp_enabled)
P
pbrook 已提交
4644 4645 4646 4647 4648 4649 4650 4651 4652
      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;
4653
        if (op > 10)
P
pbrook 已提交
4654
            return 1;
4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669
        /* Catch UNDEF cases for bad values of align field */
        switch (op & 0xc) {
        case 4:
            if (((insn >> 5) & 1) == 1) {
                return 1;
            }
            break;
        case 8:
            if (((insn >> 4) & 3) == 3) {
                return 1;
            }
            break;
        default:
            break;
        }
P
pbrook 已提交
4670 4671
        nregs = neon_ls_element_type[op].nregs;
        interleave = neon_ls_element_type[op].interleave;
4672 4673 4674
        spacing = neon_ls_element_type[op].spacing;
        if (size == 3 && (interleave | spacing) != 1)
            return 1;
4675
        addr = tcg_temp_new_i32();
4676
        load_reg_var(s, addr, rn);
P
pbrook 已提交
4677 4678 4679
        stride = (1 << size) * interleave;
        for (reg = 0; reg < nregs; reg++) {
            if (interleave > 2 || (interleave == 2 && nregs == 2)) {
4680 4681
                load_reg_var(s, addr, rn);
                tcg_gen_addi_i32(addr, addr, (1 << size) * reg);
P
pbrook 已提交
4682
            } else if (interleave == 2 && nregs == 4 && reg == 2) {
4683 4684
                load_reg_var(s, addr, rn);
                tcg_gen_addi_i32(addr, addr, 1 << size);
P
pbrook 已提交
4685
            }
4686
            if (size == 3) {
4687
                tmp64 = tcg_temp_new_i64();
4688
                if (load) {
4689
                    gen_aa32_ld64(s, tmp64, addr, get_mem_index(s));
4690 4691 4692
                    neon_store_reg64(tmp64, rd);
                } else {
                    neon_load_reg64(tmp64, rd);
4693
                    gen_aa32_st64(s, tmp64, addr, get_mem_index(s));
4694
                }
4695
                tcg_temp_free_i64(tmp64);
4696 4697 4698 4699 4700
                tcg_gen_addi_i32(addr, addr, stride);
            } else {
                for (pass = 0; pass < 2; pass++) {
                    if (size == 2) {
                        if (load) {
4701
                            tmp = tcg_temp_new_i32();
4702
                            gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
4703 4704 4705
                            neon_store_reg(rd, pass, tmp);
                        } else {
                            tmp = neon_load_reg(rd, pass);
4706
                            gen_aa32_st32(s, tmp, addr, get_mem_index(s));
4707
                            tcg_temp_free_i32(tmp);
4708
                        }
4709
                        tcg_gen_addi_i32(addr, addr, stride);
4710 4711
                    } else if (size == 1) {
                        if (load) {
4712
                            tmp = tcg_temp_new_i32();
4713
                            gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
4714
                            tcg_gen_addi_i32(addr, addr, stride);
4715
                            tmp2 = tcg_temp_new_i32();
4716
                            gen_aa32_ld16u(s, tmp2, addr, get_mem_index(s));
4717
                            tcg_gen_addi_i32(addr, addr, stride);
P
Paul Brook 已提交
4718 4719
                            tcg_gen_shli_i32(tmp2, tmp2, 16);
                            tcg_gen_or_i32(tmp, tmp, tmp2);
4720
                            tcg_temp_free_i32(tmp2);
4721 4722 4723
                            neon_store_reg(rd, pass, tmp);
                        } else {
                            tmp = neon_load_reg(rd, pass);
4724
                            tmp2 = tcg_temp_new_i32();
4725
                            tcg_gen_shri_i32(tmp2, tmp, 16);
4726
                            gen_aa32_st16(s, tmp, addr, get_mem_index(s));
4727
                            tcg_temp_free_i32(tmp);
4728
                            tcg_gen_addi_i32(addr, addr, stride);
4729
                            gen_aa32_st16(s, tmp2, addr, get_mem_index(s));
4730
                            tcg_temp_free_i32(tmp2);
4731
                            tcg_gen_addi_i32(addr, addr, stride);
P
pbrook 已提交
4732
                        }
4733 4734
                    } else /* size == 0 */ {
                        if (load) {
4735
                            TCGV_UNUSED_I32(tmp2);
4736
                            for (n = 0; n < 4; n++) {
4737
                                tmp = tcg_temp_new_i32();
4738
                                gen_aa32_ld8u(s, tmp, addr, get_mem_index(s));
4739 4740 4741 4742
                                tcg_gen_addi_i32(addr, addr, stride);
                                if (n == 0) {
                                    tmp2 = tmp;
                                } else {
P
Paul Brook 已提交
4743 4744
                                    tcg_gen_shli_i32(tmp, tmp, n * 8);
                                    tcg_gen_or_i32(tmp2, tmp2, tmp);
4745
                                    tcg_temp_free_i32(tmp);
4746
                                }
P
pbrook 已提交
4747
                            }
4748 4749 4750 4751
                            neon_store_reg(rd, pass, tmp2);
                        } else {
                            tmp2 = neon_load_reg(rd, pass);
                            for (n = 0; n < 4; n++) {
4752
                                tmp = tcg_temp_new_i32();
4753 4754 4755 4756 4757
                                if (n == 0) {
                                    tcg_gen_mov_i32(tmp, tmp2);
                                } else {
                                    tcg_gen_shri_i32(tmp, tmp2, n * 8);
                                }
4758
                                gen_aa32_st8(s, tmp, addr, get_mem_index(s));
4759
                                tcg_temp_free_i32(tmp);
4760 4761
                                tcg_gen_addi_i32(addr, addr, stride);
                            }
4762
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
4763 4764 4765 4766
                        }
                    }
                }
            }
4767
            rd += spacing;
P
pbrook 已提交
4768
        }
4769
        tcg_temp_free_i32(addr);
P
pbrook 已提交
4770 4771 4772 4773 4774
        stride = nregs * 8;
    } else {
        size = (insn >> 10) & 3;
        if (size == 3) {
            /* Load single element to all lanes.  */
4775 4776
            int a = (insn >> 4) & 1;
            if (!load) {
P
pbrook 已提交
4777
                return 1;
4778
            }
P
pbrook 已提交
4779 4780
            size = (insn >> 6) & 3;
            nregs = ((insn >> 8) & 3) + 1;
4781 4782 4783

            if (size == 3) {
                if (nregs != 4 || a == 0) {
P
pbrook 已提交
4784
                    return 1;
B
bellard 已提交
4785
                }
4786 4787 4788 4789 4790 4791 4792 4793 4794
                /* For VLD4 size==3 a == 1 means 32 bits at 16 byte alignment */
                size = 2;
            }
            if (nregs == 1 && a == 1 && size == 0) {
                return 1;
            }
            if (nregs == 3 && a == 1) {
                return 1;
            }
4795
            addr = tcg_temp_new_i32();
4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817
            load_reg_var(s, addr, rn);
            if (nregs == 1) {
                /* VLD1 to all lanes: bit 5 indicates how many Dregs to write */
                tmp = gen_load_and_replicate(s, addr, size);
                tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd, 0));
                tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd, 1));
                if (insn & (1 << 5)) {
                    tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd + 1, 0));
                    tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd + 1, 1));
                }
                tcg_temp_free_i32(tmp);
            } else {
                /* VLD2/3/4 to all lanes: bit 5 indicates register stride */
                stride = (insn & (1 << 5)) ? 2 : 1;
                for (reg = 0; reg < nregs; reg++) {
                    tmp = gen_load_and_replicate(s, addr, size);
                    tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd, 0));
                    tcg_gen_st_i32(tmp, cpu_env, neon_reg_offset(rd, 1));
                    tcg_temp_free_i32(tmp);
                    tcg_gen_addi_i32(addr, addr, 1 << size);
                    rd += stride;
                }
P
pbrook 已提交
4818
            }
4819
            tcg_temp_free_i32(addr);
P
pbrook 已提交
4820 4821 4822
            stride = (1 << size) * nregs;
        } else {
            /* Single element.  */
4823
            int idx = (insn >> 4) & 0xf;
P
pbrook 已提交
4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841
            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;
4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874
            /* Catch the UNDEF cases. This is unavoidably a bit messy. */
            switch (nregs) {
            case 1:
                if (((idx & (1 << size)) != 0) ||
                    (size == 2 && ((idx & 3) == 1 || (idx & 3) == 2))) {
                    return 1;
                }
                break;
            case 3:
                if ((idx & 1) != 0) {
                    return 1;
                }
                /* fall through */
            case 2:
                if (size == 2 && (idx & 2) != 0) {
                    return 1;
                }
                break;
            case 4:
                if ((size == 2) && ((idx & 3) == 3)) {
                    return 1;
                }
                break;
            default:
                abort();
            }
            if ((rd + stride * (nregs - 1)) > 31) {
                /* Attempts to write off the end of the register file
                 * are UNPREDICTABLE; we choose to UNDEF because otherwise
                 * the neon_load_reg() would write off the end of the array.
                 */
                return 1;
            }
4875
            addr = tcg_temp_new_i32();
4876
            load_reg_var(s, addr, rn);
P
pbrook 已提交
4877 4878
            for (reg = 0; reg < nregs; reg++) {
                if (load) {
4879
                    tmp = tcg_temp_new_i32();
P
pbrook 已提交
4880 4881
                    switch (size) {
                    case 0:
4882
                        gen_aa32_ld8u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
4883 4884
                        break;
                    case 1:
4885
                        gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
4886 4887
                        break;
                    case 2:
4888
                        gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
4889
                        break;
P
pbrook 已提交
4890 4891
                    default: /* Avoid compiler warnings.  */
                        abort();
P
pbrook 已提交
4892 4893
                    }
                    if (size != 2) {
P
pbrook 已提交
4894
                        tmp2 = neon_load_reg(rd, pass);
4895 4896
                        tcg_gen_deposit_i32(tmp, tmp2, tmp,
                                            shift, size ? 16 : 8);
4897
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
4898
                    }
P
pbrook 已提交
4899
                    neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
4900
                } else { /* Store */
P
pbrook 已提交
4901 4902 4903
                    tmp = neon_load_reg(rd, pass);
                    if (shift)
                        tcg_gen_shri_i32(tmp, tmp, shift);
P
pbrook 已提交
4904 4905
                    switch (size) {
                    case 0:
4906
                        gen_aa32_st8(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
4907 4908
                        break;
                    case 1:
4909
                        gen_aa32_st16(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
4910 4911
                        break;
                    case 2:
4912
                        gen_aa32_st32(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
4913
                        break;
B
bellard 已提交
4914
                    }
4915
                    tcg_temp_free_i32(tmp);
B
bellard 已提交
4916
                }
P
pbrook 已提交
4917
                rd += stride;
4918
                tcg_gen_addi_i32(addr, addr, 1 << size);
B
bellard 已提交
4919
            }
4920
            tcg_temp_free_i32(addr);
P
pbrook 已提交
4921
            stride = nregs * (1 << size);
B
bellard 已提交
4922
        }
P
pbrook 已提交
4923 4924
    }
    if (rm != 15) {
4925
        TCGv_i32 base;
P
pbrook 已提交
4926 4927

        base = load_reg(s, rn);
P
pbrook 已提交
4928
        if (rm == 13) {
P
pbrook 已提交
4929
            tcg_gen_addi_i32(base, base, stride);
P
pbrook 已提交
4930
        } else {
4931
            TCGv_i32 index;
P
pbrook 已提交
4932 4933
            index = load_reg(s, rm);
            tcg_gen_add_i32(base, base, index);
4934
            tcg_temp_free_i32(index);
P
pbrook 已提交
4935
        }
P
pbrook 已提交
4936
        store_reg(s, rn, base);
P
pbrook 已提交
4937 4938 4939
    }
    return 0;
}
4940

P
pbrook 已提交
4941
/* Bitwise select.  dest = c ? t : f.  Clobbers T and F.  */
4942
static void gen_neon_bsl(TCGv_i32 dest, TCGv_i32 t, TCGv_i32 f, TCGv_i32 c)
P
pbrook 已提交
4943 4944
{
    tcg_gen_and_i32(t, t, c);
4945
    tcg_gen_andc_i32(f, f, c);
P
pbrook 已提交
4946 4947 4948
    tcg_gen_or_i32(dest, t, f);
}

4949
static inline void gen_neon_narrow(int size, TCGv_i32 dest, TCGv_i64 src)
P
pbrook 已提交
4950 4951 4952 4953
{
    switch (size) {
    case 0: gen_helper_neon_narrow_u8(dest, src); break;
    case 1: gen_helper_neon_narrow_u16(dest, src); break;
4954
    case 2: tcg_gen_extrl_i64_i32(dest, src); break;
P
pbrook 已提交
4955 4956 4957 4958
    default: abort();
    }
}

4959
static inline void gen_neon_narrow_sats(int size, TCGv_i32 dest, TCGv_i64 src)
P
pbrook 已提交
4960 4961
{
    switch (size) {
4962 4963 4964
    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;
P
pbrook 已提交
4965 4966 4967 4968
    default: abort();
    }
}

4969
static inline void gen_neon_narrow_satu(int size, TCGv_i32 dest, TCGv_i64 src)
P
pbrook 已提交
4970 4971
{
    switch (size) {
4972 4973 4974
    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;
P
pbrook 已提交
4975 4976 4977 4978
    default: abort();
    }
}

4979
static inline void gen_neon_unarrow_sats(int size, TCGv_i32 dest, TCGv_i64 src)
4980 4981
{
    switch (size) {
4982 4983 4984
    case 0: gen_helper_neon_unarrow_sat8(dest, cpu_env, src); break;
    case 1: gen_helper_neon_unarrow_sat16(dest, cpu_env, src); break;
    case 2: gen_helper_neon_unarrow_sat32(dest, cpu_env, src); break;
4985 4986 4987 4988
    default: abort();
    }
}

4989
static inline void gen_neon_shift_narrow(int size, TCGv_i32 var, TCGv_i32 shift,
P
pbrook 已提交
4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008
                                         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) {
5009 5010
            case 1: gen_helper_neon_shl_u16(var, var, shift); break;
            case 2: gen_helper_neon_shl_u32(var, var, shift); break;
P
pbrook 已提交
5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022
            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();
            }
        }
    }
}

5023
static inline void gen_neon_widen(TCGv_i64 dest, TCGv_i32 src, int size, int u)
P
pbrook 已提交
5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039
{
    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();
        }
    }
5040
    tcg_temp_free_i32(src);
P
pbrook 已提交
5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062
}

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 已提交
5063
static inline void gen_neon_negl(TCGv_i64 var, int size)
P
pbrook 已提交
5064 5065 5066 5067
{
    switch (size) {
    case 0: gen_helper_neon_negl_u16(var, var); break;
    case 1: gen_helper_neon_negl_u32(var, var); break;
5068 5069 5070
    case 2:
        tcg_gen_neg_i64(var, var);
        break;
P
pbrook 已提交
5071 5072 5073 5074
    default: abort();
    }
}

P
pbrook 已提交
5075
static inline void gen_neon_addl_saturate(TCGv_i64 op0, TCGv_i64 op1, int size)
P
pbrook 已提交
5076 5077
{
    switch (size) {
5078 5079
    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;
P
pbrook 已提交
5080 5081 5082 5083
    default: abort();
    }
}

5084 5085
static inline void gen_neon_mull(TCGv_i64 dest, TCGv_i32 a, TCGv_i32 b,
                                 int size, int u)
P
pbrook 已提交
5086
{
P
pbrook 已提交
5087
    TCGv_i64 tmp;
P
pbrook 已提交
5088 5089 5090 5091 5092 5093 5094 5095 5096

    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);
5097
        tcg_temp_free_i64(tmp);
P
pbrook 已提交
5098 5099 5100 5101
        break;
    case 5:
        tmp = gen_mulu_i64_i32(a, b);
        tcg_gen_mov_i64(dest, tmp);
5102
        tcg_temp_free_i64(tmp);
P
pbrook 已提交
5103 5104 5105
        break;
    default: abort();
    }
5106 5107 5108 5109

    /* gen_helper_neon_mull_[su]{8|16} do not free their parameters.
       Don't forget to clean them now.  */
    if (size < 2) {
5110 5111
        tcg_temp_free_i32(a);
        tcg_temp_free_i32(b);
5112
    }
P
pbrook 已提交
5113 5114
}

5115 5116
static void gen_neon_narrow_op(int op, int u, int size,
                               TCGv_i32 dest, TCGv_i64 src)
5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132
{
    if (op) {
        if (u) {
            gen_neon_unarrow_sats(size, dest, src);
        } else {
            gen_neon_narrow(size, dest, src);
        }
    } else {
        if (u) {
            gen_neon_narrow_satu(size, dest, src);
        } else {
            gen_neon_narrow_sats(size, dest, src);
        }
    }
}

5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160
/* Symbolic constants for op fields for Neon 3-register same-length.
 * The values correspond to bits [11:8,4]; see the ARM ARM DDI0406B
 * table A7-9.
 */
#define NEON_3R_VHADD 0
#define NEON_3R_VQADD 1
#define NEON_3R_VRHADD 2
#define NEON_3R_LOGIC 3 /* VAND,VBIC,VORR,VMOV,VORN,VEOR,VBIF,VBIT,VBSL */
#define NEON_3R_VHSUB 4
#define NEON_3R_VQSUB 5
#define NEON_3R_VCGT 6
#define NEON_3R_VCGE 7
#define NEON_3R_VSHL 8
#define NEON_3R_VQSHL 9
#define NEON_3R_VRSHL 10
#define NEON_3R_VQRSHL 11
#define NEON_3R_VMAX 12
#define NEON_3R_VMIN 13
#define NEON_3R_VABD 14
#define NEON_3R_VABA 15
#define NEON_3R_VADD_VSUB 16
#define NEON_3R_VTST_VCEQ 17
#define NEON_3R_VML 18 /* VMLA, VMLAL, VMLS, VMLSL */
#define NEON_3R_VMUL 19
#define NEON_3R_VPMAX 20
#define NEON_3R_VPMIN 21
#define NEON_3R_VQDMULH_VQRDMULH 22
#define NEON_3R_VPADD 23
5161
#define NEON_3R_SHA 24 /* SHA1C,SHA1P,SHA1M,SHA1SU0,SHA256H{2},SHA256SU1 */
5162
#define NEON_3R_VFM 25 /* VFMA, VFMS : float fused multiply-add */
5163 5164 5165 5166 5167
#define NEON_3R_FLOAT_ARITH 26 /* float VADD, VSUB, VPADD, VABD */
#define NEON_3R_FLOAT_MULTIPLY 27 /* float VMLA, VMLS, VMUL */
#define NEON_3R_FLOAT_CMP 28 /* float VCEQ, VCGE, VCGT */
#define NEON_3R_FLOAT_ACMP 29 /* float VACGE, VACGT, VACLE, VACLT */
#define NEON_3R_FLOAT_MINMAX 30 /* float VMIN, VMAX */
5168
#define NEON_3R_FLOAT_MISC 31 /* float VRECPS, VRSQRTS, VMAXNM/MINNM */
5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194

static const uint8_t neon_3r_sizes[] = {
    [NEON_3R_VHADD] = 0x7,
    [NEON_3R_VQADD] = 0xf,
    [NEON_3R_VRHADD] = 0x7,
    [NEON_3R_LOGIC] = 0xf, /* size field encodes op type */
    [NEON_3R_VHSUB] = 0x7,
    [NEON_3R_VQSUB] = 0xf,
    [NEON_3R_VCGT] = 0x7,
    [NEON_3R_VCGE] = 0x7,
    [NEON_3R_VSHL] = 0xf,
    [NEON_3R_VQSHL] = 0xf,
    [NEON_3R_VRSHL] = 0xf,
    [NEON_3R_VQRSHL] = 0xf,
    [NEON_3R_VMAX] = 0x7,
    [NEON_3R_VMIN] = 0x7,
    [NEON_3R_VABD] = 0x7,
    [NEON_3R_VABA] = 0x7,
    [NEON_3R_VADD_VSUB] = 0xf,
    [NEON_3R_VTST_VCEQ] = 0x7,
    [NEON_3R_VML] = 0x7,
    [NEON_3R_VMUL] = 0x7,
    [NEON_3R_VPMAX] = 0x7,
    [NEON_3R_VPMIN] = 0x7,
    [NEON_3R_VQDMULH_VQRDMULH] = 0x6,
    [NEON_3R_VPADD] = 0x7,
5195
    [NEON_3R_SHA] = 0xf, /* size field encodes op type */
5196
    [NEON_3R_VFM] = 0x5, /* size bit 1 encodes op */
5197 5198 5199 5200 5201
    [NEON_3R_FLOAT_ARITH] = 0x5, /* size bit 1 encodes op */
    [NEON_3R_FLOAT_MULTIPLY] = 0x5, /* size bit 1 encodes op */
    [NEON_3R_FLOAT_CMP] = 0x5, /* size bit 1 encodes op */
    [NEON_3R_FLOAT_ACMP] = 0x5, /* size bit 1 encodes op */
    [NEON_3R_FLOAT_MINMAX] = 0x5, /* size bit 1 encodes op */
5202
    [NEON_3R_FLOAT_MISC] = 0x5, /* size bit 1 encodes op */
5203 5204
};

5205 5206 5207 5208 5209 5210 5211 5212 5213
/* Symbolic constants for op fields for Neon 2-register miscellaneous.
 * The values correspond to bits [17:16,10:7]; see the ARM ARM DDI0406B
 * table A7-13.
 */
#define NEON_2RM_VREV64 0
#define NEON_2RM_VREV32 1
#define NEON_2RM_VREV16 2
#define NEON_2RM_VPADDL 4
#define NEON_2RM_VPADDL_U 5
5214 5215
#define NEON_2RM_AESE 6 /* Includes AESD */
#define NEON_2RM_AESMC 7 /* Includes AESIMC */
5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228
#define NEON_2RM_VCLS 8
#define NEON_2RM_VCLZ 9
#define NEON_2RM_VCNT 10
#define NEON_2RM_VMVN 11
#define NEON_2RM_VPADAL 12
#define NEON_2RM_VPADAL_U 13
#define NEON_2RM_VQABS 14
#define NEON_2RM_VQNEG 15
#define NEON_2RM_VCGT0 16
#define NEON_2RM_VCGE0 17
#define NEON_2RM_VCEQ0 18
#define NEON_2RM_VCLE0 19
#define NEON_2RM_VCLT0 20
5229
#define NEON_2RM_SHA1H 21
5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245
#define NEON_2RM_VABS 22
#define NEON_2RM_VNEG 23
#define NEON_2RM_VCGT0_F 24
#define NEON_2RM_VCGE0_F 25
#define NEON_2RM_VCEQ0_F 26
#define NEON_2RM_VCLE0_F 27
#define NEON_2RM_VCLT0_F 28
#define NEON_2RM_VABS_F 30
#define NEON_2RM_VNEG_F 31
#define NEON_2RM_VSWP 32
#define NEON_2RM_VTRN 33
#define NEON_2RM_VUZP 34
#define NEON_2RM_VZIP 35
#define NEON_2RM_VMOVN 36 /* Includes VQMOVN, VQMOVUN */
#define NEON_2RM_VQMOVN 37 /* Includes VQMOVUN */
#define NEON_2RM_VSHLL 38
5246
#define NEON_2RM_SHA1SU1 39 /* Includes SHA256SU0 */
5247
#define NEON_2RM_VRINTN 40
5248
#define NEON_2RM_VRINTX 41
5249 5250
#define NEON_2RM_VRINTA 42
#define NEON_2RM_VRINTZ 43
5251
#define NEON_2RM_VCVT_F16_F32 44
5252
#define NEON_2RM_VRINTM 45
5253
#define NEON_2RM_VCVT_F32_F16 46
5254
#define NEON_2RM_VRINTP 47
5255 5256 5257 5258 5259 5260 5261 5262
#define NEON_2RM_VCVTAU 48
#define NEON_2RM_VCVTAS 49
#define NEON_2RM_VCVTNU 50
#define NEON_2RM_VCVTNS 51
#define NEON_2RM_VCVTPU 52
#define NEON_2RM_VCVTPS 53
#define NEON_2RM_VCVTMU 54
#define NEON_2RM_VCVTMS 55
5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275
#define NEON_2RM_VRECPE 56
#define NEON_2RM_VRSQRTE 57
#define NEON_2RM_VRECPE_F 58
#define NEON_2RM_VRSQRTE_F 59
#define NEON_2RM_VCVT_FS 60
#define NEON_2RM_VCVT_FU 61
#define NEON_2RM_VCVT_SF 62
#define NEON_2RM_VCVT_UF 63

static int neon_2rm_is_float_op(int op)
{
    /* Return true if this neon 2reg-misc op is float-to-float */
    return (op == NEON_2RM_VABS_F || op == NEON_2RM_VNEG_F ||
5276
            (op >= NEON_2RM_VRINTN && op <= NEON_2RM_VRINTZ) ||
5277 5278
            op == NEON_2RM_VRINTM ||
            (op >= NEON_2RM_VRINTP && op <= NEON_2RM_VCVTMS) ||
5279
            op >= NEON_2RM_VRECPE_F);
5280 5281
}

5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305
static bool neon_2rm_is_v8_op(int op)
{
    /* Return true if this neon 2reg-misc op is ARMv8 and up */
    switch (op) {
    case NEON_2RM_VRINTN:
    case NEON_2RM_VRINTA:
    case NEON_2RM_VRINTM:
    case NEON_2RM_VRINTP:
    case NEON_2RM_VRINTZ:
    case NEON_2RM_VRINTX:
    case NEON_2RM_VCVTAU:
    case NEON_2RM_VCVTAS:
    case NEON_2RM_VCVTNU:
    case NEON_2RM_VCVTNS:
    case NEON_2RM_VCVTPU:
    case NEON_2RM_VCVTPS:
    case NEON_2RM_VCVTMU:
    case NEON_2RM_VCVTMS:
        return true;
    default:
        return false;
    }
}

5306 5307 5308 5309 5310 5311 5312 5313 5314 5315
/* Each entry in this array has bit n set if the insn allows
 * size value n (otherwise it will UNDEF). Since unallocated
 * op values will have no bits set they always UNDEF.
 */
static const uint8_t neon_2rm_sizes[] = {
    [NEON_2RM_VREV64] = 0x7,
    [NEON_2RM_VREV32] = 0x3,
    [NEON_2RM_VREV16] = 0x1,
    [NEON_2RM_VPADDL] = 0x7,
    [NEON_2RM_VPADDL_U] = 0x7,
5316 5317
    [NEON_2RM_AESE] = 0x1,
    [NEON_2RM_AESMC] = 0x1,
5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330
    [NEON_2RM_VCLS] = 0x7,
    [NEON_2RM_VCLZ] = 0x7,
    [NEON_2RM_VCNT] = 0x1,
    [NEON_2RM_VMVN] = 0x1,
    [NEON_2RM_VPADAL] = 0x7,
    [NEON_2RM_VPADAL_U] = 0x7,
    [NEON_2RM_VQABS] = 0x7,
    [NEON_2RM_VQNEG] = 0x7,
    [NEON_2RM_VCGT0] = 0x7,
    [NEON_2RM_VCGE0] = 0x7,
    [NEON_2RM_VCEQ0] = 0x7,
    [NEON_2RM_VCLE0] = 0x7,
    [NEON_2RM_VCLT0] = 0x7,
5331
    [NEON_2RM_SHA1H] = 0x4,
5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347
    [NEON_2RM_VABS] = 0x7,
    [NEON_2RM_VNEG] = 0x7,
    [NEON_2RM_VCGT0_F] = 0x4,
    [NEON_2RM_VCGE0_F] = 0x4,
    [NEON_2RM_VCEQ0_F] = 0x4,
    [NEON_2RM_VCLE0_F] = 0x4,
    [NEON_2RM_VCLT0_F] = 0x4,
    [NEON_2RM_VABS_F] = 0x4,
    [NEON_2RM_VNEG_F] = 0x4,
    [NEON_2RM_VSWP] = 0x1,
    [NEON_2RM_VTRN] = 0x7,
    [NEON_2RM_VUZP] = 0x7,
    [NEON_2RM_VZIP] = 0x7,
    [NEON_2RM_VMOVN] = 0x7,
    [NEON_2RM_VQMOVN] = 0x7,
    [NEON_2RM_VSHLL] = 0x7,
5348
    [NEON_2RM_SHA1SU1] = 0x4,
5349
    [NEON_2RM_VRINTN] = 0x4,
5350
    [NEON_2RM_VRINTX] = 0x4,
5351 5352
    [NEON_2RM_VRINTA] = 0x4,
    [NEON_2RM_VRINTZ] = 0x4,
5353
    [NEON_2RM_VCVT_F16_F32] = 0x2,
5354
    [NEON_2RM_VRINTM] = 0x4,
5355
    [NEON_2RM_VCVT_F32_F16] = 0x2,
5356
    [NEON_2RM_VRINTP] = 0x4,
5357 5358 5359 5360 5361 5362 5363 5364
    [NEON_2RM_VCVTAU] = 0x4,
    [NEON_2RM_VCVTAS] = 0x4,
    [NEON_2RM_VCVTNU] = 0x4,
    [NEON_2RM_VCVTNS] = 0x4,
    [NEON_2RM_VCVTPU] = 0x4,
    [NEON_2RM_VCVTPS] = 0x4,
    [NEON_2RM_VCVTMU] = 0x4,
    [NEON_2RM_VCVTMS] = 0x4,
5365 5366 5367 5368 5369 5370 5371 5372 5373 5374
    [NEON_2RM_VRECPE] = 0x4,
    [NEON_2RM_VRSQRTE] = 0x4,
    [NEON_2RM_VRECPE_F] = 0x4,
    [NEON_2RM_VRSQRTE_F] = 0x4,
    [NEON_2RM_VCVT_FS] = 0x4,
    [NEON_2RM_VCVT_FU] = 0x4,
    [NEON_2RM_VCVT_SF] = 0x4,
    [NEON_2RM_VCVT_UF] = 0x4,
};

P
pbrook 已提交
5375 5376
/* Translate a NEON data processing instruction.  Return nonzero if the
   instruction is invalid.
P
pbrook 已提交
5377 5378
   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 已提交
5379

5380
static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
P
pbrook 已提交
5381 5382 5383 5384 5385 5386 5387 5388 5389 5390
{
    int op;
    int q;
    int rd, rn, rm;
    int size;
    int shift;
    int pass;
    int count;
    int pairwise;
    int u;
5391
    uint32_t imm, mask;
5392
    TCGv_i32 tmp, tmp2, tmp3, tmp4, tmp5;
P
pbrook 已提交
5393
    TCGv_i64 tmp64;
P
pbrook 已提交
5394

5395 5396 5397 5398
    /* FIXME: this access check should not take precedence over UNDEF
     * for invalid encodings; we will generate incorrect syndrome information
     * for attempts to execute invalid vfp/neon encodings with FP disabled.
     */
5399
    if (s->fp_excp_el) {
5400
        gen_exception_insn(s, 4, EXCP_UDEF,
5401
                           syn_fp_access_trap(1, 0xe, false), s->fp_excp_el);
5402 5403 5404
        return 0;
    }

5405
    if (!s->vfp_enabled)
P
pbrook 已提交
5406 5407 5408 5409 5410 5411 5412 5413 5414 5415
      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);
5416 5417 5418 5419
        /* Catch invalid op and bad size combinations: UNDEF */
        if ((neon_3r_sizes[op] & (1 << size)) == 0) {
            return 1;
        }
5420 5421 5422 5423 5424 5425
        /* All insns of this form UNDEF for either this condition or the
         * superset of cases "Q==1"; we catch the latter later.
         */
        if (q && ((rd | rn | rm) & 1)) {
            return 1;
        }
5426 5427 5428 5429 5430 5431 5432 5433 5434 5435
        /*
         * The SHA-1/SHA-256 3-register instructions require special treatment
         * here, as their size field is overloaded as an op type selector, and
         * they all consume their input in a single pass.
         */
        if (op == NEON_3R_SHA) {
            if (!q) {
                return 1;
            }
            if (!u) { /* SHA-1 */
5436
                if (!arm_dc_feature(s, ARM_FEATURE_V8_SHA1)) {
5437 5438 5439 5440 5441 5442 5443 5444 5445
                    return 1;
                }
                tmp = tcg_const_i32(rd);
                tmp2 = tcg_const_i32(rn);
                tmp3 = tcg_const_i32(rm);
                tmp4 = tcg_const_i32(size);
                gen_helper_crypto_sha1_3reg(cpu_env, tmp, tmp2, tmp3, tmp4);
                tcg_temp_free_i32(tmp4);
            } else { /* SHA-256 */
5446
                if (!arm_dc_feature(s, ARM_FEATURE_V8_SHA256) || size == 3) {
5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468
                    return 1;
                }
                tmp = tcg_const_i32(rd);
                tmp2 = tcg_const_i32(rn);
                tmp3 = tcg_const_i32(rm);
                switch (size) {
                case 0:
                    gen_helper_crypto_sha256h(cpu_env, tmp, tmp2, tmp3);
                    break;
                case 1:
                    gen_helper_crypto_sha256h2(cpu_env, tmp, tmp2, tmp3);
                    break;
                case 2:
                    gen_helper_crypto_sha256su1(cpu_env, tmp, tmp2, tmp3);
                    break;
                }
            }
            tcg_temp_free_i32(tmp);
            tcg_temp_free_i32(tmp2);
            tcg_temp_free_i32(tmp3);
            return 0;
        }
5469 5470
        if (size == 3 && op != NEON_3R_LOGIC) {
            /* 64-bit element instructions. */
P
pbrook 已提交
5471
            for (pass = 0; pass < (q ? 2 : 1); pass++) {
P
pbrook 已提交
5472 5473
                neon_load_reg64(cpu_V0, rn + pass);
                neon_load_reg64(cpu_V1, rm + pass);
P
pbrook 已提交
5474
                switch (op) {
5475
                case NEON_3R_VQADD:
P
pbrook 已提交
5476
                    if (u) {
5477 5478
                        gen_helper_neon_qadd_u64(cpu_V0, cpu_env,
                                                 cpu_V0, cpu_V1);
B
bellard 已提交
5479
                    } else {
5480 5481
                        gen_helper_neon_qadd_s64(cpu_V0, cpu_env,
                                                 cpu_V0, cpu_V1);
B
bellard 已提交
5482
                    }
P
pbrook 已提交
5483
                    break;
5484
                case NEON_3R_VQSUB:
P
pbrook 已提交
5485
                    if (u) {
5486 5487
                        gen_helper_neon_qsub_u64(cpu_V0, cpu_env,
                                                 cpu_V0, cpu_V1);
P
pbrook 已提交
5488
                    } else {
5489 5490
                        gen_helper_neon_qsub_s64(cpu_V0, cpu_env,
                                                 cpu_V0, cpu_V1);
P
pbrook 已提交
5491 5492
                    }
                    break;
5493
                case NEON_3R_VSHL:
P
pbrook 已提交
5494 5495 5496 5497 5498 5499
                    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;
5500
                case NEON_3R_VQSHL:
P
pbrook 已提交
5501
                    if (u) {
5502 5503
                        gen_helper_neon_qshl_u64(cpu_V0, cpu_env,
                                                 cpu_V1, cpu_V0);
P
pbrook 已提交
5504
                    } else {
5505 5506
                        gen_helper_neon_qshl_s64(cpu_V0, cpu_env,
                                                 cpu_V1, cpu_V0);
P
pbrook 已提交
5507 5508
                    }
                    break;
5509
                case NEON_3R_VRSHL:
P
pbrook 已提交
5510 5511
                    if (u) {
                        gen_helper_neon_rshl_u64(cpu_V0, cpu_V1, cpu_V0);
B
bellard 已提交
5512
                    } else {
P
pbrook 已提交
5513 5514 5515
                        gen_helper_neon_rshl_s64(cpu_V0, cpu_V1, cpu_V0);
                    }
                    break;
5516
                case NEON_3R_VQRSHL:
P
pbrook 已提交
5517
                    if (u) {
5518 5519
                        gen_helper_neon_qrshl_u64(cpu_V0, cpu_env,
                                                  cpu_V1, cpu_V0);
P
pbrook 已提交
5520
                    } else {
5521 5522
                        gen_helper_neon_qrshl_s64(cpu_V0, cpu_env,
                                                  cpu_V1, cpu_V0);
B
bellard 已提交
5523
                    }
P
pbrook 已提交
5524
                    break;
5525
                case NEON_3R_VADD_VSUB:
P
pbrook 已提交
5526
                    if (u) {
P
pbrook 已提交
5527
                        tcg_gen_sub_i64(CPU_V001);
P
pbrook 已提交
5528
                    } else {
P
pbrook 已提交
5529
                        tcg_gen_add_i64(CPU_V001);
P
pbrook 已提交
5530 5531 5532 5533
                    }
                    break;
                default:
                    abort();
B
bellard 已提交
5534
                }
P
pbrook 已提交
5535
                neon_store_reg64(cpu_V0, rd + pass);
B
bellard 已提交
5536
            }
P
pbrook 已提交
5537
            return 0;
B
bellard 已提交
5538
        }
5539
        pairwise = 0;
P
pbrook 已提交
5540
        switch (op) {
5541 5542 5543 5544
        case NEON_3R_VSHL:
        case NEON_3R_VQSHL:
        case NEON_3R_VRSHL:
        case NEON_3R_VQRSHL:
P
pbrook 已提交
5545
            {
P
pbrook 已提交
5546 5547 5548
                int rtmp;
                /* Shift instruction operands are reversed.  */
                rtmp = rn;
P
pbrook 已提交
5549
                rn = rm;
P
pbrook 已提交
5550
                rm = rtmp;
P
pbrook 已提交
5551
            }
B
bellard 已提交
5552
            break;
5553 5554 5555 5556 5557
        case NEON_3R_VPADD:
            if (u) {
                return 1;
            }
            /* Fall through */
5558 5559
        case NEON_3R_VPMAX:
        case NEON_3R_VPMIN:
P
pbrook 已提交
5560
            pairwise = 1;
B
bellard 已提交
5561
            break;
5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578
        case NEON_3R_FLOAT_ARITH:
            pairwise = (u && size < 2); /* if VPADD (float) */
            break;
        case NEON_3R_FLOAT_MINMAX:
            pairwise = u; /* if VPMIN/VPMAX (float) */
            break;
        case NEON_3R_FLOAT_CMP:
            if (!u && size) {
                /* no encoding for U=0 C=1x */
                return 1;
            }
            break;
        case NEON_3R_FLOAT_ACMP:
            if (!u) {
                return 1;
            }
            break;
5579 5580
        case NEON_3R_FLOAT_MISC:
            /* VMAXNM/VMINNM in ARMv8 */
5581
            if (u && !arm_dc_feature(s, ARM_FEATURE_V8)) {
5582 5583
                return 1;
            }
B
bellard 已提交
5584
            break;
5585 5586 5587 5588 5589
        case NEON_3R_VMUL:
            if (u && (size != 0)) {
                /* UNDEF on invalid size for polynomial subcase */
                return 1;
            }
B
bellard 已提交
5590
            break;
5591
        case NEON_3R_VFM:
5592
            if (!arm_dc_feature(s, ARM_FEATURE_VFP4) || u) {
5593 5594 5595
                return 1;
            }
            break;
P
pbrook 已提交
5596
        default:
B
bellard 已提交
5597
            break;
P
pbrook 已提交
5598
        }
5599

5600 5601 5602 5603 5604
        if (pairwise && q) {
            /* All the pairwise insns UNDEF if Q is set */
            return 1;
        }

P
pbrook 已提交
5605 5606 5607 5608
        for (pass = 0; pass < (q ? 4 : 2); pass++) {

        if (pairwise) {
            /* Pairwise.  */
5609 5610 5611
            if (pass < 1) {
                tmp = neon_load_reg(rn, 0);
                tmp2 = neon_load_reg(rn, 1);
P
pbrook 已提交
5612
            } else {
5613 5614
                tmp = neon_load_reg(rm, 0);
                tmp2 = neon_load_reg(rm, 1);
P
pbrook 已提交
5615 5616 5617
            }
        } else {
            /* Elementwise.  */
5618 5619
            tmp = neon_load_reg(rn, pass);
            tmp2 = neon_load_reg(rm, pass);
P
pbrook 已提交
5620 5621
        }
        switch (op) {
5622
        case NEON_3R_VHADD:
P
pbrook 已提交
5623 5624
            GEN_NEON_INTEGER_OP(hadd);
            break;
5625
        case NEON_3R_VQADD:
5626
            GEN_NEON_INTEGER_OP_ENV(qadd);
B
bellard 已提交
5627
            break;
5628
        case NEON_3R_VRHADD:
P
pbrook 已提交
5629
            GEN_NEON_INTEGER_OP(rhadd);
B
bellard 已提交
5630
            break;
5631
        case NEON_3R_LOGIC: /* Logic ops.  */
P
pbrook 已提交
5632 5633
            switch ((u << 2) | size) {
            case 0: /* VAND */
5634
                tcg_gen_and_i32(tmp, tmp, tmp2);
P
pbrook 已提交
5635 5636
                break;
            case 1: /* BIC */
5637
                tcg_gen_andc_i32(tmp, tmp, tmp2);
P
pbrook 已提交
5638 5639
                break;
            case 2: /* VORR */
5640
                tcg_gen_or_i32(tmp, tmp, tmp2);
P
pbrook 已提交
5641 5642
                break;
            case 3: /* VORN */
5643
                tcg_gen_orc_i32(tmp, tmp, tmp2);
P
pbrook 已提交
5644 5645
                break;
            case 4: /* VEOR */
5646
                tcg_gen_xor_i32(tmp, tmp, tmp2);
P
pbrook 已提交
5647 5648
                break;
            case 5: /* VBSL */
5649 5650
                tmp3 = neon_load_reg(rd, pass);
                gen_neon_bsl(tmp, tmp, tmp2, tmp3);
5651
                tcg_temp_free_i32(tmp3);
P
pbrook 已提交
5652 5653
                break;
            case 6: /* VBIT */
5654 5655
                tmp3 = neon_load_reg(rd, pass);
                gen_neon_bsl(tmp, tmp, tmp3, tmp2);
5656
                tcg_temp_free_i32(tmp3);
P
pbrook 已提交
5657 5658
                break;
            case 7: /* VBIF */
5659 5660
                tmp3 = neon_load_reg(rd, pass);
                gen_neon_bsl(tmp, tmp3, tmp, tmp2);
5661
                tcg_temp_free_i32(tmp3);
P
pbrook 已提交
5662
                break;
B
bellard 已提交
5663 5664
            }
            break;
5665
        case NEON_3R_VHSUB:
P
pbrook 已提交
5666 5667
            GEN_NEON_INTEGER_OP(hsub);
            break;
5668
        case NEON_3R_VQSUB:
5669
            GEN_NEON_INTEGER_OP_ENV(qsub);
B
bellard 已提交
5670
            break;
5671
        case NEON_3R_VCGT:
P
pbrook 已提交
5672 5673
            GEN_NEON_INTEGER_OP(cgt);
            break;
5674
        case NEON_3R_VCGE:
P
pbrook 已提交
5675 5676
            GEN_NEON_INTEGER_OP(cge);
            break;
5677
        case NEON_3R_VSHL:
P
pbrook 已提交
5678
            GEN_NEON_INTEGER_OP(shl);
B
bellard 已提交
5679
            break;
5680
        case NEON_3R_VQSHL:
5681
            GEN_NEON_INTEGER_OP_ENV(qshl);
B
bellard 已提交
5682
            break;
5683
        case NEON_3R_VRSHL:
P
pbrook 已提交
5684
            GEN_NEON_INTEGER_OP(rshl);
B
bellard 已提交
5685
            break;
5686
        case NEON_3R_VQRSHL:
5687
            GEN_NEON_INTEGER_OP_ENV(qrshl);
P
pbrook 已提交
5688
            break;
5689
        case NEON_3R_VMAX:
P
pbrook 已提交
5690 5691
            GEN_NEON_INTEGER_OP(max);
            break;
5692
        case NEON_3R_VMIN:
P
pbrook 已提交
5693 5694
            GEN_NEON_INTEGER_OP(min);
            break;
5695
        case NEON_3R_VABD:
P
pbrook 已提交
5696 5697
            GEN_NEON_INTEGER_OP(abd);
            break;
5698
        case NEON_3R_VABA:
P
pbrook 已提交
5699
            GEN_NEON_INTEGER_OP(abd);
5700
            tcg_temp_free_i32(tmp2);
5701 5702
            tmp2 = neon_load_reg(rd, pass);
            gen_neon_add(size, tmp, tmp2);
P
pbrook 已提交
5703
            break;
5704
        case NEON_3R_VADD_VSUB:
P
pbrook 已提交
5705
            if (!u) { /* VADD */
5706
                gen_neon_add(size, tmp, tmp2);
P
pbrook 已提交
5707 5708
            } else { /* VSUB */
                switch (size) {
5709 5710 5711
                case 0: gen_helper_neon_sub_u8(tmp, tmp, tmp2); break;
                case 1: gen_helper_neon_sub_u16(tmp, tmp, tmp2); break;
                case 2: tcg_gen_sub_i32(tmp, tmp, tmp2); break;
5712
                default: abort();
P
pbrook 已提交
5713 5714 5715
                }
            }
            break;
5716
        case NEON_3R_VTST_VCEQ:
P
pbrook 已提交
5717 5718
            if (!u) { /* VTST */
                switch (size) {
5719 5720 5721
                case 0: gen_helper_neon_tst_u8(tmp, tmp, tmp2); break;
                case 1: gen_helper_neon_tst_u16(tmp, tmp, tmp2); break;
                case 2: gen_helper_neon_tst_u32(tmp, tmp, tmp2); break;
5722
                default: abort();
P
pbrook 已提交
5723 5724 5725
                }
            } else { /* VCEQ */
                switch (size) {
5726 5727 5728
                case 0: gen_helper_neon_ceq_u8(tmp, tmp, tmp2); break;
                case 1: gen_helper_neon_ceq_u16(tmp, tmp, tmp2); break;
                case 2: gen_helper_neon_ceq_u32(tmp, tmp, tmp2); break;
5729
                default: abort();
P
pbrook 已提交
5730 5731 5732
                }
            }
            break;
5733
        case NEON_3R_VML: /* VMLA, VMLAL, VMLS,VMLSL */
P
pbrook 已提交
5734
            switch (size) {
5735 5736 5737
            case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break;
            case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break;
            case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break;
5738
            default: abort();
P
pbrook 已提交
5739
            }
5740
            tcg_temp_free_i32(tmp2);
5741
            tmp2 = neon_load_reg(rd, pass);
P
pbrook 已提交
5742
            if (u) { /* VMLS */
5743
                gen_neon_rsb(size, tmp, tmp2);
P
pbrook 已提交
5744
            } else { /* VMLA */
5745
                gen_neon_add(size, tmp, tmp2);
P
pbrook 已提交
5746 5747
            }
            break;
5748
        case NEON_3R_VMUL:
P
pbrook 已提交
5749
            if (u) { /* polynomial */
5750
                gen_helper_neon_mul_p8(tmp, tmp, tmp2);
P
pbrook 已提交
5751 5752
            } else { /* Integer */
                switch (size) {
5753 5754 5755
                case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break;
                case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break;
                case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break;
5756
                default: abort();
P
pbrook 已提交
5757 5758 5759
                }
            }
            break;
5760
        case NEON_3R_VPMAX:
P
pbrook 已提交
5761 5762
            GEN_NEON_INTEGER_OP(pmax);
            break;
5763
        case NEON_3R_VPMIN:
P
pbrook 已提交
5764 5765
            GEN_NEON_INTEGER_OP(pmin);
            break;
5766
        case NEON_3R_VQDMULH_VQRDMULH: /* Multiply high.  */
P
pbrook 已提交
5767 5768
            if (!u) { /* VQDMULH */
                switch (size) {
5769 5770 5771 5772 5773 5774
                case 1:
                    gen_helper_neon_qdmulh_s16(tmp, cpu_env, tmp, tmp2);
                    break;
                case 2:
                    gen_helper_neon_qdmulh_s32(tmp, cpu_env, tmp, tmp2);
                    break;
5775
                default: abort();
P
pbrook 已提交
5776
                }
5777
            } else { /* VQRDMULH */
P
pbrook 已提交
5778
                switch (size) {
5779 5780 5781 5782 5783 5784
                case 1:
                    gen_helper_neon_qrdmulh_s16(tmp, cpu_env, tmp, tmp2);
                    break;
                case 2:
                    gen_helper_neon_qrdmulh_s32(tmp, cpu_env, tmp, tmp2);
                    break;
5785
                default: abort();
P
pbrook 已提交
5786 5787 5788
                }
            }
            break;
5789
        case NEON_3R_VPADD:
P
pbrook 已提交
5790
            switch (size) {
5791 5792 5793
            case 0: gen_helper_neon_padd_u8(tmp, tmp, tmp2); break;
            case 1: gen_helper_neon_padd_u16(tmp, tmp, tmp2); break;
            case 2: tcg_gen_add_i32(tmp, tmp, tmp2); break;
5794
            default: abort();
P
pbrook 已提交
5795 5796
            }
            break;
5797
        case NEON_3R_FLOAT_ARITH: /* Floating point arithmetic. */
5798 5799
        {
            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
P
pbrook 已提交
5800 5801
            switch ((u << 2) | size) {
            case 0: /* VADD */
5802 5803
            case 4: /* VPADD */
                gen_helper_vfp_adds(tmp, tmp, tmp2, fpstatus);
P
pbrook 已提交
5804 5805
                break;
            case 2: /* VSUB */
5806
                gen_helper_vfp_subs(tmp, tmp, tmp2, fpstatus);
P
pbrook 已提交
5807 5808
                break;
            case 6: /* VABD */
5809
                gen_helper_neon_abd_f32(tmp, tmp, tmp2, fpstatus);
P
pbrook 已提交
5810 5811
                break;
            default:
5812
                abort();
P
pbrook 已提交
5813
            }
5814
            tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
5815
            break;
5816
        }
5817
        case NEON_3R_FLOAT_MULTIPLY:
5818 5819 5820
        {
            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
            gen_helper_vfp_muls(tmp, tmp, tmp2, fpstatus);
P
pbrook 已提交
5821
            if (!u) {
5822
                tcg_temp_free_i32(tmp2);
5823
                tmp2 = neon_load_reg(rd, pass);
P
pbrook 已提交
5824
                if (size == 0) {
5825
                    gen_helper_vfp_adds(tmp, tmp, tmp2, fpstatus);
P
pbrook 已提交
5826
                } else {
5827
                    gen_helper_vfp_subs(tmp, tmp2, tmp, fpstatus);
P
pbrook 已提交
5828 5829
                }
            }
5830
            tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
5831
            break;
5832
        }
5833
        case NEON_3R_FLOAT_CMP:
5834 5835
        {
            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
P
pbrook 已提交
5836
            if (!u) {
5837
                gen_helper_neon_ceq_f32(tmp, tmp, tmp2, fpstatus);
B
bellard 已提交
5838
            } else {
5839 5840 5841 5842 5843
                if (size == 0) {
                    gen_helper_neon_cge_f32(tmp, tmp, tmp2, fpstatus);
                } else {
                    gen_helper_neon_cgt_f32(tmp, tmp, tmp2, fpstatus);
                }
B
bellard 已提交
5844
            }
5845
            tcg_temp_free_ptr(fpstatus);
B
bellard 已提交
5846
            break;
5847
        }
5848
        case NEON_3R_FLOAT_ACMP:
5849 5850 5851 5852 5853 5854 5855 5856
        {
            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
            if (size == 0) {
                gen_helper_neon_acge_f32(tmp, tmp, tmp2, fpstatus);
            } else {
                gen_helper_neon_acgt_f32(tmp, tmp, tmp2, fpstatus);
            }
            tcg_temp_free_ptr(fpstatus);
B
bellard 已提交
5857
            break;
5858
        }
5859
        case NEON_3R_FLOAT_MINMAX:
5860 5861 5862
        {
            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
            if (size == 0) {
5863
                gen_helper_vfp_maxs(tmp, tmp, tmp2, fpstatus);
5864
            } else {
5865
                gen_helper_vfp_mins(tmp, tmp, tmp2, fpstatus);
5866 5867
            }
            tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
5868
            break;
5869
        }
5870 5871 5872 5873 5874
        case NEON_3R_FLOAT_MISC:
            if (u) {
                /* VMAXNM/VMINNM */
                TCGv_ptr fpstatus = get_fpstatus_ptr(1);
                if (size == 0) {
5875
                    gen_helper_vfp_maxnums(tmp, tmp, tmp2, fpstatus);
5876
                } else {
5877
                    gen_helper_vfp_minnums(tmp, tmp, tmp2, fpstatus);
5878 5879 5880 5881 5882 5883 5884 5885 5886
                }
                tcg_temp_free_ptr(fpstatus);
            } else {
                if (size == 0) {
                    gen_helper_recps_f32(tmp, tmp, tmp2, cpu_env);
                } else {
                    gen_helper_rsqrts_f32(tmp, tmp, tmp2, cpu_env);
              }
            }
B
bellard 已提交
5887
            break;
5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901
        case NEON_3R_VFM:
        {
            /* VFMA, VFMS: fused multiply-add */
            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
            TCGv_i32 tmp3 = neon_load_reg(rd, pass);
            if (size) {
                /* VFMS */
                gen_helper_vfp_negs(tmp, tmp);
            }
            gen_helper_vfp_muladds(tmp, tmp, tmp2, tmp3, fpstatus);
            tcg_temp_free_i32(tmp3);
            tcg_temp_free_ptr(fpstatus);
            break;
        }
P
pbrook 已提交
5902 5903
        default:
            abort();
B
bellard 已提交
5904
        }
5905
        tcg_temp_free_i32(tmp2);
5906

P
pbrook 已提交
5907 5908 5909 5910
        /* 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) {
5911
            neon_store_scratch(pass, tmp);
P
pbrook 已提交
5912
        } else {
5913
            neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
5914 5915 5916 5917 5918
        }

        } /* for pass */
        if (pairwise && rd == rm) {
            for (pass = 0; pass < (q ? 4 : 2); pass++) {
5919 5920
                tmp = neon_load_scratch(pass);
                neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
5921 5922
            }
        }
P
pbrook 已提交
5923
        /* End of 3 register same size operations.  */
P
pbrook 已提交
5924 5925 5926 5927 5928
    } else if (insn & (1 << 4)) {
        if ((insn & 0x00380080) != 0) {
            /* Two registers and shift.  */
            op = (insn >> 8) & 0xf;
            if (insn & (1 << 7)) {
5929 5930 5931 5932
                /* 64-bit shift. */
                if (op > 7) {
                    return 1;
                }
P
pbrook 已提交
5933 5934 5935 5936 5937 5938 5939
                size = 3;
            } else {
                size = 2;
                while ((insn & (1 << (size + 19))) == 0)
                    size--;
            }
            shift = (insn >> 16) & ((1 << (3 + size)) - 1);
5940
            /* To avoid excessive duplication of ops we implement shift
P
pbrook 已提交
5941 5942 5943 5944
               by immediate using the variable shift operations.  */
            if (op < 8) {
                /* Shift by immediate:
                   VSHR, VSRA, VRSHR, VRSRA, VSRI, VSHL, VQSHL, VQSHLU.  */
5945 5946 5947 5948 5949 5950
                if (q && ((rd | rm) & 1)) {
                    return 1;
                }
                if (!u && (op == 4 || op == 6)) {
                    return 1;
                }
P
pbrook 已提交
5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978
                /* 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 已提交
5979 5980 5981 5982 5983 5984 5985 5986
                    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 已提交
5987
                            else
P
pbrook 已提交
5988
                                gen_helper_neon_shl_s64(cpu_V0, cpu_V0, cpu_V1);
P
pbrook 已提交
5989
                            break;
P
pbrook 已提交
5990 5991 5992 5993
                        case 2: /* VRSHR */
                        case 3: /* VRSRA */
                            if (u)
                                gen_helper_neon_rshl_u64(cpu_V0, cpu_V0, cpu_V1);
P
pbrook 已提交
5994
                            else
P
pbrook 已提交
5995
                                gen_helper_neon_rshl_s64(cpu_V0, cpu_V0, cpu_V1);
P
pbrook 已提交
5996
                            break;
P
pbrook 已提交
5997 5998 5999 6000
                        case 4: /* VSRI */
                        case 5: /* VSHL, VSLI */
                            gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1);
                            break;
6001
                        case 6: /* VQSHLU */
6002 6003
                            gen_helper_neon_qshlu_s64(cpu_V0, cpu_env,
                                                      cpu_V0, cpu_V1);
P
pbrook 已提交
6004
                            break;
6005 6006
                        case 7: /* VQSHL */
                            if (u) {
6007
                                gen_helper_neon_qshl_u64(cpu_V0, cpu_env,
6008 6009
                                                         cpu_V0, cpu_V1);
                            } else {
6010
                                gen_helper_neon_qshl_s64(cpu_V0, cpu_env,
6011 6012
                                                         cpu_V0, cpu_V1);
                            }
P
pbrook 已提交
6013 6014
                            break;
                        }
P
pbrook 已提交
6015 6016
                        if (op == 1 || op == 3) {
                            /* Accumulate.  */
6017
                            neon_load_reg64(cpu_V1, rd + pass);
P
pbrook 已提交
6018 6019 6020
                            tcg_gen_add_i64(cpu_V0, cpu_V0, cpu_V1);
                        } else if (op == 4 || (op == 5 && u)) {
                            /* Insert */
6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033
                            neon_load_reg64(cpu_V1, rd + pass);
                            uint64_t mask;
                            if (shift < -63 || shift > 63) {
                                mask = 0;
                            } else {
                                if (op == 4) {
                                    mask = 0xffffffffffffffffull >> -shift;
                                } else {
                                    mask = 0xffffffffffffffffull << shift;
                                }
                            }
                            tcg_gen_andi_i64(cpu_V1, cpu_V1, ~mask);
                            tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1);
P
pbrook 已提交
6034 6035 6036 6037
                        }
                        neon_store_reg64(cpu_V0, rd + pass);
                    } else { /* size < 3 */
                        /* Operands in T0 and T1.  */
6038
                        tmp = neon_load_reg(rm, pass);
6039
                        tmp2 = tcg_temp_new_i32();
6040
                        tcg_gen_movi_i32(tmp2, imm);
P
pbrook 已提交
6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052
                        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 */
                        case 5: /* VSHL, VSLI */
                            switch (size) {
6053 6054 6055
                            case 0: gen_helper_neon_shl_u8(tmp, tmp, tmp2); break;
                            case 1: gen_helper_neon_shl_u16(tmp, tmp, tmp2); break;
                            case 2: gen_helper_neon_shl_u32(tmp, tmp, tmp2); break;
6056
                            default: abort();
P
pbrook 已提交
6057 6058
                            }
                            break;
6059
                        case 6: /* VQSHLU */
P
pbrook 已提交
6060
                            switch (size) {
6061
                            case 0:
6062 6063
                                gen_helper_neon_qshlu_s8(tmp, cpu_env,
                                                         tmp, tmp2);
6064 6065
                                break;
                            case 1:
6066 6067
                                gen_helper_neon_qshlu_s16(tmp, cpu_env,
                                                          tmp, tmp2);
6068 6069
                                break;
                            case 2:
6070 6071
                                gen_helper_neon_qshlu_s32(tmp, cpu_env,
                                                          tmp, tmp2);
6072 6073
                                break;
                            default:
6074
                                abort();
P
pbrook 已提交
6075 6076
                            }
                            break;
6077
                        case 7: /* VQSHL */
6078
                            GEN_NEON_INTEGER_OP_ENV(qshl);
6079
                            break;
P
pbrook 已提交
6080
                        }
6081
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
6082 6083 6084

                        if (op == 1 || op == 3) {
                            /* Accumulate.  */
6085
                            tmp2 = neon_load_reg(rd, pass);
6086
                            gen_neon_add(size, tmp, tmp2);
6087
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
6088 6089 6090 6091 6092
                        } else if (op == 4 || (op == 5 && u)) {
                            /* Insert */
                            switch (size) {
                            case 0:
                                if (op == 4)
6093
                                    mask = 0xff >> -shift;
P
pbrook 已提交
6094
                                else
6095 6096 6097
                                    mask = (uint8_t)(0xff << shift);
                                mask |= mask << 8;
                                mask |= mask << 16;
P
pbrook 已提交
6098 6099 6100
                                break;
                            case 1:
                                if (op == 4)
6101
                                    mask = 0xffff >> -shift;
P
pbrook 已提交
6102
                                else
6103 6104
                                    mask = (uint16_t)(0xffff << shift);
                                mask |= mask << 16;
P
pbrook 已提交
6105 6106
                                break;
                            case 2:
6107 6108 6109 6110 6111 6112 6113 6114
                                if (shift < -31 || shift > 31) {
                                    mask = 0;
                                } else {
                                    if (op == 4)
                                        mask = 0xffffffffu >> -shift;
                                    else
                                        mask = 0xffffffffu << shift;
                                }
P
pbrook 已提交
6115 6116 6117 6118
                                break;
                            default:
                                abort();
                            }
6119
                            tmp2 = neon_load_reg(rd, pass);
6120 6121
                            tcg_gen_andi_i32(tmp, tmp, mask);
                            tcg_gen_andi_i32(tmp2, tmp2, ~mask);
6122
                            tcg_gen_or_i32(tmp, tmp, tmp2);
6123
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
6124
                        }
6125
                        neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
6126 6127 6128
                    }
                } /* for pass */
            } else if (op < 10) {
P
pbrook 已提交
6129
                /* Shift by immediate and narrow:
P
pbrook 已提交
6130
                   VSHRN, VRSHRN, VQSHRN, VQRSHRN.  */
6131
                int input_unsigned = (op == 8) ? !u : u;
6132 6133 6134
                if (rm & 1) {
                    return 1;
                }
P
pbrook 已提交
6135 6136
                shift = shift - (1 << (size + 3));
                size++;
6137
                if (size == 3) {
P
pbrook 已提交
6138
                    tmp64 = tcg_const_i64(shift);
6139 6140 6141 6142 6143 6144 6145 6146 6147
                    neon_load_reg64(cpu_V0, rm);
                    neon_load_reg64(cpu_V1, rm + 1);
                    for (pass = 0; pass < 2; pass++) {
                        TCGv_i64 in;
                        if (pass == 0) {
                            in = cpu_V0;
                        } else {
                            in = cpu_V1;
                        }
P
pbrook 已提交
6148
                        if (q) {
6149
                            if (input_unsigned) {
6150
                                gen_helper_neon_rshl_u64(cpu_V0, in, tmp64);
6151
                            } else {
6152
                                gen_helper_neon_rshl_s64(cpu_V0, in, tmp64);
6153
                            }
P
pbrook 已提交
6154
                        } else {
6155
                            if (input_unsigned) {
6156
                                gen_helper_neon_shl_u64(cpu_V0, in, tmp64);
6157
                            } else {
6158
                                gen_helper_neon_shl_s64(cpu_V0, in, tmp64);
6159
                            }
P
pbrook 已提交
6160
                        }
6161
                        tmp = tcg_temp_new_i32();
6162 6163 6164 6165 6166 6167 6168 6169
                        gen_neon_narrow_op(op == 8, u, size - 1, tmp, cpu_V0);
                        neon_store_reg(rd, pass, tmp);
                    } /* for pass */
                    tcg_temp_free_i64(tmp64);
                } else {
                    if (size == 1) {
                        imm = (uint16_t)shift;
                        imm |= imm << 16;
B
bellard 已提交
6170
                    } else {
6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182
                        /* size == 2 */
                        imm = (uint32_t)shift;
                    }
                    tmp2 = tcg_const_i32(imm);
                    tmp4 = neon_load_reg(rm + 1, 0);
                    tmp5 = neon_load_reg(rm + 1, 1);
                    for (pass = 0; pass < 2; pass++) {
                        if (pass == 0) {
                            tmp = neon_load_reg(rm, 0);
                        } else {
                            tmp = tmp4;
                        }
6183 6184
                        gen_neon_shift_narrow(size, tmp, tmp2, q,
                                              input_unsigned);
6185 6186 6187 6188 6189
                        if (pass == 0) {
                            tmp3 = neon_load_reg(rm, 1);
                        } else {
                            tmp3 = tmp5;
                        }
6190 6191
                        gen_neon_shift_narrow(size, tmp3, tmp2, q,
                                              input_unsigned);
P
pbrook 已提交
6192
                        tcg_gen_concat_i32_i64(cpu_V0, tmp, tmp3);
6193 6194 6195
                        tcg_temp_free_i32(tmp);
                        tcg_temp_free_i32(tmp3);
                        tmp = tcg_temp_new_i32();
6196 6197 6198
                        gen_neon_narrow_op(op == 8, u, size - 1, tmp, cpu_V0);
                        neon_store_reg(rd, pass, tmp);
                    } /* for pass */
6199
                    tcg_temp_free_i32(tmp2);
6200
                }
P
pbrook 已提交
6201
            } else if (op == 10) {
6202 6203
                /* VSHLL, VMOVL */
                if (q || (rd & 1)) {
P
pbrook 已提交
6204
                    return 1;
6205
                }
P
pbrook 已提交
6206 6207
                tmp = neon_load_reg(rm, 0);
                tmp2 = neon_load_reg(rm, 1);
P
pbrook 已提交
6208
                for (pass = 0; pass < 2; pass++) {
P
pbrook 已提交
6209 6210 6211 6212
                    if (pass == 1)
                        tmp = tmp2;

                    gen_neon_widen(cpu_V0, tmp, size, u);
P
pbrook 已提交
6213 6214 6215

                    if (shift != 0) {
                        /* The shift is less than the width of the source
P
pbrook 已提交
6216 6217
                           type, so we can just shift the whole register.  */
                        tcg_gen_shli_i64(cpu_V0, cpu_V0, shift);
6218 6219 6220 6221 6222
                        /* Widen the result of shift: we need to clear
                         * the potential overflow bits resulting from
                         * left bits of the narrow input appearing as
                         * right bits of left the neighbour narrow
                         * input.  */
P
pbrook 已提交
6223 6224 6225 6226 6227
                        if (size < 2 || !u) {
                            uint64_t imm64;
                            if (size == 0) {
                                imm = (0xffu >> (8 - shift));
                                imm |= imm << 16;
6228
                            } else if (size == 1) {
P
pbrook 已提交
6229
                                imm = 0xffff >> (16 - shift);
6230 6231 6232 6233 6234 6235 6236 6237
                            } else {
                                /* size == 2 */
                                imm = 0xffffffff >> (32 - shift);
                            }
                            if (size < 2) {
                                imm64 = imm | (((uint64_t)imm) << 32);
                            } else {
                                imm64 = imm;
P
pbrook 已提交
6238
                            }
6239
                            tcg_gen_andi_i64(cpu_V0, cpu_V0, ~imm64);
P
pbrook 已提交
6240 6241
                        }
                    }
P
pbrook 已提交
6242
                    neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
6243
                }
6244
            } else if (op >= 14) {
P
pbrook 已提交
6245
                /* VCVT fixed-point.  */
6246 6247 6248
                if (!(insn & (1 << 21)) || (q && ((rd | rm) & 1))) {
                    return 1;
                }
6249 6250 6251 6252
                /* We have already masked out the must-be-1 top bit of imm6,
                 * hence this 32-shift where the ARM ARM has 64-imm6.
                 */
                shift = 32 - shift;
P
pbrook 已提交
6253
                for (pass = 0; pass < (q ? 4 : 2); pass++) {
P
pbrook 已提交
6254
                    tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, pass));
6255
                    if (!(op & 1)) {
P
pbrook 已提交
6256
                        if (u)
6257
                            gen_vfp_ulto(0, shift, 1);
P
pbrook 已提交
6258
                        else
6259
                            gen_vfp_slto(0, shift, 1);
P
pbrook 已提交
6260 6261
                    } else {
                        if (u)
6262
                            gen_vfp_toul(0, shift, 1);
P
pbrook 已提交
6263
                        else
6264
                            gen_vfp_tosl(0, shift, 1);
B
bellard 已提交
6265
                    }
P
pbrook 已提交
6266
                    tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, pass));
B
bellard 已提交
6267 6268
                }
            } else {
P
pbrook 已提交
6269 6270 6271 6272
                return 1;
            }
        } else { /* (insn & 0x00380080) == 0 */
            int invert;
6273 6274 6275
            if (q && (rd & 1)) {
                return 1;
            }
P
pbrook 已提交
6276 6277 6278 6279 6280

            op = (insn >> 8) & 0xf;
            /* One register and immediate.  */
            imm = (u << 7) | ((insn >> 12) & 0x70) | (insn & 0xf);
            invert = (insn & (1 << 5)) != 0;
6281 6282 6283 6284
            /* Note that op = 2,3,4,5,6,7,10,11,12,13 imm=0 is UNPREDICTABLE.
             * We choose to not special-case this and will behave as if a
             * valid constant encoding of 0 had been given.
             */
P
pbrook 已提交
6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304
            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:
6305
                imm = (imm << 8) | 0xff;
P
pbrook 已提交
6306 6307 6308 6309 6310 6311 6312 6313 6314 6315
                break;
            case 13:
                imm = (imm << 16) | 0xffff;
                break;
            case 14:
                imm |= (imm << 8) | (imm << 16) | (imm << 24);
                if (invert)
                    imm = ~imm;
                break;
            case 15:
6316 6317 6318
                if (invert) {
                    return 1;
                }
P
pbrook 已提交
6319 6320 6321 6322 6323 6324 6325 6326 6327
                imm = ((imm & 0x80) << 24) | ((imm & 0x3f) << 19)
                      | ((imm & 0x40) ? (0x1f << 25) : (1 << 30));
                break;
            }
            if (invert)
                imm = ~imm;

            for (pass = 0; pass < (q ? 4 : 2); pass++) {
                if (op & 1 && op < 12) {
P
pbrook 已提交
6328
                    tmp = neon_load_reg(rd, pass);
P
pbrook 已提交
6329 6330 6331
                    if (invert) {
                        /* The immediate value has already been inverted, so
                           BIC becomes AND.  */
P
pbrook 已提交
6332
                        tcg_gen_andi_i32(tmp, tmp, imm);
P
pbrook 已提交
6333
                    } else {
P
pbrook 已提交
6334
                        tcg_gen_ori_i32(tmp, tmp, imm);
P
pbrook 已提交
6335 6336
                    }
                } else {
P
pbrook 已提交
6337
                    /* VMOV, VMVN.  */
6338
                    tmp = tcg_temp_new_i32();
P
pbrook 已提交
6339
                    if (op == 14 && invert) {
6340
                        int n;
P
pbrook 已提交
6341 6342
                        uint32_t val;
                        val = 0;
P
pbrook 已提交
6343 6344
                        for (n = 0; n < 4; n++) {
                            if (imm & (1 << (n + (pass & 1) * 4)))
P
pbrook 已提交
6345
                                val |= 0xff << (n * 8);
P
pbrook 已提交
6346
                        }
P
pbrook 已提交
6347 6348 6349
                        tcg_gen_movi_i32(tmp, val);
                    } else {
                        tcg_gen_movi_i32(tmp, imm);
P
pbrook 已提交
6350 6351
                    }
                }
P
pbrook 已提交
6352
                neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
6353 6354
            }
        }
P
pbrook 已提交
6355
    } else { /* (insn & 0x00800010 == 0x00800000) */
P
pbrook 已提交
6356 6357 6358 6359 6360 6361 6362
        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;
6363 6364 6365 6366 6367
                /* undefreq: bit 0 : UNDEF if size == 0
                 *           bit 1 : UNDEF if size == 1
                 *           bit 2 : UNDEF if size == 2
                 *           bit 3 : UNDEF if U == 1
                 * Note that [2:0] set implies 'always UNDEF'
6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380
                 */
                int undefreq;
                /* prewiden, src1_wide, src2_wide, undefreq */
                static const int neon_3reg_wide[16][4] = {
                    {1, 0, 0, 0}, /* VADDL */
                    {1, 1, 0, 0}, /* VADDW */
                    {1, 0, 0, 0}, /* VSUBL */
                    {1, 1, 0, 0}, /* VSUBW */
                    {0, 1, 1, 0}, /* VADDHN */
                    {0, 0, 0, 0}, /* VABAL */
                    {0, 1, 1, 0}, /* VSUBHN */
                    {0, 0, 0, 0}, /* VABDL */
                    {0, 0, 0, 0}, /* VMLAL */
6381
                    {0, 0, 0, 9}, /* VQDMLAL */
6382
                    {0, 0, 0, 0}, /* VMLSL */
6383
                    {0, 0, 0, 9}, /* VQDMLSL */
6384
                    {0, 0, 0, 0}, /* Integer VMULL */
6385
                    {0, 0, 0, 1}, /* VQDMULL */
6386
                    {0, 0, 0, 0xa}, /* Polynomial VMULL */
6387
                    {0, 0, 0, 7}, /* Reserved: always UNDEF */
P
pbrook 已提交
6388 6389 6390 6391 6392
                };

                prewiden = neon_3reg_wide[op][0];
                src1_wide = neon_3reg_wide[op][1];
                src2_wide = neon_3reg_wide[op][2];
6393
                undefreq = neon_3reg_wide[op][3];
P
pbrook 已提交
6394

6395 6396
                if ((undefreq & (1 << size)) ||
                    ((undefreq & 8) && u)) {
6397 6398 6399 6400 6401
                    return 1;
                }
                if ((src1_wide && (rn & 1)) ||
                    (src2_wide && (rm & 1)) ||
                    (!src2_wide && (rd & 1))) {
P
pbrook 已提交
6402
                    return 1;
6403
                }
P
pbrook 已提交
6404

6405 6406 6407 6408 6409 6410
                /* Handle VMULL.P64 (Polynomial 64x64 to 128 bit multiply)
                 * outside the loop below as it only performs a single pass.
                 */
                if (op == 14 && size == 2) {
                    TCGv_i64 tcg_rn, tcg_rm, tcg_rd;

6411
                    if (!arm_dc_feature(s, ARM_FEATURE_V8_PMULL)) {
6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428
                        return 1;
                    }
                    tcg_rn = tcg_temp_new_i64();
                    tcg_rm = tcg_temp_new_i64();
                    tcg_rd = tcg_temp_new_i64();
                    neon_load_reg64(tcg_rn, rn);
                    neon_load_reg64(tcg_rm, rm);
                    gen_helper_neon_pmull_64_lo(tcg_rd, tcg_rn, tcg_rm);
                    neon_store_reg64(tcg_rd, rd);
                    gen_helper_neon_pmull_64_hi(tcg_rd, tcg_rn, tcg_rm);
                    neon_store_reg64(tcg_rd, rd + 1);
                    tcg_temp_free_i64(tcg_rn);
                    tcg_temp_free_i64(tcg_rm);
                    tcg_temp_free_i64(tcg_rd);
                    return 0;
                }

P
pbrook 已提交
6429 6430 6431
                /* Avoid overlapping operands.  Wide source operands are
                   always aligned so will never overlap with wide
                   destinations in problematic ways.  */
P
pbrook 已提交
6432
                if (rd == rm && !src2_wide) {
6433 6434
                    tmp = neon_load_reg(rm, 1);
                    neon_store_scratch(2, tmp);
P
pbrook 已提交
6435
                } else if (rd == rn && !src1_wide) {
6436 6437
                    tmp = neon_load_reg(rn, 1);
                    neon_store_scratch(2, tmp);
P
pbrook 已提交
6438
                }
6439
                TCGV_UNUSED_I32(tmp3);
P
pbrook 已提交
6440
                for (pass = 0; pass < 2; pass++) {
P
pbrook 已提交
6441 6442
                    if (src1_wide) {
                        neon_load_reg64(cpu_V0, rn + pass);
6443
                        TCGV_UNUSED_I32(tmp);
P
pbrook 已提交
6444
                    } else {
P
pbrook 已提交
6445
                        if (pass == 1 && rd == rn) {
6446
                            tmp = neon_load_scratch(2);
P
pbrook 已提交
6447
                        } else {
P
pbrook 已提交
6448 6449 6450 6451
                            tmp = neon_load_reg(rn, pass);
                        }
                        if (prewiden) {
                            gen_neon_widen(cpu_V0, tmp, size, u);
P
pbrook 已提交
6452 6453
                        }
                    }
P
pbrook 已提交
6454 6455
                    if (src2_wide) {
                        neon_load_reg64(cpu_V1, rm + pass);
6456
                        TCGV_UNUSED_I32(tmp2);
P
pbrook 已提交
6457
                    } else {
P
pbrook 已提交
6458
                        if (pass == 1 && rd == rm) {
6459
                            tmp2 = neon_load_scratch(2);
P
pbrook 已提交
6460
                        } else {
P
pbrook 已提交
6461 6462 6463 6464
                            tmp2 = neon_load_reg(rm, pass);
                        }
                        if (prewiden) {
                            gen_neon_widen(cpu_V1, tmp2, size, u);
P
pbrook 已提交
6465 6466 6467 6468
                        }
                    }
                    switch (op) {
                    case 0: case 1: case 4: /* VADDL, VADDW, VADDHN, VRADDHN */
P
pbrook 已提交
6469
                        gen_neon_addl(size);
P
pbrook 已提交
6470
                        break;
6471
                    case 2: case 3: case 6: /* VSUBL, VSUBW, VSUBHN, VRSUBHN */
P
pbrook 已提交
6472
                        gen_neon_subl(size);
P
pbrook 已提交
6473 6474 6475
                        break;
                    case 5: case 7: /* VABAL, VABDL */
                        switch ((size << 1) | u) {
P
pbrook 已提交
6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493
                        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 已提交
6494 6495
                        default: abort();
                        }
6496 6497
                        tcg_temp_free_i32(tmp2);
                        tcg_temp_free_i32(tmp);
P
pbrook 已提交
6498 6499 6500
                        break;
                    case 8: case 9: case 10: case 11: case 12: case 13:
                        /* VMLAL, VQDMLAL, VMLSL, VQDMLSL, VMULL, VQDMULL */
P
pbrook 已提交
6501
                        gen_neon_mull(cpu_V0, tmp, tmp2, size, u);
P
pbrook 已提交
6502 6503
                        break;
                    case 14: /* Polynomial VMULL */
P
Peter Maydell 已提交
6504
                        gen_helper_neon_mull_p8(cpu_V0, tmp, tmp2);
6505 6506
                        tcg_temp_free_i32(tmp2);
                        tcg_temp_free_i32(tmp);
P
Peter Maydell 已提交
6507
                        break;
6508 6509
                    default: /* 15 is RESERVED: caught earlier  */
                        abort();
P
pbrook 已提交
6510
                    }
6511 6512 6513 6514 6515
                    if (op == 13) {
                        /* VQDMULL */
                        gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
                        neon_store_reg64(cpu_V0, rd + pass);
                    } else if (op == 5 || (op >= 8 && op <= 11)) {
P
pbrook 已提交
6516
                        /* Accumulate.  */
6517
                        neon_load_reg64(cpu_V1, rd + pass);
P
pbrook 已提交
6518
                        switch (op) {
6519 6520 6521 6522
                        case 10: /* VMLSL */
                            gen_neon_negl(cpu_V0, size);
                            /* Fall through */
                        case 5: case 8: /* VABAL, VMLAL */
P
pbrook 已提交
6523
                            gen_neon_addl(size);
P
pbrook 已提交
6524 6525
                            break;
                        case 9: case 11: /* VQDMLAL, VQDMLSL */
P
pbrook 已提交
6526
                            gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
6527 6528 6529
                            if (op == 11) {
                                gen_neon_negl(cpu_V0, size);
                            }
P
pbrook 已提交
6530 6531
                            gen_neon_addl_saturate(cpu_V0, cpu_V1, size);
                            break;
P
pbrook 已提交
6532 6533 6534
                        default:
                            abort();
                        }
P
pbrook 已提交
6535
                        neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
6536 6537
                    } else if (op == 4 || op == 6) {
                        /* Narrowing operation.  */
6538
                        tmp = tcg_temp_new_i32();
6539
                        if (!u) {
P
pbrook 已提交
6540
                            switch (size) {
P
pbrook 已提交
6541 6542 6543 6544 6545 6546 6547 6548
                            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);
6549
                                tcg_gen_extrl_i64_i32(tmp, cpu_V0);
P
pbrook 已提交
6550
                                break;
P
pbrook 已提交
6551 6552 6553 6554
                            default: abort();
                            }
                        } else {
                            switch (size) {
P
pbrook 已提交
6555 6556 6557 6558 6559 6560 6561 6562 6563
                            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);
6564
                                tcg_gen_extrl_i64_i32(tmp, cpu_V0);
P
pbrook 已提交
6565
                                break;
P
pbrook 已提交
6566 6567 6568
                            default: abort();
                            }
                        }
P
pbrook 已提交
6569 6570 6571 6572 6573 6574
                        if (pass == 0) {
                            tmp3 = tmp;
                        } else {
                            neon_store_reg(rd, 0, tmp3);
                            neon_store_reg(rd, 1, tmp);
                        }
P
pbrook 已提交
6575 6576
                    } else {
                        /* Write back the result.  */
P
pbrook 已提交
6577
                        neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
6578 6579 6580
                    }
                }
            } else {
6581 6582 6583 6584 6585 6586 6587
                /* Two registers and a scalar. NB that for ops of this form
                 * the ARM ARM labels bit 24 as Q, but it is in our variable
                 * 'u', not 'q'.
                 */
                if (size == 0) {
                    return 1;
                }
P
pbrook 已提交
6588 6589 6590 6591
                switch (op) {
                case 1: /* Float VMLA scalar */
                case 5: /* Floating point VMLS scalar */
                case 9: /* Floating point VMUL scalar */
6592 6593 6594 6595 6596 6597 6598
                    if (size == 1) {
                        return 1;
                    }
                    /* fall through */
                case 0: /* Integer VMLA scalar */
                case 4: /* Integer VMLS scalar */
                case 8: /* Integer VMUL scalar */
P
pbrook 已提交
6599 6600
                case 12: /* VQDMULH scalar */
                case 13: /* VQRDMULH scalar */
6601 6602 6603
                    if (u && ((rd | rn) & 1)) {
                        return 1;
                    }
6604 6605
                    tmp = neon_get_scalar(size, rm);
                    neon_store_scratch(0, tmp);
P
pbrook 已提交
6606
                    for (pass = 0; pass < (u ? 4 : 2); pass++) {
6607 6608
                        tmp = neon_load_scratch(0);
                        tmp2 = neon_load_reg(rn, pass);
P
pbrook 已提交
6609 6610
                        if (op == 12) {
                            if (size == 1) {
6611
                                gen_helper_neon_qdmulh_s16(tmp, cpu_env, tmp, tmp2);
P
pbrook 已提交
6612
                            } else {
6613
                                gen_helper_neon_qdmulh_s32(tmp, cpu_env, tmp, tmp2);
P
pbrook 已提交
6614 6615 6616
                            }
                        } else if (op == 13) {
                            if (size == 1) {
6617
                                gen_helper_neon_qrdmulh_s16(tmp, cpu_env, tmp, tmp2);
P
pbrook 已提交
6618
                            } else {
6619
                                gen_helper_neon_qrdmulh_s32(tmp, cpu_env, tmp, tmp2);
P
pbrook 已提交
6620 6621
                            }
                        } else if (op & 1) {
6622 6623 6624
                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
                            gen_helper_vfp_muls(tmp, tmp, tmp2, fpstatus);
                            tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
6625 6626
                        } else {
                            switch (size) {
6627 6628 6629
                            case 0: gen_helper_neon_mul_u8(tmp, tmp, tmp2); break;
                            case 1: gen_helper_neon_mul_u16(tmp, tmp, tmp2); break;
                            case 2: tcg_gen_mul_i32(tmp, tmp, tmp2); break;
6630
                            default: abort();
P
pbrook 已提交
6631 6632
                            }
                        }
6633
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
6634 6635
                        if (op < 8) {
                            /* Accumulate.  */
6636
                            tmp2 = neon_load_reg(rd, pass);
P
pbrook 已提交
6637 6638
                            switch (op) {
                            case 0:
6639
                                gen_neon_add(size, tmp, tmp2);
P
pbrook 已提交
6640 6641
                                break;
                            case 1:
6642 6643 6644 6645
                            {
                                TCGv_ptr fpstatus = get_fpstatus_ptr(1);
                                gen_helper_vfp_adds(tmp, tmp, tmp2, fpstatus);
                                tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
6646
                                break;
6647
                            }
P
pbrook 已提交
6648
                            case 4:
6649
                                gen_neon_rsb(size, tmp, tmp2);
P
pbrook 已提交
6650 6651
                                break;
                            case 5:
6652 6653 6654 6655
                            {
                                TCGv_ptr fpstatus = get_fpstatus_ptr(1);
                                gen_helper_vfp_subs(tmp, tmp2, tmp, fpstatus);
                                tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
6656
                                break;
6657
                            }
P
pbrook 已提交
6658 6659 6660
                            default:
                                abort();
                            }
6661
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
6662
                        }
6663
                        neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
6664 6665 6666 6667 6668
                    }
                    break;
                case 3: /* VQDMLAL scalar */
                case 7: /* VQDMLSL scalar */
                case 11: /* VQDMULL scalar */
6669
                    if (u == 1) {
P
pbrook 已提交
6670
                        return 1;
6671 6672 6673 6674 6675 6676 6677 6678
                    }
                    /* fall through */
                case 2: /* VMLAL sclar */
                case 6: /* VMLSL scalar */
                case 10: /* VMULL scalar */
                    if (rd & 1) {
                        return 1;
                    }
6679
                    tmp2 = neon_get_scalar(size, rm);
6680 6681
                    /* We need a copy of tmp2 because gen_neon_mull
                     * deletes it during pass 0.  */
6682
                    tmp4 = tcg_temp_new_i32();
6683
                    tcg_gen_mov_i32(tmp4, tmp2);
6684
                    tmp3 = neon_load_reg(rn, 1);
P
pbrook 已提交
6685

P
pbrook 已提交
6686
                    for (pass = 0; pass < 2; pass++) {
P
pbrook 已提交
6687 6688
                        if (pass == 0) {
                            tmp = neon_load_reg(rn, 0);
P
pbrook 已提交
6689
                        } else {
6690
                            tmp = tmp3;
6691
                            tmp2 = tmp4;
P
pbrook 已提交
6692
                        }
P
pbrook 已提交
6693 6694 6695
                        gen_neon_mull(cpu_V0, tmp, tmp2, size, u);
                        if (op != 11) {
                            neon_load_reg64(cpu_V1, rd + pass);
P
pbrook 已提交
6696 6697
                        }
                        switch (op) {
6698 6699 6700 6701
                        case 6:
                            gen_neon_negl(cpu_V0, size);
                            /* Fall through */
                        case 2:
P
pbrook 已提交
6702
                            gen_neon_addl(size);
P
pbrook 已提交
6703 6704
                            break;
                        case 3: case 7:
P
pbrook 已提交
6705
                            gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
6706 6707 6708
                            if (op == 7) {
                                gen_neon_negl(cpu_V0, size);
                            }
P
pbrook 已提交
6709
                            gen_neon_addl_saturate(cpu_V0, cpu_V1, size);
P
pbrook 已提交
6710 6711 6712 6713 6714
                            break;
                        case 10:
                            /* no-op */
                            break;
                        case 11:
P
pbrook 已提交
6715
                            gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
P
pbrook 已提交
6716 6717 6718 6719
                            break;
                        default:
                            abort();
                        }
P
pbrook 已提交
6720
                        neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
6721
                    }
6722 6723


P
pbrook 已提交
6724 6725 6726 6727 6728 6729 6730 6731 6732
                    break;
                default: /* 14 and 15 are RESERVED */
                    return 1;
                }
            }
        } else { /* size == 3 */
            if (!u) {
                /* Extract.  */
                imm = (insn >> 8) & 0xf;
P
pbrook 已提交
6733 6734 6735 6736

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

6737 6738 6739 6740
                if (q && ((rd | rn | rm) & 1)) {
                    return 1;
                }

P
pbrook 已提交
6741 6742 6743 6744
                if (imm == 0) {
                    neon_load_reg64(cpu_V0, rn);
                    if (q) {
                        neon_load_reg64(cpu_V1, rn + 1);
P
pbrook 已提交
6745
                    }
P
pbrook 已提交
6746 6747 6748 6749
                } else if (imm == 8) {
                    neon_load_reg64(cpu_V0, rn + 1);
                    if (q) {
                        neon_load_reg64(cpu_V1, rm);
P
pbrook 已提交
6750
                    }
P
pbrook 已提交
6751
                } else if (q) {
P
pbrook 已提交
6752
                    tmp64 = tcg_temp_new_i64();
P
pbrook 已提交
6753 6754
                    if (imm < 8) {
                        neon_load_reg64(cpu_V0, rn);
P
pbrook 已提交
6755
                        neon_load_reg64(tmp64, rn + 1);
P
pbrook 已提交
6756 6757
                    } else {
                        neon_load_reg64(cpu_V0, rn + 1);
P
pbrook 已提交
6758
                        neon_load_reg64(tmp64, rm);
P
pbrook 已提交
6759 6760
                    }
                    tcg_gen_shri_i64(cpu_V0, cpu_V0, (imm & 7) * 8);
P
pbrook 已提交
6761
                    tcg_gen_shli_i64(cpu_V1, tmp64, 64 - ((imm & 7) * 8));
P
pbrook 已提交
6762 6763 6764
                    tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1);
                    if (imm < 8) {
                        neon_load_reg64(cpu_V1, rm);
P
pbrook 已提交
6765
                    } else {
P
pbrook 已提交
6766 6767
                        neon_load_reg64(cpu_V1, rm + 1);
                        imm -= 8;
P
pbrook 已提交
6768
                    }
P
pbrook 已提交
6769
                    tcg_gen_shli_i64(cpu_V1, cpu_V1, 64 - (imm * 8));
P
pbrook 已提交
6770 6771
                    tcg_gen_shri_i64(tmp64, tmp64, imm * 8);
                    tcg_gen_or_i64(cpu_V1, cpu_V1, tmp64);
6772
                    tcg_temp_free_i64(tmp64);
P
pbrook 已提交
6773
                } else {
P
pbrook 已提交
6774
                    /* BUGFIX */
P
pbrook 已提交
6775
                    neon_load_reg64(cpu_V0, rn);
P
pbrook 已提交
6776
                    tcg_gen_shri_i64(cpu_V0, cpu_V0, imm * 8);
P
pbrook 已提交
6777
                    neon_load_reg64(cpu_V1, rm);
P
pbrook 已提交
6778
                    tcg_gen_shli_i64(cpu_V1, cpu_V1, 64 - (imm * 8));
P
pbrook 已提交
6779 6780 6781 6782 6783
                    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 已提交
6784 6785 6786 6787 6788
                }
            } else if ((insn & (1 << 11)) == 0) {
                /* Two register misc.  */
                op = ((insn >> 12) & 0x30) | ((insn >> 7) & 0xf);
                size = (insn >> 18) & 3;
6789 6790 6791 6792
                /* UNDEF for unknown op values and bad op-size combinations */
                if ((neon_2rm_sizes[op] & (1 << size)) == 0) {
                    return 1;
                }
6793 6794 6795 6796
                if (neon_2rm_is_v8_op(op) &&
                    !arm_dc_feature(s, ARM_FEATURE_V8)) {
                    return 1;
                }
6797 6798 6799 6800
                if ((op != NEON_2RM_VMOVN && op != NEON_2RM_VQMOVN) &&
                    q && ((rm | rd) & 1)) {
                    return 1;
                }
P
pbrook 已提交
6801
                switch (op) {
6802
                case NEON_2RM_VREV64:
P
pbrook 已提交
6803
                    for (pass = 0; pass < (q ? 2 : 1); pass++) {
6804 6805
                        tmp = neon_load_reg(rm, pass * 2);
                        tmp2 = neon_load_reg(rm, pass * 2 + 1);
P
pbrook 已提交
6806
                        switch (size) {
6807 6808
                        case 0: tcg_gen_bswap32_i32(tmp, tmp); break;
                        case 1: gen_swap_half(tmp); break;
P
pbrook 已提交
6809 6810 6811
                        case 2: /* no-op */ break;
                        default: abort();
                        }
6812
                        neon_store_reg(rd, pass * 2 + 1, tmp);
P
pbrook 已提交
6813
                        if (size == 2) {
6814
                            neon_store_reg(rd, pass * 2, tmp2);
P
pbrook 已提交
6815 6816
                        } else {
                            switch (size) {
6817 6818
                            case 0: tcg_gen_bswap32_i32(tmp2, tmp2); break;
                            case 1: gen_swap_half(tmp2); break;
P
pbrook 已提交
6819 6820
                            default: abort();
                            }
6821
                            neon_store_reg(rd, pass * 2, tmp2);
P
pbrook 已提交
6822 6823 6824
                        }
                    }
                    break;
6825 6826
                case NEON_2RM_VPADDL: case NEON_2RM_VPADDL_U:
                case NEON_2RM_VPADAL: case NEON_2RM_VPADAL_U:
P
pbrook 已提交
6827 6828 6829 6830 6831 6832 6833 6834 6835 6836 6837
                    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();
                        }
6838
                        if (op >= NEON_2RM_VPADAL) {
P
pbrook 已提交
6839
                            /* Accumulate.  */
P
pbrook 已提交
6840 6841
                            neon_load_reg64(cpu_V1, rd + pass);
                            gen_neon_addl(size);
P
pbrook 已提交
6842
                        }
P
pbrook 已提交
6843
                        neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
6844 6845
                    }
                    break;
6846
                case NEON_2RM_VTRN:
P
pbrook 已提交
6847
                    if (size == 2) {
6848
                        int n;
P
pbrook 已提交
6849
                        for (n = 0; n < (q ? 4 : 2); n += 2) {
6850 6851 6852 6853
                            tmp = neon_load_reg(rm, n);
                            tmp2 = neon_load_reg(rd, n + 1);
                            neon_store_reg(rm, n, tmp2);
                            neon_store_reg(rd, n + 1, tmp);
P
pbrook 已提交
6854 6855 6856 6857 6858
                        }
                    } else {
                        goto elementwise;
                    }
                    break;
6859
                case NEON_2RM_VUZP:
6860
                    if (gen_neon_unzip(rd, rm, size, q)) {
P
pbrook 已提交
6861 6862 6863
                        return 1;
                    }
                    break;
6864
                case NEON_2RM_VZIP:
6865
                    if (gen_neon_zip(rd, rm, size, q)) {
P
pbrook 已提交
6866 6867 6868
                        return 1;
                    }
                    break;
6869 6870
                case NEON_2RM_VMOVN: case NEON_2RM_VQMOVN:
                    /* also VQMOVUN; op field and mnemonics don't line up */
6871 6872 6873
                    if (rm & 1) {
                        return 1;
                    }
6874
                    TCGV_UNUSED_I32(tmp2);
P
pbrook 已提交
6875
                    for (pass = 0; pass < 2; pass++) {
P
pbrook 已提交
6876
                        neon_load_reg64(cpu_V0, rm + pass);
6877
                        tmp = tcg_temp_new_i32();
6878 6879
                        gen_neon_narrow_op(op == NEON_2RM_VMOVN, q, size,
                                           tmp, cpu_V0);
P
pbrook 已提交
6880 6881 6882 6883 6884
                        if (pass == 0) {
                            tmp2 = tmp;
                        } else {
                            neon_store_reg(rd, 0, tmp2);
                            neon_store_reg(rd, 1, tmp);
P
pbrook 已提交
6885 6886 6887
                        }
                    }
                    break;
6888
                case NEON_2RM_VSHLL:
6889
                    if (q || (rd & 1)) {
P
pbrook 已提交
6890
                        return 1;
6891
                    }
P
pbrook 已提交
6892 6893
                    tmp = neon_load_reg(rm, 0);
                    tmp2 = neon_load_reg(rm, 1);
P
pbrook 已提交
6894
                    for (pass = 0; pass < 2; pass++) {
P
pbrook 已提交
6895 6896 6897
                        if (pass == 1)
                            tmp = tmp2;
                        gen_neon_widen(cpu_V0, tmp, size, 1);
6898
                        tcg_gen_shli_i64(cpu_V0, cpu_V0, 8 << size);
P
pbrook 已提交
6899
                        neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
6900 6901
                    }
                    break;
6902
                case NEON_2RM_VCVT_F16_F32:
6903
                    if (!arm_dc_feature(s, ARM_FEATURE_VFP_FP16) ||
6904 6905 6906
                        q || (rm & 1)) {
                        return 1;
                    }
6907 6908
                    tmp = tcg_temp_new_i32();
                    tmp2 = tcg_temp_new_i32();
P
Paul Brook 已提交
6909
                    tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 0));
6910
                    gen_helper_neon_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
P
Paul Brook 已提交
6911
                    tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 1));
6912
                    gen_helper_neon_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env);
P
Paul Brook 已提交
6913 6914 6915
                    tcg_gen_shli_i32(tmp2, tmp2, 16);
                    tcg_gen_or_i32(tmp2, tmp2, tmp);
                    tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 2));
6916
                    gen_helper_neon_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
P
Paul Brook 已提交
6917 6918
                    tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 3));
                    neon_store_reg(rd, 0, tmp2);
6919
                    tmp2 = tcg_temp_new_i32();
6920
                    gen_helper_neon_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env);
P
Paul Brook 已提交
6921 6922 6923
                    tcg_gen_shli_i32(tmp2, tmp2, 16);
                    tcg_gen_or_i32(tmp2, tmp2, tmp);
                    neon_store_reg(rd, 1, tmp2);
6924
                    tcg_temp_free_i32(tmp);
P
Paul Brook 已提交
6925
                    break;
6926
                case NEON_2RM_VCVT_F32_F16:
6927
                    if (!arm_dc_feature(s, ARM_FEATURE_VFP_FP16) ||
6928 6929 6930
                        q || (rd & 1)) {
                        return 1;
                    }
6931
                    tmp3 = tcg_temp_new_i32();
P
Paul Brook 已提交
6932 6933 6934
                    tmp = neon_load_reg(rm, 0);
                    tmp2 = neon_load_reg(rm, 1);
                    tcg_gen_ext16u_i32(tmp3, tmp);
6935
                    gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
P
Paul Brook 已提交
6936 6937
                    tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 0));
                    tcg_gen_shri_i32(tmp3, tmp, 16);
6938
                    gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
P
Paul Brook 已提交
6939
                    tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 1));
6940
                    tcg_temp_free_i32(tmp);
P
Paul Brook 已提交
6941
                    tcg_gen_ext16u_i32(tmp3, tmp2);
6942
                    gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
P
Paul Brook 已提交
6943 6944
                    tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 2));
                    tcg_gen_shri_i32(tmp3, tmp2, 16);
6945
                    gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
P
Paul Brook 已提交
6946
                    tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 3));
6947 6948
                    tcg_temp_free_i32(tmp2);
                    tcg_temp_free_i32(tmp3);
P
Paul Brook 已提交
6949
                    break;
6950
                case NEON_2RM_AESE: case NEON_2RM_AESMC:
6951
                    if (!arm_dc_feature(s, ARM_FEATURE_V8_AES)
6952 6953 6954 6955 6956 6957 6958 6959 6960 6961 6962 6963 6964 6965 6966 6967 6968 6969 6970 6971
                        || ((rm | rd) & 1)) {
                        return 1;
                    }
                    tmp = tcg_const_i32(rd);
                    tmp2 = tcg_const_i32(rm);

                     /* Bit 6 is the lowest opcode bit; it distinguishes between
                      * encryption (AESE/AESMC) and decryption (AESD/AESIMC)
                      */
                    tmp3 = tcg_const_i32(extract32(insn, 6, 1));

                    if (op == NEON_2RM_AESE) {
                        gen_helper_crypto_aese(cpu_env, tmp, tmp2, tmp3);
                    } else {
                        gen_helper_crypto_aesmc(cpu_env, tmp, tmp2, tmp3);
                    }
                    tcg_temp_free_i32(tmp);
                    tcg_temp_free_i32(tmp2);
                    tcg_temp_free_i32(tmp3);
                    break;
6972
                case NEON_2RM_SHA1H:
6973
                    if (!arm_dc_feature(s, ARM_FEATURE_V8_SHA1)
6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 6987 6988 6989 6990
                        || ((rm | rd) & 1)) {
                        return 1;
                    }
                    tmp = tcg_const_i32(rd);
                    tmp2 = tcg_const_i32(rm);

                    gen_helper_crypto_sha1h(cpu_env, tmp, tmp2);

                    tcg_temp_free_i32(tmp);
                    tcg_temp_free_i32(tmp2);
                    break;
                case NEON_2RM_SHA1SU1:
                    if ((rm | rd) & 1) {
                            return 1;
                    }
                    /* bit 6 (q): set -> SHA256SU0, cleared -> SHA1SU1 */
                    if (q) {
6991
                        if (!arm_dc_feature(s, ARM_FEATURE_V8_SHA256)) {
6992 6993
                            return 1;
                        }
6994
                    } else if (!arm_dc_feature(s, ARM_FEATURE_V8_SHA1)) {
6995 6996 6997 6998 6999 7000 7001 7002 7003 7004 7005 7006
                        return 1;
                    }
                    tmp = tcg_const_i32(rd);
                    tmp2 = tcg_const_i32(rm);
                    if (q) {
                        gen_helper_crypto_sha256su0(cpu_env, tmp, tmp2);
                    } else {
                        gen_helper_crypto_sha1su1(cpu_env, tmp, tmp2);
                    }
                    tcg_temp_free_i32(tmp);
                    tcg_temp_free_i32(tmp2);
                    break;
P
pbrook 已提交
7007 7008 7009
                default:
                elementwise:
                    for (pass = 0; pass < (q ? 4 : 2); pass++) {
7010
                        if (neon_2rm_is_float_op(op)) {
P
pbrook 已提交
7011 7012
                            tcg_gen_ld_f32(cpu_F0s, cpu_env,
                                           neon_reg_offset(rm, pass));
7013
                            TCGV_UNUSED_I32(tmp);
P
pbrook 已提交
7014
                        } else {
7015
                            tmp = neon_load_reg(rm, pass);
P
pbrook 已提交
7016 7017
                        }
                        switch (op) {
7018
                        case NEON_2RM_VREV32:
P
pbrook 已提交
7019
                            switch (size) {
7020 7021
                            case 0: tcg_gen_bswap32_i32(tmp, tmp); break;
                            case 1: gen_swap_half(tmp); break;
7022
                            default: abort();
P
pbrook 已提交
7023 7024
                            }
                            break;
7025
                        case NEON_2RM_VREV16:
7026
                            gen_rev16(tmp);
P
pbrook 已提交
7027
                            break;
7028
                        case NEON_2RM_VCLS:
P
pbrook 已提交
7029
                            switch (size) {
7030 7031 7032
                            case 0: gen_helper_neon_cls_s8(tmp, tmp); break;
                            case 1: gen_helper_neon_cls_s16(tmp, tmp); break;
                            case 2: gen_helper_neon_cls_s32(tmp, tmp); break;
7033
                            default: abort();
P
pbrook 已提交
7034 7035
                            }
                            break;
7036
                        case NEON_2RM_VCLZ:
P
pbrook 已提交
7037
                            switch (size) {
7038 7039
                            case 0: gen_helper_neon_clz_u8(tmp, tmp); break;
                            case 1: gen_helper_neon_clz_u16(tmp, tmp); break;
R
Richard Henderson 已提交
7040
                            case 2: tcg_gen_clzi_i32(tmp, tmp, 32); break;
7041
                            default: abort();
P
pbrook 已提交
7042 7043
                            }
                            break;
7044
                        case NEON_2RM_VCNT:
7045
                            gen_helper_neon_cnt_u8(tmp, tmp);
P
pbrook 已提交
7046
                            break;
7047
                        case NEON_2RM_VMVN:
7048
                            tcg_gen_not_i32(tmp, tmp);
P
pbrook 已提交
7049
                            break;
7050
                        case NEON_2RM_VQABS:
P
pbrook 已提交
7051
                            switch (size) {
7052 7053 7054 7055 7056 7057 7058 7059 7060
                            case 0:
                                gen_helper_neon_qabs_s8(tmp, cpu_env, tmp);
                                break;
                            case 1:
                                gen_helper_neon_qabs_s16(tmp, cpu_env, tmp);
                                break;
                            case 2:
                                gen_helper_neon_qabs_s32(tmp, cpu_env, tmp);
                                break;
7061
                            default: abort();
P
pbrook 已提交
7062 7063
                            }
                            break;
7064
                        case NEON_2RM_VQNEG:
P
pbrook 已提交
7065
                            switch (size) {
7066 7067 7068 7069 7070 7071 7072 7073 7074
                            case 0:
                                gen_helper_neon_qneg_s8(tmp, cpu_env, tmp);
                                break;
                            case 1:
                                gen_helper_neon_qneg_s16(tmp, cpu_env, tmp);
                                break;
                            case 2:
                                gen_helper_neon_qneg_s32(tmp, cpu_env, tmp);
                                break;
7075
                            default: abort();
P
pbrook 已提交
7076 7077
                            }
                            break;
7078
                        case NEON_2RM_VCGT0: case NEON_2RM_VCLE0:
7079
                            tmp2 = tcg_const_i32(0);
P
pbrook 已提交
7080
                            switch(size) {
7081 7082 7083
                            case 0: gen_helper_neon_cgt_s8(tmp, tmp, tmp2); break;
                            case 1: gen_helper_neon_cgt_s16(tmp, tmp, tmp2); break;
                            case 2: gen_helper_neon_cgt_s32(tmp, tmp, tmp2); break;
7084
                            default: abort();
P
pbrook 已提交
7085
                            }
7086
                            tcg_temp_free_i32(tmp2);
7087
                            if (op == NEON_2RM_VCLE0) {
7088
                                tcg_gen_not_i32(tmp, tmp);
7089
                            }
P
pbrook 已提交
7090
                            break;
7091
                        case NEON_2RM_VCGE0: case NEON_2RM_VCLT0:
7092
                            tmp2 = tcg_const_i32(0);
P
pbrook 已提交
7093
                            switch(size) {
7094 7095 7096
                            case 0: gen_helper_neon_cge_s8(tmp, tmp, tmp2); break;
                            case 1: gen_helper_neon_cge_s16(tmp, tmp, tmp2); break;
                            case 2: gen_helper_neon_cge_s32(tmp, tmp, tmp2); break;
7097
                            default: abort();
P
pbrook 已提交
7098
                            }
7099
                            tcg_temp_free_i32(tmp2);
7100
                            if (op == NEON_2RM_VCLT0) {
7101
                                tcg_gen_not_i32(tmp, tmp);
7102
                            }
P
pbrook 已提交
7103
                            break;
7104
                        case NEON_2RM_VCEQ0:
7105
                            tmp2 = tcg_const_i32(0);
P
pbrook 已提交
7106
                            switch(size) {
7107 7108 7109
                            case 0: gen_helper_neon_ceq_u8(tmp, tmp, tmp2); break;
                            case 1: gen_helper_neon_ceq_u16(tmp, tmp, tmp2); break;
                            case 2: gen_helper_neon_ceq_u32(tmp, tmp, tmp2); break;
7110
                            default: abort();
P
pbrook 已提交
7111
                            }
7112
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
7113
                            break;
7114
                        case NEON_2RM_VABS:
P
pbrook 已提交
7115
                            switch(size) {
7116 7117 7118
                            case 0: gen_helper_neon_abs_s8(tmp, tmp); break;
                            case 1: gen_helper_neon_abs_s16(tmp, tmp); break;
                            case 2: tcg_gen_abs_i32(tmp, tmp); break;
7119
                            default: abort();
P
pbrook 已提交
7120 7121
                            }
                            break;
7122
                        case NEON_2RM_VNEG:
7123 7124
                            tmp2 = tcg_const_i32(0);
                            gen_neon_rsb(size, tmp, tmp2);
7125
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
7126
                            break;
7127
                        case NEON_2RM_VCGT0_F:
7128 7129
                        {
                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
7130
                            tmp2 = tcg_const_i32(0);
7131
                            gen_helper_neon_cgt_f32(tmp, tmp, tmp2, fpstatus);
7132
                            tcg_temp_free_i32(tmp2);
7133
                            tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
7134
                            break;
7135
                        }
7136
                        case NEON_2RM_VCGE0_F:
7137 7138
                        {
                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
7139
                            tmp2 = tcg_const_i32(0);
7140
                            gen_helper_neon_cge_f32(tmp, tmp, tmp2, fpstatus);
7141
                            tcg_temp_free_i32(tmp2);
7142
                            tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
7143
                            break;
7144
                        }
7145
                        case NEON_2RM_VCEQ0_F:
7146 7147
                        {
                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
7148
                            tmp2 = tcg_const_i32(0);
7149
                            gen_helper_neon_ceq_f32(tmp, tmp, tmp2, fpstatus);
7150
                            tcg_temp_free_i32(tmp2);
7151
                            tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
7152
                            break;
7153
                        }
7154
                        case NEON_2RM_VCLE0_F:
7155 7156
                        {
                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
7157
                            tmp2 = tcg_const_i32(0);
7158
                            gen_helper_neon_cge_f32(tmp, tmp2, tmp, fpstatus);
7159
                            tcg_temp_free_i32(tmp2);
7160
                            tcg_temp_free_ptr(fpstatus);
7161
                            break;
7162
                        }
7163
                        case NEON_2RM_VCLT0_F:
7164 7165
                        {
                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
7166
                            tmp2 = tcg_const_i32(0);
7167
                            gen_helper_neon_cgt_f32(tmp, tmp2, tmp, fpstatus);
7168
                            tcg_temp_free_i32(tmp2);
7169
                            tcg_temp_free_ptr(fpstatus);
7170
                            break;
7171
                        }
7172
                        case NEON_2RM_VABS_F:
P
pbrook 已提交
7173
                            gen_vfp_abs(0);
P
pbrook 已提交
7174
                            break;
7175
                        case NEON_2RM_VNEG_F:
P
pbrook 已提交
7176
                            gen_vfp_neg(0);
P
pbrook 已提交
7177
                            break;
7178
                        case NEON_2RM_VSWP:
7179 7180
                            tmp2 = neon_load_reg(rd, pass);
                            neon_store_reg(rm, pass, tmp2);
P
pbrook 已提交
7181
                            break;
7182
                        case NEON_2RM_VTRN:
7183
                            tmp2 = neon_load_reg(rd, pass);
P
pbrook 已提交
7184
                            switch (size) {
7185 7186
                            case 0: gen_neon_trn_u8(tmp, tmp2); break;
                            case 1: gen_neon_trn_u16(tmp, tmp2); break;
7187
                            default: abort();
P
pbrook 已提交
7188
                            }
7189
                            neon_store_reg(rm, pass, tmp2);
P
pbrook 已提交
7190
                            break;
7191 7192 7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212 7213 7214 7215 7216
                        case NEON_2RM_VRINTN:
                        case NEON_2RM_VRINTA:
                        case NEON_2RM_VRINTM:
                        case NEON_2RM_VRINTP:
                        case NEON_2RM_VRINTZ:
                        {
                            TCGv_i32 tcg_rmode;
                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
                            int rmode;

                            if (op == NEON_2RM_VRINTZ) {
                                rmode = FPROUNDING_ZERO;
                            } else {
                                rmode = fp_decode_rm[((op & 0x6) >> 1) ^ 1];
                            }

                            tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rmode));
                            gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode,
                                                      cpu_env);
                            gen_helper_rints(cpu_F0s, cpu_F0s, fpstatus);
                            gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode,
                                                      cpu_env);
                            tcg_temp_free_ptr(fpstatus);
                            tcg_temp_free_i32(tcg_rmode);
                            break;
                        }
7217 7218 7219 7220 7221 7222 7223
                        case NEON_2RM_VRINTX:
                        {
                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
                            gen_helper_rints_exact(cpu_F0s, cpu_F0s, fpstatus);
                            tcg_temp_free_ptr(fpstatus);
                            break;
                        }
7224 7225 7226 7227 7228 7229 7230 7231 7232 7233 7234 7235 7236 7237 7238 7239 7240 7241 7242 7243 7244 7245 7246 7247 7248 7249 7250 7251 7252 7253 7254 7255 7256 7257
                        case NEON_2RM_VCVTAU:
                        case NEON_2RM_VCVTAS:
                        case NEON_2RM_VCVTNU:
                        case NEON_2RM_VCVTNS:
                        case NEON_2RM_VCVTPU:
                        case NEON_2RM_VCVTPS:
                        case NEON_2RM_VCVTMU:
                        case NEON_2RM_VCVTMS:
                        {
                            bool is_signed = !extract32(insn, 7, 1);
                            TCGv_ptr fpst = get_fpstatus_ptr(1);
                            TCGv_i32 tcg_rmode, tcg_shift;
                            int rmode = fp_decode_rm[extract32(insn, 8, 2)];

                            tcg_shift = tcg_const_i32(0);
                            tcg_rmode = tcg_const_i32(arm_rmode_to_sf(rmode));
                            gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode,
                                                      cpu_env);

                            if (is_signed) {
                                gen_helper_vfp_tosls(cpu_F0s, cpu_F0s,
                                                     tcg_shift, fpst);
                            } else {
                                gen_helper_vfp_touls(cpu_F0s, cpu_F0s,
                                                     tcg_shift, fpst);
                            }

                            gen_helper_set_neon_rmode(tcg_rmode, tcg_rmode,
                                                      cpu_env);
                            tcg_temp_free_i32(tcg_rmode);
                            tcg_temp_free_i32(tcg_shift);
                            tcg_temp_free_ptr(fpst);
                            break;
                        }
7258
                        case NEON_2RM_VRECPE:
7259 7260 7261 7262
                        {
                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
                            gen_helper_recpe_u32(tmp, tmp, fpstatus);
                            tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
7263
                            break;
7264
                        }
7265
                        case NEON_2RM_VRSQRTE:
7266 7267 7268 7269
                        {
                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
                            gen_helper_rsqrte_u32(tmp, tmp, fpstatus);
                            tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
7270
                            break;
7271
                        }
7272
                        case NEON_2RM_VRECPE_F:
7273 7274 7275 7276
                        {
                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
                            gen_helper_recpe_f32(cpu_F0s, cpu_F0s, fpstatus);
                            tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
7277
                            break;
7278
                        }
7279
                        case NEON_2RM_VRSQRTE_F:
7280 7281 7282 7283
                        {
                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
                            gen_helper_rsqrte_f32(cpu_F0s, cpu_F0s, fpstatus);
                            tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
7284
                            break;
7285
                        }
7286
                        case NEON_2RM_VCVT_FS: /* VCVT.F32.S32 */
7287
                            gen_vfp_sito(0, 1);
P
pbrook 已提交
7288
                            break;
7289
                        case NEON_2RM_VCVT_FU: /* VCVT.F32.U32 */
7290
                            gen_vfp_uito(0, 1);
P
pbrook 已提交
7291
                            break;
7292
                        case NEON_2RM_VCVT_SF: /* VCVT.S32.F32 */
7293
                            gen_vfp_tosiz(0, 1);
P
pbrook 已提交
7294
                            break;
7295
                        case NEON_2RM_VCVT_UF: /* VCVT.U32.F32 */
7296
                            gen_vfp_touiz(0, 1);
P
pbrook 已提交
7297 7298
                            break;
                        default:
7299 7300 7301 7302
                            /* Reserved op values were caught by the
                             * neon_2rm_sizes[] check earlier.
                             */
                            abort();
P
pbrook 已提交
7303
                        }
7304
                        if (neon_2rm_is_float_op(op)) {
P
pbrook 已提交
7305 7306
                            tcg_gen_st_f32(cpu_F0s, cpu_env,
                                           neon_reg_offset(rd, pass));
P
pbrook 已提交
7307
                        } else {
7308
                            neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
7309 7310 7311 7312 7313 7314
                        }
                    }
                    break;
                }
            } else if ((insn & (1 << 10)) == 0) {
                /* VTBL, VTBX.  */
7315 7316 7317 7318 7319 7320 7321 7322
                int n = ((insn >> 8) & 3) + 1;
                if ((rn + n) > 32) {
                    /* This is UNPREDICTABLE; we choose to UNDEF to avoid the
                     * helper function running off the end of the register file.
                     */
                    return 1;
                }
                n <<= 3;
P
pbrook 已提交
7323
                if (insn & (1 << 6)) {
P
pbrook 已提交
7324
                    tmp = neon_load_reg(rd, 0);
P
pbrook 已提交
7325
                } else {
7326
                    tmp = tcg_temp_new_i32();
P
pbrook 已提交
7327
                    tcg_gen_movi_i32(tmp, 0);
P
pbrook 已提交
7328
                }
P
pbrook 已提交
7329
                tmp2 = neon_load_reg(rm, 0);
7330 7331
                tmp4 = tcg_const_i32(rn);
                tmp5 = tcg_const_i32(n);
7332
                gen_helper_neon_tbl(tmp2, cpu_env, tmp2, tmp, tmp4, tmp5);
7333
                tcg_temp_free_i32(tmp);
P
pbrook 已提交
7334
                if (insn & (1 << 6)) {
P
pbrook 已提交
7335
                    tmp = neon_load_reg(rd, 1);
P
pbrook 已提交
7336
                } else {
7337
                    tmp = tcg_temp_new_i32();
P
pbrook 已提交
7338
                    tcg_gen_movi_i32(tmp, 0);
P
pbrook 已提交
7339
                }
P
pbrook 已提交
7340
                tmp3 = neon_load_reg(rm, 1);
7341
                gen_helper_neon_tbl(tmp3, cpu_env, tmp3, tmp, tmp4, tmp5);
7342 7343
                tcg_temp_free_i32(tmp5);
                tcg_temp_free_i32(tmp4);
P
pbrook 已提交
7344
                neon_store_reg(rd, 0, tmp2);
P
pbrook 已提交
7345
                neon_store_reg(rd, 1, tmp3);
7346
                tcg_temp_free_i32(tmp);
P
pbrook 已提交
7347 7348
            } else if ((insn & 0x380) == 0) {
                /* VDUP */
7349 7350 7351
                if ((insn & (7 << 16)) == 0 || (q && (rd & 1))) {
                    return 1;
                }
P
pbrook 已提交
7352
                if (insn & (1 << 19)) {
7353
                    tmp = neon_load_reg(rm, 1);
P
pbrook 已提交
7354
                } else {
7355
                    tmp = neon_load_reg(rm, 0);
P
pbrook 已提交
7356 7357
                }
                if (insn & (1 << 16)) {
7358
                    gen_neon_dup_u8(tmp, ((insn >> 17) & 3) * 8);
P
pbrook 已提交
7359 7360
                } else if (insn & (1 << 17)) {
                    if ((insn >> 18) & 1)
7361
                        gen_neon_dup_high16(tmp);
P
pbrook 已提交
7362
                    else
7363
                        gen_neon_dup_low16(tmp);
P
pbrook 已提交
7364 7365
                }
                for (pass = 0; pass < (q ? 4 : 2); pass++) {
7366
                    tmp2 = tcg_temp_new_i32();
7367 7368
                    tcg_gen_mov_i32(tmp2, tmp);
                    neon_store_reg(rd, pass, tmp2);
P
pbrook 已提交
7369
                }
7370
                tcg_temp_free_i32(tmp);
P
pbrook 已提交
7371 7372 7373 7374 7375 7376 7377 7378
            } else {
                return 1;
            }
        }
    }
    return 0;
}

7379
static int disas_coproc_insn(DisasContext *s, uint32_t insn)
P
pbrook 已提交
7380
{
7381 7382
    int cpnum, is64, crn, crm, opc1, opc2, isread, rt, rt2;
    const ARMCPRegInfo *ri;
P
pbrook 已提交
7383 7384

    cpnum = (insn >> 8) & 0xf;
7385 7386

    /* First check for coprocessor space used for XScale/iwMMXt insns */
7387
    if (arm_dc_feature(s, ARM_FEATURE_XSCALE) && (cpnum < 2)) {
7388 7389 7390
        if (extract32(s->c15_cpar, cpnum, 1) == 0) {
            return 1;
        }
7391
        if (arm_dc_feature(s, ARM_FEATURE_IWMMXT)) {
7392
            return disas_iwmmxt_insn(s, insn);
7393
        } else if (arm_dc_feature(s, ARM_FEATURE_XSCALE)) {
7394
            return disas_dsp_insn(s, insn);
7395 7396
        }
        return 1;
7397 7398 7399 7400 7401 7402 7403 7404 7405 7406 7407 7408 7409 7410 7411 7412 7413 7414 7415 7416 7417 7418 7419 7420
    }

    /* Otherwise treat as a generic register access */
    is64 = (insn & (1 << 25)) == 0;
    if (!is64 && ((insn & (1 << 4)) == 0)) {
        /* cdp */
        return 1;
    }

    crm = insn & 0xf;
    if (is64) {
        crn = 0;
        opc1 = (insn >> 4) & 0xf;
        opc2 = 0;
        rt2 = (insn >> 16) & 0xf;
    } else {
        crn = (insn >> 16) & 0xf;
        opc1 = (insn >> 21) & 7;
        opc2 = (insn >> 5) & 7;
        rt2 = 0;
    }
    isread = (insn >> 20) & 1;
    rt = (insn >> 12) & 0xf;

7421
    ri = get_arm_cp_reginfo(s->cp_regs,
7422
            ENCODE_CP_REG(cpnum, is64, s->ns, crn, crm, opc1, opc2));
7423 7424
    if (ri) {
        /* Check access permissions */
7425
        if (!cp_access_ok(s->current_el, ri, isread)) {
7426 7427 7428
            return 1;
        }

7429
        if (ri->accessfn ||
7430
            (arm_dc_feature(s, ARM_FEATURE_XSCALE) && cpnum < 14)) {
7431 7432
            /* Emit code to perform further access permissions checks at
             * runtime; this may result in an exception.
7433 7434
             * Note that on XScale all cp0..c13 registers do an access check
             * call in order to handle c15_cpar.
7435 7436
             */
            TCGv_ptr tmpptr;
7437
            TCGv_i32 tcg_syn, tcg_isread;
7438 7439 7440 7441 7442 7443 7444 7445 7446 7447 7448 7449 7450 7451
            uint32_t syndrome;

            /* Note that since we are an implementation which takes an
             * exception on a trapped conditional instruction only if the
             * instruction passes its condition code check, we can take
             * advantage of the clause in the ARM ARM that allows us to set
             * the COND field in the instruction to 0xE in all cases.
             * We could fish the actual condition out of the insn (ARM)
             * or the condexec bits (Thumb) but it isn't necessary.
             */
            switch (cpnum) {
            case 14:
                if (is64) {
                    syndrome = syn_cp14_rrt_trap(1, 0xe, opc1, crm, rt, rt2,
7452
                                                 isread, false);
7453 7454
                } else {
                    syndrome = syn_cp14_rt_trap(1, 0xe, opc1, opc2, crn, crm,
7455
                                                rt, isread, false);
7456 7457 7458 7459 7460
                }
                break;
            case 15:
                if (is64) {
                    syndrome = syn_cp15_rrt_trap(1, 0xe, opc1, crm, rt, rt2,
7461
                                                 isread, false);
7462 7463
                } else {
                    syndrome = syn_cp15_rt_trap(1, 0xe, opc1, opc2, crn, crm,
7464
                                                rt, isread, false);
7465 7466 7467 7468 7469 7470 7471 7472
                }
                break;
            default:
                /* ARMv8 defines that only coprocessors 14 and 15 exist,
                 * so this can only happen if this is an ARMv7 or earlier CPU,
                 * in which case the syndrome information won't actually be
                 * guest visible.
                 */
7473
                assert(!arm_dc_feature(s, ARM_FEATURE_V8));
7474 7475 7476 7477
                syndrome = syn_uncategorized();
                break;
            }

7478
            gen_set_condexec(s);
7479
            gen_set_pc_im(s, s->pc - 4);
7480
            tmpptr = tcg_const_ptr(ri);
7481
            tcg_syn = tcg_const_i32(syndrome);
7482 7483 7484
            tcg_isread = tcg_const_i32(isread);
            gen_helper_access_check_cp_reg(cpu_env, tmpptr, tcg_syn,
                                           tcg_isread);
7485
            tcg_temp_free_ptr(tmpptr);
7486
            tcg_temp_free_i32(tcg_syn);
7487
            tcg_temp_free_i32(tcg_isread);
7488 7489
        }

7490 7491 7492 7493 7494 7495 7496 7497
        /* Handle special cases first */
        switch (ri->type & ~(ARM_CP_FLAG_MASK & ~ARM_CP_SPECIAL)) {
        case ARM_CP_NOP:
            return 0;
        case ARM_CP_WFI:
            if (isread) {
                return 1;
            }
7498
            gen_set_pc_im(s, s->pc);
7499
            s->is_jmp = DISAS_WFI;
P
Paul Brook 已提交
7500
            return 0;
7501 7502 7503 7504
        default:
            break;
        }

7505
        if ((s->tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
7506 7507 7508
            gen_io_start();
        }

7509 7510 7511 7512 7513 7514 7515 7516 7517 7518 7519 7520 7521 7522 7523 7524 7525 7526
        if (isread) {
            /* Read */
            if (is64) {
                TCGv_i64 tmp64;
                TCGv_i32 tmp;
                if (ri->type & ARM_CP_CONST) {
                    tmp64 = tcg_const_i64(ri->resetvalue);
                } else if (ri->readfn) {
                    TCGv_ptr tmpptr;
                    tmp64 = tcg_temp_new_i64();
                    tmpptr = tcg_const_ptr(ri);
                    gen_helper_get_cp_reg64(tmp64, cpu_env, tmpptr);
                    tcg_temp_free_ptr(tmpptr);
                } else {
                    tmp64 = tcg_temp_new_i64();
                    tcg_gen_ld_i64(tmp64, cpu_env, ri->fieldoffset);
                }
                tmp = tcg_temp_new_i32();
7527
                tcg_gen_extrl_i64_i32(tmp, tmp64);
7528 7529
                store_reg(s, rt, tmp);
                tcg_gen_shri_i64(tmp64, tmp64, 32);
7530
                tmp = tcg_temp_new_i32();
7531
                tcg_gen_extrl_i64_i32(tmp, tmp64);
7532
                tcg_temp_free_i64(tmp64);
7533 7534
                store_reg(s, rt2, tmp);
            } else {
7535
                TCGv_i32 tmp;
7536 7537 7538 7539 7540 7541 7542 7543 7544 7545 7546 7547 7548 7549 7550 7551 7552 7553 7554 7555 7556 7557 7558 7559 7560 7561 7562 7563 7564
                if (ri->type & ARM_CP_CONST) {
                    tmp = tcg_const_i32(ri->resetvalue);
                } else if (ri->readfn) {
                    TCGv_ptr tmpptr;
                    tmp = tcg_temp_new_i32();
                    tmpptr = tcg_const_ptr(ri);
                    gen_helper_get_cp_reg(tmp, cpu_env, tmpptr);
                    tcg_temp_free_ptr(tmpptr);
                } else {
                    tmp = load_cpu_offset(ri->fieldoffset);
                }
                if (rt == 15) {
                    /* Destination register of r15 for 32 bit loads sets
                     * the condition codes from the high 4 bits of the value
                     */
                    gen_set_nzcv(tmp);
                    tcg_temp_free_i32(tmp);
                } else {
                    store_reg(s, rt, tmp);
                }
            }
        } else {
            /* Write */
            if (ri->type & ARM_CP_CONST) {
                /* If not forbidden by access permissions, treat as WI */
                return 0;
            }

            if (is64) {
7565
                TCGv_i32 tmplo, tmphi;
7566 7567 7568 7569 7570 7571 7572 7573 7574 7575 7576 7577 7578 7579 7580 7581
                TCGv_i64 tmp64 = tcg_temp_new_i64();
                tmplo = load_reg(s, rt);
                tmphi = load_reg(s, rt2);
                tcg_gen_concat_i32_i64(tmp64, tmplo, tmphi);
                tcg_temp_free_i32(tmplo);
                tcg_temp_free_i32(tmphi);
                if (ri->writefn) {
                    TCGv_ptr tmpptr = tcg_const_ptr(ri);
                    gen_helper_set_cp_reg64(cpu_env, tmpptr, tmp64);
                    tcg_temp_free_ptr(tmpptr);
                } else {
                    tcg_gen_st_i64(tmp64, cpu_env, ri->fieldoffset);
                }
                tcg_temp_free_i64(tmp64);
            } else {
                if (ri->writefn) {
7582
                    TCGv_i32 tmp;
7583 7584 7585 7586 7587 7588 7589
                    TCGv_ptr tmpptr;
                    tmp = load_reg(s, rt);
                    tmpptr = tcg_const_ptr(ri);
                    gen_helper_set_cp_reg(cpu_env, tmpptr, tmp);
                    tcg_temp_free_ptr(tmpptr);
                    tcg_temp_free_i32(tmp);
                } else {
7590
                    TCGv_i32 tmp = load_reg(s, rt);
7591 7592 7593
                    store_cpu_offset(tmp, ri->fieldoffset);
                }
            }
7594 7595
        }

7596
        if ((s->tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
7597 7598 7599 7600
            /* I/O operations must end the TB here (whether read or write) */
            gen_io_end();
            gen_lookup_tb(s);
        } else if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) {
7601 7602 7603 7604
            /* We default to ending the TB on a coprocessor register write,
             * but allow this to be suppressed by the register definition
             * (usually only necessary to work around guest bugs).
             */
7605
            gen_lookup_tb(s);
7606
        }
7607

7608 7609 7610
        return 0;
    }

7611 7612 7613 7614 7615
    /* Unknown register; this might be a guest error or a QEMU
     * unimplemented feature.
     */
    if (is64) {
        qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 "
7616 7617 7618 7619
                      "64 bit system register cp:%d opc1: %d crm:%d "
                      "(%s)\n",
                      isread ? "read" : "write", cpnum, opc1, crm,
                      s->ns ? "non-secure" : "secure");
7620 7621
    } else {
        qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 "
7622 7623 7624 7625
                      "system register cp:%d opc1:%d crn:%d crm:%d opc2:%d "
                      "(%s)\n",
                      isread ? "read" : "write", cpnum, opc1, crn, crm, opc2,
                      s->ns ? "non-secure" : "secure");
7626 7627
    }

7628
    return 1;
P
pbrook 已提交
7629 7630
}

P
pbrook 已提交
7631 7632

/* Store a 64-bit value to a register pair.  Clobbers val.  */
P
pbrook 已提交
7633
static void gen_storeq_reg(DisasContext *s, int rlow, int rhigh, TCGv_i64 val)
P
pbrook 已提交
7634
{
7635
    TCGv_i32 tmp;
7636
    tmp = tcg_temp_new_i32();
7637
    tcg_gen_extrl_i64_i32(tmp, val);
P
pbrook 已提交
7638
    store_reg(s, rlow, tmp);
7639
    tmp = tcg_temp_new_i32();
P
pbrook 已提交
7640
    tcg_gen_shri_i64(val, val, 32);
7641
    tcg_gen_extrl_i64_i32(tmp, val);
P
pbrook 已提交
7642 7643 7644 7645
    store_reg(s, rhigh, tmp);
}

/* load a 32-bit value from a register and perform a 64-bit accumulate.  */
P
pbrook 已提交
7646
static void gen_addq_lo(DisasContext *s, TCGv_i64 val, int rlow)
P
pbrook 已提交
7647
{
P
pbrook 已提交
7648
    TCGv_i64 tmp;
7649
    TCGv_i32 tmp2;
P
pbrook 已提交
7650

P
pbrook 已提交
7651
    /* Load value and extend to 64 bits.  */
P
pbrook 已提交
7652
    tmp = tcg_temp_new_i64();
P
pbrook 已提交
7653 7654
    tmp2 = load_reg(s, rlow);
    tcg_gen_extu_i32_i64(tmp, tmp2);
7655
    tcg_temp_free_i32(tmp2);
P
pbrook 已提交
7656
    tcg_gen_add_i64(val, val, tmp);
7657
    tcg_temp_free_i64(tmp);
P
pbrook 已提交
7658 7659 7660
}

/* load and add a 64-bit value from a register pair.  */
P
pbrook 已提交
7661
static void gen_addq(DisasContext *s, TCGv_i64 val, int rlow, int rhigh)
P
pbrook 已提交
7662
{
P
pbrook 已提交
7663
    TCGv_i64 tmp;
7664 7665
    TCGv_i32 tmpl;
    TCGv_i32 tmph;
P
pbrook 已提交
7666 7667

    /* Load 64-bit value rd:rn.  */
P
pbrook 已提交
7668 7669
    tmpl = load_reg(s, rlow);
    tmph = load_reg(s, rhigh);
P
pbrook 已提交
7670
    tmp = tcg_temp_new_i64();
P
pbrook 已提交
7671
    tcg_gen_concat_i32_i64(tmp, tmpl, tmph);
7672 7673
    tcg_temp_free_i32(tmpl);
    tcg_temp_free_i32(tmph);
P
pbrook 已提交
7674
    tcg_gen_add_i64(val, val, tmp);
7675
    tcg_temp_free_i64(tmp);
P
pbrook 已提交
7676 7677
}

7678
/* Set N and Z flags from hi|lo.  */
7679
static void gen_logicq_cc(TCGv_i32 lo, TCGv_i32 hi)
P
pbrook 已提交
7680
{
7681 7682
    tcg_gen_mov_i32(cpu_NF, hi);
    tcg_gen_or_i32(cpu_ZF, lo, hi);
P
pbrook 已提交
7683 7684
}

P
Paul Brook 已提交
7685 7686
/* Load/Store exclusive instructions are implemented by remembering
   the value/address loaded, and seeing if these are the same
7687
   when the store is performed.  This should be sufficient to implement
P
Paul Brook 已提交
7688
   the architecturally mandated semantics, and avoids having to monitor
7689 7690
   regular stores.  The compare vs the remembered value is done during
   the cmpxchg operation, but we must compare the addresses manually.  */
P
Paul Brook 已提交
7691
static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
7692
                               TCGv_i32 addr, int size)
P
Paul Brook 已提交
7693
{
7694
    TCGv_i32 tmp = tcg_temp_new_i32();
7695
    TCGMemOp opc = size | MO_ALIGN | s->be_data;
P
Paul Brook 已提交
7696

7697 7698
    s->is_ldex = true;

P
Paul Brook 已提交
7699
    if (size == 3) {
7700
        TCGv_i32 tmp2 = tcg_temp_new_i32();
7701
        TCGv_i64 t64 = tcg_temp_new_i64();
7702

7703 7704 7705 7706 7707 7708
        gen_aa32_ld_i64(s, t64, addr, get_mem_index(s), opc);
        tcg_gen_mov_i64(cpu_exclusive_val, t64);
        tcg_gen_extr_i64_i32(tmp, tmp2, t64);
        tcg_temp_free_i64(t64);

        store_reg(s, rt2, tmp2);
7709
    } else {
7710
        gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), opc);
7711
        tcg_gen_extu_i32_i64(cpu_exclusive_val, tmp);
P
Paul Brook 已提交
7712
    }
7713 7714 7715

    store_reg(s, rt, tmp);
    tcg_gen_extu_i32_i64(cpu_exclusive_addr, addr);
P
Paul Brook 已提交
7716 7717 7718 7719
}

static void gen_clrex(DisasContext *s)
{
7720
    tcg_gen_movi_i64(cpu_exclusive_addr, -1);
P
Paul Brook 已提交
7721 7722 7723
}

static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
7724
                                TCGv_i32 addr, int size)
P
Paul Brook 已提交
7725
{
7726 7727 7728
    TCGv_i32 t0, t1, t2;
    TCGv_i64 extaddr;
    TCGv taddr;
7729 7730
    TCGLabel *done_label;
    TCGLabel *fail_label;
7731
    TCGMemOp opc = size | MO_ALIGN | s->be_data;
P
Paul Brook 已提交
7732 7733 7734 7735 7736 7737 7738 7739 7740

    /* if (env->exclusive_addr == addr && env->exclusive_val == [addr]) {
         [addr] = {Rt};
         {Rd} = 0;
       } else {
         {Rd} = 1;
       } */
    fail_label = gen_new_label();
    done_label = gen_new_label();
7741 7742 7743 7744 7745
    extaddr = tcg_temp_new_i64();
    tcg_gen_extu_i32_i64(extaddr, addr);
    tcg_gen_brcond_i64(TCG_COND_NE, extaddr, cpu_exclusive_addr, fail_label);
    tcg_temp_free_i64(extaddr);

7746 7747 7748
    taddr = gen_aa32_addr(s, addr, opc);
    t0 = tcg_temp_new_i32();
    t1 = load_reg(s, rt);
P
Paul Brook 已提交
7749
    if (size == 3) {
7750 7751
        TCGv_i64 o64 = tcg_temp_new_i64();
        TCGv_i64 n64 = tcg_temp_new_i64();
7752

7753 7754 7755 7756
        t2 = load_reg(s, rt2);
        tcg_gen_concat_i32_i64(n64, t1, t2);
        tcg_temp_free_i32(t2);
        gen_aa32_frob64(s, n64);
7757

7758 7759 7760 7761 7762 7763 7764 7765 7766 7767 7768 7769 7770 7771 7772
        tcg_gen_atomic_cmpxchg_i64(o64, taddr, cpu_exclusive_val, n64,
                                   get_mem_index(s), opc);
        tcg_temp_free_i64(n64);

        gen_aa32_frob64(s, o64);
        tcg_gen_setcond_i64(TCG_COND_NE, o64, o64, cpu_exclusive_val);
        tcg_gen_extrl_i64_i32(t0, o64);

        tcg_temp_free_i64(o64);
    } else {
        t2 = tcg_temp_new_i32();
        tcg_gen_extrl_i64_i32(t2, cpu_exclusive_val);
        tcg_gen_atomic_cmpxchg_i32(t0, taddr, t2, t1, get_mem_index(s), opc);
        tcg_gen_setcond_i32(TCG_COND_NE, t0, t0, t2);
        tcg_temp_free_i32(t2);
P
Paul Brook 已提交
7773
    }
7774 7775 7776 7777
    tcg_temp_free_i32(t1);
    tcg_temp_free(taddr);
    tcg_gen_mov_i32(cpu_R[rd], t0);
    tcg_temp_free_i32(t0);
P
Paul Brook 已提交
7778
    tcg_gen_br(done_label);
7779

P
Paul Brook 已提交
7780 7781 7782
    gen_set_label(fail_label);
    tcg_gen_movi_i32(cpu_R[rd], 1);
    gen_set_label(done_label);
7783
    tcg_gen_movi_i64(cpu_exclusive_addr, -1);
P
Paul Brook 已提交
7784 7785
}

7786 7787 7788 7789 7790 7791 7792 7793 7794 7795 7796 7797 7798
/* gen_srs:
 * @env: CPUARMState
 * @s: DisasContext
 * @mode: mode field from insn (which stack to store to)
 * @amode: addressing mode (DA/IA/DB/IB), encoded as per P,U bits in ARM insn
 * @writeback: true if writeback bit set
 *
 * Generate code for the SRS (Store Return State) insn.
 */
static void gen_srs(DisasContext *s,
                    uint32_t mode, uint32_t amode, bool writeback)
{
    int32_t offset;
7799 7800 7801 7802 7803
    TCGv_i32 addr, tmp;
    bool undef = false;

    /* SRS is:
     * - trapped to EL3 if EL3 is AArch64 and we are at Secure EL1
7804
     *   and specified mode is monitor mode
7805 7806 7807 7808 7809 7810 7811
     * - UNDEFINED in Hyp mode
     * - UNPREDICTABLE in User or System mode
     * - UNPREDICTABLE if the specified mode is:
     * -- not implemented
     * -- not a valid mode number
     * -- a mode that's at a higher exception level
     * -- Monitor, if we are Non-secure
7812
     * For the UNPREDICTABLE cases we choose to UNDEF.
7813
     */
7814
    if (s->current_el == 1 && !s->ns && mode == ARM_CPU_MODE_MON) {
7815 7816 7817 7818 7819 7820 7821 7822 7823 7824 7825 7826 7827 7828 7829 7830 7831 7832 7833 7834 7835 7836 7837 7838 7839 7840 7841 7842 7843 7844 7845 7846 7847 7848 7849 7850 7851 7852 7853 7854 7855 7856 7857
        gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized(), 3);
        return;
    }

    if (s->current_el == 0 || s->current_el == 2) {
        undef = true;
    }

    switch (mode) {
    case ARM_CPU_MODE_USR:
    case ARM_CPU_MODE_FIQ:
    case ARM_CPU_MODE_IRQ:
    case ARM_CPU_MODE_SVC:
    case ARM_CPU_MODE_ABT:
    case ARM_CPU_MODE_UND:
    case ARM_CPU_MODE_SYS:
        break;
    case ARM_CPU_MODE_HYP:
        if (s->current_el == 1 || !arm_dc_feature(s, ARM_FEATURE_EL2)) {
            undef = true;
        }
        break;
    case ARM_CPU_MODE_MON:
        /* No need to check specifically for "are we non-secure" because
         * we've already made EL0 UNDEF and handled the trap for S-EL1;
         * so if this isn't EL3 then we must be non-secure.
         */
        if (s->current_el != 3) {
            undef = true;
        }
        break;
    default:
        undef = true;
    }

    if (undef) {
        gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized(),
                           default_exception_el(s));
        return;
    }

    addr = tcg_temp_new_i32();
    tmp = tcg_const_i32(mode);
7858 7859 7860
    /* get_r13_banked() will raise an exception if called from System mode */
    gen_set_condexec(s);
    gen_set_pc_im(s, s->pc - 4);
7861 7862 7863 7864 7865 7866 7867 7868 7869 7870 7871 7872 7873 7874 7875 7876 7877 7878 7879 7880
    gen_helper_get_r13_banked(addr, cpu_env, tmp);
    tcg_temp_free_i32(tmp);
    switch (amode) {
    case 0: /* DA */
        offset = -4;
        break;
    case 1: /* IA */
        offset = 0;
        break;
    case 2: /* DB */
        offset = -8;
        break;
    case 3: /* IB */
        offset = 4;
        break;
    default:
        abort();
    }
    tcg_gen_addi_i32(addr, addr, offset);
    tmp = load_reg(s, 14);
7881
    gen_aa32_st32(s, tmp, addr, get_mem_index(s));
7882
    tcg_temp_free_i32(tmp);
7883 7884
    tmp = load_cpu_field(spsr);
    tcg_gen_addi_i32(addr, addr, 4);
7885
    gen_aa32_st32(s, tmp, addr, get_mem_index(s));
7886
    tcg_temp_free_i32(tmp);
7887 7888 7889 7890 7891 7892 7893 7894 7895 7896 7897 7898 7899 7900 7901 7902 7903 7904 7905 7906 7907 7908 7909
    if (writeback) {
        switch (amode) {
        case 0:
            offset = -8;
            break;
        case 1:
            offset = 4;
            break;
        case 2:
            offset = -4;
            break;
        case 3:
            offset = 0;
            break;
        default:
            abort();
        }
        tcg_gen_addi_i32(addr, addr, offset);
        tmp = tcg_const_i32(mode);
        gen_helper_set_r13_banked(cpu_env, tmp, addr);
        tcg_temp_free_i32(tmp);
    }
    tcg_temp_free_i32(addr);
7910
    s->is_jmp = DISAS_UPDATE;
7911 7912
}

7913
static void disas_arm_insn(DisasContext *s, unsigned int insn)
P
pbrook 已提交
7914
{
7915
    unsigned int cond, val, op1, i, shift, rm, rs, rn, rd, sh;
7916 7917 7918 7919
    TCGv_i32 tmp;
    TCGv_i32 tmp2;
    TCGv_i32 tmp3;
    TCGv_i32 addr;
P
pbrook 已提交
7920
    TCGv_i64 tmp64;
P
pbrook 已提交
7921 7922

    /* M variants do not implement ARM mode.  */
7923
    if (arm_dc_feature(s, ARM_FEATURE_M)) {
P
pbrook 已提交
7924
        goto illegal_op;
7925
    }
P
pbrook 已提交
7926 7927
    cond = insn >> 28;
    if (cond == 0xf){
7928 7929 7930 7931 7932 7933
        /* In ARMv3 and v4 the NV condition is UNPREDICTABLE; we
         * choose to UNDEF. In ARMv5 and above the space is used
         * for miscellaneous unconditional instructions.
         */
        ARCH(5);

P
pbrook 已提交
7934 7935 7936
        /* Unconditional instructions.  */
        if (((insn >> 25) & 7) == 1) {
            /* NEON Data processing.  */
7937
            if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
P
pbrook 已提交
7938
                goto illegal_op;
7939
            }
P
pbrook 已提交
7940

7941
            if (disas_neon_data_insn(s, insn)) {
P
pbrook 已提交
7942
                goto illegal_op;
7943
            }
P
pbrook 已提交
7944 7945 7946 7947
            return;
        }
        if ((insn & 0x0f100000) == 0x04000000) {
            /* NEON load/store.  */
7948
            if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
P
pbrook 已提交
7949
                goto illegal_op;
7950
            }
P
pbrook 已提交
7951

7952
            if (disas_neon_ls_insn(s, insn)) {
P
pbrook 已提交
7953
                goto illegal_op;
7954
            }
P
pbrook 已提交
7955 7956
            return;
        }
7957 7958
        if ((insn & 0x0f000e10) == 0x0e000a00) {
            /* VFP.  */
7959
            if (disas_vfp_insn(s, insn)) {
7960 7961 7962 7963
                goto illegal_op;
            }
            return;
        }
7964 7965 7966 7967
        if (((insn & 0x0f30f000) == 0x0510f000) ||
            ((insn & 0x0f30f010) == 0x0710f000)) {
            if ((insn & (1 << 22)) == 0) {
                /* PLDW; v7MP */
7968
                if (!arm_dc_feature(s, ARM_FEATURE_V7MP)) {
7969 7970 7971 7972
                    goto illegal_op;
                }
            }
            /* Otherwise PLD; v5TE+ */
7973
            ARCH(5TE);
7974 7975 7976 7977 7978 7979 7980 7981 7982
            return;
        }
        if (((insn & 0x0f70f000) == 0x0450f000) ||
            ((insn & 0x0f70f010) == 0x0650f000)) {
            ARCH(7);
            return; /* PLI; V7 */
        }
        if (((insn & 0x0f700000) == 0x04100000) ||
            ((insn & 0x0f700010) == 0x06100000)) {
7983
            if (!arm_dc_feature(s, ARM_FEATURE_V7MP)) {
7984 7985 7986 7987 7988 7989
                goto illegal_op;
            }
            return; /* v7MP: Unallocated memory hint: must NOP */
        }

        if ((insn & 0x0ffffdff) == 0x01010000) {
P
pbrook 已提交
7990 7991
            ARCH(6);
            /* setend */
P
Paolo Bonzini 已提交
7992 7993 7994
            if (((insn >> 9) & 1) != !!(s->be_data == MO_BE)) {
                gen_helper_setend(cpu_env);
                s->is_jmp = DISAS_UPDATE;
P
pbrook 已提交
7995 7996 7997 7998 7999 8000
            }
            return;
        } else if ((insn & 0x0fffff00) == 0x057ff000) {
            switch ((insn >> 4) & 0xf) {
            case 1: /* clrex */
                ARCH(6K);
P
Paul Brook 已提交
8001
                gen_clrex(s);
P
pbrook 已提交
8002 8003 8004 8005
                return;
            case 4: /* dsb */
            case 5: /* dmb */
                ARCH(7);
8006
                tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
P
pbrook 已提交
8007
                return;
8008 8009 8010 8011 8012 8013 8014
            case 6: /* isb */
                /* We need to break the TB after this insn to execute
                 * self-modifying code correctly and also to take
                 * any pending interrupts immediately.
                 */
                gen_lookup_tb(s);
                return;
P
pbrook 已提交
8015 8016 8017 8018 8019
            default:
                goto illegal_op;
            }
        } else if ((insn & 0x0e5fffe0) == 0x084d0500) {
            /* srs */
8020 8021
            ARCH(6);
            gen_srs(s, (insn & 0x1f), (insn >> 23) & 3, insn & (1 << 21));
8022
            return;
8023
        } else if ((insn & 0x0e50ffe0) == 0x08100a00) {
P
pbrook 已提交
8024
            /* rfe */
8025
            int32_t offset;
P
pbrook 已提交
8026 8027 8028 8029
            if (IS_USER(s))
                goto illegal_op;
            ARCH(6);
            rn = (insn >> 16) & 0xf;
P
pbrook 已提交
8030
            addr = load_reg(s, rn);
P
pbrook 已提交
8031 8032
            i = (insn >> 23) & 3;
            switch (i) {
P
pbrook 已提交
8033
            case 0: offset = -4; break; /* DA */
8034 8035
            case 1: offset = 0; break; /* IA */
            case 2: offset = -8; break; /* DB */
P
pbrook 已提交
8036
            case 3: offset = 4; break; /* IB */
P
pbrook 已提交
8037 8038 8039
            default: abort();
            }
            if (offset)
P
pbrook 已提交
8040 8041
                tcg_gen_addi_i32(addr, addr, offset);
            /* Load PC into tmp and CPSR into tmp2.  */
8042
            tmp = tcg_temp_new_i32();
8043
            gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
8044
            tcg_gen_addi_i32(addr, addr, 4);
8045
            tmp2 = tcg_temp_new_i32();
8046
            gen_aa32_ld32u(s, tmp2, addr, get_mem_index(s));
P
pbrook 已提交
8047 8048 8049
            if (insn & (1 << 21)) {
                /* Base writeback.  */
                switch (i) {
P
pbrook 已提交
8050
                case 0: offset = -8; break;
8051 8052
                case 1: offset = 4; break;
                case 2: offset = -4; break;
P
pbrook 已提交
8053
                case 3: offset = 0; break;
P
pbrook 已提交
8054 8055 8056
                default: abort();
                }
                if (offset)
P
pbrook 已提交
8057 8058 8059
                    tcg_gen_addi_i32(addr, addr, offset);
                store_reg(s, rn, addr);
            } else {
8060
                tcg_temp_free_i32(addr);
P
pbrook 已提交
8061
            }
P
pbrook 已提交
8062
            gen_rfe(s, tmp, tmp2);
8063
            return;
P
pbrook 已提交
8064 8065 8066 8067 8068
        } else if ((insn & 0x0e000000) == 0x0a000000) {
            /* branch link and change to thumb (blx <offset>) */
            int32_t offset;

            val = (uint32_t)s->pc;
8069
            tmp = tcg_temp_new_i32();
P
pbrook 已提交
8070 8071
            tcg_gen_movi_i32(tmp, val);
            store_reg(s, 14, tmp);
P
pbrook 已提交
8072 8073 8074 8075 8076 8077
            /* 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;
8078
            /* protected by ARCH(5); above, near the start of uncond block */
P
pbrook 已提交
8079
            gen_bx_im(s, val);
P
pbrook 已提交
8080 8081
            return;
        } else if ((insn & 0x0e000f00) == 0x0c000100) {
8082
            if (arm_dc_feature(s, ARM_FEATURE_IWMMXT)) {
P
pbrook 已提交
8083
                /* iWMMXt register transfer.  */
8084
                if (extract32(s->c15_cpar, 1, 1)) {
8085
                    if (!disas_iwmmxt_insn(s, insn)) {
P
pbrook 已提交
8086
                        return;
8087 8088
                    }
                }
P
pbrook 已提交
8089 8090 8091
            }
        } else if ((insn & 0x0fe00000) == 0x0c400000) {
            /* Coprocessor double register transfer.  */
8092
            ARCH(5TE);
P
pbrook 已提交
8093 8094
        } else if ((insn & 0x0f000010) == 0x0e000010) {
            /* Additional coprocessor register transfer.  */
B
balrog 已提交
8095
        } else if ((insn & 0x0ff10020) == 0x01000000) {
P
pbrook 已提交
8096 8097 8098 8099 8100 8101 8102 8103 8104 8105 8106 8107 8108 8109 8110 8111
            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 已提交
8112
            if (insn & (1 << 17)) {
P
pbrook 已提交
8113 8114 8115 8116
                mask |= CPSR_M;
                val |= (insn & 0x1f);
            }
            if (mask) {
8117
                gen_set_psr_im(s, mask, 0, val);
P
pbrook 已提交
8118 8119 8120 8121 8122 8123 8124 8125 8126
            }
            return;
        }
        goto illegal_op;
    }
    if (cond != 0xe) {
        /* if not always execute, we generate a conditional jump to
           next instruction */
        s->condlabel = gen_new_label();
8127
        arm_gen_test_cc(cond ^ 1, s->condlabel);
P
pbrook 已提交
8128 8129 8130 8131 8132 8133 8134 8135 8136
        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 */
8137
                tmp = tcg_temp_new_i32();
P
pbrook 已提交
8138
                tcg_gen_movi_i32(tmp, val);
P
pbrook 已提交
8139 8140
            } else {
                /* MOVT */
P
pbrook 已提交
8141
                tmp = load_reg(s, rd);
P
pbrook 已提交
8142
                tcg_gen_ext16u_i32(tmp, tmp);
P
pbrook 已提交
8143
                tcg_gen_ori_i32(tmp, tmp, val << 16);
P
pbrook 已提交
8144
            }
P
pbrook 已提交
8145
            store_reg(s, rd, tmp);
P
pbrook 已提交
8146 8147 8148 8149 8150 8151 8152 8153 8154 8155 8156 8157
        } else {
            if (((insn >> 12) & 0xf) != 0xf)
                goto illegal_op;
            if (((insn >> 16) & 0xf) == 0) {
                gen_nop_hint(s, insn & 0xff);
            } else {
                /* CPSR = immediate */
                val = insn & 0xff;
                shift = ((insn >> 8) & 0xf) * 2;
                if (shift)
                    val = (val >> shift) | (val << (32 - shift));
                i = ((insn & (1 << 22)) != 0);
8158 8159
                if (gen_set_psr_im(s, msr_mask(s, (insn >> 16) & 0xf, i),
                                   i, val)) {
P
pbrook 已提交
8160
                    goto illegal_op;
8161
                }
P
pbrook 已提交
8162 8163 8164 8165 8166 8167 8168 8169 8170
            }
        }
    } else if ((insn & 0x0f900000) == 0x01000000
               && (insn & 0x00000090) != 0x00000090) {
        /* miscellaneous instructions */
        op1 = (insn >> 21) & 3;
        sh = (insn >> 4) & 0xf;
        rm = insn & 0xf;
        switch (sh) {
8171 8172 8173 8174 8175 8176 8177 8178 8179 8180 8181 8182 8183 8184 8185 8186 8187 8188 8189 8190
        case 0x0: /* MSR, MRS */
            if (insn & (1 << 9)) {
                /* MSR (banked) and MRS (banked) */
                int sysm = extract32(insn, 16, 4) |
                    (extract32(insn, 8, 1) << 4);
                int r = extract32(insn, 22, 1);

                if (op1 & 1) {
                    /* MSR (banked) */
                    gen_msr_banked(s, r, sysm, rm);
                } else {
                    /* MRS (banked) */
                    int rd = extract32(insn, 12, 4);

                    gen_mrs_banked(s, r, sysm, rd);
                }
                break;
            }

            /* MSR, MRS (for PSRs) */
P
pbrook 已提交
8191 8192
            if (op1 & 1) {
                /* PSR = reg */
8193
                tmp = load_reg(s, rm);
P
pbrook 已提交
8194
                i = ((op1 & 2) != 0);
8195
                if (gen_set_psr(s, msr_mask(s, (insn >> 16) & 0xf, i), i, tmp))
P
pbrook 已提交
8196 8197 8198 8199 8200 8201 8202
                    goto illegal_op;
            } else {
                /* reg = PSR */
                rd = (insn >> 12) & 0xf;
                if (op1 & 2) {
                    if (IS_USER(s))
                        goto illegal_op;
P
pbrook 已提交
8203
                    tmp = load_cpu_field(spsr);
P
pbrook 已提交
8204
                } else {
8205
                    tmp = tcg_temp_new_i32();
8206
                    gen_helper_cpsr_read(tmp, cpu_env);
P
pbrook 已提交
8207
                }
P
pbrook 已提交
8208
                store_reg(s, rd, tmp);
P
pbrook 已提交
8209 8210 8211 8212 8213
            }
            break;
        case 0x1:
            if (op1 == 1) {
                /* branch/exchange thumb (bx).  */
8214
                ARCH(4T);
P
pbrook 已提交
8215 8216
                tmp = load_reg(s, rm);
                gen_bx(s, tmp);
P
pbrook 已提交
8217 8218
            } else if (op1 == 3) {
                /* clz */
8219
                ARCH(5);
P
pbrook 已提交
8220
                rd = (insn >> 12) & 0xf;
P
pbrook 已提交
8221
                tmp = load_reg(s, rm);
R
Richard Henderson 已提交
8222
                tcg_gen_clzi_i32(tmp, tmp, 32);
P
pbrook 已提交
8223
                store_reg(s, rd, tmp);
P
pbrook 已提交
8224 8225 8226 8227 8228 8229 8230 8231
            } else {
                goto illegal_op;
            }
            break;
        case 0x2:
            if (op1 == 1) {
                ARCH(5J); /* bxj */
                /* Trivial implementation equivalent to bx.  */
P
pbrook 已提交
8232 8233
                tmp = load_reg(s, rm);
                gen_bx(s, tmp);
P
pbrook 已提交
8234 8235 8236 8237 8238 8239 8240 8241
            } else {
                goto illegal_op;
            }
            break;
        case 0x3:
            if (op1 != 1)
              goto illegal_op;

8242
            ARCH(5);
P
pbrook 已提交
8243
            /* branch link/exchange thumb (blx) */
P
pbrook 已提交
8244
            tmp = load_reg(s, rm);
8245
            tmp2 = tcg_temp_new_i32();
P
pbrook 已提交
8246 8247 8248
            tcg_gen_movi_i32(tmp2, s->pc);
            store_reg(s, 14, tmp2);
            gen_bx(s, tmp);
P
pbrook 已提交
8249
            break;
8250 8251 8252 8253 8254 8255 8256 8257 8258
        case 0x4:
        {
            /* crc32/crc32c */
            uint32_t c = extract32(insn, 8, 4);

            /* Check this CPU supports ARMv8 CRC instructions.
             * op1 == 3 is UNPREDICTABLE but handle as UNDEFINED.
             * Bits 8, 10 and 11 should be zero.
             */
8259
            if (!arm_dc_feature(s, ARM_FEATURE_CRC) || op1 == 0x3 ||
8260 8261 8262 8263 8264 8265 8266 8267 8268
                (c & 0xd) != 0) {
                goto illegal_op;
            }

            rn = extract32(insn, 16, 4);
            rd = extract32(insn, 12, 4);

            tmp = load_reg(s, rn);
            tmp2 = load_reg(s, rm);
8269 8270 8271 8272 8273
            if (op1 == 0) {
                tcg_gen_andi_i32(tmp2, tmp2, 0xff);
            } else if (op1 == 1) {
                tcg_gen_andi_i32(tmp2, tmp2, 0xffff);
            }
8274 8275 8276 8277 8278 8279 8280 8281 8282 8283 8284
            tmp3 = tcg_const_i32(1 << op1);
            if (c & 0x2) {
                gen_helper_crc32c(tmp, tmp, tmp2, tmp3);
            } else {
                gen_helper_crc32(tmp, tmp, tmp2, tmp3);
            }
            tcg_temp_free_i32(tmp2);
            tcg_temp_free_i32(tmp3);
            store_reg(s, rd, tmp);
            break;
        }
P
pbrook 已提交
8285
        case 0x5: /* saturating add/subtract */
8286
            ARCH(5TE);
P
pbrook 已提交
8287 8288
            rd = (insn >> 12) & 0xf;
            rn = (insn >> 16) & 0xf;
8289
            tmp = load_reg(s, rm);
P
pbrook 已提交
8290
            tmp2 = load_reg(s, rn);
P
pbrook 已提交
8291
            if (op1 & 2)
8292
                gen_helper_double_saturate(tmp2, cpu_env, tmp2);
P
pbrook 已提交
8293
            if (op1 & 1)
8294
                gen_helper_sub_saturate(tmp, cpu_env, tmp, tmp2);
P
pbrook 已提交
8295
            else
8296
                gen_helper_add_saturate(tmp, cpu_env, tmp, tmp2);
8297
            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8298
            store_reg(s, rd, tmp);
P
pbrook 已提交
8299
            break;
8300
        case 7:
8301 8302
        {
            int imm16 = extract32(insn, 0, 4) | (extract32(insn, 8, 12) << 4);
8303
            switch (op1) {
8304 8305 8306 8307
            case 0:
                /* HLT */
                gen_hlt(s, imm16);
                break;
8308 8309 8310 8311
            case 1:
                /* bkpt */
                ARCH(5);
                gen_exception_insn(s, 4, EXCP_BKPT,
8312 8313
                                   syn_aa32_bkpt(imm16, false),
                                   default_exception_el(s));
8314 8315 8316 8317 8318 8319 8320 8321 8322 8323 8324 8325 8326 8327 8328 8329 8330 8331
                break;
            case 2:
                /* Hypervisor call (v7) */
                ARCH(7);
                if (IS_USER(s)) {
                    goto illegal_op;
                }
                gen_hvc(s, imm16);
                break;
            case 3:
                /* Secure monitor call (v6+) */
                ARCH(6K);
                if (IS_USER(s)) {
                    goto illegal_op;
                }
                gen_smc(s);
                break;
            default:
8332
                g_assert_not_reached();
8333
            }
P
pbrook 已提交
8334
            break;
8335
        }
P
pbrook 已提交
8336 8337 8338 8339
        case 0x8: /* signed multiply */
        case 0xa:
        case 0xc:
        case 0xe:
8340
            ARCH(5TE);
P
pbrook 已提交
8341 8342 8343 8344 8345
            rs = (insn >> 8) & 0xf;
            rn = (insn >> 12) & 0xf;
            rd = (insn >> 16) & 0xf;
            if (op1 == 1) {
                /* (32 * 16) >> 16 */
P
pbrook 已提交
8346 8347
                tmp = load_reg(s, rm);
                tmp2 = load_reg(s, rs);
P
pbrook 已提交
8348
                if (sh & 4)
P
pbrook 已提交
8349
                    tcg_gen_sari_i32(tmp2, tmp2, 16);
P
pbrook 已提交
8350
                else
P
pbrook 已提交
8351
                    gen_sxth(tmp2);
P
pbrook 已提交
8352 8353
                tmp64 = gen_muls_i64_i32(tmp, tmp2);
                tcg_gen_shri_i64(tmp64, tmp64, 16);
8354
                tmp = tcg_temp_new_i32();
8355
                tcg_gen_extrl_i64_i32(tmp, tmp64);
8356
                tcg_temp_free_i64(tmp64);
P
pbrook 已提交
8357
                if ((sh & 2) == 0) {
P
pbrook 已提交
8358
                    tmp2 = load_reg(s, rn);
8359
                    gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
8360
                    tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8361
                }
P
pbrook 已提交
8362
                store_reg(s, rd, tmp);
P
pbrook 已提交
8363 8364
            } else {
                /* 16 * 16 */
P
pbrook 已提交
8365 8366 8367
                tmp = load_reg(s, rm);
                tmp2 = load_reg(s, rs);
                gen_mulxy(tmp, tmp2, sh & 2, sh & 4);
8368
                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8369
                if (op1 == 2) {
P
pbrook 已提交
8370 8371
                    tmp64 = tcg_temp_new_i64();
                    tcg_gen_ext_i32_i64(tmp64, tmp);
8372
                    tcg_temp_free_i32(tmp);
P
pbrook 已提交
8373 8374
                    gen_addq(s, tmp64, rn, rd);
                    gen_storeq_reg(s, rn, rd, tmp64);
8375
                    tcg_temp_free_i64(tmp64);
P
pbrook 已提交
8376 8377
                } else {
                    if (op1 == 0) {
P
pbrook 已提交
8378
                        tmp2 = load_reg(s, rn);
8379
                        gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
8380
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8381
                    }
P
pbrook 已提交
8382
                    store_reg(s, rd, tmp);
P
pbrook 已提交
8383 8384 8385 8386 8387 8388 8389 8390 8391 8392 8393 8394 8395 8396 8397 8398 8399 8400 8401 8402
                }
            }
            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;
8403
            if (shift) {
P
pbrook 已提交
8404
                val = (val >> shift) | (val << (32 - shift));
8405
            }
8406
            tmp2 = tcg_temp_new_i32();
8407 8408 8409 8410
            tcg_gen_movi_i32(tmp2, val);
            if (logic_cc && shift) {
                gen_set_CF_bit31(tmp2);
            }
P
pbrook 已提交
8411 8412 8413
        } else {
            /* register */
            rm = (insn) & 0xf;
8414
            tmp2 = load_reg(s, rm);
P
pbrook 已提交
8415 8416 8417
            shiftop = (insn >> 5) & 3;
            if (!(insn & (1 << 4))) {
                shift = (insn >> 7) & 0x1f;
8418
                gen_arm_shift_im(tmp2, shiftop, shift, logic_cc);
P
pbrook 已提交
8419 8420
            } else {
                rs = (insn >> 8) & 0xf;
P
pbrook 已提交
8421
                tmp = load_reg(s, rs);
8422
                gen_arm_shift_reg(tmp2, shiftop, tmp, logic_cc);
P
pbrook 已提交
8423 8424 8425 8426
            }
        }
        if (op1 != 0x0f && op1 != 0x0d) {
            rn = (insn >> 16) & 0xf;
8427 8428
            tmp = load_reg(s, rn);
        } else {
8429
            TCGV_UNUSED_I32(tmp);
P
pbrook 已提交
8430 8431 8432 8433
        }
        rd = (insn >> 12) & 0xf;
        switch(op1) {
        case 0x00:
8434 8435 8436 8437
            tcg_gen_and_i32(tmp, tmp, tmp2);
            if (logic_cc) {
                gen_logic_CC(tmp);
            }
8438
            store_reg_bx(s, rd, tmp);
P
pbrook 已提交
8439 8440
            break;
        case 0x01:
8441 8442 8443 8444
            tcg_gen_xor_i32(tmp, tmp, tmp2);
            if (logic_cc) {
                gen_logic_CC(tmp);
            }
8445
            store_reg_bx(s, rd, tmp);
P
pbrook 已提交
8446 8447 8448 8449
            break;
        case 0x02:
            if (set_cc && rd == 15) {
                /* SUBS r15, ... is used for exception return.  */
8450
                if (IS_USER(s)) {
P
pbrook 已提交
8451
                    goto illegal_op;
8452
                }
8453
                gen_sub_CC(tmp, tmp, tmp2);
8454
                gen_exception_return(s, tmp);
P
pbrook 已提交
8455
            } else {
8456
                if (set_cc) {
8457
                    gen_sub_CC(tmp, tmp, tmp2);
8458 8459 8460
                } else {
                    tcg_gen_sub_i32(tmp, tmp, tmp2);
                }
8461
                store_reg_bx(s, rd, tmp);
P
pbrook 已提交
8462 8463 8464
            }
            break;
        case 0x03:
8465
            if (set_cc) {
8466
                gen_sub_CC(tmp, tmp2, tmp);
8467 8468 8469
            } else {
                tcg_gen_sub_i32(tmp, tmp2, tmp);
            }
8470
            store_reg_bx(s, rd, tmp);
P
pbrook 已提交
8471 8472
            break;
        case 0x04:
8473
            if (set_cc) {
8474
                gen_add_CC(tmp, tmp, tmp2);
8475 8476 8477
            } else {
                tcg_gen_add_i32(tmp, tmp, tmp2);
            }
8478
            store_reg_bx(s, rd, tmp);
P
pbrook 已提交
8479 8480
            break;
        case 0x05:
8481
            if (set_cc) {
8482
                gen_adc_CC(tmp, tmp, tmp2);
8483 8484 8485
            } else {
                gen_add_carry(tmp, tmp, tmp2);
            }
8486
            store_reg_bx(s, rd, tmp);
P
pbrook 已提交
8487 8488
            break;
        case 0x06:
8489
            if (set_cc) {
8490
                gen_sbc_CC(tmp, tmp, tmp2);
8491 8492 8493
            } else {
                gen_sub_carry(tmp, tmp, tmp2);
            }
8494
            store_reg_bx(s, rd, tmp);
P
pbrook 已提交
8495 8496
            break;
        case 0x07:
8497
            if (set_cc) {
8498
                gen_sbc_CC(tmp, tmp2, tmp);
8499 8500 8501
            } else {
                gen_sub_carry(tmp, tmp2, tmp);
            }
8502
            store_reg_bx(s, rd, tmp);
P
pbrook 已提交
8503 8504 8505
            break;
        case 0x08:
            if (set_cc) {
8506 8507
                tcg_gen_and_i32(tmp, tmp, tmp2);
                gen_logic_CC(tmp);
P
pbrook 已提交
8508
            }
8509
            tcg_temp_free_i32(tmp);
P
pbrook 已提交
8510 8511 8512
            break;
        case 0x09:
            if (set_cc) {
8513 8514
                tcg_gen_xor_i32(tmp, tmp, tmp2);
                gen_logic_CC(tmp);
P
pbrook 已提交
8515
            }
8516
            tcg_temp_free_i32(tmp);
P
pbrook 已提交
8517 8518 8519
            break;
        case 0x0a:
            if (set_cc) {
8520
                gen_sub_CC(tmp, tmp, tmp2);
P
pbrook 已提交
8521
            }
8522
            tcg_temp_free_i32(tmp);
P
pbrook 已提交
8523 8524 8525
            break;
        case 0x0b:
            if (set_cc) {
8526
                gen_add_CC(tmp, tmp, tmp2);
P
pbrook 已提交
8527
            }
8528
            tcg_temp_free_i32(tmp);
P
pbrook 已提交
8529 8530
            break;
        case 0x0c:
8531 8532 8533 8534
            tcg_gen_or_i32(tmp, tmp, tmp2);
            if (logic_cc) {
                gen_logic_CC(tmp);
            }
8535
            store_reg_bx(s, rd, tmp);
P
pbrook 已提交
8536 8537 8538 8539
            break;
        case 0x0d:
            if (logic_cc && rd == 15) {
                /* MOVS r15, ... is used for exception return.  */
8540
                if (IS_USER(s)) {
P
pbrook 已提交
8541
                    goto illegal_op;
8542 8543
                }
                gen_exception_return(s, tmp2);
P
pbrook 已提交
8544
            } else {
8545 8546 8547
                if (logic_cc) {
                    gen_logic_CC(tmp2);
                }
8548
                store_reg_bx(s, rd, tmp2);
P
pbrook 已提交
8549 8550 8551
            }
            break;
        case 0x0e:
8552
            tcg_gen_andc_i32(tmp, tmp, tmp2);
8553 8554 8555
            if (logic_cc) {
                gen_logic_CC(tmp);
            }
8556
            store_reg_bx(s, rd, tmp);
P
pbrook 已提交
8557 8558 8559
            break;
        default:
        case 0x0f:
8560 8561 8562 8563
            tcg_gen_not_i32(tmp2, tmp2);
            if (logic_cc) {
                gen_logic_CC(tmp2);
            }
8564
            store_reg_bx(s, rd, tmp2);
P
pbrook 已提交
8565 8566
            break;
        }
8567
        if (op1 != 0x0f && op1 != 0x0d) {
8568
            tcg_temp_free_i32(tmp2);
8569
        }
P
pbrook 已提交
8570 8571 8572 8573 8574 8575 8576 8577 8578 8579 8580 8581 8582 8583 8584 8585 8586 8587
    } 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 已提交
8588 8589 8590
                        tmp = load_reg(s, rs);
                        tmp2 = load_reg(s, rm);
                        tcg_gen_mul_i32(tmp, tmp, tmp2);
8591
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8592 8593 8594
                        if (insn & (1 << 22)) {
                            /* Subtract (mls) */
                            ARCH(6T2);
P
pbrook 已提交
8595 8596
                            tmp2 = load_reg(s, rn);
                            tcg_gen_sub_i32(tmp, tmp2, tmp);
8597
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8598 8599
                        } else if (insn & (1 << 21)) {
                            /* Add */
P
pbrook 已提交
8600 8601
                            tmp2 = load_reg(s, rn);
                            tcg_gen_add_i32(tmp, tmp, tmp2);
8602
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8603 8604
                        }
                        if (insn & (1 << 20))
P
pbrook 已提交
8605 8606
                            gen_logic_CC(tmp);
                        store_reg(s, rd, tmp);
P
pbrook 已提交
8607
                        break;
A
Aurelien Jarno 已提交
8608 8609 8610 8611 8612 8613 8614 8615 8616 8617 8618 8619 8620 8621
                    case 4:
                        /* 64 bit mul double accumulate (UMAAL) */
                        ARCH(6);
                        tmp = load_reg(s, rs);
                        tmp2 = load_reg(s, rm);
                        tmp64 = gen_mulu_i64_i32(tmp, tmp2);
                        gen_addq_lo(s, tmp64, rn);
                        gen_addq_lo(s, tmp64, rd);
                        gen_storeq_reg(s, rn, rd, tmp64);
                        tcg_temp_free_i64(tmp64);
                        break;
                    case 8: case 9: case 10: case 11:
                    case 12: case 13: case 14: case 15:
                        /* 64 bit mul: UMULL, UMLAL, SMULL, SMLAL. */
P
pbrook 已提交
8622 8623
                        tmp = load_reg(s, rs);
                        tmp2 = load_reg(s, rm);
A
Aurelien Jarno 已提交
8624
                        if (insn & (1 << 22)) {
8625
                            tcg_gen_muls2_i32(tmp, tmp2, tmp, tmp2);
A
Aurelien Jarno 已提交
8626
                        } else {
8627
                            tcg_gen_mulu2_i32(tmp, tmp2, tmp, tmp2);
A
Aurelien Jarno 已提交
8628 8629
                        }
                        if (insn & (1 << 21)) { /* mult accumulate */
8630 8631
                            TCGv_i32 al = load_reg(s, rn);
                            TCGv_i32 ah = load_reg(s, rd);
8632
                            tcg_gen_add2_i32(tmp, tmp2, tmp, tmp2, al, ah);
8633 8634
                            tcg_temp_free_i32(al);
                            tcg_temp_free_i32(ah);
P
pbrook 已提交
8635
                        }
A
Aurelien Jarno 已提交
8636
                        if (insn & (1 << 20)) {
8637
                            gen_logicq_cc(tmp, tmp2);
A
Aurelien Jarno 已提交
8638
                        }
8639 8640
                        store_reg(s, rn, tmp);
                        store_reg(s, rd, tmp2);
P
pbrook 已提交
8641
                        break;
A
Aurelien Jarno 已提交
8642 8643
                    default:
                        goto illegal_op;
P
pbrook 已提交
8644 8645 8646 8647 8648 8649
                    }
                } else {
                    rn = (insn >> 16) & 0xf;
                    rd = (insn >> 12) & 0xf;
                    if (insn & (1 << 23)) {
                        /* load/store exclusive */
8650
                        int op2 = (insn >> 8) & 3;
P
pbrook 已提交
8651
                        op1 = (insn >> 21) & 0x3;
8652 8653 8654 8655 8656 8657 8658 8659 8660 8661 8662 8663 8664 8665 8666 8667 8668 8669 8670 8671 8672 8673

                        switch (op2) {
                        case 0: /* lda/stl */
                            if (op1 == 1) {
                                goto illegal_op;
                            }
                            ARCH(8);
                            break;
                        case 1: /* reserved */
                            goto illegal_op;
                        case 2: /* ldaex/stlex */
                            ARCH(8);
                            break;
                        case 3: /* ldrex/strex */
                            if (op1) {
                                ARCH(6K);
                            } else {
                                ARCH(6);
                            }
                            break;
                        }

8674
                        addr = tcg_temp_local_new_i32();
8675
                        load_reg_var(s, addr, rn);
8676 8677 8678 8679 8680 8681 8682 8683 8684

                        /* Since the emulation does not have barriers,
                           the acquire/release semantics need no special
                           handling */
                        if (op2 == 0) {
                            if (insn & (1 << 20)) {
                                tmp = tcg_temp_new_i32();
                                switch (op1) {
                                case 0: /* lda */
8685 8686
                                    gen_aa32_ld32u(s, tmp, addr,
                                                   get_mem_index(s));
8687 8688
                                    break;
                                case 2: /* ldab */
8689 8690
                                    gen_aa32_ld8u(s, tmp, addr,
                                                  get_mem_index(s));
8691 8692
                                    break;
                                case 3: /* ldah */
8693 8694
                                    gen_aa32_ld16u(s, tmp, addr,
                                                   get_mem_index(s));
8695 8696 8697 8698 8699 8700 8701 8702 8703 8704
                                    break;
                                default:
                                    abort();
                                }
                                store_reg(s, rd, tmp);
                            } else {
                                rm = insn & 0xf;
                                tmp = load_reg(s, rm);
                                switch (op1) {
                                case 0: /* stl */
8705 8706
                                    gen_aa32_st32(s, tmp, addr,
                                                  get_mem_index(s));
8707 8708
                                    break;
                                case 2: /* stlb */
8709 8710
                                    gen_aa32_st8(s, tmp, addr,
                                                 get_mem_index(s));
8711 8712
                                    break;
                                case 3: /* stlh */
8713 8714
                                    gen_aa32_st16(s, tmp, addr,
                                                  get_mem_index(s));
8715 8716 8717 8718 8719 8720 8721
                                    break;
                                default:
                                    abort();
                                }
                                tcg_temp_free_i32(tmp);
                            }
                        } else if (insn & (1 << 20)) {
P
pbrook 已提交
8722 8723
                            switch (op1) {
                            case 0: /* ldrex */
P
Paul Brook 已提交
8724
                                gen_load_exclusive(s, rd, 15, addr, 2);
P
pbrook 已提交
8725 8726
                                break;
                            case 1: /* ldrexd */
P
Paul Brook 已提交
8727
                                gen_load_exclusive(s, rd, rd + 1, addr, 3);
P
pbrook 已提交
8728 8729
                                break;
                            case 2: /* ldrexb */
P
Paul Brook 已提交
8730
                                gen_load_exclusive(s, rd, 15, addr, 0);
P
pbrook 已提交
8731 8732
                                break;
                            case 3: /* ldrexh */
P
Paul Brook 已提交
8733
                                gen_load_exclusive(s, rd, 15, addr, 1);
P
pbrook 已提交
8734 8735 8736 8737
                                break;
                            default:
                                abort();
                            }
P
pbrook 已提交
8738 8739
                        } else {
                            rm = insn & 0xf;
P
pbrook 已提交
8740 8741
                            switch (op1) {
                            case 0:  /*  strex */
P
Paul Brook 已提交
8742
                                gen_store_exclusive(s, rd, rm, 15, addr, 2);
P
pbrook 已提交
8743 8744
                                break;
                            case 1: /*  strexd */
A
Aurelien Jarno 已提交
8745
                                gen_store_exclusive(s, rd, rm, rm + 1, addr, 3);
P
pbrook 已提交
8746 8747
                                break;
                            case 2: /*  strexb */
P
Paul Brook 已提交
8748
                                gen_store_exclusive(s, rd, rm, 15, addr, 0);
P
pbrook 已提交
8749 8750
                                break;
                            case 3: /* strexh */
P
Paul Brook 已提交
8751
                                gen_store_exclusive(s, rd, rm, 15, addr, 1);
P
pbrook 已提交
8752 8753 8754 8755
                                break;
                            default:
                                abort();
                            }
P
pbrook 已提交
8756
                        }
8757
                        tcg_temp_free_i32(addr);
P
pbrook 已提交
8758
                    } else {
8759 8760 8761
                        TCGv taddr;
                        TCGMemOp opc = s->be_data;

P
pbrook 已提交
8762 8763 8764 8765
                        /* SWP instruction */
                        rm = (insn) & 0xf;

                        if (insn & (1 << 22)) {
8766
                            opc |= MO_UB;
P
pbrook 已提交
8767
                        } else {
8768
                            opc |= MO_UL | MO_ALIGN;
P
pbrook 已提交
8769
                        }
8770 8771 8772

                        addr = load_reg(s, rn);
                        taddr = gen_aa32_addr(s, addr, opc);
8773
                        tcg_temp_free_i32(addr);
8774 8775 8776 8777 8778 8779

                        tmp = load_reg(s, rm);
                        tcg_gen_atomic_xchg_i32(tmp, taddr, tmp,
                                                get_mem_index(s), opc);
                        tcg_temp_free(taddr);
                        store_reg(s, rd, tmp);
P
pbrook 已提交
8780 8781 8782 8783
                    }
                }
            } else {
                int address_offset;
8784 8785
                bool load = insn & (1 << 20);
                bool doubleword = false;
P
pbrook 已提交
8786 8787 8788
                /* Misc load/store */
                rn = (insn >> 16) & 0xf;
                rd = (insn >> 12) & 0xf;
8789 8790 8791 8792 8793 8794 8795 8796 8797 8798 8799 8800

                if (!load && (sh & 2)) {
                    /* doubleword */
                    ARCH(5TE);
                    if (rd & 1) {
                        /* UNPREDICTABLE; we choose to UNDEF */
                        goto illegal_op;
                    }
                    load = (sh & 1) == 0;
                    doubleword = true;
                }

P
pbrook 已提交
8801
                addr = load_reg(s, rn);
P
pbrook 已提交
8802
                if (insn & (1 << 24))
P
pbrook 已提交
8803
                    gen_add_datah_offset(s, insn, 0, addr);
P
pbrook 已提交
8804
                address_offset = 0;
8805 8806 8807

                if (doubleword) {
                    if (!load) {
P
pbrook 已提交
8808
                        /* store */
P
pbrook 已提交
8809
                        tmp = load_reg(s, rd);
8810
                        gen_aa32_st32(s, tmp, addr, get_mem_index(s));
8811
                        tcg_temp_free_i32(tmp);
P
pbrook 已提交
8812 8813
                        tcg_gen_addi_i32(addr, addr, 4);
                        tmp = load_reg(s, rd + 1);
8814
                        gen_aa32_st32(s, tmp, addr, get_mem_index(s));
8815
                        tcg_temp_free_i32(tmp);
P
pbrook 已提交
8816 8817
                    } else {
                        /* load */
8818
                        tmp = tcg_temp_new_i32();
8819
                        gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
8820 8821
                        store_reg(s, rd, tmp);
                        tcg_gen_addi_i32(addr, addr, 4);
8822
                        tmp = tcg_temp_new_i32();
8823
                        gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
8824 8825 8826
                        rd++;
                    }
                    address_offset = -4;
8827 8828 8829 8830 8831
                } else if (load) {
                    /* load */
                    tmp = tcg_temp_new_i32();
                    switch (sh) {
                    case 1:
8832
                        gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
8833 8834
                        break;
                    case 2:
8835
                        gen_aa32_ld8s(s, tmp, addr, get_mem_index(s));
8836 8837 8838
                        break;
                    default:
                    case 3:
8839
                        gen_aa32_ld16s(s, tmp, addr, get_mem_index(s));
8840 8841
                        break;
                    }
P
pbrook 已提交
8842 8843
                } else {
                    /* store */
P
pbrook 已提交
8844
                    tmp = load_reg(s, rd);
8845
                    gen_aa32_st16(s, tmp, addr, get_mem_index(s));
8846
                    tcg_temp_free_i32(tmp);
P
pbrook 已提交
8847 8848 8849
                }
                /* Perform base writeback before the loaded value to
                   ensure correct behavior with overlapping index registers.
8850
                   ldrd with base writeback is undefined if the
P
pbrook 已提交
8851 8852
                   destination and index registers overlap.  */
                if (!(insn & (1 << 24))) {
P
pbrook 已提交
8853 8854
                    gen_add_datah_offset(s, insn, address_offset, addr);
                    store_reg(s, rn, addr);
P
pbrook 已提交
8855 8856
                } else if (insn & (1 << 21)) {
                    if (address_offset)
P
pbrook 已提交
8857 8858 8859
                        tcg_gen_addi_i32(addr, addr, address_offset);
                    store_reg(s, rn, addr);
                } else {
8860
                    tcg_temp_free_i32(addr);
P
pbrook 已提交
8861 8862 8863
                }
                if (load) {
                    /* Complete the load.  */
P
pbrook 已提交
8864
                    store_reg(s, rd, tmp);
P
pbrook 已提交
8865 8866 8867 8868 8869 8870 8871 8872 8873 8874 8875 8876 8877
                }
            }
            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 已提交
8878
                rd = (insn >> 12) & 0xf;
P
pbrook 已提交
8879 8880 8881 8882
                rs = (insn >> 8) & 0xf;
                switch ((insn >> 23) & 3) {
                case 0: /* Parallel add/subtract.  */
                    op1 = (insn >> 20) & 7;
P
pbrook 已提交
8883 8884
                    tmp = load_reg(s, rn);
                    tmp2 = load_reg(s, rm);
P
pbrook 已提交
8885 8886 8887
                    sh = (insn >> 5) & 7;
                    if ((op1 & 3) == 0 || sh == 5 || sh == 6)
                        goto illegal_op;
P
pbrook 已提交
8888
                    gen_arm_parallel_addsub(op1, sh, tmp, tmp2);
8889
                    tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8890
                    store_reg(s, rd, tmp);
P
pbrook 已提交
8891 8892 8893
                    break;
                case 1:
                    if ((insn & 0x00700020) == 0) {
B
balrog 已提交
8894
                        /* Halfword pack.  */
P
pbrook 已提交
8895 8896
                        tmp = load_reg(s, rn);
                        tmp2 = load_reg(s, rm);
P
pbrook 已提交
8897
                        shift = (insn >> 7) & 0x1f;
P
pbrook 已提交
8898 8899
                        if (insn & (1 << 6)) {
                            /* pkhtb */
8900 8901 8902
                            if (shift == 0)
                                shift = 31;
                            tcg_gen_sari_i32(tmp2, tmp2, shift);
P
pbrook 已提交
8903
                            tcg_gen_andi_i32(tmp, tmp, 0xffff0000);
P
pbrook 已提交
8904
                            tcg_gen_ext16u_i32(tmp2, tmp2);
P
pbrook 已提交
8905 8906
                        } else {
                            /* pkhbt */
8907 8908
                            if (shift)
                                tcg_gen_shli_i32(tmp2, tmp2, shift);
P
pbrook 已提交
8909
                            tcg_gen_ext16u_i32(tmp, tmp);
P
pbrook 已提交
8910 8911 8912
                            tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000);
                        }
                        tcg_gen_or_i32(tmp, tmp, tmp2);
8913
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8914
                        store_reg(s, rd, tmp);
P
pbrook 已提交
8915 8916
                    } else if ((insn & 0x00200020) == 0x00200000) {
                        /* [us]sat */
P
pbrook 已提交
8917
                        tmp = load_reg(s, rm);
P
pbrook 已提交
8918 8919 8920 8921
                        shift = (insn >> 7) & 0x1f;
                        if (insn & (1 << 6)) {
                            if (shift == 0)
                                shift = 31;
P
pbrook 已提交
8922
                            tcg_gen_sari_i32(tmp, tmp, shift);
P
pbrook 已提交
8923
                        } else {
P
pbrook 已提交
8924
                            tcg_gen_shli_i32(tmp, tmp, shift);
P
pbrook 已提交
8925 8926
                        }
                        sh = (insn >> 16) & 0x1f;
8927 8928
                        tmp2 = tcg_const_i32(sh);
                        if (insn & (1 << 22))
8929
                          gen_helper_usat(tmp, cpu_env, tmp, tmp2);
8930
                        else
8931
                          gen_helper_ssat(tmp, cpu_env, tmp, tmp2);
8932
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8933
                        store_reg(s, rd, tmp);
P
pbrook 已提交
8934 8935
                    } else if ((insn & 0x00300fe0) == 0x00200f20) {
                        /* [us]sat16 */
P
pbrook 已提交
8936
                        tmp = load_reg(s, rm);
P
pbrook 已提交
8937
                        sh = (insn >> 16) & 0x1f;
8938 8939
                        tmp2 = tcg_const_i32(sh);
                        if (insn & (1 << 22))
8940
                          gen_helper_usat16(tmp, cpu_env, tmp, tmp2);
8941
                        else
8942
                          gen_helper_ssat16(tmp, cpu_env, tmp, tmp2);
8943
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8944
                        store_reg(s, rd, tmp);
P
pbrook 已提交
8945 8946
                    } else if ((insn & 0x00700fe0) == 0x00000fa0) {
                        /* Select bytes.  */
P
pbrook 已提交
8947 8948
                        tmp = load_reg(s, rn);
                        tmp2 = load_reg(s, rm);
8949
                        tmp3 = tcg_temp_new_i32();
8950
                        tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUARMState, GE));
P
pbrook 已提交
8951
                        gen_helper_sel_flags(tmp, tmp3, tmp, tmp2);
8952 8953
                        tcg_temp_free_i32(tmp3);
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8954
                        store_reg(s, rd, tmp);
P
pbrook 已提交
8955
                    } else if ((insn & 0x000003e0) == 0x00000060) {
P
pbrook 已提交
8956
                        tmp = load_reg(s, rm);
P
pbrook 已提交
8957
                        shift = (insn >> 10) & 3;
8958
                        /* ??? In many cases it's not necessary to do a
P
pbrook 已提交
8959 8960
                           rotate, a shift is sufficient.  */
                        if (shift != 0)
8961
                            tcg_gen_rotri_i32(tmp, tmp, shift * 8);
P
pbrook 已提交
8962 8963
                        op1 = (insn >> 20) & 7;
                        switch (op1) {
P
pbrook 已提交
8964 8965 8966 8967 8968 8969
                        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 已提交
8970 8971 8972
                        default: goto illegal_op;
                        }
                        if (rn != 15) {
P
pbrook 已提交
8973
                            tmp2 = load_reg(s, rn);
P
pbrook 已提交
8974
                            if ((op1 & 3) == 0) {
P
pbrook 已提交
8975
                                gen_add16(tmp, tmp2);
P
pbrook 已提交
8976
                            } else {
P
pbrook 已提交
8977
                                tcg_gen_add_i32(tmp, tmp, tmp2);
8978
                                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8979 8980
                            }
                        }
B
balrog 已提交
8981
                        store_reg(s, rd, tmp);
P
pbrook 已提交
8982 8983
                    } else if ((insn & 0x003f0f60) == 0x003f0f20) {
                        /* rev */
P
pbrook 已提交
8984
                        tmp = load_reg(s, rm);
P
pbrook 已提交
8985 8986
                        if (insn & (1 << 22)) {
                            if (insn & (1 << 7)) {
P
pbrook 已提交
8987
                                gen_revsh(tmp);
P
pbrook 已提交
8988 8989
                            } else {
                                ARCH(6T2);
P
pbrook 已提交
8990
                                gen_helper_rbit(tmp, tmp);
P
pbrook 已提交
8991 8992 8993
                            }
                        } else {
                            if (insn & (1 << 7))
P
pbrook 已提交
8994
                                gen_rev16(tmp);
P
pbrook 已提交
8995
                            else
A
aurel32 已提交
8996
                                tcg_gen_bswap32_i32(tmp, tmp);
P
pbrook 已提交
8997
                        }
P
pbrook 已提交
8998
                        store_reg(s, rd, tmp);
P
pbrook 已提交
8999 9000 9001 9002 9003
                    } else {
                        goto illegal_op;
                    }
                    break;
                case 2: /* Multiplies (Type 3).  */
9004 9005 9006 9007 9008 9009
                    switch ((insn >> 20) & 0x7) {
                    case 5:
                        if (((insn >> 6) ^ (insn >> 7)) & 1) {
                            /* op2 not 00x or 11x : UNDEF */
                            goto illegal_op;
                        }
9010 9011
                        /* Signed multiply most significant [accumulate].
                           (SMMUL, SMMLA, SMMLS) */
9012 9013
                        tmp = load_reg(s, rm);
                        tmp2 = load_reg(s, rs);
P
pbrook 已提交
9014
                        tmp64 = gen_muls_i64_i32(tmp, tmp2);
9015

9016
                        if (rd != 15) {
9017
                            tmp = load_reg(s, rd);
P
pbrook 已提交
9018
                            if (insn & (1 << 6)) {
9019
                                tmp64 = gen_subq_msw(tmp64, tmp);
P
pbrook 已提交
9020
                            } else {
9021
                                tmp64 = gen_addq_msw(tmp64, tmp);
P
pbrook 已提交
9022 9023
                            }
                        }
9024 9025 9026 9027
                        if (insn & (1 << 5)) {
                            tcg_gen_addi_i64(tmp64, tmp64, 0x80000000u);
                        }
                        tcg_gen_shri_i64(tmp64, tmp64, 32);
9028
                        tmp = tcg_temp_new_i32();
9029
                        tcg_gen_extrl_i64_i32(tmp, tmp64);
9030
                        tcg_temp_free_i64(tmp64);
9031
                        store_reg(s, rn, tmp);
9032 9033 9034 9035 9036 9037 9038 9039 9040
                        break;
                    case 0:
                    case 4:
                        /* SMLAD, SMUAD, SMLSD, SMUSD, SMLALD, SMLSLD */
                        if (insn & (1 << 7)) {
                            goto illegal_op;
                        }
                        tmp = load_reg(s, rm);
                        tmp2 = load_reg(s, rs);
P
pbrook 已提交
9041
                        if (insn & (1 << 5))
P
pbrook 已提交
9042 9043
                            gen_swap_half(tmp2);
                        gen_smul_dual(tmp, tmp2);
P
pbrook 已提交
9044
                        if (insn & (1 << 22)) {
P
pbrook 已提交
9045
                            /* smlald, smlsld */
9046 9047
                            TCGv_i64 tmp64_2;

P
pbrook 已提交
9048
                            tmp64 = tcg_temp_new_i64();
9049
                            tmp64_2 = tcg_temp_new_i64();
P
pbrook 已提交
9050
                            tcg_gen_ext_i32_i64(tmp64, tmp);
9051
                            tcg_gen_ext_i32_i64(tmp64_2, tmp2);
9052
                            tcg_temp_free_i32(tmp);
9053 9054 9055 9056 9057 9058 9059
                            tcg_temp_free_i32(tmp2);
                            if (insn & (1 << 6)) {
                                tcg_gen_sub_i64(tmp64, tmp64, tmp64_2);
                            } else {
                                tcg_gen_add_i64(tmp64, tmp64, tmp64_2);
                            }
                            tcg_temp_free_i64(tmp64_2);
P
pbrook 已提交
9060 9061
                            gen_addq(s, tmp64, rd, rn);
                            gen_storeq_reg(s, rd, rn, tmp64);
9062
                            tcg_temp_free_i64(tmp64);
P
pbrook 已提交
9063
                        } else {
P
pbrook 已提交
9064
                            /* smuad, smusd, smlad, smlsd */
9065 9066 9067 9068 9069 9070 9071 9072 9073 9074 9075 9076
                            if (insn & (1 << 6)) {
                                /* This subtraction cannot overflow. */
                                tcg_gen_sub_i32(tmp, tmp, tmp2);
                            } else {
                                /* This addition cannot overflow 32 bits;
                                 * however it may overflow considered as a
                                 * signed operation, in which case we must set
                                 * the Q flag.
                                 */
                                gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
                            }
                            tcg_temp_free_i32(tmp2);
9077
                            if (rd != 15)
P
pbrook 已提交
9078
                              {
9079
                                tmp2 = load_reg(s, rd);
9080
                                gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
9081
                                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
9082
                              }
9083
                            store_reg(s, rn, tmp);
P
pbrook 已提交
9084
                        }
9085
                        break;
9086 9087 9088
                    case 1:
                    case 3:
                        /* SDIV, UDIV */
9089
                        if (!arm_dc_feature(s, ARM_FEATURE_ARM_DIV)) {
9090 9091 9092 9093 9094 9095 9096 9097 9098 9099 9100 9101 9102 9103 9104
                            goto illegal_op;
                        }
                        if (((insn >> 5) & 7) || (rd != 15)) {
                            goto illegal_op;
                        }
                        tmp = load_reg(s, rm);
                        tmp2 = load_reg(s, rs);
                        if (insn & (1 << 21)) {
                            gen_helper_udiv(tmp, tmp, tmp2);
                        } else {
                            gen_helper_sdiv(tmp, tmp, tmp2);
                        }
                        tcg_temp_free_i32(tmp2);
                        store_reg(s, rn, tmp);
                        break;
9105 9106
                    default:
                        goto illegal_op;
P
pbrook 已提交
9107 9108 9109 9110 9111 9112
                    }
                    break;
                case 3:
                    op1 = ((insn >> 17) & 0x38) | ((insn >> 5) & 7);
                    switch (op1) {
                    case 0: /* Unsigned sum of absolute differences.  */
P
pbrook 已提交
9113 9114 9115 9116
                        ARCH(6);
                        tmp = load_reg(s, rm);
                        tmp2 = load_reg(s, rs);
                        gen_helper_usad8(tmp, tmp, tmp2);
9117
                        tcg_temp_free_i32(tmp2);
9118 9119
                        if (rd != 15) {
                            tmp2 = load_reg(s, rd);
P
pbrook 已提交
9120
                            tcg_gen_add_i32(tmp, tmp, tmp2);
9121
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
9122
                        }
9123
                        store_reg(s, rn, tmp);
P
pbrook 已提交
9124 9125 9126 9127 9128 9129
                        break;
                    case 0x20: case 0x24: case 0x28: case 0x2c:
                        /* Bitfield insert/clear.  */
                        ARCH(6T2);
                        shift = (insn >> 7) & 0x1f;
                        i = (insn >> 16) & 0x1f;
9130 9131 9132 9133
                        if (i < shift) {
                            /* UNPREDICTABLE; we choose to UNDEF */
                            goto illegal_op;
                        }
P
pbrook 已提交
9134 9135
                        i = i + 1 - shift;
                        if (rm == 15) {
9136
                            tmp = tcg_temp_new_i32();
P
pbrook 已提交
9137
                            tcg_gen_movi_i32(tmp, 0);
P
pbrook 已提交
9138
                        } else {
P
pbrook 已提交
9139
                            tmp = load_reg(s, rm);
P
pbrook 已提交
9140 9141
                        }
                        if (i != 32) {
P
pbrook 已提交
9142
                            tmp2 = load_reg(s, rd);
9143
                            tcg_gen_deposit_i32(tmp, tmp2, tmp, shift, i);
9144
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
9145
                        }
P
pbrook 已提交
9146
                        store_reg(s, rd, tmp);
P
pbrook 已提交
9147 9148 9149
                        break;
                    case 0x12: case 0x16: case 0x1a: case 0x1e: /* sbfx */
                    case 0x32: case 0x36: case 0x3a: case 0x3e: /* ubfx */
9150
                        ARCH(6T2);
P
pbrook 已提交
9151
                        tmp = load_reg(s, rm);
P
pbrook 已提交
9152 9153 9154 9155 9156 9157
                        shift = (insn >> 7) & 0x1f;
                        i = ((insn >> 16) & 0x1f) + 1;
                        if (shift + i > 32)
                            goto illegal_op;
                        if (i < 32) {
                            if (op1 & 0x20) {
9158
                                tcg_gen_extract_i32(tmp, tmp, shift, i);
P
pbrook 已提交
9159
                            } else {
9160
                                tcg_gen_sextract_i32(tmp, tmp, shift, i);
P
pbrook 已提交
9161 9162
                            }
                        }
P
pbrook 已提交
9163
                        store_reg(s, rd, tmp);
P
pbrook 已提交
9164 9165 9166 9167 9168 9169 9170 9171 9172 9173 9174 9175 9176 9177 9178 9179 9180 9181 9182 9183 9184
                        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 已提交
9185
            tmp2 = load_reg(s, rn);
9186 9187
            if ((insn & 0x01200000) == 0x00200000) {
                /* ldrt/strt */
9188
                i = get_a32_user_mem_index(s);
9189 9190 9191
            } else {
                i = get_mem_index(s);
            }
P
pbrook 已提交
9192
            if (insn & (1 << 24))
P
pbrook 已提交
9193
                gen_add_data_offset(s, insn, tmp2);
P
pbrook 已提交
9194 9195
            if (insn & (1 << 20)) {
                /* load */
9196
                tmp = tcg_temp_new_i32();
P
pbrook 已提交
9197
                if (insn & (1 << 22)) {
9198
                    gen_aa32_ld8u(s, tmp, tmp2, i);
P
pbrook 已提交
9199
                } else {
9200
                    gen_aa32_ld32u(s, tmp, tmp2, i);
P
pbrook 已提交
9201 9202 9203
                }
            } else {
                /* store */
P
pbrook 已提交
9204
                tmp = load_reg(s, rd);
9205
                if (insn & (1 << 22)) {
9206
                    gen_aa32_st8(s, tmp, tmp2, i);
9207
                } else {
9208
                    gen_aa32_st32(s, tmp, tmp2, i);
9209 9210
                }
                tcg_temp_free_i32(tmp);
P
pbrook 已提交
9211 9212
            }
            if (!(insn & (1 << 24))) {
P
pbrook 已提交
9213 9214 9215 9216 9217
                gen_add_data_offset(s, insn, tmp2);
                store_reg(s, rn, tmp2);
            } else if (insn & (1 << 21)) {
                store_reg(s, rn, tmp2);
            } else {
9218
                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
9219 9220 9221
            }
            if (insn & (1 << 20)) {
                /* Complete the load.  */
9222
                store_reg_from_load(s, rd, tmp);
P
pbrook 已提交
9223 9224 9225 9226 9227
            }
            break;
        case 0x08:
        case 0x09:
            {
9228 9229 9230 9231
                int j, n, loaded_base;
                bool exc_return = false;
                bool is_load = extract32(insn, 20, 1);
                bool user = false;
9232
                TCGv_i32 loaded_var;
P
pbrook 已提交
9233 9234 9235
                /* load/store multiple words */
                /* XXX: store correct base if write back */
                if (insn & (1 << 22)) {
9236
                    /* LDM (user), LDM (exception return) and STM (user) */
P
pbrook 已提交
9237 9238 9239
                    if (IS_USER(s))
                        goto illegal_op; /* only usable in supervisor mode */

9240 9241 9242 9243 9244
                    if (is_load && extract32(insn, 15, 1)) {
                        exc_return = true;
                    } else {
                        user = true;
                    }
P
pbrook 已提交
9245 9246
                }
                rn = (insn >> 16) & 0xf;
P
pbrook 已提交
9247
                addr = load_reg(s, rn);
P
pbrook 已提交
9248 9249 9250

                /* compute total size */
                loaded_base = 0;
9251
                TCGV_UNUSED_I32(loaded_var);
P
pbrook 已提交
9252 9253 9254 9255 9256 9257 9258 9259 9260
                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 已提交
9261
                        tcg_gen_addi_i32(addr, addr, 4);
P
pbrook 已提交
9262 9263 9264 9265 9266 9267
                    } else {
                        /* post increment */
                    }
                } else {
                    if (insn & (1 << 24)) {
                        /* pre decrement */
P
pbrook 已提交
9268
                        tcg_gen_addi_i32(addr, addr, -(n * 4));
P
pbrook 已提交
9269 9270 9271
                    } else {
                        /* post decrement */
                        if (n != 1)
P
pbrook 已提交
9272
                        tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
P
pbrook 已提交
9273 9274 9275 9276 9277
                    }
                }
                j = 0;
                for(i=0;i<16;i++) {
                    if (insn & (1 << i)) {
9278
                        if (is_load) {
P
pbrook 已提交
9279
                            /* load */
9280
                            tmp = tcg_temp_new_i32();
9281
                            gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
9282
                            if (user) {
9283
                                tmp2 = tcg_const_i32(i);
B
Blue Swirl 已提交
9284
                                gen_helper_set_user_reg(cpu_env, tmp2, tmp);
9285
                                tcg_temp_free_i32(tmp2);
9286
                                tcg_temp_free_i32(tmp);
P
pbrook 已提交
9287
                            } else if (i == rn) {
P
pbrook 已提交
9288
                                loaded_var = tmp;
P
pbrook 已提交
9289
                                loaded_base = 1;
9290 9291
                            } else if (rn == 15 && exc_return) {
                                store_pc_exc_ret(s, tmp);
P
pbrook 已提交
9292
                            } else {
9293
                                store_reg_from_load(s, i, tmp);
P
pbrook 已提交
9294 9295 9296 9297 9298 9299
                            }
                        } else {
                            /* store */
                            if (i == 15) {
                                /* special case: r15 = PC + 8 */
                                val = (long)s->pc + 4;
9300
                                tmp = tcg_temp_new_i32();
P
pbrook 已提交
9301
                                tcg_gen_movi_i32(tmp, val);
P
pbrook 已提交
9302
                            } else if (user) {
9303
                                tmp = tcg_temp_new_i32();
9304
                                tmp2 = tcg_const_i32(i);
9305
                                gen_helper_get_user_reg(tmp, cpu_env, tmp2);
9306
                                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
9307
                            } else {
P
pbrook 已提交
9308
                                tmp = load_reg(s, i);
P
pbrook 已提交
9309
                            }
9310
                            gen_aa32_st32(s, tmp, addr, get_mem_index(s));
9311
                            tcg_temp_free_i32(tmp);
P
pbrook 已提交
9312 9313 9314 9315
                        }
                        j++;
                        /* no need to add after the last transfer */
                        if (j != n)
P
pbrook 已提交
9316
                            tcg_gen_addi_i32(addr, addr, 4);
P
pbrook 已提交
9317 9318 9319 9320 9321 9322 9323 9324 9325
                    }
                }
                if (insn & (1 << 21)) {
                    /* write back */
                    if (insn & (1 << 23)) {
                        if (insn & (1 << 24)) {
                            /* pre increment */
                        } else {
                            /* post increment */
P
pbrook 已提交
9326
                            tcg_gen_addi_i32(addr, addr, 4);
P
pbrook 已提交
9327 9328 9329 9330 9331
                        }
                    } else {
                        if (insn & (1 << 24)) {
                            /* pre decrement */
                            if (n != 1)
P
pbrook 已提交
9332
                                tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
P
pbrook 已提交
9333 9334
                        } else {
                            /* post decrement */
P
pbrook 已提交
9335
                            tcg_gen_addi_i32(addr, addr, -(n * 4));
P
pbrook 已提交
9336 9337
                        }
                    }
P
pbrook 已提交
9338 9339
                    store_reg(s, rn, addr);
                } else {
9340
                    tcg_temp_free_i32(addr);
P
pbrook 已提交
9341 9342
                }
                if (loaded_base) {
P
pbrook 已提交
9343
                    store_reg(s, rn, loaded_var);
P
pbrook 已提交
9344
                }
9345
                if (exc_return) {
P
pbrook 已提交
9346
                    /* Restore CPSR from SPSR.  */
P
pbrook 已提交
9347
                    tmp = load_cpu_field(spsr);
9348
                    gen_helper_cpsr_write_eret(cpu_env, tmp);
9349
                    tcg_temp_free_i32(tmp);
9350
                    s->is_jmp = DISAS_JUMP;
P
pbrook 已提交
9351 9352 9353 9354 9355 9356 9357 9358 9359 9360 9361
                }
            }
            break;
        case 0xa:
        case 0xb:
            {
                int32_t offset;

                /* branch (and link) */
                val = (int32_t)s->pc;
                if (insn & (1 << 24)) {
9362
                    tmp = tcg_temp_new_i32();
P
pbrook 已提交
9363 9364
                    tcg_gen_movi_i32(tmp, val);
                    store_reg(s, 14, tmp);
P
pbrook 已提交
9365
                }
9366 9367
                offset = sextract32(insn << 2, 0, 26);
                val += offset + 4;
P
pbrook 已提交
9368 9369 9370 9371 9372 9373
                gen_jmp(s, val);
            }
            break;
        case 0xc:
        case 0xd:
        case 0xe:
9374 9375
            if (((insn >> 8) & 0xe) == 10) {
                /* VFP.  */
9376
                if (disas_vfp_insn(s, insn)) {
9377 9378
                    goto illegal_op;
                }
9379
            } else if (disas_coproc_insn(s, insn)) {
9380
                /* Coprocessor.  */
P
pbrook 已提交
9381
                goto illegal_op;
9382
            }
P
pbrook 已提交
9383 9384 9385
            break;
        case 0xf:
            /* swi */
9386
            gen_set_pc_im(s, s->pc);
9387
            s->svc_imm = extract32(insn, 0, 24);
P
pbrook 已提交
9388 9389 9390 9391
            s->is_jmp = DISAS_SWI;
            break;
        default:
        illegal_op:
9392 9393
            gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized(),
                               default_exception_el(s));
P
pbrook 已提交
9394 9395 9396 9397 9398 9399 9400 9401 9402 9403 9404 9405 9406 9407 9408 9409 9410 9411 9412
            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
9413 9414
gen_thumb2_data_op(DisasContext *s, int op, int conds, uint32_t shifter_out,
                   TCGv_i32 t0, TCGv_i32 t1)
P
pbrook 已提交
9415 9416 9417 9418 9419 9420
{
    int logic_cc;

    logic_cc = 0;
    switch (op) {
    case 0: /* and */
9421
        tcg_gen_and_i32(t0, t0, t1);
P
pbrook 已提交
9422 9423 9424
        logic_cc = conds;
        break;
    case 1: /* bic */
9425
        tcg_gen_andc_i32(t0, t0, t1);
P
pbrook 已提交
9426 9427 9428
        logic_cc = conds;
        break;
    case 2: /* orr */
9429
        tcg_gen_or_i32(t0, t0, t1);
P
pbrook 已提交
9430 9431 9432
        logic_cc = conds;
        break;
    case 3: /* orn */
9433
        tcg_gen_orc_i32(t0, t0, t1);
P
pbrook 已提交
9434 9435 9436
        logic_cc = conds;
        break;
    case 4: /* eor */
9437
        tcg_gen_xor_i32(t0, t0, t1);
P
pbrook 已提交
9438 9439 9440 9441
        logic_cc = conds;
        break;
    case 8: /* add */
        if (conds)
9442
            gen_add_CC(t0, t0, t1);
P
pbrook 已提交
9443
        else
9444
            tcg_gen_add_i32(t0, t0, t1);
P
pbrook 已提交
9445 9446 9447
        break;
    case 10: /* adc */
        if (conds)
9448
            gen_adc_CC(t0, t0, t1);
P
pbrook 已提交
9449
        else
9450
            gen_adc(t0, t1);
P
pbrook 已提交
9451 9452
        break;
    case 11: /* sbc */
9453 9454 9455
        if (conds) {
            gen_sbc_CC(t0, t0, t1);
        } else {
9456
            gen_sub_carry(t0, t0, t1);
9457
        }
P
pbrook 已提交
9458 9459 9460
        break;
    case 13: /* sub */
        if (conds)
9461
            gen_sub_CC(t0, t0, t1);
P
pbrook 已提交
9462
        else
9463
            tcg_gen_sub_i32(t0, t0, t1);
P
pbrook 已提交
9464 9465 9466
        break;
    case 14: /* rsb */
        if (conds)
9467
            gen_sub_CC(t0, t1, t0);
P
pbrook 已提交
9468
        else
9469
            tcg_gen_sub_i32(t0, t1, t0);
P
pbrook 已提交
9470 9471 9472 9473 9474
        break;
    default: /* 5, 6, 7, 9, 12, 15. */
        return 1;
    }
    if (logic_cc) {
9475
        gen_logic_CC(t0);
P
pbrook 已提交
9476
        if (shifter_out)
9477
            gen_set_CF_bit31(t1);
P
pbrook 已提交
9478 9479 9480 9481 9482 9483
    }
    return 0;
}

/* Translate a 32-bit thumb instruction.  Returns nonzero if the instruction
   is not legal.  */
9484
static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw1)
P
pbrook 已提交
9485
{
P
pbrook 已提交
9486
    uint32_t insn, imm, shift, offset;
P
pbrook 已提交
9487
    uint32_t rd, rn, rm, rs;
9488 9489 9490 9491
    TCGv_i32 tmp;
    TCGv_i32 tmp2;
    TCGv_i32 tmp3;
    TCGv_i32 addr;
P
pbrook 已提交
9492
    TCGv_i64 tmp64;
P
pbrook 已提交
9493 9494 9495 9496 9497
    int op;
    int shiftop;
    int conds;
    int logic_cc;

9498 9499
    if (!(arm_dc_feature(s, ARM_FEATURE_THUMB2)
          || arm_dc_feature(s, ARM_FEATURE_M))) {
9500
        /* Thumb-1 cores may need to treat bl and blx as a pair of
P
pbrook 已提交
9501 9502 9503
           16-bit instructions to get correct prefetch abort behavior.  */
        insn = insn_hw1;
        if ((insn & (1 << 12)) == 0) {
9504
            ARCH(5);
P
pbrook 已提交
9505 9506
            /* Second half of blx.  */
            offset = ((insn & 0x7ff) << 1);
P
pbrook 已提交
9507 9508 9509
            tmp = load_reg(s, 14);
            tcg_gen_addi_i32(tmp, tmp, offset);
            tcg_gen_andi_i32(tmp, tmp, 0xfffffffc);
P
pbrook 已提交
9510

9511
            tmp2 = tcg_temp_new_i32();
P
pbrook 已提交
9512
            tcg_gen_movi_i32(tmp2, s->pc | 1);
P
pbrook 已提交
9513 9514
            store_reg(s, 14, tmp2);
            gen_bx(s, tmp);
P
pbrook 已提交
9515 9516 9517 9518 9519
            return 0;
        }
        if (insn & (1 << 11)) {
            /* Second half of bl.  */
            offset = ((insn & 0x7ff) << 1) | 1;
P
pbrook 已提交
9520
            tmp = load_reg(s, 14);
B
balrog 已提交
9521
            tcg_gen_addi_i32(tmp, tmp, offset);
P
pbrook 已提交
9522

9523
            tmp2 = tcg_temp_new_i32();
P
pbrook 已提交
9524
            tcg_gen_movi_i32(tmp2, s->pc | 1);
P
pbrook 已提交
9525 9526
            store_reg(s, 14, tmp2);
            gen_bx(s, tmp);
P
pbrook 已提交
9527 9528 9529 9530 9531 9532 9533
            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;
9534
            tcg_gen_movi_i32(cpu_R[14], s->pc + 2 + offset);
P
pbrook 已提交
9535 9536 9537 9538 9539
            return 0;
        }
        /* Fall through to 32-bit decode.  */
    }

9540
    insn = arm_lduw_code(env, s->pc, s->sctlr_b);
P
pbrook 已提交
9541 9542 9543 9544 9545 9546 9547 9548 9549 9550 9551 9552 9553 9554 9555 9556 9557 9558 9559 9560 9561
    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) {
9562
                    addr = tcg_temp_new_i32();
P
pbrook 已提交
9563
                    tcg_gen_movi_i32(addr, s->pc & ~3);
P
pbrook 已提交
9564
                } else {
P
pbrook 已提交
9565
                    addr = load_reg(s, rn);
P
pbrook 已提交
9566 9567 9568 9569 9570
                }
                offset = (insn & 0xff) * 4;
                if ((insn & (1 << 23)) == 0)
                    offset = -offset;
                if (insn & (1 << 24)) {
P
pbrook 已提交
9571
                    tcg_gen_addi_i32(addr, addr, offset);
P
pbrook 已提交
9572 9573 9574 9575
                    offset = 0;
                }
                if (insn & (1 << 20)) {
                    /* ldrd */
9576
                    tmp = tcg_temp_new_i32();
9577
                    gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
9578 9579
                    store_reg(s, rs, tmp);
                    tcg_gen_addi_i32(addr, addr, 4);
9580
                    tmp = tcg_temp_new_i32();
9581
                    gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
9582
                    store_reg(s, rd, tmp);
P
pbrook 已提交
9583 9584
                } else {
                    /* strd */
P
pbrook 已提交
9585
                    tmp = load_reg(s, rs);
9586
                    gen_aa32_st32(s, tmp, addr, get_mem_index(s));
9587
                    tcg_temp_free_i32(tmp);
P
pbrook 已提交
9588 9589
                    tcg_gen_addi_i32(addr, addr, 4);
                    tmp = load_reg(s, rd);
9590
                    gen_aa32_st32(s, tmp, addr, get_mem_index(s));
9591
                    tcg_temp_free_i32(tmp);
P
pbrook 已提交
9592 9593 9594 9595 9596
                }
                if (insn & (1 << 21)) {
                    /* Base writeback.  */
                    if (rn == 15)
                        goto illegal_op;
P
pbrook 已提交
9597 9598 9599
                    tcg_gen_addi_i32(addr, addr, offset - 4);
                    store_reg(s, rn, addr);
                } else {
9600
                    tcg_temp_free_i32(addr);
P
pbrook 已提交
9601 9602 9603
                }
            } else if ((insn & (1 << 23)) == 0) {
                /* Load/store exclusive word.  */
9604
                addr = tcg_temp_local_new_i32();
9605
                load_reg_var(s, addr, rn);
P
Paul Brook 已提交
9606
                tcg_gen_addi_i32(addr, addr, (insn & 0xff) << 2);
B
bellard 已提交
9607
                if (insn & (1 << 20)) {
P
Paul Brook 已提交
9608
                    gen_load_exclusive(s, rs, 15, addr, 2);
P
pbrook 已提交
9609
                } else {
P
Paul Brook 已提交
9610
                    gen_store_exclusive(s, rd, rs, 15, addr, 2);
P
pbrook 已提交
9611
                }
9612
                tcg_temp_free_i32(addr);
9613
            } else if ((insn & (7 << 5)) == 0) {
P
pbrook 已提交
9614 9615
                /* Table Branch.  */
                if (rn == 15) {
9616
                    addr = tcg_temp_new_i32();
P
pbrook 已提交
9617
                    tcg_gen_movi_i32(addr, s->pc);
P
pbrook 已提交
9618
                } else {
P
pbrook 已提交
9619
                    addr = load_reg(s, rn);
P
pbrook 已提交
9620
                }
P
pbrook 已提交
9621
                tmp = load_reg(s, rm);
P
pbrook 已提交
9622
                tcg_gen_add_i32(addr, addr, tmp);
P
pbrook 已提交
9623 9624
                if (insn & (1 << 4)) {
                    /* tbh */
P
pbrook 已提交
9625
                    tcg_gen_add_i32(addr, addr, tmp);
9626
                    tcg_temp_free_i32(tmp);
9627
                    tmp = tcg_temp_new_i32();
9628
                    gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
9629
                } else { /* tbb */
9630
                    tcg_temp_free_i32(tmp);
9631
                    tmp = tcg_temp_new_i32();
9632
                    gen_aa32_ld8u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
9633
                }
9634
                tcg_temp_free_i32(addr);
P
pbrook 已提交
9635 9636 9637
                tcg_gen_shli_i32(tmp, tmp, 1);
                tcg_gen_addi_i32(tmp, tmp, s->pc);
                store_reg(s, 15, tmp);
P
pbrook 已提交
9638
            } else {
9639
                int op2 = (insn >> 6) & 0x3;
P
pbrook 已提交
9640
                op = (insn >> 4) & 0x3;
9641 9642
                switch (op2) {
                case 0:
P
Paul Brook 已提交
9643
                    goto illegal_op;
9644 9645 9646 9647 9648 9649 9650 9651 9652 9653 9654 9655 9656 9657 9658 9659 9660
                case 1:
                    /* Load/store exclusive byte/halfword/doubleword */
                    if (op == 2) {
                        goto illegal_op;
                    }
                    ARCH(7);
                    break;
                case 2:
                    /* Load-acquire/store-release */
                    if (op == 3) {
                        goto illegal_op;
                    }
                    /* Fall through */
                case 3:
                    /* Load-acquire/store-release exclusive */
                    ARCH(8);
                    break;
P
Paul Brook 已提交
9661
                }
9662
                addr = tcg_temp_local_new_i32();
9663
                load_reg_var(s, addr, rn);
9664 9665 9666 9667 9668
                if (!(op2 & 1)) {
                    if (insn & (1 << 20)) {
                        tmp = tcg_temp_new_i32();
                        switch (op) {
                        case 0: /* ldab */
9669
                            gen_aa32_ld8u(s, tmp, addr, get_mem_index(s));
9670 9671
                            break;
                        case 1: /* ldah */
9672
                            gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
9673 9674
                            break;
                        case 2: /* lda */
9675
                            gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
9676 9677 9678 9679 9680 9681 9682 9683 9684
                            break;
                        default:
                            abort();
                        }
                        store_reg(s, rs, tmp);
                    } else {
                        tmp = load_reg(s, rs);
                        switch (op) {
                        case 0: /* stlb */
9685
                            gen_aa32_st8(s, tmp, addr, get_mem_index(s));
9686 9687
                            break;
                        case 1: /* stlh */
9688
                            gen_aa32_st16(s, tmp, addr, get_mem_index(s));
9689 9690
                            break;
                        case 2: /* stl */
9691
                            gen_aa32_st32(s, tmp, addr, get_mem_index(s));
9692 9693 9694 9695 9696 9697 9698
                            break;
                        default:
                            abort();
                        }
                        tcg_temp_free_i32(tmp);
                    }
                } else if (insn & (1 << 20)) {
P
Paul Brook 已提交
9699
                    gen_load_exclusive(s, rs, rd, addr, op);
P
pbrook 已提交
9700
                } else {
P
Paul Brook 已提交
9701
                    gen_store_exclusive(s, rm, rs, rd, addr, op);
P
pbrook 已提交
9702
                }
9703
                tcg_temp_free_i32(addr);
P
pbrook 已提交
9704 9705 9706 9707
            }
        } else {
            /* Load/store multiple, RFE, SRS.  */
            if (((insn >> 23) & 1) == ((insn >> 24) & 1)) {
9708
                /* RFE, SRS: not available in user mode or on M profile */
9709
                if (IS_USER(s) || arm_dc_feature(s, ARM_FEATURE_M)) {
P
pbrook 已提交
9710
                    goto illegal_op;
9711
                }
P
pbrook 已提交
9712 9713
                if (insn & (1 << 20)) {
                    /* rfe */
P
pbrook 已提交
9714 9715 9716 9717
                    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.  */
9718
                    tmp = tcg_temp_new_i32();
9719
                    gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
9720
                    tcg_gen_addi_i32(addr, addr, 4);
9721
                    tmp2 = tcg_temp_new_i32();
9722
                    gen_aa32_ld32u(s, tmp2, addr, get_mem_index(s));
P
pbrook 已提交
9723 9724
                    if (insn & (1 << 21)) {
                        /* Base writeback.  */
P
pbrook 已提交
9725 9726 9727 9728 9729 9730 9731
                        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 {
9732
                        tcg_temp_free_i32(addr);
P
pbrook 已提交
9733
                    }
P
pbrook 已提交
9734
                    gen_rfe(s, tmp, tmp2);
P
pbrook 已提交
9735 9736
                } else {
                    /* srs */
9737 9738
                    gen_srs(s, (insn & 0x1f), (insn & (1 << 24)) ? 1 : 2,
                            insn & (1 << 21));
P
pbrook 已提交
9739 9740
                }
            } else {
9741
                int i, loaded_base = 0;
9742
                TCGv_i32 loaded_var;
P
pbrook 已提交
9743
                /* Load/store multiple.  */
P
pbrook 已提交
9744
                addr = load_reg(s, rn);
P
pbrook 已提交
9745 9746 9747 9748 9749 9750
                offset = 0;
                for (i = 0; i < 16; i++) {
                    if (insn & (1 << i))
                        offset += 4;
                }
                if (insn & (1 << 24)) {
P
pbrook 已提交
9751
                    tcg_gen_addi_i32(addr, addr, -offset);
P
pbrook 已提交
9752 9753
                }

9754
                TCGV_UNUSED_I32(loaded_var);
P
pbrook 已提交
9755 9756 9757 9758 9759
                for (i = 0; i < 16; i++) {
                    if ((insn & (1 << i)) == 0)
                        continue;
                    if (insn & (1 << 20)) {
                        /* Load.  */
9760
                        tmp = tcg_temp_new_i32();
9761
                        gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
9762
                        if (i == 15) {
P
pbrook 已提交
9763
                            gen_bx(s, tmp);
9764 9765 9766
                        } else if (i == rn) {
                            loaded_var = tmp;
                            loaded_base = 1;
P
pbrook 已提交
9767
                        } else {
P
pbrook 已提交
9768
                            store_reg(s, i, tmp);
P
pbrook 已提交
9769 9770 9771
                        }
                    } else {
                        /* Store.  */
P
pbrook 已提交
9772
                        tmp = load_reg(s, i);
9773
                        gen_aa32_st32(s, tmp, addr, get_mem_index(s));
9774
                        tcg_temp_free_i32(tmp);
P
pbrook 已提交
9775
                    }
P
pbrook 已提交
9776
                    tcg_gen_addi_i32(addr, addr, 4);
P
pbrook 已提交
9777
                }
9778 9779 9780
                if (loaded_base) {
                    store_reg(s, rn, loaded_var);
                }
P
pbrook 已提交
9781 9782 9783
                if (insn & (1 << 21)) {
                    /* Base register writeback.  */
                    if (insn & (1 << 24)) {
P
pbrook 已提交
9784
                        tcg_gen_addi_i32(addr, addr, -offset);
P
pbrook 已提交
9785 9786 9787 9788
                    }
                    /* Fault if writeback register is in register list.  */
                    if (insn & (1 << rn))
                        goto illegal_op;
P
pbrook 已提交
9789 9790
                    store_reg(s, rn, addr);
                } else {
9791
                    tcg_temp_free_i32(addr);
P
pbrook 已提交
9792 9793 9794 9795
                }
            }
        }
        break;
9796 9797
    case 5:

P
pbrook 已提交
9798
        op = (insn >> 21) & 0xf;
9799
        if (op == 6) {
9800 9801 9802
            if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
                goto illegal_op;
            }
9803 9804 9805 9806 9807 9808 9809 9810 9811 9812 9813 9814 9815 9816 9817 9818 9819 9820 9821
            /* Halfword pack.  */
            tmp = load_reg(s, rn);
            tmp2 = load_reg(s, rm);
            shift = ((insn >> 10) & 0x1c) | ((insn >> 6) & 0x3);
            if (insn & (1 << 5)) {
                /* pkhtb */
                if (shift == 0)
                    shift = 31;
                tcg_gen_sari_i32(tmp2, tmp2, shift);
                tcg_gen_andi_i32(tmp, tmp, 0xffff0000);
                tcg_gen_ext16u_i32(tmp2, tmp2);
            } else {
                /* pkhbt */
                if (shift)
                    tcg_gen_shli_i32(tmp2, tmp2, shift);
                tcg_gen_ext16u_i32(tmp, tmp);
                tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000);
            }
            tcg_gen_or_i32(tmp, tmp, tmp2);
9822
            tcg_temp_free_i32(tmp2);
9823 9824
            store_reg(s, rd, tmp);
        } else {
9825 9826
            /* Data processing register constant shift.  */
            if (rn == 15) {
9827
                tmp = tcg_temp_new_i32();
9828 9829 9830 9831 9832 9833 9834 9835 9836 9837 9838 9839 9840
                tcg_gen_movi_i32(tmp, 0);
            } else {
                tmp = load_reg(s, rn);
            }
            tmp2 = load_reg(s, rm);

            shiftop = (insn >> 4) & 3;
            shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c);
            conds = (insn & (1 << 20)) != 0;
            logic_cc = (conds && thumb2_logic_op(op));
            gen_arm_shift_im(tmp2, shiftop, shift, logic_cc);
            if (gen_thumb2_data_op(s, op, conds, 0, tmp, tmp2))
                goto illegal_op;
9841
            tcg_temp_free_i32(tmp2);
9842 9843 9844
            if (rd != 15) {
                store_reg(s, rd, tmp);
            } else {
9845
                tcg_temp_free_i32(tmp);
9846
            }
9847
        }
P
pbrook 已提交
9848 9849 9850 9851 9852 9853 9854
        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 已提交
9855 9856
            tmp = load_reg(s, rn);
            tmp2 = load_reg(s, rm);
P
pbrook 已提交
9857 9858 9859
            if ((insn & 0x70) != 0)
                goto illegal_op;
            op = (insn >> 21) & 3;
P
pbrook 已提交
9860 9861 9862 9863
            logic_cc = (insn & (1 << 20)) != 0;
            gen_arm_shift_reg(tmp, op, tmp2, logic_cc);
            if (logic_cc)
                gen_logic_CC(tmp);
9864
            store_reg_bx(s, rd, tmp);
P
pbrook 已提交
9865 9866
            break;
        case 1: /* Sign/zero extend.  */
9867 9868 9869 9870 9871 9872 9873 9874 9875 9876 9877 9878 9879 9880 9881 9882 9883 9884 9885 9886 9887
            op = (insn >> 20) & 7;
            switch (op) {
            case 0: /* SXTAH, SXTH */
            case 1: /* UXTAH, UXTH */
            case 4: /* SXTAB, SXTB */
            case 5: /* UXTAB, UXTB */
                break;
            case 2: /* SXTAB16, SXTB16 */
            case 3: /* UXTAB16, UXTB16 */
                if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
                    goto illegal_op;
                }
                break;
            default:
                goto illegal_op;
            }
            if (rn != 15) {
                if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
                    goto illegal_op;
                }
            }
P
pbrook 已提交
9888
            tmp = load_reg(s, rm);
P
pbrook 已提交
9889
            shift = (insn >> 4) & 3;
9890
            /* ??? In many cases it's not necessary to do a
P
pbrook 已提交
9891 9892
               rotate, a shift is sufficient.  */
            if (shift != 0)
9893
                tcg_gen_rotri_i32(tmp, tmp, shift * 8);
P
pbrook 已提交
9894 9895
            op = (insn >> 20) & 7;
            switch (op) {
P
pbrook 已提交
9896 9897 9898 9899 9900 9901
            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;
9902 9903
            default:
                g_assert_not_reached();
P
pbrook 已提交
9904 9905
            }
            if (rn != 15) {
P
pbrook 已提交
9906
                tmp2 = load_reg(s, rn);
P
pbrook 已提交
9907
                if ((op >> 1) == 1) {
P
pbrook 已提交
9908
                    gen_add16(tmp, tmp2);
P
pbrook 已提交
9909
                } else {
P
pbrook 已提交
9910
                    tcg_gen_add_i32(tmp, tmp, tmp2);
9911
                    tcg_temp_free_i32(tmp2);
P
pbrook 已提交
9912 9913
                }
            }
P
pbrook 已提交
9914
            store_reg(s, rd, tmp);
P
pbrook 已提交
9915 9916
            break;
        case 2: /* SIMD add/subtract.  */
9917 9918 9919
            if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
                goto illegal_op;
            }
P
pbrook 已提交
9920 9921 9922 9923
            op = (insn >> 20) & 7;
            shift = (insn >> 4) & 7;
            if ((op & 3) == 3 || (shift & 3) == 3)
                goto illegal_op;
P
pbrook 已提交
9924 9925 9926
            tmp = load_reg(s, rn);
            tmp2 = load_reg(s, rm);
            gen_thumb2_parallel_addsub(op, shift, tmp, tmp2);
9927
            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
9928
            store_reg(s, rd, tmp);
P
pbrook 已提交
9929 9930 9931 9932 9933
            break;
        case 3: /* Other data processing.  */
            op = ((insn >> 17) & 0x38) | ((insn >> 4) & 7);
            if (op < 4) {
                /* Saturating add/subtract.  */
9934 9935 9936
                if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
                    goto illegal_op;
                }
P
pbrook 已提交
9937 9938
                tmp = load_reg(s, rn);
                tmp2 = load_reg(s, rm);
P
pbrook 已提交
9939
                if (op & 1)
9940
                    gen_helper_double_saturate(tmp, cpu_env, tmp);
9941
                if (op & 2)
9942
                    gen_helper_sub_saturate(tmp, cpu_env, tmp2, tmp);
P
pbrook 已提交
9943
                else
9944
                    gen_helper_add_saturate(tmp, cpu_env, tmp, tmp2);
9945
                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
9946
            } else {
9947 9948 9949 9950 9951 9952 9953 9954 9955 9956 9957 9958 9959 9960 9961 9962 9963 9964 9965 9966 9967 9968 9969 9970 9971
                switch (op) {
                case 0x0a: /* rbit */
                case 0x08: /* rev */
                case 0x09: /* rev16 */
                case 0x0b: /* revsh */
                case 0x18: /* clz */
                    break;
                case 0x10: /* sel */
                    if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
                        goto illegal_op;
                    }
                    break;
                case 0x20: /* crc32/crc32c */
                case 0x21:
                case 0x22:
                case 0x28:
                case 0x29:
                case 0x2a:
                    if (!arm_dc_feature(s, ARM_FEATURE_CRC)) {
                        goto illegal_op;
                    }
                    break;
                default:
                    goto illegal_op;
                }
P
pbrook 已提交
9972
                tmp = load_reg(s, rn);
P
pbrook 已提交
9973 9974
                switch (op) {
                case 0x0a: /* rbit */
P
pbrook 已提交
9975
                    gen_helper_rbit(tmp, tmp);
P
pbrook 已提交
9976 9977
                    break;
                case 0x08: /* rev */
A
aurel32 已提交
9978
                    tcg_gen_bswap32_i32(tmp, tmp);
P
pbrook 已提交
9979 9980
                    break;
                case 0x09: /* rev16 */
P
pbrook 已提交
9981
                    gen_rev16(tmp);
P
pbrook 已提交
9982 9983
                    break;
                case 0x0b: /* revsh */
P
pbrook 已提交
9984
                    gen_revsh(tmp);
P
pbrook 已提交
9985 9986
                    break;
                case 0x10: /* sel */
P
pbrook 已提交
9987
                    tmp2 = load_reg(s, rm);
9988
                    tmp3 = tcg_temp_new_i32();
9989
                    tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUARMState, GE));
P
pbrook 已提交
9990
                    gen_helper_sel_flags(tmp, tmp3, tmp, tmp2);
9991 9992
                    tcg_temp_free_i32(tmp3);
                    tcg_temp_free_i32(tmp2);
P
pbrook 已提交
9993 9994
                    break;
                case 0x18: /* clz */
R
Richard Henderson 已提交
9995
                    tcg_gen_clzi_i32(tmp, tmp, 32);
P
pbrook 已提交
9996
                    break;
9997 9998 9999 10000 10001 10002 10003 10004 10005 10006 10007 10008
                case 0x20:
                case 0x21:
                case 0x22:
                case 0x28:
                case 0x29:
                case 0x2a:
                {
                    /* crc32/crc32c */
                    uint32_t sz = op & 0x3;
                    uint32_t c = op & 0x8;

                    tmp2 = load_reg(s, rm);
10009 10010 10011 10012 10013
                    if (sz == 0) {
                        tcg_gen_andi_i32(tmp2, tmp2, 0xff);
                    } else if (sz == 1) {
                        tcg_gen_andi_i32(tmp2, tmp2, 0xffff);
                    }
10014 10015 10016 10017 10018 10019 10020 10021 10022 10023
                    tmp3 = tcg_const_i32(1 << sz);
                    if (c) {
                        gen_helper_crc32c(tmp, tmp, tmp2, tmp3);
                    } else {
                        gen_helper_crc32(tmp, tmp, tmp2, tmp3);
                    }
                    tcg_temp_free_i32(tmp2);
                    tcg_temp_free_i32(tmp3);
                    break;
                }
P
pbrook 已提交
10024
                default:
10025
                    g_assert_not_reached();
P
pbrook 已提交
10026 10027
                }
            }
P
pbrook 已提交
10028
            store_reg(s, rd, tmp);
P
pbrook 已提交
10029 10030
            break;
        case 4: case 5: /* 32-bit multiply.  Sum of absolute differences.  */
10031 10032 10033 10034 10035 10036 10037 10038 10039 10040 10041 10042 10043 10044
            switch ((insn >> 20) & 7) {
            case 0: /* 32 x 32 -> 32 */
            case 7: /* Unsigned sum of absolute differences.  */
                break;
            case 1: /* 16 x 16 -> 32 */
            case 2: /* Dual multiply add.  */
            case 3: /* 32 * 16 -> 32msb */
            case 4: /* Dual multiply subtract.  */
            case 5: case 6: /* 32 * 32 -> 32msb (SMMUL, SMMLA, SMMLS) */
                if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
                    goto illegal_op;
                }
                break;
            }
P
pbrook 已提交
10045
            op = (insn >> 4) & 0xf;
P
pbrook 已提交
10046 10047
            tmp = load_reg(s, rn);
            tmp2 = load_reg(s, rm);
P
pbrook 已提交
10048 10049
            switch ((insn >> 20) & 7) {
            case 0: /* 32 x 32 -> 32 */
P
pbrook 已提交
10050
                tcg_gen_mul_i32(tmp, tmp, tmp2);
10051
                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
10052
                if (rs != 15) {
P
pbrook 已提交
10053
                    tmp2 = load_reg(s, rs);
P
pbrook 已提交
10054
                    if (op)
P
pbrook 已提交
10055
                        tcg_gen_sub_i32(tmp, tmp2, tmp);
P
pbrook 已提交
10056
                    else
P
pbrook 已提交
10057
                        tcg_gen_add_i32(tmp, tmp, tmp2);
10058
                    tcg_temp_free_i32(tmp2);
P
pbrook 已提交
10059 10060 10061
                }
                break;
            case 1: /* 16 x 16 -> 32 */
P
pbrook 已提交
10062
                gen_mulxy(tmp, tmp2, op & 2, op & 1);
10063
                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
10064
                if (rs != 15) {
P
pbrook 已提交
10065
                    tmp2 = load_reg(s, rs);
10066
                    gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
10067
                    tcg_temp_free_i32(tmp2);
P
pbrook 已提交
10068 10069 10070 10071 10072
                }
                break;
            case 2: /* Dual multiply add.  */
            case 4: /* Dual multiply subtract.  */
                if (op)
P
pbrook 已提交
10073 10074
                    gen_swap_half(tmp2);
                gen_smul_dual(tmp, tmp2);
P
pbrook 已提交
10075
                if (insn & (1 << 22)) {
10076
                    /* This subtraction cannot overflow. */
P
pbrook 已提交
10077
                    tcg_gen_sub_i32(tmp, tmp, tmp2);
P
pbrook 已提交
10078
                } else {
10079 10080 10081 10082
                    /* This addition cannot overflow 32 bits;
                     * however it may overflow considered as a signed
                     * operation, in which case we must set the Q flag.
                     */
10083
                    gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
P
pbrook 已提交
10084
                }
10085
                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
10086 10087
                if (rs != 15)
                  {
P
pbrook 已提交
10088
                    tmp2 = load_reg(s, rs);
10089
                    gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
10090
                    tcg_temp_free_i32(tmp2);
P
pbrook 已提交
10091 10092 10093 10094
                  }
                break;
            case 3: /* 32 * 16 -> 32msb */
                if (op)
P
pbrook 已提交
10095
                    tcg_gen_sari_i32(tmp2, tmp2, 16);
P
pbrook 已提交
10096
                else
P
pbrook 已提交
10097
                    gen_sxth(tmp2);
P
pbrook 已提交
10098 10099
                tmp64 = gen_muls_i64_i32(tmp, tmp2);
                tcg_gen_shri_i64(tmp64, tmp64, 16);
10100
                tmp = tcg_temp_new_i32();
10101
                tcg_gen_extrl_i64_i32(tmp, tmp64);
10102
                tcg_temp_free_i64(tmp64);
P
pbrook 已提交
10103 10104
                if (rs != 15)
                  {
P
pbrook 已提交
10105
                    tmp2 = load_reg(s, rs);
10106
                    gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
10107
                    tcg_temp_free_i32(tmp2);
P
pbrook 已提交
10108 10109
                  }
                break;
10110 10111
            case 5: case 6: /* 32 * 32 -> 32msb (SMMUL, SMMLA, SMMLS) */
                tmp64 = gen_muls_i64_i32(tmp, tmp2);
P
pbrook 已提交
10112
                if (rs != 15) {
10113 10114 10115
                    tmp = load_reg(s, rs);
                    if (insn & (1 << 20)) {
                        tmp64 = gen_addq_msw(tmp64, tmp);
B
bellard 已提交
10116
                    } else {
10117
                        tmp64 = gen_subq_msw(tmp64, tmp);
B
bellard 已提交
10118
                    }
B
bellard 已提交
10119
                }
10120 10121 10122 10123
                if (insn & (1 << 4)) {
                    tcg_gen_addi_i64(tmp64, tmp64, 0x80000000u);
                }
                tcg_gen_shri_i64(tmp64, tmp64, 32);
10124
                tmp = tcg_temp_new_i32();
10125
                tcg_gen_extrl_i64_i32(tmp, tmp64);
10126
                tcg_temp_free_i64(tmp64);
P
pbrook 已提交
10127 10128
                break;
            case 7: /* Unsigned sum of absolute differences.  */
P
pbrook 已提交
10129
                gen_helper_usad8(tmp, tmp, tmp2);
10130
                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
10131
                if (rs != 15) {
P
pbrook 已提交
10132 10133
                    tmp2 = load_reg(s, rs);
                    tcg_gen_add_i32(tmp, tmp, tmp2);
10134
                    tcg_temp_free_i32(tmp2);
10135
                }
P
pbrook 已提交
10136
                break;
B
bellard 已提交
10137
            }
P
pbrook 已提交
10138
            store_reg(s, rd, tmp);
B
bellard 已提交
10139
            break;
P
pbrook 已提交
10140 10141
        case 6: case 7: /* 64-bit multiply, Divide.  */
            op = ((insn >> 4) & 0xf) | ((insn >> 16) & 0x70);
P
pbrook 已提交
10142 10143
            tmp = load_reg(s, rn);
            tmp2 = load_reg(s, rm);
P
pbrook 已提交
10144 10145
            if ((op & 0x50) == 0x10) {
                /* sdiv, udiv */
10146
                if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DIV)) {
P
pbrook 已提交
10147
                    goto illegal_op;
10148
                }
P
pbrook 已提交
10149
                if (op & 0x20)
P
pbrook 已提交
10150
                    gen_helper_udiv(tmp, tmp, tmp2);
B
bellard 已提交
10151
                else
P
pbrook 已提交
10152
                    gen_helper_sdiv(tmp, tmp, tmp2);
10153
                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
10154
                store_reg(s, rd, tmp);
P
pbrook 已提交
10155 10156
            } else if ((op & 0xe) == 0xc) {
                /* Dual multiply accumulate long.  */
10157 10158 10159 10160 10161
                if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
                    tcg_temp_free_i32(tmp);
                    tcg_temp_free_i32(tmp2);
                    goto illegal_op;
                }
P
pbrook 已提交
10162
                if (op & 1)
P
pbrook 已提交
10163 10164
                    gen_swap_half(tmp2);
                gen_smul_dual(tmp, tmp2);
P
pbrook 已提交
10165
                if (op & 0x10) {
P
pbrook 已提交
10166
                    tcg_gen_sub_i32(tmp, tmp, tmp2);
B
bellard 已提交
10167
                } else {
P
pbrook 已提交
10168
                    tcg_gen_add_i32(tmp, tmp, tmp2);
B
bellard 已提交
10169
                }
10170
                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
10171 10172 10173
                /* BUGFIX */
                tmp64 = tcg_temp_new_i64();
                tcg_gen_ext_i32_i64(tmp64, tmp);
10174
                tcg_temp_free_i32(tmp);
P
pbrook 已提交
10175 10176
                gen_addq(s, tmp64, rs, rd);
                gen_storeq_reg(s, rs, rd, tmp64);
10177
                tcg_temp_free_i64(tmp64);
B
bellard 已提交
10178
            } else {
P
pbrook 已提交
10179 10180
                if (op & 0x20) {
                    /* Unsigned 64-bit multiply  */
P
pbrook 已提交
10181
                    tmp64 = gen_mulu_i64_i32(tmp, tmp2);
B
bellard 已提交
10182
                } else {
P
pbrook 已提交
10183 10184
                    if (op & 8) {
                        /* smlalxy */
10185 10186 10187 10188 10189
                        if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
                            tcg_temp_free_i32(tmp2);
                            tcg_temp_free_i32(tmp);
                            goto illegal_op;
                        }
P
pbrook 已提交
10190
                        gen_mulxy(tmp, tmp2, op & 2, op & 1);
10191
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
10192 10193
                        tmp64 = tcg_temp_new_i64();
                        tcg_gen_ext_i32_i64(tmp64, tmp);
10194
                        tcg_temp_free_i32(tmp);
P
pbrook 已提交
10195 10196
                    } else {
                        /* Signed 64-bit multiply  */
P
pbrook 已提交
10197
                        tmp64 = gen_muls_i64_i32(tmp, tmp2);
P
pbrook 已提交
10198
                    }
B
bellard 已提交
10199
                }
P
pbrook 已提交
10200 10201
                if (op & 4) {
                    /* umaal */
10202 10203 10204 10205
                    if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
                        tcg_temp_free_i64(tmp64);
                        goto illegal_op;
                    }
P
pbrook 已提交
10206 10207
                    gen_addq_lo(s, tmp64, rs);
                    gen_addq_lo(s, tmp64, rd);
P
pbrook 已提交
10208 10209
                } else if (op & 0x40) {
                    /* 64-bit accumulate.  */
P
pbrook 已提交
10210
                    gen_addq(s, tmp64, rs, rd);
P
pbrook 已提交
10211
                }
P
pbrook 已提交
10212
                gen_storeq_reg(s, rs, rd, tmp64);
10213
                tcg_temp_free_i64(tmp64);
10214
            }
B
bellard 已提交
10215
            break;
P
pbrook 已提交
10216 10217 10218 10219 10220 10221
        }
        break;
    case 6: case 7: case 14: case 15:
        /* Coprocessor.  */
        if (((insn >> 24) & 3) == 3) {
            /* Translate into the equivalent ARM encoding.  */
10222
            insn = (insn & 0xe2ffffff) | ((insn & (1 << 28)) >> 4) | (1 << 28);
10223
            if (disas_neon_data_insn(s, insn)) {
P
pbrook 已提交
10224
                goto illegal_op;
10225
            }
10226
        } else if (((insn >> 8) & 0xe) == 10) {
10227
            if (disas_vfp_insn(s, insn)) {
10228 10229
                goto illegal_op;
            }
P
pbrook 已提交
10230 10231 10232
        } else {
            if (insn & (1 << 28))
                goto illegal_op;
10233
            if (disas_coproc_insn(s, insn)) {
P
pbrook 已提交
10234
                goto illegal_op;
10235
            }
P
pbrook 已提交
10236 10237 10238 10239 10240 10241 10242 10243 10244 10245 10246 10247 10248 10249 10250 10251 10252 10253 10254
        }
        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.  */
10255
                    tcg_gen_movi_i32(cpu_R[14], s->pc | 1);
B
bellard 已提交
10256
                }
10257

P
pbrook 已提交
10258
                offset += s->pc;
P
pbrook 已提交
10259 10260
                if (insn & (1 << 12)) {
                    /* b/bl */
P
pbrook 已提交
10261
                    gen_jmp(s, offset);
P
pbrook 已提交
10262 10263
                } else {
                    /* blx */
P
pbrook 已提交
10264
                    offset &= ~(uint32_t)2;
10265
                    /* thumb2 bx, no need to check */
P
pbrook 已提交
10266
                    gen_bx_im(s, offset);
B
bellard 已提交
10267
                }
P
pbrook 已提交
10268 10269 10270 10271 10272 10273
            } else if (((insn >> 23) & 7) == 7) {
                /* Misc control */
                if (insn & (1 << 13))
                    goto illegal_op;

                if (insn & (1 << 26)) {
10274 10275 10276 10277 10278 10279 10280 10281 10282 10283 10284 10285 10286 10287 10288 10289 10290
                    if (!(insn & (1 << 20))) {
                        /* Hypervisor call (v7) */
                        int imm16 = extract32(insn, 16, 4) << 12
                            | extract32(insn, 0, 12);
                        ARCH(7);
                        if (IS_USER(s)) {
                            goto illegal_op;
                        }
                        gen_hvc(s, imm16);
                    } else {
                        /* Secure monitor call (v6+) */
                        ARCH(6K);
                        if (IS_USER(s)) {
                            goto illegal_op;
                        }
                        gen_smc(s);
                    }
B
bellard 已提交
10291
                } else {
P
pbrook 已提交
10292 10293 10294
                    op = (insn >> 20) & 7;
                    switch (op) {
                    case 0: /* msr cpsr.  */
10295
                        if (arm_dc_feature(s, ARM_FEATURE_M)) {
P
pbrook 已提交
10296 10297 10298
                            tmp = load_reg(s, rn);
                            addr = tcg_const_i32(insn & 0xff);
                            gen_helper_v7m_msr(cpu_env, addr, tmp);
10299
                            tcg_temp_free_i32(addr);
10300
                            tcg_temp_free_i32(tmp);
P
pbrook 已提交
10301 10302 10303 10304 10305
                            gen_lookup_tb(s);
                            break;
                        }
                        /* fall through */
                    case 1: /* msr spsr.  */
10306
                        if (arm_dc_feature(s, ARM_FEATURE_M)) {
P
pbrook 已提交
10307
                            goto illegal_op;
10308
                        }
10309 10310 10311 10312 10313 10314 10315 10316 10317 10318 10319 10320

                        if (extract32(insn, 5, 1)) {
                            /* MSR (banked) */
                            int sysm = extract32(insn, 8, 4) |
                                (extract32(insn, 4, 1) << 4);
                            int r = op & 1;

                            gen_msr_banked(s, r, sysm, rm);
                            break;
                        }

                        /* MSR (for PSRs) */
10321 10322
                        tmp = load_reg(s, rn);
                        if (gen_set_psr(s,
10323
                              msr_mask(s, (insn >> 8) & 0xf, op == 1),
10324
                              op == 1, tmp))
P
pbrook 已提交
10325 10326 10327 10328 10329 10330 10331 10332 10333 10334 10335 10336 10337 10338 10339 10340 10341 10342 10343 10344 10345 10346 10347 10348 10349 10350
                            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) {
10351
                            gen_set_psr_im(s, offset, 0, imm);
P
pbrook 已提交
10352 10353 10354
                        }
                        break;
                    case 3: /* Special control operations.  */
P
Paul Brook 已提交
10355
                        ARCH(7);
P
pbrook 已提交
10356 10357 10358
                        op = (insn >> 4) & 0xf;
                        switch (op) {
                        case 2: /* clrex */
P
Paul Brook 已提交
10359
                            gen_clrex(s);
P
pbrook 已提交
10360 10361 10362
                            break;
                        case 4: /* dsb */
                        case 5: /* dmb */
10363
                            tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
P
pbrook 已提交
10364
                            break;
10365 10366 10367 10368 10369 10370 10371 10372
                        case 6: /* isb */
                            /* We need to break the TB after this insn
                             * to execute self-modifying code correctly
                             * and also to take any pending interrupts
                             * immediately.
                             */
                            gen_lookup_tb(s);
                            break;
P
pbrook 已提交
10373 10374 10375 10376 10377 10378
                        default:
                            goto illegal_op;
                        }
                        break;
                    case 4: /* bxj */
                        /* Trivial implementation equivalent to bx.  */
P
pbrook 已提交
10379 10380
                        tmp = load_reg(s, rn);
                        gen_bx(s, tmp);
P
pbrook 已提交
10381 10382
                        break;
                    case 5: /* Exception return.  */
10383 10384 10385 10386 10387 10388 10389 10390 10391 10392
                        if (IS_USER(s)) {
                            goto illegal_op;
                        }
                        if (rn != 14 || rd != 15) {
                            goto illegal_op;
                        }
                        tmp = load_reg(s, rn);
                        tcg_gen_subi_i32(tmp, tmp, insn & 0xff);
                        gen_exception_return(s, tmp);
                        break;
10393 10394 10395 10396 10397 10398 10399 10400 10401 10402 10403
                    case 6: /* MRS */
                        if (extract32(insn, 5, 1)) {
                            /* MRS (banked) */
                            int sysm = extract32(insn, 16, 4) |
                                (extract32(insn, 4, 1) << 4);

                            gen_mrs_banked(s, 0, sysm, rd);
                            break;
                        }

                        /* mrs cpsr */
10404
                        tmp = tcg_temp_new_i32();
10405
                        if (arm_dc_feature(s, ARM_FEATURE_M)) {
P
pbrook 已提交
10406 10407
                            addr = tcg_const_i32(insn & 0xff);
                            gen_helper_v7m_mrs(tmp, cpu_env, addr);
10408
                            tcg_temp_free_i32(addr);
P
pbrook 已提交
10409
                        } else {
10410
                            gen_helper_cpsr_read(tmp, cpu_env);
P
pbrook 已提交
10411
                        }
P
pbrook 已提交
10412
                        store_reg(s, rd, tmp);
P
pbrook 已提交
10413
                        break;
10414 10415 10416 10417 10418 10419 10420 10421 10422 10423 10424
                    case 7: /* MRS */
                        if (extract32(insn, 5, 1)) {
                            /* MRS (banked) */
                            int sysm = extract32(insn, 16, 4) |
                                (extract32(insn, 4, 1) << 4);

                            gen_mrs_banked(s, 1, sysm, rd);
                            break;
                        }

                        /* mrs spsr.  */
P
pbrook 已提交
10425
                        /* Not accessible in user mode.  */
10426
                        if (IS_USER(s) || arm_dc_feature(s, ARM_FEATURE_M)) {
P
pbrook 已提交
10427
                            goto illegal_op;
10428
                        }
P
pbrook 已提交
10429 10430
                        tmp = load_cpu_field(spsr);
                        store_reg(s, rd, tmp);
P
pbrook 已提交
10431
                        break;
B
bellard 已提交
10432 10433
                    }
                }
P
pbrook 已提交
10434 10435 10436 10437 10438
            } else {
                /* Conditional branch.  */
                op = (insn >> 22) & 0xf;
                /* Generate a conditional jump to next instruction.  */
                s->condlabel = gen_new_label();
10439
                arm_gen_test_cc(op ^ 1, s->condlabel);
P
pbrook 已提交
10440 10441 10442 10443 10444 10445 10446 10447 10448 10449 10450 10451 10452 10453
                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 已提交
10454
                gen_jmp(s, s->pc + offset);
P
pbrook 已提交
10455 10456 10457 10458 10459 10460 10461 10462 10463 10464 10465
            }
        } 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 已提交
10466
                    if (rn == 15) {
10467
                        tmp = tcg_temp_new_i32();
P
pbrook 已提交
10468 10469 10470 10471
                        tcg_gen_movi_i32(tmp, 0);
                    } else {
                        tmp = load_reg(s, rn);
                    }
P
pbrook 已提交
10472 10473 10474 10475 10476
                    switch (op) {
                    case 2: /* Signed bitfield extract.  */
                        imm++;
                        if (shift + imm > 32)
                            goto illegal_op;
10477 10478 10479
                        if (imm < 32) {
                            tcg_gen_sextract_i32(tmp, tmp, shift, imm);
                        }
P
pbrook 已提交
10480 10481 10482 10483 10484
                        break;
                    case 6: /* Unsigned bitfield extract.  */
                        imm++;
                        if (shift + imm > 32)
                            goto illegal_op;
10485 10486 10487
                        if (imm < 32) {
                            tcg_gen_extract_i32(tmp, tmp, shift, imm);
                        }
P
pbrook 已提交
10488 10489 10490 10491 10492 10493
                        break;
                    case 3: /* Bitfield insert/clear.  */
                        if (imm < shift)
                            goto illegal_op;
                        imm = imm + 1 - shift;
                        if (imm != 32) {
P
pbrook 已提交
10494
                            tmp2 = load_reg(s, rd);
10495
                            tcg_gen_deposit_i32(tmp, tmp2, tmp, shift, imm);
10496
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
10497 10498 10499 10500 10501 10502 10503
                        }
                        break;
                    case 7:
                        goto illegal_op;
                    default: /* Saturate.  */
                        if (shift) {
                            if (op & 1)
P
pbrook 已提交
10504
                                tcg_gen_sari_i32(tmp, tmp, shift);
P
pbrook 已提交
10505
                            else
P
pbrook 已提交
10506
                                tcg_gen_shli_i32(tmp, tmp, shift);
P
pbrook 已提交
10507
                        }
P
pbrook 已提交
10508
                        tmp2 = tcg_const_i32(imm);
P
pbrook 已提交
10509 10510
                        if (op & 4) {
                            /* Unsigned.  */
10511 10512 10513 10514 10515 10516
                            if ((op & 1) && shift == 0) {
                                if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
                                    tcg_temp_free_i32(tmp);
                                    tcg_temp_free_i32(tmp2);
                                    goto illegal_op;
                                }
10517
                                gen_helper_usat16(tmp, cpu_env, tmp, tmp2);
10518
                            } else {
10519
                                gen_helper_usat(tmp, cpu_env, tmp, tmp2);
10520
                            }
B
bellard 已提交
10521
                        } else {
P
pbrook 已提交
10522
                            /* Signed.  */
10523 10524 10525 10526 10527 10528
                            if ((op & 1) && shift == 0) {
                                if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
                                    tcg_temp_free_i32(tmp);
                                    tcg_temp_free_i32(tmp2);
                                    goto illegal_op;
                                }
10529
                                gen_helper_ssat16(tmp, cpu_env, tmp, tmp2);
10530
                            } else {
10531
                                gen_helper_ssat(tmp, cpu_env, tmp, tmp2);
10532
                            }
B
bellard 已提交
10533
                        }
10534
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
10535
                        break;
B
bellard 已提交
10536
                    }
P
pbrook 已提交
10537
                    store_reg(s, rd, tmp);
P
pbrook 已提交
10538 10539 10540 10541 10542 10543 10544 10545
                } 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 已提交
10546
                            tmp = load_reg(s, rd);
P
pbrook 已提交
10547
                            tcg_gen_ext16u_i32(tmp, tmp);
P
pbrook 已提交
10548
                            tcg_gen_ori_i32(tmp, tmp, imm << 16);
B
bellard 已提交
10549
                        } else {
P
pbrook 已提交
10550
                            /* movw */
10551
                            tmp = tcg_temp_new_i32();
P
pbrook 已提交
10552
                            tcg_gen_movi_i32(tmp, imm);
B
bellard 已提交
10553 10554
                        }
                    } else {
P
pbrook 已提交
10555 10556
                        /* Add/sub 12-bit immediate.  */
                        if (rn == 15) {
P
pbrook 已提交
10557
                            offset = s->pc & ~(uint32_t)3;
P
pbrook 已提交
10558
                            if (insn & (1 << 23))
P
pbrook 已提交
10559
                                offset -= imm;
P
pbrook 已提交
10560
                            else
P
pbrook 已提交
10561
                                offset += imm;
10562
                            tmp = tcg_temp_new_i32();
P
pbrook 已提交
10563
                            tcg_gen_movi_i32(tmp, offset);
B
bellard 已提交
10564
                        } else {
P
pbrook 已提交
10565
                            tmp = load_reg(s, rn);
P
pbrook 已提交
10566
                            if (insn & (1 << 23))
P
pbrook 已提交
10567
                                tcg_gen_subi_i32(tmp, tmp, imm);
P
pbrook 已提交
10568
                            else
P
pbrook 已提交
10569
                                tcg_gen_addi_i32(tmp, tmp, imm);
B
bellard 已提交
10570
                        }
P
pbrook 已提交
10571
                    }
P
pbrook 已提交
10572
                    store_reg(s, rd, tmp);
P
pbrook 已提交
10573
                }
P
pbrook 已提交
10574 10575 10576 10577 10578 10579 10580 10581 10582 10583 10584 10585 10586 10587 10588 10589 10590 10591 10592 10593 10594 10595 10596 10597 10598 10599
            } 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 已提交
10600
                }
10601
                tmp2 = tcg_temp_new_i32();
10602
                tcg_gen_movi_i32(tmp2, imm);
P
pbrook 已提交
10603
                rn = (insn >> 16) & 0xf;
10604
                if (rn == 15) {
10605
                    tmp = tcg_temp_new_i32();
10606 10607 10608 10609
                    tcg_gen_movi_i32(tmp, 0);
                } else {
                    tmp = load_reg(s, rn);
                }
P
pbrook 已提交
10610 10611
                op = (insn >> 21) & 0xf;
                if (gen_thumb2_data_op(s, op, (insn & (1 << 20)) != 0,
10612
                                       shifter_out, tmp, tmp2))
P
pbrook 已提交
10613
                    goto illegal_op;
10614
                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
10615 10616
                rd = (insn >> 8) & 0xf;
                if (rd != 15) {
10617 10618
                    store_reg(s, rd, tmp);
                } else {
10619
                    tcg_temp_free_i32(tmp);
B
bellard 已提交
10620 10621
                }
            }
P
pbrook 已提交
10622 10623 10624 10625 10626 10627
        }
        break;
    case 12: /* Load/store single data item.  */
        {
        int postinc = 0;
        int writeback = 0;
10628
        int memidx;
P
pbrook 已提交
10629
        if ((insn & 0x01100000) == 0x01000000) {
10630
            if (disas_neon_ls_insn(s, insn)) {
10631
                goto illegal_op;
10632
            }
P
pbrook 已提交
10633 10634
            break;
        }
10635 10636 10637 10638 10639 10640 10641 10642 10643 10644 10645 10646 10647 10648 10649 10650 10651 10652 10653 10654 10655 10656 10657
        op = ((insn >> 21) & 3) | ((insn >> 22) & 4);
        if (rs == 15) {
            if (!(insn & (1 << 20))) {
                goto illegal_op;
            }
            if (op != 2) {
                /* Byte or halfword load space with dest == r15 : memory hints.
                 * Catch them early so we don't emit pointless addressing code.
                 * This space is a mix of:
                 *  PLD/PLDW/PLI,  which we implement as NOPs (note that unlike
                 *     the ARM encodings, PLDW space doesn't UNDEF for non-v7MP
                 *     cores)
                 *  unallocated hints, which must be treated as NOPs
                 *  UNPREDICTABLE space, which we NOP or UNDEF depending on
                 *     which is easiest for the decoding logic
                 *  Some space which must UNDEF
                 */
                int op1 = (insn >> 23) & 3;
                int op2 = (insn >> 6) & 0x3f;
                if (op & 2) {
                    goto illegal_op;
                }
                if (rn == 15) {
10658 10659 10660
                    /* UNPREDICTABLE, unallocated hint or
                     * PLD/PLDW/PLI (literal)
                     */
10661 10662 10663
                    return 0;
                }
                if (op1 & 1) {
10664
                    return 0; /* PLD/PLDW/PLI or unallocated hint */
10665 10666
                }
                if ((op2 == 0) || ((op2 & 0x3c) == 0x30)) {
10667
                    return 0; /* PLD/PLDW/PLI or unallocated hint */
10668 10669 10670 10671 10672
                }
                /* UNDEF space, or an UNPREDICTABLE */
                return 1;
            }
        }
10673
        memidx = get_mem_index(s);
P
pbrook 已提交
10674
        if (rn == 15) {
10675
            addr = tcg_temp_new_i32();
P
pbrook 已提交
10676 10677 10678 10679 10680 10681 10682
            /* 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 已提交
10683
            tcg_gen_movi_i32(addr, imm);
P
pbrook 已提交
10684
        } else {
P
pbrook 已提交
10685
            addr = load_reg(s, rn);
P
pbrook 已提交
10686 10687 10688
            if (insn & (1 << 23)) {
                /* Positive offset.  */
                imm = insn & 0xfff;
P
pbrook 已提交
10689
                tcg_gen_addi_i32(addr, addr, imm);
P
pbrook 已提交
10690 10691
            } else {
                imm = insn & 0xff;
10692 10693
                switch ((insn >> 8) & 0xf) {
                case 0x0: /* Shifted Register.  */
P
pbrook 已提交
10694
                    shift = (insn >> 4) & 0xf;
10695 10696
                    if (shift > 3) {
                        tcg_temp_free_i32(addr);
10697
                        goto illegal_op;
10698
                    }
P
pbrook 已提交
10699
                    tmp = load_reg(s, rm);
P
pbrook 已提交
10700
                    if (shift)
P
pbrook 已提交
10701
                        tcg_gen_shli_i32(tmp, tmp, shift);
P
pbrook 已提交
10702
                    tcg_gen_add_i32(addr, addr, tmp);
10703
                    tcg_temp_free_i32(tmp);
P
pbrook 已提交
10704
                    break;
10705
                case 0xc: /* Negative offset.  */
P
pbrook 已提交
10706
                    tcg_gen_addi_i32(addr, addr, -imm);
P
pbrook 已提交
10707
                    break;
10708
                case 0xe: /* User privilege.  */
P
pbrook 已提交
10709
                    tcg_gen_addi_i32(addr, addr, imm);
10710
                    memidx = get_a32_user_mem_index(s);
P
pbrook 已提交
10711
                    break;
10712
                case 0x9: /* Post-decrement.  */
P
pbrook 已提交
10713 10714
                    imm = -imm;
                    /* Fall through.  */
10715
                case 0xb: /* Post-increment.  */
P
pbrook 已提交
10716 10717 10718
                    postinc = 1;
                    writeback = 1;
                    break;
10719
                case 0xd: /* Pre-decrement.  */
P
pbrook 已提交
10720 10721
                    imm = -imm;
                    /* Fall through.  */
10722
                case 0xf: /* Pre-increment.  */
P
pbrook 已提交
10723
                    tcg_gen_addi_i32(addr, addr, imm);
P
pbrook 已提交
10724 10725 10726
                    writeback = 1;
                    break;
                default:
10727
                    tcg_temp_free_i32(addr);
B
bellard 已提交
10728
                    goto illegal_op;
P
pbrook 已提交
10729 10730 10731 10732 10733
                }
            }
        }
        if (insn & (1 << 20)) {
            /* Load.  */
10734
            tmp = tcg_temp_new_i32();
10735
            switch (op) {
10736
            case 0:
10737
                gen_aa32_ld8u(s, tmp, addr, memidx);
10738 10739
                break;
            case 4:
10740
                gen_aa32_ld8s(s, tmp, addr, memidx);
10741 10742
                break;
            case 1:
10743
                gen_aa32_ld16u(s, tmp, addr, memidx);
10744 10745
                break;
            case 5:
10746
                gen_aa32_ld16s(s, tmp, addr, memidx);
10747 10748
                break;
            case 2:
10749
                gen_aa32_ld32u(s, tmp, addr, memidx);
10750
                break;
10751
            default:
10752
                tcg_temp_free_i32(tmp);
10753 10754
                tcg_temp_free_i32(addr);
                goto illegal_op;
10755 10756 10757
            }
            if (rs == 15) {
                gen_bx(s, tmp);
P
pbrook 已提交
10758
            } else {
10759
                store_reg(s, rs, tmp);
P
pbrook 已提交
10760 10761 10762
            }
        } else {
            /* Store.  */
P
pbrook 已提交
10763
            tmp = load_reg(s, rs);
P
pbrook 已提交
10764
            switch (op) {
10765
            case 0:
10766
                gen_aa32_st8(s, tmp, addr, memidx);
10767 10768
                break;
            case 1:
10769
                gen_aa32_st16(s, tmp, addr, memidx);
10770 10771
                break;
            case 2:
10772
                gen_aa32_st32(s, tmp, addr, memidx);
10773
                break;
10774
            default:
10775
                tcg_temp_free_i32(tmp);
10776 10777
                tcg_temp_free_i32(addr);
                goto illegal_op;
B
bellard 已提交
10778
            }
10779
            tcg_temp_free_i32(tmp);
B
bellard 已提交
10780
        }
P
pbrook 已提交
10781
        if (postinc)
P
pbrook 已提交
10782 10783 10784 10785
            tcg_gen_addi_i32(addr, addr, imm);
        if (writeback) {
            store_reg(s, rn, addr);
        } else {
10786
            tcg_temp_free_i32(addr);
P
pbrook 已提交
10787
        }
P
pbrook 已提交
10788 10789 10790 10791
        }
        break;
    default:
        goto illegal_op;
B
bellard 已提交
10792
    }
P
pbrook 已提交
10793 10794 10795
    return 0;
illegal_op:
    return 1;
B
bellard 已提交
10796 10797
}

10798
static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
B
bellard 已提交
10799 10800 10801 10802
{
    uint32_t val, insn, op, rm, rn, rd, shift, cond;
    int32_t offset;
    int i;
10803 10804 10805
    TCGv_i32 tmp;
    TCGv_i32 tmp2;
    TCGv_i32 addr;
B
bellard 已提交
10806

P
pbrook 已提交
10807 10808
    if (s->condexec_mask) {
        cond = s->condexec_cond;
10809 10810
        if (cond != 0x0e) {     /* Skip conditional when condition is AL. */
          s->condlabel = gen_new_label();
10811
          arm_gen_test_cc(cond ^ 1, s->condlabel);
10812 10813
          s->condjmp = 1;
        }
P
pbrook 已提交
10814 10815
    }

10816
    insn = arm_lduw_code(env, s->pc, s->sctlr_b);
B
bellard 已提交
10817
    s->pc += 2;
B
bellard 已提交
10818

B
bellard 已提交
10819 10820
    switch (insn >> 12) {
    case 0: case 1:
10821

B
bellard 已提交
10822 10823 10824 10825 10826
        rd = insn & 7;
        op = (insn >> 11) & 3;
        if (op == 3) {
            /* add/subtract */
            rn = (insn >> 3) & 7;
10827
            tmp = load_reg(s, rn);
B
bellard 已提交
10828 10829
            if (insn & (1 << 10)) {
                /* immediate */
10830
                tmp2 = tcg_temp_new_i32();
10831
                tcg_gen_movi_i32(tmp2, (insn >> 6) & 7);
B
bellard 已提交
10832 10833 10834
            } else {
                /* reg */
                rm = (insn >> 6) & 7;
10835
                tmp2 = load_reg(s, rm);
B
bellard 已提交
10836
            }
P
pbrook 已提交
10837 10838
            if (insn & (1 << 9)) {
                if (s->condexec_mask)
10839
                    tcg_gen_sub_i32(tmp, tmp, tmp2);
P
pbrook 已提交
10840
                else
10841
                    gen_sub_CC(tmp, tmp, tmp2);
P
pbrook 已提交
10842 10843
            } else {
                if (s->condexec_mask)
10844
                    tcg_gen_add_i32(tmp, tmp, tmp2);
P
pbrook 已提交
10845
                else
10846
                    gen_add_CC(tmp, tmp, tmp2);
P
pbrook 已提交
10847
            }
10848
            tcg_temp_free_i32(tmp2);
10849
            store_reg(s, rd, tmp);
B
bellard 已提交
10850 10851 10852 10853
        } else {
            /* shift immediate */
            rm = (insn >> 3) & 7;
            shift = (insn >> 6) & 0x1f;
P
pbrook 已提交
10854 10855 10856 10857 10858
            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 已提交
10859 10860 10861 10862 10863 10864
        }
        break;
    case 2: case 3:
        /* arithmetic large immediate */
        op = (insn >> 11) & 3;
        rd = (insn >> 8) & 0x7;
10865
        if (op == 0) { /* mov */
10866
            tmp = tcg_temp_new_i32();
10867
            tcg_gen_movi_i32(tmp, insn & 0xff);
P
pbrook 已提交
10868
            if (!s->condexec_mask)
10869 10870 10871 10872
                gen_logic_CC(tmp);
            store_reg(s, rd, tmp);
        } else {
            tmp = load_reg(s, rd);
10873
            tmp2 = tcg_temp_new_i32();
10874 10875 10876
            tcg_gen_movi_i32(tmp2, insn & 0xff);
            switch (op) {
            case 1: /* cmp */
10877
                gen_sub_CC(tmp, tmp, tmp2);
10878 10879
                tcg_temp_free_i32(tmp);
                tcg_temp_free_i32(tmp2);
10880 10881 10882 10883 10884
                break;
            case 2: /* add */
                if (s->condexec_mask)
                    tcg_gen_add_i32(tmp, tmp, tmp2);
                else
10885
                    gen_add_CC(tmp, tmp, tmp2);
10886
                tcg_temp_free_i32(tmp2);
10887 10888 10889 10890 10891 10892
                store_reg(s, rd, tmp);
                break;
            case 3: /* sub */
                if (s->condexec_mask)
                    tcg_gen_sub_i32(tmp, tmp, tmp2);
                else
10893
                    gen_sub_CC(tmp, tmp, tmp2);
10894
                tcg_temp_free_i32(tmp2);
10895 10896 10897
                store_reg(s, rd, tmp);
                break;
            }
B
bellard 已提交
10898 10899 10900 10901 10902
        }
        break;
    case 4:
        if (insn & (1 << 11)) {
            rd = (insn >> 8) & 7;
B
bellard 已提交
10903 10904 10905
            /* load pc-relative.  Bit 1 of PC is ignored.  */
            val = s->pc + 2 + ((insn & 0xff) * 4);
            val &= ~(uint32_t)2;
10906
            addr = tcg_temp_new_i32();
P
pbrook 已提交
10907
            tcg_gen_movi_i32(addr, val);
10908
            tmp = tcg_temp_new_i32();
10909
            gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
10910
            tcg_temp_free_i32(addr);
P
pbrook 已提交
10911
            store_reg(s, rd, tmp);
B
bellard 已提交
10912 10913 10914 10915 10916 10917 10918 10919 10920
            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 */
10921 10922 10923
                tmp = load_reg(s, rd);
                tmp2 = load_reg(s, rm);
                tcg_gen_add_i32(tmp, tmp, tmp2);
10924
                tcg_temp_free_i32(tmp2);
10925
                store_reg(s, rd, tmp);
B
bellard 已提交
10926 10927
                break;
            case 1: /* cmp */
10928 10929
                tmp = load_reg(s, rd);
                tmp2 = load_reg(s, rm);
10930
                gen_sub_CC(tmp, tmp, tmp2);
10931 10932
                tcg_temp_free_i32(tmp2);
                tcg_temp_free_i32(tmp);
B
bellard 已提交
10933 10934
                break;
            case 2: /* mov/cpy */
10935 10936
                tmp = load_reg(s, rm);
                store_reg(s, rd, tmp);
B
bellard 已提交
10937 10938
                break;
            case 3:/* branch [and link] exchange thumb register */
P
pbrook 已提交
10939
                tmp = load_reg(s, rm);
B
bellard 已提交
10940
                if (insn & (1 << 7)) {
10941
                    ARCH(5);
B
bellard 已提交
10942
                    val = (uint32_t)s->pc | 1;
10943
                    tmp2 = tcg_temp_new_i32();
P
pbrook 已提交
10944 10945
                    tcg_gen_movi_i32(tmp2, val);
                    store_reg(s, 14, tmp2);
B
bellard 已提交
10946
                }
10947
                /* already thumb, no need to check */
P
pbrook 已提交
10948
                gen_bx(s, tmp);
B
bellard 已提交
10949 10950 10951 10952 10953 10954 10955 10956 10957 10958 10959 10960 10961 10962 10963 10964 10965 10966 10967
                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;
        }

10968
        if (op == 9) { /* neg */
10969
            tmp = tcg_temp_new_i32();
10970 10971 10972 10973
            tcg_gen_movi_i32(tmp, 0);
        } else if (op != 0xf) { /* mvn doesn't read its first operand */
            tmp = load_reg(s, rd);
        } else {
10974
            TCGV_UNUSED_I32(tmp);
10975
        }
B
bellard 已提交
10976

10977
        tmp2 = load_reg(s, rm);
B
bellard 已提交
10978
        switch (op) {
B
bellard 已提交
10979
        case 0x0: /* and */
10980
            tcg_gen_and_i32(tmp, tmp, tmp2);
P
pbrook 已提交
10981
            if (!s->condexec_mask)
10982
                gen_logic_CC(tmp);
B
bellard 已提交
10983 10984
            break;
        case 0x1: /* eor */
10985
            tcg_gen_xor_i32(tmp, tmp, tmp2);
P
pbrook 已提交
10986
            if (!s->condexec_mask)
10987
                gen_logic_CC(tmp);
B
bellard 已提交
10988 10989
            break;
        case 0x2: /* lsl */
P
pbrook 已提交
10990
            if (s->condexec_mask) {
10991
                gen_shl(tmp2, tmp2, tmp);
P
pbrook 已提交
10992
            } else {
10993
                gen_helper_shl_cc(tmp2, cpu_env, tmp2, tmp);
10994
                gen_logic_CC(tmp2);
P
pbrook 已提交
10995
            }
B
bellard 已提交
10996 10997
            break;
        case 0x3: /* lsr */
P
pbrook 已提交
10998
            if (s->condexec_mask) {
10999
                gen_shr(tmp2, tmp2, tmp);
P
pbrook 已提交
11000
            } else {
11001
                gen_helper_shr_cc(tmp2, cpu_env, tmp2, tmp);
11002
                gen_logic_CC(tmp2);
P
pbrook 已提交
11003
            }
B
bellard 已提交
11004 11005
            break;
        case 0x4: /* asr */
P
pbrook 已提交
11006
            if (s->condexec_mask) {
11007
                gen_sar(tmp2, tmp2, tmp);
P
pbrook 已提交
11008
            } else {
11009
                gen_helper_sar_cc(tmp2, cpu_env, tmp2, tmp);
11010
                gen_logic_CC(tmp2);
P
pbrook 已提交
11011
            }
B
bellard 已提交
11012 11013
            break;
        case 0x5: /* adc */
11014
            if (s->condexec_mask) {
11015
                gen_adc(tmp, tmp2);
11016 11017 11018
            } else {
                gen_adc_CC(tmp, tmp, tmp2);
            }
B
bellard 已提交
11019 11020
            break;
        case 0x6: /* sbc */
11021
            if (s->condexec_mask) {
11022
                gen_sub_carry(tmp, tmp, tmp2);
11023 11024 11025
            } else {
                gen_sbc_CC(tmp, tmp, tmp2);
            }
B
bellard 已提交
11026 11027
            break;
        case 0x7: /* ror */
P
pbrook 已提交
11028
            if (s->condexec_mask) {
11029 11030
                tcg_gen_andi_i32(tmp, tmp, 0x1f);
                tcg_gen_rotr_i32(tmp2, tmp2, tmp);
P
pbrook 已提交
11031
            } else {
11032
                gen_helper_ror_cc(tmp2, cpu_env, tmp2, tmp);
11033
                gen_logic_CC(tmp2);
P
pbrook 已提交
11034
            }
B
bellard 已提交
11035 11036
            break;
        case 0x8: /* tst */
11037 11038
            tcg_gen_and_i32(tmp, tmp, tmp2);
            gen_logic_CC(tmp);
B
bellard 已提交
11039
            rd = 16;
B
bellard 已提交
11040
            break;
B
bellard 已提交
11041
        case 0x9: /* neg */
P
pbrook 已提交
11042
            if (s->condexec_mask)
11043
                tcg_gen_neg_i32(tmp, tmp2);
P
pbrook 已提交
11044
            else
11045
                gen_sub_CC(tmp, tmp, tmp2);
B
bellard 已提交
11046 11047
            break;
        case 0xa: /* cmp */
11048
            gen_sub_CC(tmp, tmp, tmp2);
B
bellard 已提交
11049 11050 11051
            rd = 16;
            break;
        case 0xb: /* cmn */
11052
            gen_add_CC(tmp, tmp, tmp2);
B
bellard 已提交
11053 11054 11055
            rd = 16;
            break;
        case 0xc: /* orr */
11056
            tcg_gen_or_i32(tmp, tmp, tmp2);
P
pbrook 已提交
11057
            if (!s->condexec_mask)
11058
                gen_logic_CC(tmp);
B
bellard 已提交
11059 11060
            break;
        case 0xd: /* mul */
11061
            tcg_gen_mul_i32(tmp, tmp, tmp2);
P
pbrook 已提交
11062
            if (!s->condexec_mask)
11063
                gen_logic_CC(tmp);
B
bellard 已提交
11064 11065
            break;
        case 0xe: /* bic */
11066
            tcg_gen_andc_i32(tmp, tmp, tmp2);
P
pbrook 已提交
11067
            if (!s->condexec_mask)
11068
                gen_logic_CC(tmp);
B
bellard 已提交
11069 11070
            break;
        case 0xf: /* mvn */
11071
            tcg_gen_not_i32(tmp2, tmp2);
P
pbrook 已提交
11072
            if (!s->condexec_mask)
11073
                gen_logic_CC(tmp2);
B
bellard 已提交
11074
            val = 1;
B
bellard 已提交
11075
            rm = rd;
B
bellard 已提交
11076 11077 11078
            break;
        }
        if (rd != 16) {
11079 11080 11081
            if (val) {
                store_reg(s, rm, tmp2);
                if (op != 0xf)
11082
                    tcg_temp_free_i32(tmp);
11083 11084
            } else {
                store_reg(s, rd, tmp);
11085
                tcg_temp_free_i32(tmp2);
11086 11087
            }
        } else {
11088 11089
            tcg_temp_free_i32(tmp);
            tcg_temp_free_i32(tmp2);
B
bellard 已提交
11090 11091 11092 11093 11094 11095 11096 11097 11098
        }
        break;

    case 5:
        /* load/store register offset.  */
        rd = insn & 7;
        rn = (insn >> 3) & 7;
        rm = (insn >> 6) & 7;
        op = (insn >> 9) & 7;
P
pbrook 已提交
11099
        addr = load_reg(s, rn);
P
pbrook 已提交
11100
        tmp = load_reg(s, rm);
P
pbrook 已提交
11101
        tcg_gen_add_i32(addr, addr, tmp);
11102
        tcg_temp_free_i32(tmp);
B
bellard 已提交
11103

11104
        if (op < 3) { /* store */
P
pbrook 已提交
11105
            tmp = load_reg(s, rd);
11106 11107 11108
        } else {
            tmp = tcg_temp_new_i32();
        }
B
bellard 已提交
11109 11110 11111

        switch (op) {
        case 0: /* str */
11112
            gen_aa32_st32(s, tmp, addr, get_mem_index(s));
B
bellard 已提交
11113 11114
            break;
        case 1: /* strh */
11115
            gen_aa32_st16(s, tmp, addr, get_mem_index(s));
B
bellard 已提交
11116 11117
            break;
        case 2: /* strb */
11118
            gen_aa32_st8(s, tmp, addr, get_mem_index(s));
B
bellard 已提交
11119 11120
            break;
        case 3: /* ldrsb */
11121
            gen_aa32_ld8s(s, tmp, addr, get_mem_index(s));
B
bellard 已提交
11122 11123
            break;
        case 4: /* ldr */
11124
            gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
B
bellard 已提交
11125 11126
            break;
        case 5: /* ldrh */
11127
            gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
B
bellard 已提交
11128 11129
            break;
        case 6: /* ldrb */
11130
            gen_aa32_ld8u(s, tmp, addr, get_mem_index(s));
B
bellard 已提交
11131 11132
            break;
        case 7: /* ldrsh */
11133
            gen_aa32_ld16s(s, tmp, addr, get_mem_index(s));
B
bellard 已提交
11134 11135
            break;
        }
11136
        if (op >= 3) { /* load */
P
pbrook 已提交
11137
            store_reg(s, rd, tmp);
11138 11139 11140
        } else {
            tcg_temp_free_i32(tmp);
        }
11141
        tcg_temp_free_i32(addr);
B
bellard 已提交
11142 11143 11144 11145 11146 11147
        break;

    case 6:
        /* load/store word immediate offset */
        rd = insn & 7;
        rn = (insn >> 3) & 7;
P
pbrook 已提交
11148
        addr = load_reg(s, rn);
B
bellard 已提交
11149
        val = (insn >> 4) & 0x7c;
P
pbrook 已提交
11150
        tcg_gen_addi_i32(addr, addr, val);
B
bellard 已提交
11151 11152 11153

        if (insn & (1 << 11)) {
            /* load */
11154
            tmp = tcg_temp_new_i32();
11155
            gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
11156
            store_reg(s, rd, tmp);
B
bellard 已提交
11157 11158
        } else {
            /* store */
P
pbrook 已提交
11159
            tmp = load_reg(s, rd);
11160
            gen_aa32_st32(s, tmp, addr, get_mem_index(s));
11161
            tcg_temp_free_i32(tmp);
B
bellard 已提交
11162
        }
11163
        tcg_temp_free_i32(addr);
B
bellard 已提交
11164 11165 11166 11167 11168 11169
        break;

    case 7:
        /* load/store byte immediate offset */
        rd = insn & 7;
        rn = (insn >> 3) & 7;
P
pbrook 已提交
11170
        addr = load_reg(s, rn);
B
bellard 已提交
11171
        val = (insn >> 6) & 0x1f;
P
pbrook 已提交
11172
        tcg_gen_addi_i32(addr, addr, val);
B
bellard 已提交
11173 11174 11175

        if (insn & (1 << 11)) {
            /* load */
11176
            tmp = tcg_temp_new_i32();
11177
            gen_aa32_ld8u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
11178
            store_reg(s, rd, tmp);
B
bellard 已提交
11179 11180
        } else {
            /* store */
P
pbrook 已提交
11181
            tmp = load_reg(s, rd);
11182
            gen_aa32_st8(s, tmp, addr, get_mem_index(s));
11183
            tcg_temp_free_i32(tmp);
B
bellard 已提交
11184
        }
11185
        tcg_temp_free_i32(addr);
B
bellard 已提交
11186 11187 11188 11189 11190 11191
        break;

    case 8:
        /* load/store halfword immediate offset */
        rd = insn & 7;
        rn = (insn >> 3) & 7;
P
pbrook 已提交
11192
        addr = load_reg(s, rn);
B
bellard 已提交
11193
        val = (insn >> 5) & 0x3e;
P
pbrook 已提交
11194
        tcg_gen_addi_i32(addr, addr, val);
B
bellard 已提交
11195 11196 11197

        if (insn & (1 << 11)) {
            /* load */
11198
            tmp = tcg_temp_new_i32();
11199
            gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
11200
            store_reg(s, rd, tmp);
B
bellard 已提交
11201 11202
        } else {
            /* store */
P
pbrook 已提交
11203
            tmp = load_reg(s, rd);
11204
            gen_aa32_st16(s, tmp, addr, get_mem_index(s));
11205
            tcg_temp_free_i32(tmp);
B
bellard 已提交
11206
        }
11207
        tcg_temp_free_i32(addr);
B
bellard 已提交
11208 11209 11210 11211 11212
        break;

    case 9:
        /* load/store from stack */
        rd = (insn >> 8) & 7;
P
pbrook 已提交
11213
        addr = load_reg(s, 13);
B
bellard 已提交
11214
        val = (insn & 0xff) * 4;
P
pbrook 已提交
11215
        tcg_gen_addi_i32(addr, addr, val);
B
bellard 已提交
11216 11217 11218

        if (insn & (1 << 11)) {
            /* load */
11219
            tmp = tcg_temp_new_i32();
11220
            gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
11221
            store_reg(s, rd, tmp);
B
bellard 已提交
11222 11223
        } else {
            /* store */
P
pbrook 已提交
11224
            tmp = load_reg(s, rd);
11225
            gen_aa32_st32(s, tmp, addr, get_mem_index(s));
11226
            tcg_temp_free_i32(tmp);
B
bellard 已提交
11227
        }
11228
        tcg_temp_free_i32(addr);
B
bellard 已提交
11229 11230 11231 11232 11233
        break;

    case 10:
        /* add to high reg */
        rd = (insn >> 8) & 7;
B
bellard 已提交
11234 11235
        if (insn & (1 << 11)) {
            /* SP */
P
pbrook 已提交
11236
            tmp = load_reg(s, 13);
B
bellard 已提交
11237 11238
        } else {
            /* PC. bit 1 is ignored.  */
11239
            tmp = tcg_temp_new_i32();
P
pbrook 已提交
11240
            tcg_gen_movi_i32(tmp, (s->pc + 2) & ~(uint32_t)2);
B
bellard 已提交
11241
        }
B
bellard 已提交
11242
        val = (insn & 0xff) * 4;
P
pbrook 已提交
11243 11244
        tcg_gen_addi_i32(tmp, tmp, val);
        store_reg(s, rd, tmp);
B
bellard 已提交
11245 11246 11247 11248 11249 11250 11251 11252
        break;

    case 11:
        /* misc */
        op = (insn >> 8) & 0xf;
        switch (op) {
        case 0:
            /* adjust stack pointer */
P
pbrook 已提交
11253
            tmp = load_reg(s, 13);
B
bellard 已提交
11254 11255
            val = (insn & 0x7f) * 4;
            if (insn & (1 << 7))
B
balrog 已提交
11256
                val = -(int32_t)val;
P
pbrook 已提交
11257 11258
            tcg_gen_addi_i32(tmp, tmp, val);
            store_reg(s, 13, tmp);
B
bellard 已提交
11259 11260
            break;

P
pbrook 已提交
11261 11262 11263 11264
        case 2: /* sign/zero extend.  */
            ARCH(6);
            rd = insn & 7;
            rm = (insn >> 3) & 7;
P
pbrook 已提交
11265
            tmp = load_reg(s, rm);
P
pbrook 已提交
11266
            switch ((insn >> 6) & 3) {
P
pbrook 已提交
11267 11268 11269 11270
            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 已提交
11271
            }
P
pbrook 已提交
11272
            store_reg(s, rd, tmp);
P
pbrook 已提交
11273
            break;
B
bellard 已提交
11274 11275
        case 4: case 5: case 0xc: case 0xd:
            /* push/pop */
P
pbrook 已提交
11276
            addr = load_reg(s, 13);
B
bellard 已提交
11277 11278
            if (insn & (1 << 8))
                offset = 4;
B
bellard 已提交
11279
            else
B
bellard 已提交
11280 11281 11282 11283 11284 11285
                offset = 0;
            for (i = 0; i < 8; i++) {
                if (insn & (1 << i))
                    offset += 4;
            }
            if ((insn & (1 << 11)) == 0) {
P
pbrook 已提交
11286
                tcg_gen_addi_i32(addr, addr, -offset);
B
bellard 已提交
11287
            }
B
bellard 已提交
11288 11289 11290 11291
            for (i = 0; i < 8; i++) {
                if (insn & (1 << i)) {
                    if (insn & (1 << 11)) {
                        /* pop */
11292
                        tmp = tcg_temp_new_i32();
11293
                        gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
11294
                        store_reg(s, i, tmp);
B
bellard 已提交
11295 11296
                    } else {
                        /* push */
P
pbrook 已提交
11297
                        tmp = load_reg(s, i);
11298
                        gen_aa32_st32(s, tmp, addr, get_mem_index(s));
11299
                        tcg_temp_free_i32(tmp);
B
bellard 已提交
11300
                    }
B
bellard 已提交
11301
                    /* advance to the next address.  */
P
pbrook 已提交
11302
                    tcg_gen_addi_i32(addr, addr, 4);
B
bellard 已提交
11303 11304
                }
            }
11305
            TCGV_UNUSED_I32(tmp);
B
bellard 已提交
11306 11307 11308
            if (insn & (1 << 8)) {
                if (insn & (1 << 11)) {
                    /* pop pc */
11309
                    tmp = tcg_temp_new_i32();
11310
                    gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
B
bellard 已提交
11311 11312 11313 11314
                    /* don't set the pc until the rest of the instruction
                       has completed */
                } else {
                    /* push lr */
P
pbrook 已提交
11315
                    tmp = load_reg(s, 14);
11316
                    gen_aa32_st32(s, tmp, addr, get_mem_index(s));
11317
                    tcg_temp_free_i32(tmp);
B
bellard 已提交
11318
                }
P
pbrook 已提交
11319
                tcg_gen_addi_i32(addr, addr, 4);
B
bellard 已提交
11320
            }
B
bellard 已提交
11321
            if ((insn & (1 << 11)) == 0) {
P
pbrook 已提交
11322
                tcg_gen_addi_i32(addr, addr, -offset);
B
bellard 已提交
11323
            }
B
bellard 已提交
11324
            /* write back the new stack pointer */
P
pbrook 已提交
11325
            store_reg(s, 13, addr);
B
bellard 已提交
11326
            /* set the new PC value */
11327
            if ((insn & 0x0900) == 0x0900) {
11328
                store_reg_from_load(s, 15, tmp);
11329
            }
B
bellard 已提交
11330 11331
            break;

P
pbrook 已提交
11332 11333
        case 1: case 3: case 9: case 11: /* czb */
            rm = insn & 7;
P
pbrook 已提交
11334
            tmp = load_reg(s, rm);
P
pbrook 已提交
11335 11336 11337
            s->condlabel = gen_new_label();
            s->condjmp = 1;
            if (insn & (1 << 11))
P
pbrook 已提交
11338
                tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, s->condlabel);
P
pbrook 已提交
11339
            else
P
pbrook 已提交
11340
                tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, s->condlabel);
11341
            tcg_temp_free_i32(tmp);
P
pbrook 已提交
11342 11343 11344 11345 11346 11347 11348 11349 11350 11351 11352 11353 11354 11355 11356 11357 11358
            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 已提交
11359
        case 0xe: /* bkpt */
11360 11361
        {
            int imm8 = extract32(insn, 0, 8);
11362
            ARCH(5);
11363 11364
            gen_exception_insn(s, 2, EXCP_BKPT, syn_aa32_bkpt(imm8, true),
                               default_exception_el(s));
P
pbrook 已提交
11365
            break;
11366
        }
P
pbrook 已提交
11367

11368 11369 11370 11371 11372 11373 11374 11375 11376 11377 11378 11379 11380
        case 0xa: /* rev, and hlt */
        {
            int op1 = extract32(insn, 6, 2);

            if (op1 == 2) {
                /* HLT */
                int imm6 = extract32(insn, 0, 6);

                gen_hlt(s, imm6);
                break;
            }

            /* Otherwise this is rev */
P
pbrook 已提交
11381 11382 11383
            ARCH(6);
            rn = (insn >> 3) & 0x7;
            rd = insn & 0x7;
P
pbrook 已提交
11384
            tmp = load_reg(s, rn);
11385
            switch (op1) {
A
aurel32 已提交
11386
            case 0: tcg_gen_bswap32_i32(tmp, tmp); break;
P
pbrook 已提交
11387 11388
            case 1: gen_rev16(tmp); break;
            case 3: gen_revsh(tmp); break;
11389 11390
            default:
                g_assert_not_reached();
P
pbrook 已提交
11391
            }
P
pbrook 已提交
11392
            store_reg(s, rd, tmp);
P
pbrook 已提交
11393
            break;
11394
        }
P
pbrook 已提交
11395

11396 11397 11398 11399 11400
        case 6:
            switch ((insn >> 5) & 7) {
            case 2:
                /* setend */
                ARCH(6);
P
Paolo Bonzini 已提交
11401 11402 11403
                if (((insn >> 3) & 1) != !!(s->be_data == MO_BE)) {
                    gen_helper_setend(cpu_env);
                    s->is_jmp = DISAS_UPDATE;
11404
                }
P
pbrook 已提交
11405
                break;
11406 11407 11408 11409 11410
            case 3:
                /* cps */
                ARCH(6);
                if (IS_USER(s)) {
                    break;
P
pbrook 已提交
11411
                }
11412
                if (arm_dc_feature(s, ARM_FEATURE_M)) {
11413 11414 11415 11416 11417 11418 11419 11420 11421 11422 11423 11424 11425 11426 11427 11428 11429 11430 11431 11432 11433 11434
                    tmp = tcg_const_i32((insn & (1 << 4)) != 0);
                    /* FAULTMASK */
                    if (insn & 1) {
                        addr = tcg_const_i32(19);
                        gen_helper_v7m_msr(cpu_env, addr, tmp);
                        tcg_temp_free_i32(addr);
                    }
                    /* PRIMASK */
                    if (insn & 2) {
                        addr = tcg_const_i32(16);
                        gen_helper_v7m_msr(cpu_env, addr, tmp);
                        tcg_temp_free_i32(addr);
                    }
                    tcg_temp_free_i32(tmp);
                    gen_lookup_tb(s);
                } else {
                    if (insn & (1 << 4)) {
                        shift = CPSR_A | CPSR_I | CPSR_F;
                    } else {
                        shift = 0;
                    }
                    gen_set_psr_im(s, ((insn & 7) << 6), 0, shift);
P
pbrook 已提交
11435
                }
11436 11437 11438
                break;
            default:
                goto undef;
P
pbrook 已提交
11439 11440 11441
            }
            break;

B
bellard 已提交
11442 11443 11444 11445 11446 11447
        default:
            goto undef;
        }
        break;

    case 12:
11448
    {
B
bellard 已提交
11449
        /* load/store multiple */
11450 11451
        TCGv_i32 loaded_var;
        TCGV_UNUSED_I32(loaded_var);
B
bellard 已提交
11452
        rn = (insn >> 8) & 0x7;
P
pbrook 已提交
11453
        addr = load_reg(s, rn);
B
bellard 已提交
11454 11455 11456 11457
        for (i = 0; i < 8; i++) {
            if (insn & (1 << i)) {
                if (insn & (1 << 11)) {
                    /* load */
11458
                    tmp = tcg_temp_new_i32();
11459
                    gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
11460 11461 11462 11463 11464
                    if (i == rn) {
                        loaded_var = tmp;
                    } else {
                        store_reg(s, i, tmp);
                    }
B
bellard 已提交
11465 11466
                } else {
                    /* store */
P
pbrook 已提交
11467
                    tmp = load_reg(s, i);
11468
                    gen_aa32_st32(s, tmp, addr, get_mem_index(s));
11469
                    tcg_temp_free_i32(tmp);
B
bellard 已提交
11470
                }
B
bellard 已提交
11471
                /* advance to the next address */
P
pbrook 已提交
11472
                tcg_gen_addi_i32(addr, addr, 4);
B
bellard 已提交
11473 11474
            }
        }
P
pbrook 已提交
11475
        if ((insn & (1 << rn)) == 0) {
11476
            /* base reg not in list: base register writeback */
P
pbrook 已提交
11477 11478
            store_reg(s, rn, addr);
        } else {
11479 11480 11481 11482
            /* base reg in list: if load, complete it now */
            if (insn & (1 << 11)) {
                store_reg(s, rn, loaded_var);
            }
11483
            tcg_temp_free_i32(addr);
P
pbrook 已提交
11484
        }
B
bellard 已提交
11485
        break;
11486
    }
B
bellard 已提交
11487 11488 11489 11490 11491 11492 11493 11494
    case 13:
        /* conditional branch or swi */
        cond = (insn >> 8) & 0xf;
        if (cond == 0xe)
            goto undef;

        if (cond == 0xf) {
            /* swi */
11495
            gen_set_pc_im(s, s->pc);
11496
            s->svc_imm = extract32(insn, 0, 8);
P
pbrook 已提交
11497
            s->is_jmp = DISAS_SWI;
B
bellard 已提交
11498 11499 11500
            break;
        }
        /* generate a conditional jump to next instruction */
11501
        s->condlabel = gen_new_label();
11502
        arm_gen_test_cc(cond ^ 1, s->condlabel);
11503
        s->condjmp = 1;
B
bellard 已提交
11504 11505

        /* jump to the offset */
B
bellard 已提交
11506
        val = (uint32_t)s->pc + 2;
B
bellard 已提交
11507
        offset = ((int32_t)insn << 24) >> 24;
B
bellard 已提交
11508
        val += offset << 1;
B
bellard 已提交
11509
        gen_jmp(s, val);
B
bellard 已提交
11510 11511 11512
        break;

    case 14:
P
pbrook 已提交
11513
        if (insn & (1 << 11)) {
P
pbrook 已提交
11514 11515
            if (disas_thumb2_insn(env, s, insn))
              goto undef32;
P
pbrook 已提交
11516 11517
            break;
        }
P
pbrook 已提交
11518
        /* unconditional branch */
B
bellard 已提交
11519 11520 11521
        val = (uint32_t)s->pc;
        offset = ((int32_t)insn << 21) >> 21;
        val += (offset << 1) + 2;
B
bellard 已提交
11522
        gen_jmp(s, val);
B
bellard 已提交
11523 11524 11525
        break;

    case 15:
P
pbrook 已提交
11526
        if (disas_thumb2_insn(env, s, insn))
B
balrog 已提交
11527
            goto undef32;
P
pbrook 已提交
11528
        break;
B
bellard 已提交
11529 11530
    }
    return;
P
pbrook 已提交
11531
undef32:
11532 11533
    gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized(),
                       default_exception_el(s));
P
pbrook 已提交
11534 11535
    return;
illegal_op:
B
bellard 已提交
11536
undef:
11537 11538
    gen_exception_insn(s, 2, EXCP_UDEF, syn_uncategorized(),
                       default_exception_el(s));
B
bellard 已提交
11539 11540
}

11541 11542 11543 11544 11545 11546 11547 11548 11549 11550 11551 11552 11553
static bool insn_crosses_page(CPUARMState *env, DisasContext *s)
{
    /* Return true if the insn at dc->pc might cross a page boundary.
     * (False positives are OK, false negatives are not.)
     */
    uint16_t insn;

    if ((s->pc & 3) == 0) {
        /* At a 4-aligned address we can't be crossing a page */
        return false;
    }

    /* This must be a Thumb insn */
11554
    insn = arm_lduw_code(env, s->pc, s->sctlr_b);
11555 11556 11557 11558 11559 11560 11561 11562 11563 11564 11565 11566 11567 11568 11569

    if ((insn >> 11) >= 0x1d) {
        /* Top five bits 0b11101 / 0b11110 / 0b11111 : this is the
         * First half of a 32-bit Thumb insn. Thumb-1 cores might
         * end up actually treating this as two 16-bit insns (see the
         * code at the start of disas_thumb2_insn()) but we don't bother
         * to check for that as it is unlikely, and false positives here
         * are harmless.
         */
        return true;
    }
    /* Definitely a 16-bit insn, can't be crossing a page. */
    return false;
}

11570
/* generate intermediate code for basic block 'tb'.  */
11571
void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
B
bellard 已提交
11572
{
11573
    ARMCPU *cpu = arm_env_get_cpu(env);
11574
    CPUState *cs = CPU(cpu);
B
bellard 已提交
11575
    DisasContext dc1, *dc = &dc1;
B
bellard 已提交
11576
    target_ulong pc_start;
11577
    target_ulong next_page_start;
P
pbrook 已提交
11578 11579
    int num_insns;
    int max_insns;
11580
    bool end_of_page;
11581

B
bellard 已提交
11582
    /* generate intermediate code */
11583 11584 11585 11586 11587

    /* The A64 decoder has its own top level loop, because it doesn't need
     * the A32/T32 complexity to do with conditional execution/IT blocks/etc.
     */
    if (ARM_TBFLAG_AARCH64_STATE(tb->flags)) {
11588
        gen_intermediate_code_a64(cpu, tb);
11589 11590 11591
        return;
    }

B
bellard 已提交
11592
    pc_start = tb->pc;
11593

B
bellard 已提交
11594 11595 11596 11597
    dc->tb = tb;

    dc->is_jmp = DISAS_NEXT;
    dc->pc = pc_start;
11598
    dc->singlestep_enabled = cs->singlestep_enabled;
11599
    dc->condjmp = 0;
11600

11601
    dc->aarch64 = 0;
11602 11603 11604 11605 11606
    /* If we are coming from secure EL0 in a system with a 32-bit EL3, then
     * there is no secure EL1, so we route exceptions to EL3.
     */
    dc->secure_routed_to_el3 = arm_feature(env, ARM_FEATURE_EL3) &&
                               !arm_el_is_aa64(env, 3);
11607
    dc->thumb = ARM_TBFLAG_THUMB(tb->flags);
11608
    dc->sctlr_b = ARM_TBFLAG_SCTLR_B(tb->flags);
11609
    dc->be_data = ARM_TBFLAG_BE_DATA(tb->flags) ? MO_BE : MO_LE;
11610 11611
    dc->condexec_mask = (ARM_TBFLAG_CONDEXEC(tb->flags) & 0xf) << 1;
    dc->condexec_cond = ARM_TBFLAG_CONDEXEC(tb->flags) >> 4;
11612 11613
    dc->mmu_idx = ARM_TBFLAG_MMUIDX(tb->flags);
    dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx);
11614
#if !defined(CONFIG_USER_ONLY)
11615
    dc->user = (dc->current_el == 0);
11616
#endif
11617
    dc->ns = ARM_TBFLAG_NS(tb->flags);
11618
    dc->fp_excp_el = ARM_TBFLAG_FPEXC_EL(tb->flags);
11619 11620 11621
    dc->vfp_enabled = ARM_TBFLAG_VFPEN(tb->flags);
    dc->vec_len = ARM_TBFLAG_VECLEN(tb->flags);
    dc->vec_stride = ARM_TBFLAG_VECSTRIDE(tb->flags);
11622
    dc->c15_cpar = ARM_TBFLAG_XSCALE_CPAR(tb->flags);
11623
    dc->cp_regs = cpu->cp_regs;
11624
    dc->features = env->features;
11625

11626 11627 11628 11629 11630 11631 11632 11633 11634 11635 11636 11637 11638 11639 11640 11641 11642 11643 11644 11645
    /* Single step state. The code-generation logic here is:
     *  SS_ACTIVE == 0:
     *   generate code with no special handling for single-stepping (except
     *   that anything that can make us go to SS_ACTIVE == 1 must end the TB;
     *   this happens anyway because those changes are all system register or
     *   PSTATE writes).
     *  SS_ACTIVE == 1, PSTATE.SS == 1: (active-not-pending)
     *   emit code for one insn
     *   emit code to clear PSTATE.SS
     *   emit code to generate software step exception for completed step
     *   end TB (as usual for having generated an exception)
     *  SS_ACTIVE == 1, PSTATE.SS == 0: (active-pending)
     *   emit code to generate a software step exception
     *   end the TB
     */
    dc->ss_active = ARM_TBFLAG_SS_ACTIVE(tb->flags);
    dc->pstate_ss = ARM_TBFLAG_PSTATE_SS(tb->flags);
    dc->is_ldex = false;
    dc->ss_same_el = false; /* Can't be true since EL_d must be AArch64 */

P
pbrook 已提交
11646 11647 11648 11649
    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 已提交
11650 11651
    cpu_V0 = cpu_F0d;
    cpu_V1 = cpu_F1d;
P
pbrook 已提交
11652
    /* FIXME: cpu_M0 can probably be the same as cpu_V0.  */
P
pbrook 已提交
11653
    cpu_M0 = tcg_temp_new_i64();
B
bellard 已提交
11654
    next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
P
pbrook 已提交
11655 11656
    num_insns = 0;
    max_insns = tb->cflags & CF_COUNT_MASK;
R
Richard Henderson 已提交
11657
    if (max_insns == 0) {
P
pbrook 已提交
11658
        max_insns = CF_COUNT_MASK;
R
Richard Henderson 已提交
11659 11660 11661 11662
    }
    if (max_insns > TCG_MAX_INSNS) {
        max_insns = TCG_MAX_INSNS;
    }
P
pbrook 已提交
11663

11664
    gen_tb_start(tb);
11665

11666 11667
    tcg_clear_temp_count();

11668 11669 11670
    /* A note on handling of the condexec (IT) bits:
     *
     * We want to avoid the overhead of having to write the updated condexec
11671
     * bits back to the CPUARMState for every instruction in an IT block. So:
11672
     * (1) if the condexec bits are not already zero then we write
11673
     * zero back into the CPUARMState now. This avoids complications trying
11674 11675 11676 11677 11678
     * to do it at the end of the block. (For example if we don't do this
     * it's hard to identify whether we can safely skip writing condexec
     * at the end of the TB, which we definitely want to do for the case
     * where a TB doesn't do anything with the IT state at all.)
     * (2) if we are going to leave the TB then we call gen_set_condexec()
11679
     * which will write the correct value into CPUARMState if zero is wrong.
11680 11681 11682 11683 11684 11685
     * This is done both for leaving the TB at the end, and for leaving
     * it because of an exception we know will happen, which is done in
     * gen_exception_insn(). The latter is necessary because we need to
     * leave the TB with the PC/IT state just prior to execution of the
     * instruction which caused the exception.
     * (3) if we leave the TB unexpectedly (eg a data abort on a load)
11686
     * then the CPUARMState will be wrong and we need to reset it.
11687
     * This is handled in the same way as restoration of the
11688 11689 11690
     * PC in these situations; we save the value of the condexec bits
     * for each PC via tcg_gen_insn_start(), and restore_state_to_opc()
     * then uses this to restore them after an exception.
11691 11692 11693
     *
     * Note that there are no instructions which can read the condexec
     * bits, and none which can write non-static values to them, so
11694
     * we don't need to care about whether CPUARMState is correct in the
11695 11696 11697
     * middle of a TB.
     */

P
pbrook 已提交
11698 11699
    /* Reset the conditional execution bits immediately. This avoids
       complications trying to do it at the end of the block.  */
11700
    if (dc->condexec_mask || dc->condexec_cond)
P
pbrook 已提交
11701
      {
11702
        TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
11703
        tcg_gen_movi_i32(tmp, 0);
P
pbrook 已提交
11704
        store_cpu_field(tmp, condexec_bits);
P
pbrook 已提交
11705
      }
B
bellard 已提交
11706
    do {
11707
        tcg_gen_insn_start(dc->pc,
11708 11709
                           (dc->condexec_cond << 4) | (dc->condexec_mask >> 1),
                           0);
11710 11711
        num_insns++;

11712 11713
#ifdef CONFIG_USER_ONLY
        /* Intercept jump to the magic kernel page.  */
11714
        if (dc->pc >= 0xffff0000) {
11715 11716
            /* We always get here via a jump, so know we are not in a
               conditional execution block.  */
11717
            gen_exception_internal(EXCP_KERNEL_TRAP);
11718
            dc->is_jmp = DISAS_EXC;
11719 11720 11721
            break;
        }
#else
11722 11723 11724 11725 11726 11727
        if (arm_dc_feature(dc, ARM_FEATURE_M)) {
            /* Branches to the magic exception-return addresses should
             * already have been caught via the arm_v7m_unassigned_access hook,
             * and never get here.
             */
            assert(dc->pc < 0xfffffff0);
P
pbrook 已提交
11728 11729 11730
        }
#endif

11731
        if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
11732
            CPUBreakpoint *bp;
11733
            QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
11734
                if (bp->pc == dc->pc) {
11735
                    if (bp->flags & BP_CPU) {
11736
                        gen_set_condexec(dc);
11737
                        gen_set_pc_im(dc, dc->pc);
11738 11739 11740 11741 11742
                        gen_helper_check_breakpoints(cpu_env);
                        /* End the TB early; it's likely not going to be executed */
                        dc->is_jmp = DISAS_UPDATE;
                    } else {
                        gen_exception_internal_insn(dc, 0, EXCP_DEBUG);
11743 11744 11745 11746 11747
                        /* The address covered by the breakpoint must be
                           included in [tb->pc, tb->pc + tb->size) in order
                           to for it to be properly cleared -- thus we
                           increment the PC here so that the logic setting
                           tb->size below does the right thing.  */
11748 11749 11750 11751 11752 11753
                        /* TODO: Advance PC by correct instruction length to
                         * avoid disassembler error messages */
                        dc->pc += 2;
                        goto done_generating;
                    }
                    break;
B
bellard 已提交
11754 11755 11756
                }
            }
        }
11757

11758
        if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
P
pbrook 已提交
11759
            gen_io_start();
11760
        }
P
pbrook 已提交
11761

11762 11763 11764 11765 11766 11767 11768 11769 11770 11771 11772
        if (dc->ss_active && !dc->pstate_ss) {
            /* Singlestep state is Active-pending.
             * If we're in this state at the start of a TB then either
             *  a) we just took an exception to an EL which is being debugged
             *     and this is the first insn in the exception handler
             *  b) debug exceptions were masked and we just unmasked them
             *     without changing EL (eg by clearing PSTATE.D)
             * In either case we're going to take a swstep exception in the
             * "did not step an insn" case, and so the syndrome ISV and EX
             * bits should be zero.
             */
11773
            assert(num_insns == 1);
11774 11775
            gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0),
                          default_exception_el(dc));
11776 11777 11778
            goto done_generating;
        }

11779
        if (dc->thumb) {
P
pbrook 已提交
11780 11781 11782 11783 11784 11785 11786 11787 11788 11789
            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 {
11790
            unsigned int insn = arm_ldl_code(env, dc->pc, dc->sctlr_b);
11791 11792
            dc->pc += 4;
            disas_arm_insn(dc, insn);
P
pbrook 已提交
11793
        }
11794 11795 11796 11797 11798

        if (dc->condjmp && !dc->is_jmp) {
            gen_set_label(dc->condlabel);
            dc->condjmp = 0;
        }
11799 11800

        if (tcg_check_temp_count()) {
11801 11802
            fprintf(stderr, "TCG temporary leak before "TARGET_FMT_lx"\n",
                    dc->pc);
11803 11804
        }

B
balrog 已提交
11805
        /* Translation stops when a conditional branch is encountered.
11806
         * Otherwise the subsequent code could get translated several times.
B
bellard 已提交
11807
         * Also stop translation when a page boundary is reached.  This
T
ths 已提交
11808
         * ensures prefetch aborts occur at the right place.  */
11809 11810 11811 11812 11813 11814 11815 11816 11817 11818 11819 11820 11821

        /* We want to stop the TB if the next insn starts in a new page,
         * or if it spans between this page and the next. This means that
         * if we're looking at the last halfword in the page we need to
         * see if it's a 16-bit Thumb insn (which will fit in this TB)
         * or a 32-bit Thumb insn (which won't).
         * This is to avoid generating a silly TB with a single 16-bit insn
         * in it at the end of this page (which would execute correctly
         * but isn't very efficient).
         */
        end_of_page = (dc->pc >= next_page_start) ||
            ((dc->pc >= next_page_start - 3) && insn_crosses_page(env, dc));

11822
    } while (!dc->is_jmp && !tcg_op_buf_full() &&
11823
             !cs->singlestep_enabled &&
11824
             !singlestep &&
11825
             !dc->ss_active &&
11826
             !end_of_page &&
P
pbrook 已提交
11827 11828 11829 11830 11831 11832
             num_insns < max_insns);

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

B
bellard 已提交
11838
    /* At this stage dc->condjmp will only be set when the skipped
P
pbrook 已提交
11839 11840
       instruction was a conditional branch or trap, and the PC has
       already been written.  */
11841
    if (unlikely(cs->singlestep_enabled || dc->ss_active)) {
11842
        /* Unconditional and "condition passed" instruction codepath. */
P
pbrook 已提交
11843
        gen_set_condexec(dc);
11844 11845
        switch (dc->is_jmp) {
        case DISAS_SWI:
11846
            gen_ss_advance(dc);
11847 11848
            gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb),
                          default_exception_el(dc));
11849 11850
            break;
        case DISAS_HVC:
11851
            gen_ss_advance(dc);
11852
            gen_exception(EXCP_HVC, syn_aa32_hvc(dc->svc_imm), 2);
11853 11854
            break;
        case DISAS_SMC:
11855
            gen_ss_advance(dc);
11856
            gen_exception(EXCP_SMC, syn_aa32_smc(), 3);
11857 11858 11859 11860 11861 11862 11863 11864 11865 11866 11867 11868 11869 11870 11871 11872 11873 11874 11875 11876 11877 11878 11879 11880
            break;
        case DISAS_NEXT:
        case DISAS_UPDATE:
            gen_set_pc_im(dc, dc->pc);
            /* fall through */
        default:
            if (dc->ss_active) {
                gen_step_complete_exception(dc);
            } else {
                /* FIXME: Single stepping a WFI insn will not halt
                   the CPU.  */
                gen_exception_internal(EXCP_DEBUG);
            }
        }
        if (dc->condjmp) {
            /* "Condition failed" instruction codepath. */
            gen_set_label(dc->condlabel);
            gen_set_condexec(dc);
            gen_set_pc_im(dc, dc->pc);
            if (dc->ss_active) {
                gen_step_complete_exception(dc);
            } else {
                gen_exception_internal(EXCP_DEBUG);
            }
P
pbrook 已提交
11881
        }
B
bellard 已提交
11882
    } else {
P
pbrook 已提交
11883 11884
        /* While branches must always occur at the end of an IT block,
           there are a few other things that can cause us to terminate
11885
           the TB in the middle of an IT block:
P
pbrook 已提交
11886 11887 11888 11889 11890 11891
            - 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 已提交
11892 11893
        switch(dc->is_jmp) {
        case DISAS_NEXT:
11894
            gen_goto_tb(dc, 1, dc->pc);
B
bellard 已提交
11895 11896
            break;
        case DISAS_UPDATE:
11897 11898 11899 11900
            gen_set_pc_im(dc, dc->pc);
            /* fall through */
        case DISAS_JUMP:
        default:
B
bellard 已提交
11901
            /* indicate that the hash table must be used to find the next TB */
B
bellard 已提交
11902
            tcg_gen_exit_tb(0);
B
bellard 已提交
11903 11904 11905 11906
            break;
        case DISAS_TB_JUMP:
            /* nothing more to generate */
            break;
P
pbrook 已提交
11907
        case DISAS_WFI:
B
Blue Swirl 已提交
11908
            gen_helper_wfi(cpu_env);
11909 11910 11911 11912
            /* The helper doesn't necessarily throw an exception, but we
             * must go back to the main loop to check for interrupts anyway.
             */
            tcg_gen_exit_tb(0);
P
pbrook 已提交
11913
            break;
11914 11915 11916
        case DISAS_WFE:
            gen_helper_wfe(cpu_env);
            break;
11917 11918 11919
        case DISAS_YIELD:
            gen_helper_yield(cpu_env);
            break;
P
pbrook 已提交
11920
        case DISAS_SWI:
11921 11922
            gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb),
                          default_exception_el(dc));
P
pbrook 已提交
11923
            break;
11924
        case DISAS_HVC:
11925
            gen_exception(EXCP_HVC, syn_aa32_hvc(dc->svc_imm), 2);
11926 11927
            break;
        case DISAS_SMC:
11928
            gen_exception(EXCP_SMC, syn_aa32_smc(), 3);
11929
            break;
B
bellard 已提交
11930
        }
11931 11932
        if (dc->condjmp) {
            gen_set_label(dc->condlabel);
P
pbrook 已提交
11933
            gen_set_condexec(dc);
11934
            gen_goto_tb(dc, 1, dc->pc);
11935 11936
            dc->condjmp = 0;
        }
B
bellard 已提交
11937
    }
P
pbrook 已提交
11938

P
pbrook 已提交
11939
done_generating:
11940
    gen_tb_end(tb, num_insns);
B
bellard 已提交
11941 11942

#ifdef DEBUG_DISAS
11943 11944
    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) &&
        qemu_log_in_addr_range(pc_start)) {
11945
        qemu_log_lock();
11946 11947
        qemu_log("----------------\n");
        qemu_log("IN: %s\n", lookup_symbol(pc_start));
11948
        log_target_disas(cs, pc_start, dc->pc - pc_start,
11949
                         dc->thumb | (dc->sctlr_b << 1));
11950
        qemu_log("\n");
11951
        qemu_log_unlock();
B
bellard 已提交
11952 11953
    }
#endif
11954 11955
    tb->size = dc->pc - pc_start;
    tb->icount = num_insns;
B
bellard 已提交
11956 11957
}

B
bellard 已提交
11958
static const char *cpu_mode_names[16] = {
11959 11960
  "usr", "fiq", "irq", "svc", "???", "???", "mon", "abt",
  "???", "???", "hyp", "und", "???", "???", "???", "sys"
B
bellard 已提交
11961
};
P
pbrook 已提交
11962

11963 11964
void arm_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
                        int flags)
B
bellard 已提交
11965
{
11966 11967
    ARMCPU *cpu = ARM_CPU(cs);
    CPUARMState *env = &cpu->env;
B
bellard 已提交
11968
    int i;
B
bellard 已提交
11969
    uint32_t psr;
11970
    const char *ns_status;
B
bellard 已提交
11971

11972 11973 11974 11975 11976
    if (is_a64(env)) {
        aarch64_cpu_dump_state(cs, f, cpu_fprintf, flags);
        return;
    }

B
bellard 已提交
11977
    for(i=0;i<16;i++) {
B
bellard 已提交
11978
        cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
B
bellard 已提交
11979
        if ((i % 4) == 3)
B
bellard 已提交
11980
            cpu_fprintf(f, "\n");
B
bellard 已提交
11981
        else
B
bellard 已提交
11982
            cpu_fprintf(f, " ");
B
bellard 已提交
11983
    }
B
bellard 已提交
11984
    psr = cpsr_read(env);
11985 11986 11987 11988 11989 11990 11991 11992 11993

    if (arm_feature(env, ARM_FEATURE_EL3) &&
        (psr & CPSR_M) != ARM_CPU_MODE_MON) {
        ns_status = env->cp15.scr_el3 & SCR_NS ? "NS " : "S ";
    } else {
        ns_status = "";
    }

    cpu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%s%d\n",
11994
                psr,
B
bellard 已提交
11995 11996 11997 11998
                psr & (1 << 31) ? 'N' : '-',
                psr & (1 << 30) ? 'Z' : '-',
                psr & (1 << 29) ? 'C' : '-',
                psr & (1 << 28) ? 'V' : '-',
11999
                psr & CPSR_T ? 'T' : 'A',
12000
                ns_status,
B
bellard 已提交
12001
                cpu_mode_names[psr & 0xf], (psr & 0x10) ? 32 : 26);
B
bellard 已提交
12002

12003 12004 12005 12006 12007 12008 12009 12010 12011 12012 12013 12014 12015 12016 12017 12018
    if (flags & CPU_DUMP_FPU) {
        int numvfpregs = 0;
        if (arm_feature(env, ARM_FEATURE_VFP)) {
            numvfpregs += 16;
        }
        if (arm_feature(env, ARM_FEATURE_VFP3)) {
            numvfpregs += 16;
        }
        for (i = 0; i < numvfpregs; i++) {
            uint64_t v = float64_val(env->vfp.regs[i]);
            cpu_fprintf(f, "s%02d=%08x s%02d=%08x d%02d=%016" PRIx64 "\n",
                        i * 2, (uint32_t)v,
                        i * 2 + 1, (uint32_t)(v >> 32),
                        i, v);
        }
        cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.xregs[ARM_VFP_FPSCR]);
B
bellard 已提交
12019
    }
B
bellard 已提交
12020
}
B
bellard 已提交
12021

12022 12023
void restore_state_to_opc(CPUARMState *env, TranslationBlock *tb,
                          target_ulong *data)
A
aurel32 已提交
12024
{
12025
    if (is_a64(env)) {
12026
        env->pc = data[0];
12027
        env->condexec_bits = 0;
12028
        env->exception.syndrome = data[2] << ARM_INSN_START_WORD2_SHIFT;
12029
    } else {
12030 12031
        env->regs[15] = data[0];
        env->condexec_bits = data[1];
12032
        env->exception.syndrome = data[2] << ARM_INSN_START_WORD2_SHIFT;
12033
    }
A
aurel32 已提交
12034
}