translate.c 424.7 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 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
/* Flags for the disas_set_da_iss info argument:
 * lower bits hold the Rt register number, higher bits are flags.
 */
typedef enum ISSInfo {
    ISSNone = 0,
    ISSRegMask = 0x1f,
    ISSInvalid = (1 << 5),
    ISSIsAcqRel = (1 << 6),
    ISSIsWrite = (1 << 7),
    ISSIs16Bit = (1 << 8),
} ISSInfo;

/* Save the syndrome information for a Data Abort */
static void disas_set_da_iss(DisasContext *s, TCGMemOp memop, ISSInfo issinfo)
{
    uint32_t syn;
    int sas = memop & MO_SIZE;
    bool sse = memop & MO_SIGN;
    bool is_acqrel = issinfo & ISSIsAcqRel;
    bool is_write = issinfo & ISSIsWrite;
    bool is_16bit = issinfo & ISSIs16Bit;
    int srt = issinfo & ISSRegMask;

    if (issinfo & ISSInvalid) {
        /* Some callsites want to conditionally provide ISS info,
         * eg "only if this was not a writeback"
         */
        return;
    }

    if (srt == 15) {
        /* For AArch32, insns where the src/dest is R15 never generate
         * ISS information. Catching that here saves checking at all
         * the call sites.
         */
        return;
    }

    syn = syn_data_abort_with_iss(0, sas, sse, srt, 0, is_acqrel,
                                  0, 0, 0, is_write, 0, is_16bit);
    disas_set_insn_syndrome(s, syn);
}

148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
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();
    }
}

170
static inline TCGv_i32 load_cpu_offset(int offset)
P
pbrook 已提交
171
{
172
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
173 174 175 176
    tcg_gen_ld_i32(tmp, cpu_env, offset);
    return tmp;
}

177
#define load_cpu_field(name) load_cpu_offset(offsetof(CPUARMState, name))
P
pbrook 已提交
178

179
static inline void store_cpu_offset(TCGv_i32 var, int offset)
P
pbrook 已提交
180 181
{
    tcg_gen_st_i32(var, cpu_env, offset);
182
    tcg_temp_free_i32(var);
P
pbrook 已提交
183 184 185
}

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

P
pbrook 已提交
188
/* Set a variable to the value of a CPU register.  */
189
static void load_reg_var(DisasContext *s, TCGv_i32 var, int reg)
P
pbrook 已提交
190 191 192
{
    if (reg == 15) {
        uint32_t addr;
193
        /* normally, since we updated PC, we need only to add one insn */
P
pbrook 已提交
194 195 196 197 198 199
        if (s->thumb)
            addr = (long)s->pc + 2;
        else
            addr = (long)s->pc + 4;
        tcg_gen_movi_i32(var, addr);
    } else {
200
        tcg_gen_mov_i32(var, cpu_R[reg]);
P
pbrook 已提交
201 202 203 204
    }
}

/* Create a new temporary and set it to the value of a CPU register.  */
205
static inline TCGv_i32 load_reg(DisasContext *s, int reg)
P
pbrook 已提交
206
{
207
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
208 209 210 211 212 213
    load_reg_var(s, tmp, reg);
    return tmp;
}

/* Set a CPU register.  The source must be a temporary and will be
   marked as dead.  */
214
static void store_reg(DisasContext *s, int reg, TCGv_i32 var)
P
pbrook 已提交
215 216
{
    if (reg == 15) {
217 218 219 220 221 222
        /* 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 已提交
223 224
        s->is_jmp = DISAS_JUMP;
    }
225
    tcg_gen_mov_i32(cpu_R[reg], var);
226
    tcg_temp_free_i32(var);
P
pbrook 已提交
227 228 229
}

/* Value extensions.  */
P
pbrook 已提交
230 231
#define gen_uxtb(var) tcg_gen_ext8u_i32(var, var)
#define gen_uxth(var) tcg_gen_ext16u_i32(var, var)
P
pbrook 已提交
232 233 234
#define gen_sxtb(var) tcg_gen_ext8s_i32(var, var)
#define gen_sxth(var) tcg_gen_ext16s_i32(var, var)

P
pbrook 已提交
235 236
#define gen_sxtb16(var) gen_helper_sxtb16(var, var)
#define gen_uxtb16(var) gen_helper_uxtb16(var, var)
P
pbrook 已提交
237

P
pbrook 已提交
238

239
static inline void gen_set_cpsr(TCGv_i32 var, uint32_t mask)
240
{
241
    TCGv_i32 tmp_mask = tcg_const_i32(mask);
B
Blue Swirl 已提交
242
    gen_helper_cpsr_write(cpu_env, var, tmp_mask);
243 244
    tcg_temp_free_i32(tmp_mask);
}
P
pbrook 已提交
245 246 247
/* Set NZCV flags from the high 4 bits of var.  */
#define gen_set_nzcv(var) gen_set_cpsr(var, CPSR_NZCV)

248
static void gen_exception_internal(int excp)
P
pbrook 已提交
249
{
250 251 252 253 254 255 256
    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);
}

257
static void gen_exception(int excp, uint32_t syndrome, uint32_t target_el)
258 259 260
{
    TCGv_i32 tcg_excp = tcg_const_i32(excp);
    TCGv_i32 tcg_syn = tcg_const_i32(syndrome);
261
    TCGv_i32 tcg_el = tcg_const_i32(target_el);
262

263 264 265 266
    gen_helper_exception_with_syndrome(cpu_env, tcg_excp,
                                       tcg_syn, tcg_el);

    tcg_temp_free_i32(tcg_el);
267 268
    tcg_temp_free_i32(tcg_syn);
    tcg_temp_free_i32(tcg_excp);
P
pbrook 已提交
269 270
}

271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
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);
294 295
    gen_exception(EXCP_UDEF, syn_swstep(s->ss_same_el, 1, s->is_ldex),
                  default_exception_el(s));
296 297 298
    s->is_jmp = DISAS_EXC;
}

299
static void gen_smul_dual(TCGv_i32 a, TCGv_i32 b)
P
pbrook 已提交
300
{
301 302
    TCGv_i32 tmp1 = tcg_temp_new_i32();
    TCGv_i32 tmp2 = tcg_temp_new_i32();
303 304
    tcg_gen_ext16s_i32(tmp1, a);
    tcg_gen_ext16s_i32(tmp2, b);
P
pbrook 已提交
305
    tcg_gen_mul_i32(tmp1, tmp1, tmp2);
306
    tcg_temp_free_i32(tmp2);
P
pbrook 已提交
307 308 309 310
    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);
311
    tcg_temp_free_i32(tmp1);
P
pbrook 已提交
312 313 314
}

/* Byteswap each halfword.  */
315
static void gen_rev16(TCGv_i32 var)
P
pbrook 已提交
316
{
317
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
318 319 320 321 322
    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);
323
    tcg_temp_free_i32(tmp);
P
pbrook 已提交
324 325 326
}

/* Byteswap low halfword and sign extend.  */
327
static void gen_revsh(TCGv_i32 var)
P
pbrook 已提交
328
{
329 330 331
    tcg_gen_ext16u_i32(var, var);
    tcg_gen_bswap16_i32(var, var);
    tcg_gen_ext16s_i32(var, var);
P
pbrook 已提交
332 333
}

334
/* Return (b << 32) + a. Mark inputs as dead */
335
static TCGv_i64 gen_addq_msw(TCGv_i64 a, TCGv_i32 b)
P
pbrook 已提交
336
{
337 338 339
    TCGv_i64 tmp64 = tcg_temp_new_i64();

    tcg_gen_extu_i32_i64(tmp64, b);
340
    tcg_temp_free_i32(b);
341 342 343 344 345 346 347 348
    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. */
349
static TCGv_i64 gen_subq_msw(TCGv_i64 a, TCGv_i32 b)
350 351 352 353
{
    TCGv_i64 tmp64 = tcg_temp_new_i64();

    tcg_gen_extu_i32_i64(tmp64, b);
354
    tcg_temp_free_i32(b);
355 356 357 358 359
    tcg_gen_shli_i64(tmp64, tmp64, 32);
    tcg_gen_sub_i64(a, tmp64, a);

    tcg_temp_free_i64(tmp64);
    return a;
P
pbrook 已提交
360 361
}

P
pbrook 已提交
362
/* 32x32->64 multiply.  Marks inputs as dead.  */
363
static TCGv_i64 gen_mulu_i64_i32(TCGv_i32 a, TCGv_i32 b)
P
pbrook 已提交
364
{
365 366
    TCGv_i32 lo = tcg_temp_new_i32();
    TCGv_i32 hi = tcg_temp_new_i32();
367
    TCGv_i64 ret;
P
pbrook 已提交
368

369
    tcg_gen_mulu2_i32(lo, hi, a, b);
370 371
    tcg_temp_free_i32(a);
    tcg_temp_free_i32(b);
372 373 374

    ret = tcg_temp_new_i64();
    tcg_gen_concat_i32_i64(ret, lo, hi);
375 376
    tcg_temp_free_i32(lo);
    tcg_temp_free_i32(hi);
377 378

    return ret;
P
pbrook 已提交
379 380
}

381
static TCGv_i64 gen_muls_i64_i32(TCGv_i32 a, TCGv_i32 b)
P
pbrook 已提交
382
{
383 384
    TCGv_i32 lo = tcg_temp_new_i32();
    TCGv_i32 hi = tcg_temp_new_i32();
385
    TCGv_i64 ret;
P
pbrook 已提交
386

387
    tcg_gen_muls2_i32(lo, hi, a, b);
388 389
    tcg_temp_free_i32(a);
    tcg_temp_free_i32(b);
390 391 392

    ret = tcg_temp_new_i64();
    tcg_gen_concat_i32_i64(ret, lo, hi);
393 394
    tcg_temp_free_i32(lo);
    tcg_temp_free_i32(hi);
395 396

    return ret;
P
pbrook 已提交
397 398
}

P
pbrook 已提交
399
/* Swap low and high halfwords.  */
400
static void gen_swap_half(TCGv_i32 var)
P
pbrook 已提交
401
{
402
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
403 404 405
    tcg_gen_shri_i32(tmp, var, 16);
    tcg_gen_shli_i32(var, var, 16);
    tcg_gen_or_i32(var, var, tmp);
406
    tcg_temp_free_i32(tmp);
P
pbrook 已提交
407 408
}

P
pbrook 已提交
409 410 411 412 413 414 415
/* 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;
 */

416
static void gen_add16(TCGv_i32 t0, TCGv_i32 t1)
P
pbrook 已提交
417
{
418
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
419 420 421 422 423 424
    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);
425 426
    tcg_temp_free_i32(tmp);
    tcg_temp_free_i32(t1);
P
pbrook 已提交
427 428 429
}

/* Set CF to the top bit of var.  */
430
static void gen_set_CF_bit31(TCGv_i32 var)
P
pbrook 已提交
431
{
432
    tcg_gen_shri_i32(cpu_CF, var, 31);
P
pbrook 已提交
433 434 435
}

/* Set N and Z flags from var.  */
436
static inline void gen_logic_CC(TCGv_i32 var)
P
pbrook 已提交
437
{
438 439
    tcg_gen_mov_i32(cpu_NF, var);
    tcg_gen_mov_i32(cpu_ZF, var);
P
pbrook 已提交
440 441 442
}

/* T0 += T1 + CF.  */
443
static void gen_adc(TCGv_i32 t0, TCGv_i32 t1)
P
pbrook 已提交
444
{
445
    tcg_gen_add_i32(t0, t0, t1);
446
    tcg_gen_add_i32(t0, t0, cpu_CF);
P
pbrook 已提交
447 448
}

449
/* dest = T0 + T1 + CF. */
450
static void gen_add_carry(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)
451 452
{
    tcg_gen_add_i32(dest, t0, t1);
453
    tcg_gen_add_i32(dest, dest, cpu_CF);
454 455
}

P
pbrook 已提交
456
/* dest = T0 - T1 + CF - 1.  */
457
static void gen_sub_carry(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)
P
pbrook 已提交
458 459
{
    tcg_gen_sub_i32(dest, t0, t1);
460
    tcg_gen_add_i32(dest, dest, cpu_CF);
P
pbrook 已提交
461 462 463
    tcg_gen_subi_i32(dest, dest, 1);
}

464
/* dest = T0 + T1. Compute C, N, V and Z flags */
465
static void gen_add_CC(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)
466
{
467
    TCGv_i32 tmp = tcg_temp_new_i32();
468 469
    tcg_gen_movi_i32(tmp, 0);
    tcg_gen_add2_i32(cpu_NF, cpu_CF, t0, tmp, t1, tmp);
470 471 472 473 474 475 476 477
    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);
}

478
/* dest = T0 + T1 + CF.  Compute C, N, V and Z flags */
479
static void gen_adc_CC(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)
480
{
481
    TCGv_i32 tmp = tcg_temp_new_i32();
482 483 484
    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);
485
        tcg_gen_add2_i32(cpu_NF, cpu_CF, cpu_NF, cpu_CF, t1, tmp);
486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505
    } 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);
}

506
/* dest = T0 - T1. Compute C, N, V and Z flags */
507
static void gen_sub_CC(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)
508
{
509
    TCGv_i32 tmp;
510 511 512 513 514 515 516 517 518 519 520
    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 已提交
521
/* dest = T0 + ~T1 + CF.  Compute C, N, V and Z flags */
522
static void gen_sbc_CC(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)
523
{
524
    TCGv_i32 tmp = tcg_temp_new_i32();
R
Richard Henderson 已提交
525 526
    tcg_gen_not_i32(tmp, t1);
    gen_adc_CC(dest, t0, tmp);
527
    tcg_temp_free_i32(tmp);
528 529
}

530
#define GEN_SHIFT(name)                                               \
531
static void gen_##name(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)       \
532
{                                                                     \
533
    TCGv_i32 tmp1, tmp2, tmp3;                                        \
534 535 536 537 538 539 540 541 542 543 544 545 546 547 548
    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

549
static void gen_sar(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)
550
{
551
    TCGv_i32 tmp1, tmp2;
552 553 554 555 556 557 558 559 560
    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);
}

561
static void tcg_gen_abs_i32(TCGv_i32 dest, TCGv_i32 src)
562
{
563 564
    TCGv_i32 c0 = tcg_const_i32(0);
    TCGv_i32 tmp = tcg_temp_new_i32();
565 566 567 568 569
    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 已提交
570

571
static void shifter_out_im(TCGv_i32 var, int shift)
P
pbrook 已提交
572
{
P
pbrook 已提交
573
    if (shift == 0) {
574
        tcg_gen_andi_i32(cpu_CF, var, 1);
P
pbrook 已提交
575
    } else {
576 577 578 579
        tcg_gen_shri_i32(cpu_CF, var, shift);
        if (shift != 31) {
            tcg_gen_andi_i32(cpu_CF, cpu_CF, 1);
        }
P
pbrook 已提交
580 581
    }
}
P
pbrook 已提交
582

P
pbrook 已提交
583
/* Shift by immediate.  Includes special handling for shift == 0.  */
584 585
static inline void gen_arm_shift_im(TCGv_i32 var, int shiftop,
                                    int shift, int flags)
P
pbrook 已提交
586 587 588 589 590 591 592 593 594 595 596 597
{
    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) {
598
                tcg_gen_shri_i32(cpu_CF, var, 31);
P
pbrook 已提交
599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619
            }
            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);
620
            tcg_gen_rotri_i32(var, var, shift); break;
P
pbrook 已提交
621
        } else {
622
            TCGv_i32 tmp = tcg_temp_new_i32();
623
            tcg_gen_shli_i32(tmp, cpu_CF, 31);
P
pbrook 已提交
624 625 626
            if (flags)
                shifter_out_im(var, 0);
            tcg_gen_shri_i32(var, var, 1);
P
pbrook 已提交
627
            tcg_gen_or_i32(var, var, tmp);
628
            tcg_temp_free_i32(tmp);
P
pbrook 已提交
629 630 631 632
        }
    }
};

633 634
static inline void gen_arm_shift_reg(TCGv_i32 var, int shiftop,
                                     TCGv_i32 shift, int flags)
P
pbrook 已提交
635 636 637
{
    if (flags) {
        switch (shiftop) {
638 639 640 641
        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 已提交
642 643 644
        }
    } else {
        switch (shiftop) {
645 646 647 648 649 650 651 652 653
        case 0:
            gen_shl(var, var, shift);
            break;
        case 1:
            gen_shr(var, var, shift);
            break;
        case 2:
            gen_sar(var, var, shift);
            break;
654 655
        case 3: tcg_gen_andi_i32(shift, shift, 0x1f);
                tcg_gen_rotr_i32(var, var, shift); break;
P
pbrook 已提交
656 657
        }
    }
658
    tcg_temp_free_i32(shift);
P
pbrook 已提交
659 660
}

P
pbrook 已提交
661 662 663 664 665 666 667 668 669
#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; \
    }
670
static void gen_arm_parallel_addsub(int op1, int op2, TCGv_i32 a, TCGv_i32 b)
P
pbrook 已提交
671
{
P
pbrook 已提交
672
    TCGv_ptr tmp;
P
pbrook 已提交
673 674 675 676

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

P
pbrook 已提交
707 708
/* For unknown reasons Arm and Thumb-2 use arbitrarily different encodings.  */
#define PAS_OP(pfx) \
709
    switch (op1) {  \
P
pbrook 已提交
710 711 712 713 714 715 716
    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; \
    }
717
static void gen_thumb2_parallel_addsub(int op1, int op2, TCGv_i32 a, TCGv_i32 b)
P
pbrook 已提交
718
{
P
pbrook 已提交
719
    TCGv_ptr tmp;
P
pbrook 已提交
720

721
    switch (op2) {
P
pbrook 已提交
722 723
#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp)
    case 0:
P
pbrook 已提交
724
        tmp = tcg_temp_new_ptr();
725
        tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUARMState, GE));
P
pbrook 已提交
726
        PAS_OP(s)
727
        tcg_temp_free_ptr(tmp);
P
pbrook 已提交
728 729
        break;
    case 4:
P
pbrook 已提交
730
        tmp = tcg_temp_new_ptr();
731
        tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUARMState, GE));
P
pbrook 已提交
732
        PAS_OP(u)
733
        tcg_temp_free_ptr(tmp);
P
pbrook 已提交
734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751
        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 已提交
752 753
#undef PAS_OP

754
/*
755
 * Generate a conditional based on ARM condition code cc.
756 757
 * This is common between ARM and Aarch64 targets.
 */
758
void arm_test_cc(DisasCompare *cmp, int cc)
P
pbrook 已提交
759
{
760 761 762
    TCGv_i32 value;
    TCGCond cond;
    bool global = true;
P
pbrook 已提交
763 764 765 766

    switch (cc) {
    case 0: /* eq: Z */
    case 1: /* ne: !Z */
767 768
        cond = TCG_COND_EQ;
        value = cpu_ZF;
P
pbrook 已提交
769
        break;
770

P
pbrook 已提交
771 772
    case 2: /* cs: C */
    case 3: /* cc: !C */
773 774
        cond = TCG_COND_NE;
        value = cpu_CF;
P
pbrook 已提交
775
        break;
776

P
pbrook 已提交
777 778
    case 4: /* mi: N */
    case 5: /* pl: !N */
779 780
        cond = TCG_COND_LT;
        value = cpu_NF;
P
pbrook 已提交
781
        break;
782

P
pbrook 已提交
783 784
    case 6: /* vs: V */
    case 7: /* vc: !V */
785 786
        cond = TCG_COND_LT;
        value = cpu_VF;
P
pbrook 已提交
787
        break;
788

P
pbrook 已提交
789
    case 8: /* hi: C && !Z */
790 791 792 793 794 795 796 797
    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 已提交
798
        break;
799

P
pbrook 已提交
800 801
    case 10: /* ge: N == V -> N ^ V == 0 */
    case 11: /* lt: N != V -> N ^ V != 0 */
802 803 804 805 806
        /* 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 已提交
807
        break;
808

P
pbrook 已提交
809 810
    case 12: /* gt: !Z && N == V */
    case 13: /* le: Z || N != V */
811 812 813 814 815 816 817 818
        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 已提交
819
        break;
820

821 822 823 824 825 826 827 828
    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 已提交
829 830 831 832
    default:
        fprintf(stderr, "Bad condition code 0x%x\n", cc);
        abort();
    }
833 834 835 836 837

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

838
 no_invert:
839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861
    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 已提交
862
}
B
bellard 已提交
863

864
static const uint8_t table_logic_cc[16] = {
B
bellard 已提交
865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881
    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 */
};
882

P
pbrook 已提交
883 884
/* Set PC and Thumb state from an immediate address.  */
static inline void gen_bx_im(DisasContext *s, uint32_t addr)
B
bellard 已提交
885
{
886
    TCGv_i32 tmp;
B
bellard 已提交
887

888
    s->is_jmp = DISAS_JUMP;
P
pbrook 已提交
889
    if (s->thumb != (addr & 1)) {
890
        tmp = tcg_temp_new_i32();
P
pbrook 已提交
891
        tcg_gen_movi_i32(tmp, addr & 1);
892
        tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUARMState, thumb));
893
        tcg_temp_free_i32(tmp);
P
pbrook 已提交
894
    }
895
    tcg_gen_movi_i32(cpu_R[15], addr & ~1);
P
pbrook 已提交
896 897 898
}

/* Set PC and Thumb state from var.  var is marked as dead.  */
899
static inline void gen_bx(DisasContext *s, TCGv_i32 var)
P
pbrook 已提交
900
{
901
    s->is_jmp = DISAS_JUMP;
902 903 904
    tcg_gen_andi_i32(cpu_R[15], var, ~1);
    tcg_gen_andi_i32(var, var, 1);
    store_cpu_field(var, thumb);
P
pbrook 已提交
905 906
}

907 908 909
/* 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. */
910
static inline void store_reg_bx(DisasContext *s, int reg, TCGv_i32 var)
911 912 913 914 915 916 917 918
{
    if (reg == 15 && ENABLE_ARCH_7) {
        gen_bx(s, var);
    } else {
        store_reg(s, reg, var);
    }
}

919 920 921 922
/* 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. */
923
static inline void store_reg_from_load(DisasContext *s, int reg, TCGv_i32 var)
924 925 926 927 928 929 930 931
{
    if (reg == 15 && ENABLE_ARCH_5) {
        gen_bx(s, var);
    } else {
        store_reg(s, reg, var);
    }
}

932 933 934 935 936 937
#ifdef CONFIG_USER_ONLY
#define IS_USER_ONLY 1
#else
#define IS_USER_ONLY 0
#endif

938 939 940 941 942
/* 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
943
 * that the address argument is TCGv_i32 rather than TCGv.
944 945
 */

946
static inline TCGv gen_aa32_addr(DisasContext *s, TCGv_i32 a32, TCGMemOp op)
947
{
948 949 950
    TCGv addr = tcg_temp_new();
    tcg_gen_extu_i32_tl(addr, a32);

951
    /* Not needed for user-mode BE32, where we use MO_BE instead.  */
952 953
    if (!IS_USER_ONLY && s->sctlr_b && (op & MO_SIZE) < MO_32) {
        tcg_gen_xori_tl(addr, addr, 4 - (1 << (op & MO_SIZE)));
954
    }
955
    return addr;
956 957
}

958 959
static void gen_aa32_ld_i32(DisasContext *s, TCGv_i32 val, TCGv_i32 a32,
                            int index, TCGMemOp opc)
960
{
961 962 963
    TCGv addr = gen_aa32_addr(s, a32, opc);
    tcg_gen_qemu_ld_i32(val, addr, index, opc);
    tcg_temp_free(addr);
964 965
}

966 967 968 969 970 971 972
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);
}
973

974
#define DO_GEN_LD(SUFF, OPC)                                             \
975
static inline void gen_aa32_ld##SUFF(DisasContext *s, TCGv_i32 val,      \
976
                                     TCGv_i32 a32, int index)            \
977
{                                                                        \
978
    gen_aa32_ld_i32(s, val, a32, index, OPC | s->be_data);               \
979 980 981 982 983 984 985 986
}                                                                        \
static inline void gen_aa32_ld##SUFF##_iss(DisasContext *s,              \
                                           TCGv_i32 val,                 \
                                           TCGv_i32 a32, int index,      \
                                           ISSInfo issinfo)              \
{                                                                        \
    gen_aa32_ld##SUFF(s, val, a32, index);                               \
    disas_set_da_iss(s, OPC, issinfo);                                   \
987 988
}

989
#define DO_GEN_ST(SUFF, OPC)                                             \
990
static inline void gen_aa32_st##SUFF(DisasContext *s, TCGv_i32 val,      \
991
                                     TCGv_i32 a32, int index)            \
992
{                                                                        \
993
    gen_aa32_st_i32(s, val, a32, index, OPC | s->be_data);               \
994 995 996 997 998 999 1000 1001
}                                                                        \
static inline void gen_aa32_st##SUFF##_iss(DisasContext *s,              \
                                           TCGv_i32 val,                 \
                                           TCGv_i32 a32, int index,      \
                                           ISSInfo issinfo)              \
{                                                                        \
    gen_aa32_st##SUFF(s, val, a32, index);                               \
    disas_set_da_iss(s, OPC, issinfo | ISSIsWrite);                      \
1002 1003
}

1004
static inline void gen_aa32_frob64(DisasContext *s, TCGv_i64 val)
1005
{
1006 1007 1008 1009
    /* 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);
    }
1010 1011
}

1012 1013
static void gen_aa32_ld_i64(DisasContext *s, TCGv_i64 val, TCGv_i32 a32,
                            int index, TCGMemOp opc)
1014
{
1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030
    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);
1031 1032 1033

    /* Not needed for user-mode BE32, where we use MO_BE instead.  */
    if (!IS_USER_ONLY && s->sctlr_b) {
1034
        TCGv_i64 tmp = tcg_temp_new_i64();
1035
        tcg_gen_rotri_i64(tmp, val, 32);
1036 1037
        tcg_gen_qemu_st_i64(tmp, addr, index, opc);
        tcg_temp_free_i64(tmp);
1038
    } else {
1039
        tcg_gen_qemu_st_i64(val, addr, index, opc);
1040
    }
1041
    tcg_temp_free(addr);
1042 1043
}

1044 1045 1046 1047 1048
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);
}
1049

1050 1051 1052 1053 1054 1055 1056 1057
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)
1058

1059
static inline void gen_set_pc_im(DisasContext *s, target_ulong val)
P
pbrook 已提交
1060
{
1061
    tcg_gen_movi_i32(cpu_R[15], val);
P
pbrook 已提交
1062 1063
}

1064 1065 1066 1067 1068 1069 1070 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
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;
}

1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115
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;
}

1116 1117
static void gen_exception_insn(DisasContext *s, int offset, int excp,
                               int syn, uint32_t target_el)
1118 1119 1120
{
    gen_set_condexec(s);
    gen_set_pc_im(s, s->pc - offset);
1121
    gen_exception(excp, syn, target_el);
1122 1123 1124
    s->is_jmp = DISAS_JUMP;
}

B
bellard 已提交
1125 1126 1127
/* Force a TB lookup after an instruction that changes the CPU state.  */
static inline void gen_lookup_tb(DisasContext *s)
{
1128
    tcg_gen_movi_i32(cpu_R[15], s->pc & ~1);
1129
    s->is_jmp = DISAS_JUMP;
B
bellard 已提交
1130 1131
}

1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158
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 已提交
1159
static inline void gen_add_data_offset(DisasContext *s, unsigned int insn,
1160
                                       TCGv_i32 var)
B
bellard 已提交
1161
{
B
bellard 已提交
1162
    int val, rm, shift, shiftop;
1163
    TCGv_i32 offset;
B
bellard 已提交
1164 1165 1166 1167 1168 1169

    if (!(insn & (1 << 25))) {
        /* immediate */
        val = insn & 0xfff;
        if (!(insn & (1 << 23)))
            val = -val;
B
bellard 已提交
1170
        if (val != 0)
P
pbrook 已提交
1171
            tcg_gen_addi_i32(var, var, val);
B
bellard 已提交
1172 1173 1174 1175
    } else {
        /* shift/register */
        rm = (insn) & 0xf;
        shift = (insn >> 7) & 0x1f;
B
bellard 已提交
1176
        shiftop = (insn >> 5) & 3;
P
pbrook 已提交
1177
        offset = load_reg(s, rm);
P
pbrook 已提交
1178
        gen_arm_shift_im(offset, shiftop, shift, 0);
B
bellard 已提交
1179
        if (!(insn & (1 << 23)))
P
pbrook 已提交
1180
            tcg_gen_sub_i32(var, var, offset);
B
bellard 已提交
1181
        else
P
pbrook 已提交
1182
            tcg_gen_add_i32(var, var, offset);
1183
        tcg_temp_free_i32(offset);
B
bellard 已提交
1184 1185 1186
    }
}

P
pbrook 已提交
1187
static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn,
1188
                                        int extra, TCGv_i32 var)
B
bellard 已提交
1189 1190
{
    int val, rm;
1191
    TCGv_i32 offset;
1192

B
bellard 已提交
1193 1194 1195 1196 1197
    if (insn & (1 << 22)) {
        /* immediate */
        val = (insn & 0xf) | ((insn >> 4) & 0xf0);
        if (!(insn & (1 << 23)))
            val = -val;
1198
        val += extra;
B
bellard 已提交
1199
        if (val != 0)
P
pbrook 已提交
1200
            tcg_gen_addi_i32(var, var, val);
B
bellard 已提交
1201 1202
    } else {
        /* register */
P
pbrook 已提交
1203
        if (extra)
P
pbrook 已提交
1204
            tcg_gen_addi_i32(var, var, extra);
B
bellard 已提交
1205
        rm = (insn) & 0xf;
P
pbrook 已提交
1206
        offset = load_reg(s, rm);
B
bellard 已提交
1207
        if (!(insn & (1 << 23)))
P
pbrook 已提交
1208
            tcg_gen_sub_i32(var, var, offset);
B
bellard 已提交
1209
        else
P
pbrook 已提交
1210
            tcg_gen_add_i32(var, var, offset);
1211
        tcg_temp_free_i32(offset);
B
bellard 已提交
1212 1213 1214
    }
}

1215 1216 1217 1218 1219
static TCGv_ptr get_fpstatus_ptr(int neon)
{
    TCGv_ptr statusptr = tcg_temp_new_ptr();
    int offset;
    if (neon) {
1220
        offset = offsetof(CPUARMState, vfp.standard_fp_status);
1221
    } else {
1222
        offset = offsetof(CPUARMState, vfp.fp_status);
1223 1224 1225 1226 1227
    }
    tcg_gen_addi_ptr(statusptr, cpu_env, offset);
    return statusptr;
}

P
pbrook 已提交
1228 1229 1230
#define VFP_OP2(name)                                                 \
static inline void gen_vfp_##name(int dp)                             \
{                                                                     \
1231 1232 1233 1234 1235 1236 1237
    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 已提交
1238 1239
}

P
pbrook 已提交
1240 1241 1242 1243 1244 1245 1246
VFP_OP2(add)
VFP_OP2(sub)
VFP_OP2(mul)
VFP_OP2(div)

#undef VFP_OP2

1247 1248 1249
static inline void gen_vfp_F1_mul(int dp)
{
    /* Like gen_vfp_mul() but put result in F1 */
1250
    TCGv_ptr fpst = get_fpstatus_ptr(0);
1251
    if (dp) {
1252
        gen_helper_vfp_muld(cpu_F1d, cpu_F0d, cpu_F1d, fpst);
1253
    } else {
1254
        gen_helper_vfp_muls(cpu_F1s, cpu_F0s, cpu_F1s, fpst);
1255
    }
1256
    tcg_temp_free_ptr(fpst);
1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268
}

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 已提交
1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311
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 已提交
1312
        tcg_gen_movi_i64(cpu_F1d, 0);
P
pbrook 已提交
1313
    else
B
balrog 已提交
1314
        tcg_gen_movi_i32(cpu_F1s, 0);
P
pbrook 已提交
1315 1316
}

1317 1318 1319
#define VFP_GEN_ITOF(name) \
static inline void gen_vfp_##name(int dp, int neon) \
{ \
1320
    TCGv_ptr statusptr = get_fpstatus_ptr(neon); \
1321 1322 1323 1324 1325
    if (dp) { \
        gen_helper_vfp_##name##d(cpu_F0d, cpu_F0s, statusptr); \
    } else { \
        gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, statusptr); \
    } \
1326
    tcg_temp_free_ptr(statusptr); \
P
pbrook 已提交
1327 1328
}

1329 1330 1331
VFP_GEN_ITOF(uito)
VFP_GEN_ITOF(sito)
#undef VFP_GEN_ITOF
P
pbrook 已提交
1332

1333 1334 1335
#define VFP_GEN_FTOI(name) \
static inline void gen_vfp_##name(int dp, int neon) \
{ \
1336
    TCGv_ptr statusptr = get_fpstatus_ptr(neon); \
1337 1338 1339 1340 1341
    if (dp) { \
        gen_helper_vfp_##name##d(cpu_F0s, cpu_F0d, statusptr); \
    } else { \
        gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, statusptr); \
    } \
1342
    tcg_temp_free_ptr(statusptr); \
P
pbrook 已提交
1343 1344
}

1345 1346 1347 1348 1349
VFP_GEN_FTOI(toui)
VFP_GEN_FTOI(touiz)
VFP_GEN_FTOI(tosi)
VFP_GEN_FTOI(tosiz)
#undef VFP_GEN_FTOI
P
pbrook 已提交
1350

1351
#define VFP_GEN_FIX(name, round) \
1352
static inline void gen_vfp_##name(int dp, int shift, int neon) \
P
pbrook 已提交
1353
{ \
1354
    TCGv_i32 tmp_shift = tcg_const_i32(shift); \
1355
    TCGv_ptr statusptr = get_fpstatus_ptr(neon); \
1356
    if (dp) { \
1357 1358
        gen_helper_vfp_##name##d##round(cpu_F0d, cpu_F0d, tmp_shift, \
                                        statusptr); \
1359
    } else { \
1360 1361
        gen_helper_vfp_##name##s##round(cpu_F0s, cpu_F0s, tmp_shift, \
                                        statusptr); \
1362
    } \
1363
    tcg_temp_free_i32(tmp_shift); \
1364
    tcg_temp_free_ptr(statusptr); \
P
pbrook 已提交
1365
}
1366 1367 1368 1369 1370 1371 1372 1373
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 已提交
1374
#undef VFP_GEN_FIX
P
pbrook 已提交
1375

1376
static inline void gen_vfp_ld(DisasContext *s, int dp, TCGv_i32 addr)
B
bellard 已提交
1377
{
1378
    if (dp) {
1379
        gen_aa32_ld64(s, cpu_F0d, addr, get_mem_index(s));
1380
    } else {
1381
        gen_aa32_ld32u(s, cpu_F0s, addr, get_mem_index(s));
1382
    }
B
bellard 已提交
1383 1384
}

1385
static inline void gen_vfp_st(DisasContext *s, int dp, TCGv_i32 addr)
B
bellard 已提交
1386
{
1387
    if (dp) {
1388
        gen_aa32_st64(s, cpu_F0d, addr, get_mem_index(s));
1389
    } else {
1390
        gen_aa32_st32(s, cpu_F0s, addr, get_mem_index(s));
1391
    }
B
bellard 已提交
1392 1393
}

B
bellard 已提交
1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406
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 已提交
1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417

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

1418
static TCGv_i32 neon_load_reg(int reg, int pass)
P
pbrook 已提交
1419
{
1420
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
1421 1422 1423 1424
    tcg_gen_ld_i32(tmp, cpu_env, neon_reg_offset(reg, pass));
    return tmp;
}

1425
static void neon_store_reg(int reg, int pass, TCGv_i32 var)
P
pbrook 已提交
1426 1427
{
    tcg_gen_st_i32(var, cpu_env, neon_reg_offset(reg, pass));
1428
    tcg_temp_free_i32(var);
P
pbrook 已提交
1429 1430
}

P
pbrook 已提交
1431
static inline void neon_load_reg64(TCGv_i64 var, int reg)
P
pbrook 已提交
1432 1433 1434 1435
{
    tcg_gen_ld_i64(var, cpu_env, vfp_reg_offset(1, reg));
}

P
pbrook 已提交
1436
static inline void neon_store_reg64(TCGv_i64 var, int reg)
P
pbrook 已提交
1437 1438 1439 1440
{
    tcg_gen_st_i64(var, cpu_env, vfp_reg_offset(1, reg));
}

P
pbrook 已提交
1441 1442 1443 1444 1445
#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 已提交
1446 1447 1448
static inline void gen_mov_F0_vreg(int dp, int reg)
{
    if (dp)
P
pbrook 已提交
1449
        tcg_gen_ld_f64(cpu_F0d, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1450
    else
P
pbrook 已提交
1451
        tcg_gen_ld_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1452 1453 1454 1455 1456
}

static inline void gen_mov_F1_vreg(int dp, int reg)
{
    if (dp)
P
pbrook 已提交
1457
        tcg_gen_ld_f64(cpu_F1d, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1458
    else
P
pbrook 已提交
1459
        tcg_gen_ld_f32(cpu_F1s, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1460 1461 1462 1463 1464
}

static inline void gen_mov_vreg_F0(int dp, int reg)
{
    if (dp)
P
pbrook 已提交
1465
        tcg_gen_st_f64(cpu_F0d, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1466
    else
P
pbrook 已提交
1467
        tcg_gen_st_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1468 1469
}

1470 1471
#define ARM_CP_RW_BIT	(1 << 20)

P
pbrook 已提交
1472
static inline void iwmmxt_load_reg(TCGv_i64 var, int reg)
P
pbrook 已提交
1473
{
1474
    tcg_gen_ld_i64(var, cpu_env, offsetof(CPUARMState, iwmmxt.regs[reg]));
P
pbrook 已提交
1475 1476
}

P
pbrook 已提交
1477
static inline void iwmmxt_store_reg(TCGv_i64 var, int reg)
P
pbrook 已提交
1478
{
1479
    tcg_gen_st_i64(var, cpu_env, offsetof(CPUARMState, iwmmxt.regs[reg]));
P
pbrook 已提交
1480 1481
}

1482
static inline TCGv_i32 iwmmxt_load_creg(int reg)
P
pbrook 已提交
1483
{
1484
    TCGv_i32 var = tcg_temp_new_i32();
1485
    tcg_gen_ld_i32(var, cpu_env, offsetof(CPUARMState, iwmmxt.cregs[reg]));
1486
    return var;
P
pbrook 已提交
1487 1488
}

1489
static inline void iwmmxt_store_creg(int reg, TCGv_i32 var)
P
pbrook 已提交
1490
{
1491
    tcg_gen_st_i32(var, cpu_env, offsetof(CPUARMState, iwmmxt.cregs[reg]));
1492
    tcg_temp_free_i32(var);
P
pbrook 已提交
1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529
}

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

1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540
#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 已提交
1541

1542
#define IWMMXT_OP_ENV1(name) \
P
pbrook 已提交
1543 1544
static inline void gen_op_iwmmxt_##name##_M0(void) \
{ \
1545
    gen_helper_iwmmxt_##name(cpu_M0, cpu_env, cpu_M0); \
P
pbrook 已提交
1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558
}

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)

1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594
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 已提交
1595

1596 1597 1598 1599 1600 1601
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 已提交
1602 1603 1604

static void gen_op_iwmmxt_set_mup(void)
{
1605
    TCGv_i32 tmp;
P
pbrook 已提交
1606 1607 1608 1609 1610 1611 1612
    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)
{
1613
    TCGv_i32 tmp;
P
pbrook 已提交
1614 1615 1616 1617 1618 1619 1620
    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)
{
1621
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
1622 1623 1624 1625 1626 1627 1628
    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 已提交
1629
    tcg_gen_ext32u_i64(cpu_V1, cpu_V1);
P
pbrook 已提交
1630 1631 1632
    tcg_gen_add_i64(cpu_M0, cpu_M0, cpu_V1);
}

1633 1634
static inline int gen_iwmmxt_address(DisasContext *s, uint32_t insn,
                                     TCGv_i32 dest)
1635 1636 1637
{
    int rd;
    uint32_t offset;
1638
    TCGv_i32 tmp;
1639 1640

    rd = (insn >> 16) & 0xf;
1641
    tmp = load_reg(s, rd);
1642 1643 1644 1645 1646

    offset = (insn & 0xff) << ((insn >> 7) & 2);
    if (insn & (1 << 24)) {
        /* Pre indexed */
        if (insn & (1 << 23))
1647
            tcg_gen_addi_i32(tmp, tmp, offset);
1648
        else
1649 1650
            tcg_gen_addi_i32(tmp, tmp, -offset);
        tcg_gen_mov_i32(dest, tmp);
1651
        if (insn & (1 << 21))
1652 1653
            store_reg(s, rd, tmp);
        else
1654
            tcg_temp_free_i32(tmp);
1655 1656
    } else if (insn & (1 << 21)) {
        /* Post indexed */
1657
        tcg_gen_mov_i32(dest, tmp);
1658
        if (insn & (1 << 23))
1659
            tcg_gen_addi_i32(tmp, tmp, offset);
1660
        else
1661 1662
            tcg_gen_addi_i32(tmp, tmp, -offset);
        store_reg(s, rd, tmp);
1663 1664 1665 1666 1667
    } else if (!(insn & (1 << 23)))
        return 1;
    return 0;
}

1668
static inline int gen_iwmmxt_shift(uint32_t insn, uint32_t mask, TCGv_i32 dest)
1669 1670
{
    int rd = (insn >> 0) & 0xf;
1671
    TCGv_i32 tmp;
1672

1673 1674
    if (insn & (1 << 8)) {
        if (rd < ARM_IWMMXT_wCGR0 || rd > ARM_IWMMXT_wCGR3) {
1675
            return 1;
1676 1677 1678 1679
        } else {
            tmp = iwmmxt_load_creg(rd);
        }
    } else {
1680
        tmp = tcg_temp_new_i32();
1681
        iwmmxt_load_reg(cpu_V0, rd);
1682
        tcg_gen_extrl_i64_i32(tmp, cpu_V0);
1683 1684 1685
    }
    tcg_gen_andi_i32(tmp, tmp, mask);
    tcg_gen_mov_i32(dest, tmp);
1686
    tcg_temp_free_i32(tmp);
1687 1688 1689
    return 0;
}

1690
/* Disassemble an iwMMXt instruction.  Returns nonzero if an error occurred
1691
   (ie. an undefined instruction).  */
1692
static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
1693 1694 1695
{
    int rd, wrd;
    int rdhi, rdlo, rd0, rd1, i;
1696 1697
    TCGv_i32 addr;
    TCGv_i32 tmp, tmp2, tmp3;
1698 1699 1700 1701 1702 1703 1704

    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 */
1705
                iwmmxt_load_reg(cpu_V0, wrd);
1706
                tcg_gen_extrl_i64_i32(cpu_R[rdlo], cpu_V0);
1707
                tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
1708
                tcg_gen_extrl_i64_i32(cpu_R[rdhi], cpu_V0);
1709
            } else {					/* TMCRR */
1710 1711
                tcg_gen_concat_i32_i64(cpu_V0, cpu_R[rdlo], cpu_R[rdhi]);
                iwmmxt_store_reg(cpu_V0, wrd);
1712 1713 1714 1715 1716 1717
                gen_op_iwmmxt_set_mup();
            }
            return 0;
        }

        wrd = (insn >> 12) & 0xf;
1718
        addr = tcg_temp_new_i32();
1719
        if (gen_iwmmxt_address(s, insn, addr)) {
1720
            tcg_temp_free_i32(addr);
1721
            return 1;
1722
        }
1723 1724
        if (insn & ARM_CP_RW_BIT) {
            if ((insn >> 28) == 0xf) {			/* WLDRW wCx */
1725
                tmp = tcg_temp_new_i32();
1726
                gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
1727
                iwmmxt_store_creg(wrd, tmp);
1728
            } else {
P
pbrook 已提交
1729 1730 1731
                i = 1;
                if (insn & (1 << 8)) {
                    if (insn & (1 << 22)) {		/* WLDRD */
1732
                        gen_aa32_ld64(s, cpu_M0, addr, get_mem_index(s));
P
pbrook 已提交
1733 1734
                        i = 0;
                    } else {				/* WLDRW wRd */
1735
                        tmp = tcg_temp_new_i32();
1736
                        gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
1737 1738
                    }
                } else {
1739
                    tmp = tcg_temp_new_i32();
P
pbrook 已提交
1740
                    if (insn & (1 << 22)) {		/* WLDRH */
1741
                        gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
1742
                    } else {				/* WLDRB */
1743
                        gen_aa32_ld8u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
1744 1745 1746 1747
                    }
                }
                if (i) {
                    tcg_gen_extu_i32_i64(cpu_M0, tmp);
1748
                    tcg_temp_free_i32(tmp);
P
pbrook 已提交
1749
                }
1750 1751 1752 1753
                gen_op_iwmmxt_movq_wRn_M0(wrd);
            }
        } else {
            if ((insn >> 28) == 0xf) {			/* WSTRW wCx */
1754
                tmp = iwmmxt_load_creg(wrd);
1755
                gen_aa32_st32(s, tmp, addr, get_mem_index(s));
1756 1757
            } else {
                gen_op_iwmmxt_movq_M0_wRn(wrd);
1758
                tmp = tcg_temp_new_i32();
P
pbrook 已提交
1759 1760
                if (insn & (1 << 8)) {
                    if (insn & (1 << 22)) {		/* WSTRD */
1761
                        gen_aa32_st64(s, cpu_M0, addr, get_mem_index(s));
P
pbrook 已提交
1762
                    } else {				/* WSTRW wRd */
1763
                        tcg_gen_extrl_i64_i32(tmp, cpu_M0);
1764
                        gen_aa32_st32(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
1765 1766 1767
                    }
                } else {
                    if (insn & (1 << 22)) {		/* WSTRH */
1768
                        tcg_gen_extrl_i64_i32(tmp, cpu_M0);
1769
                        gen_aa32_st16(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
1770
                    } else {				/* WSTRB */
1771
                        tcg_gen_extrl_i64_i32(tmp, cpu_M0);
1772
                        gen_aa32_st8(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
1773 1774
                    }
                }
1775
            }
1776
            tcg_temp_free_i32(tmp);
1777
        }
1778
        tcg_temp_free_i32(addr);
1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809
        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:
1810 1811
            tmp = iwmmxt_load_creg(wrd);
            tmp2 = load_reg(s, rd);
1812
            tcg_gen_andc_i32(tmp, tmp, tmp2);
1813
            tcg_temp_free_i32(tmp2);
1814
            iwmmxt_store_creg(wrd, tmp);
1815 1816 1817 1818 1819 1820
            break;
        case ARM_IWMMXT_wCGR0:
        case ARM_IWMMXT_wCGR1:
        case ARM_IWMMXT_wCGR2:
        case ARM_IWMMXT_wCGR3:
            gen_op_iwmmxt_set_cup();
1821 1822
            tmp = load_reg(s, rd);
            iwmmxt_store_creg(wrd, tmp);
1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843
            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;
1844 1845
        tmp = iwmmxt_load_creg(wrd);
        store_reg(s, rd, tmp);
1846 1847 1848 1849 1850 1851
        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 已提交
1852
        tcg_gen_neg_i64(cpu_M0, cpu_M0);
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 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944
        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 已提交
1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955
        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);
        }
1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968
        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 已提交
1969 1970
            iwmmxt_load_reg(cpu_V1, wrd);
            tcg_gen_add_i64(cpu_M0, cpu_M0, cpu_V1);
1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001
        }
        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 已提交
2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012
        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);
        }
2013 2014 2015 2016 2017 2018 2019 2020 2021
        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);
2022 2023 2024 2025
        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);
2026
        tcg_temp_free_i32(tmp);
2027 2028 2029 2030
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        break;
    case 0x601: case 0x605: case 0x609: case 0x60d:	/* TINSR */
2031 2032
        if (((insn >> 6) & 3) == 3)
            return 1;
2033 2034
        rd = (insn >> 12) & 0xf;
        wrd = (insn >> 16) & 0xf;
2035
        tmp = load_reg(s, rd);
2036 2037 2038
        gen_op_iwmmxt_movq_M0_wRn(wrd);
        switch ((insn >> 6) & 3) {
        case 0:
2039 2040
            tmp2 = tcg_const_i32(0xff);
            tmp3 = tcg_const_i32((insn & 7) << 3);
2041 2042
            break;
        case 1:
2043 2044
            tmp2 = tcg_const_i32(0xffff);
            tmp3 = tcg_const_i32((insn & 3) << 4);
2045 2046
            break;
        case 2:
2047 2048
            tmp2 = tcg_const_i32(0xffffffff);
            tmp3 = tcg_const_i32((insn & 1) << 5);
2049
            break;
2050
        default:
2051 2052
            TCGV_UNUSED_I32(tmp2);
            TCGV_UNUSED_I32(tmp3);
2053
        }
2054
        gen_helper_iwmmxt_insr(cpu_M0, cpu_M0, tmp, tmp2, tmp3);
2055 2056
        tcg_temp_free_i32(tmp3);
        tcg_temp_free_i32(tmp2);
2057
        tcg_temp_free_i32(tmp);
2058 2059 2060 2061 2062 2063
        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;
2064
        if (rd == 15 || ((insn >> 22) & 3) == 3)
2065 2066
            return 1;
        gen_op_iwmmxt_movq_M0_wRn(wrd);
2067
        tmp = tcg_temp_new_i32();
2068 2069
        switch ((insn >> 22) & 3) {
        case 0:
2070
            tcg_gen_shri_i64(cpu_M0, cpu_M0, (insn & 7) << 3);
2071
            tcg_gen_extrl_i64_i32(tmp, cpu_M0);
2072 2073 2074 2075
            if (insn & 8) {
                tcg_gen_ext8s_i32(tmp, tmp);
            } else {
                tcg_gen_andi_i32(tmp, tmp, 0xff);
2076 2077 2078
            }
            break;
        case 1:
2079
            tcg_gen_shri_i64(cpu_M0, cpu_M0, (insn & 3) << 4);
2080
            tcg_gen_extrl_i64_i32(tmp, cpu_M0);
2081 2082 2083 2084
            if (insn & 8) {
                tcg_gen_ext16s_i32(tmp, tmp);
            } else {
                tcg_gen_andi_i32(tmp, tmp, 0xffff);
2085 2086 2087
            }
            break;
        case 2:
2088
            tcg_gen_shri_i64(cpu_M0, cpu_M0, (insn & 1) << 5);
2089
            tcg_gen_extrl_i64_i32(tmp, cpu_M0);
2090 2091
            break;
        }
2092
        store_reg(s, rd, tmp);
2093 2094
        break;
    case 0x117: case 0x517: case 0x917: case 0xd17:	/* TEXTRC */
2095
        if ((insn & 0x000ff008) != 0x0003f000 || ((insn >> 22) & 3) == 3)
2096
            return 1;
2097
        tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF);
2098 2099
        switch ((insn >> 22) & 3) {
        case 0:
2100
            tcg_gen_shri_i32(tmp, tmp, ((insn & 7) << 2) + 0);
2101 2102
            break;
        case 1:
2103
            tcg_gen_shri_i32(tmp, tmp, ((insn & 3) << 3) + 4);
2104 2105
            break;
        case 2:
2106
            tcg_gen_shri_i32(tmp, tmp, ((insn & 1) << 4) + 12);
2107 2108
            break;
        }
2109 2110
        tcg_gen_shli_i32(tmp, tmp, 28);
        gen_set_nzcv(tmp);
2111
        tcg_temp_free_i32(tmp);
2112 2113
        break;
    case 0x401: case 0x405: case 0x409: case 0x40d:	/* TBCST */
2114 2115
        if (((insn >> 6) & 3) == 3)
            return 1;
2116 2117
        rd = (insn >> 12) & 0xf;
        wrd = (insn >> 16) & 0xf;
2118
        tmp = load_reg(s, rd);
2119 2120
        switch ((insn >> 6) & 3) {
        case 0:
2121
            gen_helper_iwmmxt_bcstb(cpu_M0, tmp);
2122 2123
            break;
        case 1:
2124
            gen_helper_iwmmxt_bcstw(cpu_M0, tmp);
2125 2126
            break;
        case 2:
2127
            gen_helper_iwmmxt_bcstl(cpu_M0, tmp);
2128 2129
            break;
        }
2130
        tcg_temp_free_i32(tmp);
2131 2132 2133 2134
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        break;
    case 0x113: case 0x513: case 0x913: case 0xd13:	/* TANDC */
2135
        if ((insn & 0x000ff00f) != 0x0003f000 || ((insn >> 22) & 3) == 3)
2136
            return 1;
2137
        tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF);
2138
        tmp2 = tcg_temp_new_i32();
2139
        tcg_gen_mov_i32(tmp2, tmp);
2140 2141 2142
        switch ((insn >> 22) & 3) {
        case 0:
            for (i = 0; i < 7; i ++) {
2143 2144
                tcg_gen_shli_i32(tmp2, tmp2, 4);
                tcg_gen_and_i32(tmp, tmp, tmp2);
2145 2146 2147 2148
            }
            break;
        case 1:
            for (i = 0; i < 3; i ++) {
2149 2150
                tcg_gen_shli_i32(tmp2, tmp2, 8);
                tcg_gen_and_i32(tmp, tmp, tmp2);
2151 2152 2153
            }
            break;
        case 2:
2154 2155
            tcg_gen_shli_i32(tmp2, tmp2, 16);
            tcg_gen_and_i32(tmp, tmp, tmp2);
2156 2157
            break;
        }
2158
        gen_set_nzcv(tmp);
2159 2160
        tcg_temp_free_i32(tmp2);
        tcg_temp_free_i32(tmp);
2161 2162 2163 2164 2165 2166 2167
        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 已提交
2168
            gen_helper_iwmmxt_addcb(cpu_M0, cpu_M0);
2169 2170
            break;
        case 1:
P
pbrook 已提交
2171
            gen_helper_iwmmxt_addcw(cpu_M0, cpu_M0);
2172 2173
            break;
        case 2:
P
pbrook 已提交
2174
            gen_helper_iwmmxt_addcl(cpu_M0, cpu_M0);
2175 2176 2177 2178 2179 2180 2181 2182
            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 */
2183
        if ((insn & 0x000ff00f) != 0x0003f000 || ((insn >> 22) & 3) == 3)
2184
            return 1;
2185
        tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF);
2186
        tmp2 = tcg_temp_new_i32();
2187
        tcg_gen_mov_i32(tmp2, tmp);
2188 2189 2190
        switch ((insn >> 22) & 3) {
        case 0:
            for (i = 0; i < 7; i ++) {
2191 2192
                tcg_gen_shli_i32(tmp2, tmp2, 4);
                tcg_gen_or_i32(tmp, tmp, tmp2);
2193 2194 2195 2196
            }
            break;
        case 1:
            for (i = 0; i < 3; i ++) {
2197 2198
                tcg_gen_shli_i32(tmp2, tmp2, 8);
                tcg_gen_or_i32(tmp, tmp, tmp2);
2199 2200 2201
            }
            break;
        case 2:
2202 2203
            tcg_gen_shli_i32(tmp2, tmp2, 16);
            tcg_gen_or_i32(tmp, tmp, tmp2);
2204 2205
            break;
        }
2206
        gen_set_nzcv(tmp);
2207 2208
        tcg_temp_free_i32(tmp2);
        tcg_temp_free_i32(tmp);
2209 2210 2211 2212
        break;
    case 0x103: case 0x503: case 0x903: case 0xd03:	/* TMOVMSK */
        rd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
2213
        if ((insn & 0xf) != 0 || ((insn >> 22) & 3) == 3)
2214 2215
            return 1;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
2216
        tmp = tcg_temp_new_i32();
2217 2218
        switch ((insn >> 22) & 3) {
        case 0:
2219
            gen_helper_iwmmxt_msbb(tmp, cpu_M0);
2220 2221
            break;
        case 1:
2222
            gen_helper_iwmmxt_msbw(tmp, cpu_M0);
2223 2224
            break;
        case 2:
2225
            gen_helper_iwmmxt_msbl(tmp, cpu_M0);
2226 2227
            break;
        }
2228
        store_reg(s, rd, tmp);
2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325
        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:
2326 2327
        if (((insn >> 22) & 3) == 0)
            return 1;
2328 2329 2330
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
2331
        tmp = tcg_temp_new_i32();
2332
        if (gen_iwmmxt_shift(insn, 0xff, tmp)) {
2333
            tcg_temp_free_i32(tmp);
2334
            return 1;
2335
        }
2336 2337
        switch ((insn >> 22) & 3) {
        case 1:
2338
            gen_helper_iwmmxt_srlw(cpu_M0, cpu_env, cpu_M0, tmp);
2339 2340
            break;
        case 2:
2341
            gen_helper_iwmmxt_srll(cpu_M0, cpu_env, cpu_M0, tmp);
2342 2343
            break;
        case 3:
2344
            gen_helper_iwmmxt_srlq(cpu_M0, cpu_env, cpu_M0, tmp);
2345 2346
            break;
        }
2347
        tcg_temp_free_i32(tmp);
2348 2349 2350 2351 2352 2353
        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:
2354 2355
        if (((insn >> 22) & 3) == 0)
            return 1;
2356 2357 2358
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
2359
        tmp = tcg_temp_new_i32();
2360
        if (gen_iwmmxt_shift(insn, 0xff, tmp)) {
2361
            tcg_temp_free_i32(tmp);
2362
            return 1;
2363
        }
2364 2365
        switch ((insn >> 22) & 3) {
        case 1:
2366
            gen_helper_iwmmxt_sraw(cpu_M0, cpu_env, cpu_M0, tmp);
2367 2368
            break;
        case 2:
2369
            gen_helper_iwmmxt_sral(cpu_M0, cpu_env, cpu_M0, tmp);
2370 2371
            break;
        case 3:
2372
            gen_helper_iwmmxt_sraq(cpu_M0, cpu_env, cpu_M0, tmp);
2373 2374
            break;
        }
2375
        tcg_temp_free_i32(tmp);
2376 2377 2378 2379 2380 2381
        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:
2382 2383
        if (((insn >> 22) & 3) == 0)
            return 1;
2384 2385 2386
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
2387
        tmp = tcg_temp_new_i32();
2388
        if (gen_iwmmxt_shift(insn, 0xff, tmp)) {
2389
            tcg_temp_free_i32(tmp);
2390
            return 1;
2391
        }
2392 2393
        switch ((insn >> 22) & 3) {
        case 1:
2394
            gen_helper_iwmmxt_sllw(cpu_M0, cpu_env, cpu_M0, tmp);
2395 2396
            break;
        case 2:
2397
            gen_helper_iwmmxt_slll(cpu_M0, cpu_env, cpu_M0, tmp);
2398 2399
            break;
        case 3:
2400
            gen_helper_iwmmxt_sllq(cpu_M0, cpu_env, cpu_M0, tmp);
2401 2402
            break;
        }
2403
        tcg_temp_free_i32(tmp);
2404 2405 2406 2407 2408 2409
        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:
2410 2411
        if (((insn >> 22) & 3) == 0)
            return 1;
2412 2413 2414
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
2415
        tmp = tcg_temp_new_i32();
2416 2417
        switch ((insn >> 22) & 3) {
        case 1:
2418
            if (gen_iwmmxt_shift(insn, 0xf, tmp)) {
2419
                tcg_temp_free_i32(tmp);
2420
                return 1;
2421
            }
2422
            gen_helper_iwmmxt_rorw(cpu_M0, cpu_env, cpu_M0, tmp);
2423 2424
            break;
        case 2:
2425
            if (gen_iwmmxt_shift(insn, 0x1f, tmp)) {
2426
                tcg_temp_free_i32(tmp);
2427
                return 1;
2428
            }
2429
            gen_helper_iwmmxt_rorl(cpu_M0, cpu_env, cpu_M0, tmp);
2430 2431
            break;
        case 3:
2432
            if (gen_iwmmxt_shift(insn, 0x3f, tmp)) {
2433
                tcg_temp_free_i32(tmp);
2434
                return 1;
2435
            }
2436
            gen_helper_iwmmxt_rorq(cpu_M0, cpu_env, cpu_M0, tmp);
2437 2438
            break;
        }
2439
        tcg_temp_free_i32(tmp);
2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511
        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);
2512 2513 2514
        tmp = tcg_const_i32((insn >> 20) & 3);
        iwmmxt_load_reg(cpu_V1, rd1);
        gen_helper_iwmmxt_align(cpu_M0, cpu_M0, cpu_V1, tmp);
2515
        tcg_temp_free_i32(tmp);
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 2564 2565 2566 2567 2568
        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);
2569
        tmp = tcg_const_i32(((insn >> 16) & 0xf0) | (insn & 0x0f));
2570
        gen_helper_iwmmxt_shufh(cpu_M0, cpu_env, cpu_M0, tmp);
2571
        tcg_temp_free_i32(tmp);
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 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622
        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:
2623 2624
        if (!(insn & (1 << 20)) || ((insn >> 22) & 3) == 0)
            return 1;
2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662
        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);
2663 2664
        tmp = load_reg(s, rd0);
        tmp2 = load_reg(s, rd1);
2665 2666
        switch ((insn >> 16) & 0xf) {
        case 0x0:					/* TMIA */
2667
            gen_helper_iwmmxt_muladdsl(cpu_M0, cpu_M0, tmp, tmp2);
2668 2669
            break;
        case 0x8:					/* TMIAPH */
2670
            gen_helper_iwmmxt_muladdsw(cpu_M0, cpu_M0, tmp, tmp2);
2671 2672 2673
            break;
        case 0xc: case 0xd: case 0xe: case 0xf:		/* TMIAxy */
            if (insn & (1 << 16))
2674
                tcg_gen_shri_i32(tmp, tmp, 16);
2675
            if (insn & (1 << 17))
2676 2677
                tcg_gen_shri_i32(tmp2, tmp2, 16);
            gen_helper_iwmmxt_muladdswl(cpu_M0, cpu_M0, tmp, tmp2);
2678 2679
            break;
        default:
2680 2681
            tcg_temp_free_i32(tmp2);
            tcg_temp_free_i32(tmp);
2682 2683
            return 1;
        }
2684 2685
        tcg_temp_free_i32(tmp2);
        tcg_temp_free_i32(tmp);
2686 2687 2688 2689 2690 2691 2692 2693 2694 2695
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        break;
    default:
        return 1;
    }

    return 0;
}

2696
/* Disassemble an XScale DSP instruction.  Returns nonzero if an error occurred
2697
   (ie. an undefined instruction).  */
2698
static int disas_dsp_insn(DisasContext *s, uint32_t insn)
2699 2700
{
    int acc, rd0, rd1, rdhi, rdlo;
2701
    TCGv_i32 tmp, tmp2;
2702 2703 2704 2705 2706 2707 2708 2709 2710 2711

    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;

2712 2713
        tmp = load_reg(s, rd0);
        tmp2 = load_reg(s, rd1);
2714 2715
        switch ((insn >> 16) & 0xf) {
        case 0x0:					/* MIA */
2716
            gen_helper_iwmmxt_muladdsl(cpu_M0, cpu_M0, tmp, tmp2);
2717 2718
            break;
        case 0x8:					/* MIAPH */
2719
            gen_helper_iwmmxt_muladdsw(cpu_M0, cpu_M0, tmp, tmp2);
2720 2721 2722 2723 2724 2725
            break;
        case 0xc:					/* MIABB */
        case 0xd:					/* MIABT */
        case 0xe:					/* MIATB */
        case 0xf:					/* MIATT */
            if (insn & (1 << 16))
2726
                tcg_gen_shri_i32(tmp, tmp, 16);
2727
            if (insn & (1 << 17))
2728 2729
                tcg_gen_shri_i32(tmp2, tmp2, 16);
            gen_helper_iwmmxt_muladdswl(cpu_M0, cpu_M0, tmp, tmp2);
2730 2731 2732 2733
            break;
        default:
            return 1;
        }
2734 2735
        tcg_temp_free_i32(tmp2);
        tcg_temp_free_i32(tmp);
2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750

        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 */
2751
            iwmmxt_load_reg(cpu_V0, acc);
2752
            tcg_gen_extrl_i64_i32(cpu_R[rdlo], cpu_V0);
2753
            tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
2754
            tcg_gen_extrl_i64_i32(cpu_R[rdhi], cpu_V0);
2755
            tcg_gen_andi_i32(cpu_R[rdhi], cpu_R[rdhi], (1 << (40 - 32)) - 1);
2756
        } else {					/* MAR */
2757 2758
            tcg_gen_concat_i32_i64(cpu_V0, cpu_R[rdlo], cpu_R[rdhi]);
            iwmmxt_store_reg(cpu_V0, acc);
2759 2760 2761 2762 2763 2764 2765
        }
        return 0;
    }

    return 1;
}

P
pbrook 已提交
2766 2767 2768 2769
#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 { \
2770
    if (arm_dc_feature(s, ARM_FEATURE_VFP3)) { \
P
pbrook 已提交
2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785
        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 已提交
2786
/* Move between integer and VFP cores.  */
2787
static TCGv_i32 gen_vfp_mrs(void)
P
pbrook 已提交
2788
{
2789
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
2790 2791 2792 2793
    tcg_gen_mov_i32(tmp, cpu_F0s);
    return tmp;
}

2794
static void gen_vfp_msr(TCGv_i32 tmp)
P
pbrook 已提交
2795 2796
{
    tcg_gen_mov_i32(cpu_F0s, tmp);
2797
    tcg_temp_free_i32(tmp);
P
pbrook 已提交
2798 2799
}

2800
static void gen_neon_dup_u8(TCGv_i32 var, int shift)
P
pbrook 已提交
2801
{
2802
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
2803 2804
    if (shift)
        tcg_gen_shri_i32(var, var, shift);
P
pbrook 已提交
2805
    tcg_gen_ext8u_i32(var, var);
P
pbrook 已提交
2806 2807 2808 2809
    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);
2810
    tcg_temp_free_i32(tmp);
P
pbrook 已提交
2811 2812
}

2813
static void gen_neon_dup_low16(TCGv_i32 var)
P
pbrook 已提交
2814
{
2815
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
2816
    tcg_gen_ext16u_i32(var, var);
P
pbrook 已提交
2817 2818
    tcg_gen_shli_i32(tmp, var, 16);
    tcg_gen_or_i32(var, var, tmp);
2819
    tcg_temp_free_i32(tmp);
P
pbrook 已提交
2820 2821
}

2822
static void gen_neon_dup_high16(TCGv_i32 var)
P
pbrook 已提交
2823
{
2824
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
2825 2826 2827
    tcg_gen_andi_i32(var, var, 0xffff0000);
    tcg_gen_shri_i32(tmp, var, 16);
    tcg_gen_or_i32(var, var, tmp);
2828
    tcg_temp_free_i32(tmp);
P
pbrook 已提交
2829 2830
}

2831
static TCGv_i32 gen_load_and_replicate(DisasContext *s, TCGv_i32 addr, int size)
2832 2833
{
    /* Load a single Neon element and replicate into a 32 bit TCG reg */
2834
    TCGv_i32 tmp = tcg_temp_new_i32();
2835 2836
    switch (size) {
    case 0:
2837
        gen_aa32_ld8u(s, tmp, addr, get_mem_index(s));
2838 2839 2840
        gen_neon_dup_u8(tmp, 0);
        break;
    case 1:
2841
        gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
2842 2843 2844
        gen_neon_dup_low16(tmp);
        break;
    case 2:
2845
        gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
2846 2847 2848 2849 2850 2851 2852
        break;
    default: /* Avoid compiler warnings.  */
        abort();
    }
    return tmp;
}

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 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961
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;
}

2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977
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) {
2978
            gen_helper_vfp_minnumd(dest, frn, frm, fpst);
2979
        } else {
2980
            gen_helper_vfp_maxnumd(dest, frn, frm, fpst);
2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995
        }
        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) {
2996
            gen_helper_vfp_minnums(dest, frn, frm, fpst);
2997
        } else {
2998
            gen_helper_vfp_maxnums(dest, frn, frm, fpst);
2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009
        }
        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;
}

3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047
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;
}

3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075
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);
        }
3076
        tcg_gen_extrl_i64_i32(tcg_tmp, tcg_res);
3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104
        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;
}
3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116

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

3117
static int disas_vfp_v8_insn(DisasContext *s, uint32_t insn)
3118 3119 3120
{
    uint32_t rd, rn, rm, dp = extract32(insn, 8, 1);

3121
    if (!arm_dc_feature(s, ARM_FEATURE_V8)) {
3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136
        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);
3137 3138
    } else if ((insn & 0x0fb00e10) == 0x0e800a00) {
        return handle_vminmaxnm(insn, rd, rn, rm, dp);
3139 3140 3141 3142
    } 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);
3143 3144 3145 3146
    } 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);
3147 3148 3149 3150
    }
    return 1;
}

3151
/* Disassemble a VFP instruction.  Returns nonzero if an error occurred
B
bellard 已提交
3152
   (ie. an undefined instruction).  */
3153
static int disas_vfp_insn(DisasContext *s, uint32_t insn)
B
bellard 已提交
3154 3155 3156
{
    uint32_t rd, rn, rm, op, i, n, offset, delta_d, delta_m, bank_mask;
    int dp, veclen;
3157 3158 3159
    TCGv_i32 addr;
    TCGv_i32 tmp;
    TCGv_i32 tmp2;
B
bellard 已提交
3160

3161
    if (!arm_dc_feature(s, ARM_FEATURE_VFP)) {
P
pbrook 已提交
3162
        return 1;
3163
    }
P
pbrook 已提交
3164

3165 3166 3167 3168
    /* 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.
     */
3169
    if (s->fp_excp_el) {
3170
        gen_exception_insn(s, 4, EXCP_UDEF,
3171
                           syn_fp_access_trap(1, 0xe, false), s->fp_excp_el);
3172 3173 3174
        return 0;
    }

3175
    if (!s->vfp_enabled) {
P
pbrook 已提交
3176
        /* VFP disabled.  Only allow fmxr/fmrx to/from some control regs.  */
P
pbrook 已提交
3177 3178 3179
        if ((insn & 0x0fe00fff) != 0x0ee00a10)
            return 1;
        rn = (insn >> 16) & 0xf;
3180 3181
        if (rn != ARM_VFP_FPSID && rn != ARM_VFP_FPEXC && rn != ARM_VFP_MVFR2
            && rn != ARM_VFP_MVFR1 && rn != ARM_VFP_MVFR0) {
P
pbrook 已提交
3182
            return 1;
3183
        }
P
pbrook 已提交
3184
    }
3185 3186 3187 3188 3189

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

B
bellard 已提交
3193 3194 3195 3196 3197 3198 3199
    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 已提交
3200 3201 3202 3203 3204
                int size;
                int pass;

                VFP_DREG_N(rn, insn);
                if (insn & 0xf)
B
bellard 已提交
3205
                    return 1;
P
pbrook 已提交
3206
                if (insn & 0x00c00060
3207
                    && !arm_dc_feature(s, ARM_FEATURE_NEON)) {
P
pbrook 已提交
3208
                    return 1;
3209
                }
P
pbrook 已提交
3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221

                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;
                }
3222
                if (insn & ARM_CP_RW_BIT) {
B
bellard 已提交
3223
                    /* vfp->arm */
P
pbrook 已提交
3224
                    tmp = neon_load_reg(rn, pass);
P
pbrook 已提交
3225 3226 3227
                    switch (size) {
                    case 0:
                        if (offset)
P
pbrook 已提交
3228
                            tcg_gen_shri_i32(tmp, tmp, offset);
P
pbrook 已提交
3229
                        if (insn & (1 << 23))
P
pbrook 已提交
3230
                            gen_uxtb(tmp);
P
pbrook 已提交
3231
                        else
P
pbrook 已提交
3232
                            gen_sxtb(tmp);
P
pbrook 已提交
3233 3234 3235 3236
                        break;
                    case 1:
                        if (insn & (1 << 23)) {
                            if (offset) {
P
pbrook 已提交
3237
                                tcg_gen_shri_i32(tmp, tmp, 16);
P
pbrook 已提交
3238
                            } else {
P
pbrook 已提交
3239
                                gen_uxth(tmp);
P
pbrook 已提交
3240 3241 3242
                            }
                        } else {
                            if (offset) {
P
pbrook 已提交
3243
                                tcg_gen_sari_i32(tmp, tmp, 16);
P
pbrook 已提交
3244
                            } else {
P
pbrook 已提交
3245
                                gen_sxth(tmp);
P
pbrook 已提交
3246 3247 3248 3249 3250 3251
                            }
                        }
                        break;
                    case 2:
                        break;
                    }
P
pbrook 已提交
3252
                    store_reg(s, rd, tmp);
B
bellard 已提交
3253 3254
                } else {
                    /* arm->vfp */
P
pbrook 已提交
3255
                    tmp = load_reg(s, rd);
P
pbrook 已提交
3256 3257 3258
                    if (insn & (1 << 23)) {
                        /* VDUP */
                        if (size == 0) {
P
pbrook 已提交
3259
                            gen_neon_dup_u8(tmp, 0);
P
pbrook 已提交
3260
                        } else if (size == 1) {
P
pbrook 已提交
3261
                            gen_neon_dup_low16(tmp);
P
pbrook 已提交
3262
                        }
P
pbrook 已提交
3263
                        for (n = 0; n <= pass * 2; n++) {
3264
                            tmp2 = tcg_temp_new_i32();
P
pbrook 已提交
3265 3266 3267 3268
                            tcg_gen_mov_i32(tmp2, tmp);
                            neon_store_reg(rn, n, tmp2);
                        }
                        neon_store_reg(rn, n, tmp);
P
pbrook 已提交
3269 3270 3271 3272
                    } else {
                        /* VMOV */
                        switch (size) {
                        case 0:
P
pbrook 已提交
3273
                            tmp2 = neon_load_reg(rn, pass);
3274
                            tcg_gen_deposit_i32(tmp, tmp2, tmp, offset, 8);
3275
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
3276 3277
                            break;
                        case 1:
P
pbrook 已提交
3278
                            tmp2 = neon_load_reg(rn, pass);
3279
                            tcg_gen_deposit_i32(tmp, tmp2, tmp, offset, 16);
3280
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
3281 3282 3283 3284
                            break;
                        case 2:
                            break;
                        }
P
pbrook 已提交
3285
                        neon_store_reg(rn, pass, tmp);
P
pbrook 已提交
3286
                    }
B
bellard 已提交
3287
                }
P
pbrook 已提交
3288 3289 3290 3291
            } else { /* !dp */
                if ((insn & 0x6f) != 0x00)
                    return 1;
                rn = VFP_SREG_N(insn);
3292
                if (insn & ARM_CP_RW_BIT) {
B
bellard 已提交
3293 3294 3295
                    /* vfp->arm */
                    if (insn & (1 << 21)) {
                        /* system register */
P
pbrook 已提交
3296
                        rn >>= 1;
P
pbrook 已提交
3297

B
bellard 已提交
3298
                        switch (rn) {
P
pbrook 已提交
3299
                        case ARM_VFP_FPSID:
P
pbrook 已提交
3300
                            /* VFP2 allows access to FSID from userspace.
P
pbrook 已提交
3301 3302 3303
                               VFP3 restricts all id registers to privileged
                               accesses.  */
                            if (IS_USER(s)
3304
                                && arm_dc_feature(s, ARM_FEATURE_VFP3)) {
P
pbrook 已提交
3305
                                return 1;
3306
                            }
P
pbrook 已提交
3307
                            tmp = load_cpu_field(vfp.xregs[rn]);
P
pbrook 已提交
3308
                            break;
P
pbrook 已提交
3309
                        case ARM_VFP_FPEXC:
P
pbrook 已提交
3310 3311
                            if (IS_USER(s))
                                return 1;
P
pbrook 已提交
3312
                            tmp = load_cpu_field(vfp.xregs[rn]);
P
pbrook 已提交
3313
                            break;
P
pbrook 已提交
3314 3315
                        case ARM_VFP_FPINST:
                        case ARM_VFP_FPINST2:
P
pbrook 已提交
3316 3317
                            /* Not present in VFP3.  */
                            if (IS_USER(s)
3318
                                || arm_dc_feature(s, ARM_FEATURE_VFP3)) {
P
pbrook 已提交
3319
                                return 1;
3320
                            }
P
pbrook 已提交
3321
                            tmp = load_cpu_field(vfp.xregs[rn]);
B
bellard 已提交
3322
                            break;
P
pbrook 已提交
3323
                        case ARM_VFP_FPSCR:
3324
                            if (rd == 15) {
P
pbrook 已提交
3325 3326 3327
                                tmp = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]);
                                tcg_gen_andi_i32(tmp, tmp, 0xf0000000);
                            } else {
3328
                                tmp = tcg_temp_new_i32();
P
pbrook 已提交
3329 3330
                                gen_helper_vfp_get_fpscr(tmp, cpu_env);
                            }
B
bellard 已提交
3331
                            break;
3332
                        case ARM_VFP_MVFR2:
3333
                            if (!arm_dc_feature(s, ARM_FEATURE_V8)) {
3334 3335 3336
                                return 1;
                            }
                            /* fall through */
P
pbrook 已提交
3337 3338 3339
                        case ARM_VFP_MVFR0:
                        case ARM_VFP_MVFR1:
                            if (IS_USER(s)
3340
                                || !arm_dc_feature(s, ARM_FEATURE_MVFR)) {
P
pbrook 已提交
3341
                                return 1;
3342
                            }
P
pbrook 已提交
3343
                            tmp = load_cpu_field(vfp.xregs[rn]);
P
pbrook 已提交
3344
                            break;
B
bellard 已提交
3345 3346 3347 3348 3349
                        default:
                            return 1;
                        }
                    } else {
                        gen_mov_F0_vreg(0, rn);
P
pbrook 已提交
3350
                        tmp = gen_vfp_mrs();
B
bellard 已提交
3351 3352
                    }
                    if (rd == 15) {
B
bellard 已提交
3353
                        /* Set the 4 flag bits in the CPSR.  */
P
pbrook 已提交
3354
                        gen_set_nzcv(tmp);
3355
                        tcg_temp_free_i32(tmp);
P
pbrook 已提交
3356 3357 3358
                    } else {
                        store_reg(s, rd, tmp);
                    }
B
bellard 已提交
3359 3360 3361
                } else {
                    /* arm->vfp */
                    if (insn & (1 << 21)) {
P
pbrook 已提交
3362
                        rn >>= 1;
B
bellard 已提交
3363 3364
                        /* system register */
                        switch (rn) {
P
pbrook 已提交
3365
                        case ARM_VFP_FPSID:
P
pbrook 已提交
3366 3367
                        case ARM_VFP_MVFR0:
                        case ARM_VFP_MVFR1:
B
bellard 已提交
3368 3369
                            /* Writes are ignored.  */
                            break;
P
pbrook 已提交
3370
                        case ARM_VFP_FPSCR:
3371
                            tmp = load_reg(s, rd);
P
pbrook 已提交
3372
                            gen_helper_vfp_set_fpscr(cpu_env, tmp);
3373
                            tcg_temp_free_i32(tmp);
B
bellard 已提交
3374
                            gen_lookup_tb(s);
B
bellard 已提交
3375
                            break;
P
pbrook 已提交
3376
                        case ARM_VFP_FPEXC:
P
pbrook 已提交
3377 3378
                            if (IS_USER(s))
                                return 1;
3379 3380
                            /* TODO: VFP subarchitecture support.
                             * For now, keep the EN bit only */
3381
                            tmp = load_reg(s, rd);
3382
                            tcg_gen_andi_i32(tmp, tmp, 1 << 30);
P
pbrook 已提交
3383
                            store_cpu_field(tmp, vfp.xregs[rn]);
P
pbrook 已提交
3384 3385 3386 3387
                            gen_lookup_tb(s);
                            break;
                        case ARM_VFP_FPINST:
                        case ARM_VFP_FPINST2:
3388 3389 3390
                            if (IS_USER(s)) {
                                return 1;
                            }
3391
                            tmp = load_reg(s, rd);
P
pbrook 已提交
3392
                            store_cpu_field(tmp, vfp.xregs[rn]);
P
pbrook 已提交
3393
                            break;
B
bellard 已提交
3394 3395 3396 3397
                        default:
                            return 1;
                        }
                    } else {
3398
                        tmp = load_reg(s, rd);
P
pbrook 已提交
3399
                        gen_vfp_msr(tmp);
B
bellard 已提交
3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413
                        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 已提交
3414
                    VFP_DREG_N(rn, insn);
B
bellard 已提交
3415 3416
                }

3417 3418 3419
                if (op == 15 && (rn == 15 || ((rn & 0x1c) == 0x18) ||
                                 ((rn & 0x1e) == 0x6))) {
                    /* Integer or single/half precision destination.  */
P
pbrook 已提交
3420
                    rd = VFP_SREG_D(insn);
B
bellard 已提交
3421
                } else {
P
pbrook 已提交
3422
                    VFP_DREG_D(rd, insn);
B
bellard 已提交
3423
                }
3424
                if (op == 15 &&
3425 3426 3427 3428 3429
                    (((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.
3430 3431
                     */
                    rm = VFP_SREG_M(insn);
B
bellard 已提交
3432
                } else {
P
pbrook 已提交
3433
                    VFP_DREG_M(rm, insn);
B
bellard 已提交
3434 3435
                }
            } else {
P
pbrook 已提交
3436
                rn = VFP_SREG_N(insn);
B
bellard 已提交
3437 3438
                if (op == 15 && rn == 15) {
                    /* Double precision destination.  */
P
pbrook 已提交
3439 3440 3441 3442
                    VFP_DREG_D(rd, insn);
                } else {
                    rd = VFP_SREG_D(insn);
                }
3443 3444 3445
                /* 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 已提交
3446
                rm = VFP_SREG_M(insn);
B
bellard 已提交
3447 3448
            }

3449
            veclen = s->vec_len;
B
bellard 已提交
3450 3451 3452 3453 3454 3455 3456
            if (op == 15 && rn > 3)
                veclen = 0;

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

B
bellard 已提交
3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469
            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)
3470
                        delta_d = (s->vec_stride >> 1) + 1;
B
bellard 已提交
3471
                    else
3472
                        delta_d = s->vec_stride + 1;
B
bellard 已提交
3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503

                    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 已提交
3504 3505 3506 3507
                case 20:
                case 21:
                case 22:
                case 23:
P
pbrook 已提交
3508 3509 3510 3511
                case 28:
                case 29:
                case 30:
                case 31:
P
pbrook 已提交
3512 3513 3514
                    /* Source and destination the same.  */
                    gen_mov_F0_vreg(dp, rd);
                    break;
3515 3516 3517 3518
                case 4:
                case 5:
                case 6:
                case 7:
3519 3520 3521
                    /* VCVTB, VCVTT: only present with the halfprec extension
                     * UNPREDICTABLE if bit 8 is set prior to ARMv8
                     * (we choose to UNDEF)
3522
                     */
3523 3524
                    if ((dp && !arm_dc_feature(s, ARM_FEATURE_V8)) ||
                        !arm_dc_feature(s, ARM_FEATURE_VFP_FP16)) {
3525 3526
                        return 1;
                    }
3527 3528 3529 3530 3531
                    if (!extract32(rn, 1, 1)) {
                        /* Half precision source.  */
                        gen_mov_F0_vreg(0, rm);
                        break;
                    }
3532
                    /* Otherwise fall through */
B
bellard 已提交
3533 3534 3535
                default:
                    /* One source operand.  */
                    gen_mov_F0_vreg(dp, rm);
P
pbrook 已提交
3536
                    break;
B
bellard 已提交
3537 3538 3539 3540 3541 3542 3543 3544 3545 3546
                }
            } else {
                /* Two source operands.  */
                gen_mov_F0_vreg(dp, rn);
                gen_mov_F1_vreg(dp, rm);
            }

            for (;;) {
                /* Perform the calculation.  */
                switch (op) {
3547 3548 3549 3550
                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 已提交
3551 3552
                    gen_vfp_add(dp);
                    break;
3553
                case 1: /* VMLS: fd + -(fn * fm) */
B
bellard 已提交
3554
                    gen_vfp_mul(dp);
3555 3556
                    gen_vfp_F1_neg(dp);
                    gen_mov_F0_vreg(dp, rd);
B
bellard 已提交
3557 3558
                    gen_vfp_add(dp);
                    break;
3559 3560 3561 3562 3563 3564 3565 3566 3567
                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 已提交
3568
                    break;
3569
                case 3: /* VNMLA: -fd + -(fn * fm) */
B
bellard 已提交
3570
                    gen_vfp_mul(dp);
3571 3572
                    gen_vfp_F1_neg(dp);
                    gen_mov_F0_vreg(dp, rd);
B
bellard 已提交
3573
                    gen_vfp_neg(dp);
3574
                    gen_vfp_add(dp);
B
bellard 已提交
3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591
                    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;
3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602
                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.
                     */
3603
                    if (!arm_dc_feature(s, ARM_FEATURE_VFP4)) {
3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642
                        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 已提交
3643
                case 14: /* fconst */
3644 3645 3646
                    if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
                        return 1;
                    }
P
pbrook 已提交
3647 3648 3649 3650 3651 3652 3653 3654 3655

                    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 已提交
3656
                        tcg_gen_movi_i64(cpu_F0d, ((uint64_t)n) << 32);
P
pbrook 已提交
3657 3658 3659 3660 3661 3662
                    } else {
                        if (i & 0x40)
                            i |= 0x780;
                        else
                            i |= 0x800;
                        n |= i << 19;
B
balrog 已提交
3663
                        tcg_gen_movi_i32(cpu_F0s, n);
P
pbrook 已提交
3664 3665
                    }
                    break;
B
bellard 已提交
3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679
                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;
3680
                    case 4: /* vcvtb.f32.f16, vcvtb.f64.f16 */
P
Paul Brook 已提交
3681 3682
                        tmp = gen_vfp_mrs();
                        tcg_gen_ext16u_i32(tmp, tmp);
3683 3684 3685 3686 3687 3688 3689
                        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);
                        }
3690
                        tcg_temp_free_i32(tmp);
P
Paul Brook 已提交
3691
                        break;
3692
                    case 5: /* vcvtt.f32.f16, vcvtt.f64.f16 */
P
Paul Brook 已提交
3693 3694
                        tmp = gen_vfp_mrs();
                        tcg_gen_shri_i32(tmp, tmp, 16);
3695 3696 3697 3698 3699 3700 3701
                        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);
                        }
3702
                        tcg_temp_free_i32(tmp);
P
Paul Brook 已提交
3703
                        break;
3704
                    case 6: /* vcvtb.f16.f32, vcvtb.f16.f64 */
3705
                        tmp = tcg_temp_new_i32();
3706 3707 3708 3709 3710 3711 3712
                        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 已提交
3713 3714 3715 3716
                        gen_mov_F0_vreg(0, rd);
                        tmp2 = gen_vfp_mrs();
                        tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000);
                        tcg_gen_or_i32(tmp, tmp, tmp2);
3717
                        tcg_temp_free_i32(tmp2);
P
Paul Brook 已提交
3718 3719
                        gen_vfp_msr(tmp);
                        break;
3720
                    case 7: /* vcvtt.f16.f32, vcvtt.f16.f64 */
3721
                        tmp = tcg_temp_new_i32();
3722 3723 3724 3725 3726 3727 3728
                        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 已提交
3729 3730 3731 3732 3733
                        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);
3734
                        tcg_temp_free_i32(tmp2);
P
Paul Brook 已提交
3735 3736
                        gen_vfp_msr(tmp);
                        break;
B
bellard 已提交
3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749
                    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;
3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760
                    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;
                    }
3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776
                    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;
                    }
3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787
                    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 已提交
3788 3789
                    case 15: /* single<->double conversion */
                        if (dp)
P
pbrook 已提交
3790
                            gen_helper_vfp_fcvtsd(cpu_F0s, cpu_F0d, cpu_env);
B
bellard 已提交
3791
                        else
P
pbrook 已提交
3792
                            gen_helper_vfp_fcvtds(cpu_F0d, cpu_F0s, cpu_env);
B
bellard 已提交
3793 3794
                        break;
                    case 16: /* fuito */
3795
                        gen_vfp_uito(dp, 0);
B
bellard 已提交
3796 3797
                        break;
                    case 17: /* fsito */
3798
                        gen_vfp_sito(dp, 0);
B
bellard 已提交
3799
                        break;
P
pbrook 已提交
3800
                    case 20: /* fshto */
3801 3802 3803
                        if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
                            return 1;
                        }
3804
                        gen_vfp_shto(dp, 16 - rm, 0);
P
pbrook 已提交
3805 3806
                        break;
                    case 21: /* fslto */
3807 3808 3809
                        if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
                            return 1;
                        }
3810
                        gen_vfp_slto(dp, 32 - rm, 0);
P
pbrook 已提交
3811 3812
                        break;
                    case 22: /* fuhto */
3813 3814 3815
                        if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
                            return 1;
                        }
3816
                        gen_vfp_uhto(dp, 16 - rm, 0);
P
pbrook 已提交
3817 3818
                        break;
                    case 23: /* fulto */
3819 3820 3821
                        if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
                            return 1;
                        }
3822
                        gen_vfp_ulto(dp, 32 - rm, 0);
P
pbrook 已提交
3823
                        break;
B
bellard 已提交
3824
                    case 24: /* ftoui */
3825
                        gen_vfp_toui(dp, 0);
B
bellard 已提交
3826 3827
                        break;
                    case 25: /* ftouiz */
3828
                        gen_vfp_touiz(dp, 0);
B
bellard 已提交
3829 3830
                        break;
                    case 26: /* ftosi */
3831
                        gen_vfp_tosi(dp, 0);
B
bellard 已提交
3832 3833
                        break;
                    case 27: /* ftosiz */
3834
                        gen_vfp_tosiz(dp, 0);
B
bellard 已提交
3835
                        break;
P
pbrook 已提交
3836
                    case 28: /* ftosh */
3837 3838 3839
                        if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
                            return 1;
                        }
3840
                        gen_vfp_tosh(dp, 16 - rm, 0);
P
pbrook 已提交
3841 3842
                        break;
                    case 29: /* ftosl */
3843 3844 3845
                        if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
                            return 1;
                        }
3846
                        gen_vfp_tosl(dp, 32 - rm, 0);
P
pbrook 已提交
3847 3848
                        break;
                    case 30: /* ftouh */
3849 3850 3851
                        if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
                            return 1;
                        }
3852
                        gen_vfp_touh(dp, 16 - rm, 0);
P
pbrook 已提交
3853 3854
                        break;
                    case 31: /* ftoul */
3855 3856 3857
                        if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) {
                            return 1;
                        }
3858
                        gen_vfp_toul(dp, 32 - rm, 0);
P
pbrook 已提交
3859
                        break;
B
bellard 已提交
3860 3861 3862 3863 3864 3865 3866 3867 3868
                    default: /* undefined */
                        return 1;
                    }
                    break;
                default: /* undefined */
                    return 1;
                }

                /* Write back the result.  */
3869 3870 3871 3872 3873 3874 3875 3876
                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 已提交
3877
                    gen_mov_vreg_F0(0, rd);
3878
                } else if (op == 15 && rn == 15) {
B
bellard 已提交
3879 3880
                    /* conversion */
                    gen_mov_vreg_F0(!dp, rd);
3881
                } else {
B
bellard 已提交
3882
                    gen_mov_vreg_F0(dp, rd);
3883
                }
B
bellard 已提交
3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923

                /* 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:
3924
        if ((insn & 0x03e00000) == 0x00400000) {
B
bellard 已提交
3925 3926 3927 3928
            /* two-register transfer */
            rn = (insn >> 16) & 0xf;
            rd = (insn >> 12) & 0xf;
            if (dp) {
P
pbrook 已提交
3929 3930 3931 3932
                VFP_DREG_M(rm, insn);
            } else {
                rm = VFP_SREG_M(insn);
            }
B
bellard 已提交
3933

3934
            if (insn & ARM_CP_RW_BIT) {
B
bellard 已提交
3935 3936
                /* vfp->arm */
                if (dp) {
P
pbrook 已提交
3937 3938 3939 3940 3941 3942
                    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 已提交
3943 3944
                } else {
                    gen_mov_F0_vreg(0, rm);
P
pbrook 已提交
3945
                    tmp = gen_vfp_mrs();
3946
                    store_reg(s, rd, tmp);
B
bellard 已提交
3947
                    gen_mov_F0_vreg(0, rm + 1);
P
pbrook 已提交
3948
                    tmp = gen_vfp_mrs();
3949
                    store_reg(s, rn, tmp);
B
bellard 已提交
3950 3951 3952 3953
                }
            } else {
                /* arm->vfp */
                if (dp) {
P
pbrook 已提交
3954 3955 3956 3957 3958 3959
                    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 已提交
3960
                } else {
3961
                    tmp = load_reg(s, rd);
P
pbrook 已提交
3962
                    gen_vfp_msr(tmp);
B
bellard 已提交
3963
                    gen_mov_vreg_F0(0, rm);
3964
                    tmp = load_reg(s, rn);
P
pbrook 已提交
3965
                    gen_vfp_msr(tmp);
B
bellard 已提交
3966 3967 3968 3969 3970 3971 3972
                    gen_mov_vreg_F0(0, rm + 1);
                }
            }
        } else {
            /* Load/store */
            rn = (insn >> 16) & 0xf;
            if (dp)
P
pbrook 已提交
3973
                VFP_DREG_D(rd, insn);
B
bellard 已提交
3974
            else
P
pbrook 已提交
3975
                rd = VFP_SREG_D(insn);
B
bellard 已提交
3976 3977 3978 3979 3980
            if ((insn & 0x01200000) == 0x01000000) {
                /* Single load/store */
                offset = (insn & 0xff) << 2;
                if ((insn & (1 << 23)) == 0)
                    offset = -offset;
3981 3982 3983 3984 3985 3986 3987
                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);
                }
3988
                tcg_gen_addi_i32(addr, addr, offset);
B
bellard 已提交
3989
                if (insn & (1 << 20)) {
3990
                    gen_vfp_ld(s, dp, addr);
B
bellard 已提交
3991 3992 3993
                    gen_mov_vreg_F0(dp, rd);
                } else {
                    gen_mov_F0_vreg(dp, rd);
3994
                    gen_vfp_st(s, dp, addr);
B
bellard 已提交
3995
                }
3996
                tcg_temp_free_i32(addr);
B
bellard 已提交
3997 3998
            } else {
                /* load/store multiple */
3999
                int w = insn & (1 << 21);
B
bellard 已提交
4000 4001 4002 4003 4004
                if (dp)
                    n = (insn >> 1) & 0x7f;
                else
                    n = insn & 0xff;

4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026
                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 已提交
4027
                if (insn & (1 << 24)) /* pre-decrement */
4028
                    tcg_gen_addi_i32(addr, addr, -((insn & 0xff) << 2));
B
bellard 已提交
4029 4030 4031 4032 4033 4034

                if (dp)
                    offset = 8;
                else
                    offset = 4;
                for (i = 0; i < n; i++) {
4035
                    if (insn & ARM_CP_RW_BIT) {
B
bellard 已提交
4036
                        /* load */
4037
                        gen_vfp_ld(s, dp, addr);
B
bellard 已提交
4038 4039 4040 4041
                        gen_mov_vreg_F0(dp, rd + i);
                    } else {
                        /* store */
                        gen_mov_F0_vreg(dp, rd + i);
4042
                        gen_vfp_st(s, dp, addr);
B
bellard 已提交
4043
                    }
4044
                    tcg_gen_addi_i32(addr, addr, offset);
B
bellard 已提交
4045
                }
4046
                if (w) {
B
bellard 已提交
4047 4048 4049 4050 4051 4052 4053 4054 4055
                    /* writeback */
                    if (insn & (1 << 24))
                        offset = -offset * n;
                    else if (dp && (insn & 1))
                        offset = 4;
                    else
                        offset = 0;

                    if (offset != 0)
4056 4057 4058
                        tcg_gen_addi_i32(addr, addr, offset);
                    store_reg(s, rn, addr);
                } else {
4059
                    tcg_temp_free_i32(addr);
B
bellard 已提交
4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070
                }
            }
        }
        break;
    default:
        /* Should never happen.  */
        return 1;
    }
    return 0;
}

4071
static inline bool use_goto_tb(DisasContext *s, target_ulong dest)
B
bellard 已提交
4072
{
4073 4074 4075 4076 4077 4078 4079
#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
}
4080

4081 4082 4083
static inline void gen_goto_tb(DisasContext *s, int n, target_ulong dest)
{
    if (use_goto_tb(s, dest)) {
B
bellard 已提交
4084
        tcg_gen_goto_tb(n);
4085
        gen_set_pc_im(s, dest);
4086
        tcg_gen_exit_tb((uintptr_t)s->tb + n);
4087
    } else {
4088
        gen_set_pc_im(s, dest);
B
bellard 已提交
4089
        tcg_gen_exit_tb(0);
4090
    }
B
bellard 已提交
4091 4092
}

B
bellard 已提交
4093 4094
static inline void gen_jmp (DisasContext *s, uint32_t dest)
{
4095
    if (unlikely(s->singlestep_enabled || s->ss_active)) {
B
bellard 已提交
4096
        /* An indirect jump so that we still trigger the debug exception.  */
B
bellard 已提交
4097
        if (s->thumb)
P
pbrook 已提交
4098 4099
            dest |= 1;
        gen_bx_im(s, dest);
B
bellard 已提交
4100
    } else {
4101
        gen_goto_tb(s, 0, dest);
B
bellard 已提交
4102 4103 4104 4105
        s->is_jmp = DISAS_TB_JUMP;
    }
}

4106
static inline void gen_mulxy(TCGv_i32 t0, TCGv_i32 t1, int x, int y)
B
bellard 已提交
4107
{
B
bellard 已提交
4108
    if (x)
P
pbrook 已提交
4109
        tcg_gen_sari_i32(t0, t0, 16);
B
bellard 已提交
4110
    else
P
pbrook 已提交
4111
        gen_sxth(t0);
B
bellard 已提交
4112
    if (y)
P
pbrook 已提交
4113
        tcg_gen_sari_i32(t1, t1, 16);
B
bellard 已提交
4114
    else
P
pbrook 已提交
4115 4116
        gen_sxth(t1);
    tcg_gen_mul_i32(t0, t0, t1);
B
bellard 已提交
4117 4118 4119
}

/* Return the mask of PSR bits set by a MSR instruction.  */
4120 4121
static uint32_t msr_mask(DisasContext *s, int flags, int spsr)
{
B
bellard 已提交
4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132
    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 已提交
4133

P
pbrook 已提交
4134
    /* Mask out undefined bits.  */
P
pbrook 已提交
4135
    mask &= ~CPSR_RESERVED;
4136
    if (!arm_dc_feature(s, ARM_FEATURE_V4T)) {
4137
        mask &= ~CPSR_T;
4138 4139
    }
    if (!arm_dc_feature(s, ARM_FEATURE_V5)) {
4140
        mask &= ~CPSR_Q; /* V5TE in reality*/
4141 4142
    }
    if (!arm_dc_feature(s, ARM_FEATURE_V6)) {
P
pbrook 已提交
4143
        mask &= ~(CPSR_E | CPSR_GE);
4144 4145
    }
    if (!arm_dc_feature(s, ARM_FEATURE_THUMB2)) {
P
pbrook 已提交
4146
        mask &= ~CPSR_IT;
4147
    }
4148 4149 4150 4151
    /* Mask out execution state and reserved bits.  */
    if (!spsr) {
        mask &= ~(CPSR_EXEC | CPSR_RESERVED);
    }
B
bellard 已提交
4152 4153
    /* Mask out privileged bits.  */
    if (IS_USER(s))
P
pbrook 已提交
4154
        mask &= CPSR_USER;
B
bellard 已提交
4155 4156 4157
    return mask;
}

4158
/* Returns nonzero if access to the PSR is not permitted. Marks t0 as dead. */
4159
static int gen_set_psr(DisasContext *s, uint32_t mask, int spsr, TCGv_i32 t0)
B
bellard 已提交
4160
{
4161
    TCGv_i32 tmp;
B
bellard 已提交
4162 4163 4164 4165
    if (spsr) {
        /* ??? This is also undefined in system mode.  */
        if (IS_USER(s))
            return 1;
P
pbrook 已提交
4166 4167 4168

        tmp = load_cpu_field(spsr);
        tcg_gen_andi_i32(tmp, tmp, ~mask);
4169 4170
        tcg_gen_andi_i32(t0, t0, mask);
        tcg_gen_or_i32(tmp, tmp, t0);
P
pbrook 已提交
4171
        store_cpu_field(tmp, spsr);
B
bellard 已提交
4172
    } else {
4173
        gen_set_cpsr(t0, mask);
B
bellard 已提交
4174
    }
4175
    tcg_temp_free_i32(t0);
B
bellard 已提交
4176 4177 4178 4179
    gen_lookup_tb(s);
    return 0;
}

4180 4181 4182
/* 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)
{
4183
    TCGv_i32 tmp;
4184
    tmp = tcg_temp_new_i32();
4185 4186 4187 4188
    tcg_gen_movi_i32(tmp, val);
    return gen_set_psr(s, mask, spsr, tmp);
}

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 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377
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;
}

4378 4379 4380 4381 4382
/* 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 已提交
4383
{
4384 4385
    tcg_gen_mov_i32(cpu_R[15], pc);
    tcg_temp_free_i32(pc);
B
bellard 已提交
4386 4387
}

P
pbrook 已提交
4388
/* Generate a v6 exception return.  Marks both values as dead.  */
4389
static void gen_rfe(DisasContext *s, TCGv_i32 pc, TCGv_i32 cpsr)
B
bellard 已提交
4390
{
4391 4392 4393 4394 4395
    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.
     */
4396
    gen_helper_cpsr_write_eret(cpu_env, cpsr);
4397
    tcg_temp_free_i32(cpsr);
4398
    s->is_jmp = DISAS_JUMP;
P
pbrook 已提交
4399
}
4400

4401 4402 4403 4404 4405 4406
/* 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));
}

4407 4408 4409 4410 4411 4412 4413 4414
/*
 * For WFI we will halt the vCPU until an IRQ. For WFE and YIELD we
 * only call the helper when running single threaded TCG code to ensure
 * the next round-robin scheduled vCPU gets a crack. In MTTCG mode we
 * just skip this instruction. Currently the SEV/SEVL instructions
 * which are *one* of many ways to wake the CPU from WFE are not
 * implemented so we can't sleep like WFI does.
 */
P
pbrook 已提交
4415 4416 4417
static void gen_nop_hint(DisasContext *s, int val)
{
    switch (val) {
4418
    case 1: /* yield */
4419 4420 4421 4422
        if (!parallel_cpus) {
            gen_set_pc_im(s, s->pc);
            s->is_jmp = DISAS_YIELD;
        }
4423
        break;
P
pbrook 已提交
4424
    case 3: /* wfi */
4425
        gen_set_pc_im(s, s->pc);
P
pbrook 已提交
4426 4427 4428
        s->is_jmp = DISAS_WFI;
        break;
    case 2: /* wfe */
4429 4430 4431 4432
        if (!parallel_cpus) {
            gen_set_pc_im(s, s->pc);
            s->is_jmp = DISAS_WFE;
        }
4433
        break;
P
pbrook 已提交
4434
    case 4: /* sev */
4435 4436
    case 5: /* sevl */
        /* TODO: Implement SEV, SEVL and WFE.  May help SMP performance.  */
P
pbrook 已提交
4437 4438 4439 4440
    default: /* nop */
        break;
    }
}
B
bellard 已提交
4441

P
pbrook 已提交
4442
#define CPU_V001 cpu_V0, cpu_V0, cpu_V1
P
pbrook 已提交
4443

4444
static inline void gen_neon_add(int size, TCGv_i32 t0, TCGv_i32 t1)
P
pbrook 已提交
4445 4446
{
    switch (size) {
4447 4448 4449
    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;
4450
    default: abort();
P
pbrook 已提交
4451 4452 4453
    }
}

4454
static inline void gen_neon_rsb(int size, TCGv_i32 t0, TCGv_i32 t1)
P
pbrook 已提交
4455 4456
{
    switch (size) {
4457 4458 4459
    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 已提交
4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472
    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: \
4473
        gen_helper_neon_##name##_s8(tmp, cpu_env, tmp, tmp2); \
P
pbrook 已提交
4474 4475
        break; \
    case 1: \
4476
        gen_helper_neon_##name##_u8(tmp, cpu_env, tmp, tmp2); \
P
pbrook 已提交
4477 4478
        break; \
    case 2: \
4479
        gen_helper_neon_##name##_s16(tmp, cpu_env, tmp, tmp2); \
P
pbrook 已提交
4480 4481
        break; \
    case 3: \
4482
        gen_helper_neon_##name##_u16(tmp, cpu_env, tmp, tmp2); \
P
pbrook 已提交
4483 4484
        break; \
    case 4: \
4485
        gen_helper_neon_##name##_s32(tmp, cpu_env, tmp, tmp2); \
P
pbrook 已提交
4486 4487
        break; \
    case 5: \
4488
        gen_helper_neon_##name##_u32(tmp, cpu_env, tmp, tmp2); \
P
pbrook 已提交
4489 4490 4491
        break; \
    default: return 1; \
    }} while (0)
P
pbrook 已提交
4492 4493 4494

#define GEN_NEON_INTEGER_OP(name) do { \
    switch ((size << 1) | u) { \
P
pbrook 已提交
4495
    case 0: \
4496
        gen_helper_neon_##name##_s8(tmp, tmp, tmp2); \
P
pbrook 已提交
4497 4498
        break; \
    case 1: \
4499
        gen_helper_neon_##name##_u8(tmp, tmp, tmp2); \
P
pbrook 已提交
4500 4501
        break; \
    case 2: \
4502
        gen_helper_neon_##name##_s16(tmp, tmp, tmp2); \
P
pbrook 已提交
4503 4504
        break; \
    case 3: \
4505
        gen_helper_neon_##name##_u16(tmp, tmp, tmp2); \
P
pbrook 已提交
4506 4507
        break; \
    case 4: \
4508
        gen_helper_neon_##name##_s32(tmp, tmp, tmp2); \
P
pbrook 已提交
4509 4510
        break; \
    case 5: \
4511
        gen_helper_neon_##name##_u32(tmp, tmp, tmp2); \
P
pbrook 已提交
4512
        break; \
P
pbrook 已提交
4513 4514 4515
    default: return 1; \
    }} while (0)

4516
static TCGv_i32 neon_load_scratch(int scratch)
P
pbrook 已提交
4517
{
4518
    TCGv_i32 tmp = tcg_temp_new_i32();
4519 4520
    tcg_gen_ld_i32(tmp, cpu_env, offsetof(CPUARMState, vfp.scratch[scratch]));
    return tmp;
P
pbrook 已提交
4521 4522
}

4523
static void neon_store_scratch(int scratch, TCGv_i32 var)
P
pbrook 已提交
4524
{
4525
    tcg_gen_st_i32(var, cpu_env, offsetof(CPUARMState, vfp.scratch[scratch]));
4526
    tcg_temp_free_i32(var);
P
pbrook 已提交
4527 4528
}

4529
static inline TCGv_i32 neon_get_scalar(int size, int reg)
P
pbrook 已提交
4530
{
4531
    TCGv_i32 tmp;
P
pbrook 已提交
4532
    if (size == 1) {
4533 4534
        tmp = neon_load_reg(reg & 7, reg >> 4);
        if (reg & 8) {
4535
            gen_neon_dup_high16(tmp);
4536 4537
        } else {
            gen_neon_dup_low16(tmp);
4538
        }
4539 4540
    } else {
        tmp = neon_load_reg(reg & 15, reg >> 4);
P
pbrook 已提交
4541
    }
4542
    return tmp;
P
pbrook 已提交
4543 4544
}

4545
static int gen_neon_unzip(int rd, int rm, int size, int q)
4546
{
4547
    TCGv_i32 tmp, tmp2;
4548
    if (!q && size == 2) {
4549 4550 4551 4552 4553 4554 4555
        return 1;
    }
    tmp = tcg_const_i32(rd);
    tmp2 = tcg_const_i32(rm);
    if (q) {
        switch (size) {
        case 0:
4556
            gen_helper_neon_qunzip8(cpu_env, tmp, tmp2);
4557 4558
            break;
        case 1:
4559
            gen_helper_neon_qunzip16(cpu_env, tmp, tmp2);
4560 4561
            break;
        case 2:
4562
            gen_helper_neon_qunzip32(cpu_env, tmp, tmp2);
4563 4564 4565 4566 4567 4568 4569
            break;
        default:
            abort();
        }
    } else {
        switch (size) {
        case 0:
4570
            gen_helper_neon_unzip8(cpu_env, tmp, tmp2);
4571 4572
            break;
        case 1:
4573
            gen_helper_neon_unzip16(cpu_env, tmp, tmp2);
4574 4575 4576 4577 4578 4579 4580 4581
            break;
        default:
            abort();
        }
    }
    tcg_temp_free_i32(tmp);
    tcg_temp_free_i32(tmp2);
    return 0;
4582 4583
}

4584
static int gen_neon_zip(int rd, int rm, int size, int q)
4585
{
4586
    TCGv_i32 tmp, tmp2;
4587
    if (!q && size == 2) {
4588 4589 4590 4591 4592 4593 4594
        return 1;
    }
    tmp = tcg_const_i32(rd);
    tmp2 = tcg_const_i32(rm);
    if (q) {
        switch (size) {
        case 0:
4595
            gen_helper_neon_qzip8(cpu_env, tmp, tmp2);
4596 4597
            break;
        case 1:
4598
            gen_helper_neon_qzip16(cpu_env, tmp, tmp2);
4599 4600
            break;
        case 2:
4601
            gen_helper_neon_qzip32(cpu_env, tmp, tmp2);
4602 4603 4604 4605 4606 4607 4608
            break;
        default:
            abort();
        }
    } else {
        switch (size) {
        case 0:
4609
            gen_helper_neon_zip8(cpu_env, tmp, tmp2);
4610 4611
            break;
        case 1:
4612
            gen_helper_neon_zip16(cpu_env, tmp, tmp2);
4613 4614 4615 4616 4617 4618 4619 4620
            break;
        default:
            abort();
        }
    }
    tcg_temp_free_i32(tmp);
    tcg_temp_free_i32(tmp2);
    return 0;
4621 4622
}

4623
static void gen_neon_trn_u8(TCGv_i32 t0, TCGv_i32 t1)
4624
{
4625
    TCGv_i32 rd, tmp;
4626

4627 4628
    rd = tcg_temp_new_i32();
    tmp = tcg_temp_new_i32();
4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640

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

4641 4642
    tcg_temp_free_i32(tmp);
    tcg_temp_free_i32(rd);
4643 4644
}

4645
static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1)
4646
{
4647
    TCGv_i32 rd, tmp;
4648

4649 4650
    rd = tcg_temp_new_i32();
    tmp = tcg_temp_new_i32();
4651 4652 4653 4654 4655 4656 4657 4658 4659

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

4660 4661
    tcg_temp_free_i32(tmp);
    tcg_temp_free_i32(rd);
4662 4663 4664
}


P
pbrook 已提交
4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684
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.  */
4685
static int disas_neon_ls_insn(DisasContext *s, uint32_t insn)
P
pbrook 已提交
4686 4687 4688 4689 4690
{
    int rd, rn, rm;
    int op;
    int nregs;
    int interleave;
4691
    int spacing;
P
pbrook 已提交
4692 4693 4694 4695 4696 4697 4698
    int stride;
    int size;
    int reg;
    int pass;
    int load;
    int shift;
    int n;
4699 4700 4701
    TCGv_i32 addr;
    TCGv_i32 tmp;
    TCGv_i32 tmp2;
4702
    TCGv_i64 tmp64;
P
pbrook 已提交
4703

4704 4705 4706 4707
    /* 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.
     */
4708
    if (s->fp_excp_el) {
4709
        gen_exception_insn(s, 4, EXCP_UDEF,
4710
                           syn_fp_access_trap(1, 0xe, false), s->fp_excp_el);
4711 4712 4713
        return 0;
    }

4714
    if (!s->vfp_enabled)
P
pbrook 已提交
4715 4716 4717 4718 4719 4720 4721 4722 4723
      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;
4724
        if (op > 10)
P
pbrook 已提交
4725
            return 1;
4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740
        /* 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 已提交
4741 4742
        nregs = neon_ls_element_type[op].nregs;
        interleave = neon_ls_element_type[op].interleave;
4743 4744 4745
        spacing = neon_ls_element_type[op].spacing;
        if (size == 3 && (interleave | spacing) != 1)
            return 1;
4746
        addr = tcg_temp_new_i32();
4747
        load_reg_var(s, addr, rn);
P
pbrook 已提交
4748 4749 4750
        stride = (1 << size) * interleave;
        for (reg = 0; reg < nregs; reg++) {
            if (interleave > 2 || (interleave == 2 && nregs == 2)) {
4751 4752
                load_reg_var(s, addr, rn);
                tcg_gen_addi_i32(addr, addr, (1 << size) * reg);
P
pbrook 已提交
4753
            } else if (interleave == 2 && nregs == 4 && reg == 2) {
4754 4755
                load_reg_var(s, addr, rn);
                tcg_gen_addi_i32(addr, addr, 1 << size);
P
pbrook 已提交
4756
            }
4757
            if (size == 3) {
4758
                tmp64 = tcg_temp_new_i64();
4759
                if (load) {
4760
                    gen_aa32_ld64(s, tmp64, addr, get_mem_index(s));
4761 4762 4763
                    neon_store_reg64(tmp64, rd);
                } else {
                    neon_load_reg64(tmp64, rd);
4764
                    gen_aa32_st64(s, tmp64, addr, get_mem_index(s));
4765
                }
4766
                tcg_temp_free_i64(tmp64);
4767 4768 4769 4770 4771
                tcg_gen_addi_i32(addr, addr, stride);
            } else {
                for (pass = 0; pass < 2; pass++) {
                    if (size == 2) {
                        if (load) {
4772
                            tmp = tcg_temp_new_i32();
4773
                            gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
4774 4775 4776
                            neon_store_reg(rd, pass, tmp);
                        } else {
                            tmp = neon_load_reg(rd, pass);
4777
                            gen_aa32_st32(s, tmp, addr, get_mem_index(s));
4778
                            tcg_temp_free_i32(tmp);
4779
                        }
4780
                        tcg_gen_addi_i32(addr, addr, stride);
4781 4782
                    } else if (size == 1) {
                        if (load) {
4783
                            tmp = tcg_temp_new_i32();
4784
                            gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
4785
                            tcg_gen_addi_i32(addr, addr, stride);
4786
                            tmp2 = tcg_temp_new_i32();
4787
                            gen_aa32_ld16u(s, tmp2, addr, get_mem_index(s));
4788
                            tcg_gen_addi_i32(addr, addr, stride);
P
Paul Brook 已提交
4789 4790
                            tcg_gen_shli_i32(tmp2, tmp2, 16);
                            tcg_gen_or_i32(tmp, tmp, tmp2);
4791
                            tcg_temp_free_i32(tmp2);
4792 4793 4794
                            neon_store_reg(rd, pass, tmp);
                        } else {
                            tmp = neon_load_reg(rd, pass);
4795
                            tmp2 = tcg_temp_new_i32();
4796
                            tcg_gen_shri_i32(tmp2, tmp, 16);
4797
                            gen_aa32_st16(s, tmp, addr, get_mem_index(s));
4798
                            tcg_temp_free_i32(tmp);
4799
                            tcg_gen_addi_i32(addr, addr, stride);
4800
                            gen_aa32_st16(s, tmp2, addr, get_mem_index(s));
4801
                            tcg_temp_free_i32(tmp2);
4802
                            tcg_gen_addi_i32(addr, addr, stride);
P
pbrook 已提交
4803
                        }
4804 4805
                    } else /* size == 0 */ {
                        if (load) {
4806
                            TCGV_UNUSED_I32(tmp2);
4807
                            for (n = 0; n < 4; n++) {
4808
                                tmp = tcg_temp_new_i32();
4809
                                gen_aa32_ld8u(s, tmp, addr, get_mem_index(s));
4810 4811 4812 4813
                                tcg_gen_addi_i32(addr, addr, stride);
                                if (n == 0) {
                                    tmp2 = tmp;
                                } else {
P
Paul Brook 已提交
4814 4815
                                    tcg_gen_shli_i32(tmp, tmp, n * 8);
                                    tcg_gen_or_i32(tmp2, tmp2, tmp);
4816
                                    tcg_temp_free_i32(tmp);
4817
                                }
P
pbrook 已提交
4818
                            }
4819 4820 4821 4822
                            neon_store_reg(rd, pass, tmp2);
                        } else {
                            tmp2 = neon_load_reg(rd, pass);
                            for (n = 0; n < 4; n++) {
4823
                                tmp = tcg_temp_new_i32();
4824 4825 4826 4827 4828
                                if (n == 0) {
                                    tcg_gen_mov_i32(tmp, tmp2);
                                } else {
                                    tcg_gen_shri_i32(tmp, tmp2, n * 8);
                                }
4829
                                gen_aa32_st8(s, tmp, addr, get_mem_index(s));
4830
                                tcg_temp_free_i32(tmp);
4831 4832
                                tcg_gen_addi_i32(addr, addr, stride);
                            }
4833
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
4834 4835 4836 4837
                        }
                    }
                }
            }
4838
            rd += spacing;
P
pbrook 已提交
4839
        }
4840
        tcg_temp_free_i32(addr);
P
pbrook 已提交
4841 4842 4843 4844 4845
        stride = nregs * 8;
    } else {
        size = (insn >> 10) & 3;
        if (size == 3) {
            /* Load single element to all lanes.  */
4846 4847
            int a = (insn >> 4) & 1;
            if (!load) {
P
pbrook 已提交
4848
                return 1;
4849
            }
P
pbrook 已提交
4850 4851
            size = (insn >> 6) & 3;
            nregs = ((insn >> 8) & 3) + 1;
4852 4853 4854

            if (size == 3) {
                if (nregs != 4 || a == 0) {
P
pbrook 已提交
4855
                    return 1;
B
bellard 已提交
4856
                }
4857 4858 4859 4860 4861 4862 4863 4864 4865
                /* 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;
            }
4866
            addr = tcg_temp_new_i32();
4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888
            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 已提交
4889
            }
4890
            tcg_temp_free_i32(addr);
P
pbrook 已提交
4891 4892 4893
            stride = (1 << size) * nregs;
        } else {
            /* Single element.  */
4894
            int idx = (insn >> 4) & 0xf;
P
pbrook 已提交
4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912
            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;
4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945
            /* 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;
            }
4946
            addr = tcg_temp_new_i32();
4947
            load_reg_var(s, addr, rn);
P
pbrook 已提交
4948 4949
            for (reg = 0; reg < nregs; reg++) {
                if (load) {
4950
                    tmp = tcg_temp_new_i32();
P
pbrook 已提交
4951 4952
                    switch (size) {
                    case 0:
4953
                        gen_aa32_ld8u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
4954 4955
                        break;
                    case 1:
4956
                        gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
4957 4958
                        break;
                    case 2:
4959
                        gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
4960
                        break;
P
pbrook 已提交
4961 4962
                    default: /* Avoid compiler warnings.  */
                        abort();
P
pbrook 已提交
4963 4964
                    }
                    if (size != 2) {
P
pbrook 已提交
4965
                        tmp2 = neon_load_reg(rd, pass);
4966 4967
                        tcg_gen_deposit_i32(tmp, tmp2, tmp,
                                            shift, size ? 16 : 8);
4968
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
4969
                    }
P
pbrook 已提交
4970
                    neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
4971
                } else { /* Store */
P
pbrook 已提交
4972 4973 4974
                    tmp = neon_load_reg(rd, pass);
                    if (shift)
                        tcg_gen_shri_i32(tmp, tmp, shift);
P
pbrook 已提交
4975 4976
                    switch (size) {
                    case 0:
4977
                        gen_aa32_st8(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
4978 4979
                        break;
                    case 1:
4980
                        gen_aa32_st16(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
4981 4982
                        break;
                    case 2:
4983
                        gen_aa32_st32(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
4984
                        break;
B
bellard 已提交
4985
                    }
4986
                    tcg_temp_free_i32(tmp);
B
bellard 已提交
4987
                }
P
pbrook 已提交
4988
                rd += stride;
4989
                tcg_gen_addi_i32(addr, addr, 1 << size);
B
bellard 已提交
4990
            }
4991
            tcg_temp_free_i32(addr);
P
pbrook 已提交
4992
            stride = nregs * (1 << size);
B
bellard 已提交
4993
        }
P
pbrook 已提交
4994 4995
    }
    if (rm != 15) {
4996
        TCGv_i32 base;
P
pbrook 已提交
4997 4998

        base = load_reg(s, rn);
P
pbrook 已提交
4999
        if (rm == 13) {
P
pbrook 已提交
5000
            tcg_gen_addi_i32(base, base, stride);
P
pbrook 已提交
5001
        } else {
5002
            TCGv_i32 index;
P
pbrook 已提交
5003 5004
            index = load_reg(s, rm);
            tcg_gen_add_i32(base, base, index);
5005
            tcg_temp_free_i32(index);
P
pbrook 已提交
5006
        }
P
pbrook 已提交
5007
        store_reg(s, rn, base);
P
pbrook 已提交
5008 5009 5010
    }
    return 0;
}
5011

P
pbrook 已提交
5012
/* Bitwise select.  dest = c ? t : f.  Clobbers T and F.  */
5013
static void gen_neon_bsl(TCGv_i32 dest, TCGv_i32 t, TCGv_i32 f, TCGv_i32 c)
P
pbrook 已提交
5014 5015
{
    tcg_gen_and_i32(t, t, c);
5016
    tcg_gen_andc_i32(f, f, c);
P
pbrook 已提交
5017 5018 5019
    tcg_gen_or_i32(dest, t, f);
}

5020
static inline void gen_neon_narrow(int size, TCGv_i32 dest, TCGv_i64 src)
P
pbrook 已提交
5021 5022 5023 5024
{
    switch (size) {
    case 0: gen_helper_neon_narrow_u8(dest, src); break;
    case 1: gen_helper_neon_narrow_u16(dest, src); break;
5025
    case 2: tcg_gen_extrl_i64_i32(dest, src); break;
P
pbrook 已提交
5026 5027 5028 5029
    default: abort();
    }
}

5030
static inline void gen_neon_narrow_sats(int size, TCGv_i32 dest, TCGv_i64 src)
P
pbrook 已提交
5031 5032
{
    switch (size) {
5033 5034 5035
    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 已提交
5036 5037 5038 5039
    default: abort();
    }
}

5040
static inline void gen_neon_narrow_satu(int size, TCGv_i32 dest, TCGv_i64 src)
P
pbrook 已提交
5041 5042
{
    switch (size) {
5043 5044 5045
    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 已提交
5046 5047 5048 5049
    default: abort();
    }
}

5050
static inline void gen_neon_unarrow_sats(int size, TCGv_i32 dest, TCGv_i64 src)
5051 5052
{
    switch (size) {
5053 5054 5055
    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;
5056 5057 5058 5059
    default: abort();
    }
}

5060
static inline void gen_neon_shift_narrow(int size, TCGv_i32 var, TCGv_i32 shift,
P
pbrook 已提交
5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079
                                         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) {
5080 5081
            case 1: gen_helper_neon_shl_u16(var, var, shift); break;
            case 2: gen_helper_neon_shl_u32(var, var, shift); break;
P
pbrook 已提交
5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093
            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();
            }
        }
    }
}

5094
static inline void gen_neon_widen(TCGv_i64 dest, TCGv_i32 src, int size, int u)
P
pbrook 已提交
5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110
{
    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();
        }
    }
5111
    tcg_temp_free_i32(src);
P
pbrook 已提交
5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133
}

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 已提交
5134
static inline void gen_neon_negl(TCGv_i64 var, int size)
P
pbrook 已提交
5135 5136 5137 5138
{
    switch (size) {
    case 0: gen_helper_neon_negl_u16(var, var); break;
    case 1: gen_helper_neon_negl_u32(var, var); break;
5139 5140 5141
    case 2:
        tcg_gen_neg_i64(var, var);
        break;
P
pbrook 已提交
5142 5143 5144 5145
    default: abort();
    }
}

P
pbrook 已提交
5146
static inline void gen_neon_addl_saturate(TCGv_i64 op0, TCGv_i64 op1, int size)
P
pbrook 已提交
5147 5148
{
    switch (size) {
5149 5150
    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 已提交
5151 5152 5153 5154
    default: abort();
    }
}

5155 5156
static inline void gen_neon_mull(TCGv_i64 dest, TCGv_i32 a, TCGv_i32 b,
                                 int size, int u)
P
pbrook 已提交
5157
{
P
pbrook 已提交
5158
    TCGv_i64 tmp;
P
pbrook 已提交
5159 5160 5161 5162 5163 5164 5165 5166 5167

    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);
5168
        tcg_temp_free_i64(tmp);
P
pbrook 已提交
5169 5170 5171 5172
        break;
    case 5:
        tmp = gen_mulu_i64_i32(a, b);
        tcg_gen_mov_i64(dest, tmp);
5173
        tcg_temp_free_i64(tmp);
P
pbrook 已提交
5174 5175 5176
        break;
    default: abort();
    }
5177 5178 5179 5180

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

5186 5187
static void gen_neon_narrow_op(int op, int u, int size,
                               TCGv_i32 dest, TCGv_i64 src)
5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203
{
    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);
        }
    }
}

5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231
/* 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
5232
#define NEON_3R_SHA 24 /* SHA1C,SHA1P,SHA1M,SHA1SU0,SHA256H{2},SHA256SU1 */
5233
#define NEON_3R_VFM 25 /* VFMA, VFMS : float fused multiply-add */
5234 5235 5236 5237 5238
#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 */
5239
#define NEON_3R_FLOAT_MISC 31 /* float VRECPS, VRSQRTS, VMAXNM/MINNM */
5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265

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,
5266
    [NEON_3R_SHA] = 0xf, /* size field encodes op type */
5267
    [NEON_3R_VFM] = 0x5, /* size bit 1 encodes op */
5268 5269 5270 5271 5272
    [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 */
5273
    [NEON_3R_FLOAT_MISC] = 0x5, /* size bit 1 encodes op */
5274 5275
};

5276 5277 5278 5279 5280 5281 5282 5283 5284
/* 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
5285 5286
#define NEON_2RM_AESE 6 /* Includes AESD */
#define NEON_2RM_AESMC 7 /* Includes AESIMC */
5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299
#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
5300
#define NEON_2RM_SHA1H 21
5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316
#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
5317
#define NEON_2RM_SHA1SU1 39 /* Includes SHA256SU0 */
5318
#define NEON_2RM_VRINTN 40
5319
#define NEON_2RM_VRINTX 41
5320 5321
#define NEON_2RM_VRINTA 42
#define NEON_2RM_VRINTZ 43
5322
#define NEON_2RM_VCVT_F16_F32 44
5323
#define NEON_2RM_VRINTM 45
5324
#define NEON_2RM_VCVT_F32_F16 46
5325
#define NEON_2RM_VRINTP 47
5326 5327 5328 5329 5330 5331 5332 5333
#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
5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346
#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 ||
5347
            (op >= NEON_2RM_VRINTN && op <= NEON_2RM_VRINTZ) ||
5348 5349
            op == NEON_2RM_VRINTM ||
            (op >= NEON_2RM_VRINTP && op <= NEON_2RM_VCVTMS) ||
5350
            op >= NEON_2RM_VRECPE_F);
5351 5352
}

5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376
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;
    }
}

5377 5378 5379 5380 5381 5382 5383 5384 5385 5386
/* 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,
5387 5388
    [NEON_2RM_AESE] = 0x1,
    [NEON_2RM_AESMC] = 0x1,
5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401
    [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,
5402
    [NEON_2RM_SHA1H] = 0x4,
5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418
    [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,
5419
    [NEON_2RM_SHA1SU1] = 0x4,
5420
    [NEON_2RM_VRINTN] = 0x4,
5421
    [NEON_2RM_VRINTX] = 0x4,
5422 5423
    [NEON_2RM_VRINTA] = 0x4,
    [NEON_2RM_VRINTZ] = 0x4,
5424
    [NEON_2RM_VCVT_F16_F32] = 0x2,
5425
    [NEON_2RM_VRINTM] = 0x4,
5426
    [NEON_2RM_VCVT_F32_F16] = 0x2,
5427
    [NEON_2RM_VRINTP] = 0x4,
5428 5429 5430 5431 5432 5433 5434 5435
    [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,
5436 5437 5438 5439 5440 5441 5442 5443 5444 5445
    [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 已提交
5446 5447
/* Translate a NEON data processing instruction.  Return nonzero if the
   instruction is invalid.
P
pbrook 已提交
5448 5449
   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 已提交
5450

5451
static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
P
pbrook 已提交
5452 5453 5454 5455 5456 5457 5458 5459 5460 5461
{
    int op;
    int q;
    int rd, rn, rm;
    int size;
    int shift;
    int pass;
    int count;
    int pairwise;
    int u;
5462
    uint32_t imm, mask;
5463
    TCGv_i32 tmp, tmp2, tmp3, tmp4, tmp5;
P
pbrook 已提交
5464
    TCGv_i64 tmp64;
P
pbrook 已提交
5465

5466 5467 5468 5469
    /* 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.
     */
5470
    if (s->fp_excp_el) {
5471
        gen_exception_insn(s, 4, EXCP_UDEF,
5472
                           syn_fp_access_trap(1, 0xe, false), s->fp_excp_el);
5473 5474 5475
        return 0;
    }

5476
    if (!s->vfp_enabled)
P
pbrook 已提交
5477 5478 5479 5480 5481 5482 5483 5484 5485 5486
      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);
5487 5488 5489 5490
        /* Catch invalid op and bad size combinations: UNDEF */
        if ((neon_3r_sizes[op] & (1 << size)) == 0) {
            return 1;
        }
5491 5492 5493 5494 5495 5496
        /* 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;
        }
5497 5498 5499 5500 5501 5502 5503 5504 5505 5506
        /*
         * 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 */
5507
                if (!arm_dc_feature(s, ARM_FEATURE_V8_SHA1)) {
5508 5509 5510 5511 5512 5513 5514 5515 5516
                    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 */
5517
                if (!arm_dc_feature(s, ARM_FEATURE_V8_SHA256) || size == 3) {
5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539
                    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;
        }
5540 5541
        if (size == 3 && op != NEON_3R_LOGIC) {
            /* 64-bit element instructions. */
P
pbrook 已提交
5542
            for (pass = 0; pass < (q ? 2 : 1); pass++) {
P
pbrook 已提交
5543 5544
                neon_load_reg64(cpu_V0, rn + pass);
                neon_load_reg64(cpu_V1, rm + pass);
P
pbrook 已提交
5545
                switch (op) {
5546
                case NEON_3R_VQADD:
P
pbrook 已提交
5547
                    if (u) {
5548 5549
                        gen_helper_neon_qadd_u64(cpu_V0, cpu_env,
                                                 cpu_V0, cpu_V1);
B
bellard 已提交
5550
                    } else {
5551 5552
                        gen_helper_neon_qadd_s64(cpu_V0, cpu_env,
                                                 cpu_V0, cpu_V1);
B
bellard 已提交
5553
                    }
P
pbrook 已提交
5554
                    break;
5555
                case NEON_3R_VQSUB:
P
pbrook 已提交
5556
                    if (u) {
5557 5558
                        gen_helper_neon_qsub_u64(cpu_V0, cpu_env,
                                                 cpu_V0, cpu_V1);
P
pbrook 已提交
5559
                    } else {
5560 5561
                        gen_helper_neon_qsub_s64(cpu_V0, cpu_env,
                                                 cpu_V0, cpu_V1);
P
pbrook 已提交
5562 5563
                    }
                    break;
5564
                case NEON_3R_VSHL:
P
pbrook 已提交
5565 5566 5567 5568 5569 5570
                    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;
5571
                case NEON_3R_VQSHL:
P
pbrook 已提交
5572
                    if (u) {
5573 5574
                        gen_helper_neon_qshl_u64(cpu_V0, cpu_env,
                                                 cpu_V1, cpu_V0);
P
pbrook 已提交
5575
                    } else {
5576 5577
                        gen_helper_neon_qshl_s64(cpu_V0, cpu_env,
                                                 cpu_V1, cpu_V0);
P
pbrook 已提交
5578 5579
                    }
                    break;
5580
                case NEON_3R_VRSHL:
P
pbrook 已提交
5581 5582
                    if (u) {
                        gen_helper_neon_rshl_u64(cpu_V0, cpu_V1, cpu_V0);
B
bellard 已提交
5583
                    } else {
P
pbrook 已提交
5584 5585 5586
                        gen_helper_neon_rshl_s64(cpu_V0, cpu_V1, cpu_V0);
                    }
                    break;
5587
                case NEON_3R_VQRSHL:
P
pbrook 已提交
5588
                    if (u) {
5589 5590
                        gen_helper_neon_qrshl_u64(cpu_V0, cpu_env,
                                                  cpu_V1, cpu_V0);
P
pbrook 已提交
5591
                    } else {
5592 5593
                        gen_helper_neon_qrshl_s64(cpu_V0, cpu_env,
                                                  cpu_V1, cpu_V0);
B
bellard 已提交
5594
                    }
P
pbrook 已提交
5595
                    break;
5596
                case NEON_3R_VADD_VSUB:
P
pbrook 已提交
5597
                    if (u) {
P
pbrook 已提交
5598
                        tcg_gen_sub_i64(CPU_V001);
P
pbrook 已提交
5599
                    } else {
P
pbrook 已提交
5600
                        tcg_gen_add_i64(CPU_V001);
P
pbrook 已提交
5601 5602 5603 5604
                    }
                    break;
                default:
                    abort();
B
bellard 已提交
5605
                }
P
pbrook 已提交
5606
                neon_store_reg64(cpu_V0, rd + pass);
B
bellard 已提交
5607
            }
P
pbrook 已提交
5608
            return 0;
B
bellard 已提交
5609
        }
5610
        pairwise = 0;
P
pbrook 已提交
5611
        switch (op) {
5612 5613 5614 5615
        case NEON_3R_VSHL:
        case NEON_3R_VQSHL:
        case NEON_3R_VRSHL:
        case NEON_3R_VQRSHL:
P
pbrook 已提交
5616
            {
P
pbrook 已提交
5617 5618 5619
                int rtmp;
                /* Shift instruction operands are reversed.  */
                rtmp = rn;
P
pbrook 已提交
5620
                rn = rm;
P
pbrook 已提交
5621
                rm = rtmp;
P
pbrook 已提交
5622
            }
B
bellard 已提交
5623
            break;
5624 5625 5626 5627 5628
        case NEON_3R_VPADD:
            if (u) {
                return 1;
            }
            /* Fall through */
5629 5630
        case NEON_3R_VPMAX:
        case NEON_3R_VPMIN:
P
pbrook 已提交
5631
            pairwise = 1;
B
bellard 已提交
5632
            break;
5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649
        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;
5650 5651
        case NEON_3R_FLOAT_MISC:
            /* VMAXNM/VMINNM in ARMv8 */
5652
            if (u && !arm_dc_feature(s, ARM_FEATURE_V8)) {
5653 5654
                return 1;
            }
B
bellard 已提交
5655
            break;
5656 5657 5658 5659 5660
        case NEON_3R_VMUL:
            if (u && (size != 0)) {
                /* UNDEF on invalid size for polynomial subcase */
                return 1;
            }
B
bellard 已提交
5661
            break;
5662
        case NEON_3R_VFM:
5663
            if (!arm_dc_feature(s, ARM_FEATURE_VFP4) || u) {
5664 5665 5666
                return 1;
            }
            break;
P
pbrook 已提交
5667
        default:
B
bellard 已提交
5668
            break;
P
pbrook 已提交
5669
        }
5670

5671 5672 5673 5674 5675
        if (pairwise && q) {
            /* All the pairwise insns UNDEF if Q is set */
            return 1;
        }

P
pbrook 已提交
5676 5677 5678 5679
        for (pass = 0; pass < (q ? 4 : 2); pass++) {

        if (pairwise) {
            /* Pairwise.  */
5680 5681 5682
            if (pass < 1) {
                tmp = neon_load_reg(rn, 0);
                tmp2 = neon_load_reg(rn, 1);
P
pbrook 已提交
5683
            } else {
5684 5685
                tmp = neon_load_reg(rm, 0);
                tmp2 = neon_load_reg(rm, 1);
P
pbrook 已提交
5686 5687 5688
            }
        } else {
            /* Elementwise.  */
5689 5690
            tmp = neon_load_reg(rn, pass);
            tmp2 = neon_load_reg(rm, pass);
P
pbrook 已提交
5691 5692
        }
        switch (op) {
5693
        case NEON_3R_VHADD:
P
pbrook 已提交
5694 5695
            GEN_NEON_INTEGER_OP(hadd);
            break;
5696
        case NEON_3R_VQADD:
5697
            GEN_NEON_INTEGER_OP_ENV(qadd);
B
bellard 已提交
5698
            break;
5699
        case NEON_3R_VRHADD:
P
pbrook 已提交
5700
            GEN_NEON_INTEGER_OP(rhadd);
B
bellard 已提交
5701
            break;
5702
        case NEON_3R_LOGIC: /* Logic ops.  */
P
pbrook 已提交
5703 5704
            switch ((u << 2) | size) {
            case 0: /* VAND */
5705
                tcg_gen_and_i32(tmp, tmp, tmp2);
P
pbrook 已提交
5706 5707
                break;
            case 1: /* BIC */
5708
                tcg_gen_andc_i32(tmp, tmp, tmp2);
P
pbrook 已提交
5709 5710
                break;
            case 2: /* VORR */
5711
                tcg_gen_or_i32(tmp, tmp, tmp2);
P
pbrook 已提交
5712 5713
                break;
            case 3: /* VORN */
5714
                tcg_gen_orc_i32(tmp, tmp, tmp2);
P
pbrook 已提交
5715 5716
                break;
            case 4: /* VEOR */
5717
                tcg_gen_xor_i32(tmp, tmp, tmp2);
P
pbrook 已提交
5718 5719
                break;
            case 5: /* VBSL */
5720 5721
                tmp3 = neon_load_reg(rd, pass);
                gen_neon_bsl(tmp, tmp, tmp2, tmp3);
5722
                tcg_temp_free_i32(tmp3);
P
pbrook 已提交
5723 5724
                break;
            case 6: /* VBIT */
5725 5726
                tmp3 = neon_load_reg(rd, pass);
                gen_neon_bsl(tmp, tmp, tmp3, tmp2);
5727
                tcg_temp_free_i32(tmp3);
P
pbrook 已提交
5728 5729
                break;
            case 7: /* VBIF */
5730 5731
                tmp3 = neon_load_reg(rd, pass);
                gen_neon_bsl(tmp, tmp3, tmp, tmp2);
5732
                tcg_temp_free_i32(tmp3);
P
pbrook 已提交
5733
                break;
B
bellard 已提交
5734 5735
            }
            break;
5736
        case NEON_3R_VHSUB:
P
pbrook 已提交
5737 5738
            GEN_NEON_INTEGER_OP(hsub);
            break;
5739
        case NEON_3R_VQSUB:
5740
            GEN_NEON_INTEGER_OP_ENV(qsub);
B
bellard 已提交
5741
            break;
5742
        case NEON_3R_VCGT:
P
pbrook 已提交
5743 5744
            GEN_NEON_INTEGER_OP(cgt);
            break;
5745
        case NEON_3R_VCGE:
P
pbrook 已提交
5746 5747
            GEN_NEON_INTEGER_OP(cge);
            break;
5748
        case NEON_3R_VSHL:
P
pbrook 已提交
5749
            GEN_NEON_INTEGER_OP(shl);
B
bellard 已提交
5750
            break;
5751
        case NEON_3R_VQSHL:
5752
            GEN_NEON_INTEGER_OP_ENV(qshl);
B
bellard 已提交
5753
            break;
5754
        case NEON_3R_VRSHL:
P
pbrook 已提交
5755
            GEN_NEON_INTEGER_OP(rshl);
B
bellard 已提交
5756
            break;
5757
        case NEON_3R_VQRSHL:
5758
            GEN_NEON_INTEGER_OP_ENV(qrshl);
P
pbrook 已提交
5759
            break;
5760
        case NEON_3R_VMAX:
P
pbrook 已提交
5761 5762
            GEN_NEON_INTEGER_OP(max);
            break;
5763
        case NEON_3R_VMIN:
P
pbrook 已提交
5764 5765
            GEN_NEON_INTEGER_OP(min);
            break;
5766
        case NEON_3R_VABD:
P
pbrook 已提交
5767 5768
            GEN_NEON_INTEGER_OP(abd);
            break;
5769
        case NEON_3R_VABA:
P
pbrook 已提交
5770
            GEN_NEON_INTEGER_OP(abd);
5771
            tcg_temp_free_i32(tmp2);
5772 5773
            tmp2 = neon_load_reg(rd, pass);
            gen_neon_add(size, tmp, tmp2);
P
pbrook 已提交
5774
            break;
5775
        case NEON_3R_VADD_VSUB:
P
pbrook 已提交
5776
            if (!u) { /* VADD */
5777
                gen_neon_add(size, tmp, tmp2);
P
pbrook 已提交
5778 5779
            } else { /* VSUB */
                switch (size) {
5780 5781 5782
                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;
5783
                default: abort();
P
pbrook 已提交
5784 5785 5786
                }
            }
            break;
5787
        case NEON_3R_VTST_VCEQ:
P
pbrook 已提交
5788 5789
            if (!u) { /* VTST */
                switch (size) {
5790 5791 5792
                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;
5793
                default: abort();
P
pbrook 已提交
5794 5795 5796
                }
            } else { /* VCEQ */
                switch (size) {
5797 5798 5799
                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;
5800
                default: abort();
P
pbrook 已提交
5801 5802 5803
                }
            }
            break;
5804
        case NEON_3R_VML: /* VMLA, VMLAL, VMLS,VMLSL */
P
pbrook 已提交
5805
            switch (size) {
5806 5807 5808
            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;
5809
            default: abort();
P
pbrook 已提交
5810
            }
5811
            tcg_temp_free_i32(tmp2);
5812
            tmp2 = neon_load_reg(rd, pass);
P
pbrook 已提交
5813
            if (u) { /* VMLS */
5814
                gen_neon_rsb(size, tmp, tmp2);
P
pbrook 已提交
5815
            } else { /* VMLA */
5816
                gen_neon_add(size, tmp, tmp2);
P
pbrook 已提交
5817 5818
            }
            break;
5819
        case NEON_3R_VMUL:
P
pbrook 已提交
5820
            if (u) { /* polynomial */
5821
                gen_helper_neon_mul_p8(tmp, tmp, tmp2);
P
pbrook 已提交
5822 5823
            } else { /* Integer */
                switch (size) {
5824 5825 5826
                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;
5827
                default: abort();
P
pbrook 已提交
5828 5829 5830
                }
            }
            break;
5831
        case NEON_3R_VPMAX:
P
pbrook 已提交
5832 5833
            GEN_NEON_INTEGER_OP(pmax);
            break;
5834
        case NEON_3R_VPMIN:
P
pbrook 已提交
5835 5836
            GEN_NEON_INTEGER_OP(pmin);
            break;
5837
        case NEON_3R_VQDMULH_VQRDMULH: /* Multiply high.  */
P
pbrook 已提交
5838 5839
            if (!u) { /* VQDMULH */
                switch (size) {
5840 5841 5842 5843 5844 5845
                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;
5846
                default: abort();
P
pbrook 已提交
5847
                }
5848
            } else { /* VQRDMULH */
P
pbrook 已提交
5849
                switch (size) {
5850 5851 5852 5853 5854 5855
                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;
5856
                default: abort();
P
pbrook 已提交
5857 5858 5859
                }
            }
            break;
5860
        case NEON_3R_VPADD:
P
pbrook 已提交
5861
            switch (size) {
5862 5863 5864
            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;
5865
            default: abort();
P
pbrook 已提交
5866 5867
            }
            break;
5868
        case NEON_3R_FLOAT_ARITH: /* Floating point arithmetic. */
5869 5870
        {
            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
P
pbrook 已提交
5871 5872
            switch ((u << 2) | size) {
            case 0: /* VADD */
5873 5874
            case 4: /* VPADD */
                gen_helper_vfp_adds(tmp, tmp, tmp2, fpstatus);
P
pbrook 已提交
5875 5876
                break;
            case 2: /* VSUB */
5877
                gen_helper_vfp_subs(tmp, tmp, tmp2, fpstatus);
P
pbrook 已提交
5878 5879
                break;
            case 6: /* VABD */
5880
                gen_helper_neon_abd_f32(tmp, tmp, tmp2, fpstatus);
P
pbrook 已提交
5881 5882
                break;
            default:
5883
                abort();
P
pbrook 已提交
5884
            }
5885
            tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
5886
            break;
5887
        }
5888
        case NEON_3R_FLOAT_MULTIPLY:
5889 5890 5891
        {
            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
            gen_helper_vfp_muls(tmp, tmp, tmp2, fpstatus);
P
pbrook 已提交
5892
            if (!u) {
5893
                tcg_temp_free_i32(tmp2);
5894
                tmp2 = neon_load_reg(rd, pass);
P
pbrook 已提交
5895
                if (size == 0) {
5896
                    gen_helper_vfp_adds(tmp, tmp, tmp2, fpstatus);
P
pbrook 已提交
5897
                } else {
5898
                    gen_helper_vfp_subs(tmp, tmp2, tmp, fpstatus);
P
pbrook 已提交
5899 5900
                }
            }
5901
            tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
5902
            break;
5903
        }
5904
        case NEON_3R_FLOAT_CMP:
5905 5906
        {
            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
P
pbrook 已提交
5907
            if (!u) {
5908
                gen_helper_neon_ceq_f32(tmp, tmp, tmp2, fpstatus);
B
bellard 已提交
5909
            } else {
5910 5911 5912 5913 5914
                if (size == 0) {
                    gen_helper_neon_cge_f32(tmp, tmp, tmp2, fpstatus);
                } else {
                    gen_helper_neon_cgt_f32(tmp, tmp, tmp2, fpstatus);
                }
B
bellard 已提交
5915
            }
5916
            tcg_temp_free_ptr(fpstatus);
B
bellard 已提交
5917
            break;
5918
        }
5919
        case NEON_3R_FLOAT_ACMP:
5920 5921 5922 5923 5924 5925 5926 5927
        {
            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 已提交
5928
            break;
5929
        }
5930
        case NEON_3R_FLOAT_MINMAX:
5931 5932 5933
        {
            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
            if (size == 0) {
5934
                gen_helper_vfp_maxs(tmp, tmp, tmp2, fpstatus);
5935
            } else {
5936
                gen_helper_vfp_mins(tmp, tmp, tmp2, fpstatus);
5937 5938
            }
            tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
5939
            break;
5940
        }
5941 5942 5943 5944 5945
        case NEON_3R_FLOAT_MISC:
            if (u) {
                /* VMAXNM/VMINNM */
                TCGv_ptr fpstatus = get_fpstatus_ptr(1);
                if (size == 0) {
5946
                    gen_helper_vfp_maxnums(tmp, tmp, tmp2, fpstatus);
5947
                } else {
5948
                    gen_helper_vfp_minnums(tmp, tmp, tmp2, fpstatus);
5949 5950 5951 5952 5953 5954 5955 5956 5957
                }
                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 已提交
5958
            break;
5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972
        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 已提交
5973 5974
        default:
            abort();
B
bellard 已提交
5975
        }
5976
        tcg_temp_free_i32(tmp2);
5977

P
pbrook 已提交
5978 5979 5980 5981
        /* 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) {
5982
            neon_store_scratch(pass, tmp);
P
pbrook 已提交
5983
        } else {
5984
            neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
5985 5986 5987 5988 5989
        }

        } /* for pass */
        if (pairwise && rd == rm) {
            for (pass = 0; pass < (q ? 4 : 2); pass++) {
5990 5991
                tmp = neon_load_scratch(pass);
                neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
5992 5993
            }
        }
P
pbrook 已提交
5994
        /* End of 3 register same size operations.  */
P
pbrook 已提交
5995 5996 5997 5998 5999
    } else if (insn & (1 << 4)) {
        if ((insn & 0x00380080) != 0) {
            /* Two registers and shift.  */
            op = (insn >> 8) & 0xf;
            if (insn & (1 << 7)) {
6000 6001 6002 6003
                /* 64-bit shift. */
                if (op > 7) {
                    return 1;
                }
P
pbrook 已提交
6004 6005 6006 6007 6008 6009 6010
                size = 3;
            } else {
                size = 2;
                while ((insn & (1 << (size + 19))) == 0)
                    size--;
            }
            shift = (insn >> 16) & ((1 << (3 + size)) - 1);
6011
            /* To avoid excessive duplication of ops we implement shift
P
pbrook 已提交
6012 6013 6014 6015
               by immediate using the variable shift operations.  */
            if (op < 8) {
                /* Shift by immediate:
                   VSHR, VSRA, VRSHR, VRSRA, VSRI, VSHL, VQSHL, VQSHLU.  */
6016 6017 6018 6019 6020 6021
                if (q && ((rd | rm) & 1)) {
                    return 1;
                }
                if (!u && (op == 4 || op == 6)) {
                    return 1;
                }
P
pbrook 已提交
6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049
                /* 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 已提交
6050 6051 6052 6053 6054 6055 6056 6057
                    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 已提交
6058
                            else
P
pbrook 已提交
6059
                                gen_helper_neon_shl_s64(cpu_V0, cpu_V0, cpu_V1);
P
pbrook 已提交
6060
                            break;
P
pbrook 已提交
6061 6062 6063 6064
                        case 2: /* VRSHR */
                        case 3: /* VRSRA */
                            if (u)
                                gen_helper_neon_rshl_u64(cpu_V0, cpu_V0, cpu_V1);
P
pbrook 已提交
6065
                            else
P
pbrook 已提交
6066
                                gen_helper_neon_rshl_s64(cpu_V0, cpu_V0, cpu_V1);
P
pbrook 已提交
6067
                            break;
P
pbrook 已提交
6068 6069 6070 6071
                        case 4: /* VSRI */
                        case 5: /* VSHL, VSLI */
                            gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1);
                            break;
6072
                        case 6: /* VQSHLU */
6073 6074
                            gen_helper_neon_qshlu_s64(cpu_V0, cpu_env,
                                                      cpu_V0, cpu_V1);
P
pbrook 已提交
6075
                            break;
6076 6077
                        case 7: /* VQSHL */
                            if (u) {
6078
                                gen_helper_neon_qshl_u64(cpu_V0, cpu_env,
6079 6080
                                                         cpu_V0, cpu_V1);
                            } else {
6081
                                gen_helper_neon_qshl_s64(cpu_V0, cpu_env,
6082 6083
                                                         cpu_V0, cpu_V1);
                            }
P
pbrook 已提交
6084 6085
                            break;
                        }
P
pbrook 已提交
6086 6087
                        if (op == 1 || op == 3) {
                            /* Accumulate.  */
6088
                            neon_load_reg64(cpu_V1, rd + pass);
P
pbrook 已提交
6089 6090 6091
                            tcg_gen_add_i64(cpu_V0, cpu_V0, cpu_V1);
                        } else if (op == 4 || (op == 5 && u)) {
                            /* Insert */
6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104
                            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 已提交
6105 6106 6107 6108
                        }
                        neon_store_reg64(cpu_V0, rd + pass);
                    } else { /* size < 3 */
                        /* Operands in T0 and T1.  */
6109
                        tmp = neon_load_reg(rm, pass);
6110
                        tmp2 = tcg_temp_new_i32();
6111
                        tcg_gen_movi_i32(tmp2, imm);
P
pbrook 已提交
6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123
                        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) {
6124 6125 6126
                            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;
6127
                            default: abort();
P
pbrook 已提交
6128 6129
                            }
                            break;
6130
                        case 6: /* VQSHLU */
P
pbrook 已提交
6131
                            switch (size) {
6132
                            case 0:
6133 6134
                                gen_helper_neon_qshlu_s8(tmp, cpu_env,
                                                         tmp, tmp2);
6135 6136
                                break;
                            case 1:
6137 6138
                                gen_helper_neon_qshlu_s16(tmp, cpu_env,
                                                          tmp, tmp2);
6139 6140
                                break;
                            case 2:
6141 6142
                                gen_helper_neon_qshlu_s32(tmp, cpu_env,
                                                          tmp, tmp2);
6143 6144
                                break;
                            default:
6145
                                abort();
P
pbrook 已提交
6146 6147
                            }
                            break;
6148
                        case 7: /* VQSHL */
6149
                            GEN_NEON_INTEGER_OP_ENV(qshl);
6150
                            break;
P
pbrook 已提交
6151
                        }
6152
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
6153 6154 6155

                        if (op == 1 || op == 3) {
                            /* Accumulate.  */
6156
                            tmp2 = neon_load_reg(rd, pass);
6157
                            gen_neon_add(size, tmp, tmp2);
6158
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
6159 6160 6161 6162 6163
                        } else if (op == 4 || (op == 5 && u)) {
                            /* Insert */
                            switch (size) {
                            case 0:
                                if (op == 4)
6164
                                    mask = 0xff >> -shift;
P
pbrook 已提交
6165
                                else
6166 6167 6168
                                    mask = (uint8_t)(0xff << shift);
                                mask |= mask << 8;
                                mask |= mask << 16;
P
pbrook 已提交
6169 6170 6171
                                break;
                            case 1:
                                if (op == 4)
6172
                                    mask = 0xffff >> -shift;
P
pbrook 已提交
6173
                                else
6174 6175
                                    mask = (uint16_t)(0xffff << shift);
                                mask |= mask << 16;
P
pbrook 已提交
6176 6177
                                break;
                            case 2:
6178 6179 6180 6181 6182 6183 6184 6185
                                if (shift < -31 || shift > 31) {
                                    mask = 0;
                                } else {
                                    if (op == 4)
                                        mask = 0xffffffffu >> -shift;
                                    else
                                        mask = 0xffffffffu << shift;
                                }
P
pbrook 已提交
6186 6187 6188 6189
                                break;
                            default:
                                abort();
                            }
6190
                            tmp2 = neon_load_reg(rd, pass);
6191 6192
                            tcg_gen_andi_i32(tmp, tmp, mask);
                            tcg_gen_andi_i32(tmp2, tmp2, ~mask);
6193
                            tcg_gen_or_i32(tmp, tmp, tmp2);
6194
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
6195
                        }
6196
                        neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
6197 6198 6199
                    }
                } /* for pass */
            } else if (op < 10) {
P
pbrook 已提交
6200
                /* Shift by immediate and narrow:
P
pbrook 已提交
6201
                   VSHRN, VRSHRN, VQSHRN, VQRSHRN.  */
6202
                int input_unsigned = (op == 8) ? !u : u;
6203 6204 6205
                if (rm & 1) {
                    return 1;
                }
P
pbrook 已提交
6206 6207
                shift = shift - (1 << (size + 3));
                size++;
6208
                if (size == 3) {
P
pbrook 已提交
6209
                    tmp64 = tcg_const_i64(shift);
6210 6211 6212 6213 6214 6215 6216 6217 6218
                    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 已提交
6219
                        if (q) {
6220
                            if (input_unsigned) {
6221
                                gen_helper_neon_rshl_u64(cpu_V0, in, tmp64);
6222
                            } else {
6223
                                gen_helper_neon_rshl_s64(cpu_V0, in, tmp64);
6224
                            }
P
pbrook 已提交
6225
                        } else {
6226
                            if (input_unsigned) {
6227
                                gen_helper_neon_shl_u64(cpu_V0, in, tmp64);
6228
                            } else {
6229
                                gen_helper_neon_shl_s64(cpu_V0, in, tmp64);
6230
                            }
P
pbrook 已提交
6231
                        }
6232
                        tmp = tcg_temp_new_i32();
6233 6234 6235 6236 6237 6238 6239 6240
                        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 已提交
6241
                    } else {
6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253
                        /* 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;
                        }
6254 6255
                        gen_neon_shift_narrow(size, tmp, tmp2, q,
                                              input_unsigned);
6256 6257 6258 6259 6260
                        if (pass == 0) {
                            tmp3 = neon_load_reg(rm, 1);
                        } else {
                            tmp3 = tmp5;
                        }
6261 6262
                        gen_neon_shift_narrow(size, tmp3, tmp2, q,
                                              input_unsigned);
P
pbrook 已提交
6263
                        tcg_gen_concat_i32_i64(cpu_V0, tmp, tmp3);
6264 6265 6266
                        tcg_temp_free_i32(tmp);
                        tcg_temp_free_i32(tmp3);
                        tmp = tcg_temp_new_i32();
6267 6268 6269
                        gen_neon_narrow_op(op == 8, u, size - 1, tmp, cpu_V0);
                        neon_store_reg(rd, pass, tmp);
                    } /* for pass */
6270
                    tcg_temp_free_i32(tmp2);
6271
                }
P
pbrook 已提交
6272
            } else if (op == 10) {
6273 6274
                /* VSHLL, VMOVL */
                if (q || (rd & 1)) {
P
pbrook 已提交
6275
                    return 1;
6276
                }
P
pbrook 已提交
6277 6278
                tmp = neon_load_reg(rm, 0);
                tmp2 = neon_load_reg(rm, 1);
P
pbrook 已提交
6279
                for (pass = 0; pass < 2; pass++) {
P
pbrook 已提交
6280 6281 6282 6283
                    if (pass == 1)
                        tmp = tmp2;

                    gen_neon_widen(cpu_V0, tmp, size, u);
P
pbrook 已提交
6284 6285 6286

                    if (shift != 0) {
                        /* The shift is less than the width of the source
P
pbrook 已提交
6287 6288
                           type, so we can just shift the whole register.  */
                        tcg_gen_shli_i64(cpu_V0, cpu_V0, shift);
6289 6290 6291 6292 6293
                        /* 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 已提交
6294 6295 6296 6297 6298
                        if (size < 2 || !u) {
                            uint64_t imm64;
                            if (size == 0) {
                                imm = (0xffu >> (8 - shift));
                                imm |= imm << 16;
6299
                            } else if (size == 1) {
P
pbrook 已提交
6300
                                imm = 0xffff >> (16 - shift);
6301 6302 6303 6304 6305 6306 6307 6308
                            } else {
                                /* size == 2 */
                                imm = 0xffffffff >> (32 - shift);
                            }
                            if (size < 2) {
                                imm64 = imm | (((uint64_t)imm) << 32);
                            } else {
                                imm64 = imm;
P
pbrook 已提交
6309
                            }
6310
                            tcg_gen_andi_i64(cpu_V0, cpu_V0, ~imm64);
P
pbrook 已提交
6311 6312
                        }
                    }
P
pbrook 已提交
6313
                    neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
6314
                }
6315
            } else if (op >= 14) {
P
pbrook 已提交
6316
                /* VCVT fixed-point.  */
6317 6318 6319
                if (!(insn & (1 << 21)) || (q && ((rd | rm) & 1))) {
                    return 1;
                }
6320 6321 6322 6323
                /* 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 已提交
6324
                for (pass = 0; pass < (q ? 4 : 2); pass++) {
P
pbrook 已提交
6325
                    tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, pass));
6326
                    if (!(op & 1)) {
P
pbrook 已提交
6327
                        if (u)
6328
                            gen_vfp_ulto(0, shift, 1);
P
pbrook 已提交
6329
                        else
6330
                            gen_vfp_slto(0, shift, 1);
P
pbrook 已提交
6331 6332
                    } else {
                        if (u)
6333
                            gen_vfp_toul(0, shift, 1);
P
pbrook 已提交
6334
                        else
6335
                            gen_vfp_tosl(0, shift, 1);
B
bellard 已提交
6336
                    }
P
pbrook 已提交
6337
                    tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, pass));
B
bellard 已提交
6338 6339
                }
            } else {
P
pbrook 已提交
6340 6341 6342 6343
                return 1;
            }
        } else { /* (insn & 0x00380080) == 0 */
            int invert;
6344 6345 6346
            if (q && (rd & 1)) {
                return 1;
            }
P
pbrook 已提交
6347 6348 6349 6350 6351

            op = (insn >> 8) & 0xf;
            /* One register and immediate.  */
            imm = (u << 7) | ((insn >> 12) & 0x70) | (insn & 0xf);
            invert = (insn & (1 << 5)) != 0;
6352 6353 6354 6355
            /* 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 已提交
6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375
            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:
6376
                imm = (imm << 8) | 0xff;
P
pbrook 已提交
6377 6378 6379 6380 6381 6382 6383 6384 6385 6386
                break;
            case 13:
                imm = (imm << 16) | 0xffff;
                break;
            case 14:
                imm |= (imm << 8) | (imm << 16) | (imm << 24);
                if (invert)
                    imm = ~imm;
                break;
            case 15:
6387 6388 6389
                if (invert) {
                    return 1;
                }
P
pbrook 已提交
6390 6391 6392 6393 6394 6395 6396 6397 6398
                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 已提交
6399
                    tmp = neon_load_reg(rd, pass);
P
pbrook 已提交
6400 6401 6402
                    if (invert) {
                        /* The immediate value has already been inverted, so
                           BIC becomes AND.  */
P
pbrook 已提交
6403
                        tcg_gen_andi_i32(tmp, tmp, imm);
P
pbrook 已提交
6404
                    } else {
P
pbrook 已提交
6405
                        tcg_gen_ori_i32(tmp, tmp, imm);
P
pbrook 已提交
6406 6407
                    }
                } else {
P
pbrook 已提交
6408
                    /* VMOV, VMVN.  */
6409
                    tmp = tcg_temp_new_i32();
P
pbrook 已提交
6410
                    if (op == 14 && invert) {
6411
                        int n;
P
pbrook 已提交
6412 6413
                        uint32_t val;
                        val = 0;
P
pbrook 已提交
6414 6415
                        for (n = 0; n < 4; n++) {
                            if (imm & (1 << (n + (pass & 1) * 4)))
P
pbrook 已提交
6416
                                val |= 0xff << (n * 8);
P
pbrook 已提交
6417
                        }
P
pbrook 已提交
6418 6419 6420
                        tcg_gen_movi_i32(tmp, val);
                    } else {
                        tcg_gen_movi_i32(tmp, imm);
P
pbrook 已提交
6421 6422
                    }
                }
P
pbrook 已提交
6423
                neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
6424 6425
            }
        }
P
pbrook 已提交
6426
    } else { /* (insn & 0x00800010 == 0x00800000) */
P
pbrook 已提交
6427 6428 6429 6430 6431 6432 6433
        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;
6434 6435 6436 6437 6438
                /* 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'
6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451
                 */
                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 */
6452
                    {0, 0, 0, 9}, /* VQDMLAL */
6453
                    {0, 0, 0, 0}, /* VMLSL */
6454
                    {0, 0, 0, 9}, /* VQDMLSL */
6455
                    {0, 0, 0, 0}, /* Integer VMULL */
6456
                    {0, 0, 0, 1}, /* VQDMULL */
6457
                    {0, 0, 0, 0xa}, /* Polynomial VMULL */
6458
                    {0, 0, 0, 7}, /* Reserved: always UNDEF */
P
pbrook 已提交
6459 6460 6461 6462 6463
                };

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

6466 6467
                if ((undefreq & (1 << size)) ||
                    ((undefreq & 8) && u)) {
6468 6469 6470 6471 6472
                    return 1;
                }
                if ((src1_wide && (rn & 1)) ||
                    (src2_wide && (rm & 1)) ||
                    (!src2_wide && (rd & 1))) {
P
pbrook 已提交
6473
                    return 1;
6474
                }
P
pbrook 已提交
6475

6476 6477 6478 6479 6480 6481
                /* 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;

6482
                    if (!arm_dc_feature(s, ARM_FEATURE_V8_PMULL)) {
6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499
                        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 已提交
6500 6501 6502
                /* Avoid overlapping operands.  Wide source operands are
                   always aligned so will never overlap with wide
                   destinations in problematic ways.  */
P
pbrook 已提交
6503
                if (rd == rm && !src2_wide) {
6504 6505
                    tmp = neon_load_reg(rm, 1);
                    neon_store_scratch(2, tmp);
P
pbrook 已提交
6506
                } else if (rd == rn && !src1_wide) {
6507 6508
                    tmp = neon_load_reg(rn, 1);
                    neon_store_scratch(2, tmp);
P
pbrook 已提交
6509
                }
6510
                TCGV_UNUSED_I32(tmp3);
P
pbrook 已提交
6511
                for (pass = 0; pass < 2; pass++) {
P
pbrook 已提交
6512 6513
                    if (src1_wide) {
                        neon_load_reg64(cpu_V0, rn + pass);
6514
                        TCGV_UNUSED_I32(tmp);
P
pbrook 已提交
6515
                    } else {
P
pbrook 已提交
6516
                        if (pass == 1 && rd == rn) {
6517
                            tmp = neon_load_scratch(2);
P
pbrook 已提交
6518
                        } else {
P
pbrook 已提交
6519 6520 6521 6522
                            tmp = neon_load_reg(rn, pass);
                        }
                        if (prewiden) {
                            gen_neon_widen(cpu_V0, tmp, size, u);
P
pbrook 已提交
6523 6524
                        }
                    }
P
pbrook 已提交
6525 6526
                    if (src2_wide) {
                        neon_load_reg64(cpu_V1, rm + pass);
6527
                        TCGV_UNUSED_I32(tmp2);
P
pbrook 已提交
6528
                    } else {
P
pbrook 已提交
6529
                        if (pass == 1 && rd == rm) {
6530
                            tmp2 = neon_load_scratch(2);
P
pbrook 已提交
6531
                        } else {
P
pbrook 已提交
6532 6533 6534 6535
                            tmp2 = neon_load_reg(rm, pass);
                        }
                        if (prewiden) {
                            gen_neon_widen(cpu_V1, tmp2, size, u);
P
pbrook 已提交
6536 6537 6538 6539
                        }
                    }
                    switch (op) {
                    case 0: case 1: case 4: /* VADDL, VADDW, VADDHN, VRADDHN */
P
pbrook 已提交
6540
                        gen_neon_addl(size);
P
pbrook 已提交
6541
                        break;
6542
                    case 2: case 3: case 6: /* VSUBL, VSUBW, VSUBHN, VRSUBHN */
P
pbrook 已提交
6543
                        gen_neon_subl(size);
P
pbrook 已提交
6544 6545 6546
                        break;
                    case 5: case 7: /* VABAL, VABDL */
                        switch ((size << 1) | u) {
P
pbrook 已提交
6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564
                        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 已提交
6565 6566
                        default: abort();
                        }
6567 6568
                        tcg_temp_free_i32(tmp2);
                        tcg_temp_free_i32(tmp);
P
pbrook 已提交
6569 6570 6571
                        break;
                    case 8: case 9: case 10: case 11: case 12: case 13:
                        /* VMLAL, VQDMLAL, VMLSL, VQDMLSL, VMULL, VQDMULL */
P
pbrook 已提交
6572
                        gen_neon_mull(cpu_V0, tmp, tmp2, size, u);
P
pbrook 已提交
6573 6574
                        break;
                    case 14: /* Polynomial VMULL */
P
Peter Maydell 已提交
6575
                        gen_helper_neon_mull_p8(cpu_V0, tmp, tmp2);
6576 6577
                        tcg_temp_free_i32(tmp2);
                        tcg_temp_free_i32(tmp);
P
Peter Maydell 已提交
6578
                        break;
6579 6580
                    default: /* 15 is RESERVED: caught earlier  */
                        abort();
P
pbrook 已提交
6581
                    }
6582 6583 6584 6585 6586
                    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 已提交
6587
                        /* Accumulate.  */
6588
                        neon_load_reg64(cpu_V1, rd + pass);
P
pbrook 已提交
6589
                        switch (op) {
6590 6591 6592 6593
                        case 10: /* VMLSL */
                            gen_neon_negl(cpu_V0, size);
                            /* Fall through */
                        case 5: case 8: /* VABAL, VMLAL */
P
pbrook 已提交
6594
                            gen_neon_addl(size);
P
pbrook 已提交
6595 6596
                            break;
                        case 9: case 11: /* VQDMLAL, VQDMLSL */
P
pbrook 已提交
6597
                            gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
6598 6599 6600
                            if (op == 11) {
                                gen_neon_negl(cpu_V0, size);
                            }
P
pbrook 已提交
6601 6602
                            gen_neon_addl_saturate(cpu_V0, cpu_V1, size);
                            break;
P
pbrook 已提交
6603 6604 6605
                        default:
                            abort();
                        }
P
pbrook 已提交
6606
                        neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
6607 6608
                    } else if (op == 4 || op == 6) {
                        /* Narrowing operation.  */
6609
                        tmp = tcg_temp_new_i32();
6610
                        if (!u) {
P
pbrook 已提交
6611
                            switch (size) {
P
pbrook 已提交
6612 6613 6614 6615 6616 6617 6618 6619
                            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);
6620
                                tcg_gen_extrl_i64_i32(tmp, cpu_V0);
P
pbrook 已提交
6621
                                break;
P
pbrook 已提交
6622 6623 6624 6625
                            default: abort();
                            }
                        } else {
                            switch (size) {
P
pbrook 已提交
6626 6627 6628 6629 6630 6631 6632 6633 6634
                            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);
6635
                                tcg_gen_extrl_i64_i32(tmp, cpu_V0);
P
pbrook 已提交
6636
                                break;
P
pbrook 已提交
6637 6638 6639
                            default: abort();
                            }
                        }
P
pbrook 已提交
6640 6641 6642 6643 6644 6645
                        if (pass == 0) {
                            tmp3 = tmp;
                        } else {
                            neon_store_reg(rd, 0, tmp3);
                            neon_store_reg(rd, 1, tmp);
                        }
P
pbrook 已提交
6646 6647
                    } else {
                        /* Write back the result.  */
P
pbrook 已提交
6648
                        neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
6649 6650 6651
                    }
                }
            } else {
6652 6653 6654 6655 6656 6657 6658
                /* 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 已提交
6659 6660 6661 6662
                switch (op) {
                case 1: /* Float VMLA scalar */
                case 5: /* Floating point VMLS scalar */
                case 9: /* Floating point VMUL scalar */
6663 6664 6665 6666 6667 6668 6669
                    if (size == 1) {
                        return 1;
                    }
                    /* fall through */
                case 0: /* Integer VMLA scalar */
                case 4: /* Integer VMLS scalar */
                case 8: /* Integer VMUL scalar */
P
pbrook 已提交
6670 6671
                case 12: /* VQDMULH scalar */
                case 13: /* VQRDMULH scalar */
6672 6673 6674
                    if (u && ((rd | rn) & 1)) {
                        return 1;
                    }
6675 6676
                    tmp = neon_get_scalar(size, rm);
                    neon_store_scratch(0, tmp);
P
pbrook 已提交
6677
                    for (pass = 0; pass < (u ? 4 : 2); pass++) {
6678 6679
                        tmp = neon_load_scratch(0);
                        tmp2 = neon_load_reg(rn, pass);
P
pbrook 已提交
6680 6681
                        if (op == 12) {
                            if (size == 1) {
6682
                                gen_helper_neon_qdmulh_s16(tmp, cpu_env, tmp, tmp2);
P
pbrook 已提交
6683
                            } else {
6684
                                gen_helper_neon_qdmulh_s32(tmp, cpu_env, tmp, tmp2);
P
pbrook 已提交
6685 6686 6687
                            }
                        } else if (op == 13) {
                            if (size == 1) {
6688
                                gen_helper_neon_qrdmulh_s16(tmp, cpu_env, tmp, tmp2);
P
pbrook 已提交
6689
                            } else {
6690
                                gen_helper_neon_qrdmulh_s32(tmp, cpu_env, tmp, tmp2);
P
pbrook 已提交
6691 6692
                            }
                        } else if (op & 1) {
6693 6694 6695
                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
                            gen_helper_vfp_muls(tmp, tmp, tmp2, fpstatus);
                            tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
6696 6697
                        } else {
                            switch (size) {
6698 6699 6700
                            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;
6701
                            default: abort();
P
pbrook 已提交
6702 6703
                            }
                        }
6704
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
6705 6706
                        if (op < 8) {
                            /* Accumulate.  */
6707
                            tmp2 = neon_load_reg(rd, pass);
P
pbrook 已提交
6708 6709
                            switch (op) {
                            case 0:
6710
                                gen_neon_add(size, tmp, tmp2);
P
pbrook 已提交
6711 6712
                                break;
                            case 1:
6713 6714 6715 6716
                            {
                                TCGv_ptr fpstatus = get_fpstatus_ptr(1);
                                gen_helper_vfp_adds(tmp, tmp, tmp2, fpstatus);
                                tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
6717
                                break;
6718
                            }
P
pbrook 已提交
6719
                            case 4:
6720
                                gen_neon_rsb(size, tmp, tmp2);
P
pbrook 已提交
6721 6722
                                break;
                            case 5:
6723 6724 6725 6726
                            {
                                TCGv_ptr fpstatus = get_fpstatus_ptr(1);
                                gen_helper_vfp_subs(tmp, tmp2, tmp, fpstatus);
                                tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
6727
                                break;
6728
                            }
P
pbrook 已提交
6729 6730 6731
                            default:
                                abort();
                            }
6732
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
6733
                        }
6734
                        neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
6735 6736 6737 6738 6739
                    }
                    break;
                case 3: /* VQDMLAL scalar */
                case 7: /* VQDMLSL scalar */
                case 11: /* VQDMULL scalar */
6740
                    if (u == 1) {
P
pbrook 已提交
6741
                        return 1;
6742 6743 6744 6745 6746 6747 6748 6749
                    }
                    /* fall through */
                case 2: /* VMLAL sclar */
                case 6: /* VMLSL scalar */
                case 10: /* VMULL scalar */
                    if (rd & 1) {
                        return 1;
                    }
6750
                    tmp2 = neon_get_scalar(size, rm);
6751 6752
                    /* We need a copy of tmp2 because gen_neon_mull
                     * deletes it during pass 0.  */
6753
                    tmp4 = tcg_temp_new_i32();
6754
                    tcg_gen_mov_i32(tmp4, tmp2);
6755
                    tmp3 = neon_load_reg(rn, 1);
P
pbrook 已提交
6756

P
pbrook 已提交
6757
                    for (pass = 0; pass < 2; pass++) {
P
pbrook 已提交
6758 6759
                        if (pass == 0) {
                            tmp = neon_load_reg(rn, 0);
P
pbrook 已提交
6760
                        } else {
6761
                            tmp = tmp3;
6762
                            tmp2 = tmp4;
P
pbrook 已提交
6763
                        }
P
pbrook 已提交
6764 6765 6766
                        gen_neon_mull(cpu_V0, tmp, tmp2, size, u);
                        if (op != 11) {
                            neon_load_reg64(cpu_V1, rd + pass);
P
pbrook 已提交
6767 6768
                        }
                        switch (op) {
6769 6770 6771 6772
                        case 6:
                            gen_neon_negl(cpu_V0, size);
                            /* Fall through */
                        case 2:
P
pbrook 已提交
6773
                            gen_neon_addl(size);
P
pbrook 已提交
6774 6775
                            break;
                        case 3: case 7:
P
pbrook 已提交
6776
                            gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
6777 6778 6779
                            if (op == 7) {
                                gen_neon_negl(cpu_V0, size);
                            }
P
pbrook 已提交
6780
                            gen_neon_addl_saturate(cpu_V0, cpu_V1, size);
P
pbrook 已提交
6781 6782 6783 6784 6785
                            break;
                        case 10:
                            /* no-op */
                            break;
                        case 11:
P
pbrook 已提交
6786
                            gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
P
pbrook 已提交
6787 6788 6789 6790
                            break;
                        default:
                            abort();
                        }
P
pbrook 已提交
6791
                        neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
6792
                    }
6793 6794


P
pbrook 已提交
6795 6796 6797 6798 6799 6800 6801 6802 6803
                    break;
                default: /* 14 and 15 are RESERVED */
                    return 1;
                }
            }
        } else { /* size == 3 */
            if (!u) {
                /* Extract.  */
                imm = (insn >> 8) & 0xf;
P
pbrook 已提交
6804 6805 6806 6807

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

6808 6809 6810 6811
                if (q && ((rd | rn | rm) & 1)) {
                    return 1;
                }

P
pbrook 已提交
6812 6813 6814 6815
                if (imm == 0) {
                    neon_load_reg64(cpu_V0, rn);
                    if (q) {
                        neon_load_reg64(cpu_V1, rn + 1);
P
pbrook 已提交
6816
                    }
P
pbrook 已提交
6817 6818 6819 6820
                } else if (imm == 8) {
                    neon_load_reg64(cpu_V0, rn + 1);
                    if (q) {
                        neon_load_reg64(cpu_V1, rm);
P
pbrook 已提交
6821
                    }
P
pbrook 已提交
6822
                } else if (q) {
P
pbrook 已提交
6823
                    tmp64 = tcg_temp_new_i64();
P
pbrook 已提交
6824 6825
                    if (imm < 8) {
                        neon_load_reg64(cpu_V0, rn);
P
pbrook 已提交
6826
                        neon_load_reg64(tmp64, rn + 1);
P
pbrook 已提交
6827 6828
                    } else {
                        neon_load_reg64(cpu_V0, rn + 1);
P
pbrook 已提交
6829
                        neon_load_reg64(tmp64, rm);
P
pbrook 已提交
6830 6831
                    }
                    tcg_gen_shri_i64(cpu_V0, cpu_V0, (imm & 7) * 8);
P
pbrook 已提交
6832
                    tcg_gen_shli_i64(cpu_V1, tmp64, 64 - ((imm & 7) * 8));
P
pbrook 已提交
6833 6834 6835
                    tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1);
                    if (imm < 8) {
                        neon_load_reg64(cpu_V1, rm);
P
pbrook 已提交
6836
                    } else {
P
pbrook 已提交
6837 6838
                        neon_load_reg64(cpu_V1, rm + 1);
                        imm -= 8;
P
pbrook 已提交
6839
                    }
P
pbrook 已提交
6840
                    tcg_gen_shli_i64(cpu_V1, cpu_V1, 64 - (imm * 8));
P
pbrook 已提交
6841 6842
                    tcg_gen_shri_i64(tmp64, tmp64, imm * 8);
                    tcg_gen_or_i64(cpu_V1, cpu_V1, tmp64);
6843
                    tcg_temp_free_i64(tmp64);
P
pbrook 已提交
6844
                } else {
P
pbrook 已提交
6845
                    /* BUGFIX */
P
pbrook 已提交
6846
                    neon_load_reg64(cpu_V0, rn);
P
pbrook 已提交
6847
                    tcg_gen_shri_i64(cpu_V0, cpu_V0, imm * 8);
P
pbrook 已提交
6848
                    neon_load_reg64(cpu_V1, rm);
P
pbrook 已提交
6849
                    tcg_gen_shli_i64(cpu_V1, cpu_V1, 64 - (imm * 8));
P
pbrook 已提交
6850 6851 6852 6853 6854
                    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 已提交
6855 6856 6857 6858 6859
                }
            } else if ((insn & (1 << 11)) == 0) {
                /* Two register misc.  */
                op = ((insn >> 12) & 0x30) | ((insn >> 7) & 0xf);
                size = (insn >> 18) & 3;
6860 6861 6862 6863
                /* UNDEF for unknown op values and bad op-size combinations */
                if ((neon_2rm_sizes[op] & (1 << size)) == 0) {
                    return 1;
                }
6864 6865 6866 6867
                if (neon_2rm_is_v8_op(op) &&
                    !arm_dc_feature(s, ARM_FEATURE_V8)) {
                    return 1;
                }
6868 6869 6870 6871
                if ((op != NEON_2RM_VMOVN && op != NEON_2RM_VQMOVN) &&
                    q && ((rm | rd) & 1)) {
                    return 1;
                }
P
pbrook 已提交
6872
                switch (op) {
6873
                case NEON_2RM_VREV64:
P
pbrook 已提交
6874
                    for (pass = 0; pass < (q ? 2 : 1); pass++) {
6875 6876
                        tmp = neon_load_reg(rm, pass * 2);
                        tmp2 = neon_load_reg(rm, pass * 2 + 1);
P
pbrook 已提交
6877
                        switch (size) {
6878 6879
                        case 0: tcg_gen_bswap32_i32(tmp, tmp); break;
                        case 1: gen_swap_half(tmp); break;
P
pbrook 已提交
6880 6881 6882
                        case 2: /* no-op */ break;
                        default: abort();
                        }
6883
                        neon_store_reg(rd, pass * 2 + 1, tmp);
P
pbrook 已提交
6884
                        if (size == 2) {
6885
                            neon_store_reg(rd, pass * 2, tmp2);
P
pbrook 已提交
6886 6887
                        } else {
                            switch (size) {
6888 6889
                            case 0: tcg_gen_bswap32_i32(tmp2, tmp2); break;
                            case 1: gen_swap_half(tmp2); break;
P
pbrook 已提交
6890 6891
                            default: abort();
                            }
6892
                            neon_store_reg(rd, pass * 2, tmp2);
P
pbrook 已提交
6893 6894 6895
                        }
                    }
                    break;
6896 6897
                case NEON_2RM_VPADDL: case NEON_2RM_VPADDL_U:
                case NEON_2RM_VPADAL: case NEON_2RM_VPADAL_U:
P
pbrook 已提交
6898 6899 6900 6901 6902 6903 6904 6905 6906 6907 6908
                    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();
                        }
6909
                        if (op >= NEON_2RM_VPADAL) {
P
pbrook 已提交
6910
                            /* Accumulate.  */
P
pbrook 已提交
6911 6912
                            neon_load_reg64(cpu_V1, rd + pass);
                            gen_neon_addl(size);
P
pbrook 已提交
6913
                        }
P
pbrook 已提交
6914
                        neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
6915 6916
                    }
                    break;
6917
                case NEON_2RM_VTRN:
P
pbrook 已提交
6918
                    if (size == 2) {
6919
                        int n;
P
pbrook 已提交
6920
                        for (n = 0; n < (q ? 4 : 2); n += 2) {
6921 6922 6923 6924
                            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 已提交
6925 6926 6927 6928 6929
                        }
                    } else {
                        goto elementwise;
                    }
                    break;
6930
                case NEON_2RM_VUZP:
6931
                    if (gen_neon_unzip(rd, rm, size, q)) {
P
pbrook 已提交
6932 6933 6934
                        return 1;
                    }
                    break;
6935
                case NEON_2RM_VZIP:
6936
                    if (gen_neon_zip(rd, rm, size, q)) {
P
pbrook 已提交
6937 6938 6939
                        return 1;
                    }
                    break;
6940 6941
                case NEON_2RM_VMOVN: case NEON_2RM_VQMOVN:
                    /* also VQMOVUN; op field and mnemonics don't line up */
6942 6943 6944
                    if (rm & 1) {
                        return 1;
                    }
6945
                    TCGV_UNUSED_I32(tmp2);
P
pbrook 已提交
6946
                    for (pass = 0; pass < 2; pass++) {
P
pbrook 已提交
6947
                        neon_load_reg64(cpu_V0, rm + pass);
6948
                        tmp = tcg_temp_new_i32();
6949 6950
                        gen_neon_narrow_op(op == NEON_2RM_VMOVN, q, size,
                                           tmp, cpu_V0);
P
pbrook 已提交
6951 6952 6953 6954 6955
                        if (pass == 0) {
                            tmp2 = tmp;
                        } else {
                            neon_store_reg(rd, 0, tmp2);
                            neon_store_reg(rd, 1, tmp);
P
pbrook 已提交
6956 6957 6958
                        }
                    }
                    break;
6959
                case NEON_2RM_VSHLL:
6960
                    if (q || (rd & 1)) {
P
pbrook 已提交
6961
                        return 1;
6962
                    }
P
pbrook 已提交
6963 6964
                    tmp = neon_load_reg(rm, 0);
                    tmp2 = neon_load_reg(rm, 1);
P
pbrook 已提交
6965
                    for (pass = 0; pass < 2; pass++) {
P
pbrook 已提交
6966 6967 6968
                        if (pass == 1)
                            tmp = tmp2;
                        gen_neon_widen(cpu_V0, tmp, size, 1);
6969
                        tcg_gen_shli_i64(cpu_V0, cpu_V0, 8 << size);
P
pbrook 已提交
6970
                        neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
6971 6972
                    }
                    break;
6973
                case NEON_2RM_VCVT_F16_F32:
6974
                    if (!arm_dc_feature(s, ARM_FEATURE_VFP_FP16) ||
6975 6976 6977
                        q || (rm & 1)) {
                        return 1;
                    }
6978 6979
                    tmp = tcg_temp_new_i32();
                    tmp2 = tcg_temp_new_i32();
P
Paul Brook 已提交
6980
                    tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 0));
6981
                    gen_helper_neon_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
P
Paul Brook 已提交
6982
                    tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 1));
6983
                    gen_helper_neon_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env);
P
Paul Brook 已提交
6984 6985 6986
                    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));
6987
                    gen_helper_neon_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
P
Paul Brook 已提交
6988 6989
                    tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 3));
                    neon_store_reg(rd, 0, tmp2);
6990
                    tmp2 = tcg_temp_new_i32();
6991
                    gen_helper_neon_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env);
P
Paul Brook 已提交
6992 6993 6994
                    tcg_gen_shli_i32(tmp2, tmp2, 16);
                    tcg_gen_or_i32(tmp2, tmp2, tmp);
                    neon_store_reg(rd, 1, tmp2);
6995
                    tcg_temp_free_i32(tmp);
P
Paul Brook 已提交
6996
                    break;
6997
                case NEON_2RM_VCVT_F32_F16:
6998
                    if (!arm_dc_feature(s, ARM_FEATURE_VFP_FP16) ||
6999 7000 7001
                        q || (rd & 1)) {
                        return 1;
                    }
7002
                    tmp3 = tcg_temp_new_i32();
P
Paul Brook 已提交
7003 7004 7005
                    tmp = neon_load_reg(rm, 0);
                    tmp2 = neon_load_reg(rm, 1);
                    tcg_gen_ext16u_i32(tmp3, tmp);
7006
                    gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
P
Paul Brook 已提交
7007 7008
                    tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 0));
                    tcg_gen_shri_i32(tmp3, tmp, 16);
7009
                    gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
P
Paul Brook 已提交
7010
                    tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 1));
7011
                    tcg_temp_free_i32(tmp);
P
Paul Brook 已提交
7012
                    tcg_gen_ext16u_i32(tmp3, tmp2);
7013
                    gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
P
Paul Brook 已提交
7014 7015
                    tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 2));
                    tcg_gen_shri_i32(tmp3, tmp2, 16);
7016
                    gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
P
Paul Brook 已提交
7017
                    tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 3));
7018 7019
                    tcg_temp_free_i32(tmp2);
                    tcg_temp_free_i32(tmp3);
P
Paul Brook 已提交
7020
                    break;
7021
                case NEON_2RM_AESE: case NEON_2RM_AESMC:
7022
                    if (!arm_dc_feature(s, ARM_FEATURE_V8_AES)
7023 7024 7025 7026 7027 7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 7042
                        || ((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;
7043
                case NEON_2RM_SHA1H:
7044
                    if (!arm_dc_feature(s, ARM_FEATURE_V8_SHA1)
7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7058 7059 7060 7061
                        || ((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) {
7062
                        if (!arm_dc_feature(s, ARM_FEATURE_V8_SHA256)) {
7063 7064
                            return 1;
                        }
7065
                    } else if (!arm_dc_feature(s, ARM_FEATURE_V8_SHA1)) {
7066 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077
                        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 已提交
7078 7079 7080
                default:
                elementwise:
                    for (pass = 0; pass < (q ? 4 : 2); pass++) {
7081
                        if (neon_2rm_is_float_op(op)) {
P
pbrook 已提交
7082 7083
                            tcg_gen_ld_f32(cpu_F0s, cpu_env,
                                           neon_reg_offset(rm, pass));
7084
                            TCGV_UNUSED_I32(tmp);
P
pbrook 已提交
7085
                        } else {
7086
                            tmp = neon_load_reg(rm, pass);
P
pbrook 已提交
7087 7088
                        }
                        switch (op) {
7089
                        case NEON_2RM_VREV32:
P
pbrook 已提交
7090
                            switch (size) {
7091 7092
                            case 0: tcg_gen_bswap32_i32(tmp, tmp); break;
                            case 1: gen_swap_half(tmp); break;
7093
                            default: abort();
P
pbrook 已提交
7094 7095
                            }
                            break;
7096
                        case NEON_2RM_VREV16:
7097
                            gen_rev16(tmp);
P
pbrook 已提交
7098
                            break;
7099
                        case NEON_2RM_VCLS:
P
pbrook 已提交
7100
                            switch (size) {
7101 7102 7103
                            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;
7104
                            default: abort();
P
pbrook 已提交
7105 7106
                            }
                            break;
7107
                        case NEON_2RM_VCLZ:
P
pbrook 已提交
7108
                            switch (size) {
7109 7110
                            case 0: gen_helper_neon_clz_u8(tmp, tmp); break;
                            case 1: gen_helper_neon_clz_u16(tmp, tmp); break;
R
Richard Henderson 已提交
7111
                            case 2: tcg_gen_clzi_i32(tmp, tmp, 32); break;
7112
                            default: abort();
P
pbrook 已提交
7113 7114
                            }
                            break;
7115
                        case NEON_2RM_VCNT:
7116
                            gen_helper_neon_cnt_u8(tmp, tmp);
P
pbrook 已提交
7117
                            break;
7118
                        case NEON_2RM_VMVN:
7119
                            tcg_gen_not_i32(tmp, tmp);
P
pbrook 已提交
7120
                            break;
7121
                        case NEON_2RM_VQABS:
P
pbrook 已提交
7122
                            switch (size) {
7123 7124 7125 7126 7127 7128 7129 7130 7131
                            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;
7132
                            default: abort();
P
pbrook 已提交
7133 7134
                            }
                            break;
7135
                        case NEON_2RM_VQNEG:
P
pbrook 已提交
7136
                            switch (size) {
7137 7138 7139 7140 7141 7142 7143 7144 7145
                            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;
7146
                            default: abort();
P
pbrook 已提交
7147 7148
                            }
                            break;
7149
                        case NEON_2RM_VCGT0: case NEON_2RM_VCLE0:
7150
                            tmp2 = tcg_const_i32(0);
P
pbrook 已提交
7151
                            switch(size) {
7152 7153 7154
                            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;
7155
                            default: abort();
P
pbrook 已提交
7156
                            }
7157
                            tcg_temp_free_i32(tmp2);
7158
                            if (op == NEON_2RM_VCLE0) {
7159
                                tcg_gen_not_i32(tmp, tmp);
7160
                            }
P
pbrook 已提交
7161
                            break;
7162
                        case NEON_2RM_VCGE0: case NEON_2RM_VCLT0:
7163
                            tmp2 = tcg_const_i32(0);
P
pbrook 已提交
7164
                            switch(size) {
7165 7166 7167
                            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;
7168
                            default: abort();
P
pbrook 已提交
7169
                            }
7170
                            tcg_temp_free_i32(tmp2);
7171
                            if (op == NEON_2RM_VCLT0) {
7172
                                tcg_gen_not_i32(tmp, tmp);
7173
                            }
P
pbrook 已提交
7174
                            break;
7175
                        case NEON_2RM_VCEQ0:
7176
                            tmp2 = tcg_const_i32(0);
P
pbrook 已提交
7177
                            switch(size) {
7178 7179 7180
                            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;
7181
                            default: abort();
P
pbrook 已提交
7182
                            }
7183
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
7184
                            break;
7185
                        case NEON_2RM_VABS:
P
pbrook 已提交
7186
                            switch(size) {
7187 7188 7189
                            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;
7190
                            default: abort();
P
pbrook 已提交
7191 7192
                            }
                            break;
7193
                        case NEON_2RM_VNEG:
7194 7195
                            tmp2 = tcg_const_i32(0);
                            gen_neon_rsb(size, tmp, tmp2);
7196
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
7197
                            break;
7198
                        case NEON_2RM_VCGT0_F:
7199 7200
                        {
                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
7201
                            tmp2 = tcg_const_i32(0);
7202
                            gen_helper_neon_cgt_f32(tmp, tmp, tmp2, fpstatus);
7203
                            tcg_temp_free_i32(tmp2);
7204
                            tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
7205
                            break;
7206
                        }
7207
                        case NEON_2RM_VCGE0_F:
7208 7209
                        {
                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
7210
                            tmp2 = tcg_const_i32(0);
7211
                            gen_helper_neon_cge_f32(tmp, tmp, tmp2, fpstatus);
7212
                            tcg_temp_free_i32(tmp2);
7213
                            tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
7214
                            break;
7215
                        }
7216
                        case NEON_2RM_VCEQ0_F:
7217 7218
                        {
                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
7219
                            tmp2 = tcg_const_i32(0);
7220
                            gen_helper_neon_ceq_f32(tmp, tmp, tmp2, fpstatus);
7221
                            tcg_temp_free_i32(tmp2);
7222
                            tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
7223
                            break;
7224
                        }
7225
                        case NEON_2RM_VCLE0_F:
7226 7227
                        {
                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
7228
                            tmp2 = tcg_const_i32(0);
7229
                            gen_helper_neon_cge_f32(tmp, tmp2, tmp, fpstatus);
7230
                            tcg_temp_free_i32(tmp2);
7231
                            tcg_temp_free_ptr(fpstatus);
7232
                            break;
7233
                        }
7234
                        case NEON_2RM_VCLT0_F:
7235 7236
                        {
                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
7237
                            tmp2 = tcg_const_i32(0);
7238
                            gen_helper_neon_cgt_f32(tmp, tmp2, tmp, fpstatus);
7239
                            tcg_temp_free_i32(tmp2);
7240
                            tcg_temp_free_ptr(fpstatus);
7241
                            break;
7242
                        }
7243
                        case NEON_2RM_VABS_F:
P
pbrook 已提交
7244
                            gen_vfp_abs(0);
P
pbrook 已提交
7245
                            break;
7246
                        case NEON_2RM_VNEG_F:
P
pbrook 已提交
7247
                            gen_vfp_neg(0);
P
pbrook 已提交
7248
                            break;
7249
                        case NEON_2RM_VSWP:
7250 7251
                            tmp2 = neon_load_reg(rd, pass);
                            neon_store_reg(rm, pass, tmp2);
P
pbrook 已提交
7252
                            break;
7253
                        case NEON_2RM_VTRN:
7254
                            tmp2 = neon_load_reg(rd, pass);
P
pbrook 已提交
7255
                            switch (size) {
7256 7257
                            case 0: gen_neon_trn_u8(tmp, tmp2); break;
                            case 1: gen_neon_trn_u16(tmp, tmp2); break;
7258
                            default: abort();
P
pbrook 已提交
7259
                            }
7260
                            neon_store_reg(rm, pass, tmp2);
P
pbrook 已提交
7261
                            break;
7262 7263 7264 7265 7266 7267 7268 7269 7270 7271 7272 7273 7274 7275 7276 7277 7278 7279 7280 7281 7282 7283 7284 7285 7286 7287
                        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;
                        }
7288 7289 7290 7291 7292 7293 7294
                        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;
                        }
7295 7296 7297 7298 7299 7300 7301 7302 7303 7304 7305 7306 7307 7308 7309 7310 7311 7312 7313 7314 7315 7316 7317 7318 7319 7320 7321 7322 7323 7324 7325 7326 7327 7328
                        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;
                        }
7329
                        case NEON_2RM_VRECPE:
7330 7331 7332 7333
                        {
                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
                            gen_helper_recpe_u32(tmp, tmp, fpstatus);
                            tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
7334
                            break;
7335
                        }
7336
                        case NEON_2RM_VRSQRTE:
7337 7338 7339 7340
                        {
                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
                            gen_helper_rsqrte_u32(tmp, tmp, fpstatus);
                            tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
7341
                            break;
7342
                        }
7343
                        case NEON_2RM_VRECPE_F:
7344 7345 7346 7347
                        {
                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
                            gen_helper_recpe_f32(cpu_F0s, cpu_F0s, fpstatus);
                            tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
7348
                            break;
7349
                        }
7350
                        case NEON_2RM_VRSQRTE_F:
7351 7352 7353 7354
                        {
                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
                            gen_helper_rsqrte_f32(cpu_F0s, cpu_F0s, fpstatus);
                            tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
7355
                            break;
7356
                        }
7357
                        case NEON_2RM_VCVT_FS: /* VCVT.F32.S32 */
7358
                            gen_vfp_sito(0, 1);
P
pbrook 已提交
7359
                            break;
7360
                        case NEON_2RM_VCVT_FU: /* VCVT.F32.U32 */
7361
                            gen_vfp_uito(0, 1);
P
pbrook 已提交
7362
                            break;
7363
                        case NEON_2RM_VCVT_SF: /* VCVT.S32.F32 */
7364
                            gen_vfp_tosiz(0, 1);
P
pbrook 已提交
7365
                            break;
7366
                        case NEON_2RM_VCVT_UF: /* VCVT.U32.F32 */
7367
                            gen_vfp_touiz(0, 1);
P
pbrook 已提交
7368 7369
                            break;
                        default:
7370 7371 7372 7373
                            /* Reserved op values were caught by the
                             * neon_2rm_sizes[] check earlier.
                             */
                            abort();
P
pbrook 已提交
7374
                        }
7375
                        if (neon_2rm_is_float_op(op)) {
P
pbrook 已提交
7376 7377
                            tcg_gen_st_f32(cpu_F0s, cpu_env,
                                           neon_reg_offset(rd, pass));
P
pbrook 已提交
7378
                        } else {
7379
                            neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
7380 7381 7382 7383 7384 7385
                        }
                    }
                    break;
                }
            } else if ((insn & (1 << 10)) == 0) {
                /* VTBL, VTBX.  */
7386 7387 7388 7389 7390 7391 7392 7393
                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 已提交
7394
                if (insn & (1 << 6)) {
P
pbrook 已提交
7395
                    tmp = neon_load_reg(rd, 0);
P
pbrook 已提交
7396
                } else {
7397
                    tmp = tcg_temp_new_i32();
P
pbrook 已提交
7398
                    tcg_gen_movi_i32(tmp, 0);
P
pbrook 已提交
7399
                }
P
pbrook 已提交
7400
                tmp2 = neon_load_reg(rm, 0);
7401 7402
                tmp4 = tcg_const_i32(rn);
                tmp5 = tcg_const_i32(n);
7403
                gen_helper_neon_tbl(tmp2, cpu_env, tmp2, tmp, tmp4, tmp5);
7404
                tcg_temp_free_i32(tmp);
P
pbrook 已提交
7405
                if (insn & (1 << 6)) {
P
pbrook 已提交
7406
                    tmp = neon_load_reg(rd, 1);
P
pbrook 已提交
7407
                } else {
7408
                    tmp = tcg_temp_new_i32();
P
pbrook 已提交
7409
                    tcg_gen_movi_i32(tmp, 0);
P
pbrook 已提交
7410
                }
P
pbrook 已提交
7411
                tmp3 = neon_load_reg(rm, 1);
7412
                gen_helper_neon_tbl(tmp3, cpu_env, tmp3, tmp, tmp4, tmp5);
7413 7414
                tcg_temp_free_i32(tmp5);
                tcg_temp_free_i32(tmp4);
P
pbrook 已提交
7415
                neon_store_reg(rd, 0, tmp2);
P
pbrook 已提交
7416
                neon_store_reg(rd, 1, tmp3);
7417
                tcg_temp_free_i32(tmp);
P
pbrook 已提交
7418 7419
            } else if ((insn & 0x380) == 0) {
                /* VDUP */
7420 7421 7422
                if ((insn & (7 << 16)) == 0 || (q && (rd & 1))) {
                    return 1;
                }
P
pbrook 已提交
7423
                if (insn & (1 << 19)) {
7424
                    tmp = neon_load_reg(rm, 1);
P
pbrook 已提交
7425
                } else {
7426
                    tmp = neon_load_reg(rm, 0);
P
pbrook 已提交
7427 7428
                }
                if (insn & (1 << 16)) {
7429
                    gen_neon_dup_u8(tmp, ((insn >> 17) & 3) * 8);
P
pbrook 已提交
7430 7431
                } else if (insn & (1 << 17)) {
                    if ((insn >> 18) & 1)
7432
                        gen_neon_dup_high16(tmp);
P
pbrook 已提交
7433
                    else
7434
                        gen_neon_dup_low16(tmp);
P
pbrook 已提交
7435 7436
                }
                for (pass = 0; pass < (q ? 4 : 2); pass++) {
7437
                    tmp2 = tcg_temp_new_i32();
7438 7439
                    tcg_gen_mov_i32(tmp2, tmp);
                    neon_store_reg(rd, pass, tmp2);
P
pbrook 已提交
7440
                }
7441
                tcg_temp_free_i32(tmp);
P
pbrook 已提交
7442 7443 7444 7445 7446 7447 7448 7449
            } else {
                return 1;
            }
        }
    }
    return 0;
}

7450
static int disas_coproc_insn(DisasContext *s, uint32_t insn)
P
pbrook 已提交
7451
{
7452 7453
    int cpnum, is64, crn, crm, opc1, opc2, isread, rt, rt2;
    const ARMCPRegInfo *ri;
P
pbrook 已提交
7454 7455

    cpnum = (insn >> 8) & 0xf;
7456 7457

    /* First check for coprocessor space used for XScale/iwMMXt insns */
7458
    if (arm_dc_feature(s, ARM_FEATURE_XSCALE) && (cpnum < 2)) {
7459 7460 7461
        if (extract32(s->c15_cpar, cpnum, 1) == 0) {
            return 1;
        }
7462
        if (arm_dc_feature(s, ARM_FEATURE_IWMMXT)) {
7463
            return disas_iwmmxt_insn(s, insn);
7464
        } else if (arm_dc_feature(s, ARM_FEATURE_XSCALE)) {
7465
            return disas_dsp_insn(s, insn);
7466 7467
        }
        return 1;
7468 7469 7470 7471 7472 7473 7474 7475 7476 7477 7478 7479 7480 7481 7482 7483 7484 7485 7486 7487 7488 7489 7490 7491
    }

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

7492
    ri = get_arm_cp_reginfo(s->cp_regs,
7493
            ENCODE_CP_REG(cpnum, is64, s->ns, crn, crm, opc1, opc2));
7494 7495
    if (ri) {
        /* Check access permissions */
7496
        if (!cp_access_ok(s->current_el, ri, isread)) {
7497 7498 7499
            return 1;
        }

7500
        if (ri->accessfn ||
7501
            (arm_dc_feature(s, ARM_FEATURE_XSCALE) && cpnum < 14)) {
7502 7503
            /* Emit code to perform further access permissions checks at
             * runtime; this may result in an exception.
7504 7505
             * Note that on XScale all cp0..c13 registers do an access check
             * call in order to handle c15_cpar.
7506 7507
             */
            TCGv_ptr tmpptr;
7508
            TCGv_i32 tcg_syn, tcg_isread;
7509 7510 7511 7512 7513 7514 7515 7516 7517 7518 7519 7520 7521 7522
            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,
7523
                                                 isread, false);
7524 7525
                } else {
                    syndrome = syn_cp14_rt_trap(1, 0xe, opc1, opc2, crn, crm,
7526
                                                rt, isread, false);
7527 7528 7529 7530 7531
                }
                break;
            case 15:
                if (is64) {
                    syndrome = syn_cp15_rrt_trap(1, 0xe, opc1, crm, rt, rt2,
7532
                                                 isread, false);
7533 7534
                } else {
                    syndrome = syn_cp15_rt_trap(1, 0xe, opc1, opc2, crn, crm,
7535
                                                rt, isread, false);
7536 7537 7538 7539 7540 7541 7542 7543
                }
                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.
                 */
7544
                assert(!arm_dc_feature(s, ARM_FEATURE_V8));
7545 7546 7547 7548
                syndrome = syn_uncategorized();
                break;
            }

7549
            gen_set_condexec(s);
7550
            gen_set_pc_im(s, s->pc - 4);
7551
            tmpptr = tcg_const_ptr(ri);
7552
            tcg_syn = tcg_const_i32(syndrome);
7553 7554 7555
            tcg_isread = tcg_const_i32(isread);
            gen_helper_access_check_cp_reg(cpu_env, tmpptr, tcg_syn,
                                           tcg_isread);
7556
            tcg_temp_free_ptr(tmpptr);
7557
            tcg_temp_free_i32(tcg_syn);
7558
            tcg_temp_free_i32(tcg_isread);
7559 7560
        }

7561 7562 7563 7564 7565 7566 7567 7568
        /* 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;
            }
7569
            gen_set_pc_im(s, s->pc);
7570
            s->is_jmp = DISAS_WFI;
P
Paul Brook 已提交
7571
            return 0;
7572 7573 7574 7575
        default:
            break;
        }

7576
        if ((s->tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
7577 7578 7579
            gen_io_start();
        }

7580 7581 7582 7583 7584 7585 7586 7587 7588 7589 7590 7591 7592 7593 7594 7595 7596 7597
        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();
7598
                tcg_gen_extrl_i64_i32(tmp, tmp64);
7599 7600
                store_reg(s, rt, tmp);
                tcg_gen_shri_i64(tmp64, tmp64, 32);
7601
                tmp = tcg_temp_new_i32();
7602
                tcg_gen_extrl_i64_i32(tmp, tmp64);
7603
                tcg_temp_free_i64(tmp64);
7604 7605
                store_reg(s, rt2, tmp);
            } else {
7606
                TCGv_i32 tmp;
7607 7608 7609 7610 7611 7612 7613 7614 7615 7616 7617 7618 7619 7620 7621 7622 7623 7624 7625 7626 7627 7628 7629 7630 7631 7632 7633 7634 7635
                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) {
7636
                TCGv_i32 tmplo, tmphi;
7637 7638 7639 7640 7641 7642 7643 7644 7645 7646 7647 7648 7649 7650 7651 7652
                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) {
7653
                    TCGv_i32 tmp;
7654 7655 7656 7657 7658 7659 7660
                    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 {
7661
                    TCGv_i32 tmp = load_reg(s, rt);
7662 7663 7664
                    store_cpu_offset(tmp, ri->fieldoffset);
                }
            }
7665 7666
        }

7667
        if ((s->tb->cflags & CF_USE_ICOUNT) && (ri->type & ARM_CP_IO)) {
7668 7669 7670 7671
            /* 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)) {
7672 7673 7674 7675
            /* 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).
             */
7676
            gen_lookup_tb(s);
7677
        }
7678

7679 7680 7681
        return 0;
    }

7682 7683 7684 7685 7686
    /* 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 "
7687 7688 7689 7690
                      "64 bit system register cp:%d opc1: %d crm:%d "
                      "(%s)\n",
                      isread ? "read" : "write", cpnum, opc1, crm,
                      s->ns ? "non-secure" : "secure");
7691 7692
    } else {
        qemu_log_mask(LOG_UNIMP, "%s access to unsupported AArch32 "
7693 7694 7695 7696
                      "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");
7697 7698
    }

7699
    return 1;
P
pbrook 已提交
7700 7701
}

P
pbrook 已提交
7702 7703

/* Store a 64-bit value to a register pair.  Clobbers val.  */
P
pbrook 已提交
7704
static void gen_storeq_reg(DisasContext *s, int rlow, int rhigh, TCGv_i64 val)
P
pbrook 已提交
7705
{
7706
    TCGv_i32 tmp;
7707
    tmp = tcg_temp_new_i32();
7708
    tcg_gen_extrl_i64_i32(tmp, val);
P
pbrook 已提交
7709
    store_reg(s, rlow, tmp);
7710
    tmp = tcg_temp_new_i32();
P
pbrook 已提交
7711
    tcg_gen_shri_i64(val, val, 32);
7712
    tcg_gen_extrl_i64_i32(tmp, val);
P
pbrook 已提交
7713 7714 7715 7716
    store_reg(s, rhigh, tmp);
}

/* load a 32-bit value from a register and perform a 64-bit accumulate.  */
P
pbrook 已提交
7717
static void gen_addq_lo(DisasContext *s, TCGv_i64 val, int rlow)
P
pbrook 已提交
7718
{
P
pbrook 已提交
7719
    TCGv_i64 tmp;
7720
    TCGv_i32 tmp2;
P
pbrook 已提交
7721

P
pbrook 已提交
7722
    /* Load value and extend to 64 bits.  */
P
pbrook 已提交
7723
    tmp = tcg_temp_new_i64();
P
pbrook 已提交
7724 7725
    tmp2 = load_reg(s, rlow);
    tcg_gen_extu_i32_i64(tmp, tmp2);
7726
    tcg_temp_free_i32(tmp2);
P
pbrook 已提交
7727
    tcg_gen_add_i64(val, val, tmp);
7728
    tcg_temp_free_i64(tmp);
P
pbrook 已提交
7729 7730 7731
}

/* load and add a 64-bit value from a register pair.  */
P
pbrook 已提交
7732
static void gen_addq(DisasContext *s, TCGv_i64 val, int rlow, int rhigh)
P
pbrook 已提交
7733
{
P
pbrook 已提交
7734
    TCGv_i64 tmp;
7735 7736
    TCGv_i32 tmpl;
    TCGv_i32 tmph;
P
pbrook 已提交
7737 7738

    /* Load 64-bit value rd:rn.  */
P
pbrook 已提交
7739 7740
    tmpl = load_reg(s, rlow);
    tmph = load_reg(s, rhigh);
P
pbrook 已提交
7741
    tmp = tcg_temp_new_i64();
P
pbrook 已提交
7742
    tcg_gen_concat_i32_i64(tmp, tmpl, tmph);
7743 7744
    tcg_temp_free_i32(tmpl);
    tcg_temp_free_i32(tmph);
P
pbrook 已提交
7745
    tcg_gen_add_i64(val, val, tmp);
7746
    tcg_temp_free_i64(tmp);
P
pbrook 已提交
7747 7748
}

7749
/* Set N and Z flags from hi|lo.  */
7750
static void gen_logicq_cc(TCGv_i32 lo, TCGv_i32 hi)
P
pbrook 已提交
7751
{
7752 7753
    tcg_gen_mov_i32(cpu_NF, hi);
    tcg_gen_or_i32(cpu_ZF, lo, hi);
P
pbrook 已提交
7754 7755
}

P
Paul Brook 已提交
7756 7757
/* Load/Store exclusive instructions are implemented by remembering
   the value/address loaded, and seeing if these are the same
7758
   when the store is performed.  This should be sufficient to implement
P
Paul Brook 已提交
7759
   the architecturally mandated semantics, and avoids having to monitor
7760 7761
   regular stores.  The compare vs the remembered value is done during
   the cmpxchg operation, but we must compare the addresses manually.  */
P
Paul Brook 已提交
7762
static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
7763
                               TCGv_i32 addr, int size)
P
Paul Brook 已提交
7764
{
7765
    TCGv_i32 tmp = tcg_temp_new_i32();
7766
    TCGMemOp opc = size | MO_ALIGN | s->be_data;
P
Paul Brook 已提交
7767

7768 7769
    s->is_ldex = true;

P
Paul Brook 已提交
7770
    if (size == 3) {
7771
        TCGv_i32 tmp2 = tcg_temp_new_i32();
7772
        TCGv_i64 t64 = tcg_temp_new_i64();
7773

7774 7775 7776 7777 7778 7779
        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);
7780
    } else {
7781
        gen_aa32_ld_i32(s, tmp, addr, get_mem_index(s), opc);
7782
        tcg_gen_extu_i32_i64(cpu_exclusive_val, tmp);
P
Paul Brook 已提交
7783
    }
7784 7785 7786

    store_reg(s, rt, tmp);
    tcg_gen_extu_i32_i64(cpu_exclusive_addr, addr);
P
Paul Brook 已提交
7787 7788 7789 7790
}

static void gen_clrex(DisasContext *s)
{
7791
    tcg_gen_movi_i64(cpu_exclusive_addr, -1);
P
Paul Brook 已提交
7792 7793 7794
}

static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
7795
                                TCGv_i32 addr, int size)
P
Paul Brook 已提交
7796
{
7797 7798 7799
    TCGv_i32 t0, t1, t2;
    TCGv_i64 extaddr;
    TCGv taddr;
7800 7801
    TCGLabel *done_label;
    TCGLabel *fail_label;
7802
    TCGMemOp opc = size | MO_ALIGN | s->be_data;
P
Paul Brook 已提交
7803 7804 7805 7806 7807 7808 7809 7810 7811

    /* 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();
7812 7813 7814 7815 7816
    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);

7817 7818 7819
    taddr = gen_aa32_addr(s, addr, opc);
    t0 = tcg_temp_new_i32();
    t1 = load_reg(s, rt);
P
Paul Brook 已提交
7820
    if (size == 3) {
7821 7822
        TCGv_i64 o64 = tcg_temp_new_i64();
        TCGv_i64 n64 = tcg_temp_new_i64();
7823

7824 7825 7826 7827
        t2 = load_reg(s, rt2);
        tcg_gen_concat_i32_i64(n64, t1, t2);
        tcg_temp_free_i32(t2);
        gen_aa32_frob64(s, n64);
7828

7829 7830 7831 7832 7833 7834 7835 7836 7837 7838 7839 7840 7841 7842 7843
        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 已提交
7844
    }
7845 7846 7847 7848
    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 已提交
7849
    tcg_gen_br(done_label);
7850

P
Paul Brook 已提交
7851 7852 7853
    gen_set_label(fail_label);
    tcg_gen_movi_i32(cpu_R[rd], 1);
    gen_set_label(done_label);
7854
    tcg_gen_movi_i64(cpu_exclusive_addr, -1);
P
Paul Brook 已提交
7855 7856
}

7857 7858 7859 7860 7861 7862 7863 7864 7865 7866 7867 7868 7869
/* 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;
7870 7871 7872 7873 7874
    TCGv_i32 addr, tmp;
    bool undef = false;

    /* SRS is:
     * - trapped to EL3 if EL3 is AArch64 and we are at Secure EL1
7875
     *   and specified mode is monitor mode
7876 7877 7878 7879 7880 7881 7882
     * - 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
7883
     * For the UNPREDICTABLE cases we choose to UNDEF.
7884
     */
7885
    if (s->current_el == 1 && !s->ns && mode == ARM_CPU_MODE_MON) {
7886 7887 7888 7889 7890 7891 7892 7893 7894 7895 7896 7897 7898 7899 7900 7901 7902 7903 7904 7905 7906 7907 7908 7909 7910 7911 7912 7913 7914 7915 7916 7917 7918 7919 7920 7921 7922 7923 7924 7925 7926 7927 7928
        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);
7929 7930 7931
    /* get_r13_banked() will raise an exception if called from System mode */
    gen_set_condexec(s);
    gen_set_pc_im(s, s->pc - 4);
7932 7933 7934 7935 7936 7937 7938 7939 7940 7941 7942 7943 7944 7945 7946 7947 7948 7949 7950 7951
    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);
7952
    gen_aa32_st32(s, tmp, addr, get_mem_index(s));
7953
    tcg_temp_free_i32(tmp);
7954 7955
    tmp = load_cpu_field(spsr);
    tcg_gen_addi_i32(addr, addr, 4);
7956
    gen_aa32_st32(s, tmp, addr, get_mem_index(s));
7957
    tcg_temp_free_i32(tmp);
7958 7959 7960 7961 7962 7963 7964 7965 7966 7967 7968 7969 7970 7971 7972 7973 7974 7975 7976 7977 7978 7979 7980
    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);
7981
    s->is_jmp = DISAS_UPDATE;
7982 7983
}

7984
static void disas_arm_insn(DisasContext *s, unsigned int insn)
P
pbrook 已提交
7985
{
7986
    unsigned int cond, val, op1, i, shift, rm, rs, rn, rd, sh;
7987 7988 7989 7990
    TCGv_i32 tmp;
    TCGv_i32 tmp2;
    TCGv_i32 tmp3;
    TCGv_i32 addr;
P
pbrook 已提交
7991
    TCGv_i64 tmp64;
P
pbrook 已提交
7992

7993 7994 7995
    /* M variants do not implement ARM mode; this must raise the INVSTATE
     * UsageFault exception.
     */
7996
    if (arm_dc_feature(s, ARM_FEATURE_M)) {
7997 7998 7999
        gen_exception_insn(s, 4, EXCP_INVSTATE, syn_uncategorized(),
                           default_exception_el(s));
        return;
8000
    }
P
pbrook 已提交
8001 8002
    cond = insn >> 28;
    if (cond == 0xf){
8003 8004 8005 8006 8007 8008
        /* 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 已提交
8009 8010 8011
        /* Unconditional instructions.  */
        if (((insn >> 25) & 7) == 1) {
            /* NEON Data processing.  */
8012
            if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
P
pbrook 已提交
8013
                goto illegal_op;
8014
            }
P
pbrook 已提交
8015

8016
            if (disas_neon_data_insn(s, insn)) {
P
pbrook 已提交
8017
                goto illegal_op;
8018
            }
P
pbrook 已提交
8019 8020 8021 8022
            return;
        }
        if ((insn & 0x0f100000) == 0x04000000) {
            /* NEON load/store.  */
8023
            if (!arm_dc_feature(s, ARM_FEATURE_NEON)) {
P
pbrook 已提交
8024
                goto illegal_op;
8025
            }
P
pbrook 已提交
8026

8027
            if (disas_neon_ls_insn(s, insn)) {
P
pbrook 已提交
8028
                goto illegal_op;
8029
            }
P
pbrook 已提交
8030 8031
            return;
        }
8032 8033
        if ((insn & 0x0f000e10) == 0x0e000a00) {
            /* VFP.  */
8034
            if (disas_vfp_insn(s, insn)) {
8035 8036 8037 8038
                goto illegal_op;
            }
            return;
        }
8039 8040 8041 8042
        if (((insn & 0x0f30f000) == 0x0510f000) ||
            ((insn & 0x0f30f010) == 0x0710f000)) {
            if ((insn & (1 << 22)) == 0) {
                /* PLDW; v7MP */
8043
                if (!arm_dc_feature(s, ARM_FEATURE_V7MP)) {
8044 8045 8046 8047
                    goto illegal_op;
                }
            }
            /* Otherwise PLD; v5TE+ */
8048
            ARCH(5TE);
8049 8050 8051 8052 8053 8054 8055 8056 8057
            return;
        }
        if (((insn & 0x0f70f000) == 0x0450f000) ||
            ((insn & 0x0f70f010) == 0x0650f000)) {
            ARCH(7);
            return; /* PLI; V7 */
        }
        if (((insn & 0x0f700000) == 0x04100000) ||
            ((insn & 0x0f700010) == 0x06100000)) {
8058
            if (!arm_dc_feature(s, ARM_FEATURE_V7MP)) {
8059 8060 8061 8062 8063 8064
                goto illegal_op;
            }
            return; /* v7MP: Unallocated memory hint: must NOP */
        }

        if ((insn & 0x0ffffdff) == 0x01010000) {
P
pbrook 已提交
8065 8066
            ARCH(6);
            /* setend */
P
Paolo Bonzini 已提交
8067 8068 8069
            if (((insn >> 9) & 1) != !!(s->be_data == MO_BE)) {
                gen_helper_setend(cpu_env);
                s->is_jmp = DISAS_UPDATE;
P
pbrook 已提交
8070 8071 8072 8073 8074 8075
            }
            return;
        } else if ((insn & 0x0fffff00) == 0x057ff000) {
            switch ((insn >> 4) & 0xf) {
            case 1: /* clrex */
                ARCH(6K);
P
Paul Brook 已提交
8076
                gen_clrex(s);
P
pbrook 已提交
8077 8078 8079 8080
                return;
            case 4: /* dsb */
            case 5: /* dmb */
                ARCH(7);
8081
                tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
P
pbrook 已提交
8082
                return;
8083 8084 8085 8086 8087 8088 8089
            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 已提交
8090 8091 8092 8093 8094
            default:
                goto illegal_op;
            }
        } else if ((insn & 0x0e5fffe0) == 0x084d0500) {
            /* srs */
8095 8096
            ARCH(6);
            gen_srs(s, (insn & 0x1f), (insn >> 23) & 3, insn & (1 << 21));
8097
            return;
8098
        } else if ((insn & 0x0e50ffe0) == 0x08100a00) {
P
pbrook 已提交
8099
            /* rfe */
8100
            int32_t offset;
P
pbrook 已提交
8101 8102 8103 8104
            if (IS_USER(s))
                goto illegal_op;
            ARCH(6);
            rn = (insn >> 16) & 0xf;
P
pbrook 已提交
8105
            addr = load_reg(s, rn);
P
pbrook 已提交
8106 8107
            i = (insn >> 23) & 3;
            switch (i) {
P
pbrook 已提交
8108
            case 0: offset = -4; break; /* DA */
8109 8110
            case 1: offset = 0; break; /* IA */
            case 2: offset = -8; break; /* DB */
P
pbrook 已提交
8111
            case 3: offset = 4; break; /* IB */
P
pbrook 已提交
8112 8113 8114
            default: abort();
            }
            if (offset)
P
pbrook 已提交
8115 8116
                tcg_gen_addi_i32(addr, addr, offset);
            /* Load PC into tmp and CPSR into tmp2.  */
8117
            tmp = tcg_temp_new_i32();
8118
            gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
8119
            tcg_gen_addi_i32(addr, addr, 4);
8120
            tmp2 = tcg_temp_new_i32();
8121
            gen_aa32_ld32u(s, tmp2, addr, get_mem_index(s));
P
pbrook 已提交
8122 8123 8124
            if (insn & (1 << 21)) {
                /* Base writeback.  */
                switch (i) {
P
pbrook 已提交
8125
                case 0: offset = -8; break;
8126 8127
                case 1: offset = 4; break;
                case 2: offset = -4; break;
P
pbrook 已提交
8128
                case 3: offset = 0; break;
P
pbrook 已提交
8129 8130 8131
                default: abort();
                }
                if (offset)
P
pbrook 已提交
8132 8133 8134
                    tcg_gen_addi_i32(addr, addr, offset);
                store_reg(s, rn, addr);
            } else {
8135
                tcg_temp_free_i32(addr);
P
pbrook 已提交
8136
            }
P
pbrook 已提交
8137
            gen_rfe(s, tmp, tmp2);
8138
            return;
P
pbrook 已提交
8139 8140 8141 8142 8143
        } else if ((insn & 0x0e000000) == 0x0a000000) {
            /* branch link and change to thumb (blx <offset>) */
            int32_t offset;

            val = (uint32_t)s->pc;
8144
            tmp = tcg_temp_new_i32();
P
pbrook 已提交
8145 8146
            tcg_gen_movi_i32(tmp, val);
            store_reg(s, 14, tmp);
P
pbrook 已提交
8147 8148 8149 8150 8151 8152
            /* 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;
8153
            /* protected by ARCH(5); above, near the start of uncond block */
P
pbrook 已提交
8154
            gen_bx_im(s, val);
P
pbrook 已提交
8155 8156
            return;
        } else if ((insn & 0x0e000f00) == 0x0c000100) {
8157
            if (arm_dc_feature(s, ARM_FEATURE_IWMMXT)) {
P
pbrook 已提交
8158
                /* iWMMXt register transfer.  */
8159
                if (extract32(s->c15_cpar, 1, 1)) {
8160
                    if (!disas_iwmmxt_insn(s, insn)) {
P
pbrook 已提交
8161
                        return;
8162 8163
                    }
                }
P
pbrook 已提交
8164 8165 8166
            }
        } else if ((insn & 0x0fe00000) == 0x0c400000) {
            /* Coprocessor double register transfer.  */
8167
            ARCH(5TE);
P
pbrook 已提交
8168 8169
        } else if ((insn & 0x0f000010) == 0x0e000010) {
            /* Additional coprocessor register transfer.  */
B
balrog 已提交
8170
        } else if ((insn & 0x0ff10020) == 0x01000000) {
P
pbrook 已提交
8171 8172 8173 8174 8175 8176 8177 8178 8179 8180 8181 8182 8183 8184 8185 8186
            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 已提交
8187
            if (insn & (1 << 17)) {
P
pbrook 已提交
8188 8189 8190 8191
                mask |= CPSR_M;
                val |= (insn & 0x1f);
            }
            if (mask) {
8192
                gen_set_psr_im(s, mask, 0, val);
P
pbrook 已提交
8193 8194 8195 8196 8197 8198 8199 8200 8201
            }
            return;
        }
        goto illegal_op;
    }
    if (cond != 0xe) {
        /* if not always execute, we generate a conditional jump to
           next instruction */
        s->condlabel = gen_new_label();
8202
        arm_gen_test_cc(cond ^ 1, s->condlabel);
P
pbrook 已提交
8203 8204 8205 8206 8207 8208 8209 8210 8211
        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 */
8212
                tmp = tcg_temp_new_i32();
P
pbrook 已提交
8213
                tcg_gen_movi_i32(tmp, val);
P
pbrook 已提交
8214 8215
            } else {
                /* MOVT */
P
pbrook 已提交
8216
                tmp = load_reg(s, rd);
P
pbrook 已提交
8217
                tcg_gen_ext16u_i32(tmp, tmp);
P
pbrook 已提交
8218
                tcg_gen_ori_i32(tmp, tmp, val << 16);
P
pbrook 已提交
8219
            }
P
pbrook 已提交
8220
            store_reg(s, rd, tmp);
P
pbrook 已提交
8221 8222 8223 8224 8225 8226 8227 8228 8229 8230 8231 8232
        } 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);
8233 8234
                if (gen_set_psr_im(s, msr_mask(s, (insn >> 16) & 0xf, i),
                                   i, val)) {
P
pbrook 已提交
8235
                    goto illegal_op;
8236
                }
P
pbrook 已提交
8237 8238 8239 8240 8241 8242 8243 8244 8245
            }
        }
    } else if ((insn & 0x0f900000) == 0x01000000
               && (insn & 0x00000090) != 0x00000090) {
        /* miscellaneous instructions */
        op1 = (insn >> 21) & 3;
        sh = (insn >> 4) & 0xf;
        rm = insn & 0xf;
        switch (sh) {
8246 8247 8248 8249 8250 8251 8252 8253 8254 8255 8256 8257 8258 8259 8260 8261 8262 8263 8264 8265
        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 已提交
8266 8267
            if (op1 & 1) {
                /* PSR = reg */
8268
                tmp = load_reg(s, rm);
P
pbrook 已提交
8269
                i = ((op1 & 2) != 0);
8270
                if (gen_set_psr(s, msr_mask(s, (insn >> 16) & 0xf, i), i, tmp))
P
pbrook 已提交
8271 8272 8273 8274 8275 8276 8277
                    goto illegal_op;
            } else {
                /* reg = PSR */
                rd = (insn >> 12) & 0xf;
                if (op1 & 2) {
                    if (IS_USER(s))
                        goto illegal_op;
P
pbrook 已提交
8278
                    tmp = load_cpu_field(spsr);
P
pbrook 已提交
8279
                } else {
8280
                    tmp = tcg_temp_new_i32();
8281
                    gen_helper_cpsr_read(tmp, cpu_env);
P
pbrook 已提交
8282
                }
P
pbrook 已提交
8283
                store_reg(s, rd, tmp);
P
pbrook 已提交
8284 8285 8286 8287 8288
            }
            break;
        case 0x1:
            if (op1 == 1) {
                /* branch/exchange thumb (bx).  */
8289
                ARCH(4T);
P
pbrook 已提交
8290 8291
                tmp = load_reg(s, rm);
                gen_bx(s, tmp);
P
pbrook 已提交
8292 8293
            } else if (op1 == 3) {
                /* clz */
8294
                ARCH(5);
P
pbrook 已提交
8295
                rd = (insn >> 12) & 0xf;
P
pbrook 已提交
8296
                tmp = load_reg(s, rm);
R
Richard Henderson 已提交
8297
                tcg_gen_clzi_i32(tmp, tmp, 32);
P
pbrook 已提交
8298
                store_reg(s, rd, tmp);
P
pbrook 已提交
8299 8300 8301 8302 8303 8304 8305 8306
            } else {
                goto illegal_op;
            }
            break;
        case 0x2:
            if (op1 == 1) {
                ARCH(5J); /* bxj */
                /* Trivial implementation equivalent to bx.  */
P
pbrook 已提交
8307 8308
                tmp = load_reg(s, rm);
                gen_bx(s, tmp);
P
pbrook 已提交
8309 8310 8311 8312 8313 8314 8315 8316
            } else {
                goto illegal_op;
            }
            break;
        case 0x3:
            if (op1 != 1)
              goto illegal_op;

8317
            ARCH(5);
P
pbrook 已提交
8318
            /* branch link/exchange thumb (blx) */
P
pbrook 已提交
8319
            tmp = load_reg(s, rm);
8320
            tmp2 = tcg_temp_new_i32();
P
pbrook 已提交
8321 8322 8323
            tcg_gen_movi_i32(tmp2, s->pc);
            store_reg(s, 14, tmp2);
            gen_bx(s, tmp);
P
pbrook 已提交
8324
            break;
8325 8326 8327 8328 8329 8330 8331 8332 8333
        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.
             */
8334
            if (!arm_dc_feature(s, ARM_FEATURE_CRC) || op1 == 0x3 ||
8335 8336 8337 8338 8339 8340 8341 8342 8343
                (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);
8344 8345 8346 8347 8348
            if (op1 == 0) {
                tcg_gen_andi_i32(tmp2, tmp2, 0xff);
            } else if (op1 == 1) {
                tcg_gen_andi_i32(tmp2, tmp2, 0xffff);
            }
8349 8350 8351 8352 8353 8354 8355 8356 8357 8358 8359
            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 已提交
8360
        case 0x5: /* saturating add/subtract */
8361
            ARCH(5TE);
P
pbrook 已提交
8362 8363
            rd = (insn >> 12) & 0xf;
            rn = (insn >> 16) & 0xf;
8364
            tmp = load_reg(s, rm);
P
pbrook 已提交
8365
            tmp2 = load_reg(s, rn);
P
pbrook 已提交
8366
            if (op1 & 2)
8367
                gen_helper_double_saturate(tmp2, cpu_env, tmp2);
P
pbrook 已提交
8368
            if (op1 & 1)
8369
                gen_helper_sub_saturate(tmp, cpu_env, tmp, tmp2);
P
pbrook 已提交
8370
            else
8371
                gen_helper_add_saturate(tmp, cpu_env, tmp, tmp2);
8372
            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8373
            store_reg(s, rd, tmp);
P
pbrook 已提交
8374
            break;
8375
        case 7:
8376 8377
        {
            int imm16 = extract32(insn, 0, 4) | (extract32(insn, 8, 12) << 4);
8378
            switch (op1) {
8379 8380 8381 8382
            case 0:
                /* HLT */
                gen_hlt(s, imm16);
                break;
8383 8384 8385 8386
            case 1:
                /* bkpt */
                ARCH(5);
                gen_exception_insn(s, 4, EXCP_BKPT,
8387 8388
                                   syn_aa32_bkpt(imm16, false),
                                   default_exception_el(s));
8389 8390 8391 8392 8393 8394 8395 8396 8397 8398 8399 8400 8401 8402 8403 8404 8405 8406
                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:
8407
                g_assert_not_reached();
8408
            }
P
pbrook 已提交
8409
            break;
8410
        }
P
pbrook 已提交
8411 8412 8413 8414
        case 0x8: /* signed multiply */
        case 0xa:
        case 0xc:
        case 0xe:
8415
            ARCH(5TE);
P
pbrook 已提交
8416 8417 8418 8419 8420
            rs = (insn >> 8) & 0xf;
            rn = (insn >> 12) & 0xf;
            rd = (insn >> 16) & 0xf;
            if (op1 == 1) {
                /* (32 * 16) >> 16 */
P
pbrook 已提交
8421 8422
                tmp = load_reg(s, rm);
                tmp2 = load_reg(s, rs);
P
pbrook 已提交
8423
                if (sh & 4)
P
pbrook 已提交
8424
                    tcg_gen_sari_i32(tmp2, tmp2, 16);
P
pbrook 已提交
8425
                else
P
pbrook 已提交
8426
                    gen_sxth(tmp2);
P
pbrook 已提交
8427 8428
                tmp64 = gen_muls_i64_i32(tmp, tmp2);
                tcg_gen_shri_i64(tmp64, tmp64, 16);
8429
                tmp = tcg_temp_new_i32();
8430
                tcg_gen_extrl_i64_i32(tmp, tmp64);
8431
                tcg_temp_free_i64(tmp64);
P
pbrook 已提交
8432
                if ((sh & 2) == 0) {
P
pbrook 已提交
8433
                    tmp2 = load_reg(s, rn);
8434
                    gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
8435
                    tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8436
                }
P
pbrook 已提交
8437
                store_reg(s, rd, tmp);
P
pbrook 已提交
8438 8439
            } else {
                /* 16 * 16 */
P
pbrook 已提交
8440 8441 8442
                tmp = load_reg(s, rm);
                tmp2 = load_reg(s, rs);
                gen_mulxy(tmp, tmp2, sh & 2, sh & 4);
8443
                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8444
                if (op1 == 2) {
P
pbrook 已提交
8445 8446
                    tmp64 = tcg_temp_new_i64();
                    tcg_gen_ext_i32_i64(tmp64, tmp);
8447
                    tcg_temp_free_i32(tmp);
P
pbrook 已提交
8448 8449
                    gen_addq(s, tmp64, rn, rd);
                    gen_storeq_reg(s, rn, rd, tmp64);
8450
                    tcg_temp_free_i64(tmp64);
P
pbrook 已提交
8451 8452
                } else {
                    if (op1 == 0) {
P
pbrook 已提交
8453
                        tmp2 = load_reg(s, rn);
8454
                        gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
8455
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8456
                    }
P
pbrook 已提交
8457
                    store_reg(s, rd, tmp);
P
pbrook 已提交
8458 8459 8460 8461 8462 8463 8464 8465 8466 8467 8468 8469 8470 8471 8472 8473 8474 8475 8476 8477
                }
            }
            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;
8478
            if (shift) {
P
pbrook 已提交
8479
                val = (val >> shift) | (val << (32 - shift));
8480
            }
8481
            tmp2 = tcg_temp_new_i32();
8482 8483 8484 8485
            tcg_gen_movi_i32(tmp2, val);
            if (logic_cc && shift) {
                gen_set_CF_bit31(tmp2);
            }
P
pbrook 已提交
8486 8487 8488
        } else {
            /* register */
            rm = (insn) & 0xf;
8489
            tmp2 = load_reg(s, rm);
P
pbrook 已提交
8490 8491 8492
            shiftop = (insn >> 5) & 3;
            if (!(insn & (1 << 4))) {
                shift = (insn >> 7) & 0x1f;
8493
                gen_arm_shift_im(tmp2, shiftop, shift, logic_cc);
P
pbrook 已提交
8494 8495
            } else {
                rs = (insn >> 8) & 0xf;
P
pbrook 已提交
8496
                tmp = load_reg(s, rs);
8497
                gen_arm_shift_reg(tmp2, shiftop, tmp, logic_cc);
P
pbrook 已提交
8498 8499 8500 8501
            }
        }
        if (op1 != 0x0f && op1 != 0x0d) {
            rn = (insn >> 16) & 0xf;
8502 8503
            tmp = load_reg(s, rn);
        } else {
8504
            TCGV_UNUSED_I32(tmp);
P
pbrook 已提交
8505 8506 8507 8508
        }
        rd = (insn >> 12) & 0xf;
        switch(op1) {
        case 0x00:
8509 8510 8511 8512
            tcg_gen_and_i32(tmp, tmp, tmp2);
            if (logic_cc) {
                gen_logic_CC(tmp);
            }
8513
            store_reg_bx(s, rd, tmp);
P
pbrook 已提交
8514 8515
            break;
        case 0x01:
8516 8517 8518 8519
            tcg_gen_xor_i32(tmp, tmp, tmp2);
            if (logic_cc) {
                gen_logic_CC(tmp);
            }
8520
            store_reg_bx(s, rd, tmp);
P
pbrook 已提交
8521 8522 8523 8524
            break;
        case 0x02:
            if (set_cc && rd == 15) {
                /* SUBS r15, ... is used for exception return.  */
8525
                if (IS_USER(s)) {
P
pbrook 已提交
8526
                    goto illegal_op;
8527
                }
8528
                gen_sub_CC(tmp, tmp, tmp2);
8529
                gen_exception_return(s, tmp);
P
pbrook 已提交
8530
            } else {
8531
                if (set_cc) {
8532
                    gen_sub_CC(tmp, tmp, tmp2);
8533 8534 8535
                } else {
                    tcg_gen_sub_i32(tmp, tmp, tmp2);
                }
8536
                store_reg_bx(s, rd, tmp);
P
pbrook 已提交
8537 8538 8539
            }
            break;
        case 0x03:
8540
            if (set_cc) {
8541
                gen_sub_CC(tmp, tmp2, tmp);
8542 8543 8544
            } else {
                tcg_gen_sub_i32(tmp, tmp2, tmp);
            }
8545
            store_reg_bx(s, rd, tmp);
P
pbrook 已提交
8546 8547
            break;
        case 0x04:
8548
            if (set_cc) {
8549
                gen_add_CC(tmp, tmp, tmp2);
8550 8551 8552
            } else {
                tcg_gen_add_i32(tmp, tmp, tmp2);
            }
8553
            store_reg_bx(s, rd, tmp);
P
pbrook 已提交
8554 8555
            break;
        case 0x05:
8556
            if (set_cc) {
8557
                gen_adc_CC(tmp, tmp, tmp2);
8558 8559 8560
            } else {
                gen_add_carry(tmp, tmp, tmp2);
            }
8561
            store_reg_bx(s, rd, tmp);
P
pbrook 已提交
8562 8563
            break;
        case 0x06:
8564
            if (set_cc) {
8565
                gen_sbc_CC(tmp, tmp, tmp2);
8566 8567 8568
            } else {
                gen_sub_carry(tmp, tmp, tmp2);
            }
8569
            store_reg_bx(s, rd, tmp);
P
pbrook 已提交
8570 8571
            break;
        case 0x07:
8572
            if (set_cc) {
8573
                gen_sbc_CC(tmp, tmp2, tmp);
8574 8575 8576
            } else {
                gen_sub_carry(tmp, tmp2, tmp);
            }
8577
            store_reg_bx(s, rd, tmp);
P
pbrook 已提交
8578 8579 8580
            break;
        case 0x08:
            if (set_cc) {
8581 8582
                tcg_gen_and_i32(tmp, tmp, tmp2);
                gen_logic_CC(tmp);
P
pbrook 已提交
8583
            }
8584
            tcg_temp_free_i32(tmp);
P
pbrook 已提交
8585 8586 8587
            break;
        case 0x09:
            if (set_cc) {
8588 8589
                tcg_gen_xor_i32(tmp, tmp, tmp2);
                gen_logic_CC(tmp);
P
pbrook 已提交
8590
            }
8591
            tcg_temp_free_i32(tmp);
P
pbrook 已提交
8592 8593 8594
            break;
        case 0x0a:
            if (set_cc) {
8595
                gen_sub_CC(tmp, tmp, tmp2);
P
pbrook 已提交
8596
            }
8597
            tcg_temp_free_i32(tmp);
P
pbrook 已提交
8598 8599 8600
            break;
        case 0x0b:
            if (set_cc) {
8601
                gen_add_CC(tmp, tmp, tmp2);
P
pbrook 已提交
8602
            }
8603
            tcg_temp_free_i32(tmp);
P
pbrook 已提交
8604 8605
            break;
        case 0x0c:
8606 8607 8608 8609
            tcg_gen_or_i32(tmp, tmp, tmp2);
            if (logic_cc) {
                gen_logic_CC(tmp);
            }
8610
            store_reg_bx(s, rd, tmp);
P
pbrook 已提交
8611 8612 8613 8614
            break;
        case 0x0d:
            if (logic_cc && rd == 15) {
                /* MOVS r15, ... is used for exception return.  */
8615
                if (IS_USER(s)) {
P
pbrook 已提交
8616
                    goto illegal_op;
8617 8618
                }
                gen_exception_return(s, tmp2);
P
pbrook 已提交
8619
            } else {
8620 8621 8622
                if (logic_cc) {
                    gen_logic_CC(tmp2);
                }
8623
                store_reg_bx(s, rd, tmp2);
P
pbrook 已提交
8624 8625 8626
            }
            break;
        case 0x0e:
8627
            tcg_gen_andc_i32(tmp, tmp, tmp2);
8628 8629 8630
            if (logic_cc) {
                gen_logic_CC(tmp);
            }
8631
            store_reg_bx(s, rd, tmp);
P
pbrook 已提交
8632 8633 8634
            break;
        default:
        case 0x0f:
8635 8636 8637 8638
            tcg_gen_not_i32(tmp2, tmp2);
            if (logic_cc) {
                gen_logic_CC(tmp2);
            }
8639
            store_reg_bx(s, rd, tmp2);
P
pbrook 已提交
8640 8641
            break;
        }
8642
        if (op1 != 0x0f && op1 != 0x0d) {
8643
            tcg_temp_free_i32(tmp2);
8644
        }
P
pbrook 已提交
8645 8646 8647 8648 8649 8650 8651 8652 8653 8654 8655 8656 8657 8658 8659 8660 8661 8662
    } 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 已提交
8663 8664 8665
                        tmp = load_reg(s, rs);
                        tmp2 = load_reg(s, rm);
                        tcg_gen_mul_i32(tmp, tmp, tmp2);
8666
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8667 8668 8669
                        if (insn & (1 << 22)) {
                            /* Subtract (mls) */
                            ARCH(6T2);
P
pbrook 已提交
8670 8671
                            tmp2 = load_reg(s, rn);
                            tcg_gen_sub_i32(tmp, tmp2, tmp);
8672
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8673 8674
                        } else if (insn & (1 << 21)) {
                            /* Add */
P
pbrook 已提交
8675 8676
                            tmp2 = load_reg(s, rn);
                            tcg_gen_add_i32(tmp, tmp, tmp2);
8677
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8678 8679
                        }
                        if (insn & (1 << 20))
P
pbrook 已提交
8680 8681
                            gen_logic_CC(tmp);
                        store_reg(s, rd, tmp);
P
pbrook 已提交
8682
                        break;
A
Aurelien Jarno 已提交
8683 8684 8685 8686 8687 8688 8689 8690 8691 8692 8693 8694 8695 8696
                    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 已提交
8697 8698
                        tmp = load_reg(s, rs);
                        tmp2 = load_reg(s, rm);
A
Aurelien Jarno 已提交
8699
                        if (insn & (1 << 22)) {
8700
                            tcg_gen_muls2_i32(tmp, tmp2, tmp, tmp2);
A
Aurelien Jarno 已提交
8701
                        } else {
8702
                            tcg_gen_mulu2_i32(tmp, tmp2, tmp, tmp2);
A
Aurelien Jarno 已提交
8703 8704
                        }
                        if (insn & (1 << 21)) { /* mult accumulate */
8705 8706
                            TCGv_i32 al = load_reg(s, rn);
                            TCGv_i32 ah = load_reg(s, rd);
8707
                            tcg_gen_add2_i32(tmp, tmp2, tmp, tmp2, al, ah);
8708 8709
                            tcg_temp_free_i32(al);
                            tcg_temp_free_i32(ah);
P
pbrook 已提交
8710
                        }
A
Aurelien Jarno 已提交
8711
                        if (insn & (1 << 20)) {
8712
                            gen_logicq_cc(tmp, tmp2);
A
Aurelien Jarno 已提交
8713
                        }
8714 8715
                        store_reg(s, rn, tmp);
                        store_reg(s, rd, tmp2);
P
pbrook 已提交
8716
                        break;
A
Aurelien Jarno 已提交
8717 8718
                    default:
                        goto illegal_op;
P
pbrook 已提交
8719 8720 8721 8722 8723 8724
                    }
                } else {
                    rn = (insn >> 16) & 0xf;
                    rd = (insn >> 12) & 0xf;
                    if (insn & (1 << 23)) {
                        /* load/store exclusive */
8725
                        int op2 = (insn >> 8) & 3;
P
pbrook 已提交
8726
                        op1 = (insn >> 21) & 0x3;
8727 8728 8729 8730 8731 8732 8733 8734 8735 8736 8737 8738 8739 8740 8741 8742 8743 8744 8745 8746 8747 8748

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

8749
                        addr = tcg_temp_local_new_i32();
8750
                        load_reg_var(s, addr, rn);
8751 8752 8753 8754 8755 8756 8757 8758 8759

                        /* 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 */
8760 8761 8762
                                    gen_aa32_ld32u_iss(s, tmp, addr,
                                                       get_mem_index(s),
                                                       rd | ISSIsAcqRel);
8763 8764
                                    break;
                                case 2: /* ldab */
8765 8766 8767
                                    gen_aa32_ld8u_iss(s, tmp, addr,
                                                      get_mem_index(s),
                                                      rd | ISSIsAcqRel);
8768 8769
                                    break;
                                case 3: /* ldah */
8770 8771 8772
                                    gen_aa32_ld16u_iss(s, tmp, addr,
                                                       get_mem_index(s),
                                                       rd | ISSIsAcqRel);
8773 8774 8775 8776 8777 8778 8779 8780 8781 8782
                                    break;
                                default:
                                    abort();
                                }
                                store_reg(s, rd, tmp);
                            } else {
                                rm = insn & 0xf;
                                tmp = load_reg(s, rm);
                                switch (op1) {
                                case 0: /* stl */
8783 8784 8785
                                    gen_aa32_st32_iss(s, tmp, addr,
                                                      get_mem_index(s),
                                                      rm | ISSIsAcqRel);
8786 8787
                                    break;
                                case 2: /* stlb */
8788 8789 8790
                                    gen_aa32_st8_iss(s, tmp, addr,
                                                     get_mem_index(s),
                                                     rm | ISSIsAcqRel);
8791 8792
                                    break;
                                case 3: /* stlh */
8793 8794 8795
                                    gen_aa32_st16_iss(s, tmp, addr,
                                                      get_mem_index(s),
                                                      rm | ISSIsAcqRel);
8796 8797 8798 8799 8800 8801 8802
                                    break;
                                default:
                                    abort();
                                }
                                tcg_temp_free_i32(tmp);
                            }
                        } else if (insn & (1 << 20)) {
P
pbrook 已提交
8803 8804
                            switch (op1) {
                            case 0: /* ldrex */
P
Paul Brook 已提交
8805
                                gen_load_exclusive(s, rd, 15, addr, 2);
P
pbrook 已提交
8806 8807
                                break;
                            case 1: /* ldrexd */
P
Paul Brook 已提交
8808
                                gen_load_exclusive(s, rd, rd + 1, addr, 3);
P
pbrook 已提交
8809 8810
                                break;
                            case 2: /* ldrexb */
P
Paul Brook 已提交
8811
                                gen_load_exclusive(s, rd, 15, addr, 0);
P
pbrook 已提交
8812 8813
                                break;
                            case 3: /* ldrexh */
P
Paul Brook 已提交
8814
                                gen_load_exclusive(s, rd, 15, addr, 1);
P
pbrook 已提交
8815 8816 8817 8818
                                break;
                            default:
                                abort();
                            }
P
pbrook 已提交
8819 8820
                        } else {
                            rm = insn & 0xf;
P
pbrook 已提交
8821 8822
                            switch (op1) {
                            case 0:  /*  strex */
P
Paul Brook 已提交
8823
                                gen_store_exclusive(s, rd, rm, 15, addr, 2);
P
pbrook 已提交
8824 8825
                                break;
                            case 1: /*  strexd */
A
Aurelien Jarno 已提交
8826
                                gen_store_exclusive(s, rd, rm, rm + 1, addr, 3);
P
pbrook 已提交
8827 8828
                                break;
                            case 2: /*  strexb */
P
Paul Brook 已提交
8829
                                gen_store_exclusive(s, rd, rm, 15, addr, 0);
P
pbrook 已提交
8830 8831
                                break;
                            case 3: /* strexh */
P
Paul Brook 已提交
8832
                                gen_store_exclusive(s, rd, rm, 15, addr, 1);
P
pbrook 已提交
8833 8834 8835 8836
                                break;
                            default:
                                abort();
                            }
P
pbrook 已提交
8837
                        }
8838
                        tcg_temp_free_i32(addr);
P
pbrook 已提交
8839
                    } else {
8840 8841 8842
                        TCGv taddr;
                        TCGMemOp opc = s->be_data;

P
pbrook 已提交
8843 8844 8845 8846
                        /* SWP instruction */
                        rm = (insn) & 0xf;

                        if (insn & (1 << 22)) {
8847
                            opc |= MO_UB;
P
pbrook 已提交
8848
                        } else {
8849
                            opc |= MO_UL | MO_ALIGN;
P
pbrook 已提交
8850
                        }
8851 8852 8853

                        addr = load_reg(s, rn);
                        taddr = gen_aa32_addr(s, addr, opc);
8854
                        tcg_temp_free_i32(addr);
8855 8856 8857 8858 8859 8860

                        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 已提交
8861 8862 8863 8864
                    }
                }
            } else {
                int address_offset;
8865
                bool load = insn & (1 << 20);
8866 8867
                bool wbit = insn & (1 << 21);
                bool pbit = insn & (1 << 24);
8868
                bool doubleword = false;
8869 8870
                ISSInfo issinfo;

P
pbrook 已提交
8871 8872 8873
                /* Misc load/store */
                rn = (insn >> 16) & 0xf;
                rd = (insn >> 12) & 0xf;
8874

8875 8876 8877
                /* ISS not valid if writeback */
                issinfo = (pbit & !wbit) ? rd : ISSInvalid;

8878 8879 8880 8881 8882 8883 8884 8885 8886 8887 8888
                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 已提交
8889
                addr = load_reg(s, rn);
8890
                if (pbit) {
P
pbrook 已提交
8891
                    gen_add_datah_offset(s, insn, 0, addr);
8892
                }
P
pbrook 已提交
8893
                address_offset = 0;
8894 8895 8896

                if (doubleword) {
                    if (!load) {
P
pbrook 已提交
8897
                        /* store */
P
pbrook 已提交
8898
                        tmp = load_reg(s, rd);
8899
                        gen_aa32_st32(s, tmp, addr, get_mem_index(s));
8900
                        tcg_temp_free_i32(tmp);
P
pbrook 已提交
8901 8902
                        tcg_gen_addi_i32(addr, addr, 4);
                        tmp = load_reg(s, rd + 1);
8903
                        gen_aa32_st32(s, tmp, addr, get_mem_index(s));
8904
                        tcg_temp_free_i32(tmp);
P
pbrook 已提交
8905 8906
                    } else {
                        /* load */
8907
                        tmp = tcg_temp_new_i32();
8908
                        gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
8909 8910
                        store_reg(s, rd, tmp);
                        tcg_gen_addi_i32(addr, addr, 4);
8911
                        tmp = tcg_temp_new_i32();
8912
                        gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
8913 8914 8915
                        rd++;
                    }
                    address_offset = -4;
8916 8917 8918 8919 8920
                } else if (load) {
                    /* load */
                    tmp = tcg_temp_new_i32();
                    switch (sh) {
                    case 1:
8921 8922
                        gen_aa32_ld16u_iss(s, tmp, addr, get_mem_index(s),
                                           issinfo);
8923 8924
                        break;
                    case 2:
8925 8926
                        gen_aa32_ld8s_iss(s, tmp, addr, get_mem_index(s),
                                          issinfo);
8927 8928 8929
                        break;
                    default:
                    case 3:
8930 8931
                        gen_aa32_ld16s_iss(s, tmp, addr, get_mem_index(s),
                                           issinfo);
8932 8933
                        break;
                    }
P
pbrook 已提交
8934 8935
                } else {
                    /* store */
P
pbrook 已提交
8936
                    tmp = load_reg(s, rd);
8937
                    gen_aa32_st16_iss(s, tmp, addr, get_mem_index(s), issinfo);
8938
                    tcg_temp_free_i32(tmp);
P
pbrook 已提交
8939 8940 8941
                }
                /* Perform base writeback before the loaded value to
                   ensure correct behavior with overlapping index registers.
8942
                   ldrd with base writeback is undefined if the
P
pbrook 已提交
8943
                   destination and index registers overlap.  */
8944
                if (!pbit) {
P
pbrook 已提交
8945 8946
                    gen_add_datah_offset(s, insn, address_offset, addr);
                    store_reg(s, rn, addr);
8947
                } else if (wbit) {
P
pbrook 已提交
8948
                    if (address_offset)
P
pbrook 已提交
8949 8950 8951
                        tcg_gen_addi_i32(addr, addr, address_offset);
                    store_reg(s, rn, addr);
                } else {
8952
                    tcg_temp_free_i32(addr);
P
pbrook 已提交
8953 8954 8955
                }
                if (load) {
                    /* Complete the load.  */
P
pbrook 已提交
8956
                    store_reg(s, rd, tmp);
P
pbrook 已提交
8957 8958 8959 8960 8961 8962 8963 8964 8965 8966 8967 8968 8969
                }
            }
            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 已提交
8970
                rd = (insn >> 12) & 0xf;
P
pbrook 已提交
8971 8972 8973 8974
                rs = (insn >> 8) & 0xf;
                switch ((insn >> 23) & 3) {
                case 0: /* Parallel add/subtract.  */
                    op1 = (insn >> 20) & 7;
P
pbrook 已提交
8975 8976
                    tmp = load_reg(s, rn);
                    tmp2 = load_reg(s, rm);
P
pbrook 已提交
8977 8978 8979
                    sh = (insn >> 5) & 7;
                    if ((op1 & 3) == 0 || sh == 5 || sh == 6)
                        goto illegal_op;
P
pbrook 已提交
8980
                    gen_arm_parallel_addsub(op1, sh, tmp, tmp2);
8981
                    tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8982
                    store_reg(s, rd, tmp);
P
pbrook 已提交
8983 8984 8985
                    break;
                case 1:
                    if ((insn & 0x00700020) == 0) {
B
balrog 已提交
8986
                        /* Halfword pack.  */
P
pbrook 已提交
8987 8988
                        tmp = load_reg(s, rn);
                        tmp2 = load_reg(s, rm);
P
pbrook 已提交
8989
                        shift = (insn >> 7) & 0x1f;
P
pbrook 已提交
8990 8991
                        if (insn & (1 << 6)) {
                            /* pkhtb */
8992 8993 8994
                            if (shift == 0)
                                shift = 31;
                            tcg_gen_sari_i32(tmp2, tmp2, shift);
P
pbrook 已提交
8995
                            tcg_gen_andi_i32(tmp, tmp, 0xffff0000);
P
pbrook 已提交
8996
                            tcg_gen_ext16u_i32(tmp2, tmp2);
P
pbrook 已提交
8997 8998
                        } else {
                            /* pkhbt */
8999 9000
                            if (shift)
                                tcg_gen_shli_i32(tmp2, tmp2, shift);
P
pbrook 已提交
9001
                            tcg_gen_ext16u_i32(tmp, tmp);
P
pbrook 已提交
9002 9003 9004
                            tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000);
                        }
                        tcg_gen_or_i32(tmp, tmp, tmp2);
9005
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
9006
                        store_reg(s, rd, tmp);
P
pbrook 已提交
9007 9008
                    } else if ((insn & 0x00200020) == 0x00200000) {
                        /* [us]sat */
P
pbrook 已提交
9009
                        tmp = load_reg(s, rm);
P
pbrook 已提交
9010 9011 9012 9013
                        shift = (insn >> 7) & 0x1f;
                        if (insn & (1 << 6)) {
                            if (shift == 0)
                                shift = 31;
P
pbrook 已提交
9014
                            tcg_gen_sari_i32(tmp, tmp, shift);
P
pbrook 已提交
9015
                        } else {
P
pbrook 已提交
9016
                            tcg_gen_shli_i32(tmp, tmp, shift);
P
pbrook 已提交
9017 9018
                        }
                        sh = (insn >> 16) & 0x1f;
9019 9020
                        tmp2 = tcg_const_i32(sh);
                        if (insn & (1 << 22))
9021
                          gen_helper_usat(tmp, cpu_env, tmp, tmp2);
9022
                        else
9023
                          gen_helper_ssat(tmp, cpu_env, tmp, tmp2);
9024
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
9025
                        store_reg(s, rd, tmp);
P
pbrook 已提交
9026 9027
                    } else if ((insn & 0x00300fe0) == 0x00200f20) {
                        /* [us]sat16 */
P
pbrook 已提交
9028
                        tmp = load_reg(s, rm);
P
pbrook 已提交
9029
                        sh = (insn >> 16) & 0x1f;
9030 9031
                        tmp2 = tcg_const_i32(sh);
                        if (insn & (1 << 22))
9032
                          gen_helper_usat16(tmp, cpu_env, tmp, tmp2);
9033
                        else
9034
                          gen_helper_ssat16(tmp, cpu_env, tmp, tmp2);
9035
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
9036
                        store_reg(s, rd, tmp);
P
pbrook 已提交
9037 9038
                    } else if ((insn & 0x00700fe0) == 0x00000fa0) {
                        /* Select bytes.  */
P
pbrook 已提交
9039 9040
                        tmp = load_reg(s, rn);
                        tmp2 = load_reg(s, rm);
9041
                        tmp3 = tcg_temp_new_i32();
9042
                        tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUARMState, GE));
P
pbrook 已提交
9043
                        gen_helper_sel_flags(tmp, tmp3, tmp, tmp2);
9044 9045
                        tcg_temp_free_i32(tmp3);
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
9046
                        store_reg(s, rd, tmp);
P
pbrook 已提交
9047
                    } else if ((insn & 0x000003e0) == 0x00000060) {
P
pbrook 已提交
9048
                        tmp = load_reg(s, rm);
P
pbrook 已提交
9049
                        shift = (insn >> 10) & 3;
9050
                        /* ??? In many cases it's not necessary to do a
P
pbrook 已提交
9051 9052
                           rotate, a shift is sufficient.  */
                        if (shift != 0)
9053
                            tcg_gen_rotri_i32(tmp, tmp, shift * 8);
P
pbrook 已提交
9054 9055
                        op1 = (insn >> 20) & 7;
                        switch (op1) {
P
pbrook 已提交
9056 9057 9058 9059 9060 9061
                        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 已提交
9062 9063 9064
                        default: goto illegal_op;
                        }
                        if (rn != 15) {
P
pbrook 已提交
9065
                            tmp2 = load_reg(s, rn);
P
pbrook 已提交
9066
                            if ((op1 & 3) == 0) {
P
pbrook 已提交
9067
                                gen_add16(tmp, tmp2);
P
pbrook 已提交
9068
                            } else {
P
pbrook 已提交
9069
                                tcg_gen_add_i32(tmp, tmp, tmp2);
9070
                                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
9071 9072
                            }
                        }
B
balrog 已提交
9073
                        store_reg(s, rd, tmp);
P
pbrook 已提交
9074 9075
                    } else if ((insn & 0x003f0f60) == 0x003f0f20) {
                        /* rev */
P
pbrook 已提交
9076
                        tmp = load_reg(s, rm);
P
pbrook 已提交
9077 9078
                        if (insn & (1 << 22)) {
                            if (insn & (1 << 7)) {
P
pbrook 已提交
9079
                                gen_revsh(tmp);
P
pbrook 已提交
9080 9081
                            } else {
                                ARCH(6T2);
P
pbrook 已提交
9082
                                gen_helper_rbit(tmp, tmp);
P
pbrook 已提交
9083 9084 9085
                            }
                        } else {
                            if (insn & (1 << 7))
P
pbrook 已提交
9086
                                gen_rev16(tmp);
P
pbrook 已提交
9087
                            else
A
aurel32 已提交
9088
                                tcg_gen_bswap32_i32(tmp, tmp);
P
pbrook 已提交
9089
                        }
P
pbrook 已提交
9090
                        store_reg(s, rd, tmp);
P
pbrook 已提交
9091 9092 9093 9094 9095
                    } else {
                        goto illegal_op;
                    }
                    break;
                case 2: /* Multiplies (Type 3).  */
9096 9097 9098 9099 9100 9101
                    switch ((insn >> 20) & 0x7) {
                    case 5:
                        if (((insn >> 6) ^ (insn >> 7)) & 1) {
                            /* op2 not 00x or 11x : UNDEF */
                            goto illegal_op;
                        }
9102 9103
                        /* Signed multiply most significant [accumulate].
                           (SMMUL, SMMLA, SMMLS) */
9104 9105
                        tmp = load_reg(s, rm);
                        tmp2 = load_reg(s, rs);
P
pbrook 已提交
9106
                        tmp64 = gen_muls_i64_i32(tmp, tmp2);
9107

9108
                        if (rd != 15) {
9109
                            tmp = load_reg(s, rd);
P
pbrook 已提交
9110
                            if (insn & (1 << 6)) {
9111
                                tmp64 = gen_subq_msw(tmp64, tmp);
P
pbrook 已提交
9112
                            } else {
9113
                                tmp64 = gen_addq_msw(tmp64, tmp);
P
pbrook 已提交
9114 9115
                            }
                        }
9116 9117 9118 9119
                        if (insn & (1 << 5)) {
                            tcg_gen_addi_i64(tmp64, tmp64, 0x80000000u);
                        }
                        tcg_gen_shri_i64(tmp64, tmp64, 32);
9120
                        tmp = tcg_temp_new_i32();
9121
                        tcg_gen_extrl_i64_i32(tmp, tmp64);
9122
                        tcg_temp_free_i64(tmp64);
9123
                        store_reg(s, rn, tmp);
9124 9125 9126 9127 9128 9129 9130 9131 9132
                        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 已提交
9133
                        if (insn & (1 << 5))
P
pbrook 已提交
9134 9135
                            gen_swap_half(tmp2);
                        gen_smul_dual(tmp, tmp2);
P
pbrook 已提交
9136
                        if (insn & (1 << 22)) {
P
pbrook 已提交
9137
                            /* smlald, smlsld */
9138 9139
                            TCGv_i64 tmp64_2;

P
pbrook 已提交
9140
                            tmp64 = tcg_temp_new_i64();
9141
                            tmp64_2 = tcg_temp_new_i64();
P
pbrook 已提交
9142
                            tcg_gen_ext_i32_i64(tmp64, tmp);
9143
                            tcg_gen_ext_i32_i64(tmp64_2, tmp2);
9144
                            tcg_temp_free_i32(tmp);
9145 9146 9147 9148 9149 9150 9151
                            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 已提交
9152 9153
                            gen_addq(s, tmp64, rd, rn);
                            gen_storeq_reg(s, rd, rn, tmp64);
9154
                            tcg_temp_free_i64(tmp64);
P
pbrook 已提交
9155
                        } else {
P
pbrook 已提交
9156
                            /* smuad, smusd, smlad, smlsd */
9157 9158 9159 9160 9161 9162 9163 9164 9165 9166 9167 9168
                            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);
9169
                            if (rd != 15)
P
pbrook 已提交
9170
                              {
9171
                                tmp2 = load_reg(s, rd);
9172
                                gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
9173
                                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
9174
                              }
9175
                            store_reg(s, rn, tmp);
P
pbrook 已提交
9176
                        }
9177
                        break;
9178 9179 9180
                    case 1:
                    case 3:
                        /* SDIV, UDIV */
9181
                        if (!arm_dc_feature(s, ARM_FEATURE_ARM_DIV)) {
9182 9183 9184 9185 9186 9187 9188 9189 9190 9191 9192 9193 9194 9195 9196
                            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;
9197 9198
                    default:
                        goto illegal_op;
P
pbrook 已提交
9199 9200 9201 9202 9203 9204
                    }
                    break;
                case 3:
                    op1 = ((insn >> 17) & 0x38) | ((insn >> 5) & 7);
                    switch (op1) {
                    case 0: /* Unsigned sum of absolute differences.  */
P
pbrook 已提交
9205 9206 9207 9208
                        ARCH(6);
                        tmp = load_reg(s, rm);
                        tmp2 = load_reg(s, rs);
                        gen_helper_usad8(tmp, tmp, tmp2);
9209
                        tcg_temp_free_i32(tmp2);
9210 9211
                        if (rd != 15) {
                            tmp2 = load_reg(s, rd);
P
pbrook 已提交
9212
                            tcg_gen_add_i32(tmp, tmp, tmp2);
9213
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
9214
                        }
9215
                        store_reg(s, rn, tmp);
P
pbrook 已提交
9216 9217 9218 9219 9220 9221
                        break;
                    case 0x20: case 0x24: case 0x28: case 0x2c:
                        /* Bitfield insert/clear.  */
                        ARCH(6T2);
                        shift = (insn >> 7) & 0x1f;
                        i = (insn >> 16) & 0x1f;
9222 9223 9224 9225
                        if (i < shift) {
                            /* UNPREDICTABLE; we choose to UNDEF */
                            goto illegal_op;
                        }
P
pbrook 已提交
9226 9227
                        i = i + 1 - shift;
                        if (rm == 15) {
9228
                            tmp = tcg_temp_new_i32();
P
pbrook 已提交
9229
                            tcg_gen_movi_i32(tmp, 0);
P
pbrook 已提交
9230
                        } else {
P
pbrook 已提交
9231
                            tmp = load_reg(s, rm);
P
pbrook 已提交
9232 9233
                        }
                        if (i != 32) {
P
pbrook 已提交
9234
                            tmp2 = load_reg(s, rd);
9235
                            tcg_gen_deposit_i32(tmp, tmp2, tmp, shift, i);
9236
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
9237
                        }
P
pbrook 已提交
9238
                        store_reg(s, rd, tmp);
P
pbrook 已提交
9239 9240 9241
                        break;
                    case 0x12: case 0x16: case 0x1a: case 0x1e: /* sbfx */
                    case 0x32: case 0x36: case 0x3a: case 0x3e: /* ubfx */
9242
                        ARCH(6T2);
P
pbrook 已提交
9243
                        tmp = load_reg(s, rm);
P
pbrook 已提交
9244 9245 9246 9247 9248 9249
                        shift = (insn >> 7) & 0x1f;
                        i = ((insn >> 16) & 0x1f) + 1;
                        if (shift + i > 32)
                            goto illegal_op;
                        if (i < 32) {
                            if (op1 & 0x20) {
9250
                                tcg_gen_extract_i32(tmp, tmp, shift, i);
P
pbrook 已提交
9251
                            } else {
9252
                                tcg_gen_sextract_i32(tmp, tmp, shift, i);
P
pbrook 已提交
9253 9254
                            }
                        }
P
pbrook 已提交
9255
                        store_reg(s, rd, tmp);
P
pbrook 已提交
9256 9257 9258 9259 9260 9261 9262 9263 9264 9265 9266 9267 9268 9269 9270 9271 9272 9273 9274 9275 9276
                        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 已提交
9277
            tmp2 = load_reg(s, rn);
9278 9279
            if ((insn & 0x01200000) == 0x00200000) {
                /* ldrt/strt */
9280
                i = get_a32_user_mem_index(s);
9281 9282 9283
            } else {
                i = get_mem_index(s);
            }
P
pbrook 已提交
9284
            if (insn & (1 << 24))
P
pbrook 已提交
9285
                gen_add_data_offset(s, insn, tmp2);
P
pbrook 已提交
9286 9287
            if (insn & (1 << 20)) {
                /* load */
9288
                tmp = tcg_temp_new_i32();
P
pbrook 已提交
9289
                if (insn & (1 << 22)) {
9290
                    gen_aa32_ld8u_iss(s, tmp, tmp2, i, rd);
P
pbrook 已提交
9291
                } else {
9292
                    gen_aa32_ld32u_iss(s, tmp, tmp2, i, rd);
P
pbrook 已提交
9293 9294 9295
                }
            } else {
                /* store */
P
pbrook 已提交
9296
                tmp = load_reg(s, rd);
9297
                if (insn & (1 << 22)) {
9298
                    gen_aa32_st8_iss(s, tmp, tmp2, i, rd);
9299
                } else {
9300
                    gen_aa32_st32_iss(s, tmp, tmp2, i, rd);
9301 9302
                }
                tcg_temp_free_i32(tmp);
P
pbrook 已提交
9303 9304
            }
            if (!(insn & (1 << 24))) {
P
pbrook 已提交
9305 9306 9307 9308 9309
                gen_add_data_offset(s, insn, tmp2);
                store_reg(s, rn, tmp2);
            } else if (insn & (1 << 21)) {
                store_reg(s, rn, tmp2);
            } else {
9310
                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
9311 9312 9313
            }
            if (insn & (1 << 20)) {
                /* Complete the load.  */
9314
                store_reg_from_load(s, rd, tmp);
P
pbrook 已提交
9315 9316 9317 9318 9319
            }
            break;
        case 0x08:
        case 0x09:
            {
9320 9321 9322 9323
                int j, n, loaded_base;
                bool exc_return = false;
                bool is_load = extract32(insn, 20, 1);
                bool user = false;
9324
                TCGv_i32 loaded_var;
P
pbrook 已提交
9325 9326 9327
                /* load/store multiple words */
                /* XXX: store correct base if write back */
                if (insn & (1 << 22)) {
9328
                    /* LDM (user), LDM (exception return) and STM (user) */
P
pbrook 已提交
9329 9330 9331
                    if (IS_USER(s))
                        goto illegal_op; /* only usable in supervisor mode */

9332 9333 9334 9335 9336
                    if (is_load && extract32(insn, 15, 1)) {
                        exc_return = true;
                    } else {
                        user = true;
                    }
P
pbrook 已提交
9337 9338
                }
                rn = (insn >> 16) & 0xf;
P
pbrook 已提交
9339
                addr = load_reg(s, rn);
P
pbrook 已提交
9340 9341 9342

                /* compute total size */
                loaded_base = 0;
9343
                TCGV_UNUSED_I32(loaded_var);
P
pbrook 已提交
9344 9345 9346 9347 9348 9349 9350 9351 9352
                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 已提交
9353
                        tcg_gen_addi_i32(addr, addr, 4);
P
pbrook 已提交
9354 9355 9356 9357 9358 9359
                    } else {
                        /* post increment */
                    }
                } else {
                    if (insn & (1 << 24)) {
                        /* pre decrement */
P
pbrook 已提交
9360
                        tcg_gen_addi_i32(addr, addr, -(n * 4));
P
pbrook 已提交
9361 9362 9363
                    } else {
                        /* post decrement */
                        if (n != 1)
P
pbrook 已提交
9364
                        tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
P
pbrook 已提交
9365 9366 9367 9368 9369
                    }
                }
                j = 0;
                for(i=0;i<16;i++) {
                    if (insn & (1 << i)) {
9370
                        if (is_load) {
P
pbrook 已提交
9371
                            /* load */
9372
                            tmp = tcg_temp_new_i32();
9373
                            gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
9374
                            if (user) {
9375
                                tmp2 = tcg_const_i32(i);
B
Blue Swirl 已提交
9376
                                gen_helper_set_user_reg(cpu_env, tmp2, tmp);
9377
                                tcg_temp_free_i32(tmp2);
9378
                                tcg_temp_free_i32(tmp);
P
pbrook 已提交
9379
                            } else if (i == rn) {
P
pbrook 已提交
9380
                                loaded_var = tmp;
P
pbrook 已提交
9381
                                loaded_base = 1;
9382 9383
                            } else if (rn == 15 && exc_return) {
                                store_pc_exc_ret(s, tmp);
P
pbrook 已提交
9384
                            } else {
9385
                                store_reg_from_load(s, i, tmp);
P
pbrook 已提交
9386 9387 9388 9389 9390 9391
                            }
                        } else {
                            /* store */
                            if (i == 15) {
                                /* special case: r15 = PC + 8 */
                                val = (long)s->pc + 4;
9392
                                tmp = tcg_temp_new_i32();
P
pbrook 已提交
9393
                                tcg_gen_movi_i32(tmp, val);
P
pbrook 已提交
9394
                            } else if (user) {
9395
                                tmp = tcg_temp_new_i32();
9396
                                tmp2 = tcg_const_i32(i);
9397
                                gen_helper_get_user_reg(tmp, cpu_env, tmp2);
9398
                                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
9399
                            } else {
P
pbrook 已提交
9400
                                tmp = load_reg(s, i);
P
pbrook 已提交
9401
                            }
9402
                            gen_aa32_st32(s, tmp, addr, get_mem_index(s));
9403
                            tcg_temp_free_i32(tmp);
P
pbrook 已提交
9404 9405 9406 9407
                        }
                        j++;
                        /* no need to add after the last transfer */
                        if (j != n)
P
pbrook 已提交
9408
                            tcg_gen_addi_i32(addr, addr, 4);
P
pbrook 已提交
9409 9410 9411 9412 9413 9414 9415 9416 9417
                    }
                }
                if (insn & (1 << 21)) {
                    /* write back */
                    if (insn & (1 << 23)) {
                        if (insn & (1 << 24)) {
                            /* pre increment */
                        } else {
                            /* post increment */
P
pbrook 已提交
9418
                            tcg_gen_addi_i32(addr, addr, 4);
P
pbrook 已提交
9419 9420 9421 9422 9423
                        }
                    } else {
                        if (insn & (1 << 24)) {
                            /* pre decrement */
                            if (n != 1)
P
pbrook 已提交
9424
                                tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
P
pbrook 已提交
9425 9426
                        } else {
                            /* post decrement */
P
pbrook 已提交
9427
                            tcg_gen_addi_i32(addr, addr, -(n * 4));
P
pbrook 已提交
9428 9429
                        }
                    }
P
pbrook 已提交
9430 9431
                    store_reg(s, rn, addr);
                } else {
9432
                    tcg_temp_free_i32(addr);
P
pbrook 已提交
9433 9434
                }
                if (loaded_base) {
P
pbrook 已提交
9435
                    store_reg(s, rn, loaded_var);
P
pbrook 已提交
9436
                }
9437
                if (exc_return) {
P
pbrook 已提交
9438
                    /* Restore CPSR from SPSR.  */
P
pbrook 已提交
9439
                    tmp = load_cpu_field(spsr);
9440
                    gen_helper_cpsr_write_eret(cpu_env, tmp);
9441
                    tcg_temp_free_i32(tmp);
9442
                    s->is_jmp = DISAS_JUMP;
P
pbrook 已提交
9443 9444 9445 9446 9447 9448 9449 9450 9451 9452 9453
                }
            }
            break;
        case 0xa:
        case 0xb:
            {
                int32_t offset;

                /* branch (and link) */
                val = (int32_t)s->pc;
                if (insn & (1 << 24)) {
9454
                    tmp = tcg_temp_new_i32();
P
pbrook 已提交
9455 9456
                    tcg_gen_movi_i32(tmp, val);
                    store_reg(s, 14, tmp);
P
pbrook 已提交
9457
                }
9458 9459
                offset = sextract32(insn << 2, 0, 26);
                val += offset + 4;
P
pbrook 已提交
9460 9461 9462 9463 9464 9465
                gen_jmp(s, val);
            }
            break;
        case 0xc:
        case 0xd:
        case 0xe:
9466 9467
            if (((insn >> 8) & 0xe) == 10) {
                /* VFP.  */
9468
                if (disas_vfp_insn(s, insn)) {
9469 9470
                    goto illegal_op;
                }
9471
            } else if (disas_coproc_insn(s, insn)) {
9472
                /* Coprocessor.  */
P
pbrook 已提交
9473
                goto illegal_op;
9474
            }
P
pbrook 已提交
9475 9476 9477
            break;
        case 0xf:
            /* swi */
9478
            gen_set_pc_im(s, s->pc);
9479
            s->svc_imm = extract32(insn, 0, 24);
P
pbrook 已提交
9480 9481 9482 9483
            s->is_jmp = DISAS_SWI;
            break;
        default:
        illegal_op:
9484 9485
            gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized(),
                               default_exception_el(s));
P
pbrook 已提交
9486 9487 9488 9489 9490 9491 9492 9493 9494 9495 9496 9497 9498 9499 9500 9501 9502 9503 9504
            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
9505 9506
gen_thumb2_data_op(DisasContext *s, int op, int conds, uint32_t shifter_out,
                   TCGv_i32 t0, TCGv_i32 t1)
P
pbrook 已提交
9507 9508 9509 9510 9511 9512
{
    int logic_cc;

    logic_cc = 0;
    switch (op) {
    case 0: /* and */
9513
        tcg_gen_and_i32(t0, t0, t1);
P
pbrook 已提交
9514 9515 9516
        logic_cc = conds;
        break;
    case 1: /* bic */
9517
        tcg_gen_andc_i32(t0, t0, t1);
P
pbrook 已提交
9518 9519 9520
        logic_cc = conds;
        break;
    case 2: /* orr */
9521
        tcg_gen_or_i32(t0, t0, t1);
P
pbrook 已提交
9522 9523 9524
        logic_cc = conds;
        break;
    case 3: /* orn */
9525
        tcg_gen_orc_i32(t0, t0, t1);
P
pbrook 已提交
9526 9527 9528
        logic_cc = conds;
        break;
    case 4: /* eor */
9529
        tcg_gen_xor_i32(t0, t0, t1);
P
pbrook 已提交
9530 9531 9532 9533
        logic_cc = conds;
        break;
    case 8: /* add */
        if (conds)
9534
            gen_add_CC(t0, t0, t1);
P
pbrook 已提交
9535
        else
9536
            tcg_gen_add_i32(t0, t0, t1);
P
pbrook 已提交
9537 9538 9539
        break;
    case 10: /* adc */
        if (conds)
9540
            gen_adc_CC(t0, t0, t1);
P
pbrook 已提交
9541
        else
9542
            gen_adc(t0, t1);
P
pbrook 已提交
9543 9544
        break;
    case 11: /* sbc */
9545 9546 9547
        if (conds) {
            gen_sbc_CC(t0, t0, t1);
        } else {
9548
            gen_sub_carry(t0, t0, t1);
9549
        }
P
pbrook 已提交
9550 9551 9552
        break;
    case 13: /* sub */
        if (conds)
9553
            gen_sub_CC(t0, t0, t1);
P
pbrook 已提交
9554
        else
9555
            tcg_gen_sub_i32(t0, t0, t1);
P
pbrook 已提交
9556 9557 9558
        break;
    case 14: /* rsb */
        if (conds)
9559
            gen_sub_CC(t0, t1, t0);
P
pbrook 已提交
9560
        else
9561
            tcg_gen_sub_i32(t0, t1, t0);
P
pbrook 已提交
9562 9563 9564 9565 9566
        break;
    default: /* 5, 6, 7, 9, 12, 15. */
        return 1;
    }
    if (logic_cc) {
9567
        gen_logic_CC(t0);
P
pbrook 已提交
9568
        if (shifter_out)
9569
            gen_set_CF_bit31(t1);
P
pbrook 已提交
9570 9571 9572 9573 9574 9575
    }
    return 0;
}

/* Translate a 32-bit thumb instruction.  Returns nonzero if the instruction
   is not legal.  */
9576
static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw1)
P
pbrook 已提交
9577
{
P
pbrook 已提交
9578
    uint32_t insn, imm, shift, offset;
P
pbrook 已提交
9579
    uint32_t rd, rn, rm, rs;
9580 9581 9582 9583
    TCGv_i32 tmp;
    TCGv_i32 tmp2;
    TCGv_i32 tmp3;
    TCGv_i32 addr;
P
pbrook 已提交
9584
    TCGv_i64 tmp64;
P
pbrook 已提交
9585 9586 9587 9588 9589
    int op;
    int shiftop;
    int conds;
    int logic_cc;

9590 9591
    if (!(arm_dc_feature(s, ARM_FEATURE_THUMB2)
          || arm_dc_feature(s, ARM_FEATURE_M))) {
9592
        /* Thumb-1 cores may need to treat bl and blx as a pair of
P
pbrook 已提交
9593 9594 9595
           16-bit instructions to get correct prefetch abort behavior.  */
        insn = insn_hw1;
        if ((insn & (1 << 12)) == 0) {
9596
            ARCH(5);
P
pbrook 已提交
9597 9598
            /* Second half of blx.  */
            offset = ((insn & 0x7ff) << 1);
P
pbrook 已提交
9599 9600 9601
            tmp = load_reg(s, 14);
            tcg_gen_addi_i32(tmp, tmp, offset);
            tcg_gen_andi_i32(tmp, tmp, 0xfffffffc);
P
pbrook 已提交
9602

9603
            tmp2 = tcg_temp_new_i32();
P
pbrook 已提交
9604
            tcg_gen_movi_i32(tmp2, s->pc | 1);
P
pbrook 已提交
9605 9606
            store_reg(s, 14, tmp2);
            gen_bx(s, tmp);
P
pbrook 已提交
9607 9608 9609 9610 9611
            return 0;
        }
        if (insn & (1 << 11)) {
            /* Second half of bl.  */
            offset = ((insn & 0x7ff) << 1) | 1;
P
pbrook 已提交
9612
            tmp = load_reg(s, 14);
B
balrog 已提交
9613
            tcg_gen_addi_i32(tmp, tmp, offset);
P
pbrook 已提交
9614

9615
            tmp2 = tcg_temp_new_i32();
P
pbrook 已提交
9616
            tcg_gen_movi_i32(tmp2, s->pc | 1);
P
pbrook 已提交
9617 9618
            store_reg(s, 14, tmp2);
            gen_bx(s, tmp);
P
pbrook 已提交
9619 9620 9621 9622 9623 9624 9625
            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;
9626
            tcg_gen_movi_i32(cpu_R[14], s->pc + 2 + offset);
P
pbrook 已提交
9627 9628 9629 9630 9631
            return 0;
        }
        /* Fall through to 32-bit decode.  */
    }

9632
    insn = arm_lduw_code(env, s->pc, s->sctlr_b);
P
pbrook 已提交
9633 9634 9635 9636 9637 9638 9639 9640 9641 9642 9643 9644 9645 9646 9647 9648 9649 9650 9651 9652 9653
    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) {
9654
                    addr = tcg_temp_new_i32();
P
pbrook 已提交
9655
                    tcg_gen_movi_i32(addr, s->pc & ~3);
P
pbrook 已提交
9656
                } else {
P
pbrook 已提交
9657
                    addr = load_reg(s, rn);
P
pbrook 已提交
9658 9659 9660 9661 9662
                }
                offset = (insn & 0xff) * 4;
                if ((insn & (1 << 23)) == 0)
                    offset = -offset;
                if (insn & (1 << 24)) {
P
pbrook 已提交
9663
                    tcg_gen_addi_i32(addr, addr, offset);
P
pbrook 已提交
9664 9665 9666 9667
                    offset = 0;
                }
                if (insn & (1 << 20)) {
                    /* ldrd */
9668
                    tmp = tcg_temp_new_i32();
9669
                    gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
9670 9671
                    store_reg(s, rs, tmp);
                    tcg_gen_addi_i32(addr, addr, 4);
9672
                    tmp = tcg_temp_new_i32();
9673
                    gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
9674
                    store_reg(s, rd, tmp);
P
pbrook 已提交
9675 9676
                } else {
                    /* strd */
P
pbrook 已提交
9677
                    tmp = load_reg(s, rs);
9678
                    gen_aa32_st32(s, tmp, addr, get_mem_index(s));
9679
                    tcg_temp_free_i32(tmp);
P
pbrook 已提交
9680 9681
                    tcg_gen_addi_i32(addr, addr, 4);
                    tmp = load_reg(s, rd);
9682
                    gen_aa32_st32(s, tmp, addr, get_mem_index(s));
9683
                    tcg_temp_free_i32(tmp);
P
pbrook 已提交
9684 9685 9686 9687 9688
                }
                if (insn & (1 << 21)) {
                    /* Base writeback.  */
                    if (rn == 15)
                        goto illegal_op;
P
pbrook 已提交
9689 9690 9691
                    tcg_gen_addi_i32(addr, addr, offset - 4);
                    store_reg(s, rn, addr);
                } else {
9692
                    tcg_temp_free_i32(addr);
P
pbrook 已提交
9693 9694 9695
                }
            } else if ((insn & (1 << 23)) == 0) {
                /* Load/store exclusive word.  */
9696
                addr = tcg_temp_local_new_i32();
9697
                load_reg_var(s, addr, rn);
P
Paul Brook 已提交
9698
                tcg_gen_addi_i32(addr, addr, (insn & 0xff) << 2);
B
bellard 已提交
9699
                if (insn & (1 << 20)) {
P
Paul Brook 已提交
9700
                    gen_load_exclusive(s, rs, 15, addr, 2);
P
pbrook 已提交
9701
                } else {
P
Paul Brook 已提交
9702
                    gen_store_exclusive(s, rd, rs, 15, addr, 2);
P
pbrook 已提交
9703
                }
9704
                tcg_temp_free_i32(addr);
9705
            } else if ((insn & (7 << 5)) == 0) {
P
pbrook 已提交
9706 9707
                /* Table Branch.  */
                if (rn == 15) {
9708
                    addr = tcg_temp_new_i32();
P
pbrook 已提交
9709
                    tcg_gen_movi_i32(addr, s->pc);
P
pbrook 已提交
9710
                } else {
P
pbrook 已提交
9711
                    addr = load_reg(s, rn);
P
pbrook 已提交
9712
                }
P
pbrook 已提交
9713
                tmp = load_reg(s, rm);
P
pbrook 已提交
9714
                tcg_gen_add_i32(addr, addr, tmp);
P
pbrook 已提交
9715 9716
                if (insn & (1 << 4)) {
                    /* tbh */
P
pbrook 已提交
9717
                    tcg_gen_add_i32(addr, addr, tmp);
9718
                    tcg_temp_free_i32(tmp);
9719
                    tmp = tcg_temp_new_i32();
9720
                    gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
9721
                } else { /* tbb */
9722
                    tcg_temp_free_i32(tmp);
9723
                    tmp = tcg_temp_new_i32();
9724
                    gen_aa32_ld8u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
9725
                }
9726
                tcg_temp_free_i32(addr);
P
pbrook 已提交
9727 9728 9729
                tcg_gen_shli_i32(tmp, tmp, 1);
                tcg_gen_addi_i32(tmp, tmp, s->pc);
                store_reg(s, 15, tmp);
P
pbrook 已提交
9730
            } else {
9731
                int op2 = (insn >> 6) & 0x3;
P
pbrook 已提交
9732
                op = (insn >> 4) & 0x3;
9733 9734
                switch (op2) {
                case 0:
P
Paul Brook 已提交
9735
                    goto illegal_op;
9736 9737 9738 9739 9740 9741 9742 9743 9744 9745 9746 9747 9748 9749 9750 9751 9752
                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 已提交
9753
                }
9754
                addr = tcg_temp_local_new_i32();
9755
                load_reg_var(s, addr, rn);
9756 9757 9758 9759 9760
                if (!(op2 & 1)) {
                    if (insn & (1 << 20)) {
                        tmp = tcg_temp_new_i32();
                        switch (op) {
                        case 0: /* ldab */
9761 9762
                            gen_aa32_ld8u_iss(s, tmp, addr, get_mem_index(s),
                                              rs | ISSIsAcqRel);
9763 9764
                            break;
                        case 1: /* ldah */
9765 9766
                            gen_aa32_ld16u_iss(s, tmp, addr, get_mem_index(s),
                                               rs | ISSIsAcqRel);
9767 9768
                            break;
                        case 2: /* lda */
9769 9770
                            gen_aa32_ld32u_iss(s, tmp, addr, get_mem_index(s),
                                               rs | ISSIsAcqRel);
9771 9772 9773 9774 9775 9776 9777 9778 9779
                            break;
                        default:
                            abort();
                        }
                        store_reg(s, rs, tmp);
                    } else {
                        tmp = load_reg(s, rs);
                        switch (op) {
                        case 0: /* stlb */
9780 9781
                            gen_aa32_st8_iss(s, tmp, addr, get_mem_index(s),
                                             rs | ISSIsAcqRel);
9782 9783
                            break;
                        case 1: /* stlh */
9784 9785
                            gen_aa32_st16_iss(s, tmp, addr, get_mem_index(s),
                                              rs | ISSIsAcqRel);
9786 9787
                            break;
                        case 2: /* stl */
9788 9789
                            gen_aa32_st32_iss(s, tmp, addr, get_mem_index(s),
                                              rs | ISSIsAcqRel);
9790 9791 9792 9793 9794 9795 9796
                            break;
                        default:
                            abort();
                        }
                        tcg_temp_free_i32(tmp);
                    }
                } else if (insn & (1 << 20)) {
P
Paul Brook 已提交
9797
                    gen_load_exclusive(s, rs, rd, addr, op);
P
pbrook 已提交
9798
                } else {
P
Paul Brook 已提交
9799
                    gen_store_exclusive(s, rm, rs, rd, addr, op);
P
pbrook 已提交
9800
                }
9801
                tcg_temp_free_i32(addr);
P
pbrook 已提交
9802 9803 9804 9805
            }
        } else {
            /* Load/store multiple, RFE, SRS.  */
            if (((insn >> 23) & 1) == ((insn >> 24) & 1)) {
9806
                /* RFE, SRS: not available in user mode or on M profile */
9807
                if (IS_USER(s) || arm_dc_feature(s, ARM_FEATURE_M)) {
P
pbrook 已提交
9808
                    goto illegal_op;
9809
                }
P
pbrook 已提交
9810 9811
                if (insn & (1 << 20)) {
                    /* rfe */
P
pbrook 已提交
9812 9813 9814 9815
                    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.  */
9816
                    tmp = tcg_temp_new_i32();
9817
                    gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
9818
                    tcg_gen_addi_i32(addr, addr, 4);
9819
                    tmp2 = tcg_temp_new_i32();
9820
                    gen_aa32_ld32u(s, tmp2, addr, get_mem_index(s));
P
pbrook 已提交
9821 9822
                    if (insn & (1 << 21)) {
                        /* Base writeback.  */
P
pbrook 已提交
9823 9824 9825 9826 9827 9828 9829
                        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 {
9830
                        tcg_temp_free_i32(addr);
P
pbrook 已提交
9831
                    }
P
pbrook 已提交
9832
                    gen_rfe(s, tmp, tmp2);
P
pbrook 已提交
9833 9834
                } else {
                    /* srs */
9835 9836
                    gen_srs(s, (insn & 0x1f), (insn & (1 << 24)) ? 1 : 2,
                            insn & (1 << 21));
P
pbrook 已提交
9837 9838
                }
            } else {
9839
                int i, loaded_base = 0;
9840
                TCGv_i32 loaded_var;
P
pbrook 已提交
9841
                /* Load/store multiple.  */
P
pbrook 已提交
9842
                addr = load_reg(s, rn);
P
pbrook 已提交
9843 9844 9845 9846 9847 9848
                offset = 0;
                for (i = 0; i < 16; i++) {
                    if (insn & (1 << i))
                        offset += 4;
                }
                if (insn & (1 << 24)) {
P
pbrook 已提交
9849
                    tcg_gen_addi_i32(addr, addr, -offset);
P
pbrook 已提交
9850 9851
                }

9852
                TCGV_UNUSED_I32(loaded_var);
P
pbrook 已提交
9853 9854 9855 9856 9857
                for (i = 0; i < 16; i++) {
                    if ((insn & (1 << i)) == 0)
                        continue;
                    if (insn & (1 << 20)) {
                        /* Load.  */
9858
                        tmp = tcg_temp_new_i32();
9859
                        gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
9860
                        if (i == 15) {
P
pbrook 已提交
9861
                            gen_bx(s, tmp);
9862 9863 9864
                        } else if (i == rn) {
                            loaded_var = tmp;
                            loaded_base = 1;
P
pbrook 已提交
9865
                        } else {
P
pbrook 已提交
9866
                            store_reg(s, i, tmp);
P
pbrook 已提交
9867 9868 9869
                        }
                    } else {
                        /* Store.  */
P
pbrook 已提交
9870
                        tmp = load_reg(s, i);
9871
                        gen_aa32_st32(s, tmp, addr, get_mem_index(s));
9872
                        tcg_temp_free_i32(tmp);
P
pbrook 已提交
9873
                    }
P
pbrook 已提交
9874
                    tcg_gen_addi_i32(addr, addr, 4);
P
pbrook 已提交
9875
                }
9876 9877 9878
                if (loaded_base) {
                    store_reg(s, rn, loaded_var);
                }
P
pbrook 已提交
9879 9880 9881
                if (insn & (1 << 21)) {
                    /* Base register writeback.  */
                    if (insn & (1 << 24)) {
P
pbrook 已提交
9882
                        tcg_gen_addi_i32(addr, addr, -offset);
P
pbrook 已提交
9883 9884 9885 9886
                    }
                    /* Fault if writeback register is in register list.  */
                    if (insn & (1 << rn))
                        goto illegal_op;
P
pbrook 已提交
9887 9888
                    store_reg(s, rn, addr);
                } else {
9889
                    tcg_temp_free_i32(addr);
P
pbrook 已提交
9890 9891 9892 9893
                }
            }
        }
        break;
9894 9895
    case 5:

P
pbrook 已提交
9896
        op = (insn >> 21) & 0xf;
9897
        if (op == 6) {
9898 9899 9900
            if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
                goto illegal_op;
            }
9901 9902 9903 9904 9905 9906 9907 9908 9909 9910 9911 9912 9913 9914 9915 9916 9917 9918 9919
            /* 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);
9920
            tcg_temp_free_i32(tmp2);
9921 9922
            store_reg(s, rd, tmp);
        } else {
9923 9924
            /* Data processing register constant shift.  */
            if (rn == 15) {
9925
                tmp = tcg_temp_new_i32();
9926 9927 9928 9929 9930 9931 9932 9933 9934 9935 9936 9937 9938
                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;
9939
            tcg_temp_free_i32(tmp2);
9940 9941 9942
            if (rd != 15) {
                store_reg(s, rd, tmp);
            } else {
9943
                tcg_temp_free_i32(tmp);
9944
            }
9945
        }
P
pbrook 已提交
9946 9947 9948 9949 9950 9951 9952
        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 已提交
9953 9954
            tmp = load_reg(s, rn);
            tmp2 = load_reg(s, rm);
P
pbrook 已提交
9955 9956 9957
            if ((insn & 0x70) != 0)
                goto illegal_op;
            op = (insn >> 21) & 3;
P
pbrook 已提交
9958 9959 9960 9961
            logic_cc = (insn & (1 << 20)) != 0;
            gen_arm_shift_reg(tmp, op, tmp2, logic_cc);
            if (logic_cc)
                gen_logic_CC(tmp);
9962
            store_reg_bx(s, rd, tmp);
P
pbrook 已提交
9963 9964
            break;
        case 1: /* Sign/zero extend.  */
9965 9966 9967 9968 9969 9970 9971 9972 9973 9974 9975 9976 9977 9978 9979 9980 9981 9982 9983 9984 9985
            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 已提交
9986
            tmp = load_reg(s, rm);
P
pbrook 已提交
9987
            shift = (insn >> 4) & 3;
9988
            /* ??? In many cases it's not necessary to do a
P
pbrook 已提交
9989 9990
               rotate, a shift is sufficient.  */
            if (shift != 0)
9991
                tcg_gen_rotri_i32(tmp, tmp, shift * 8);
P
pbrook 已提交
9992 9993
            op = (insn >> 20) & 7;
            switch (op) {
P
pbrook 已提交
9994 9995 9996 9997 9998 9999
            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;
10000 10001
            default:
                g_assert_not_reached();
P
pbrook 已提交
10002 10003
            }
            if (rn != 15) {
P
pbrook 已提交
10004
                tmp2 = load_reg(s, rn);
P
pbrook 已提交
10005
                if ((op >> 1) == 1) {
P
pbrook 已提交
10006
                    gen_add16(tmp, tmp2);
P
pbrook 已提交
10007
                } else {
P
pbrook 已提交
10008
                    tcg_gen_add_i32(tmp, tmp, tmp2);
10009
                    tcg_temp_free_i32(tmp2);
P
pbrook 已提交
10010 10011
                }
            }
P
pbrook 已提交
10012
            store_reg(s, rd, tmp);
P
pbrook 已提交
10013 10014
            break;
        case 2: /* SIMD add/subtract.  */
10015 10016 10017
            if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
                goto illegal_op;
            }
P
pbrook 已提交
10018 10019 10020 10021
            op = (insn >> 20) & 7;
            shift = (insn >> 4) & 7;
            if ((op & 3) == 3 || (shift & 3) == 3)
                goto illegal_op;
P
pbrook 已提交
10022 10023 10024
            tmp = load_reg(s, rn);
            tmp2 = load_reg(s, rm);
            gen_thumb2_parallel_addsub(op, shift, tmp, tmp2);
10025
            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
10026
            store_reg(s, rd, tmp);
P
pbrook 已提交
10027 10028 10029 10030 10031
            break;
        case 3: /* Other data processing.  */
            op = ((insn >> 17) & 0x38) | ((insn >> 4) & 7);
            if (op < 4) {
                /* Saturating add/subtract.  */
10032 10033 10034
                if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
                    goto illegal_op;
                }
P
pbrook 已提交
10035 10036
                tmp = load_reg(s, rn);
                tmp2 = load_reg(s, rm);
P
pbrook 已提交
10037
                if (op & 1)
10038
                    gen_helper_double_saturate(tmp, cpu_env, tmp);
10039
                if (op & 2)
10040
                    gen_helper_sub_saturate(tmp, cpu_env, tmp2, tmp);
P
pbrook 已提交
10041
                else
10042
                    gen_helper_add_saturate(tmp, cpu_env, tmp, tmp2);
10043
                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
10044
            } else {
10045 10046 10047 10048 10049 10050 10051 10052 10053 10054 10055 10056 10057 10058 10059 10060 10061 10062 10063 10064 10065 10066 10067 10068 10069
                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 已提交
10070
                tmp = load_reg(s, rn);
P
pbrook 已提交
10071 10072
                switch (op) {
                case 0x0a: /* rbit */
P
pbrook 已提交
10073
                    gen_helper_rbit(tmp, tmp);
P
pbrook 已提交
10074 10075
                    break;
                case 0x08: /* rev */
A
aurel32 已提交
10076
                    tcg_gen_bswap32_i32(tmp, tmp);
P
pbrook 已提交
10077 10078
                    break;
                case 0x09: /* rev16 */
P
pbrook 已提交
10079
                    gen_rev16(tmp);
P
pbrook 已提交
10080 10081
                    break;
                case 0x0b: /* revsh */
P
pbrook 已提交
10082
                    gen_revsh(tmp);
P
pbrook 已提交
10083 10084
                    break;
                case 0x10: /* sel */
P
pbrook 已提交
10085
                    tmp2 = load_reg(s, rm);
10086
                    tmp3 = tcg_temp_new_i32();
10087
                    tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUARMState, GE));
P
pbrook 已提交
10088
                    gen_helper_sel_flags(tmp, tmp3, tmp, tmp2);
10089 10090
                    tcg_temp_free_i32(tmp3);
                    tcg_temp_free_i32(tmp2);
P
pbrook 已提交
10091 10092
                    break;
                case 0x18: /* clz */
R
Richard Henderson 已提交
10093
                    tcg_gen_clzi_i32(tmp, tmp, 32);
P
pbrook 已提交
10094
                    break;
10095 10096 10097 10098 10099 10100 10101 10102 10103 10104 10105 10106
                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);
10107 10108 10109 10110 10111
                    if (sz == 0) {
                        tcg_gen_andi_i32(tmp2, tmp2, 0xff);
                    } else if (sz == 1) {
                        tcg_gen_andi_i32(tmp2, tmp2, 0xffff);
                    }
10112 10113 10114 10115 10116 10117 10118 10119 10120 10121
                    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 已提交
10122
                default:
10123
                    g_assert_not_reached();
P
pbrook 已提交
10124 10125
                }
            }
P
pbrook 已提交
10126
            store_reg(s, rd, tmp);
P
pbrook 已提交
10127 10128
            break;
        case 4: case 5: /* 32-bit multiply.  Sum of absolute differences.  */
10129 10130 10131 10132 10133 10134 10135 10136 10137 10138 10139 10140 10141 10142
            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 已提交
10143
            op = (insn >> 4) & 0xf;
P
pbrook 已提交
10144 10145
            tmp = load_reg(s, rn);
            tmp2 = load_reg(s, rm);
P
pbrook 已提交
10146 10147
            switch ((insn >> 20) & 7) {
            case 0: /* 32 x 32 -> 32 */
P
pbrook 已提交
10148
                tcg_gen_mul_i32(tmp, tmp, tmp2);
10149
                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
10150
                if (rs != 15) {
P
pbrook 已提交
10151
                    tmp2 = load_reg(s, rs);
P
pbrook 已提交
10152
                    if (op)
P
pbrook 已提交
10153
                        tcg_gen_sub_i32(tmp, tmp2, tmp);
P
pbrook 已提交
10154
                    else
P
pbrook 已提交
10155
                        tcg_gen_add_i32(tmp, tmp, tmp2);
10156
                    tcg_temp_free_i32(tmp2);
P
pbrook 已提交
10157 10158 10159
                }
                break;
            case 1: /* 16 x 16 -> 32 */
P
pbrook 已提交
10160
                gen_mulxy(tmp, tmp2, op & 2, op & 1);
10161
                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
10162
                if (rs != 15) {
P
pbrook 已提交
10163
                    tmp2 = load_reg(s, rs);
10164
                    gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
10165
                    tcg_temp_free_i32(tmp2);
P
pbrook 已提交
10166 10167 10168 10169 10170
                }
                break;
            case 2: /* Dual multiply add.  */
            case 4: /* Dual multiply subtract.  */
                if (op)
P
pbrook 已提交
10171 10172
                    gen_swap_half(tmp2);
                gen_smul_dual(tmp, tmp2);
P
pbrook 已提交
10173
                if (insn & (1 << 22)) {
10174
                    /* This subtraction cannot overflow. */
P
pbrook 已提交
10175
                    tcg_gen_sub_i32(tmp, tmp, tmp2);
P
pbrook 已提交
10176
                } else {
10177 10178 10179 10180
                    /* This addition cannot overflow 32 bits;
                     * however it may overflow considered as a signed
                     * operation, in which case we must set the Q flag.
                     */
10181
                    gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
P
pbrook 已提交
10182
                }
10183
                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
10184 10185
                if (rs != 15)
                  {
P
pbrook 已提交
10186
                    tmp2 = load_reg(s, rs);
10187
                    gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
10188
                    tcg_temp_free_i32(tmp2);
P
pbrook 已提交
10189 10190 10191 10192
                  }
                break;
            case 3: /* 32 * 16 -> 32msb */
                if (op)
P
pbrook 已提交
10193
                    tcg_gen_sari_i32(tmp2, tmp2, 16);
P
pbrook 已提交
10194
                else
P
pbrook 已提交
10195
                    gen_sxth(tmp2);
P
pbrook 已提交
10196 10197
                tmp64 = gen_muls_i64_i32(tmp, tmp2);
                tcg_gen_shri_i64(tmp64, tmp64, 16);
10198
                tmp = tcg_temp_new_i32();
10199
                tcg_gen_extrl_i64_i32(tmp, tmp64);
10200
                tcg_temp_free_i64(tmp64);
P
pbrook 已提交
10201 10202
                if (rs != 15)
                  {
P
pbrook 已提交
10203
                    tmp2 = load_reg(s, rs);
10204
                    gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
10205
                    tcg_temp_free_i32(tmp2);
P
pbrook 已提交
10206 10207
                  }
                break;
10208 10209
            case 5: case 6: /* 32 * 32 -> 32msb (SMMUL, SMMLA, SMMLS) */
                tmp64 = gen_muls_i64_i32(tmp, tmp2);
P
pbrook 已提交
10210
                if (rs != 15) {
10211 10212 10213
                    tmp = load_reg(s, rs);
                    if (insn & (1 << 20)) {
                        tmp64 = gen_addq_msw(tmp64, tmp);
B
bellard 已提交
10214
                    } else {
10215
                        tmp64 = gen_subq_msw(tmp64, tmp);
B
bellard 已提交
10216
                    }
B
bellard 已提交
10217
                }
10218 10219 10220 10221
                if (insn & (1 << 4)) {
                    tcg_gen_addi_i64(tmp64, tmp64, 0x80000000u);
                }
                tcg_gen_shri_i64(tmp64, tmp64, 32);
10222
                tmp = tcg_temp_new_i32();
10223
                tcg_gen_extrl_i64_i32(tmp, tmp64);
10224
                tcg_temp_free_i64(tmp64);
P
pbrook 已提交
10225 10226
                break;
            case 7: /* Unsigned sum of absolute differences.  */
P
pbrook 已提交
10227
                gen_helper_usad8(tmp, tmp, tmp2);
10228
                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
10229
                if (rs != 15) {
P
pbrook 已提交
10230 10231
                    tmp2 = load_reg(s, rs);
                    tcg_gen_add_i32(tmp, tmp, tmp2);
10232
                    tcg_temp_free_i32(tmp2);
10233
                }
P
pbrook 已提交
10234
                break;
B
bellard 已提交
10235
            }
P
pbrook 已提交
10236
            store_reg(s, rd, tmp);
B
bellard 已提交
10237
            break;
P
pbrook 已提交
10238 10239
        case 6: case 7: /* 64-bit multiply, Divide.  */
            op = ((insn >> 4) & 0xf) | ((insn >> 16) & 0x70);
P
pbrook 已提交
10240 10241
            tmp = load_reg(s, rn);
            tmp2 = load_reg(s, rm);
P
pbrook 已提交
10242 10243
            if ((op & 0x50) == 0x10) {
                /* sdiv, udiv */
10244
                if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DIV)) {
P
pbrook 已提交
10245
                    goto illegal_op;
10246
                }
P
pbrook 已提交
10247
                if (op & 0x20)
P
pbrook 已提交
10248
                    gen_helper_udiv(tmp, tmp, tmp2);
B
bellard 已提交
10249
                else
P
pbrook 已提交
10250
                    gen_helper_sdiv(tmp, tmp, tmp2);
10251
                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
10252
                store_reg(s, rd, tmp);
P
pbrook 已提交
10253 10254
            } else if ((op & 0xe) == 0xc) {
                /* Dual multiply accumulate long.  */
10255 10256 10257 10258 10259
                if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
                    tcg_temp_free_i32(tmp);
                    tcg_temp_free_i32(tmp2);
                    goto illegal_op;
                }
P
pbrook 已提交
10260
                if (op & 1)
P
pbrook 已提交
10261 10262
                    gen_swap_half(tmp2);
                gen_smul_dual(tmp, tmp2);
P
pbrook 已提交
10263
                if (op & 0x10) {
P
pbrook 已提交
10264
                    tcg_gen_sub_i32(tmp, tmp, tmp2);
B
bellard 已提交
10265
                } else {
P
pbrook 已提交
10266
                    tcg_gen_add_i32(tmp, tmp, tmp2);
B
bellard 已提交
10267
                }
10268
                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
10269 10270 10271
                /* BUGFIX */
                tmp64 = tcg_temp_new_i64();
                tcg_gen_ext_i32_i64(tmp64, tmp);
10272
                tcg_temp_free_i32(tmp);
P
pbrook 已提交
10273 10274
                gen_addq(s, tmp64, rs, rd);
                gen_storeq_reg(s, rs, rd, tmp64);
10275
                tcg_temp_free_i64(tmp64);
B
bellard 已提交
10276
            } else {
P
pbrook 已提交
10277 10278
                if (op & 0x20) {
                    /* Unsigned 64-bit multiply  */
P
pbrook 已提交
10279
                    tmp64 = gen_mulu_i64_i32(tmp, tmp2);
B
bellard 已提交
10280
                } else {
P
pbrook 已提交
10281 10282
                    if (op & 8) {
                        /* smlalxy */
10283 10284 10285 10286 10287
                        if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
                            tcg_temp_free_i32(tmp2);
                            tcg_temp_free_i32(tmp);
                            goto illegal_op;
                        }
P
pbrook 已提交
10288
                        gen_mulxy(tmp, tmp2, op & 2, op & 1);
10289
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
10290 10291
                        tmp64 = tcg_temp_new_i64();
                        tcg_gen_ext_i32_i64(tmp64, tmp);
10292
                        tcg_temp_free_i32(tmp);
P
pbrook 已提交
10293 10294
                    } else {
                        /* Signed 64-bit multiply  */
P
pbrook 已提交
10295
                        tmp64 = gen_muls_i64_i32(tmp, tmp2);
P
pbrook 已提交
10296
                    }
B
bellard 已提交
10297
                }
P
pbrook 已提交
10298 10299
                if (op & 4) {
                    /* umaal */
10300 10301 10302 10303
                    if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) {
                        tcg_temp_free_i64(tmp64);
                        goto illegal_op;
                    }
P
pbrook 已提交
10304 10305
                    gen_addq_lo(s, tmp64, rs);
                    gen_addq_lo(s, tmp64, rd);
P
pbrook 已提交
10306 10307
                } else if (op & 0x40) {
                    /* 64-bit accumulate.  */
P
pbrook 已提交
10308
                    gen_addq(s, tmp64, rs, rd);
P
pbrook 已提交
10309
                }
P
pbrook 已提交
10310
                gen_storeq_reg(s, rs, rd, tmp64);
10311
                tcg_temp_free_i64(tmp64);
10312
            }
B
bellard 已提交
10313
            break;
P
pbrook 已提交
10314 10315 10316 10317
        }
        break;
    case 6: case 7: case 14: case 15:
        /* Coprocessor.  */
10318 10319 10320 10321 10322 10323 10324 10325
        if (arm_dc_feature(s, ARM_FEATURE_M)) {
            /* We don't currently implement M profile FP support,
             * so this entire space should give a NOCP fault.
             */
            gen_exception_insn(s, 4, EXCP_NOCP, syn_uncategorized(),
                               default_exception_el(s));
            break;
        }
P
pbrook 已提交
10326 10327
        if (((insn >> 24) & 3) == 3) {
            /* Translate into the equivalent ARM encoding.  */
10328
            insn = (insn & 0xe2ffffff) | ((insn & (1 << 28)) >> 4) | (1 << 28);
10329
            if (disas_neon_data_insn(s, insn)) {
P
pbrook 已提交
10330
                goto illegal_op;
10331
            }
10332
        } else if (((insn >> 8) & 0xe) == 10) {
10333
            if (disas_vfp_insn(s, insn)) {
10334 10335
                goto illegal_op;
            }
P
pbrook 已提交
10336 10337 10338
        } else {
            if (insn & (1 << 28))
                goto illegal_op;
10339
            if (disas_coproc_insn(s, insn)) {
P
pbrook 已提交
10340
                goto illegal_op;
10341
            }
P
pbrook 已提交
10342 10343 10344 10345 10346 10347 10348 10349 10350 10351 10352 10353 10354 10355 10356 10357 10358 10359 10360
        }
        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.  */
10361
                    tcg_gen_movi_i32(cpu_R[14], s->pc | 1);
B
bellard 已提交
10362
                }
10363

P
pbrook 已提交
10364
                offset += s->pc;
P
pbrook 已提交
10365 10366
                if (insn & (1 << 12)) {
                    /* b/bl */
P
pbrook 已提交
10367
                    gen_jmp(s, offset);
P
pbrook 已提交
10368 10369
                } else {
                    /* blx */
P
pbrook 已提交
10370
                    offset &= ~(uint32_t)2;
10371
                    /* thumb2 bx, no need to check */
P
pbrook 已提交
10372
                    gen_bx_im(s, offset);
B
bellard 已提交
10373
                }
P
pbrook 已提交
10374 10375 10376 10377 10378 10379
            } else if (((insn >> 23) & 7) == 7) {
                /* Misc control */
                if (insn & (1 << 13))
                    goto illegal_op;

                if (insn & (1 << 26)) {
10380 10381 10382
                    if (arm_dc_feature(s, ARM_FEATURE_M)) {
                        goto illegal_op;
                    }
10383 10384 10385 10386 10387 10388 10389 10390 10391 10392 10393 10394 10395 10396 10397 10398 10399
                    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 已提交
10400
                } else {
P
pbrook 已提交
10401 10402 10403
                    op = (insn >> 20) & 7;
                    switch (op) {
                    case 0: /* msr cpsr.  */
10404
                        if (arm_dc_feature(s, ARM_FEATURE_M)) {
P
pbrook 已提交
10405 10406 10407
                            tmp = load_reg(s, rn);
                            addr = tcg_const_i32(insn & 0xff);
                            gen_helper_v7m_msr(cpu_env, addr, tmp);
10408
                            tcg_temp_free_i32(addr);
10409
                            tcg_temp_free_i32(tmp);
P
pbrook 已提交
10410 10411 10412 10413 10414
                            gen_lookup_tb(s);
                            break;
                        }
                        /* fall through */
                    case 1: /* msr spsr.  */
10415
                        if (arm_dc_feature(s, ARM_FEATURE_M)) {
P
pbrook 已提交
10416
                            goto illegal_op;
10417
                        }
10418 10419 10420 10421 10422 10423 10424 10425 10426 10427 10428 10429

                        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) */
10430 10431
                        tmp = load_reg(s, rn);
                        if (gen_set_psr(s,
10432
                              msr_mask(s, (insn >> 8) & 0xf, op == 1),
10433
                              op == 1, tmp))
P
pbrook 已提交
10434 10435 10436 10437 10438 10439 10440 10441 10442 10443 10444 10445 10446 10447 10448 10449 10450 10451 10452 10453 10454 10455 10456 10457 10458 10459
                            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) {
10460
                            gen_set_psr_im(s, offset, 0, imm);
P
pbrook 已提交
10461 10462 10463
                        }
                        break;
                    case 3: /* Special control operations.  */
P
Paul Brook 已提交
10464
                        ARCH(7);
P
pbrook 已提交
10465 10466 10467
                        op = (insn >> 4) & 0xf;
                        switch (op) {
                        case 2: /* clrex */
P
Paul Brook 已提交
10468
                            gen_clrex(s);
P
pbrook 已提交
10469 10470 10471
                            break;
                        case 4: /* dsb */
                        case 5: /* dmb */
10472
                            tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
P
pbrook 已提交
10473
                            break;
10474 10475 10476 10477 10478 10479 10480 10481
                        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 已提交
10482 10483 10484 10485 10486 10487
                        default:
                            goto illegal_op;
                        }
                        break;
                    case 4: /* bxj */
                        /* Trivial implementation equivalent to bx.  */
P
pbrook 已提交
10488 10489
                        tmp = load_reg(s, rn);
                        gen_bx(s, tmp);
P
pbrook 已提交
10490 10491
                        break;
                    case 5: /* Exception return.  */
10492 10493 10494 10495 10496 10497 10498 10499 10500 10501
                        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;
10502
                    case 6: /* MRS */
10503 10504
                        if (extract32(insn, 5, 1) &&
                            !arm_dc_feature(s, ARM_FEATURE_M)) {
10505 10506 10507 10508 10509 10510 10511 10512 10513
                            /* MRS (banked) */
                            int sysm = extract32(insn, 16, 4) |
                                (extract32(insn, 4, 1) << 4);

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

                        /* mrs cpsr */
10514
                        tmp = tcg_temp_new_i32();
10515
                        if (arm_dc_feature(s, ARM_FEATURE_M)) {
P
pbrook 已提交
10516 10517
                            addr = tcg_const_i32(insn & 0xff);
                            gen_helper_v7m_mrs(tmp, cpu_env, addr);
10518
                            tcg_temp_free_i32(addr);
P
pbrook 已提交
10519
                        } else {
10520
                            gen_helper_cpsr_read(tmp, cpu_env);
P
pbrook 已提交
10521
                        }
P
pbrook 已提交
10522
                        store_reg(s, rd, tmp);
P
pbrook 已提交
10523
                        break;
10524
                    case 7: /* MRS */
10525 10526
                        if (extract32(insn, 5, 1) &&
                            !arm_dc_feature(s, ARM_FEATURE_M)) {
10527 10528 10529 10530 10531 10532 10533 10534 10535
                            /* 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 已提交
10536
                        /* Not accessible in user mode.  */
10537
                        if (IS_USER(s) || arm_dc_feature(s, ARM_FEATURE_M)) {
P
pbrook 已提交
10538
                            goto illegal_op;
10539
                        }
P
pbrook 已提交
10540 10541
                        tmp = load_cpu_field(spsr);
                        store_reg(s, rd, tmp);
P
pbrook 已提交
10542
                        break;
B
bellard 已提交
10543 10544
                    }
                }
P
pbrook 已提交
10545 10546 10547 10548 10549
            } else {
                /* Conditional branch.  */
                op = (insn >> 22) & 0xf;
                /* Generate a conditional jump to next instruction.  */
                s->condlabel = gen_new_label();
10550
                arm_gen_test_cc(op ^ 1, s->condlabel);
P
pbrook 已提交
10551 10552 10553 10554 10555 10556 10557 10558 10559 10560 10561 10562 10563 10564
                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 已提交
10565
                gen_jmp(s, s->pc + offset);
P
pbrook 已提交
10566 10567 10568 10569 10570 10571 10572 10573 10574 10575 10576
            }
        } 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 已提交
10577
                    if (rn == 15) {
10578
                        tmp = tcg_temp_new_i32();
P
pbrook 已提交
10579 10580 10581 10582
                        tcg_gen_movi_i32(tmp, 0);
                    } else {
                        tmp = load_reg(s, rn);
                    }
P
pbrook 已提交
10583 10584 10585 10586 10587
                    switch (op) {
                    case 2: /* Signed bitfield extract.  */
                        imm++;
                        if (shift + imm > 32)
                            goto illegal_op;
10588 10589 10590
                        if (imm < 32) {
                            tcg_gen_sextract_i32(tmp, tmp, shift, imm);
                        }
P
pbrook 已提交
10591 10592 10593 10594 10595
                        break;
                    case 6: /* Unsigned bitfield extract.  */
                        imm++;
                        if (shift + imm > 32)
                            goto illegal_op;
10596 10597 10598
                        if (imm < 32) {
                            tcg_gen_extract_i32(tmp, tmp, shift, imm);
                        }
P
pbrook 已提交
10599 10600 10601 10602 10603 10604
                        break;
                    case 3: /* Bitfield insert/clear.  */
                        if (imm < shift)
                            goto illegal_op;
                        imm = imm + 1 - shift;
                        if (imm != 32) {
P
pbrook 已提交
10605
                            tmp2 = load_reg(s, rd);
10606
                            tcg_gen_deposit_i32(tmp, tmp2, tmp, shift, imm);
10607
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
10608 10609 10610 10611 10612 10613 10614
                        }
                        break;
                    case 7:
                        goto illegal_op;
                    default: /* Saturate.  */
                        if (shift) {
                            if (op & 1)
P
pbrook 已提交
10615
                                tcg_gen_sari_i32(tmp, tmp, shift);
P
pbrook 已提交
10616
                            else
P
pbrook 已提交
10617
                                tcg_gen_shli_i32(tmp, tmp, shift);
P
pbrook 已提交
10618
                        }
P
pbrook 已提交
10619
                        tmp2 = tcg_const_i32(imm);
P
pbrook 已提交
10620 10621
                        if (op & 4) {
                            /* Unsigned.  */
10622 10623 10624 10625 10626 10627
                            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;
                                }
10628
                                gen_helper_usat16(tmp, cpu_env, tmp, tmp2);
10629
                            } else {
10630
                                gen_helper_usat(tmp, cpu_env, tmp, tmp2);
10631
                            }
B
bellard 已提交
10632
                        } else {
P
pbrook 已提交
10633
                            /* Signed.  */
10634 10635 10636 10637 10638 10639
                            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;
                                }
10640
                                gen_helper_ssat16(tmp, cpu_env, tmp, tmp2);
10641
                            } else {
10642
                                gen_helper_ssat(tmp, cpu_env, tmp, tmp2);
10643
                            }
B
bellard 已提交
10644
                        }
10645
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
10646
                        break;
B
bellard 已提交
10647
                    }
P
pbrook 已提交
10648
                    store_reg(s, rd, tmp);
P
pbrook 已提交
10649 10650 10651 10652 10653 10654 10655 10656
                } 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 已提交
10657
                            tmp = load_reg(s, rd);
P
pbrook 已提交
10658
                            tcg_gen_ext16u_i32(tmp, tmp);
P
pbrook 已提交
10659
                            tcg_gen_ori_i32(tmp, tmp, imm << 16);
B
bellard 已提交
10660
                        } else {
P
pbrook 已提交
10661
                            /* movw */
10662
                            tmp = tcg_temp_new_i32();
P
pbrook 已提交
10663
                            tcg_gen_movi_i32(tmp, imm);
B
bellard 已提交
10664 10665
                        }
                    } else {
P
pbrook 已提交
10666 10667
                        /* Add/sub 12-bit immediate.  */
                        if (rn == 15) {
P
pbrook 已提交
10668
                            offset = s->pc & ~(uint32_t)3;
P
pbrook 已提交
10669
                            if (insn & (1 << 23))
P
pbrook 已提交
10670
                                offset -= imm;
P
pbrook 已提交
10671
                            else
P
pbrook 已提交
10672
                                offset += imm;
10673
                            tmp = tcg_temp_new_i32();
P
pbrook 已提交
10674
                            tcg_gen_movi_i32(tmp, offset);
B
bellard 已提交
10675
                        } else {
P
pbrook 已提交
10676
                            tmp = load_reg(s, rn);
P
pbrook 已提交
10677
                            if (insn & (1 << 23))
P
pbrook 已提交
10678
                                tcg_gen_subi_i32(tmp, tmp, imm);
P
pbrook 已提交
10679
                            else
P
pbrook 已提交
10680
                                tcg_gen_addi_i32(tmp, tmp, imm);
B
bellard 已提交
10681
                        }
P
pbrook 已提交
10682
                    }
P
pbrook 已提交
10683
                    store_reg(s, rd, tmp);
P
pbrook 已提交
10684
                }
P
pbrook 已提交
10685 10686 10687 10688 10689 10690 10691 10692 10693 10694 10695 10696 10697 10698 10699 10700 10701 10702 10703 10704 10705 10706 10707 10708 10709 10710
            } 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 已提交
10711
                }
10712
                tmp2 = tcg_temp_new_i32();
10713
                tcg_gen_movi_i32(tmp2, imm);
P
pbrook 已提交
10714
                rn = (insn >> 16) & 0xf;
10715
                if (rn == 15) {
10716
                    tmp = tcg_temp_new_i32();
10717 10718 10719 10720
                    tcg_gen_movi_i32(tmp, 0);
                } else {
                    tmp = load_reg(s, rn);
                }
P
pbrook 已提交
10721 10722
                op = (insn >> 21) & 0xf;
                if (gen_thumb2_data_op(s, op, (insn & (1 << 20)) != 0,
10723
                                       shifter_out, tmp, tmp2))
P
pbrook 已提交
10724
                    goto illegal_op;
10725
                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
10726 10727
                rd = (insn >> 8) & 0xf;
                if (rd != 15) {
10728 10729
                    store_reg(s, rd, tmp);
                } else {
10730
                    tcg_temp_free_i32(tmp);
B
bellard 已提交
10731 10732
                }
            }
P
pbrook 已提交
10733 10734 10735 10736 10737 10738
        }
        break;
    case 12: /* Load/store single data item.  */
        {
        int postinc = 0;
        int writeback = 0;
10739
        int memidx;
10740 10741
        ISSInfo issinfo;

P
pbrook 已提交
10742
        if ((insn & 0x01100000) == 0x01000000) {
10743
            if (disas_neon_ls_insn(s, insn)) {
10744
                goto illegal_op;
10745
            }
P
pbrook 已提交
10746 10747
            break;
        }
10748 10749 10750 10751 10752 10753 10754 10755 10756 10757 10758 10759 10760 10761 10762 10763 10764 10765 10766 10767 10768 10769 10770
        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) {
10771 10772 10773
                    /* UNPREDICTABLE, unallocated hint or
                     * PLD/PLDW/PLI (literal)
                     */
10774 10775 10776
                    return 0;
                }
                if (op1 & 1) {
10777
                    return 0; /* PLD/PLDW/PLI or unallocated hint */
10778 10779
                }
                if ((op2 == 0) || ((op2 & 0x3c) == 0x30)) {
10780
                    return 0; /* PLD/PLDW/PLI or unallocated hint */
10781 10782 10783 10784 10785
                }
                /* UNDEF space, or an UNPREDICTABLE */
                return 1;
            }
        }
10786
        memidx = get_mem_index(s);
P
pbrook 已提交
10787
        if (rn == 15) {
10788
            addr = tcg_temp_new_i32();
P
pbrook 已提交
10789 10790 10791 10792 10793 10794 10795
            /* 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 已提交
10796
            tcg_gen_movi_i32(addr, imm);
P
pbrook 已提交
10797
        } else {
P
pbrook 已提交
10798
            addr = load_reg(s, rn);
P
pbrook 已提交
10799 10800 10801
            if (insn & (1 << 23)) {
                /* Positive offset.  */
                imm = insn & 0xfff;
P
pbrook 已提交
10802
                tcg_gen_addi_i32(addr, addr, imm);
P
pbrook 已提交
10803 10804
            } else {
                imm = insn & 0xff;
10805 10806
                switch ((insn >> 8) & 0xf) {
                case 0x0: /* Shifted Register.  */
P
pbrook 已提交
10807
                    shift = (insn >> 4) & 0xf;
10808 10809
                    if (shift > 3) {
                        tcg_temp_free_i32(addr);
10810
                        goto illegal_op;
10811
                    }
P
pbrook 已提交
10812
                    tmp = load_reg(s, rm);
P
pbrook 已提交
10813
                    if (shift)
P
pbrook 已提交
10814
                        tcg_gen_shli_i32(tmp, tmp, shift);
P
pbrook 已提交
10815
                    tcg_gen_add_i32(addr, addr, tmp);
10816
                    tcg_temp_free_i32(tmp);
P
pbrook 已提交
10817
                    break;
10818
                case 0xc: /* Negative offset.  */
P
pbrook 已提交
10819
                    tcg_gen_addi_i32(addr, addr, -imm);
P
pbrook 已提交
10820
                    break;
10821
                case 0xe: /* User privilege.  */
P
pbrook 已提交
10822
                    tcg_gen_addi_i32(addr, addr, imm);
10823
                    memidx = get_a32_user_mem_index(s);
P
pbrook 已提交
10824
                    break;
10825
                case 0x9: /* Post-decrement.  */
P
pbrook 已提交
10826 10827
                    imm = -imm;
                    /* Fall through.  */
10828
                case 0xb: /* Post-increment.  */
P
pbrook 已提交
10829 10830 10831
                    postinc = 1;
                    writeback = 1;
                    break;
10832
                case 0xd: /* Pre-decrement.  */
P
pbrook 已提交
10833 10834
                    imm = -imm;
                    /* Fall through.  */
10835
                case 0xf: /* Pre-increment.  */
P
pbrook 已提交
10836
                    tcg_gen_addi_i32(addr, addr, imm);
P
pbrook 已提交
10837 10838 10839
                    writeback = 1;
                    break;
                default:
10840
                    tcg_temp_free_i32(addr);
B
bellard 已提交
10841
                    goto illegal_op;
P
pbrook 已提交
10842 10843 10844
                }
            }
        }
10845 10846 10847

        issinfo = writeback ? ISSInvalid : rs;

P
pbrook 已提交
10848 10849
        if (insn & (1 << 20)) {
            /* Load.  */
10850
            tmp = tcg_temp_new_i32();
10851
            switch (op) {
10852
            case 0:
10853
                gen_aa32_ld8u_iss(s, tmp, addr, memidx, issinfo);
10854 10855
                break;
            case 4:
10856
                gen_aa32_ld8s_iss(s, tmp, addr, memidx, issinfo);
10857 10858
                break;
            case 1:
10859
                gen_aa32_ld16u_iss(s, tmp, addr, memidx, issinfo);
10860 10861
                break;
            case 5:
10862
                gen_aa32_ld16s_iss(s, tmp, addr, memidx, issinfo);
10863 10864
                break;
            case 2:
10865
                gen_aa32_ld32u_iss(s, tmp, addr, memidx, issinfo);
10866
                break;
10867
            default:
10868
                tcg_temp_free_i32(tmp);
10869 10870
                tcg_temp_free_i32(addr);
                goto illegal_op;
10871 10872 10873
            }
            if (rs == 15) {
                gen_bx(s, tmp);
P
pbrook 已提交
10874
            } else {
10875
                store_reg(s, rs, tmp);
P
pbrook 已提交
10876 10877 10878
            }
        } else {
            /* Store.  */
P
pbrook 已提交
10879
            tmp = load_reg(s, rs);
P
pbrook 已提交
10880
            switch (op) {
10881
            case 0:
10882
                gen_aa32_st8_iss(s, tmp, addr, memidx, issinfo);
10883 10884
                break;
            case 1:
10885
                gen_aa32_st16_iss(s, tmp, addr, memidx, issinfo);
10886 10887
                break;
            case 2:
10888
                gen_aa32_st32_iss(s, tmp, addr, memidx, issinfo);
10889
                break;
10890
            default:
10891
                tcg_temp_free_i32(tmp);
10892 10893
                tcg_temp_free_i32(addr);
                goto illegal_op;
B
bellard 已提交
10894
            }
10895
            tcg_temp_free_i32(tmp);
B
bellard 已提交
10896
        }
P
pbrook 已提交
10897
        if (postinc)
P
pbrook 已提交
10898 10899 10900 10901
            tcg_gen_addi_i32(addr, addr, imm);
        if (writeback) {
            store_reg(s, rn, addr);
        } else {
10902
            tcg_temp_free_i32(addr);
P
pbrook 已提交
10903
        }
P
pbrook 已提交
10904 10905 10906 10907
        }
        break;
    default:
        goto illegal_op;
B
bellard 已提交
10908
    }
P
pbrook 已提交
10909 10910 10911
    return 0;
illegal_op:
    return 1;
B
bellard 已提交
10912 10913
}

10914
static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
B
bellard 已提交
10915 10916 10917 10918
{
    uint32_t val, insn, op, rm, rn, rd, shift, cond;
    int32_t offset;
    int i;
10919 10920 10921
    TCGv_i32 tmp;
    TCGv_i32 tmp2;
    TCGv_i32 addr;
B
bellard 已提交
10922

P
pbrook 已提交
10923 10924
    if (s->condexec_mask) {
        cond = s->condexec_cond;
10925 10926
        if (cond != 0x0e) {     /* Skip conditional when condition is AL. */
          s->condlabel = gen_new_label();
10927
          arm_gen_test_cc(cond ^ 1, s->condlabel);
10928 10929
          s->condjmp = 1;
        }
P
pbrook 已提交
10930 10931
    }

10932
    insn = arm_lduw_code(env, s->pc, s->sctlr_b);
B
bellard 已提交
10933
    s->pc += 2;
B
bellard 已提交
10934

B
bellard 已提交
10935 10936
    switch (insn >> 12) {
    case 0: case 1:
10937

B
bellard 已提交
10938 10939 10940 10941 10942
        rd = insn & 7;
        op = (insn >> 11) & 3;
        if (op == 3) {
            /* add/subtract */
            rn = (insn >> 3) & 7;
10943
            tmp = load_reg(s, rn);
B
bellard 已提交
10944 10945
            if (insn & (1 << 10)) {
                /* immediate */
10946
                tmp2 = tcg_temp_new_i32();
10947
                tcg_gen_movi_i32(tmp2, (insn >> 6) & 7);
B
bellard 已提交
10948 10949 10950
            } else {
                /* reg */
                rm = (insn >> 6) & 7;
10951
                tmp2 = load_reg(s, rm);
B
bellard 已提交
10952
            }
P
pbrook 已提交
10953 10954
            if (insn & (1 << 9)) {
                if (s->condexec_mask)
10955
                    tcg_gen_sub_i32(tmp, tmp, tmp2);
P
pbrook 已提交
10956
                else
10957
                    gen_sub_CC(tmp, tmp, tmp2);
P
pbrook 已提交
10958 10959
            } else {
                if (s->condexec_mask)
10960
                    tcg_gen_add_i32(tmp, tmp, tmp2);
P
pbrook 已提交
10961
                else
10962
                    gen_add_CC(tmp, tmp, tmp2);
P
pbrook 已提交
10963
            }
10964
            tcg_temp_free_i32(tmp2);
10965
            store_reg(s, rd, tmp);
B
bellard 已提交
10966 10967 10968 10969
        } else {
            /* shift immediate */
            rm = (insn >> 3) & 7;
            shift = (insn >> 6) & 0x1f;
P
pbrook 已提交
10970 10971 10972 10973 10974
            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 已提交
10975 10976 10977 10978 10979 10980
        }
        break;
    case 2: case 3:
        /* arithmetic large immediate */
        op = (insn >> 11) & 3;
        rd = (insn >> 8) & 0x7;
10981
        if (op == 0) { /* mov */
10982
            tmp = tcg_temp_new_i32();
10983
            tcg_gen_movi_i32(tmp, insn & 0xff);
P
pbrook 已提交
10984
            if (!s->condexec_mask)
10985 10986 10987 10988
                gen_logic_CC(tmp);
            store_reg(s, rd, tmp);
        } else {
            tmp = load_reg(s, rd);
10989
            tmp2 = tcg_temp_new_i32();
10990 10991 10992
            tcg_gen_movi_i32(tmp2, insn & 0xff);
            switch (op) {
            case 1: /* cmp */
10993
                gen_sub_CC(tmp, tmp, tmp2);
10994 10995
                tcg_temp_free_i32(tmp);
                tcg_temp_free_i32(tmp2);
10996 10997 10998 10999 11000
                break;
            case 2: /* add */
                if (s->condexec_mask)
                    tcg_gen_add_i32(tmp, tmp, tmp2);
                else
11001
                    gen_add_CC(tmp, tmp, tmp2);
11002
                tcg_temp_free_i32(tmp2);
11003 11004 11005 11006 11007 11008
                store_reg(s, rd, tmp);
                break;
            case 3: /* sub */
                if (s->condexec_mask)
                    tcg_gen_sub_i32(tmp, tmp, tmp2);
                else
11009
                    gen_sub_CC(tmp, tmp, tmp2);
11010
                tcg_temp_free_i32(tmp2);
11011 11012 11013
                store_reg(s, rd, tmp);
                break;
            }
B
bellard 已提交
11014 11015 11016 11017 11018
        }
        break;
    case 4:
        if (insn & (1 << 11)) {
            rd = (insn >> 8) & 7;
B
bellard 已提交
11019 11020 11021
            /* load pc-relative.  Bit 1 of PC is ignored.  */
            val = s->pc + 2 + ((insn & 0xff) * 4);
            val &= ~(uint32_t)2;
11022
            addr = tcg_temp_new_i32();
P
pbrook 已提交
11023
            tcg_gen_movi_i32(addr, val);
11024
            tmp = tcg_temp_new_i32();
11025 11026
            gen_aa32_ld32u_iss(s, tmp, addr, get_mem_index(s),
                               rd | ISSIs16Bit);
11027
            tcg_temp_free_i32(addr);
P
pbrook 已提交
11028
            store_reg(s, rd, tmp);
B
bellard 已提交
11029 11030 11031 11032 11033 11034 11035 11036 11037
            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 */
11038 11039 11040
                tmp = load_reg(s, rd);
                tmp2 = load_reg(s, rm);
                tcg_gen_add_i32(tmp, tmp, tmp2);
11041
                tcg_temp_free_i32(tmp2);
11042
                store_reg(s, rd, tmp);
B
bellard 已提交
11043 11044
                break;
            case 1: /* cmp */
11045 11046
                tmp = load_reg(s, rd);
                tmp2 = load_reg(s, rm);
11047
                gen_sub_CC(tmp, tmp, tmp2);
11048 11049
                tcg_temp_free_i32(tmp2);
                tcg_temp_free_i32(tmp);
B
bellard 已提交
11050 11051
                break;
            case 2: /* mov/cpy */
11052 11053
                tmp = load_reg(s, rm);
                store_reg(s, rd, tmp);
B
bellard 已提交
11054 11055
                break;
            case 3:/* branch [and link] exchange thumb register */
P
pbrook 已提交
11056
                tmp = load_reg(s, rm);
B
bellard 已提交
11057
                if (insn & (1 << 7)) {
11058
                    ARCH(5);
B
bellard 已提交
11059
                    val = (uint32_t)s->pc | 1;
11060
                    tmp2 = tcg_temp_new_i32();
P
pbrook 已提交
11061 11062
                    tcg_gen_movi_i32(tmp2, val);
                    store_reg(s, 14, tmp2);
B
bellard 已提交
11063
                }
11064
                /* already thumb, no need to check */
P
pbrook 已提交
11065
                gen_bx(s, tmp);
B
bellard 已提交
11066 11067 11068 11069 11070 11071 11072 11073 11074 11075 11076 11077 11078 11079 11080 11081 11082 11083 11084
                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;
        }

11085
        if (op == 9) { /* neg */
11086
            tmp = tcg_temp_new_i32();
11087 11088 11089 11090
            tcg_gen_movi_i32(tmp, 0);
        } else if (op != 0xf) { /* mvn doesn't read its first operand */
            tmp = load_reg(s, rd);
        } else {
11091
            TCGV_UNUSED_I32(tmp);
11092
        }
B
bellard 已提交
11093

11094
        tmp2 = load_reg(s, rm);
B
bellard 已提交
11095
        switch (op) {
B
bellard 已提交
11096
        case 0x0: /* and */
11097
            tcg_gen_and_i32(tmp, tmp, tmp2);
P
pbrook 已提交
11098
            if (!s->condexec_mask)
11099
                gen_logic_CC(tmp);
B
bellard 已提交
11100 11101
            break;
        case 0x1: /* eor */
11102
            tcg_gen_xor_i32(tmp, tmp, tmp2);
P
pbrook 已提交
11103
            if (!s->condexec_mask)
11104
                gen_logic_CC(tmp);
B
bellard 已提交
11105 11106
            break;
        case 0x2: /* lsl */
P
pbrook 已提交
11107
            if (s->condexec_mask) {
11108
                gen_shl(tmp2, tmp2, tmp);
P
pbrook 已提交
11109
            } else {
11110
                gen_helper_shl_cc(tmp2, cpu_env, tmp2, tmp);
11111
                gen_logic_CC(tmp2);
P
pbrook 已提交
11112
            }
B
bellard 已提交
11113 11114
            break;
        case 0x3: /* lsr */
P
pbrook 已提交
11115
            if (s->condexec_mask) {
11116
                gen_shr(tmp2, tmp2, tmp);
P
pbrook 已提交
11117
            } else {
11118
                gen_helper_shr_cc(tmp2, cpu_env, tmp2, tmp);
11119
                gen_logic_CC(tmp2);
P
pbrook 已提交
11120
            }
B
bellard 已提交
11121 11122
            break;
        case 0x4: /* asr */
P
pbrook 已提交
11123
            if (s->condexec_mask) {
11124
                gen_sar(tmp2, tmp2, tmp);
P
pbrook 已提交
11125
            } else {
11126
                gen_helper_sar_cc(tmp2, cpu_env, tmp2, tmp);
11127
                gen_logic_CC(tmp2);
P
pbrook 已提交
11128
            }
B
bellard 已提交
11129 11130
            break;
        case 0x5: /* adc */
11131
            if (s->condexec_mask) {
11132
                gen_adc(tmp, tmp2);
11133 11134 11135
            } else {
                gen_adc_CC(tmp, tmp, tmp2);
            }
B
bellard 已提交
11136 11137
            break;
        case 0x6: /* sbc */
11138
            if (s->condexec_mask) {
11139
                gen_sub_carry(tmp, tmp, tmp2);
11140 11141 11142
            } else {
                gen_sbc_CC(tmp, tmp, tmp2);
            }
B
bellard 已提交
11143 11144
            break;
        case 0x7: /* ror */
P
pbrook 已提交
11145
            if (s->condexec_mask) {
11146 11147
                tcg_gen_andi_i32(tmp, tmp, 0x1f);
                tcg_gen_rotr_i32(tmp2, tmp2, tmp);
P
pbrook 已提交
11148
            } else {
11149
                gen_helper_ror_cc(tmp2, cpu_env, tmp2, tmp);
11150
                gen_logic_CC(tmp2);
P
pbrook 已提交
11151
            }
B
bellard 已提交
11152 11153
            break;
        case 0x8: /* tst */
11154 11155
            tcg_gen_and_i32(tmp, tmp, tmp2);
            gen_logic_CC(tmp);
B
bellard 已提交
11156
            rd = 16;
B
bellard 已提交
11157
            break;
B
bellard 已提交
11158
        case 0x9: /* neg */
P
pbrook 已提交
11159
            if (s->condexec_mask)
11160
                tcg_gen_neg_i32(tmp, tmp2);
P
pbrook 已提交
11161
            else
11162
                gen_sub_CC(tmp, tmp, tmp2);
B
bellard 已提交
11163 11164
            break;
        case 0xa: /* cmp */
11165
            gen_sub_CC(tmp, tmp, tmp2);
B
bellard 已提交
11166 11167 11168
            rd = 16;
            break;
        case 0xb: /* cmn */
11169
            gen_add_CC(tmp, tmp, tmp2);
B
bellard 已提交
11170 11171 11172
            rd = 16;
            break;
        case 0xc: /* orr */
11173
            tcg_gen_or_i32(tmp, tmp, tmp2);
P
pbrook 已提交
11174
            if (!s->condexec_mask)
11175
                gen_logic_CC(tmp);
B
bellard 已提交
11176 11177
            break;
        case 0xd: /* mul */
11178
            tcg_gen_mul_i32(tmp, tmp, tmp2);
P
pbrook 已提交
11179
            if (!s->condexec_mask)
11180
                gen_logic_CC(tmp);
B
bellard 已提交
11181 11182
            break;
        case 0xe: /* bic */
11183
            tcg_gen_andc_i32(tmp, tmp, tmp2);
P
pbrook 已提交
11184
            if (!s->condexec_mask)
11185
                gen_logic_CC(tmp);
B
bellard 已提交
11186 11187
            break;
        case 0xf: /* mvn */
11188
            tcg_gen_not_i32(tmp2, tmp2);
P
pbrook 已提交
11189
            if (!s->condexec_mask)
11190
                gen_logic_CC(tmp2);
B
bellard 已提交
11191
            val = 1;
B
bellard 已提交
11192
            rm = rd;
B
bellard 已提交
11193 11194 11195
            break;
        }
        if (rd != 16) {
11196 11197 11198
            if (val) {
                store_reg(s, rm, tmp2);
                if (op != 0xf)
11199
                    tcg_temp_free_i32(tmp);
11200 11201
            } else {
                store_reg(s, rd, tmp);
11202
                tcg_temp_free_i32(tmp2);
11203 11204
            }
        } else {
11205 11206
            tcg_temp_free_i32(tmp);
            tcg_temp_free_i32(tmp2);
B
bellard 已提交
11207 11208 11209 11210 11211 11212 11213 11214 11215
        }
        break;

    case 5:
        /* load/store register offset.  */
        rd = insn & 7;
        rn = (insn >> 3) & 7;
        rm = (insn >> 6) & 7;
        op = (insn >> 9) & 7;
P
pbrook 已提交
11216
        addr = load_reg(s, rn);
P
pbrook 已提交
11217
        tmp = load_reg(s, rm);
P
pbrook 已提交
11218
        tcg_gen_add_i32(addr, addr, tmp);
11219
        tcg_temp_free_i32(tmp);
B
bellard 已提交
11220

11221
        if (op < 3) { /* store */
P
pbrook 已提交
11222
            tmp = load_reg(s, rd);
11223 11224 11225
        } else {
            tmp = tcg_temp_new_i32();
        }
B
bellard 已提交
11226 11227 11228

        switch (op) {
        case 0: /* str */
11229
            gen_aa32_st32_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
B
bellard 已提交
11230 11231
            break;
        case 1: /* strh */
11232
            gen_aa32_st16_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
B
bellard 已提交
11233 11234
            break;
        case 2: /* strb */
11235
            gen_aa32_st8_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
B
bellard 已提交
11236 11237
            break;
        case 3: /* ldrsb */
11238
            gen_aa32_ld8s_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
B
bellard 已提交
11239 11240
            break;
        case 4: /* ldr */
11241
            gen_aa32_ld32u_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
B
bellard 已提交
11242 11243
            break;
        case 5: /* ldrh */
11244
            gen_aa32_ld16u_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
B
bellard 已提交
11245 11246
            break;
        case 6: /* ldrb */
11247
            gen_aa32_ld8u_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
B
bellard 已提交
11248 11249
            break;
        case 7: /* ldrsh */
11250
            gen_aa32_ld16s_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
B
bellard 已提交
11251 11252
            break;
        }
11253
        if (op >= 3) { /* load */
P
pbrook 已提交
11254
            store_reg(s, rd, tmp);
11255 11256 11257
        } else {
            tcg_temp_free_i32(tmp);
        }
11258
        tcg_temp_free_i32(addr);
B
bellard 已提交
11259 11260 11261 11262 11263 11264
        break;

    case 6:
        /* load/store word immediate offset */
        rd = insn & 7;
        rn = (insn >> 3) & 7;
P
pbrook 已提交
11265
        addr = load_reg(s, rn);
B
bellard 已提交
11266
        val = (insn >> 4) & 0x7c;
P
pbrook 已提交
11267
        tcg_gen_addi_i32(addr, addr, val);
B
bellard 已提交
11268 11269 11270

        if (insn & (1 << 11)) {
            /* load */
11271
            tmp = tcg_temp_new_i32();
11272
            gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
11273
            store_reg(s, rd, tmp);
B
bellard 已提交
11274 11275
        } else {
            /* store */
P
pbrook 已提交
11276
            tmp = load_reg(s, rd);
11277
            gen_aa32_st32(s, tmp, addr, get_mem_index(s));
11278
            tcg_temp_free_i32(tmp);
B
bellard 已提交
11279
        }
11280
        tcg_temp_free_i32(addr);
B
bellard 已提交
11281 11282 11283 11284 11285 11286
        break;

    case 7:
        /* load/store byte immediate offset */
        rd = insn & 7;
        rn = (insn >> 3) & 7;
P
pbrook 已提交
11287
        addr = load_reg(s, rn);
B
bellard 已提交
11288
        val = (insn >> 6) & 0x1f;
P
pbrook 已提交
11289
        tcg_gen_addi_i32(addr, addr, val);
B
bellard 已提交
11290 11291 11292

        if (insn & (1 << 11)) {
            /* load */
11293
            tmp = tcg_temp_new_i32();
11294
            gen_aa32_ld8u_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
P
pbrook 已提交
11295
            store_reg(s, rd, tmp);
B
bellard 已提交
11296 11297
        } else {
            /* store */
P
pbrook 已提交
11298
            tmp = load_reg(s, rd);
11299
            gen_aa32_st8_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
11300
            tcg_temp_free_i32(tmp);
B
bellard 已提交
11301
        }
11302
        tcg_temp_free_i32(addr);
B
bellard 已提交
11303 11304 11305 11306 11307 11308
        break;

    case 8:
        /* load/store halfword immediate offset */
        rd = insn & 7;
        rn = (insn >> 3) & 7;
P
pbrook 已提交
11309
        addr = load_reg(s, rn);
B
bellard 已提交
11310
        val = (insn >> 5) & 0x3e;
P
pbrook 已提交
11311
        tcg_gen_addi_i32(addr, addr, val);
B
bellard 已提交
11312 11313 11314

        if (insn & (1 << 11)) {
            /* load */
11315
            tmp = tcg_temp_new_i32();
11316
            gen_aa32_ld16u_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
P
pbrook 已提交
11317
            store_reg(s, rd, tmp);
B
bellard 已提交
11318 11319
        } else {
            /* store */
P
pbrook 已提交
11320
            tmp = load_reg(s, rd);
11321
            gen_aa32_st16_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
11322
            tcg_temp_free_i32(tmp);
B
bellard 已提交
11323
        }
11324
        tcg_temp_free_i32(addr);
B
bellard 已提交
11325 11326 11327 11328 11329
        break;

    case 9:
        /* load/store from stack */
        rd = (insn >> 8) & 7;
P
pbrook 已提交
11330
        addr = load_reg(s, 13);
B
bellard 已提交
11331
        val = (insn & 0xff) * 4;
P
pbrook 已提交
11332
        tcg_gen_addi_i32(addr, addr, val);
B
bellard 已提交
11333 11334 11335

        if (insn & (1 << 11)) {
            /* load */
11336
            tmp = tcg_temp_new_i32();
11337
            gen_aa32_ld32u_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
P
pbrook 已提交
11338
            store_reg(s, rd, tmp);
B
bellard 已提交
11339 11340
        } else {
            /* store */
P
pbrook 已提交
11341
            tmp = load_reg(s, rd);
11342
            gen_aa32_st32_iss(s, tmp, addr, get_mem_index(s), rd | ISSIs16Bit);
11343
            tcg_temp_free_i32(tmp);
B
bellard 已提交
11344
        }
11345
        tcg_temp_free_i32(addr);
B
bellard 已提交
11346 11347 11348 11349 11350
        break;

    case 10:
        /* add to high reg */
        rd = (insn >> 8) & 7;
B
bellard 已提交
11351 11352
        if (insn & (1 << 11)) {
            /* SP */
P
pbrook 已提交
11353
            tmp = load_reg(s, 13);
B
bellard 已提交
11354 11355
        } else {
            /* PC. bit 1 is ignored.  */
11356
            tmp = tcg_temp_new_i32();
P
pbrook 已提交
11357
            tcg_gen_movi_i32(tmp, (s->pc + 2) & ~(uint32_t)2);
B
bellard 已提交
11358
        }
B
bellard 已提交
11359
        val = (insn & 0xff) * 4;
P
pbrook 已提交
11360 11361
        tcg_gen_addi_i32(tmp, tmp, val);
        store_reg(s, rd, tmp);
B
bellard 已提交
11362 11363 11364 11365 11366 11367 11368 11369
        break;

    case 11:
        /* misc */
        op = (insn >> 8) & 0xf;
        switch (op) {
        case 0:
            /* adjust stack pointer */
P
pbrook 已提交
11370
            tmp = load_reg(s, 13);
B
bellard 已提交
11371 11372
            val = (insn & 0x7f) * 4;
            if (insn & (1 << 7))
B
balrog 已提交
11373
                val = -(int32_t)val;
P
pbrook 已提交
11374 11375
            tcg_gen_addi_i32(tmp, tmp, val);
            store_reg(s, 13, tmp);
B
bellard 已提交
11376 11377
            break;

P
pbrook 已提交
11378 11379 11380 11381
        case 2: /* sign/zero extend.  */
            ARCH(6);
            rd = insn & 7;
            rm = (insn >> 3) & 7;
P
pbrook 已提交
11382
            tmp = load_reg(s, rm);
P
pbrook 已提交
11383
            switch ((insn >> 6) & 3) {
P
pbrook 已提交
11384 11385 11386 11387
            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 已提交
11388
            }
P
pbrook 已提交
11389
            store_reg(s, rd, tmp);
P
pbrook 已提交
11390
            break;
B
bellard 已提交
11391 11392
        case 4: case 5: case 0xc: case 0xd:
            /* push/pop */
P
pbrook 已提交
11393
            addr = load_reg(s, 13);
B
bellard 已提交
11394 11395
            if (insn & (1 << 8))
                offset = 4;
B
bellard 已提交
11396
            else
B
bellard 已提交
11397 11398 11399 11400 11401 11402
                offset = 0;
            for (i = 0; i < 8; i++) {
                if (insn & (1 << i))
                    offset += 4;
            }
            if ((insn & (1 << 11)) == 0) {
P
pbrook 已提交
11403
                tcg_gen_addi_i32(addr, addr, -offset);
B
bellard 已提交
11404
            }
B
bellard 已提交
11405 11406 11407 11408
            for (i = 0; i < 8; i++) {
                if (insn & (1 << i)) {
                    if (insn & (1 << 11)) {
                        /* pop */
11409
                        tmp = tcg_temp_new_i32();
11410
                        gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
P
pbrook 已提交
11411
                        store_reg(s, i, tmp);
B
bellard 已提交
11412 11413
                    } else {
                        /* push */
P
pbrook 已提交
11414
                        tmp = load_reg(s, i);
11415
                        gen_aa32_st32(s, tmp, addr, get_mem_index(s));
11416
                        tcg_temp_free_i32(tmp);
B
bellard 已提交
11417
                    }
B
bellard 已提交
11418
                    /* advance to the next address.  */
P
pbrook 已提交
11419
                    tcg_gen_addi_i32(addr, addr, 4);
B
bellard 已提交
11420 11421
                }
            }
11422
            TCGV_UNUSED_I32(tmp);
B
bellard 已提交
11423 11424 11425
            if (insn & (1 << 8)) {
                if (insn & (1 << 11)) {
                    /* pop pc */
11426
                    tmp = tcg_temp_new_i32();
11427
                    gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
B
bellard 已提交
11428 11429 11430 11431
                    /* don't set the pc until the rest of the instruction
                       has completed */
                } else {
                    /* push lr */
P
pbrook 已提交
11432
                    tmp = load_reg(s, 14);
11433
                    gen_aa32_st32(s, tmp, addr, get_mem_index(s));
11434
                    tcg_temp_free_i32(tmp);
B
bellard 已提交
11435
                }
P
pbrook 已提交
11436
                tcg_gen_addi_i32(addr, addr, 4);
B
bellard 已提交
11437
            }
B
bellard 已提交
11438
            if ((insn & (1 << 11)) == 0) {
P
pbrook 已提交
11439
                tcg_gen_addi_i32(addr, addr, -offset);
B
bellard 已提交
11440
            }
B
bellard 已提交
11441
            /* write back the new stack pointer */
P
pbrook 已提交
11442
            store_reg(s, 13, addr);
B
bellard 已提交
11443
            /* set the new PC value */
11444
            if ((insn & 0x0900) == 0x0900) {
11445
                store_reg_from_load(s, 15, tmp);
11446
            }
B
bellard 已提交
11447 11448
            break;

P
pbrook 已提交
11449 11450
        case 1: case 3: case 9: case 11: /* czb */
            rm = insn & 7;
P
pbrook 已提交
11451
            tmp = load_reg(s, rm);
P
pbrook 已提交
11452 11453 11454
            s->condlabel = gen_new_label();
            s->condjmp = 1;
            if (insn & (1 << 11))
P
pbrook 已提交
11455
                tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, s->condlabel);
P
pbrook 已提交
11456
            else
P
pbrook 已提交
11457
                tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, s->condlabel);
11458
            tcg_temp_free_i32(tmp);
P
pbrook 已提交
11459 11460 11461 11462 11463 11464 11465 11466 11467 11468 11469 11470 11471 11472 11473 11474 11475
            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 已提交
11476
        case 0xe: /* bkpt */
11477 11478
        {
            int imm8 = extract32(insn, 0, 8);
11479
            ARCH(5);
11480 11481
            gen_exception_insn(s, 2, EXCP_BKPT, syn_aa32_bkpt(imm8, true),
                               default_exception_el(s));
P
pbrook 已提交
11482
            break;
11483
        }
P
pbrook 已提交
11484

11485 11486 11487 11488 11489 11490 11491 11492 11493 11494 11495 11496 11497
        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 已提交
11498 11499 11500
            ARCH(6);
            rn = (insn >> 3) & 0x7;
            rd = insn & 0x7;
P
pbrook 已提交
11501
            tmp = load_reg(s, rn);
11502
            switch (op1) {
A
aurel32 已提交
11503
            case 0: tcg_gen_bswap32_i32(tmp, tmp); break;
P
pbrook 已提交
11504 11505
            case 1: gen_rev16(tmp); break;
            case 3: gen_revsh(tmp); break;
11506 11507
            default:
                g_assert_not_reached();
P
pbrook 已提交
11508
            }
P
pbrook 已提交
11509
            store_reg(s, rd, tmp);
P
pbrook 已提交
11510
            break;
11511
        }
P
pbrook 已提交
11512

11513 11514 11515 11516 11517
        case 6:
            switch ((insn >> 5) & 7) {
            case 2:
                /* setend */
                ARCH(6);
P
Paolo Bonzini 已提交
11518 11519 11520
                if (((insn >> 3) & 1) != !!(s->be_data == MO_BE)) {
                    gen_helper_setend(cpu_env);
                    s->is_jmp = DISAS_UPDATE;
11521
                }
P
pbrook 已提交
11522
                break;
11523 11524 11525 11526 11527
            case 3:
                /* cps */
                ARCH(6);
                if (IS_USER(s)) {
                    break;
P
pbrook 已提交
11528
                }
11529
                if (arm_dc_feature(s, ARM_FEATURE_M)) {
11530 11531 11532 11533 11534 11535 11536 11537 11538 11539 11540 11541 11542 11543 11544 11545 11546 11547 11548 11549 11550 11551
                    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 已提交
11552
                }
11553 11554 11555
                break;
            default:
                goto undef;
P
pbrook 已提交
11556 11557 11558
            }
            break;

B
bellard 已提交
11559 11560 11561 11562 11563 11564
        default:
            goto undef;
        }
        break;

    case 12:
11565
    {
B
bellard 已提交
11566
        /* load/store multiple */
11567 11568
        TCGv_i32 loaded_var;
        TCGV_UNUSED_I32(loaded_var);
B
bellard 已提交
11569
        rn = (insn >> 8) & 0x7;
P
pbrook 已提交
11570
        addr = load_reg(s, rn);
B
bellard 已提交
11571 11572 11573 11574
        for (i = 0; i < 8; i++) {
            if (insn & (1 << i)) {
                if (insn & (1 << 11)) {
                    /* load */
11575
                    tmp = tcg_temp_new_i32();
11576
                    gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
11577 11578 11579 11580 11581
                    if (i == rn) {
                        loaded_var = tmp;
                    } else {
                        store_reg(s, i, tmp);
                    }
B
bellard 已提交
11582 11583
                } else {
                    /* store */
P
pbrook 已提交
11584
                    tmp = load_reg(s, i);
11585
                    gen_aa32_st32(s, tmp, addr, get_mem_index(s));
11586
                    tcg_temp_free_i32(tmp);
B
bellard 已提交
11587
                }
B
bellard 已提交
11588
                /* advance to the next address */
P
pbrook 已提交
11589
                tcg_gen_addi_i32(addr, addr, 4);
B
bellard 已提交
11590 11591
            }
        }
P
pbrook 已提交
11592
        if ((insn & (1 << rn)) == 0) {
11593
            /* base reg not in list: base register writeback */
P
pbrook 已提交
11594 11595
            store_reg(s, rn, addr);
        } else {
11596 11597 11598 11599
            /* base reg in list: if load, complete it now */
            if (insn & (1 << 11)) {
                store_reg(s, rn, loaded_var);
            }
11600
            tcg_temp_free_i32(addr);
P
pbrook 已提交
11601
        }
B
bellard 已提交
11602
        break;
11603
    }
B
bellard 已提交
11604 11605 11606 11607 11608 11609 11610 11611
    case 13:
        /* conditional branch or swi */
        cond = (insn >> 8) & 0xf;
        if (cond == 0xe)
            goto undef;

        if (cond == 0xf) {
            /* swi */
11612
            gen_set_pc_im(s, s->pc);
11613
            s->svc_imm = extract32(insn, 0, 8);
P
pbrook 已提交
11614
            s->is_jmp = DISAS_SWI;
B
bellard 已提交
11615 11616 11617
            break;
        }
        /* generate a conditional jump to next instruction */
11618
        s->condlabel = gen_new_label();
11619
        arm_gen_test_cc(cond ^ 1, s->condlabel);
11620
        s->condjmp = 1;
B
bellard 已提交
11621 11622

        /* jump to the offset */
B
bellard 已提交
11623
        val = (uint32_t)s->pc + 2;
B
bellard 已提交
11624
        offset = ((int32_t)insn << 24) >> 24;
B
bellard 已提交
11625
        val += offset << 1;
B
bellard 已提交
11626
        gen_jmp(s, val);
B
bellard 已提交
11627 11628 11629
        break;

    case 14:
P
pbrook 已提交
11630
        if (insn & (1 << 11)) {
P
pbrook 已提交
11631 11632
            if (disas_thumb2_insn(env, s, insn))
              goto undef32;
P
pbrook 已提交
11633 11634
            break;
        }
P
pbrook 已提交
11635
        /* unconditional branch */
B
bellard 已提交
11636 11637 11638
        val = (uint32_t)s->pc;
        offset = ((int32_t)insn << 21) >> 21;
        val += (offset << 1) + 2;
B
bellard 已提交
11639
        gen_jmp(s, val);
B
bellard 已提交
11640 11641 11642
        break;

    case 15:
P
pbrook 已提交
11643
        if (disas_thumb2_insn(env, s, insn))
B
balrog 已提交
11644
            goto undef32;
P
pbrook 已提交
11645
        break;
B
bellard 已提交
11646 11647
    }
    return;
P
pbrook 已提交
11648
undef32:
11649 11650
    gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized(),
                       default_exception_el(s));
P
pbrook 已提交
11651 11652
    return;
illegal_op:
B
bellard 已提交
11653
undef:
11654 11655
    gen_exception_insn(s, 2, EXCP_UDEF, syn_uncategorized(),
                       default_exception_el(s));
B
bellard 已提交
11656 11657
}

11658 11659 11660 11661 11662 11663 11664 11665 11666 11667 11668 11669 11670
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 */
11671
    insn = arm_lduw_code(env, s->pc, s->sctlr_b);
11672 11673 11674 11675 11676 11677 11678 11679 11680 11681 11682 11683 11684 11685 11686

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

11687
/* generate intermediate code for basic block 'tb'.  */
11688
void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
B
bellard 已提交
11689
{
11690
    ARMCPU *cpu = arm_env_get_cpu(env);
11691
    CPUState *cs = CPU(cpu);
B
bellard 已提交
11692
    DisasContext dc1, *dc = &dc1;
B
bellard 已提交
11693
    target_ulong pc_start;
11694
    target_ulong next_page_start;
P
pbrook 已提交
11695 11696
    int num_insns;
    int max_insns;
11697
    bool end_of_page;
11698

B
bellard 已提交
11699
    /* generate intermediate code */
11700 11701 11702 11703 11704

    /* 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)) {
11705
        gen_intermediate_code_a64(cpu, tb);
11706 11707 11708
        return;
    }

B
bellard 已提交
11709
    pc_start = tb->pc;
11710

B
bellard 已提交
11711 11712 11713 11714
    dc->tb = tb;

    dc->is_jmp = DISAS_NEXT;
    dc->pc = pc_start;
11715
    dc->singlestep_enabled = cs->singlestep_enabled;
11716
    dc->condjmp = 0;
11717

11718
    dc->aarch64 = 0;
11719 11720 11721 11722 11723
    /* 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);
11724
    dc->thumb = ARM_TBFLAG_THUMB(tb->flags);
11725
    dc->sctlr_b = ARM_TBFLAG_SCTLR_B(tb->flags);
11726
    dc->be_data = ARM_TBFLAG_BE_DATA(tb->flags) ? MO_BE : MO_LE;
11727 11728
    dc->condexec_mask = (ARM_TBFLAG_CONDEXEC(tb->flags) & 0xf) << 1;
    dc->condexec_cond = ARM_TBFLAG_CONDEXEC(tb->flags) >> 4;
11729 11730
    dc->mmu_idx = ARM_TBFLAG_MMUIDX(tb->flags);
    dc->current_el = arm_mmu_idx_to_el(dc->mmu_idx);
11731
#if !defined(CONFIG_USER_ONLY)
11732
    dc->user = (dc->current_el == 0);
11733
#endif
11734
    dc->ns = ARM_TBFLAG_NS(tb->flags);
11735
    dc->fp_excp_el = ARM_TBFLAG_FPEXC_EL(tb->flags);
11736 11737 11738
    dc->vfp_enabled = ARM_TBFLAG_VFPEN(tb->flags);
    dc->vec_len = ARM_TBFLAG_VECLEN(tb->flags);
    dc->vec_stride = ARM_TBFLAG_VECSTRIDE(tb->flags);
11739
    dc->c15_cpar = ARM_TBFLAG_XSCALE_CPAR(tb->flags);
11740
    dc->cp_regs = cpu->cp_regs;
11741
    dc->features = env->features;
11742

11743 11744 11745 11746 11747 11748 11749 11750 11751 11752 11753 11754 11755 11756 11757 11758 11759 11760 11761 11762
    /* 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 已提交
11763 11764 11765 11766
    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 已提交
11767 11768
    cpu_V0 = cpu_F0d;
    cpu_V1 = cpu_F1d;
P
pbrook 已提交
11769
    /* FIXME: cpu_M0 can probably be the same as cpu_V0.  */
P
pbrook 已提交
11770
    cpu_M0 = tcg_temp_new_i64();
B
bellard 已提交
11771
    next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
P
pbrook 已提交
11772 11773
    num_insns = 0;
    max_insns = tb->cflags & CF_COUNT_MASK;
R
Richard Henderson 已提交
11774
    if (max_insns == 0) {
P
pbrook 已提交
11775
        max_insns = CF_COUNT_MASK;
R
Richard Henderson 已提交
11776 11777 11778 11779
    }
    if (max_insns > TCG_MAX_INSNS) {
        max_insns = TCG_MAX_INSNS;
    }
P
pbrook 已提交
11780

11781
    gen_tb_start(tb);
11782

11783 11784
    tcg_clear_temp_count();

11785 11786 11787
    /* A note on handling of the condexec (IT) bits:
     *
     * We want to avoid the overhead of having to write the updated condexec
11788
     * bits back to the CPUARMState for every instruction in an IT block. So:
11789
     * (1) if the condexec bits are not already zero then we write
11790
     * zero back into the CPUARMState now. This avoids complications trying
11791 11792 11793 11794 11795
     * 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()
11796
     * which will write the correct value into CPUARMState if zero is wrong.
11797 11798 11799 11800 11801 11802
     * 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)
11803
     * then the CPUARMState will be wrong and we need to reset it.
11804
     * This is handled in the same way as restoration of the
11805 11806 11807
     * 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.
11808 11809 11810
     *
     * Note that there are no instructions which can read the condexec
     * bits, and none which can write non-static values to them, so
11811
     * we don't need to care about whether CPUARMState is correct in the
11812 11813 11814
     * middle of a TB.
     */

P
pbrook 已提交
11815 11816
    /* Reset the conditional execution bits immediately. This avoids
       complications trying to do it at the end of the block.  */
11817
    if (dc->condexec_mask || dc->condexec_cond)
P
pbrook 已提交
11818
      {
11819
        TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
11820
        tcg_gen_movi_i32(tmp, 0);
P
pbrook 已提交
11821
        store_cpu_field(tmp, condexec_bits);
P
pbrook 已提交
11822
      }
B
bellard 已提交
11823
    do {
11824
        dc->insn_start_idx = tcg_op_buf_count();
11825
        tcg_gen_insn_start(dc->pc,
11826 11827
                           (dc->condexec_cond << 4) | (dc->condexec_mask >> 1),
                           0);
11828 11829
        num_insns++;

11830 11831
#ifdef CONFIG_USER_ONLY
        /* Intercept jump to the magic kernel page.  */
11832
        if (dc->pc >= 0xffff0000) {
11833 11834
            /* We always get here via a jump, so know we are not in a
               conditional execution block.  */
11835
            gen_exception_internal(EXCP_KERNEL_TRAP);
11836
            dc->is_jmp = DISAS_EXC;
11837 11838 11839
            break;
        }
#else
11840 11841 11842 11843 11844 11845
        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 已提交
11846 11847 11848
        }
#endif

11849
        if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
11850
            CPUBreakpoint *bp;
11851
            QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
11852
                if (bp->pc == dc->pc) {
11853
                    if (bp->flags & BP_CPU) {
11854
                        gen_set_condexec(dc);
11855
                        gen_set_pc_im(dc, dc->pc);
11856 11857 11858 11859 11860
                        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);
11861 11862 11863 11864 11865
                        /* 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.  */
11866 11867 11868 11869 11870 11871
                        /* TODO: Advance PC by correct instruction length to
                         * avoid disassembler error messages */
                        dc->pc += 2;
                        goto done_generating;
                    }
                    break;
B
bellard 已提交
11872 11873 11874
                }
            }
        }
11875

11876
        if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) {
P
pbrook 已提交
11877
            gen_io_start();
11878
        }
P
pbrook 已提交
11879

11880 11881 11882 11883 11884 11885 11886 11887 11888 11889 11890
        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.
             */
11891
            assert(num_insns == 1);
11892 11893
            gen_exception(EXCP_UDEF, syn_swstep(dc->ss_same_el, 0, 0),
                          default_exception_el(dc));
11894 11895 11896
            goto done_generating;
        }

11897
        if (dc->thumb) {
P
pbrook 已提交
11898 11899 11900 11901 11902 11903 11904 11905 11906 11907
            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 {
11908
            unsigned int insn = arm_ldl_code(env, dc->pc, dc->sctlr_b);
11909 11910
            dc->pc += 4;
            disas_arm_insn(dc, insn);
P
pbrook 已提交
11911
        }
11912 11913 11914 11915 11916

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

        if (tcg_check_temp_count()) {
11919 11920
            fprintf(stderr, "TCG temporary leak before "TARGET_FMT_lx"\n",
                    dc->pc);
11921 11922
        }

B
balrog 已提交
11923
        /* Translation stops when a conditional branch is encountered.
11924
         * Otherwise the subsequent code could get translated several times.
B
bellard 已提交
11925
         * Also stop translation when a page boundary is reached.  This
T
ths 已提交
11926
         * ensures prefetch aborts occur at the right place.  */
11927 11928 11929 11930 11931 11932 11933 11934 11935 11936 11937 11938 11939

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

11940
    } while (!dc->is_jmp && !tcg_op_buf_full() &&
11941
             !cs->singlestep_enabled &&
11942
             !singlestep &&
11943
             !dc->ss_active &&
11944
             !end_of_page &&
P
pbrook 已提交
11945 11946 11947 11948 11949 11950
             num_insns < max_insns);

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

B
bellard 已提交
11956
    /* At this stage dc->condjmp will only be set when the skipped
P
pbrook 已提交
11957 11958
       instruction was a conditional branch or trap, and the PC has
       already been written.  */
11959
    if (unlikely(cs->singlestep_enabled || dc->ss_active)) {
11960
        /* Unconditional and "condition passed" instruction codepath. */
P
pbrook 已提交
11961
        gen_set_condexec(dc);
11962 11963
        switch (dc->is_jmp) {
        case DISAS_SWI:
11964
            gen_ss_advance(dc);
11965 11966
            gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb),
                          default_exception_el(dc));
11967 11968
            break;
        case DISAS_HVC:
11969
            gen_ss_advance(dc);
11970
            gen_exception(EXCP_HVC, syn_aa32_hvc(dc->svc_imm), 2);
11971 11972
            break;
        case DISAS_SMC:
11973
            gen_ss_advance(dc);
11974
            gen_exception(EXCP_SMC, syn_aa32_smc(), 3);
11975 11976 11977 11978 11979 11980 11981 11982 11983 11984 11985 11986 11987 11988 11989 11990 11991 11992 11993 11994 11995 11996 11997 11998
            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 已提交
11999
        }
B
bellard 已提交
12000
    } else {
P
pbrook 已提交
12001 12002
        /* While branches must always occur at the end of an IT block,
           there are a few other things that can cause us to terminate
12003
           the TB in the middle of an IT block:
P
pbrook 已提交
12004 12005 12006 12007 12008 12009
            - 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 已提交
12010 12011
        switch(dc->is_jmp) {
        case DISAS_NEXT:
12012
            gen_goto_tb(dc, 1, dc->pc);
B
bellard 已提交
12013 12014
            break;
        case DISAS_UPDATE:
12015 12016 12017 12018
            gen_set_pc_im(dc, dc->pc);
            /* fall through */
        case DISAS_JUMP:
        default:
B
bellard 已提交
12019
            /* indicate that the hash table must be used to find the next TB */
B
bellard 已提交
12020
            tcg_gen_exit_tb(0);
B
bellard 已提交
12021 12022 12023 12024
            break;
        case DISAS_TB_JUMP:
            /* nothing more to generate */
            break;
P
pbrook 已提交
12025
        case DISAS_WFI:
B
Blue Swirl 已提交
12026
            gen_helper_wfi(cpu_env);
12027 12028 12029 12030
            /* 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 已提交
12031
            break;
12032 12033 12034
        case DISAS_WFE:
            gen_helper_wfe(cpu_env);
            break;
12035 12036 12037
        case DISAS_YIELD:
            gen_helper_yield(cpu_env);
            break;
P
pbrook 已提交
12038
        case DISAS_SWI:
12039 12040
            gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb),
                          default_exception_el(dc));
P
pbrook 已提交
12041
            break;
12042
        case DISAS_HVC:
12043
            gen_exception(EXCP_HVC, syn_aa32_hvc(dc->svc_imm), 2);
12044 12045
            break;
        case DISAS_SMC:
12046
            gen_exception(EXCP_SMC, syn_aa32_smc(), 3);
12047
            break;
B
bellard 已提交
12048
        }
12049 12050
        if (dc->condjmp) {
            gen_set_label(dc->condlabel);
P
pbrook 已提交
12051
            gen_set_condexec(dc);
12052
            gen_goto_tb(dc, 1, dc->pc);
12053 12054
            dc->condjmp = 0;
        }
B
bellard 已提交
12055
    }
P
pbrook 已提交
12056

P
pbrook 已提交
12057
done_generating:
12058
    gen_tb_end(tb, num_insns);
B
bellard 已提交
12059 12060

#ifdef DEBUG_DISAS
12061 12062
    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) &&
        qemu_log_in_addr_range(pc_start)) {
12063
        qemu_log_lock();
12064 12065
        qemu_log("----------------\n");
        qemu_log("IN: %s\n", lookup_symbol(pc_start));
12066
        log_target_disas(cs, pc_start, dc->pc - pc_start,
12067
                         dc->thumb | (dc->sctlr_b << 1));
12068
        qemu_log("\n");
12069
        qemu_log_unlock();
B
bellard 已提交
12070 12071
    }
#endif
12072 12073
    tb->size = dc->pc - pc_start;
    tb->icount = num_insns;
B
bellard 已提交
12074 12075
}

B
bellard 已提交
12076
static const char *cpu_mode_names[16] = {
12077 12078
  "usr", "fiq", "irq", "svc", "???", "???", "mon", "abt",
  "???", "???", "hyp", "und", "???", "???", "???", "sys"
B
bellard 已提交
12079
};
P
pbrook 已提交
12080

12081 12082
void arm_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
                        int flags)
B
bellard 已提交
12083
{
12084 12085
    ARMCPU *cpu = ARM_CPU(cs);
    CPUARMState *env = &cpu->env;
B
bellard 已提交
12086
    int i;
B
bellard 已提交
12087
    uint32_t psr;
12088
    const char *ns_status;
B
bellard 已提交
12089

12090 12091 12092 12093 12094
    if (is_a64(env)) {
        aarch64_cpu_dump_state(cs, f, cpu_fprintf, flags);
        return;
    }

B
bellard 已提交
12095
    for(i=0;i<16;i++) {
B
bellard 已提交
12096
        cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
B
bellard 已提交
12097
        if ((i % 4) == 3)
B
bellard 已提交
12098
            cpu_fprintf(f, "\n");
B
bellard 已提交
12099
        else
B
bellard 已提交
12100
            cpu_fprintf(f, " ");
B
bellard 已提交
12101
    }
B
bellard 已提交
12102
    psr = cpsr_read(env);
12103 12104 12105 12106 12107 12108 12109 12110 12111

    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",
12112
                psr,
B
bellard 已提交
12113 12114 12115 12116
                psr & (1 << 31) ? 'N' : '-',
                psr & (1 << 30) ? 'Z' : '-',
                psr & (1 << 29) ? 'C' : '-',
                psr & (1 << 28) ? 'V' : '-',
12117
                psr & CPSR_T ? 'T' : 'A',
12118
                ns_status,
B
bellard 已提交
12119
                cpu_mode_names[psr & 0xf], (psr & 0x10) ? 32 : 26);
B
bellard 已提交
12120

12121 12122 12123 12124 12125 12126 12127 12128 12129 12130 12131 12132 12133 12134 12135 12136
    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 已提交
12137
    }
B
bellard 已提交
12138
}
B
bellard 已提交
12139

12140 12141
void restore_state_to_opc(CPUARMState *env, TranslationBlock *tb,
                          target_ulong *data)
A
aurel32 已提交
12142
{
12143
    if (is_a64(env)) {
12144
        env->pc = data[0];
12145
        env->condexec_bits = 0;
12146
        env->exception.syndrome = data[2] << ARM_INSN_START_WORD2_SHIFT;
12147
    } else {
12148 12149
        env->regs[15] = data[0];
        env->condexec_bits = data[1];
12150
        env->exception.syndrome = data[2] << ARM_INSN_START_WORD2_SHIFT;
12151
    }
A
aurel32 已提交
12152
}