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

#include "cpu.h"
28
#include "disas/disas.h"
B
bellard 已提交
29
#include "tcg-op.h"
30
#include "qemu/log.h"
P
pbrook 已提交
31

L
Lluís 已提交
32
#include "helper.h"
P
pbrook 已提交
33
#define GEN_HELPER 1
L
Lluís 已提交
34
#include "helper.h"
B
bellard 已提交
35

36 37 38 39
#define ENABLE_ARCH_4T    arm_feature(env, ARM_FEATURE_V4T)
#define ENABLE_ARCH_5     arm_feature(env, ARM_FEATURE_V5)
/* currently all emulated v5 cores are also v5TE, so don't bother */
#define ENABLE_ARCH_5TE   arm_feature(env, ARM_FEATURE_V5)
P
pbrook 已提交
40 41 42 43 44
#define ENABLE_ARCH_5J    0
#define ENABLE_ARCH_6     arm_feature(env, ARM_FEATURE_V6)
#define ENABLE_ARCH_6K   arm_feature(env, ARM_FEATURE_V6K)
#define ENABLE_ARCH_6T2   arm_feature(env, ARM_FEATURE_THUMB2)
#define ENABLE_ARCH_7     arm_feature(env, ARM_FEATURE_V7)
B
bellard 已提交
45

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

B
bellard 已提交
48 49
/* internal defines */
typedef struct DisasContext {
B
bellard 已提交
50
    target_ulong pc;
B
bellard 已提交
51
    int is_jmp;
52 53 54 55
    /* Nonzero if this instruction has been conditionally skipped.  */
    int condjmp;
    /* The label that will be jumped to when the instruction is skipped.  */
    int condlabel;
56
    /* Thumb-2 conditional execution bits.  */
P
pbrook 已提交
57 58
    int condexec_mask;
    int condexec_cond;
B
bellard 已提交
59
    struct TranslationBlock *tb;
B
bellard 已提交
60
    int singlestep_enabled;
B
bellard 已提交
61
    int thumb;
P
Paul Brook 已提交
62
    int bswap_code;
B
bellard 已提交
63 64 65
#if !defined(CONFIG_USER_ONLY)
    int user;
#endif
66
    int vfp_enabled;
67 68
    int vec_len;
    int vec_stride;
B
bellard 已提交
69 70
} DisasContext;

71 72
static uint32_t gen_opc_condexec_bits[OPC_BUF_SIZE];

B
bellard 已提交
73 74 75 76 77 78
#if defined(CONFIG_USER_ONLY)
#define IS_USER(s) 1
#else
#define IS_USER(s) (s->user)
#endif

P
pbrook 已提交
79
/* These instructions trap after executing, so defer them until after the
80
   conditional execution state has been updated.  */
P
pbrook 已提交
81 82
#define DISAS_WFI 4
#define DISAS_SWI 5
B
bellard 已提交
83

P
pbrook 已提交
84
static TCGv_ptr cpu_env;
P
pbrook 已提交
85
/* We reuse the same 64-bit temporaries for efficiency.  */
P
pbrook 已提交
86
static TCGv_i64 cpu_V0, cpu_V1, cpu_M0;
87
static TCGv_i32 cpu_R[16];
88
static TCGv_i32 cpu_CF, cpu_NF, cpu_VF, cpu_ZF;
P
Paul Brook 已提交
89 90 91 92 93 94 95
static TCGv_i32 cpu_exclusive_addr;
static TCGv_i32 cpu_exclusive_val;
static TCGv_i32 cpu_exclusive_high;
#ifdef CONFIG_USER_ONLY
static TCGv_i32 cpu_exclusive_test;
static TCGv_i32 cpu_exclusive_info;
#endif
P
pbrook 已提交
96

P
pbrook 已提交
97
/* FIXME:  These should be removed.  */
98
static TCGv_i32 cpu_F0s, cpu_F1s;
P
pbrook 已提交
99
static TCGv_i64 cpu_F0d, cpu_F1d;
P
pbrook 已提交
100

101
#include "exec/gen-icount.h"
P
pbrook 已提交
102

103 104 105 106
static const char *regnames[] =
    { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
      "r8", "r9", "r10", "r11", "r12", "r13", "r14", "pc" };

P
pbrook 已提交
107 108 109
/* initialize TCG globals.  */
void arm_translate_init(void)
{
110 111
    int i;

P
pbrook 已提交
112 113
    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");

114 115
    for (i = 0; i < 16; i++) {
        cpu_R[i] = tcg_global_mem_new_i32(TCG_AREG0,
116
                                          offsetof(CPUARMState, regs[i]),
117 118
                                          regnames[i]);
    }
119 120 121 122 123
    cpu_CF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, CF), "CF");
    cpu_NF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, NF), "NF");
    cpu_VF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, VF), "VF");
    cpu_ZF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, ZF), "ZF");

P
Paul Brook 已提交
124
    cpu_exclusive_addr = tcg_global_mem_new_i32(TCG_AREG0,
125
        offsetof(CPUARMState, exclusive_addr), "exclusive_addr");
P
Paul Brook 已提交
126
    cpu_exclusive_val = tcg_global_mem_new_i32(TCG_AREG0,
127
        offsetof(CPUARMState, exclusive_val), "exclusive_val");
P
Paul Brook 已提交
128
    cpu_exclusive_high = tcg_global_mem_new_i32(TCG_AREG0,
129
        offsetof(CPUARMState, exclusive_high), "exclusive_high");
P
Paul Brook 已提交
130 131
#ifdef CONFIG_USER_ONLY
    cpu_exclusive_test = tcg_global_mem_new_i32(TCG_AREG0,
132
        offsetof(CPUARMState, exclusive_test), "exclusive_test");
P
Paul Brook 已提交
133
    cpu_exclusive_info = tcg_global_mem_new_i32(TCG_AREG0,
134
        offsetof(CPUARMState, exclusive_info), "exclusive_info");
P
Paul Brook 已提交
135
#endif
136

P
pbrook 已提交
137
#define GEN_HELPER 2
L
Lluís 已提交
138
#include "helper.h"
P
pbrook 已提交
139 140
}

141
static inline TCGv_i32 load_cpu_offset(int offset)
P
pbrook 已提交
142
{
143
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
144 145 146 147
    tcg_gen_ld_i32(tmp, cpu_env, offset);
    return tmp;
}

148
#define load_cpu_field(name) load_cpu_offset(offsetof(CPUARMState, name))
P
pbrook 已提交
149

150
static inline void store_cpu_offset(TCGv_i32 var, int offset)
P
pbrook 已提交
151 152
{
    tcg_gen_st_i32(var, cpu_env, offset);
153
    tcg_temp_free_i32(var);
P
pbrook 已提交
154 155 156
}

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

P
pbrook 已提交
159
/* Set a variable to the value of a CPU register.  */
160
static void load_reg_var(DisasContext *s, TCGv_i32 var, int reg)
P
pbrook 已提交
161 162 163
{
    if (reg == 15) {
        uint32_t addr;
164
        /* normally, since we updated PC, we need only to add one insn */
P
pbrook 已提交
165 166 167 168 169 170
        if (s->thumb)
            addr = (long)s->pc + 2;
        else
            addr = (long)s->pc + 4;
        tcg_gen_movi_i32(var, addr);
    } else {
171
        tcg_gen_mov_i32(var, cpu_R[reg]);
P
pbrook 已提交
172 173 174 175
    }
}

/* Create a new temporary and set it to the value of a CPU register.  */
176
static inline TCGv_i32 load_reg(DisasContext *s, int reg)
P
pbrook 已提交
177
{
178
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
179 180 181 182 183 184
    load_reg_var(s, tmp, reg);
    return tmp;
}

/* Set a CPU register.  The source must be a temporary and will be
   marked as dead.  */
185
static void store_reg(DisasContext *s, int reg, TCGv_i32 var)
P
pbrook 已提交
186 187 188 189 190
{
    if (reg == 15) {
        tcg_gen_andi_i32(var, var, ~1);
        s->is_jmp = DISAS_JUMP;
    }
191
    tcg_gen_mov_i32(cpu_R[reg], var);
192
    tcg_temp_free_i32(var);
P
pbrook 已提交
193 194 195
}

/* Value extensions.  */
P
pbrook 已提交
196 197
#define gen_uxtb(var) tcg_gen_ext8u_i32(var, var)
#define gen_uxth(var) tcg_gen_ext16u_i32(var, var)
P
pbrook 已提交
198 199 200
#define gen_sxtb(var) tcg_gen_ext8s_i32(var, var)
#define gen_sxth(var) tcg_gen_ext16s_i32(var, var)

P
pbrook 已提交
201 202
#define gen_sxtb16(var) gen_helper_sxtb16(var, var)
#define gen_uxtb16(var) gen_helper_uxtb16(var, var)
P
pbrook 已提交
203

P
pbrook 已提交
204

205
static inline void gen_set_cpsr(TCGv_i32 var, uint32_t mask)
206
{
207
    TCGv_i32 tmp_mask = tcg_const_i32(mask);
B
Blue Swirl 已提交
208
    gen_helper_cpsr_write(cpu_env, var, tmp_mask);
209 210
    tcg_temp_free_i32(tmp_mask);
}
P
pbrook 已提交
211 212 213 214 215
/* Set NZCV flags from the high 4 bits of var.  */
#define gen_set_nzcv(var) gen_set_cpsr(var, CPSR_NZCV)

static void gen_exception(int excp)
{
216
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
217
    tcg_gen_movi_i32(tmp, excp);
B
Blue Swirl 已提交
218
    gen_helper_exception(cpu_env, tmp);
219
    tcg_temp_free_i32(tmp);
P
pbrook 已提交
220 221
}

222
static void gen_smul_dual(TCGv_i32 a, TCGv_i32 b)
P
pbrook 已提交
223
{
224 225
    TCGv_i32 tmp1 = tcg_temp_new_i32();
    TCGv_i32 tmp2 = tcg_temp_new_i32();
226 227
    tcg_gen_ext16s_i32(tmp1, a);
    tcg_gen_ext16s_i32(tmp2, b);
P
pbrook 已提交
228
    tcg_gen_mul_i32(tmp1, tmp1, tmp2);
229
    tcg_temp_free_i32(tmp2);
P
pbrook 已提交
230 231 232 233
    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);
234
    tcg_temp_free_i32(tmp1);
P
pbrook 已提交
235 236 237
}

/* Byteswap each halfword.  */
238
static void gen_rev16(TCGv_i32 var)
P
pbrook 已提交
239
{
240
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
241 242 243 244 245
    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);
246
    tcg_temp_free_i32(tmp);
P
pbrook 已提交
247 248 249
}

/* Byteswap low halfword and sign extend.  */
250
static void gen_revsh(TCGv_i32 var)
P
pbrook 已提交
251
{
252 253 254
    tcg_gen_ext16u_i32(var, var);
    tcg_gen_bswap16_i32(var, var);
    tcg_gen_ext16s_i32(var, var);
P
pbrook 已提交
255 256 257
}

/* Unsigned bitfield extract.  */
258
static void gen_ubfx(TCGv_i32 var, int shift, uint32_t mask)
P
pbrook 已提交
259 260 261 262 263 264 265
{
    if (shift)
        tcg_gen_shri_i32(var, var, shift);
    tcg_gen_andi_i32(var, var, mask);
}

/* Signed bitfield extract.  */
266
static void gen_sbfx(TCGv_i32 var, int shift, int width)
P
pbrook 已提交
267 268 269 270 271 272 273 274 275 276 277 278 279
{
    uint32_t signbit;

    if (shift)
        tcg_gen_sari_i32(var, var, shift);
    if (shift + width < 32) {
        signbit = 1u << (width - 1);
        tcg_gen_andi_i32(var, var, (1u << width) - 1);
        tcg_gen_xori_i32(var, var, signbit);
        tcg_gen_subi_i32(var, var, signbit);
    }
}

280
/* Return (b << 32) + a. Mark inputs as dead */
281
static TCGv_i64 gen_addq_msw(TCGv_i64 a, TCGv_i32 b)
P
pbrook 已提交
282
{
283 284 285
    TCGv_i64 tmp64 = tcg_temp_new_i64();

    tcg_gen_extu_i32_i64(tmp64, b);
286
    tcg_temp_free_i32(b);
287 288 289 290 291 292 293 294
    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. */
295
static TCGv_i64 gen_subq_msw(TCGv_i64 a, TCGv_i32 b)
296 297 298 299
{
    TCGv_i64 tmp64 = tcg_temp_new_i64();

    tcg_gen_extu_i32_i64(tmp64, b);
300
    tcg_temp_free_i32(b);
301 302 303 304 305
    tcg_gen_shli_i64(tmp64, tmp64, 32);
    tcg_gen_sub_i64(a, tmp64, a);

    tcg_temp_free_i64(tmp64);
    return a;
P
pbrook 已提交
306 307
}

P
pbrook 已提交
308
/* 32x32->64 multiply.  Marks inputs as dead.  */
309
static TCGv_i64 gen_mulu_i64_i32(TCGv_i32 a, TCGv_i32 b)
P
pbrook 已提交
310
{
311 312
    TCGv_i32 lo = tcg_temp_new_i32();
    TCGv_i32 hi = tcg_temp_new_i32();
313
    TCGv_i64 ret;
P
pbrook 已提交
314

315
    tcg_gen_mulu2_i32(lo, hi, a, b);
316 317
    tcg_temp_free_i32(a);
    tcg_temp_free_i32(b);
318 319 320

    ret = tcg_temp_new_i64();
    tcg_gen_concat_i32_i64(ret, lo, hi);
321 322
    tcg_temp_free_i32(lo);
    tcg_temp_free_i32(hi);
323 324

    return ret;
P
pbrook 已提交
325 326
}

327
static TCGv_i64 gen_muls_i64_i32(TCGv_i32 a, TCGv_i32 b)
P
pbrook 已提交
328
{
329 330
    TCGv_i32 lo = tcg_temp_new_i32();
    TCGv_i32 hi = tcg_temp_new_i32();
331
    TCGv_i64 ret;
P
pbrook 已提交
332

333
    tcg_gen_muls2_i32(lo, hi, a, b);
334 335
    tcg_temp_free_i32(a);
    tcg_temp_free_i32(b);
336 337 338

    ret = tcg_temp_new_i64();
    tcg_gen_concat_i32_i64(ret, lo, hi);
339 340
    tcg_temp_free_i32(lo);
    tcg_temp_free_i32(hi);
341 342

    return ret;
P
pbrook 已提交
343 344
}

P
pbrook 已提交
345
/* Swap low and high halfwords.  */
346
static void gen_swap_half(TCGv_i32 var)
P
pbrook 已提交
347
{
348
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
349 350 351
    tcg_gen_shri_i32(tmp, var, 16);
    tcg_gen_shli_i32(var, var, 16);
    tcg_gen_or_i32(var, var, tmp);
352
    tcg_temp_free_i32(tmp);
P
pbrook 已提交
353 354
}

P
pbrook 已提交
355 356 357 358 359 360 361
/* 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;
 */

362
static void gen_add16(TCGv_i32 t0, TCGv_i32 t1)
P
pbrook 已提交
363
{
364
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
365 366 367 368 369 370
    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);
371 372
    tcg_temp_free_i32(tmp);
    tcg_temp_free_i32(t1);
P
pbrook 已提交
373 374 375
}

/* Set CF to the top bit of var.  */
376
static void gen_set_CF_bit31(TCGv_i32 var)
P
pbrook 已提交
377
{
378
    tcg_gen_shri_i32(cpu_CF, var, 31);
P
pbrook 已提交
379 380 381
}

/* Set N and Z flags from var.  */
382
static inline void gen_logic_CC(TCGv_i32 var)
P
pbrook 已提交
383
{
384 385
    tcg_gen_mov_i32(cpu_NF, var);
    tcg_gen_mov_i32(cpu_ZF, var);
P
pbrook 已提交
386 387 388
}

/* T0 += T1 + CF.  */
389
static void gen_adc(TCGv_i32 t0, TCGv_i32 t1)
P
pbrook 已提交
390
{
391
    tcg_gen_add_i32(t0, t0, t1);
392
    tcg_gen_add_i32(t0, t0, cpu_CF);
P
pbrook 已提交
393 394
}

395
/* dest = T0 + T1 + CF. */
396
static void gen_add_carry(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)
397 398
{
    tcg_gen_add_i32(dest, t0, t1);
399
    tcg_gen_add_i32(dest, dest, cpu_CF);
400 401
}

P
pbrook 已提交
402
/* dest = T0 - T1 + CF - 1.  */
403
static void gen_sub_carry(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)
P
pbrook 已提交
404 405
{
    tcg_gen_sub_i32(dest, t0, t1);
406
    tcg_gen_add_i32(dest, dest, cpu_CF);
P
pbrook 已提交
407 408 409
    tcg_gen_subi_i32(dest, dest, 1);
}

410
/* dest = T0 + T1. Compute C, N, V and Z flags */
411
static void gen_add_CC(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)
412
{
413
    TCGv_i32 tmp = tcg_temp_new_i32();
414 415
    tcg_gen_movi_i32(tmp, 0);
    tcg_gen_add2_i32(cpu_NF, cpu_CF, t0, tmp, t1, tmp);
416 417 418 419 420 421 422 423
    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);
}

424
/* dest = T0 + T1 + CF.  Compute C, N, V and Z flags */
425
static void gen_adc_CC(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)
426
{
427
    TCGv_i32 tmp = tcg_temp_new_i32();
428 429 430
    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);
431
        tcg_gen_add2_i32(cpu_NF, cpu_CF, cpu_NF, cpu_CF, t1, tmp);
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451
    } 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);
}

452
/* dest = T0 - T1. Compute C, N, V and Z flags */
453
static void gen_sub_CC(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)
454
{
455
    TCGv_i32 tmp;
456 457 458 459 460 461 462 463 464 465 466
    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 已提交
467
/* dest = T0 + ~T1 + CF.  Compute C, N, V and Z flags */
468
static void gen_sbc_CC(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)
469
{
470
    TCGv_i32 tmp = tcg_temp_new_i32();
R
Richard Henderson 已提交
471 472
    tcg_gen_not_i32(tmp, t1);
    gen_adc_CC(dest, t0, tmp);
473
    tcg_temp_free_i32(tmp);
474 475
}

476
#define GEN_SHIFT(name)                                               \
477
static void gen_##name(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)       \
478
{                                                                     \
479
    TCGv_i32 tmp1, tmp2, tmp3;                                        \
480 481 482 483 484 485 486 487 488 489 490 491 492 493 494
    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

495
static void gen_sar(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1)
496
{
497
    TCGv_i32 tmp1, tmp2;
498 499 500 501 502 503 504 505 506
    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);
}

507
static void tcg_gen_abs_i32(TCGv_i32 dest, TCGv_i32 src)
508
{
509 510
    TCGv_i32 c0 = tcg_const_i32(0);
    TCGv_i32 tmp = tcg_temp_new_i32();
511 512 513 514 515
    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 已提交
516

517
static void shifter_out_im(TCGv_i32 var, int shift)
P
pbrook 已提交
518
{
P
pbrook 已提交
519
    if (shift == 0) {
520
        tcg_gen_andi_i32(cpu_CF, var, 1);
P
pbrook 已提交
521
    } else {
522 523 524 525
        tcg_gen_shri_i32(cpu_CF, var, shift);
        if (shift != 31) {
            tcg_gen_andi_i32(cpu_CF, cpu_CF, 1);
        }
P
pbrook 已提交
526 527
    }
}
P
pbrook 已提交
528

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

579 580
static inline void gen_arm_shift_reg(TCGv_i32 var, int shiftop,
                                     TCGv_i32 shift, int flags)
P
pbrook 已提交
581 582 583
{
    if (flags) {
        switch (shiftop) {
584 585 586 587
        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 已提交
588 589 590
        }
    } else {
        switch (shiftop) {
591 592 593 594 595 596 597 598 599
        case 0:
            gen_shl(var, var, shift);
            break;
        case 1:
            gen_shr(var, var, shift);
            break;
        case 2:
            gen_sar(var, var, shift);
            break;
600 601
        case 3: tcg_gen_andi_i32(shift, shift, 0x1f);
                tcg_gen_rotr_i32(var, var, shift); break;
P
pbrook 已提交
602 603
        }
    }
604
    tcg_temp_free_i32(shift);
P
pbrook 已提交
605 606
}

P
pbrook 已提交
607 608 609 610 611 612 613 614 615
#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; \
    }
616
static void gen_arm_parallel_addsub(int op1, int op2, TCGv_i32 a, TCGv_i32 b)
P
pbrook 已提交
617
{
P
pbrook 已提交
618
    TCGv_ptr tmp;
P
pbrook 已提交
619 620 621 622

    switch (op1) {
#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp)
    case 1:
P
pbrook 已提交
623
        tmp = tcg_temp_new_ptr();
624
        tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUARMState, GE));
P
pbrook 已提交
625
        PAS_OP(s)
626
        tcg_temp_free_ptr(tmp);
P
pbrook 已提交
627 628
        break;
    case 5:
P
pbrook 已提交
629
        tmp = tcg_temp_new_ptr();
630
        tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUARMState, GE));
P
pbrook 已提交
631
        PAS_OP(u)
632
        tcg_temp_free_ptr(tmp);
P
pbrook 已提交
633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650
        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 已提交
651 652
#undef PAS_OP

P
pbrook 已提交
653 654
/* For unknown reasons Arm and Thumb-2 use arbitrarily different encodings.  */
#define PAS_OP(pfx) \
655
    switch (op1) {  \
P
pbrook 已提交
656 657 658 659 660 661 662
    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; \
    }
663
static void gen_thumb2_parallel_addsub(int op1, int op2, TCGv_i32 a, TCGv_i32 b)
P
pbrook 已提交
664
{
P
pbrook 已提交
665
    TCGv_ptr tmp;
P
pbrook 已提交
666

667
    switch (op2) {
P
pbrook 已提交
668 669
#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp)
    case 0:
P
pbrook 已提交
670
        tmp = tcg_temp_new_ptr();
671
        tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUARMState, GE));
P
pbrook 已提交
672
        PAS_OP(s)
673
        tcg_temp_free_ptr(tmp);
P
pbrook 已提交
674 675
        break;
    case 4:
P
pbrook 已提交
676
        tmp = tcg_temp_new_ptr();
677
        tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUARMState, GE));
P
pbrook 已提交
678
        PAS_OP(u)
679
        tcg_temp_free_ptr(tmp);
P
pbrook 已提交
680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697
        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 已提交
698 699
#undef PAS_OP

P
pbrook 已提交
700 701
static void gen_test_cc(int cc, int label)
{
702
    TCGv_i32 tmp;
P
pbrook 已提交
703 704 705 706
    int inv;

    switch (cc) {
    case 0: /* eq: Z */
707
        tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_ZF, 0, label);
P
pbrook 已提交
708 709
        break;
    case 1: /* ne: !Z */
710
        tcg_gen_brcondi_i32(TCG_COND_NE, cpu_ZF, 0, label);
P
pbrook 已提交
711 712
        break;
    case 2: /* cs: C */
713
        tcg_gen_brcondi_i32(TCG_COND_NE, cpu_CF, 0, label);
P
pbrook 已提交
714 715
        break;
    case 3: /* cc: !C */
716
        tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_CF, 0, label);
P
pbrook 已提交
717 718
        break;
    case 4: /* mi: N */
719
        tcg_gen_brcondi_i32(TCG_COND_LT, cpu_NF, 0, label);
P
pbrook 已提交
720 721
        break;
    case 5: /* pl: !N */
722
        tcg_gen_brcondi_i32(TCG_COND_GE, cpu_NF, 0, label);
P
pbrook 已提交
723 724
        break;
    case 6: /* vs: V */
725
        tcg_gen_brcondi_i32(TCG_COND_LT, cpu_VF, 0, label);
P
pbrook 已提交
726 727
        break;
    case 7: /* vc: !V */
728
        tcg_gen_brcondi_i32(TCG_COND_GE, cpu_VF, 0, label);
P
pbrook 已提交
729 730 731
        break;
    case 8: /* hi: C && !Z */
        inv = gen_new_label();
732 733
        tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_CF, 0, inv);
        tcg_gen_brcondi_i32(TCG_COND_NE, cpu_ZF, 0, label);
P
pbrook 已提交
734 735 736
        gen_set_label(inv);
        break;
    case 9: /* ls: !C || Z */
737 738
        tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_CF, 0, label);
        tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_ZF, 0, label);
P
pbrook 已提交
739 740
        break;
    case 10: /* ge: N == V -> N ^ V == 0 */
741 742
        tmp = tcg_temp_new_i32();
        tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF);
P
pbrook 已提交
743
        tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
744
        tcg_temp_free_i32(tmp);
P
pbrook 已提交
745 746
        break;
    case 11: /* lt: N != V -> N ^ V != 0 */
747 748
        tmp = tcg_temp_new_i32();
        tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF);
P
pbrook 已提交
749
        tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
750
        tcg_temp_free_i32(tmp);
P
pbrook 已提交
751 752 753
        break;
    case 12: /* gt: !Z && N == V */
        inv = gen_new_label();
754 755 756
        tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_ZF, 0, inv);
        tmp = tcg_temp_new_i32();
        tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF);
P
pbrook 已提交
757
        tcg_gen_brcondi_i32(TCG_COND_GE, tmp, 0, label);
758
        tcg_temp_free_i32(tmp);
P
pbrook 已提交
759 760 761
        gen_set_label(inv);
        break;
    case 13: /* le: Z || N != V */
762 763 764
        tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_ZF, 0, label);
        tmp = tcg_temp_new_i32();
        tcg_gen_xor_i32(tmp, cpu_VF, cpu_NF);
P
pbrook 已提交
765
        tcg_gen_brcondi_i32(TCG_COND_LT, tmp, 0, label);
766
        tcg_temp_free_i32(tmp);
P
pbrook 已提交
767 768 769 770 771 772
        break;
    default:
        fprintf(stderr, "Bad condition code 0x%x\n", cc);
        abort();
    }
}
B
bellard 已提交
773

774
static const uint8_t table_logic_cc[16] = {
B
bellard 已提交
775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791
    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 */
};
792

P
pbrook 已提交
793 794
/* Set PC and Thumb state from an immediate address.  */
static inline void gen_bx_im(DisasContext *s, uint32_t addr)
B
bellard 已提交
795
{
796
    TCGv_i32 tmp;
B
bellard 已提交
797

P
pbrook 已提交
798
    s->is_jmp = DISAS_UPDATE;
P
pbrook 已提交
799
    if (s->thumb != (addr & 1)) {
800
        tmp = tcg_temp_new_i32();
P
pbrook 已提交
801
        tcg_gen_movi_i32(tmp, addr & 1);
802
        tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUARMState, thumb));
803
        tcg_temp_free_i32(tmp);
P
pbrook 已提交
804
    }
805
    tcg_gen_movi_i32(cpu_R[15], addr & ~1);
P
pbrook 已提交
806 807 808
}

/* Set PC and Thumb state from var.  var is marked as dead.  */
809
static inline void gen_bx(DisasContext *s, TCGv_i32 var)
P
pbrook 已提交
810 811
{
    s->is_jmp = DISAS_UPDATE;
812 813 814
    tcg_gen_andi_i32(cpu_R[15], var, ~1);
    tcg_gen_andi_i32(var, var, 1);
    store_cpu_field(var, thumb);
P
pbrook 已提交
815 816
}

817 818 819
/* 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. */
820
static inline void store_reg_bx(CPUARMState *env, DisasContext *s,
821
                                int reg, TCGv_i32 var)
822 823 824 825 826 827 828 829
{
    if (reg == 15 && ENABLE_ARCH_7) {
        gen_bx(s, var);
    } else {
        store_reg(s, reg, var);
    }
}

830 831 832 833
/* 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. */
834
static inline void store_reg_from_load(CPUARMState *env, DisasContext *s,
835
                                       int reg, TCGv_i32 var)
836 837 838 839 840 841 842 843
{
    if (reg == 15 && ENABLE_ARCH_5) {
        gen_bx(s, var);
    } else {
        store_reg(s, reg, var);
    }
}

P
pbrook 已提交
844 845
static inline void gen_set_pc_im(uint32_t val)
{
846
    tcg_gen_movi_i32(cpu_R[15], val);
P
pbrook 已提交
847 848
}

B
bellard 已提交
849 850 851
/* Force a TB lookup after an instruction that changes the CPU state.  */
static inline void gen_lookup_tb(DisasContext *s)
{
852
    tcg_gen_movi_i32(cpu_R[15], s->pc & ~1);
B
bellard 已提交
853 854 855
    s->is_jmp = DISAS_UPDATE;
}

P
pbrook 已提交
856
static inline void gen_add_data_offset(DisasContext *s, unsigned int insn,
857
                                       TCGv_i32 var)
B
bellard 已提交
858
{
B
bellard 已提交
859
    int val, rm, shift, shiftop;
860
    TCGv_i32 offset;
B
bellard 已提交
861 862 863 864 865 866

    if (!(insn & (1 << 25))) {
        /* immediate */
        val = insn & 0xfff;
        if (!(insn & (1 << 23)))
            val = -val;
B
bellard 已提交
867
        if (val != 0)
P
pbrook 已提交
868
            tcg_gen_addi_i32(var, var, val);
B
bellard 已提交
869 870 871 872
    } else {
        /* shift/register */
        rm = (insn) & 0xf;
        shift = (insn >> 7) & 0x1f;
B
bellard 已提交
873
        shiftop = (insn >> 5) & 3;
P
pbrook 已提交
874
        offset = load_reg(s, rm);
P
pbrook 已提交
875
        gen_arm_shift_im(offset, shiftop, shift, 0);
B
bellard 已提交
876
        if (!(insn & (1 << 23)))
P
pbrook 已提交
877
            tcg_gen_sub_i32(var, var, offset);
B
bellard 已提交
878
        else
P
pbrook 已提交
879
            tcg_gen_add_i32(var, var, offset);
880
        tcg_temp_free_i32(offset);
B
bellard 已提交
881 882 883
    }
}

P
pbrook 已提交
884
static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn,
885
                                        int extra, TCGv_i32 var)
B
bellard 已提交
886 887
{
    int val, rm;
888
    TCGv_i32 offset;
889

B
bellard 已提交
890 891 892 893 894
    if (insn & (1 << 22)) {
        /* immediate */
        val = (insn & 0xf) | ((insn >> 4) & 0xf0);
        if (!(insn & (1 << 23)))
            val = -val;
895
        val += extra;
B
bellard 已提交
896
        if (val != 0)
P
pbrook 已提交
897
            tcg_gen_addi_i32(var, var, val);
B
bellard 已提交
898 899
    } else {
        /* register */
P
pbrook 已提交
900
        if (extra)
P
pbrook 已提交
901
            tcg_gen_addi_i32(var, var, extra);
B
bellard 已提交
902
        rm = (insn) & 0xf;
P
pbrook 已提交
903
        offset = load_reg(s, rm);
B
bellard 已提交
904
        if (!(insn & (1 << 23)))
P
pbrook 已提交
905
            tcg_gen_sub_i32(var, var, offset);
B
bellard 已提交
906
        else
P
pbrook 已提交
907
            tcg_gen_add_i32(var, var, offset);
908
        tcg_temp_free_i32(offset);
B
bellard 已提交
909 910 911
    }
}

912 913 914 915 916
static TCGv_ptr get_fpstatus_ptr(int neon)
{
    TCGv_ptr statusptr = tcg_temp_new_ptr();
    int offset;
    if (neon) {
917
        offset = offsetof(CPUARMState, vfp.standard_fp_status);
918
    } else {
919
        offset = offsetof(CPUARMState, vfp.fp_status);
920 921 922 923 924
    }
    tcg_gen_addi_ptr(statusptr, cpu_env, offset);
    return statusptr;
}

P
pbrook 已提交
925 926 927
#define VFP_OP2(name)                                                 \
static inline void gen_vfp_##name(int dp)                             \
{                                                                     \
928 929 930 931 932 933 934
    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 已提交
935 936
}

P
pbrook 已提交
937 938 939 940 941 942 943
VFP_OP2(add)
VFP_OP2(sub)
VFP_OP2(mul)
VFP_OP2(div)

#undef VFP_OP2

944 945 946
static inline void gen_vfp_F1_mul(int dp)
{
    /* Like gen_vfp_mul() but put result in F1 */
947
    TCGv_ptr fpst = get_fpstatus_ptr(0);
948
    if (dp) {
949
        gen_helper_vfp_muld(cpu_F1d, cpu_F0d, cpu_F1d, fpst);
950
    } else {
951
        gen_helper_vfp_muls(cpu_F1s, cpu_F0s, cpu_F1s, fpst);
952
    }
953
    tcg_temp_free_ptr(fpst);
954 955 956 957 958 959 960 961 962 963 964 965
}

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 已提交
966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008
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 已提交
1009
        tcg_gen_movi_i64(cpu_F1d, 0);
P
pbrook 已提交
1010
    else
B
balrog 已提交
1011
        tcg_gen_movi_i32(cpu_F1s, 0);
P
pbrook 已提交
1012 1013
}

1014 1015 1016
#define VFP_GEN_ITOF(name) \
static inline void gen_vfp_##name(int dp, int neon) \
{ \
1017
    TCGv_ptr statusptr = get_fpstatus_ptr(neon); \
1018 1019 1020 1021 1022
    if (dp) { \
        gen_helper_vfp_##name##d(cpu_F0d, cpu_F0s, statusptr); \
    } else { \
        gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, statusptr); \
    } \
1023
    tcg_temp_free_ptr(statusptr); \
P
pbrook 已提交
1024 1025
}

1026 1027 1028
VFP_GEN_ITOF(uito)
VFP_GEN_ITOF(sito)
#undef VFP_GEN_ITOF
P
pbrook 已提交
1029

1030 1031 1032
#define VFP_GEN_FTOI(name) \
static inline void gen_vfp_##name(int dp, int neon) \
{ \
1033
    TCGv_ptr statusptr = get_fpstatus_ptr(neon); \
1034 1035 1036 1037 1038
    if (dp) { \
        gen_helper_vfp_##name##d(cpu_F0s, cpu_F0d, statusptr); \
    } else { \
        gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, statusptr); \
    } \
1039
    tcg_temp_free_ptr(statusptr); \
P
pbrook 已提交
1040 1041
}

1042 1043 1044 1045 1046
VFP_GEN_FTOI(toui)
VFP_GEN_FTOI(touiz)
VFP_GEN_FTOI(tosi)
VFP_GEN_FTOI(tosiz)
#undef VFP_GEN_FTOI
P
pbrook 已提交
1047 1048

#define VFP_GEN_FIX(name) \
1049
static inline void gen_vfp_##name(int dp, int shift, int neon) \
P
pbrook 已提交
1050
{ \
1051
    TCGv_i32 tmp_shift = tcg_const_i32(shift); \
1052
    TCGv_ptr statusptr = get_fpstatus_ptr(neon); \
1053 1054 1055 1056 1057
    if (dp) { \
        gen_helper_vfp_##name##d(cpu_F0d, cpu_F0d, tmp_shift, statusptr); \
    } else { \
        gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, tmp_shift, statusptr); \
    } \
1058
    tcg_temp_free_i32(tmp_shift); \
1059
    tcg_temp_free_ptr(statusptr); \
P
pbrook 已提交
1060
}
P
pbrook 已提交
1061 1062 1063 1064 1065 1066 1067 1068 1069
VFP_GEN_FIX(tosh)
VFP_GEN_FIX(tosl)
VFP_GEN_FIX(touh)
VFP_GEN_FIX(toul)
VFP_GEN_FIX(shto)
VFP_GEN_FIX(slto)
VFP_GEN_FIX(uhto)
VFP_GEN_FIX(ulto)
#undef VFP_GEN_FIX
P
pbrook 已提交
1070

1071
static inline void gen_vfp_ld(DisasContext *s, int dp, TCGv_i32 addr)
B
bellard 已提交
1072 1073
{
    if (dp)
1074
        tcg_gen_qemu_ld64(cpu_F0d, addr, IS_USER(s));
B
bellard 已提交
1075
    else
1076
        tcg_gen_qemu_ld32u(cpu_F0s, addr, IS_USER(s));
B
bellard 已提交
1077 1078
}

1079
static inline void gen_vfp_st(DisasContext *s, int dp, TCGv_i32 addr)
B
bellard 已提交
1080 1081
{
    if (dp)
1082
        tcg_gen_qemu_st64(cpu_F0d, addr, IS_USER(s));
B
bellard 已提交
1083
    else
1084
        tcg_gen_qemu_st32(cpu_F0s, addr, IS_USER(s));
B
bellard 已提交
1085 1086
}

B
bellard 已提交
1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099
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 已提交
1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110

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

1111
static TCGv_i32 neon_load_reg(int reg, int pass)
P
pbrook 已提交
1112
{
1113
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
1114 1115 1116 1117
    tcg_gen_ld_i32(tmp, cpu_env, neon_reg_offset(reg, pass));
    return tmp;
}

1118
static void neon_store_reg(int reg, int pass, TCGv_i32 var)
P
pbrook 已提交
1119 1120
{
    tcg_gen_st_i32(var, cpu_env, neon_reg_offset(reg, pass));
1121
    tcg_temp_free_i32(var);
P
pbrook 已提交
1122 1123
}

P
pbrook 已提交
1124
static inline void neon_load_reg64(TCGv_i64 var, int reg)
P
pbrook 已提交
1125 1126 1127 1128
{
    tcg_gen_ld_i64(var, cpu_env, vfp_reg_offset(1, reg));
}

P
pbrook 已提交
1129
static inline void neon_store_reg64(TCGv_i64 var, int reg)
P
pbrook 已提交
1130 1131 1132 1133
{
    tcg_gen_st_i64(var, cpu_env, vfp_reg_offset(1, reg));
}

P
pbrook 已提交
1134 1135 1136 1137 1138
#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 已提交
1139 1140 1141
static inline void gen_mov_F0_vreg(int dp, int reg)
{
    if (dp)
P
pbrook 已提交
1142
        tcg_gen_ld_f64(cpu_F0d, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1143
    else
P
pbrook 已提交
1144
        tcg_gen_ld_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1145 1146 1147 1148 1149
}

static inline void gen_mov_F1_vreg(int dp, int reg)
{
    if (dp)
P
pbrook 已提交
1150
        tcg_gen_ld_f64(cpu_F1d, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1151
    else
P
pbrook 已提交
1152
        tcg_gen_ld_f32(cpu_F1s, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1153 1154 1155 1156 1157
}

static inline void gen_mov_vreg_F0(int dp, int reg)
{
    if (dp)
P
pbrook 已提交
1158
        tcg_gen_st_f64(cpu_F0d, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1159
    else
P
pbrook 已提交
1160
        tcg_gen_st_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg));
B
bellard 已提交
1161 1162
}

1163 1164
#define ARM_CP_RW_BIT	(1 << 20)

P
pbrook 已提交
1165
static inline void iwmmxt_load_reg(TCGv_i64 var, int reg)
P
pbrook 已提交
1166
{
1167
    tcg_gen_ld_i64(var, cpu_env, offsetof(CPUARMState, iwmmxt.regs[reg]));
P
pbrook 已提交
1168 1169
}

P
pbrook 已提交
1170
static inline void iwmmxt_store_reg(TCGv_i64 var, int reg)
P
pbrook 已提交
1171
{
1172
    tcg_gen_st_i64(var, cpu_env, offsetof(CPUARMState, iwmmxt.regs[reg]));
P
pbrook 已提交
1173 1174
}

1175
static inline TCGv_i32 iwmmxt_load_creg(int reg)
P
pbrook 已提交
1176
{
1177
    TCGv_i32 var = tcg_temp_new_i32();
1178
    tcg_gen_ld_i32(var, cpu_env, offsetof(CPUARMState, iwmmxt.cregs[reg]));
1179
    return var;
P
pbrook 已提交
1180 1181
}

1182
static inline void iwmmxt_store_creg(int reg, TCGv_i32 var)
P
pbrook 已提交
1183
{
1184
    tcg_gen_st_i32(var, cpu_env, offsetof(CPUARMState, iwmmxt.cregs[reg]));
1185
    tcg_temp_free_i32(var);
P
pbrook 已提交
1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222
}

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

1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233
#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 已提交
1234

1235
#define IWMMXT_OP_ENV1(name) \
P
pbrook 已提交
1236 1237
static inline void gen_op_iwmmxt_##name##_M0(void) \
{ \
1238
    gen_helper_iwmmxt_##name(cpu_M0, cpu_env, cpu_M0); \
P
pbrook 已提交
1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251
}

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)

1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287
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 已提交
1288 1289 1290

IWMMXT_OP(msadb)

1291 1292 1293 1294 1295 1296
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 已提交
1297 1298 1299

static void gen_op_iwmmxt_set_mup(void)
{
1300
    TCGv_i32 tmp;
P
pbrook 已提交
1301 1302 1303 1304 1305 1306 1307
    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)
{
1308
    TCGv_i32 tmp;
P
pbrook 已提交
1309 1310 1311 1312 1313 1314 1315
    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)
{
1316
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
1317 1318 1319 1320 1321 1322 1323
    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 已提交
1324
    tcg_gen_ext32u_i64(cpu_V1, cpu_V1);
P
pbrook 已提交
1325 1326 1327
    tcg_gen_add_i64(cpu_M0, cpu_M0, cpu_V1);
}

1328 1329
static inline int gen_iwmmxt_address(DisasContext *s, uint32_t insn,
                                     TCGv_i32 dest)
1330 1331 1332
{
    int rd;
    uint32_t offset;
1333
    TCGv_i32 tmp;
1334 1335

    rd = (insn >> 16) & 0xf;
1336
    tmp = load_reg(s, rd);
1337 1338 1339 1340 1341

    offset = (insn & 0xff) << ((insn >> 7) & 2);
    if (insn & (1 << 24)) {
        /* Pre indexed */
        if (insn & (1 << 23))
1342
            tcg_gen_addi_i32(tmp, tmp, offset);
1343
        else
1344 1345
            tcg_gen_addi_i32(tmp, tmp, -offset);
        tcg_gen_mov_i32(dest, tmp);
1346
        if (insn & (1 << 21))
1347 1348
            store_reg(s, rd, tmp);
        else
1349
            tcg_temp_free_i32(tmp);
1350 1351
    } else if (insn & (1 << 21)) {
        /* Post indexed */
1352
        tcg_gen_mov_i32(dest, tmp);
1353
        if (insn & (1 << 23))
1354
            tcg_gen_addi_i32(tmp, tmp, offset);
1355
        else
1356 1357
            tcg_gen_addi_i32(tmp, tmp, -offset);
        store_reg(s, rd, tmp);
1358 1359 1360 1361 1362
    } else if (!(insn & (1 << 23)))
        return 1;
    return 0;
}

1363
static inline int gen_iwmmxt_shift(uint32_t insn, uint32_t mask, TCGv_i32 dest)
1364 1365
{
    int rd = (insn >> 0) & 0xf;
1366
    TCGv_i32 tmp;
1367

1368 1369
    if (insn & (1 << 8)) {
        if (rd < ARM_IWMMXT_wCGR0 || rd > ARM_IWMMXT_wCGR3) {
1370
            return 1;
1371 1372 1373 1374
        } else {
            tmp = iwmmxt_load_creg(rd);
        }
    } else {
1375
        tmp = tcg_temp_new_i32();
1376 1377 1378 1379 1380
        iwmmxt_load_reg(cpu_V0, rd);
        tcg_gen_trunc_i64_i32(tmp, cpu_V0);
    }
    tcg_gen_andi_i32(tmp, tmp, mask);
    tcg_gen_mov_i32(dest, tmp);
1381
    tcg_temp_free_i32(tmp);
1382 1383 1384
    return 0;
}

1385
/* Disassemble an iwMMXt instruction.  Returns nonzero if an error occurred
1386
   (ie. an undefined instruction).  */
1387
static int disas_iwmmxt_insn(CPUARMState *env, DisasContext *s, uint32_t insn)
1388 1389 1390
{
    int rd, wrd;
    int rdhi, rdlo, rd0, rd1, i;
1391 1392
    TCGv_i32 addr;
    TCGv_i32 tmp, tmp2, tmp3;
1393 1394 1395 1396 1397 1398 1399

    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 */
1400 1401 1402 1403
                iwmmxt_load_reg(cpu_V0, wrd);
                tcg_gen_trunc_i64_i32(cpu_R[rdlo], cpu_V0);
                tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
                tcg_gen_trunc_i64_i32(cpu_R[rdhi], cpu_V0);
1404
            } else {					/* TMCRR */
1405 1406
                tcg_gen_concat_i32_i64(cpu_V0, cpu_R[rdlo], cpu_R[rdhi]);
                iwmmxt_store_reg(cpu_V0, wrd);
1407 1408 1409 1410 1411 1412
                gen_op_iwmmxt_set_mup();
            }
            return 0;
        }

        wrd = (insn >> 12) & 0xf;
1413
        addr = tcg_temp_new_i32();
1414
        if (gen_iwmmxt_address(s, insn, addr)) {
1415
            tcg_temp_free_i32(addr);
1416
            return 1;
1417
        }
1418 1419
        if (insn & ARM_CP_RW_BIT) {
            if ((insn >> 28) == 0xf) {			/* WLDRW wCx */
1420
                tmp = tcg_temp_new_i32();
1421 1422
                tcg_gen_qemu_ld32u(tmp, addr, IS_USER(s));
                iwmmxt_store_creg(wrd, tmp);
1423
            } else {
P
pbrook 已提交
1424 1425 1426
                i = 1;
                if (insn & (1 << 8)) {
                    if (insn & (1 << 22)) {		/* WLDRD */
1427
                        tcg_gen_qemu_ld64(cpu_M0, addr, IS_USER(s));
P
pbrook 已提交
1428 1429
                        i = 0;
                    } else {				/* WLDRW wRd */
1430 1431
                        tmp = tcg_temp_new_i32();
                        tcg_gen_qemu_ld32u(tmp, addr, IS_USER(s));
P
pbrook 已提交
1432 1433
                    }
                } else {
1434
                    tmp = tcg_temp_new_i32();
P
pbrook 已提交
1435
                    if (insn & (1 << 22)) {		/* WLDRH */
1436
                        tcg_gen_qemu_ld16u(tmp, addr, IS_USER(s));
P
pbrook 已提交
1437
                    } else {				/* WLDRB */
1438
                        tcg_gen_qemu_ld8u(tmp, addr, IS_USER(s));
P
pbrook 已提交
1439 1440 1441 1442
                    }
                }
                if (i) {
                    tcg_gen_extu_i32_i64(cpu_M0, tmp);
1443
                    tcg_temp_free_i32(tmp);
P
pbrook 已提交
1444
                }
1445 1446 1447 1448
                gen_op_iwmmxt_movq_wRn_M0(wrd);
            }
        } else {
            if ((insn >> 28) == 0xf) {			/* WSTRW wCx */
1449
                tmp = iwmmxt_load_creg(wrd);
1450
                tcg_gen_qemu_st32(tmp, addr, IS_USER(s));
1451 1452
            } else {
                gen_op_iwmmxt_movq_M0_wRn(wrd);
1453
                tmp = tcg_temp_new_i32();
P
pbrook 已提交
1454 1455
                if (insn & (1 << 8)) {
                    if (insn & (1 << 22)) {		/* WSTRD */
1456
                        tcg_gen_qemu_st64(cpu_M0, addr, IS_USER(s));
P
pbrook 已提交
1457 1458
                    } else {				/* WSTRW wRd */
                        tcg_gen_trunc_i64_i32(tmp, cpu_M0);
1459
                        tcg_gen_qemu_st32(tmp, addr, IS_USER(s));
P
pbrook 已提交
1460 1461 1462 1463
                    }
                } else {
                    if (insn & (1 << 22)) {		/* WSTRH */
                        tcg_gen_trunc_i64_i32(tmp, cpu_M0);
1464
                        tcg_gen_qemu_st16(tmp, addr, IS_USER(s));
P
pbrook 已提交
1465 1466
                    } else {				/* WSTRB */
                        tcg_gen_trunc_i64_i32(tmp, cpu_M0);
1467
                        tcg_gen_qemu_st8(tmp, addr, IS_USER(s));
P
pbrook 已提交
1468 1469
                    }
                }
1470
            }
1471
            tcg_temp_free_i32(tmp);
1472
        }
1473
        tcg_temp_free_i32(addr);
1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504
        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:
1505 1506
            tmp = iwmmxt_load_creg(wrd);
            tmp2 = load_reg(s, rd);
1507
            tcg_gen_andc_i32(tmp, tmp, tmp2);
1508
            tcg_temp_free_i32(tmp2);
1509
            iwmmxt_store_creg(wrd, tmp);
1510 1511 1512 1513 1514 1515
            break;
        case ARM_IWMMXT_wCGR0:
        case ARM_IWMMXT_wCGR1:
        case ARM_IWMMXT_wCGR2:
        case ARM_IWMMXT_wCGR3:
            gen_op_iwmmxt_set_cup();
1516 1517
            tmp = load_reg(s, rd);
            iwmmxt_store_creg(wrd, tmp);
1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538
            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;
1539 1540
        tmp = iwmmxt_load_creg(wrd);
        store_reg(s, rd, tmp);
1541 1542 1543 1544 1545 1546
        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 已提交
1547
        tcg_gen_neg_i64(cpu_M0, cpu_M0);
1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639
        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 已提交
1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650
        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);
        }
1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663
        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 已提交
1664 1665
            iwmmxt_load_reg(cpu_V1, wrd);
            tcg_gen_add_i64(cpu_M0, cpu_M0, cpu_V1);
1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696
        }
        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 已提交
1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707
        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);
        }
1708 1709 1710 1711 1712 1713 1714 1715 1716
        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);
1717 1718 1719 1720
        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);
1721
        tcg_temp_free_i32(tmp);
1722 1723 1724 1725
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        break;
    case 0x601: case 0x605: case 0x609: case 0x60d:	/* TINSR */
1726 1727
        if (((insn >> 6) & 3) == 3)
            return 1;
1728 1729
        rd = (insn >> 12) & 0xf;
        wrd = (insn >> 16) & 0xf;
1730
        tmp = load_reg(s, rd);
1731 1732 1733
        gen_op_iwmmxt_movq_M0_wRn(wrd);
        switch ((insn >> 6) & 3) {
        case 0:
1734 1735
            tmp2 = tcg_const_i32(0xff);
            tmp3 = tcg_const_i32((insn & 7) << 3);
1736 1737
            break;
        case 1:
1738 1739
            tmp2 = tcg_const_i32(0xffff);
            tmp3 = tcg_const_i32((insn & 3) << 4);
1740 1741
            break;
        case 2:
1742 1743
            tmp2 = tcg_const_i32(0xffffffff);
            tmp3 = tcg_const_i32((insn & 1) << 5);
1744
            break;
1745
        default:
1746 1747
            TCGV_UNUSED_I32(tmp2);
            TCGV_UNUSED_I32(tmp3);
1748
        }
1749
        gen_helper_iwmmxt_insr(cpu_M0, cpu_M0, tmp, tmp2, tmp3);
1750 1751
        tcg_temp_free_i32(tmp3);
        tcg_temp_free_i32(tmp2);
1752
        tcg_temp_free_i32(tmp);
1753 1754 1755 1756 1757 1758
        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;
1759
        if (rd == 15 || ((insn >> 22) & 3) == 3)
1760 1761
            return 1;
        gen_op_iwmmxt_movq_M0_wRn(wrd);
1762
        tmp = tcg_temp_new_i32();
1763 1764
        switch ((insn >> 22) & 3) {
        case 0:
1765 1766 1767 1768 1769 1770
            tcg_gen_shri_i64(cpu_M0, cpu_M0, (insn & 7) << 3);
            tcg_gen_trunc_i64_i32(tmp, cpu_M0);
            if (insn & 8) {
                tcg_gen_ext8s_i32(tmp, tmp);
            } else {
                tcg_gen_andi_i32(tmp, tmp, 0xff);
1771 1772 1773
            }
            break;
        case 1:
1774 1775 1776 1777 1778 1779
            tcg_gen_shri_i64(cpu_M0, cpu_M0, (insn & 3) << 4);
            tcg_gen_trunc_i64_i32(tmp, cpu_M0);
            if (insn & 8) {
                tcg_gen_ext16s_i32(tmp, tmp);
            } else {
                tcg_gen_andi_i32(tmp, tmp, 0xffff);
1780 1781 1782
            }
            break;
        case 2:
1783 1784
            tcg_gen_shri_i64(cpu_M0, cpu_M0, (insn & 1) << 5);
            tcg_gen_trunc_i64_i32(tmp, cpu_M0);
1785 1786
            break;
        }
1787
        store_reg(s, rd, tmp);
1788 1789
        break;
    case 0x117: case 0x517: case 0x917: case 0xd17:	/* TEXTRC */
1790
        if ((insn & 0x000ff008) != 0x0003f000 || ((insn >> 22) & 3) == 3)
1791
            return 1;
1792
        tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF);
1793 1794
        switch ((insn >> 22) & 3) {
        case 0:
1795
            tcg_gen_shri_i32(tmp, tmp, ((insn & 7) << 2) + 0);
1796 1797
            break;
        case 1:
1798
            tcg_gen_shri_i32(tmp, tmp, ((insn & 3) << 3) + 4);
1799 1800
            break;
        case 2:
1801
            tcg_gen_shri_i32(tmp, tmp, ((insn & 1) << 4) + 12);
1802 1803
            break;
        }
1804 1805
        tcg_gen_shli_i32(tmp, tmp, 28);
        gen_set_nzcv(tmp);
1806
        tcg_temp_free_i32(tmp);
1807 1808
        break;
    case 0x401: case 0x405: case 0x409: case 0x40d:	/* TBCST */
1809 1810
        if (((insn >> 6) & 3) == 3)
            return 1;
1811 1812
        rd = (insn >> 12) & 0xf;
        wrd = (insn >> 16) & 0xf;
1813
        tmp = load_reg(s, rd);
1814 1815
        switch ((insn >> 6) & 3) {
        case 0:
1816
            gen_helper_iwmmxt_bcstb(cpu_M0, tmp);
1817 1818
            break;
        case 1:
1819
            gen_helper_iwmmxt_bcstw(cpu_M0, tmp);
1820 1821
            break;
        case 2:
1822
            gen_helper_iwmmxt_bcstl(cpu_M0, tmp);
1823 1824
            break;
        }
1825
        tcg_temp_free_i32(tmp);
1826 1827 1828 1829
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        break;
    case 0x113: case 0x513: case 0x913: case 0xd13:	/* TANDC */
1830
        if ((insn & 0x000ff00f) != 0x0003f000 || ((insn >> 22) & 3) == 3)
1831
            return 1;
1832
        tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF);
1833
        tmp2 = tcg_temp_new_i32();
1834
        tcg_gen_mov_i32(tmp2, tmp);
1835 1836 1837
        switch ((insn >> 22) & 3) {
        case 0:
            for (i = 0; i < 7; i ++) {
1838 1839
                tcg_gen_shli_i32(tmp2, tmp2, 4);
                tcg_gen_and_i32(tmp, tmp, tmp2);
1840 1841 1842 1843
            }
            break;
        case 1:
            for (i = 0; i < 3; i ++) {
1844 1845
                tcg_gen_shli_i32(tmp2, tmp2, 8);
                tcg_gen_and_i32(tmp, tmp, tmp2);
1846 1847 1848
            }
            break;
        case 2:
1849 1850
            tcg_gen_shli_i32(tmp2, tmp2, 16);
            tcg_gen_and_i32(tmp, tmp, tmp2);
1851 1852
            break;
        }
1853
        gen_set_nzcv(tmp);
1854 1855
        tcg_temp_free_i32(tmp2);
        tcg_temp_free_i32(tmp);
1856 1857 1858 1859 1860 1861 1862
        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 已提交
1863
            gen_helper_iwmmxt_addcb(cpu_M0, cpu_M0);
1864 1865
            break;
        case 1:
P
pbrook 已提交
1866
            gen_helper_iwmmxt_addcw(cpu_M0, cpu_M0);
1867 1868
            break;
        case 2:
P
pbrook 已提交
1869
            gen_helper_iwmmxt_addcl(cpu_M0, cpu_M0);
1870 1871 1872 1873 1874 1875 1876 1877
            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 */
1878
        if ((insn & 0x000ff00f) != 0x0003f000 || ((insn >> 22) & 3) == 3)
1879
            return 1;
1880
        tmp = iwmmxt_load_creg(ARM_IWMMXT_wCASF);
1881
        tmp2 = tcg_temp_new_i32();
1882
        tcg_gen_mov_i32(tmp2, tmp);
1883 1884 1885
        switch ((insn >> 22) & 3) {
        case 0:
            for (i = 0; i < 7; i ++) {
1886 1887
                tcg_gen_shli_i32(tmp2, tmp2, 4);
                tcg_gen_or_i32(tmp, tmp, tmp2);
1888 1889 1890 1891
            }
            break;
        case 1:
            for (i = 0; i < 3; i ++) {
1892 1893
                tcg_gen_shli_i32(tmp2, tmp2, 8);
                tcg_gen_or_i32(tmp, tmp, tmp2);
1894 1895 1896
            }
            break;
        case 2:
1897 1898
            tcg_gen_shli_i32(tmp2, tmp2, 16);
            tcg_gen_or_i32(tmp, tmp, tmp2);
1899 1900
            break;
        }
1901
        gen_set_nzcv(tmp);
1902 1903
        tcg_temp_free_i32(tmp2);
        tcg_temp_free_i32(tmp);
1904 1905 1906 1907
        break;
    case 0x103: case 0x503: case 0x903: case 0xd03:	/* TMOVMSK */
        rd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
1908
        if ((insn & 0xf) != 0 || ((insn >> 22) & 3) == 3)
1909 1910
            return 1;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
1911
        tmp = tcg_temp_new_i32();
1912 1913
        switch ((insn >> 22) & 3) {
        case 0:
1914
            gen_helper_iwmmxt_msbb(tmp, cpu_M0);
1915 1916
            break;
        case 1:
1917
            gen_helper_iwmmxt_msbw(tmp, cpu_M0);
1918 1919
            break;
        case 2:
1920
            gen_helper_iwmmxt_msbl(tmp, cpu_M0);
1921 1922
            break;
        }
1923
        store_reg(s, rd, tmp);
1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 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 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020
        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:
2021 2022
        if (((insn >> 22) & 3) == 0)
            return 1;
2023 2024 2025
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
2026
        tmp = tcg_temp_new_i32();
2027
        if (gen_iwmmxt_shift(insn, 0xff, tmp)) {
2028
            tcg_temp_free_i32(tmp);
2029
            return 1;
2030
        }
2031 2032
        switch ((insn >> 22) & 3) {
        case 1:
2033
            gen_helper_iwmmxt_srlw(cpu_M0, cpu_env, cpu_M0, tmp);
2034 2035
            break;
        case 2:
2036
            gen_helper_iwmmxt_srll(cpu_M0, cpu_env, cpu_M0, tmp);
2037 2038
            break;
        case 3:
2039
            gen_helper_iwmmxt_srlq(cpu_M0, cpu_env, cpu_M0, tmp);
2040 2041
            break;
        }
2042
        tcg_temp_free_i32(tmp);
2043 2044 2045 2046 2047 2048
        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:
2049 2050
        if (((insn >> 22) & 3) == 0)
            return 1;
2051 2052 2053
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
2054
        tmp = tcg_temp_new_i32();
2055
        if (gen_iwmmxt_shift(insn, 0xff, tmp)) {
2056
            tcg_temp_free_i32(tmp);
2057
            return 1;
2058
        }
2059 2060
        switch ((insn >> 22) & 3) {
        case 1:
2061
            gen_helper_iwmmxt_sraw(cpu_M0, cpu_env, cpu_M0, tmp);
2062 2063
            break;
        case 2:
2064
            gen_helper_iwmmxt_sral(cpu_M0, cpu_env, cpu_M0, tmp);
2065 2066
            break;
        case 3:
2067
            gen_helper_iwmmxt_sraq(cpu_M0, cpu_env, cpu_M0, tmp);
2068 2069
            break;
        }
2070
        tcg_temp_free_i32(tmp);
2071 2072 2073 2074 2075 2076
        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:
2077 2078
        if (((insn >> 22) & 3) == 0)
            return 1;
2079 2080 2081
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
2082
        tmp = tcg_temp_new_i32();
2083
        if (gen_iwmmxt_shift(insn, 0xff, tmp)) {
2084
            tcg_temp_free_i32(tmp);
2085
            return 1;
2086
        }
2087 2088
        switch ((insn >> 22) & 3) {
        case 1:
2089
            gen_helper_iwmmxt_sllw(cpu_M0, cpu_env, cpu_M0, tmp);
2090 2091
            break;
        case 2:
2092
            gen_helper_iwmmxt_slll(cpu_M0, cpu_env, cpu_M0, tmp);
2093 2094
            break;
        case 3:
2095
            gen_helper_iwmmxt_sllq(cpu_M0, cpu_env, cpu_M0, tmp);
2096 2097
            break;
        }
2098
        tcg_temp_free_i32(tmp);
2099 2100 2101 2102 2103 2104
        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:
2105 2106
        if (((insn >> 22) & 3) == 0)
            return 1;
2107 2108 2109
        wrd = (insn >> 12) & 0xf;
        rd0 = (insn >> 16) & 0xf;
        gen_op_iwmmxt_movq_M0_wRn(rd0);
2110
        tmp = tcg_temp_new_i32();
2111 2112
        switch ((insn >> 22) & 3) {
        case 1:
2113
            if (gen_iwmmxt_shift(insn, 0xf, tmp)) {
2114
                tcg_temp_free_i32(tmp);
2115
                return 1;
2116
            }
2117
            gen_helper_iwmmxt_rorw(cpu_M0, cpu_env, cpu_M0, tmp);
2118 2119
            break;
        case 2:
2120
            if (gen_iwmmxt_shift(insn, 0x1f, tmp)) {
2121
                tcg_temp_free_i32(tmp);
2122
                return 1;
2123
            }
2124
            gen_helper_iwmmxt_rorl(cpu_M0, cpu_env, cpu_M0, tmp);
2125 2126
            break;
        case 3:
2127
            if (gen_iwmmxt_shift(insn, 0x3f, tmp)) {
2128
                tcg_temp_free_i32(tmp);
2129
                return 1;
2130
            }
2131
            gen_helper_iwmmxt_rorq(cpu_M0, cpu_env, cpu_M0, tmp);
2132 2133
            break;
        }
2134
        tcg_temp_free_i32(tmp);
2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206
        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);
2207 2208 2209
        tmp = tcg_const_i32((insn >> 20) & 3);
        iwmmxt_load_reg(cpu_V1, rd1);
        gen_helper_iwmmxt_align(cpu_M0, cpu_M0, cpu_V1, tmp);
2210
        tcg_temp_free_i32(tmp);
2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263
        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);
2264
        tmp = tcg_const_i32(((insn >> 16) & 0xf0) | (insn & 0x0f));
2265
        gen_helper_iwmmxt_shufh(cpu_M0, cpu_env, cpu_M0, tmp);
2266
        tcg_temp_free_i32(tmp);
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
        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:
2318 2319
        if (!(insn & (1 << 20)) || ((insn >> 22) & 3) == 0)
            return 1;
2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357
        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);
2358 2359
        tmp = load_reg(s, rd0);
        tmp2 = load_reg(s, rd1);
2360 2361
        switch ((insn >> 16) & 0xf) {
        case 0x0:					/* TMIA */
2362
            gen_helper_iwmmxt_muladdsl(cpu_M0, cpu_M0, tmp, tmp2);
2363 2364
            break;
        case 0x8:					/* TMIAPH */
2365
            gen_helper_iwmmxt_muladdsw(cpu_M0, cpu_M0, tmp, tmp2);
2366 2367 2368
            break;
        case 0xc: case 0xd: case 0xe: case 0xf:		/* TMIAxy */
            if (insn & (1 << 16))
2369
                tcg_gen_shri_i32(tmp, tmp, 16);
2370
            if (insn & (1 << 17))
2371 2372
                tcg_gen_shri_i32(tmp2, tmp2, 16);
            gen_helper_iwmmxt_muladdswl(cpu_M0, cpu_M0, tmp, tmp2);
2373 2374
            break;
        default:
2375 2376
            tcg_temp_free_i32(tmp2);
            tcg_temp_free_i32(tmp);
2377 2378
            return 1;
        }
2379 2380
        tcg_temp_free_i32(tmp2);
        tcg_temp_free_i32(tmp);
2381 2382 2383 2384 2385 2386 2387 2388 2389 2390
        gen_op_iwmmxt_movq_wRn_M0(wrd);
        gen_op_iwmmxt_set_mup();
        break;
    default:
        return 1;
    }

    return 0;
}

2391
/* Disassemble an XScale DSP instruction.  Returns nonzero if an error occurred
2392
   (ie. an undefined instruction).  */
2393
static int disas_dsp_insn(CPUARMState *env, DisasContext *s, uint32_t insn)
2394 2395
{
    int acc, rd0, rd1, rdhi, rdlo;
2396
    TCGv_i32 tmp, tmp2;
2397 2398 2399 2400 2401 2402 2403 2404 2405 2406

    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;

2407 2408
        tmp = load_reg(s, rd0);
        tmp2 = load_reg(s, rd1);
2409 2410
        switch ((insn >> 16) & 0xf) {
        case 0x0:					/* MIA */
2411
            gen_helper_iwmmxt_muladdsl(cpu_M0, cpu_M0, tmp, tmp2);
2412 2413
            break;
        case 0x8:					/* MIAPH */
2414
            gen_helper_iwmmxt_muladdsw(cpu_M0, cpu_M0, tmp, tmp2);
2415 2416 2417 2418 2419 2420
            break;
        case 0xc:					/* MIABB */
        case 0xd:					/* MIABT */
        case 0xe:					/* MIATB */
        case 0xf:					/* MIATT */
            if (insn & (1 << 16))
2421
                tcg_gen_shri_i32(tmp, tmp, 16);
2422
            if (insn & (1 << 17))
2423 2424
                tcg_gen_shri_i32(tmp2, tmp2, 16);
            gen_helper_iwmmxt_muladdswl(cpu_M0, cpu_M0, tmp, tmp2);
2425 2426 2427 2428
            break;
        default:
            return 1;
        }
2429 2430
        tcg_temp_free_i32(tmp2);
        tcg_temp_free_i32(tmp);
2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445

        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 */
2446 2447 2448 2449 2450
            iwmmxt_load_reg(cpu_V0, acc);
            tcg_gen_trunc_i64_i32(cpu_R[rdlo], cpu_V0);
            tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
            tcg_gen_trunc_i64_i32(cpu_R[rdhi], cpu_V0);
            tcg_gen_andi_i32(cpu_R[rdhi], cpu_R[rdhi], (1 << (40 - 32)) - 1);
2451
        } else {					/* MAR */
2452 2453
            tcg_gen_concat_i32_i64(cpu_V0, cpu_R[rdlo], cpu_R[rdhi]);
            iwmmxt_store_reg(cpu_V0, acc);
2454 2455 2456 2457 2458 2459 2460
        }
        return 0;
    }

    return 1;
}

P
pbrook 已提交
2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480
#define VFP_REG_SHR(x, n) (((n) > 0) ? (x) >> (n) : (x) << -(n))
#define VFP_SREG(insn, bigbit, smallbit) \
  ((VFP_REG_SHR(insn, bigbit - 1) & 0x1e) | (((insn) >> (smallbit)) & 1))
#define VFP_DREG(reg, insn, bigbit, smallbit) do { \
    if (arm_feature(env, ARM_FEATURE_VFP3)) { \
        reg = (((insn) >> (bigbit)) & 0x0f) \
              | (((insn) >> ((smallbit) - 4)) & 0x10); \
    } else { \
        if (insn & (1 << (smallbit))) \
            return 1; \
        reg = ((insn) >> (bigbit)) & 0x0f; \
    }} while (0)

#define VFP_SREG_D(insn) VFP_SREG(insn, 12, 22)
#define VFP_DREG_D(reg, insn) VFP_DREG(reg, insn, 12, 22)
#define VFP_SREG_N(insn) VFP_SREG(insn, 16,  7)
#define VFP_DREG_N(reg, insn) VFP_DREG(reg, insn, 16,  7)
#define VFP_SREG_M(insn) VFP_SREG(insn,  0,  5)
#define VFP_DREG_M(reg, insn) VFP_DREG(reg, insn,  0,  5)

P
pbrook 已提交
2481
/* Move between integer and VFP cores.  */
2482
static TCGv_i32 gen_vfp_mrs(void)
P
pbrook 已提交
2483
{
2484
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
2485 2486 2487 2488
    tcg_gen_mov_i32(tmp, cpu_F0s);
    return tmp;
}

2489
static void gen_vfp_msr(TCGv_i32 tmp)
P
pbrook 已提交
2490 2491
{
    tcg_gen_mov_i32(cpu_F0s, tmp);
2492
    tcg_temp_free_i32(tmp);
P
pbrook 已提交
2493 2494
}

2495
static void gen_neon_dup_u8(TCGv_i32 var, int shift)
P
pbrook 已提交
2496
{
2497
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
2498 2499
    if (shift)
        tcg_gen_shri_i32(var, var, shift);
P
pbrook 已提交
2500
    tcg_gen_ext8u_i32(var, var);
P
pbrook 已提交
2501 2502 2503 2504
    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);
2505
    tcg_temp_free_i32(tmp);
P
pbrook 已提交
2506 2507
}

2508
static void gen_neon_dup_low16(TCGv_i32 var)
P
pbrook 已提交
2509
{
2510
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
2511
    tcg_gen_ext16u_i32(var, var);
P
pbrook 已提交
2512 2513
    tcg_gen_shli_i32(tmp, var, 16);
    tcg_gen_or_i32(var, var, tmp);
2514
    tcg_temp_free_i32(tmp);
P
pbrook 已提交
2515 2516
}

2517
static void gen_neon_dup_high16(TCGv_i32 var)
P
pbrook 已提交
2518
{
2519
    TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
2520 2521 2522
    tcg_gen_andi_i32(var, var, 0xffff0000);
    tcg_gen_shri_i32(tmp, var, 16);
    tcg_gen_or_i32(var, var, tmp);
2523
    tcg_temp_free_i32(tmp);
P
pbrook 已提交
2524 2525
}

2526
static TCGv_i32 gen_load_and_replicate(DisasContext *s, TCGv_i32 addr, int size)
2527 2528
{
    /* Load a single Neon element and replicate into a 32 bit TCG reg */
2529
    TCGv_i32 tmp = tcg_temp_new_i32();
2530 2531
    switch (size) {
    case 0:
2532
        tcg_gen_qemu_ld8u(tmp, addr, IS_USER(s));
2533 2534 2535
        gen_neon_dup_u8(tmp, 0);
        break;
    case 1:
2536
        tcg_gen_qemu_ld16u(tmp, addr, IS_USER(s));
2537 2538 2539
        gen_neon_dup_low16(tmp);
        break;
    case 2:
2540
        tcg_gen_qemu_ld32u(tmp, addr, IS_USER(s));
2541 2542 2543 2544 2545 2546 2547
        break;
    default: /* Avoid compiler warnings.  */
        abort();
    }
    return tmp;
}

2548
/* Disassemble a VFP instruction.  Returns nonzero if an error occurred
B
bellard 已提交
2549
   (ie. an undefined instruction).  */
2550
static int disas_vfp_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
B
bellard 已提交
2551 2552 2553
{
    uint32_t rd, rn, rm, op, i, n, offset, delta_d, delta_m, bank_mask;
    int dp, veclen;
2554 2555 2556
    TCGv_i32 addr;
    TCGv_i32 tmp;
    TCGv_i32 tmp2;
B
bellard 已提交
2557

P
pbrook 已提交
2558 2559 2560
    if (!arm_feature(env, ARM_FEATURE_VFP))
        return 1;

2561
    if (!s->vfp_enabled) {
P
pbrook 已提交
2562
        /* VFP disabled.  Only allow fmxr/fmrx to/from some control regs.  */
P
pbrook 已提交
2563 2564 2565
        if ((insn & 0x0fe00fff) != 0x0ee00a10)
            return 1;
        rn = (insn >> 16) & 0xf;
P
pbrook 已提交
2566 2567
        if (rn != ARM_VFP_FPSID && rn != ARM_VFP_FPEXC
            && rn != ARM_VFP_MVFR1 && rn != ARM_VFP_MVFR0)
P
pbrook 已提交
2568 2569
            return 1;
    }
B
bellard 已提交
2570 2571 2572 2573 2574 2575 2576
    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 已提交
2577 2578 2579 2580 2581
                int size;
                int pass;

                VFP_DREG_N(rn, insn);
                if (insn & 0xf)
B
bellard 已提交
2582
                    return 1;
P
pbrook 已提交
2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597
                if (insn & 0x00c00060
                    && !arm_feature(env, ARM_FEATURE_NEON))
                    return 1;

                pass = (insn >> 21) & 1;
                if (insn & (1 << 22)) {
                    size = 0;
                    offset = ((insn >> 5) & 3) * 8;
                } else if (insn & (1 << 5)) {
                    size = 1;
                    offset = (insn & (1 << 6)) ? 16 : 0;
                } else {
                    size = 2;
                    offset = 0;
                }
2598
                if (insn & ARM_CP_RW_BIT) {
B
bellard 已提交
2599
                    /* vfp->arm */
P
pbrook 已提交
2600
                    tmp = neon_load_reg(rn, pass);
P
pbrook 已提交
2601 2602 2603
                    switch (size) {
                    case 0:
                        if (offset)
P
pbrook 已提交
2604
                            tcg_gen_shri_i32(tmp, tmp, offset);
P
pbrook 已提交
2605
                        if (insn & (1 << 23))
P
pbrook 已提交
2606
                            gen_uxtb(tmp);
P
pbrook 已提交
2607
                        else
P
pbrook 已提交
2608
                            gen_sxtb(tmp);
P
pbrook 已提交
2609 2610 2611 2612
                        break;
                    case 1:
                        if (insn & (1 << 23)) {
                            if (offset) {
P
pbrook 已提交
2613
                                tcg_gen_shri_i32(tmp, tmp, 16);
P
pbrook 已提交
2614
                            } else {
P
pbrook 已提交
2615
                                gen_uxth(tmp);
P
pbrook 已提交
2616 2617 2618
                            }
                        } else {
                            if (offset) {
P
pbrook 已提交
2619
                                tcg_gen_sari_i32(tmp, tmp, 16);
P
pbrook 已提交
2620
                            } else {
P
pbrook 已提交
2621
                                gen_sxth(tmp);
P
pbrook 已提交
2622 2623 2624 2625 2626 2627
                            }
                        }
                        break;
                    case 2:
                        break;
                    }
P
pbrook 已提交
2628
                    store_reg(s, rd, tmp);
B
bellard 已提交
2629 2630
                } else {
                    /* arm->vfp */
P
pbrook 已提交
2631
                    tmp = load_reg(s, rd);
P
pbrook 已提交
2632 2633 2634
                    if (insn & (1 << 23)) {
                        /* VDUP */
                        if (size == 0) {
P
pbrook 已提交
2635
                            gen_neon_dup_u8(tmp, 0);
P
pbrook 已提交
2636
                        } else if (size == 1) {
P
pbrook 已提交
2637
                            gen_neon_dup_low16(tmp);
P
pbrook 已提交
2638
                        }
P
pbrook 已提交
2639
                        for (n = 0; n <= pass * 2; n++) {
2640
                            tmp2 = tcg_temp_new_i32();
P
pbrook 已提交
2641 2642 2643 2644
                            tcg_gen_mov_i32(tmp2, tmp);
                            neon_store_reg(rn, n, tmp2);
                        }
                        neon_store_reg(rn, n, tmp);
P
pbrook 已提交
2645 2646 2647 2648
                    } else {
                        /* VMOV */
                        switch (size) {
                        case 0:
P
pbrook 已提交
2649
                            tmp2 = neon_load_reg(rn, pass);
2650
                            tcg_gen_deposit_i32(tmp, tmp2, tmp, offset, 8);
2651
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
2652 2653
                            break;
                        case 1:
P
pbrook 已提交
2654
                            tmp2 = neon_load_reg(rn, pass);
2655
                            tcg_gen_deposit_i32(tmp, tmp2, tmp, offset, 16);
2656
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
2657 2658 2659 2660
                            break;
                        case 2:
                            break;
                        }
P
pbrook 已提交
2661
                        neon_store_reg(rn, pass, tmp);
P
pbrook 已提交
2662
                    }
B
bellard 已提交
2663
                }
P
pbrook 已提交
2664 2665 2666 2667
            } else { /* !dp */
                if ((insn & 0x6f) != 0x00)
                    return 1;
                rn = VFP_SREG_N(insn);
2668
                if (insn & ARM_CP_RW_BIT) {
B
bellard 已提交
2669 2670 2671
                    /* vfp->arm */
                    if (insn & (1 << 21)) {
                        /* system register */
P
pbrook 已提交
2672
                        rn >>= 1;
P
pbrook 已提交
2673

B
bellard 已提交
2674
                        switch (rn) {
P
pbrook 已提交
2675
                        case ARM_VFP_FPSID:
P
pbrook 已提交
2676
                            /* VFP2 allows access to FSID from userspace.
P
pbrook 已提交
2677 2678 2679 2680 2681
                               VFP3 restricts all id registers to privileged
                               accesses.  */
                            if (IS_USER(s)
                                && arm_feature(env, ARM_FEATURE_VFP3))
                                return 1;
P
pbrook 已提交
2682
                            tmp = load_cpu_field(vfp.xregs[rn]);
P
pbrook 已提交
2683
                            break;
P
pbrook 已提交
2684
                        case ARM_VFP_FPEXC:
P
pbrook 已提交
2685 2686
                            if (IS_USER(s))
                                return 1;
P
pbrook 已提交
2687
                            tmp = load_cpu_field(vfp.xregs[rn]);
P
pbrook 已提交
2688
                            break;
P
pbrook 已提交
2689 2690
                        case ARM_VFP_FPINST:
                        case ARM_VFP_FPINST2:
P
pbrook 已提交
2691 2692 2693 2694
                            /* Not present in VFP3.  */
                            if (IS_USER(s)
                                || arm_feature(env, ARM_FEATURE_VFP3))
                                return 1;
P
pbrook 已提交
2695
                            tmp = load_cpu_field(vfp.xregs[rn]);
B
bellard 已提交
2696
                            break;
P
pbrook 已提交
2697
                        case ARM_VFP_FPSCR:
2698
                            if (rd == 15) {
P
pbrook 已提交
2699 2700 2701
                                tmp = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]);
                                tcg_gen_andi_i32(tmp, tmp, 0xf0000000);
                            } else {
2702
                                tmp = tcg_temp_new_i32();
P
pbrook 已提交
2703 2704
                                gen_helper_vfp_get_fpscr(tmp, cpu_env);
                            }
B
bellard 已提交
2705
                            break;
P
pbrook 已提交
2706 2707 2708
                        case ARM_VFP_MVFR0:
                        case ARM_VFP_MVFR1:
                            if (IS_USER(s)
2709
                                || !arm_feature(env, ARM_FEATURE_MVFR))
P
pbrook 已提交
2710
                                return 1;
P
pbrook 已提交
2711
                            tmp = load_cpu_field(vfp.xregs[rn]);
P
pbrook 已提交
2712
                            break;
B
bellard 已提交
2713 2714 2715 2716 2717
                        default:
                            return 1;
                        }
                    } else {
                        gen_mov_F0_vreg(0, rn);
P
pbrook 已提交
2718
                        tmp = gen_vfp_mrs();
B
bellard 已提交
2719 2720
                    }
                    if (rd == 15) {
B
bellard 已提交
2721
                        /* Set the 4 flag bits in the CPSR.  */
P
pbrook 已提交
2722
                        gen_set_nzcv(tmp);
2723
                        tcg_temp_free_i32(tmp);
P
pbrook 已提交
2724 2725 2726
                    } else {
                        store_reg(s, rd, tmp);
                    }
B
bellard 已提交
2727 2728 2729
                } else {
                    /* arm->vfp */
                    if (insn & (1 << 21)) {
P
pbrook 已提交
2730
                        rn >>= 1;
B
bellard 已提交
2731 2732
                        /* system register */
                        switch (rn) {
P
pbrook 已提交
2733
                        case ARM_VFP_FPSID:
P
pbrook 已提交
2734 2735
                        case ARM_VFP_MVFR0:
                        case ARM_VFP_MVFR1:
B
bellard 已提交
2736 2737
                            /* Writes are ignored.  */
                            break;
P
pbrook 已提交
2738
                        case ARM_VFP_FPSCR:
2739
                            tmp = load_reg(s, rd);
P
pbrook 已提交
2740
                            gen_helper_vfp_set_fpscr(cpu_env, tmp);
2741
                            tcg_temp_free_i32(tmp);
B
bellard 已提交
2742
                            gen_lookup_tb(s);
B
bellard 已提交
2743
                            break;
P
pbrook 已提交
2744
                        case ARM_VFP_FPEXC:
P
pbrook 已提交
2745 2746
                            if (IS_USER(s))
                                return 1;
2747 2748
                            /* TODO: VFP subarchitecture support.
                             * For now, keep the EN bit only */
2749
                            tmp = load_reg(s, rd);
2750
                            tcg_gen_andi_i32(tmp, tmp, 1 << 30);
P
pbrook 已提交
2751
                            store_cpu_field(tmp, vfp.xregs[rn]);
P
pbrook 已提交
2752 2753 2754 2755
                            gen_lookup_tb(s);
                            break;
                        case ARM_VFP_FPINST:
                        case ARM_VFP_FPINST2:
2756
                            tmp = load_reg(s, rd);
P
pbrook 已提交
2757
                            store_cpu_field(tmp, vfp.xregs[rn]);
P
pbrook 已提交
2758
                            break;
B
bellard 已提交
2759 2760 2761 2762
                        default:
                            return 1;
                        }
                    } else {
2763
                        tmp = load_reg(s, rd);
P
pbrook 已提交
2764
                        gen_vfp_msr(tmp);
B
bellard 已提交
2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778
                        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 已提交
2779
                    VFP_DREG_N(rn, insn);
B
bellard 已提交
2780 2781
                }

2782
                if (op == 15 && (rn == 15 || ((rn & 0x1c) == 0x18))) {
B
bellard 已提交
2783
                    /* Integer or single precision destination.  */
P
pbrook 已提交
2784
                    rd = VFP_SREG_D(insn);
B
bellard 已提交
2785
                } else {
P
pbrook 已提交
2786
                    VFP_DREG_D(rd, insn);
B
bellard 已提交
2787
                }
2788 2789 2790 2791 2792 2793
                if (op == 15 &&
                    (((rn & 0x1c) == 0x10) || ((rn & 0x14) == 0x14))) {
                    /* VCVT from int is always from S reg regardless of dp bit.
                     * VCVT with immediate frac_bits has same format as SREG_M
                     */
                    rm = VFP_SREG_M(insn);
B
bellard 已提交
2794
                } else {
P
pbrook 已提交
2795
                    VFP_DREG_M(rm, insn);
B
bellard 已提交
2796 2797
                }
            } else {
P
pbrook 已提交
2798
                rn = VFP_SREG_N(insn);
B
bellard 已提交
2799 2800
                if (op == 15 && rn == 15) {
                    /* Double precision destination.  */
P
pbrook 已提交
2801 2802 2803 2804
                    VFP_DREG_D(rd, insn);
                } else {
                    rd = VFP_SREG_D(insn);
                }
2805 2806 2807
                /* 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 已提交
2808
                rm = VFP_SREG_M(insn);
B
bellard 已提交
2809 2810
            }

2811
            veclen = s->vec_len;
B
bellard 已提交
2812 2813 2814 2815 2816 2817 2818
            if (op == 15 && rn > 3)
                veclen = 0;

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

B
bellard 已提交
2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831
            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)
2832
                        delta_d = (s->vec_stride >> 1) + 1;
B
bellard 已提交
2833
                    else
2834
                        delta_d = s->vec_stride + 1;
B
bellard 已提交
2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865

                    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 已提交
2866 2867 2868 2869
                case 20:
                case 21:
                case 22:
                case 23:
P
pbrook 已提交
2870 2871 2872 2873
                case 28:
                case 29:
                case 30:
                case 31:
P
pbrook 已提交
2874 2875 2876
                    /* Source and destination the same.  */
                    gen_mov_F0_vreg(dp, rd);
                    break;
2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887
                case 4:
                case 5:
                case 6:
                case 7:
                    /* VCVTB, VCVTT: only present with the halfprec extension,
                     * UNPREDICTABLE if bit 8 is set (we choose to UNDEF)
                     */
                    if (dp || !arm_feature(env, ARM_FEATURE_VFP_FP16)) {
                        return 1;
                    }
                    /* Otherwise fall through */
B
bellard 已提交
2888 2889 2890
                default:
                    /* One source operand.  */
                    gen_mov_F0_vreg(dp, rm);
P
pbrook 已提交
2891
                    break;
B
bellard 已提交
2892 2893 2894 2895 2896 2897 2898 2899 2900 2901
                }
            } else {
                /* Two source operands.  */
                gen_mov_F0_vreg(dp, rn);
                gen_mov_F1_vreg(dp, rm);
            }

            for (;;) {
                /* Perform the calculation.  */
                switch (op) {
2902 2903 2904 2905
                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 已提交
2906 2907
                    gen_vfp_add(dp);
                    break;
2908
                case 1: /* VMLS: fd + -(fn * fm) */
B
bellard 已提交
2909
                    gen_vfp_mul(dp);
2910 2911
                    gen_vfp_F1_neg(dp);
                    gen_mov_F0_vreg(dp, rd);
B
bellard 已提交
2912 2913
                    gen_vfp_add(dp);
                    break;
2914 2915 2916 2917 2918 2919 2920 2921 2922
                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 已提交
2923
                    break;
2924
                case 3: /* VNMLA: -fd + -(fn * fm) */
B
bellard 已提交
2925
                    gen_vfp_mul(dp);
2926 2927
                    gen_vfp_F1_neg(dp);
                    gen_mov_F0_vreg(dp, rd);
B
bellard 已提交
2928
                    gen_vfp_neg(dp);
2929
                    gen_vfp_add(dp);
B
bellard 已提交
2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946
                    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;
2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997
                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.
                     */
                    if (!arm_feature(env, ARM_FEATURE_VFP4)) {
                        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 已提交
2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009
                case 14: /* fconst */
                    if (!arm_feature(env, ARM_FEATURE_VFP3))
                      return 1;

                    n = (insn << 12) & 0x80000000;
                    i = ((insn >> 12) & 0x70) | (insn & 0xf);
                    if (dp) {
                        if (i & 0x40)
                            i |= 0x3f80;
                        else
                            i |= 0x4000;
                        n |= i << 16;
P
pbrook 已提交
3010
                        tcg_gen_movi_i64(cpu_F0d, ((uint64_t)n) << 32);
P
pbrook 已提交
3011 3012 3013 3014 3015 3016
                    } else {
                        if (i & 0x40)
                            i |= 0x780;
                        else
                            i |= 0x800;
                        n |= i << 19;
B
balrog 已提交
3017
                        tcg_gen_movi_i32(cpu_F0s, n);
P
pbrook 已提交
3018 3019
                    }
                    break;
B
bellard 已提交
3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033
                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;
P
Paul Brook 已提交
3034 3035 3036 3037
                    case 4: /* vcvtb.f32.f16 */
                        tmp = gen_vfp_mrs();
                        tcg_gen_ext16u_i32(tmp, tmp);
                        gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp, cpu_env);
3038
                        tcg_temp_free_i32(tmp);
P
Paul Brook 已提交
3039 3040 3041 3042 3043
                        break;
                    case 5: /* vcvtt.f32.f16 */
                        tmp = gen_vfp_mrs();
                        tcg_gen_shri_i32(tmp, tmp, 16);
                        gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp, cpu_env);
3044
                        tcg_temp_free_i32(tmp);
P
Paul Brook 已提交
3045 3046
                        break;
                    case 6: /* vcvtb.f16.f32 */
3047
                        tmp = tcg_temp_new_i32();
P
Paul Brook 已提交
3048 3049 3050 3051 3052
                        gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
                        gen_mov_F0_vreg(0, rd);
                        tmp2 = gen_vfp_mrs();
                        tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000);
                        tcg_gen_or_i32(tmp, tmp, tmp2);
3053
                        tcg_temp_free_i32(tmp2);
P
Paul Brook 已提交
3054 3055 3056
                        gen_vfp_msr(tmp);
                        break;
                    case 7: /* vcvtt.f16.f32 */
3057
                        tmp = tcg_temp_new_i32();
P
Paul Brook 已提交
3058 3059 3060 3061 3062 3063
                        gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
                        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);
3064
                        tcg_temp_free_i32(tmp2);
P
Paul Brook 已提交
3065 3066
                        gen_vfp_msr(tmp);
                        break;
B
bellard 已提交
3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081
                    case 8: /* cmp */
                        gen_vfp_cmp(dp);
                        break;
                    case 9: /* cmpe */
                        gen_vfp_cmpe(dp);
                        break;
                    case 10: /* cmpz */
                        gen_vfp_cmp(dp);
                        break;
                    case 11: /* cmpez */
                        gen_vfp_F1_ld0(dp);
                        gen_vfp_cmpe(dp);
                        break;
                    case 15: /* single<->double conversion */
                        if (dp)
P
pbrook 已提交
3082
                            gen_helper_vfp_fcvtsd(cpu_F0s, cpu_F0d, cpu_env);
B
bellard 已提交
3083
                        else
P
pbrook 已提交
3084
                            gen_helper_vfp_fcvtds(cpu_F0d, cpu_F0s, cpu_env);
B
bellard 已提交
3085 3086
                        break;
                    case 16: /* fuito */
3087
                        gen_vfp_uito(dp, 0);
B
bellard 已提交
3088 3089
                        break;
                    case 17: /* fsito */
3090
                        gen_vfp_sito(dp, 0);
B
bellard 已提交
3091
                        break;
P
pbrook 已提交
3092 3093 3094
                    case 20: /* fshto */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
3095
                        gen_vfp_shto(dp, 16 - rm, 0);
P
pbrook 已提交
3096 3097 3098 3099
                        break;
                    case 21: /* fslto */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
3100
                        gen_vfp_slto(dp, 32 - rm, 0);
P
pbrook 已提交
3101 3102 3103 3104
                        break;
                    case 22: /* fuhto */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
3105
                        gen_vfp_uhto(dp, 16 - rm, 0);
P
pbrook 已提交
3106 3107 3108 3109
                        break;
                    case 23: /* fulto */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
3110
                        gen_vfp_ulto(dp, 32 - rm, 0);
P
pbrook 已提交
3111
                        break;
B
bellard 已提交
3112
                    case 24: /* ftoui */
3113
                        gen_vfp_toui(dp, 0);
B
bellard 已提交
3114 3115
                        break;
                    case 25: /* ftouiz */
3116
                        gen_vfp_touiz(dp, 0);
B
bellard 已提交
3117 3118
                        break;
                    case 26: /* ftosi */
3119
                        gen_vfp_tosi(dp, 0);
B
bellard 已提交
3120 3121
                        break;
                    case 27: /* ftosiz */
3122
                        gen_vfp_tosiz(dp, 0);
B
bellard 已提交
3123
                        break;
P
pbrook 已提交
3124 3125 3126
                    case 28: /* ftosh */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
3127
                        gen_vfp_tosh(dp, 16 - rm, 0);
P
pbrook 已提交
3128 3129 3130 3131
                        break;
                    case 29: /* ftosl */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
3132
                        gen_vfp_tosl(dp, 32 - rm, 0);
P
pbrook 已提交
3133 3134 3135 3136
                        break;
                    case 30: /* ftouh */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
3137
                        gen_vfp_touh(dp, 16 - rm, 0);
P
pbrook 已提交
3138 3139 3140 3141
                        break;
                    case 31: /* ftoul */
                        if (!arm_feature(env, ARM_FEATURE_VFP3))
                          return 1;
3142
                        gen_vfp_toul(dp, 32 - rm, 0);
P
pbrook 已提交
3143
                        break;
B
bellard 已提交
3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154
                    default: /* undefined */
                        return 1;
                    }
                    break;
                default: /* undefined */
                    return 1;
                }

                /* Write back the result.  */
                if (op == 15 && (rn >= 8 && rn <= 11))
                    ; /* Comparison, do nothing.  */
3155 3156
                else if (op == 15 && dp && ((rn & 0x1c) == 0x18))
                    /* VCVT double to int: always integer result. */
B
bellard 已提交
3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202
                    gen_mov_vreg_F0(0, rd);
                else if (op == 15 && rn == 15)
                    /* conversion */
                    gen_mov_vreg_F0(!dp, rd);
                else
                    gen_mov_vreg_F0(dp, rd);

                /* break out of the loop if we have finished  */
                if (veclen == 0)
                    break;

                if (op == 15 && delta_m == 0) {
                    /* single source one-many */
                    while (veclen--) {
                        rd = ((rd + delta_d) & (bank_mask - 1))
                             | (rd & bank_mask);
                        gen_mov_vreg_F0(dp, rd);
                    }
                    break;
                }
                /* Setup the next operands.  */
                veclen--;
                rd = ((rd + delta_d) & (bank_mask - 1))
                     | (rd & bank_mask);

                if (op == 15) {
                    /* One source operand.  */
                    rm = ((rm + delta_m) & (bank_mask - 1))
                         | (rm & bank_mask);
                    gen_mov_F0_vreg(dp, rm);
                } else {
                    /* Two source operands.  */
                    rn = ((rn + delta_d) & (bank_mask - 1))
                         | (rn & bank_mask);
                    gen_mov_F0_vreg(dp, rn);
                    if (delta_m) {
                        rm = ((rm + delta_m) & (bank_mask - 1))
                             | (rm & bank_mask);
                        gen_mov_F1_vreg(dp, rm);
                    }
                }
            }
        }
        break;
    case 0xc:
    case 0xd:
3203
        if ((insn & 0x03e00000) == 0x00400000) {
B
bellard 已提交
3204 3205 3206 3207
            /* two-register transfer */
            rn = (insn >> 16) & 0xf;
            rd = (insn >> 12) & 0xf;
            if (dp) {
P
pbrook 已提交
3208 3209 3210 3211
                VFP_DREG_M(rm, insn);
            } else {
                rm = VFP_SREG_M(insn);
            }
B
bellard 已提交
3212

3213
            if (insn & ARM_CP_RW_BIT) {
B
bellard 已提交
3214 3215
                /* vfp->arm */
                if (dp) {
P
pbrook 已提交
3216 3217 3218 3219 3220 3221
                    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 已提交
3222 3223
                } else {
                    gen_mov_F0_vreg(0, rm);
P
pbrook 已提交
3224
                    tmp = gen_vfp_mrs();
3225
                    store_reg(s, rd, tmp);
B
bellard 已提交
3226
                    gen_mov_F0_vreg(0, rm + 1);
P
pbrook 已提交
3227
                    tmp = gen_vfp_mrs();
3228
                    store_reg(s, rn, tmp);
B
bellard 已提交
3229 3230 3231 3232
                }
            } else {
                /* arm->vfp */
                if (dp) {
P
pbrook 已提交
3233 3234 3235 3236 3237 3238
                    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 已提交
3239
                } else {
3240
                    tmp = load_reg(s, rd);
P
pbrook 已提交
3241
                    gen_vfp_msr(tmp);
B
bellard 已提交
3242
                    gen_mov_vreg_F0(0, rm);
3243
                    tmp = load_reg(s, rn);
P
pbrook 已提交
3244
                    gen_vfp_msr(tmp);
B
bellard 已提交
3245 3246 3247 3248 3249 3250 3251
                    gen_mov_vreg_F0(0, rm + 1);
                }
            }
        } else {
            /* Load/store */
            rn = (insn >> 16) & 0xf;
            if (dp)
P
pbrook 已提交
3252
                VFP_DREG_D(rd, insn);
B
bellard 已提交
3253
            else
P
pbrook 已提交
3254
                rd = VFP_SREG_D(insn);
B
bellard 已提交
3255 3256 3257 3258 3259
            if ((insn & 0x01200000) == 0x01000000) {
                /* Single load/store */
                offset = (insn & 0xff) << 2;
                if ((insn & (1 << 23)) == 0)
                    offset = -offset;
3260 3261 3262 3263 3264 3265 3266
                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);
                }
3267
                tcg_gen_addi_i32(addr, addr, offset);
B
bellard 已提交
3268
                if (insn & (1 << 20)) {
3269
                    gen_vfp_ld(s, dp, addr);
B
bellard 已提交
3270 3271 3272
                    gen_mov_vreg_F0(dp, rd);
                } else {
                    gen_mov_F0_vreg(dp, rd);
3273
                    gen_vfp_st(s, dp, addr);
B
bellard 已提交
3274
                }
3275
                tcg_temp_free_i32(addr);
B
bellard 已提交
3276 3277
            } else {
                /* load/store multiple */
3278
                int w = insn & (1 << 21);
B
bellard 已提交
3279 3280 3281 3282 3283
                if (dp)
                    n = (insn >> 1) & 0x7f;
                else
                    n = insn & 0xff;

3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305
                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 已提交
3306
                if (insn & (1 << 24)) /* pre-decrement */
3307
                    tcg_gen_addi_i32(addr, addr, -((insn & 0xff) << 2));
B
bellard 已提交
3308 3309 3310 3311 3312 3313

                if (dp)
                    offset = 8;
                else
                    offset = 4;
                for (i = 0; i < n; i++) {
3314
                    if (insn & ARM_CP_RW_BIT) {
B
bellard 已提交
3315
                        /* load */
3316
                        gen_vfp_ld(s, dp, addr);
B
bellard 已提交
3317 3318 3319 3320
                        gen_mov_vreg_F0(dp, rd + i);
                    } else {
                        /* store */
                        gen_mov_F0_vreg(dp, rd + i);
3321
                        gen_vfp_st(s, dp, addr);
B
bellard 已提交
3322
                    }
3323
                    tcg_gen_addi_i32(addr, addr, offset);
B
bellard 已提交
3324
                }
3325
                if (w) {
B
bellard 已提交
3326 3327 3328 3329 3330 3331 3332 3333 3334
                    /* writeback */
                    if (insn & (1 << 24))
                        offset = -offset * n;
                    else if (dp && (insn & 1))
                        offset = 4;
                    else
                        offset = 0;

                    if (offset != 0)
3335 3336 3337
                        tcg_gen_addi_i32(addr, addr, offset);
                    store_reg(s, rn, addr);
                } else {
3338
                    tcg_temp_free_i32(addr);
B
bellard 已提交
3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349
                }
            }
        }
        break;
    default:
        /* Should never happen.  */
        return 1;
    }
    return 0;
}

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

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

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

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

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

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

3424
/* Returns nonzero if access to the PSR is not permitted. Marks t0 as dead. */
3425
static int gen_set_psr(DisasContext *s, uint32_t mask, int spsr, TCGv_i32 t0)
B
bellard 已提交
3426
{
3427
    TCGv_i32 tmp;
B
bellard 已提交
3428 3429 3430 3431
    if (spsr) {
        /* ??? This is also undefined in system mode.  */
        if (IS_USER(s))
            return 1;
P
pbrook 已提交
3432 3433 3434

        tmp = load_cpu_field(spsr);
        tcg_gen_andi_i32(tmp, tmp, ~mask);
3435 3436
        tcg_gen_andi_i32(t0, t0, mask);
        tcg_gen_or_i32(tmp, tmp, t0);
P
pbrook 已提交
3437
        store_cpu_field(tmp, spsr);
B
bellard 已提交
3438
    } else {
3439
        gen_set_cpsr(t0, mask);
B
bellard 已提交
3440
    }
3441
    tcg_temp_free_i32(t0);
B
bellard 已提交
3442 3443 3444 3445
    gen_lookup_tb(s);
    return 0;
}

3446 3447 3448
/* 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)
{
3449
    TCGv_i32 tmp;
3450
    tmp = tcg_temp_new_i32();
3451 3452 3453 3454
    tcg_gen_movi_i32(tmp, val);
    return gen_set_psr(s, mask, spsr, tmp);
}

3455
/* Generate an old-style exception return. Marks pc as dead. */
3456
static void gen_exception_return(DisasContext *s, TCGv_i32 pc)
B
bellard 已提交
3457
{
3458
    TCGv_i32 tmp;
3459
    store_reg(s, 15, pc);
P
pbrook 已提交
3460 3461
    tmp = load_cpu_field(spsr);
    gen_set_cpsr(tmp, 0xffffffff);
3462
    tcg_temp_free_i32(tmp);
B
bellard 已提交
3463 3464 3465
    s->is_jmp = DISAS_UPDATE;
}

P
pbrook 已提交
3466
/* Generate a v6 exception return.  Marks both values as dead.  */
3467
static void gen_rfe(DisasContext *s, TCGv_i32 pc, TCGv_i32 cpsr)
B
bellard 已提交
3468
{
P
pbrook 已提交
3469
    gen_set_cpsr(cpsr, 0xffffffff);
3470
    tcg_temp_free_i32(cpsr);
P
pbrook 已提交
3471
    store_reg(s, 15, pc);
P
pbrook 已提交
3472 3473
    s->is_jmp = DISAS_UPDATE;
}
3474

P
pbrook 已提交
3475 3476 3477 3478
static inline void
gen_set_condexec (DisasContext *s)
{
    if (s->condexec_mask) {
P
pbrook 已提交
3479
        uint32_t val = (s->condexec_cond << 4) | (s->condexec_mask >> 1);
3480
        TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
3481
        tcg_gen_movi_i32(tmp, val);
P
pbrook 已提交
3482
        store_cpu_field(tmp, condexec_bits);
P
pbrook 已提交
3483 3484
    }
}
3485

3486 3487 3488 3489 3490 3491 3492 3493
static void gen_exception_insn(DisasContext *s, int offset, int excp)
{
    gen_set_condexec(s);
    gen_set_pc_im(s->pc - offset);
    gen_exception(excp);
    s->is_jmp = DISAS_JUMP;
}

P
pbrook 已提交
3494 3495 3496 3497
static void gen_nop_hint(DisasContext *s, int val)
{
    switch (val) {
    case 3: /* wfi */
P
pbrook 已提交
3498
        gen_set_pc_im(s->pc);
P
pbrook 已提交
3499 3500 3501 3502 3503 3504 3505 3506 3507
        s->is_jmp = DISAS_WFI;
        break;
    case 2: /* wfe */
    case 4: /* sev */
        /* TODO: Implement SEV and WFE.  May help SMP performance.  */
    default: /* nop */
        break;
    }
}
B
bellard 已提交
3508

P
pbrook 已提交
3509
#define CPU_V001 cpu_V0, cpu_V0, cpu_V1
P
pbrook 已提交
3510

3511
static inline void gen_neon_add(int size, TCGv_i32 t0, TCGv_i32 t1)
P
pbrook 已提交
3512 3513
{
    switch (size) {
3514 3515 3516
    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;
3517
    default: abort();
P
pbrook 已提交
3518 3519 3520
    }
}

3521
static inline void gen_neon_rsb(int size, TCGv_i32 t0, TCGv_i32 t1)
P
pbrook 已提交
3522 3523
{
    switch (size) {
3524 3525 3526
    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 已提交
3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539
    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: \
3540
        gen_helper_neon_##name##_s8(tmp, cpu_env, tmp, tmp2); \
P
pbrook 已提交
3541 3542
        break; \
    case 1: \
3543
        gen_helper_neon_##name##_u8(tmp, cpu_env, tmp, tmp2); \
P
pbrook 已提交
3544 3545
        break; \
    case 2: \
3546
        gen_helper_neon_##name##_s16(tmp, cpu_env, tmp, tmp2); \
P
pbrook 已提交
3547 3548
        break; \
    case 3: \
3549
        gen_helper_neon_##name##_u16(tmp, cpu_env, tmp, tmp2); \
P
pbrook 已提交
3550 3551
        break; \
    case 4: \
3552
        gen_helper_neon_##name##_s32(tmp, cpu_env, tmp, tmp2); \
P
pbrook 已提交
3553 3554
        break; \
    case 5: \
3555
        gen_helper_neon_##name##_u32(tmp, cpu_env, tmp, tmp2); \
P
pbrook 已提交
3556 3557 3558
        break; \
    default: return 1; \
    }} while (0)
P
pbrook 已提交
3559 3560 3561

#define GEN_NEON_INTEGER_OP(name) do { \
    switch ((size << 1) | u) { \
P
pbrook 已提交
3562
    case 0: \
3563
        gen_helper_neon_##name##_s8(tmp, tmp, tmp2); \
P
pbrook 已提交
3564 3565
        break; \
    case 1: \
3566
        gen_helper_neon_##name##_u8(tmp, tmp, tmp2); \
P
pbrook 已提交
3567 3568
        break; \
    case 2: \
3569
        gen_helper_neon_##name##_s16(tmp, tmp, tmp2); \
P
pbrook 已提交
3570 3571
        break; \
    case 3: \
3572
        gen_helper_neon_##name##_u16(tmp, tmp, tmp2); \
P
pbrook 已提交
3573 3574
        break; \
    case 4: \
3575
        gen_helper_neon_##name##_s32(tmp, tmp, tmp2); \
P
pbrook 已提交
3576 3577
        break; \
    case 5: \
3578
        gen_helper_neon_##name##_u32(tmp, tmp, tmp2); \
P
pbrook 已提交
3579
        break; \
P
pbrook 已提交
3580 3581 3582
    default: return 1; \
    }} while (0)

3583
static TCGv_i32 neon_load_scratch(int scratch)
P
pbrook 已提交
3584
{
3585
    TCGv_i32 tmp = tcg_temp_new_i32();
3586 3587
    tcg_gen_ld_i32(tmp, cpu_env, offsetof(CPUARMState, vfp.scratch[scratch]));
    return tmp;
P
pbrook 已提交
3588 3589
}

3590
static void neon_store_scratch(int scratch, TCGv_i32 var)
P
pbrook 已提交
3591
{
3592
    tcg_gen_st_i32(var, cpu_env, offsetof(CPUARMState, vfp.scratch[scratch]));
3593
    tcg_temp_free_i32(var);
P
pbrook 已提交
3594 3595
}

3596
static inline TCGv_i32 neon_get_scalar(int size, int reg)
P
pbrook 已提交
3597
{
3598
    TCGv_i32 tmp;
P
pbrook 已提交
3599
    if (size == 1) {
3600 3601
        tmp = neon_load_reg(reg & 7, reg >> 4);
        if (reg & 8) {
3602
            gen_neon_dup_high16(tmp);
3603 3604
        } else {
            gen_neon_dup_low16(tmp);
3605
        }
3606 3607
    } else {
        tmp = neon_load_reg(reg & 15, reg >> 4);
P
pbrook 已提交
3608
    }
3609
    return tmp;
P
pbrook 已提交
3610 3611
}

3612
static int gen_neon_unzip(int rd, int rm, int size, int q)
3613
{
3614
    TCGv_i32 tmp, tmp2;
3615
    if (!q && size == 2) {
3616 3617 3618 3619 3620 3621 3622
        return 1;
    }
    tmp = tcg_const_i32(rd);
    tmp2 = tcg_const_i32(rm);
    if (q) {
        switch (size) {
        case 0:
3623
            gen_helper_neon_qunzip8(cpu_env, tmp, tmp2);
3624 3625
            break;
        case 1:
3626
            gen_helper_neon_qunzip16(cpu_env, tmp, tmp2);
3627 3628
            break;
        case 2:
3629
            gen_helper_neon_qunzip32(cpu_env, tmp, tmp2);
3630 3631 3632 3633 3634 3635 3636
            break;
        default:
            abort();
        }
    } else {
        switch (size) {
        case 0:
3637
            gen_helper_neon_unzip8(cpu_env, tmp, tmp2);
3638 3639
            break;
        case 1:
3640
            gen_helper_neon_unzip16(cpu_env, tmp, tmp2);
3641 3642 3643 3644 3645 3646 3647 3648
            break;
        default:
            abort();
        }
    }
    tcg_temp_free_i32(tmp);
    tcg_temp_free_i32(tmp2);
    return 0;
3649 3650
}

3651
static int gen_neon_zip(int rd, int rm, int size, int q)
3652
{
3653
    TCGv_i32 tmp, tmp2;
3654
    if (!q && size == 2) {
3655 3656 3657 3658 3659 3660 3661
        return 1;
    }
    tmp = tcg_const_i32(rd);
    tmp2 = tcg_const_i32(rm);
    if (q) {
        switch (size) {
        case 0:
3662
            gen_helper_neon_qzip8(cpu_env, tmp, tmp2);
3663 3664
            break;
        case 1:
3665
            gen_helper_neon_qzip16(cpu_env, tmp, tmp2);
3666 3667
            break;
        case 2:
3668
            gen_helper_neon_qzip32(cpu_env, tmp, tmp2);
3669 3670 3671 3672 3673 3674 3675
            break;
        default:
            abort();
        }
    } else {
        switch (size) {
        case 0:
3676
            gen_helper_neon_zip8(cpu_env, tmp, tmp2);
3677 3678
            break;
        case 1:
3679
            gen_helper_neon_zip16(cpu_env, tmp, tmp2);
3680 3681 3682 3683 3684 3685 3686 3687
            break;
        default:
            abort();
        }
    }
    tcg_temp_free_i32(tmp);
    tcg_temp_free_i32(tmp2);
    return 0;
3688 3689
}

3690
static void gen_neon_trn_u8(TCGv_i32 t0, TCGv_i32 t1)
3691
{
3692
    TCGv_i32 rd, tmp;
3693

3694 3695
    rd = tcg_temp_new_i32();
    tmp = tcg_temp_new_i32();
3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707

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

3708 3709
    tcg_temp_free_i32(tmp);
    tcg_temp_free_i32(rd);
3710 3711
}

3712
static void gen_neon_trn_u16(TCGv_i32 t0, TCGv_i32 t1)
3713
{
3714
    TCGv_i32 rd, tmp;
3715

3716 3717
    rd = tcg_temp_new_i32();
    tmp = tcg_temp_new_i32();
3718 3719 3720 3721 3722 3723 3724 3725 3726

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

3727 3728
    tcg_temp_free_i32(tmp);
    tcg_temp_free_i32(rd);
3729 3730 3731
}


P
pbrook 已提交
3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751
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.  */
3752
static int disas_neon_ls_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
P
pbrook 已提交
3753 3754 3755 3756 3757
{
    int rd, rn, rm;
    int op;
    int nregs;
    int interleave;
3758
    int spacing;
P
pbrook 已提交
3759 3760 3761 3762 3763 3764 3765
    int stride;
    int size;
    int reg;
    int pass;
    int load;
    int shift;
    int n;
3766 3767 3768
    TCGv_i32 addr;
    TCGv_i32 tmp;
    TCGv_i32 tmp2;
3769
    TCGv_i64 tmp64;
P
pbrook 已提交
3770

3771
    if (!s->vfp_enabled)
P
pbrook 已提交
3772 3773 3774 3775 3776 3777 3778 3779 3780
      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;
3781
        if (op > 10)
P
pbrook 已提交
3782
            return 1;
3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797
        /* 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 已提交
3798 3799
        nregs = neon_ls_element_type[op].nregs;
        interleave = neon_ls_element_type[op].interleave;
3800 3801 3802
        spacing = neon_ls_element_type[op].spacing;
        if (size == 3 && (interleave | spacing) != 1)
            return 1;
3803
        addr = tcg_temp_new_i32();
3804
        load_reg_var(s, addr, rn);
P
pbrook 已提交
3805 3806 3807
        stride = (1 << size) * interleave;
        for (reg = 0; reg < nregs; reg++) {
            if (interleave > 2 || (interleave == 2 && nregs == 2)) {
3808 3809
                load_reg_var(s, addr, rn);
                tcg_gen_addi_i32(addr, addr, (1 << size) * reg);
P
pbrook 已提交
3810
            } else if (interleave == 2 && nregs == 4 && reg == 2) {
3811 3812
                load_reg_var(s, addr, rn);
                tcg_gen_addi_i32(addr, addr, 1 << size);
P
pbrook 已提交
3813
            }
3814
            if (size == 3) {
3815
                tmp64 = tcg_temp_new_i64();
3816
                if (load) {
3817
                    tcg_gen_qemu_ld64(tmp64, addr, IS_USER(s));
3818 3819 3820
                    neon_store_reg64(tmp64, rd);
                } else {
                    neon_load_reg64(tmp64, rd);
3821
                    tcg_gen_qemu_st64(tmp64, addr, IS_USER(s));
3822
                }
3823
                tcg_temp_free_i64(tmp64);
3824 3825 3826 3827 3828
                tcg_gen_addi_i32(addr, addr, stride);
            } else {
                for (pass = 0; pass < 2; pass++) {
                    if (size == 2) {
                        if (load) {
3829 3830
                            tmp = tcg_temp_new_i32();
                            tcg_gen_qemu_ld32u(tmp, addr, IS_USER(s));
3831 3832 3833
                            neon_store_reg(rd, pass, tmp);
                        } else {
                            tmp = neon_load_reg(rd, pass);
3834 3835
                            tcg_gen_qemu_st32(tmp, addr, IS_USER(s));
                            tcg_temp_free_i32(tmp);
3836
                        }
3837
                        tcg_gen_addi_i32(addr, addr, stride);
3838 3839
                    } else if (size == 1) {
                        if (load) {
3840 3841
                            tmp = tcg_temp_new_i32();
                            tcg_gen_qemu_ld16u(tmp, addr, IS_USER(s));
3842
                            tcg_gen_addi_i32(addr, addr, stride);
3843 3844
                            tmp2 = tcg_temp_new_i32();
                            tcg_gen_qemu_ld16u(tmp2, addr, IS_USER(s));
3845
                            tcg_gen_addi_i32(addr, addr, stride);
P
Paul Brook 已提交
3846 3847
                            tcg_gen_shli_i32(tmp2, tmp2, 16);
                            tcg_gen_or_i32(tmp, tmp, tmp2);
3848
                            tcg_temp_free_i32(tmp2);
3849 3850 3851
                            neon_store_reg(rd, pass, tmp);
                        } else {
                            tmp = neon_load_reg(rd, pass);
3852
                            tmp2 = tcg_temp_new_i32();
3853
                            tcg_gen_shri_i32(tmp2, tmp, 16);
3854 3855
                            tcg_gen_qemu_st16(tmp, addr, IS_USER(s));
                            tcg_temp_free_i32(tmp);
3856
                            tcg_gen_addi_i32(addr, addr, stride);
3857 3858
                            tcg_gen_qemu_st16(tmp2, addr, IS_USER(s));
                            tcg_temp_free_i32(tmp2);
3859
                            tcg_gen_addi_i32(addr, addr, stride);
P
pbrook 已提交
3860
                        }
3861 3862
                    } else /* size == 0 */ {
                        if (load) {
3863
                            TCGV_UNUSED_I32(tmp2);
3864
                            for (n = 0; n < 4; n++) {
3865 3866
                                tmp = tcg_temp_new_i32();
                                tcg_gen_qemu_ld8u(tmp, addr, IS_USER(s));
3867 3868 3869 3870
                                tcg_gen_addi_i32(addr, addr, stride);
                                if (n == 0) {
                                    tmp2 = tmp;
                                } else {
P
Paul Brook 已提交
3871 3872
                                    tcg_gen_shli_i32(tmp, tmp, n * 8);
                                    tcg_gen_or_i32(tmp2, tmp2, tmp);
3873
                                    tcg_temp_free_i32(tmp);
3874
                                }
P
pbrook 已提交
3875
                            }
3876 3877 3878 3879
                            neon_store_reg(rd, pass, tmp2);
                        } else {
                            tmp2 = neon_load_reg(rd, pass);
                            for (n = 0; n < 4; n++) {
3880
                                tmp = tcg_temp_new_i32();
3881 3882 3883 3884 3885
                                if (n == 0) {
                                    tcg_gen_mov_i32(tmp, tmp2);
                                } else {
                                    tcg_gen_shri_i32(tmp, tmp2, n * 8);
                                }
3886 3887
                                tcg_gen_qemu_st8(tmp, addr, IS_USER(s));
                                tcg_temp_free_i32(tmp);
3888 3889
                                tcg_gen_addi_i32(addr, addr, stride);
                            }
3890
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
3891 3892 3893 3894
                        }
                    }
                }
            }
3895
            rd += spacing;
P
pbrook 已提交
3896
        }
3897
        tcg_temp_free_i32(addr);
P
pbrook 已提交
3898 3899 3900 3901 3902
        stride = nregs * 8;
    } else {
        size = (insn >> 10) & 3;
        if (size == 3) {
            /* Load single element to all lanes.  */
3903 3904
            int a = (insn >> 4) & 1;
            if (!load) {
P
pbrook 已提交
3905
                return 1;
3906
            }
P
pbrook 已提交
3907 3908
            size = (insn >> 6) & 3;
            nregs = ((insn >> 8) & 3) + 1;
3909 3910 3911

            if (size == 3) {
                if (nregs != 4 || a == 0) {
P
pbrook 已提交
3912
                    return 1;
B
bellard 已提交
3913
                }
3914 3915 3916 3917 3918 3919 3920 3921 3922
                /* 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;
            }
3923
            addr = tcg_temp_new_i32();
3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945
            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 已提交
3946
            }
3947
            tcg_temp_free_i32(addr);
P
pbrook 已提交
3948 3949 3950
            stride = (1 << size) * nregs;
        } else {
            /* Single element.  */
3951
            int idx = (insn >> 4) & 0xf;
P
pbrook 已提交
3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969
            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;
3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002
            /* 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;
            }
4003
            addr = tcg_temp_new_i32();
4004
            load_reg_var(s, addr, rn);
P
pbrook 已提交
4005 4006
            for (reg = 0; reg < nregs; reg++) {
                if (load) {
4007
                    tmp = tcg_temp_new_i32();
P
pbrook 已提交
4008 4009
                    switch (size) {
                    case 0:
4010
                        tcg_gen_qemu_ld8u(tmp, addr, IS_USER(s));
P
pbrook 已提交
4011 4012
                        break;
                    case 1:
4013
                        tcg_gen_qemu_ld16u(tmp, addr, IS_USER(s));
P
pbrook 已提交
4014 4015
                        break;
                    case 2:
4016
                        tcg_gen_qemu_ld32u(tmp, addr, IS_USER(s));
P
pbrook 已提交
4017
                        break;
P
pbrook 已提交
4018 4019
                    default: /* Avoid compiler warnings.  */
                        abort();
P
pbrook 已提交
4020 4021
                    }
                    if (size != 2) {
P
pbrook 已提交
4022
                        tmp2 = neon_load_reg(rd, pass);
4023 4024
                        tcg_gen_deposit_i32(tmp, tmp2, tmp,
                                            shift, size ? 16 : 8);
4025
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
4026
                    }
P
pbrook 已提交
4027
                    neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
4028
                } else { /* Store */
P
pbrook 已提交
4029 4030 4031
                    tmp = neon_load_reg(rd, pass);
                    if (shift)
                        tcg_gen_shri_i32(tmp, tmp, shift);
P
pbrook 已提交
4032 4033
                    switch (size) {
                    case 0:
4034
                        tcg_gen_qemu_st8(tmp, addr, IS_USER(s));
P
pbrook 已提交
4035 4036
                        break;
                    case 1:
4037
                        tcg_gen_qemu_st16(tmp, addr, IS_USER(s));
P
pbrook 已提交
4038 4039
                        break;
                    case 2:
4040
                        tcg_gen_qemu_st32(tmp, addr, IS_USER(s));
P
pbrook 已提交
4041
                        break;
B
bellard 已提交
4042
                    }
4043
                    tcg_temp_free_i32(tmp);
B
bellard 已提交
4044
                }
P
pbrook 已提交
4045
                rd += stride;
4046
                tcg_gen_addi_i32(addr, addr, 1 << size);
B
bellard 已提交
4047
            }
4048
            tcg_temp_free_i32(addr);
P
pbrook 已提交
4049
            stride = nregs * (1 << size);
B
bellard 已提交
4050
        }
P
pbrook 已提交
4051 4052
    }
    if (rm != 15) {
4053
        TCGv_i32 base;
P
pbrook 已提交
4054 4055

        base = load_reg(s, rn);
P
pbrook 已提交
4056
        if (rm == 13) {
P
pbrook 已提交
4057
            tcg_gen_addi_i32(base, base, stride);
P
pbrook 已提交
4058
        } else {
4059
            TCGv_i32 index;
P
pbrook 已提交
4060 4061
            index = load_reg(s, rm);
            tcg_gen_add_i32(base, base, index);
4062
            tcg_temp_free_i32(index);
P
pbrook 已提交
4063
        }
P
pbrook 已提交
4064
        store_reg(s, rn, base);
P
pbrook 已提交
4065 4066 4067
    }
    return 0;
}
4068

P
pbrook 已提交
4069
/* Bitwise select.  dest = c ? t : f.  Clobbers T and F.  */
4070
static void gen_neon_bsl(TCGv_i32 dest, TCGv_i32 t, TCGv_i32 f, TCGv_i32 c)
P
pbrook 已提交
4071 4072
{
    tcg_gen_and_i32(t, t, c);
4073
    tcg_gen_andc_i32(f, f, c);
P
pbrook 已提交
4074 4075 4076
    tcg_gen_or_i32(dest, t, f);
}

4077
static inline void gen_neon_narrow(int size, TCGv_i32 dest, TCGv_i64 src)
P
pbrook 已提交
4078 4079 4080 4081 4082 4083 4084 4085 4086
{
    switch (size) {
    case 0: gen_helper_neon_narrow_u8(dest, src); break;
    case 1: gen_helper_neon_narrow_u16(dest, src); break;
    case 2: tcg_gen_trunc_i64_i32(dest, src); break;
    default: abort();
    }
}

4087
static inline void gen_neon_narrow_sats(int size, TCGv_i32 dest, TCGv_i64 src)
P
pbrook 已提交
4088 4089
{
    switch (size) {
4090 4091 4092
    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 已提交
4093 4094 4095 4096
    default: abort();
    }
}

4097
static inline void gen_neon_narrow_satu(int size, TCGv_i32 dest, TCGv_i64 src)
P
pbrook 已提交
4098 4099
{
    switch (size) {
4100 4101 4102
    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 已提交
4103 4104 4105 4106
    default: abort();
    }
}

4107
static inline void gen_neon_unarrow_sats(int size, TCGv_i32 dest, TCGv_i64 src)
4108 4109
{
    switch (size) {
4110 4111 4112
    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;
4113 4114 4115 4116
    default: abort();
    }
}

4117
static inline void gen_neon_shift_narrow(int size, TCGv_i32 var, TCGv_i32 shift,
P
pbrook 已提交
4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136
                                         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) {
4137 4138
            case 1: gen_helper_neon_shl_u16(var, var, shift); break;
            case 2: gen_helper_neon_shl_u32(var, var, shift); break;
P
pbrook 已提交
4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150
            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();
            }
        }
    }
}

4151
static inline void gen_neon_widen(TCGv_i64 dest, TCGv_i32 src, int size, int u)
P
pbrook 已提交
4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167
{
    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();
        }
    }
4168
    tcg_temp_free_i32(src);
P
pbrook 已提交
4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190
}

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 已提交
4191
static inline void gen_neon_negl(TCGv_i64 var, int size)
P
pbrook 已提交
4192 4193 4194 4195
{
    switch (size) {
    case 0: gen_helper_neon_negl_u16(var, var); break;
    case 1: gen_helper_neon_negl_u32(var, var); break;
4196 4197 4198
    case 2:
        tcg_gen_neg_i64(var, var);
        break;
P
pbrook 已提交
4199 4200 4201 4202
    default: abort();
    }
}

P
pbrook 已提交
4203
static inline void gen_neon_addl_saturate(TCGv_i64 op0, TCGv_i64 op1, int size)
P
pbrook 已提交
4204 4205
{
    switch (size) {
4206 4207
    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 已提交
4208 4209 4210 4211
    default: abort();
    }
}

4212 4213
static inline void gen_neon_mull(TCGv_i64 dest, TCGv_i32 a, TCGv_i32 b,
                                 int size, int u)
P
pbrook 已提交
4214
{
P
pbrook 已提交
4215
    TCGv_i64 tmp;
P
pbrook 已提交
4216 4217 4218 4219 4220 4221 4222 4223 4224

    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);
4225
        tcg_temp_free_i64(tmp);
P
pbrook 已提交
4226 4227 4228 4229
        break;
    case 5:
        tmp = gen_mulu_i64_i32(a, b);
        tcg_gen_mov_i64(dest, tmp);
4230
        tcg_temp_free_i64(tmp);
P
pbrook 已提交
4231 4232 4233
        break;
    default: abort();
    }
4234 4235 4236 4237

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

4243 4244
static void gen_neon_narrow_op(int op, int u, int size,
                               TCGv_i32 dest, TCGv_i64 src)
4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260
{
    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);
        }
    }
}

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
/* 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
4289
#define NEON_3R_VFM 25 /* VFMA, VFMS : float fused multiply-add */
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
#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 */
#define NEON_3R_VRECPS_VRSQRTS 31 /* float VRECPS, VRSQRTS */

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,
4322
    [NEON_3R_VFM] = 0x5, /* size bit 1 encodes op */
4323 4324 4325 4326 4327 4328 4329 4330
    [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 */
    [NEON_3R_VRECPS_VRSQRTS] = 0x5, /* size bit 1 encodes op */
};

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 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437
/* 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
#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
#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
#define NEON_2RM_VCVT_F16_F32 44
#define NEON_2RM_VCVT_F32_F16 46
#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 ||
            op >= NEON_2RM_VRECPE_F);
}

/* 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,
    [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,
    [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,
    [NEON_2RM_VCVT_F16_F32] = 0x2,
    [NEON_2RM_VCVT_F32_F16] = 0x2,
    [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 已提交
4438 4439
/* Translate a NEON data processing instruction.  Return nonzero if the
   instruction is invalid.
P
pbrook 已提交
4440 4441
   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 已提交
4442

4443
static int disas_neon_data_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
P
pbrook 已提交
4444 4445 4446 4447 4448 4449 4450 4451 4452 4453
{
    int op;
    int q;
    int rd, rn, rm;
    int size;
    int shift;
    int pass;
    int count;
    int pairwise;
    int u;
4454
    uint32_t imm, mask;
4455
    TCGv_i32 tmp, tmp2, tmp3, tmp4, tmp5;
P
pbrook 已提交
4456
    TCGv_i64 tmp64;
P
pbrook 已提交
4457

4458
    if (!s->vfp_enabled)
P
pbrook 已提交
4459 4460 4461 4462 4463 4464 4465 4466 4467 4468
      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);
4469 4470 4471 4472
        /* Catch invalid op and bad size combinations: UNDEF */
        if ((neon_3r_sizes[op] & (1 << size)) == 0) {
            return 1;
        }
4473 4474 4475 4476 4477 4478
        /* 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;
        }
4479 4480
        if (size == 3 && op != NEON_3R_LOGIC) {
            /* 64-bit element instructions. */
P
pbrook 已提交
4481
            for (pass = 0; pass < (q ? 2 : 1); pass++) {
P
pbrook 已提交
4482 4483
                neon_load_reg64(cpu_V0, rn + pass);
                neon_load_reg64(cpu_V1, rm + pass);
P
pbrook 已提交
4484
                switch (op) {
4485
                case NEON_3R_VQADD:
P
pbrook 已提交
4486
                    if (u) {
4487 4488
                        gen_helper_neon_qadd_u64(cpu_V0, cpu_env,
                                                 cpu_V0, cpu_V1);
B
bellard 已提交
4489
                    } else {
4490 4491
                        gen_helper_neon_qadd_s64(cpu_V0, cpu_env,
                                                 cpu_V0, cpu_V1);
B
bellard 已提交
4492
                    }
P
pbrook 已提交
4493
                    break;
4494
                case NEON_3R_VQSUB:
P
pbrook 已提交
4495
                    if (u) {
4496 4497
                        gen_helper_neon_qsub_u64(cpu_V0, cpu_env,
                                                 cpu_V0, cpu_V1);
P
pbrook 已提交
4498
                    } else {
4499 4500
                        gen_helper_neon_qsub_s64(cpu_V0, cpu_env,
                                                 cpu_V0, cpu_V1);
P
pbrook 已提交
4501 4502
                    }
                    break;
4503
                case NEON_3R_VSHL:
P
pbrook 已提交
4504 4505 4506 4507 4508 4509
                    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;
4510
                case NEON_3R_VQSHL:
P
pbrook 已提交
4511
                    if (u) {
4512 4513
                        gen_helper_neon_qshl_u64(cpu_V0, cpu_env,
                                                 cpu_V1, cpu_V0);
P
pbrook 已提交
4514
                    } else {
4515 4516
                        gen_helper_neon_qshl_s64(cpu_V0, cpu_env,
                                                 cpu_V1, cpu_V0);
P
pbrook 已提交
4517 4518
                    }
                    break;
4519
                case NEON_3R_VRSHL:
P
pbrook 已提交
4520 4521
                    if (u) {
                        gen_helper_neon_rshl_u64(cpu_V0, cpu_V1, cpu_V0);
B
bellard 已提交
4522
                    } else {
P
pbrook 已提交
4523 4524 4525
                        gen_helper_neon_rshl_s64(cpu_V0, cpu_V1, cpu_V0);
                    }
                    break;
4526
                case NEON_3R_VQRSHL:
P
pbrook 已提交
4527
                    if (u) {
4528 4529
                        gen_helper_neon_qrshl_u64(cpu_V0, cpu_env,
                                                  cpu_V1, cpu_V0);
P
pbrook 已提交
4530
                    } else {
4531 4532
                        gen_helper_neon_qrshl_s64(cpu_V0, cpu_env,
                                                  cpu_V1, cpu_V0);
B
bellard 已提交
4533
                    }
P
pbrook 已提交
4534
                    break;
4535
                case NEON_3R_VADD_VSUB:
P
pbrook 已提交
4536
                    if (u) {
P
pbrook 已提交
4537
                        tcg_gen_sub_i64(CPU_V001);
P
pbrook 已提交
4538
                    } else {
P
pbrook 已提交
4539
                        tcg_gen_add_i64(CPU_V001);
P
pbrook 已提交
4540 4541 4542 4543
                    }
                    break;
                default:
                    abort();
B
bellard 已提交
4544
                }
P
pbrook 已提交
4545
                neon_store_reg64(cpu_V0, rd + pass);
B
bellard 已提交
4546
            }
P
pbrook 已提交
4547
            return 0;
B
bellard 已提交
4548
        }
4549
        pairwise = 0;
P
pbrook 已提交
4550
        switch (op) {
4551 4552 4553 4554
        case NEON_3R_VSHL:
        case NEON_3R_VQSHL:
        case NEON_3R_VRSHL:
        case NEON_3R_VQRSHL:
P
pbrook 已提交
4555
            {
P
pbrook 已提交
4556 4557 4558
                int rtmp;
                /* Shift instruction operands are reversed.  */
                rtmp = rn;
P
pbrook 已提交
4559
                rn = rm;
P
pbrook 已提交
4560
                rm = rtmp;
P
pbrook 已提交
4561
            }
B
bellard 已提交
4562
            break;
4563 4564 4565 4566 4567
        case NEON_3R_VPADD:
            if (u) {
                return 1;
            }
            /* Fall through */
4568 4569
        case NEON_3R_VPMAX:
        case NEON_3R_VPMIN:
P
pbrook 已提交
4570
            pairwise = 1;
B
bellard 已提交
4571
            break;
4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592
        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;
        case NEON_3R_VRECPS_VRSQRTS:
            if (u) {
                return 1;
            }
B
bellard 已提交
4593
            break;
4594 4595 4596 4597 4598
        case NEON_3R_VMUL:
            if (u && (size != 0)) {
                /* UNDEF on invalid size for polynomial subcase */
                return 1;
            }
B
bellard 已提交
4599
            break;
4600 4601 4602 4603 4604
        case NEON_3R_VFM:
            if (!arm_feature(env, ARM_FEATURE_VFP4) || u) {
                return 1;
            }
            break;
P
pbrook 已提交
4605
        default:
B
bellard 已提交
4606
            break;
P
pbrook 已提交
4607
        }
4608

4609 4610 4611 4612 4613
        if (pairwise && q) {
            /* All the pairwise insns UNDEF if Q is set */
            return 1;
        }

P
pbrook 已提交
4614 4615 4616 4617
        for (pass = 0; pass < (q ? 4 : 2); pass++) {

        if (pairwise) {
            /* Pairwise.  */
4618 4619 4620
            if (pass < 1) {
                tmp = neon_load_reg(rn, 0);
                tmp2 = neon_load_reg(rn, 1);
P
pbrook 已提交
4621
            } else {
4622 4623
                tmp = neon_load_reg(rm, 0);
                tmp2 = neon_load_reg(rm, 1);
P
pbrook 已提交
4624 4625 4626
            }
        } else {
            /* Elementwise.  */
4627 4628
            tmp = neon_load_reg(rn, pass);
            tmp2 = neon_load_reg(rm, pass);
P
pbrook 已提交
4629 4630
        }
        switch (op) {
4631
        case NEON_3R_VHADD:
P
pbrook 已提交
4632 4633
            GEN_NEON_INTEGER_OP(hadd);
            break;
4634
        case NEON_3R_VQADD:
4635
            GEN_NEON_INTEGER_OP_ENV(qadd);
B
bellard 已提交
4636
            break;
4637
        case NEON_3R_VRHADD:
P
pbrook 已提交
4638
            GEN_NEON_INTEGER_OP(rhadd);
B
bellard 已提交
4639
            break;
4640
        case NEON_3R_LOGIC: /* Logic ops.  */
P
pbrook 已提交
4641 4642
            switch ((u << 2) | size) {
            case 0: /* VAND */
4643
                tcg_gen_and_i32(tmp, tmp, tmp2);
P
pbrook 已提交
4644 4645
                break;
            case 1: /* BIC */
4646
                tcg_gen_andc_i32(tmp, tmp, tmp2);
P
pbrook 已提交
4647 4648
                break;
            case 2: /* VORR */
4649
                tcg_gen_or_i32(tmp, tmp, tmp2);
P
pbrook 已提交
4650 4651
                break;
            case 3: /* VORN */
4652
                tcg_gen_orc_i32(tmp, tmp, tmp2);
P
pbrook 已提交
4653 4654
                break;
            case 4: /* VEOR */
4655
                tcg_gen_xor_i32(tmp, tmp, tmp2);
P
pbrook 已提交
4656 4657
                break;
            case 5: /* VBSL */
4658 4659
                tmp3 = neon_load_reg(rd, pass);
                gen_neon_bsl(tmp, tmp, tmp2, tmp3);
4660
                tcg_temp_free_i32(tmp3);
P
pbrook 已提交
4661 4662
                break;
            case 6: /* VBIT */
4663 4664
                tmp3 = neon_load_reg(rd, pass);
                gen_neon_bsl(tmp, tmp, tmp3, tmp2);
4665
                tcg_temp_free_i32(tmp3);
P
pbrook 已提交
4666 4667
                break;
            case 7: /* VBIF */
4668 4669
                tmp3 = neon_load_reg(rd, pass);
                gen_neon_bsl(tmp, tmp3, tmp, tmp2);
4670
                tcg_temp_free_i32(tmp3);
P
pbrook 已提交
4671
                break;
B
bellard 已提交
4672 4673
            }
            break;
4674
        case NEON_3R_VHSUB:
P
pbrook 已提交
4675 4676
            GEN_NEON_INTEGER_OP(hsub);
            break;
4677
        case NEON_3R_VQSUB:
4678
            GEN_NEON_INTEGER_OP_ENV(qsub);
B
bellard 已提交
4679
            break;
4680
        case NEON_3R_VCGT:
P
pbrook 已提交
4681 4682
            GEN_NEON_INTEGER_OP(cgt);
            break;
4683
        case NEON_3R_VCGE:
P
pbrook 已提交
4684 4685
            GEN_NEON_INTEGER_OP(cge);
            break;
4686
        case NEON_3R_VSHL:
P
pbrook 已提交
4687
            GEN_NEON_INTEGER_OP(shl);
B
bellard 已提交
4688
            break;
4689
        case NEON_3R_VQSHL:
4690
            GEN_NEON_INTEGER_OP_ENV(qshl);
B
bellard 已提交
4691
            break;
4692
        case NEON_3R_VRSHL:
P
pbrook 已提交
4693
            GEN_NEON_INTEGER_OP(rshl);
B
bellard 已提交
4694
            break;
4695
        case NEON_3R_VQRSHL:
4696
            GEN_NEON_INTEGER_OP_ENV(qrshl);
P
pbrook 已提交
4697
            break;
4698
        case NEON_3R_VMAX:
P
pbrook 已提交
4699 4700
            GEN_NEON_INTEGER_OP(max);
            break;
4701
        case NEON_3R_VMIN:
P
pbrook 已提交
4702 4703
            GEN_NEON_INTEGER_OP(min);
            break;
4704
        case NEON_3R_VABD:
P
pbrook 已提交
4705 4706
            GEN_NEON_INTEGER_OP(abd);
            break;
4707
        case NEON_3R_VABA:
P
pbrook 已提交
4708
            GEN_NEON_INTEGER_OP(abd);
4709
            tcg_temp_free_i32(tmp2);
4710 4711
            tmp2 = neon_load_reg(rd, pass);
            gen_neon_add(size, tmp, tmp2);
P
pbrook 已提交
4712
            break;
4713
        case NEON_3R_VADD_VSUB:
P
pbrook 已提交
4714
            if (!u) { /* VADD */
4715
                gen_neon_add(size, tmp, tmp2);
P
pbrook 已提交
4716 4717
            } else { /* VSUB */
                switch (size) {
4718 4719 4720
                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;
4721
                default: abort();
P
pbrook 已提交
4722 4723 4724
                }
            }
            break;
4725
        case NEON_3R_VTST_VCEQ:
P
pbrook 已提交
4726 4727
            if (!u) { /* VTST */
                switch (size) {
4728 4729 4730
                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;
4731
                default: abort();
P
pbrook 已提交
4732 4733 4734
                }
            } else { /* VCEQ */
                switch (size) {
4735 4736 4737
                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;
4738
                default: abort();
P
pbrook 已提交
4739 4740 4741
                }
            }
            break;
4742
        case NEON_3R_VML: /* VMLA, VMLAL, VMLS,VMLSL */
P
pbrook 已提交
4743
            switch (size) {
4744 4745 4746
            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;
4747
            default: abort();
P
pbrook 已提交
4748
            }
4749
            tcg_temp_free_i32(tmp2);
4750
            tmp2 = neon_load_reg(rd, pass);
P
pbrook 已提交
4751
            if (u) { /* VMLS */
4752
                gen_neon_rsb(size, tmp, tmp2);
P
pbrook 已提交
4753
            } else { /* VMLA */
4754
                gen_neon_add(size, tmp, tmp2);
P
pbrook 已提交
4755 4756
            }
            break;
4757
        case NEON_3R_VMUL:
P
pbrook 已提交
4758
            if (u) { /* polynomial */
4759
                gen_helper_neon_mul_p8(tmp, tmp, tmp2);
P
pbrook 已提交
4760 4761
            } else { /* Integer */
                switch (size) {
4762 4763 4764
                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;
4765
                default: abort();
P
pbrook 已提交
4766 4767 4768
                }
            }
            break;
4769
        case NEON_3R_VPMAX:
P
pbrook 已提交
4770 4771
            GEN_NEON_INTEGER_OP(pmax);
            break;
4772
        case NEON_3R_VPMIN:
P
pbrook 已提交
4773 4774
            GEN_NEON_INTEGER_OP(pmin);
            break;
4775
        case NEON_3R_VQDMULH_VQRDMULH: /* Multiply high.  */
P
pbrook 已提交
4776 4777
            if (!u) { /* VQDMULH */
                switch (size) {
4778 4779 4780 4781 4782 4783
                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;
4784
                default: abort();
P
pbrook 已提交
4785
                }
4786
            } else { /* VQRDMULH */
P
pbrook 已提交
4787
                switch (size) {
4788 4789 4790 4791 4792 4793
                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;
4794
                default: abort();
P
pbrook 已提交
4795 4796 4797
                }
            }
            break;
4798
        case NEON_3R_VPADD:
P
pbrook 已提交
4799
            switch (size) {
4800 4801 4802
            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;
4803
            default: abort();
P
pbrook 已提交
4804 4805
            }
            break;
4806
        case NEON_3R_FLOAT_ARITH: /* Floating point arithmetic. */
4807 4808
        {
            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
P
pbrook 已提交
4809 4810
            switch ((u << 2) | size) {
            case 0: /* VADD */
4811 4812
            case 4: /* VPADD */
                gen_helper_vfp_adds(tmp, tmp, tmp2, fpstatus);
P
pbrook 已提交
4813 4814
                break;
            case 2: /* VSUB */
4815
                gen_helper_vfp_subs(tmp, tmp, tmp2, fpstatus);
P
pbrook 已提交
4816 4817
                break;
            case 6: /* VABD */
4818
                gen_helper_neon_abd_f32(tmp, tmp, tmp2, fpstatus);
P
pbrook 已提交
4819 4820
                break;
            default:
4821
                abort();
P
pbrook 已提交
4822
            }
4823
            tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
4824
            break;
4825
        }
4826
        case NEON_3R_FLOAT_MULTIPLY:
4827 4828 4829
        {
            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
            gen_helper_vfp_muls(tmp, tmp, tmp2, fpstatus);
P
pbrook 已提交
4830
            if (!u) {
4831
                tcg_temp_free_i32(tmp2);
4832
                tmp2 = neon_load_reg(rd, pass);
P
pbrook 已提交
4833
                if (size == 0) {
4834
                    gen_helper_vfp_adds(tmp, tmp, tmp2, fpstatus);
P
pbrook 已提交
4835
                } else {
4836
                    gen_helper_vfp_subs(tmp, tmp2, tmp, fpstatus);
P
pbrook 已提交
4837 4838
                }
            }
4839
            tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
4840
            break;
4841
        }
4842
        case NEON_3R_FLOAT_CMP:
4843 4844
        {
            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
P
pbrook 已提交
4845
            if (!u) {
4846
                gen_helper_neon_ceq_f32(tmp, tmp, tmp2, fpstatus);
B
bellard 已提交
4847
            } else {
4848 4849 4850 4851 4852
                if (size == 0) {
                    gen_helper_neon_cge_f32(tmp, tmp, tmp2, fpstatus);
                } else {
                    gen_helper_neon_cgt_f32(tmp, tmp, tmp2, fpstatus);
                }
B
bellard 已提交
4853
            }
4854
            tcg_temp_free_ptr(fpstatus);
B
bellard 已提交
4855
            break;
4856
        }
4857
        case NEON_3R_FLOAT_ACMP:
4858 4859 4860 4861 4862 4863 4864 4865
        {
            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 已提交
4866
            break;
4867
        }
4868
        case NEON_3R_FLOAT_MINMAX:
4869 4870 4871 4872 4873 4874 4875 4876
        {
            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
            if (size == 0) {
                gen_helper_neon_max_f32(tmp, tmp, tmp2, fpstatus);
            } else {
                gen_helper_neon_min_f32(tmp, tmp, tmp2, fpstatus);
            }
            tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
4877
            break;
4878
        }
4879
        case NEON_3R_VRECPS_VRSQRTS:
P
pbrook 已提交
4880
            if (size == 0)
4881
                gen_helper_recps_f32(tmp, tmp, tmp2, cpu_env);
P
pbrook 已提交
4882
            else
4883
                gen_helper_rsqrts_f32(tmp, tmp, tmp2, cpu_env);
B
bellard 已提交
4884
            break;
4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898
        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 已提交
4899 4900
        default:
            abort();
B
bellard 已提交
4901
        }
4902
        tcg_temp_free_i32(tmp2);
4903

P
pbrook 已提交
4904 4905 4906 4907
        /* 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) {
4908
            neon_store_scratch(pass, tmp);
P
pbrook 已提交
4909
        } else {
4910
            neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
4911 4912 4913 4914 4915
        }

        } /* for pass */
        if (pairwise && rd == rm) {
            for (pass = 0; pass < (q ? 4 : 2); pass++) {
4916 4917
                tmp = neon_load_scratch(pass);
                neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
4918 4919
            }
        }
P
pbrook 已提交
4920
        /* End of 3 register same size operations.  */
P
pbrook 已提交
4921 4922 4923 4924 4925
    } else if (insn & (1 << 4)) {
        if ((insn & 0x00380080) != 0) {
            /* Two registers and shift.  */
            op = (insn >> 8) & 0xf;
            if (insn & (1 << 7)) {
4926 4927 4928 4929
                /* 64-bit shift. */
                if (op > 7) {
                    return 1;
                }
P
pbrook 已提交
4930 4931 4932 4933 4934 4935 4936
                size = 3;
            } else {
                size = 2;
                while ((insn & (1 << (size + 19))) == 0)
                    size--;
            }
            shift = (insn >> 16) & ((1 << (3 + size)) - 1);
4937
            /* To avoid excessive duplication of ops we implement shift
P
pbrook 已提交
4938 4939 4940 4941
               by immediate using the variable shift operations.  */
            if (op < 8) {
                /* Shift by immediate:
                   VSHR, VSRA, VRSHR, VRSRA, VSRI, VSHL, VQSHL, VQSHLU.  */
4942 4943 4944 4945 4946 4947
                if (q && ((rd | rm) & 1)) {
                    return 1;
                }
                if (!u && (op == 4 || op == 6)) {
                    return 1;
                }
P
pbrook 已提交
4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975
                /* 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 已提交
4976 4977 4978 4979 4980 4981 4982 4983
                    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 已提交
4984
                            else
P
pbrook 已提交
4985
                                gen_helper_neon_shl_s64(cpu_V0, cpu_V0, cpu_V1);
P
pbrook 已提交
4986
                            break;
P
pbrook 已提交
4987 4988 4989 4990
                        case 2: /* VRSHR */
                        case 3: /* VRSRA */
                            if (u)
                                gen_helper_neon_rshl_u64(cpu_V0, cpu_V0, cpu_V1);
P
pbrook 已提交
4991
                            else
P
pbrook 已提交
4992
                                gen_helper_neon_rshl_s64(cpu_V0, cpu_V0, cpu_V1);
P
pbrook 已提交
4993
                            break;
P
pbrook 已提交
4994 4995 4996 4997
                        case 4: /* VSRI */
                        case 5: /* VSHL, VSLI */
                            gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1);
                            break;
4998
                        case 6: /* VQSHLU */
4999 5000
                            gen_helper_neon_qshlu_s64(cpu_V0, cpu_env,
                                                      cpu_V0, cpu_V1);
P
pbrook 已提交
5001
                            break;
5002 5003
                        case 7: /* VQSHL */
                            if (u) {
5004
                                gen_helper_neon_qshl_u64(cpu_V0, cpu_env,
5005 5006
                                                         cpu_V0, cpu_V1);
                            } else {
5007
                                gen_helper_neon_qshl_s64(cpu_V0, cpu_env,
5008 5009
                                                         cpu_V0, cpu_V1);
                            }
P
pbrook 已提交
5010 5011
                            break;
                        }
P
pbrook 已提交
5012 5013
                        if (op == 1 || op == 3) {
                            /* Accumulate.  */
5014
                            neon_load_reg64(cpu_V1, rd + pass);
P
pbrook 已提交
5015 5016 5017
                            tcg_gen_add_i64(cpu_V0, cpu_V0, cpu_V1);
                        } else if (op == 4 || (op == 5 && u)) {
                            /* Insert */
5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030
                            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 已提交
5031 5032 5033 5034
                        }
                        neon_store_reg64(cpu_V0, rd + pass);
                    } else { /* size < 3 */
                        /* Operands in T0 and T1.  */
5035
                        tmp = neon_load_reg(rm, pass);
5036
                        tmp2 = tcg_temp_new_i32();
5037
                        tcg_gen_movi_i32(tmp2, imm);
P
pbrook 已提交
5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049
                        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) {
5050 5051 5052
                            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;
5053
                            default: abort();
P
pbrook 已提交
5054 5055
                            }
                            break;
5056
                        case 6: /* VQSHLU */
P
pbrook 已提交
5057
                            switch (size) {
5058
                            case 0:
5059 5060
                                gen_helper_neon_qshlu_s8(tmp, cpu_env,
                                                         tmp, tmp2);
5061 5062
                                break;
                            case 1:
5063 5064
                                gen_helper_neon_qshlu_s16(tmp, cpu_env,
                                                          tmp, tmp2);
5065 5066
                                break;
                            case 2:
5067 5068
                                gen_helper_neon_qshlu_s32(tmp, cpu_env,
                                                          tmp, tmp2);
5069 5070
                                break;
                            default:
5071
                                abort();
P
pbrook 已提交
5072 5073
                            }
                            break;
5074
                        case 7: /* VQSHL */
5075
                            GEN_NEON_INTEGER_OP_ENV(qshl);
5076
                            break;
P
pbrook 已提交
5077
                        }
5078
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
5079 5080 5081

                        if (op == 1 || op == 3) {
                            /* Accumulate.  */
5082
                            tmp2 = neon_load_reg(rd, pass);
5083
                            gen_neon_add(size, tmp, tmp2);
5084
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
5085 5086 5087 5088 5089
                        } else if (op == 4 || (op == 5 && u)) {
                            /* Insert */
                            switch (size) {
                            case 0:
                                if (op == 4)
5090
                                    mask = 0xff >> -shift;
P
pbrook 已提交
5091
                                else
5092 5093 5094
                                    mask = (uint8_t)(0xff << shift);
                                mask |= mask << 8;
                                mask |= mask << 16;
P
pbrook 已提交
5095 5096 5097
                                break;
                            case 1:
                                if (op == 4)
5098
                                    mask = 0xffff >> -shift;
P
pbrook 已提交
5099
                                else
5100 5101
                                    mask = (uint16_t)(0xffff << shift);
                                mask |= mask << 16;
P
pbrook 已提交
5102 5103
                                break;
                            case 2:
5104 5105 5106 5107 5108 5109 5110 5111
                                if (shift < -31 || shift > 31) {
                                    mask = 0;
                                } else {
                                    if (op == 4)
                                        mask = 0xffffffffu >> -shift;
                                    else
                                        mask = 0xffffffffu << shift;
                                }
P
pbrook 已提交
5112 5113 5114 5115
                                break;
                            default:
                                abort();
                            }
5116
                            tmp2 = neon_load_reg(rd, pass);
5117 5118
                            tcg_gen_andi_i32(tmp, tmp, mask);
                            tcg_gen_andi_i32(tmp2, tmp2, ~mask);
5119
                            tcg_gen_or_i32(tmp, tmp, tmp2);
5120
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
5121
                        }
5122
                        neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
5123 5124 5125
                    }
                } /* for pass */
            } else if (op < 10) {
P
pbrook 已提交
5126
                /* Shift by immediate and narrow:
P
pbrook 已提交
5127
                   VSHRN, VRSHRN, VQSHRN, VQRSHRN.  */
5128
                int input_unsigned = (op == 8) ? !u : u;
5129 5130 5131
                if (rm & 1) {
                    return 1;
                }
P
pbrook 已提交
5132 5133
                shift = shift - (1 << (size + 3));
                size++;
5134
                if (size == 3) {
P
pbrook 已提交
5135
                    tmp64 = tcg_const_i64(shift);
5136 5137 5138 5139 5140 5141 5142 5143 5144
                    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 已提交
5145
                        if (q) {
5146
                            if (input_unsigned) {
5147
                                gen_helper_neon_rshl_u64(cpu_V0, in, tmp64);
5148
                            } else {
5149
                                gen_helper_neon_rshl_s64(cpu_V0, in, tmp64);
5150
                            }
P
pbrook 已提交
5151
                        } else {
5152
                            if (input_unsigned) {
5153
                                gen_helper_neon_shl_u64(cpu_V0, in, tmp64);
5154
                            } else {
5155
                                gen_helper_neon_shl_s64(cpu_V0, in, tmp64);
5156
                            }
P
pbrook 已提交
5157
                        }
5158
                        tmp = tcg_temp_new_i32();
5159 5160 5161 5162 5163 5164 5165 5166
                        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 已提交
5167
                    } else {
5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179
                        /* 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;
                        }
5180 5181
                        gen_neon_shift_narrow(size, tmp, tmp2, q,
                                              input_unsigned);
5182 5183 5184 5185 5186
                        if (pass == 0) {
                            tmp3 = neon_load_reg(rm, 1);
                        } else {
                            tmp3 = tmp5;
                        }
5187 5188
                        gen_neon_shift_narrow(size, tmp3, tmp2, q,
                                              input_unsigned);
P
pbrook 已提交
5189
                        tcg_gen_concat_i32_i64(cpu_V0, tmp, tmp3);
5190 5191 5192
                        tcg_temp_free_i32(tmp);
                        tcg_temp_free_i32(tmp3);
                        tmp = tcg_temp_new_i32();
5193 5194 5195
                        gen_neon_narrow_op(op == 8, u, size - 1, tmp, cpu_V0);
                        neon_store_reg(rd, pass, tmp);
                    } /* for pass */
5196
                    tcg_temp_free_i32(tmp2);
5197
                }
P
pbrook 已提交
5198
            } else if (op == 10) {
5199 5200
                /* VSHLL, VMOVL */
                if (q || (rd & 1)) {
P
pbrook 已提交
5201
                    return 1;
5202
                }
P
pbrook 已提交
5203 5204
                tmp = neon_load_reg(rm, 0);
                tmp2 = neon_load_reg(rm, 1);
P
pbrook 已提交
5205
                for (pass = 0; pass < 2; pass++) {
P
pbrook 已提交
5206 5207 5208 5209
                    if (pass == 1)
                        tmp = tmp2;

                    gen_neon_widen(cpu_V0, tmp, size, u);
P
pbrook 已提交
5210 5211 5212

                    if (shift != 0) {
                        /* The shift is less than the width of the source
P
pbrook 已提交
5213 5214
                           type, so we can just shift the whole register.  */
                        tcg_gen_shli_i64(cpu_V0, cpu_V0, shift);
5215 5216 5217 5218 5219
                        /* 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 已提交
5220 5221 5222 5223 5224
                        if (size < 2 || !u) {
                            uint64_t imm64;
                            if (size == 0) {
                                imm = (0xffu >> (8 - shift));
                                imm |= imm << 16;
5225
                            } else if (size == 1) {
P
pbrook 已提交
5226
                                imm = 0xffff >> (16 - shift);
5227 5228 5229 5230 5231 5232 5233 5234
                            } else {
                                /* size == 2 */
                                imm = 0xffffffff >> (32 - shift);
                            }
                            if (size < 2) {
                                imm64 = imm | (((uint64_t)imm) << 32);
                            } else {
                                imm64 = imm;
P
pbrook 已提交
5235
                            }
5236
                            tcg_gen_andi_i64(cpu_V0, cpu_V0, ~imm64);
P
pbrook 已提交
5237 5238
                        }
                    }
P
pbrook 已提交
5239
                    neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
5240
                }
5241
            } else if (op >= 14) {
P
pbrook 已提交
5242
                /* VCVT fixed-point.  */
5243 5244 5245
                if (!(insn & (1 << 21)) || (q && ((rd | rm) & 1))) {
                    return 1;
                }
5246 5247 5248 5249
                /* 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 已提交
5250
                for (pass = 0; pass < (q ? 4 : 2); pass++) {
P
pbrook 已提交
5251
                    tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, pass));
5252
                    if (!(op & 1)) {
P
pbrook 已提交
5253
                        if (u)
5254
                            gen_vfp_ulto(0, shift, 1);
P
pbrook 已提交
5255
                        else
5256
                            gen_vfp_slto(0, shift, 1);
P
pbrook 已提交
5257 5258
                    } else {
                        if (u)
5259
                            gen_vfp_toul(0, shift, 1);
P
pbrook 已提交
5260
                        else
5261
                            gen_vfp_tosl(0, shift, 1);
B
bellard 已提交
5262
                    }
P
pbrook 已提交
5263
                    tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, pass));
B
bellard 已提交
5264 5265
                }
            } else {
P
pbrook 已提交
5266 5267 5268 5269
                return 1;
            }
        } else { /* (insn & 0x00380080) == 0 */
            int invert;
5270 5271 5272
            if (q && (rd & 1)) {
                return 1;
            }
P
pbrook 已提交
5273 5274 5275 5276 5277

            op = (insn >> 8) & 0xf;
            /* One register and immediate.  */
            imm = (u << 7) | ((insn >> 12) & 0x70) | (insn & 0xf);
            invert = (insn & (1 << 5)) != 0;
5278 5279 5280 5281
            /* 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 已提交
5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301
            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:
5302
                imm = (imm << 8) | 0xff;
P
pbrook 已提交
5303 5304 5305 5306 5307 5308 5309 5310 5311 5312
                break;
            case 13:
                imm = (imm << 16) | 0xffff;
                break;
            case 14:
                imm |= (imm << 8) | (imm << 16) | (imm << 24);
                if (invert)
                    imm = ~imm;
                break;
            case 15:
5313 5314 5315
                if (invert) {
                    return 1;
                }
P
pbrook 已提交
5316 5317 5318 5319 5320 5321 5322 5323 5324
                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 已提交
5325
                    tmp = neon_load_reg(rd, pass);
P
pbrook 已提交
5326 5327 5328
                    if (invert) {
                        /* The immediate value has already been inverted, so
                           BIC becomes AND.  */
P
pbrook 已提交
5329
                        tcg_gen_andi_i32(tmp, tmp, imm);
P
pbrook 已提交
5330
                    } else {
P
pbrook 已提交
5331
                        tcg_gen_ori_i32(tmp, tmp, imm);
P
pbrook 已提交
5332 5333
                    }
                } else {
P
pbrook 已提交
5334
                    /* VMOV, VMVN.  */
5335
                    tmp = tcg_temp_new_i32();
P
pbrook 已提交
5336
                    if (op == 14 && invert) {
5337
                        int n;
P
pbrook 已提交
5338 5339
                        uint32_t val;
                        val = 0;
P
pbrook 已提交
5340 5341
                        for (n = 0; n < 4; n++) {
                            if (imm & (1 << (n + (pass & 1) * 4)))
P
pbrook 已提交
5342
                                val |= 0xff << (n * 8);
P
pbrook 已提交
5343
                        }
P
pbrook 已提交
5344 5345 5346
                        tcg_gen_movi_i32(tmp, val);
                    } else {
                        tcg_gen_movi_i32(tmp, imm);
P
pbrook 已提交
5347 5348
                    }
                }
P
pbrook 已提交
5349
                neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
5350 5351
            }
        }
P
pbrook 已提交
5352
    } else { /* (insn & 0x00800010 == 0x00800000) */
P
pbrook 已提交
5353 5354 5355 5356 5357 5358 5359
        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;
5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383
                /* undefreq: bit 0 : UNDEF if size != 0
                 *           bit 1 : UNDEF if size == 0
                 *           bit 2 : UNDEF if U == 1
                 * Note that [1:0] set implies 'always UNDEF'
                 */
                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 */
                    {0, 0, 0, 6}, /* VQDMLAL */
                    {0, 0, 0, 0}, /* VMLSL */
                    {0, 0, 0, 6}, /* VQDMLSL */
                    {0, 0, 0, 0}, /* Integer VMULL */
                    {0, 0, 0, 2}, /* VQDMULL */
                    {0, 0, 0, 5}, /* Polynomial VMULL */
                    {0, 0, 0, 3}, /* Reserved: always UNDEF */
P
pbrook 已提交
5384 5385 5386 5387 5388
                };

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

5391 5392 5393 5394 5395 5396 5397 5398
                if (((undefreq & 1) && (size != 0)) ||
                    ((undefreq & 2) && (size == 0)) ||
                    ((undefreq & 4) && u)) {
                    return 1;
                }
                if ((src1_wide && (rn & 1)) ||
                    (src2_wide && (rm & 1)) ||
                    (!src2_wide && (rd & 1))) {
P
pbrook 已提交
5399
                    return 1;
5400
                }
P
pbrook 已提交
5401

P
pbrook 已提交
5402 5403 5404
                /* Avoid overlapping operands.  Wide source operands are
                   always aligned so will never overlap with wide
                   destinations in problematic ways.  */
P
pbrook 已提交
5405
                if (rd == rm && !src2_wide) {
5406 5407
                    tmp = neon_load_reg(rm, 1);
                    neon_store_scratch(2, tmp);
P
pbrook 已提交
5408
                } else if (rd == rn && !src1_wide) {
5409 5410
                    tmp = neon_load_reg(rn, 1);
                    neon_store_scratch(2, tmp);
P
pbrook 已提交
5411
                }
5412
                TCGV_UNUSED_I32(tmp3);
P
pbrook 已提交
5413
                for (pass = 0; pass < 2; pass++) {
P
pbrook 已提交
5414 5415
                    if (src1_wide) {
                        neon_load_reg64(cpu_V0, rn + pass);
5416
                        TCGV_UNUSED_I32(tmp);
P
pbrook 已提交
5417
                    } else {
P
pbrook 已提交
5418
                        if (pass == 1 && rd == rn) {
5419
                            tmp = neon_load_scratch(2);
P
pbrook 已提交
5420
                        } else {
P
pbrook 已提交
5421 5422 5423 5424
                            tmp = neon_load_reg(rn, pass);
                        }
                        if (prewiden) {
                            gen_neon_widen(cpu_V0, tmp, size, u);
P
pbrook 已提交
5425 5426
                        }
                    }
P
pbrook 已提交
5427 5428
                    if (src2_wide) {
                        neon_load_reg64(cpu_V1, rm + pass);
5429
                        TCGV_UNUSED_I32(tmp2);
P
pbrook 已提交
5430
                    } else {
P
pbrook 已提交
5431
                        if (pass == 1 && rd == rm) {
5432
                            tmp2 = neon_load_scratch(2);
P
pbrook 已提交
5433
                        } else {
P
pbrook 已提交
5434 5435 5436 5437
                            tmp2 = neon_load_reg(rm, pass);
                        }
                        if (prewiden) {
                            gen_neon_widen(cpu_V1, tmp2, size, u);
P
pbrook 已提交
5438 5439 5440 5441
                        }
                    }
                    switch (op) {
                    case 0: case 1: case 4: /* VADDL, VADDW, VADDHN, VRADDHN */
P
pbrook 已提交
5442
                        gen_neon_addl(size);
P
pbrook 已提交
5443
                        break;
5444
                    case 2: case 3: case 6: /* VSUBL, VSUBW, VSUBHN, VRSUBHN */
P
pbrook 已提交
5445
                        gen_neon_subl(size);
P
pbrook 已提交
5446 5447 5448
                        break;
                    case 5: case 7: /* VABAL, VABDL */
                        switch ((size << 1) | u) {
P
pbrook 已提交
5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466
                        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 已提交
5467 5468
                        default: abort();
                        }
5469 5470
                        tcg_temp_free_i32(tmp2);
                        tcg_temp_free_i32(tmp);
P
pbrook 已提交
5471 5472 5473
                        break;
                    case 8: case 9: case 10: case 11: case 12: case 13:
                        /* VMLAL, VQDMLAL, VMLSL, VQDMLSL, VMULL, VQDMULL */
P
pbrook 已提交
5474
                        gen_neon_mull(cpu_V0, tmp, tmp2, size, u);
P
pbrook 已提交
5475 5476
                        break;
                    case 14: /* Polynomial VMULL */
P
Peter Maydell 已提交
5477
                        gen_helper_neon_mull_p8(cpu_V0, tmp, tmp2);
5478 5479
                        tcg_temp_free_i32(tmp2);
                        tcg_temp_free_i32(tmp);
P
Peter Maydell 已提交
5480
                        break;
5481 5482
                    default: /* 15 is RESERVED: caught earlier  */
                        abort();
P
pbrook 已提交
5483
                    }
5484 5485 5486 5487 5488
                    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 已提交
5489
                        /* Accumulate.  */
5490
                        neon_load_reg64(cpu_V1, rd + pass);
P
pbrook 已提交
5491
                        switch (op) {
5492 5493 5494 5495
                        case 10: /* VMLSL */
                            gen_neon_negl(cpu_V0, size);
                            /* Fall through */
                        case 5: case 8: /* VABAL, VMLAL */
P
pbrook 已提交
5496
                            gen_neon_addl(size);
P
pbrook 已提交
5497 5498
                            break;
                        case 9: case 11: /* VQDMLAL, VQDMLSL */
P
pbrook 已提交
5499
                            gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
5500 5501 5502
                            if (op == 11) {
                                gen_neon_negl(cpu_V0, size);
                            }
P
pbrook 已提交
5503 5504
                            gen_neon_addl_saturate(cpu_V0, cpu_V1, size);
                            break;
P
pbrook 已提交
5505 5506 5507
                        default:
                            abort();
                        }
P
pbrook 已提交
5508
                        neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
5509 5510
                    } else if (op == 4 || op == 6) {
                        /* Narrowing operation.  */
5511
                        tmp = tcg_temp_new_i32();
5512
                        if (!u) {
P
pbrook 已提交
5513
                            switch (size) {
P
pbrook 已提交
5514 5515 5516 5517 5518 5519 5520 5521 5522 5523
                            case 0:
                                gen_helper_neon_narrow_high_u8(tmp, cpu_V0);
                                break;
                            case 1:
                                gen_helper_neon_narrow_high_u16(tmp, cpu_V0);
                                break;
                            case 2:
                                tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
                                tcg_gen_trunc_i64_i32(tmp, cpu_V0);
                                break;
P
pbrook 已提交
5524 5525 5526 5527
                            default: abort();
                            }
                        } else {
                            switch (size) {
P
pbrook 已提交
5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538
                            case 0:
                                gen_helper_neon_narrow_round_high_u8(tmp, cpu_V0);
                                break;
                            case 1:
                                gen_helper_neon_narrow_round_high_u16(tmp, cpu_V0);
                                break;
                            case 2:
                                tcg_gen_addi_i64(cpu_V0, cpu_V0, 1u << 31);
                                tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
                                tcg_gen_trunc_i64_i32(tmp, cpu_V0);
                                break;
P
pbrook 已提交
5539 5540 5541
                            default: abort();
                            }
                        }
P
pbrook 已提交
5542 5543 5544 5545 5546 5547
                        if (pass == 0) {
                            tmp3 = tmp;
                        } else {
                            neon_store_reg(rd, 0, tmp3);
                            neon_store_reg(rd, 1, tmp);
                        }
P
pbrook 已提交
5548 5549
                    } else {
                        /* Write back the result.  */
P
pbrook 已提交
5550
                        neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
5551 5552 5553
                    }
                }
            } else {
5554 5555 5556 5557 5558 5559 5560
                /* 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 已提交
5561 5562 5563 5564
                switch (op) {
                case 1: /* Float VMLA scalar */
                case 5: /* Floating point VMLS scalar */
                case 9: /* Floating point VMUL scalar */
5565 5566 5567 5568 5569 5570 5571
                    if (size == 1) {
                        return 1;
                    }
                    /* fall through */
                case 0: /* Integer VMLA scalar */
                case 4: /* Integer VMLS scalar */
                case 8: /* Integer VMUL scalar */
P
pbrook 已提交
5572 5573
                case 12: /* VQDMULH scalar */
                case 13: /* VQRDMULH scalar */
5574 5575 5576
                    if (u && ((rd | rn) & 1)) {
                        return 1;
                    }
5577 5578
                    tmp = neon_get_scalar(size, rm);
                    neon_store_scratch(0, tmp);
P
pbrook 已提交
5579
                    for (pass = 0; pass < (u ? 4 : 2); pass++) {
5580 5581
                        tmp = neon_load_scratch(0);
                        tmp2 = neon_load_reg(rn, pass);
P
pbrook 已提交
5582 5583
                        if (op == 12) {
                            if (size == 1) {
5584
                                gen_helper_neon_qdmulh_s16(tmp, cpu_env, tmp, tmp2);
P
pbrook 已提交
5585
                            } else {
5586
                                gen_helper_neon_qdmulh_s32(tmp, cpu_env, tmp, tmp2);
P
pbrook 已提交
5587 5588 5589
                            }
                        } else if (op == 13) {
                            if (size == 1) {
5590
                                gen_helper_neon_qrdmulh_s16(tmp, cpu_env, tmp, tmp2);
P
pbrook 已提交
5591
                            } else {
5592
                                gen_helper_neon_qrdmulh_s32(tmp, cpu_env, tmp, tmp2);
P
pbrook 已提交
5593 5594
                            }
                        } else if (op & 1) {
5595 5596 5597
                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
                            gen_helper_vfp_muls(tmp, tmp, tmp2, fpstatus);
                            tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
5598 5599
                        } else {
                            switch (size) {
5600 5601 5602
                            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;
5603
                            default: abort();
P
pbrook 已提交
5604 5605
                            }
                        }
5606
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
5607 5608
                        if (op < 8) {
                            /* Accumulate.  */
5609
                            tmp2 = neon_load_reg(rd, pass);
P
pbrook 已提交
5610 5611
                            switch (op) {
                            case 0:
5612
                                gen_neon_add(size, tmp, tmp2);
P
pbrook 已提交
5613 5614
                                break;
                            case 1:
5615 5616 5617 5618
                            {
                                TCGv_ptr fpstatus = get_fpstatus_ptr(1);
                                gen_helper_vfp_adds(tmp, tmp, tmp2, fpstatus);
                                tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
5619
                                break;
5620
                            }
P
pbrook 已提交
5621
                            case 4:
5622
                                gen_neon_rsb(size, tmp, tmp2);
P
pbrook 已提交
5623 5624
                                break;
                            case 5:
5625 5626 5627 5628
                            {
                                TCGv_ptr fpstatus = get_fpstatus_ptr(1);
                                gen_helper_vfp_subs(tmp, tmp2, tmp, fpstatus);
                                tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
5629
                                break;
5630
                            }
P
pbrook 已提交
5631 5632 5633
                            default:
                                abort();
                            }
5634
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
5635
                        }
5636
                        neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
5637 5638 5639 5640 5641
                    }
                    break;
                case 3: /* VQDMLAL scalar */
                case 7: /* VQDMLSL scalar */
                case 11: /* VQDMULL scalar */
5642
                    if (u == 1) {
P
pbrook 已提交
5643
                        return 1;
5644 5645 5646 5647 5648 5649 5650 5651
                    }
                    /* fall through */
                case 2: /* VMLAL sclar */
                case 6: /* VMLSL scalar */
                case 10: /* VMULL scalar */
                    if (rd & 1) {
                        return 1;
                    }
5652
                    tmp2 = neon_get_scalar(size, rm);
5653 5654
                    /* We need a copy of tmp2 because gen_neon_mull
                     * deletes it during pass 0.  */
5655
                    tmp4 = tcg_temp_new_i32();
5656
                    tcg_gen_mov_i32(tmp4, tmp2);
5657
                    tmp3 = neon_load_reg(rn, 1);
P
pbrook 已提交
5658

P
pbrook 已提交
5659
                    for (pass = 0; pass < 2; pass++) {
P
pbrook 已提交
5660 5661
                        if (pass == 0) {
                            tmp = neon_load_reg(rn, 0);
P
pbrook 已提交
5662
                        } else {
5663
                            tmp = tmp3;
5664
                            tmp2 = tmp4;
P
pbrook 已提交
5665
                        }
P
pbrook 已提交
5666 5667 5668
                        gen_neon_mull(cpu_V0, tmp, tmp2, size, u);
                        if (op != 11) {
                            neon_load_reg64(cpu_V1, rd + pass);
P
pbrook 已提交
5669 5670
                        }
                        switch (op) {
5671 5672 5673 5674
                        case 6:
                            gen_neon_negl(cpu_V0, size);
                            /* Fall through */
                        case 2:
P
pbrook 已提交
5675
                            gen_neon_addl(size);
P
pbrook 已提交
5676 5677
                            break;
                        case 3: case 7:
P
pbrook 已提交
5678
                            gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
5679 5680 5681
                            if (op == 7) {
                                gen_neon_negl(cpu_V0, size);
                            }
P
pbrook 已提交
5682
                            gen_neon_addl_saturate(cpu_V0, cpu_V1, size);
P
pbrook 已提交
5683 5684 5685 5686 5687
                            break;
                        case 10:
                            /* no-op */
                            break;
                        case 11:
P
pbrook 已提交
5688
                            gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
P
pbrook 已提交
5689 5690 5691 5692
                            break;
                        default:
                            abort();
                        }
P
pbrook 已提交
5693
                        neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
5694
                    }
5695 5696


P
pbrook 已提交
5697 5698 5699 5700 5701 5702 5703 5704 5705
                    break;
                default: /* 14 and 15 are RESERVED */
                    return 1;
                }
            }
        } else { /* size == 3 */
            if (!u) {
                /* Extract.  */
                imm = (insn >> 8) & 0xf;
P
pbrook 已提交
5706 5707 5708 5709

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

5710 5711 5712 5713
                if (q && ((rd | rn | rm) & 1)) {
                    return 1;
                }

P
pbrook 已提交
5714 5715 5716 5717
                if (imm == 0) {
                    neon_load_reg64(cpu_V0, rn);
                    if (q) {
                        neon_load_reg64(cpu_V1, rn + 1);
P
pbrook 已提交
5718
                    }
P
pbrook 已提交
5719 5720 5721 5722
                } else if (imm == 8) {
                    neon_load_reg64(cpu_V0, rn + 1);
                    if (q) {
                        neon_load_reg64(cpu_V1, rm);
P
pbrook 已提交
5723
                    }
P
pbrook 已提交
5724
                } else if (q) {
P
pbrook 已提交
5725
                    tmp64 = tcg_temp_new_i64();
P
pbrook 已提交
5726 5727
                    if (imm < 8) {
                        neon_load_reg64(cpu_V0, rn);
P
pbrook 已提交
5728
                        neon_load_reg64(tmp64, rn + 1);
P
pbrook 已提交
5729 5730
                    } else {
                        neon_load_reg64(cpu_V0, rn + 1);
P
pbrook 已提交
5731
                        neon_load_reg64(tmp64, rm);
P
pbrook 已提交
5732 5733
                    }
                    tcg_gen_shri_i64(cpu_V0, cpu_V0, (imm & 7) * 8);
P
pbrook 已提交
5734
                    tcg_gen_shli_i64(cpu_V1, tmp64, 64 - ((imm & 7) * 8));
P
pbrook 已提交
5735 5736 5737
                    tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1);
                    if (imm < 8) {
                        neon_load_reg64(cpu_V1, rm);
P
pbrook 已提交
5738
                    } else {
P
pbrook 已提交
5739 5740
                        neon_load_reg64(cpu_V1, rm + 1);
                        imm -= 8;
P
pbrook 已提交
5741
                    }
P
pbrook 已提交
5742
                    tcg_gen_shli_i64(cpu_V1, cpu_V1, 64 - (imm * 8));
P
pbrook 已提交
5743 5744
                    tcg_gen_shri_i64(tmp64, tmp64, imm * 8);
                    tcg_gen_or_i64(cpu_V1, cpu_V1, tmp64);
5745
                    tcg_temp_free_i64(tmp64);
P
pbrook 已提交
5746
                } else {
P
pbrook 已提交
5747
                    /* BUGFIX */
P
pbrook 已提交
5748
                    neon_load_reg64(cpu_V0, rn);
P
pbrook 已提交
5749
                    tcg_gen_shri_i64(cpu_V0, cpu_V0, imm * 8);
P
pbrook 已提交
5750
                    neon_load_reg64(cpu_V1, rm);
P
pbrook 已提交
5751
                    tcg_gen_shli_i64(cpu_V1, cpu_V1, 64 - (imm * 8));
P
pbrook 已提交
5752 5753 5754 5755 5756
                    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 已提交
5757 5758 5759 5760 5761
                }
            } else if ((insn & (1 << 11)) == 0) {
                /* Two register misc.  */
                op = ((insn >> 12) & 0x30) | ((insn >> 7) & 0xf);
                size = (insn >> 18) & 3;
5762 5763 5764 5765
                /* UNDEF for unknown op values and bad op-size combinations */
                if ((neon_2rm_sizes[op] & (1 << size)) == 0) {
                    return 1;
                }
5766 5767 5768 5769
                if ((op != NEON_2RM_VMOVN && op != NEON_2RM_VQMOVN) &&
                    q && ((rm | rd) & 1)) {
                    return 1;
                }
P
pbrook 已提交
5770
                switch (op) {
5771
                case NEON_2RM_VREV64:
P
pbrook 已提交
5772
                    for (pass = 0; pass < (q ? 2 : 1); pass++) {
5773 5774
                        tmp = neon_load_reg(rm, pass * 2);
                        tmp2 = neon_load_reg(rm, pass * 2 + 1);
P
pbrook 已提交
5775
                        switch (size) {
5776 5777
                        case 0: tcg_gen_bswap32_i32(tmp, tmp); break;
                        case 1: gen_swap_half(tmp); break;
P
pbrook 已提交
5778 5779 5780
                        case 2: /* no-op */ break;
                        default: abort();
                        }
5781
                        neon_store_reg(rd, pass * 2 + 1, tmp);
P
pbrook 已提交
5782
                        if (size == 2) {
5783
                            neon_store_reg(rd, pass * 2, tmp2);
P
pbrook 已提交
5784 5785
                        } else {
                            switch (size) {
5786 5787
                            case 0: tcg_gen_bswap32_i32(tmp2, tmp2); break;
                            case 1: gen_swap_half(tmp2); break;
P
pbrook 已提交
5788 5789
                            default: abort();
                            }
5790
                            neon_store_reg(rd, pass * 2, tmp2);
P
pbrook 已提交
5791 5792 5793
                        }
                    }
                    break;
5794 5795
                case NEON_2RM_VPADDL: case NEON_2RM_VPADDL_U:
                case NEON_2RM_VPADAL: case NEON_2RM_VPADAL_U:
P
pbrook 已提交
5796 5797 5798 5799 5800 5801 5802 5803 5804 5805 5806
                    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();
                        }
5807
                        if (op >= NEON_2RM_VPADAL) {
P
pbrook 已提交
5808
                            /* Accumulate.  */
P
pbrook 已提交
5809 5810
                            neon_load_reg64(cpu_V1, rd + pass);
                            gen_neon_addl(size);
P
pbrook 已提交
5811
                        }
P
pbrook 已提交
5812
                        neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
5813 5814
                    }
                    break;
5815
                case NEON_2RM_VTRN:
P
pbrook 已提交
5816
                    if (size == 2) {
5817
                        int n;
P
pbrook 已提交
5818
                        for (n = 0; n < (q ? 4 : 2); n += 2) {
5819 5820 5821 5822
                            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 已提交
5823 5824 5825 5826 5827
                        }
                    } else {
                        goto elementwise;
                    }
                    break;
5828
                case NEON_2RM_VUZP:
5829
                    if (gen_neon_unzip(rd, rm, size, q)) {
P
pbrook 已提交
5830 5831 5832
                        return 1;
                    }
                    break;
5833
                case NEON_2RM_VZIP:
5834
                    if (gen_neon_zip(rd, rm, size, q)) {
P
pbrook 已提交
5835 5836 5837
                        return 1;
                    }
                    break;
5838 5839
                case NEON_2RM_VMOVN: case NEON_2RM_VQMOVN:
                    /* also VQMOVUN; op field and mnemonics don't line up */
5840 5841 5842
                    if (rm & 1) {
                        return 1;
                    }
5843
                    TCGV_UNUSED_I32(tmp2);
P
pbrook 已提交
5844
                    for (pass = 0; pass < 2; pass++) {
P
pbrook 已提交
5845
                        neon_load_reg64(cpu_V0, rm + pass);
5846
                        tmp = tcg_temp_new_i32();
5847 5848
                        gen_neon_narrow_op(op == NEON_2RM_VMOVN, q, size,
                                           tmp, cpu_V0);
P
pbrook 已提交
5849 5850 5851 5852 5853
                        if (pass == 0) {
                            tmp2 = tmp;
                        } else {
                            neon_store_reg(rd, 0, tmp2);
                            neon_store_reg(rd, 1, tmp);
P
pbrook 已提交
5854 5855 5856
                        }
                    }
                    break;
5857
                case NEON_2RM_VSHLL:
5858
                    if (q || (rd & 1)) {
P
pbrook 已提交
5859
                        return 1;
5860
                    }
P
pbrook 已提交
5861 5862
                    tmp = neon_load_reg(rm, 0);
                    tmp2 = neon_load_reg(rm, 1);
P
pbrook 已提交
5863
                    for (pass = 0; pass < 2; pass++) {
P
pbrook 已提交
5864 5865 5866
                        if (pass == 1)
                            tmp = tmp2;
                        gen_neon_widen(cpu_V0, tmp, size, 1);
5867
                        tcg_gen_shli_i64(cpu_V0, cpu_V0, 8 << size);
P
pbrook 已提交
5868
                        neon_store_reg64(cpu_V0, rd + pass);
P
pbrook 已提交
5869 5870
                    }
                    break;
5871
                case NEON_2RM_VCVT_F16_F32:
5872 5873 5874 5875
                    if (!arm_feature(env, ARM_FEATURE_VFP_FP16) ||
                        q || (rm & 1)) {
                        return 1;
                    }
5876 5877
                    tmp = tcg_temp_new_i32();
                    tmp2 = tcg_temp_new_i32();
P
Paul Brook 已提交
5878
                    tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 0));
5879
                    gen_helper_neon_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
P
Paul Brook 已提交
5880
                    tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 1));
5881
                    gen_helper_neon_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env);
P
Paul Brook 已提交
5882 5883 5884
                    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));
5885
                    gen_helper_neon_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
P
Paul Brook 已提交
5886 5887
                    tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 3));
                    neon_store_reg(rd, 0, tmp2);
5888
                    tmp2 = tcg_temp_new_i32();
5889
                    gen_helper_neon_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env);
P
Paul Brook 已提交
5890 5891 5892
                    tcg_gen_shli_i32(tmp2, tmp2, 16);
                    tcg_gen_or_i32(tmp2, tmp2, tmp);
                    neon_store_reg(rd, 1, tmp2);
5893
                    tcg_temp_free_i32(tmp);
P
Paul Brook 已提交
5894
                    break;
5895
                case NEON_2RM_VCVT_F32_F16:
5896 5897 5898 5899
                    if (!arm_feature(env, ARM_FEATURE_VFP_FP16) ||
                        q || (rd & 1)) {
                        return 1;
                    }
5900
                    tmp3 = tcg_temp_new_i32();
P
Paul Brook 已提交
5901 5902 5903
                    tmp = neon_load_reg(rm, 0);
                    tmp2 = neon_load_reg(rm, 1);
                    tcg_gen_ext16u_i32(tmp3, tmp);
5904
                    gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
P
Paul Brook 已提交
5905 5906
                    tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 0));
                    tcg_gen_shri_i32(tmp3, tmp, 16);
5907
                    gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
P
Paul Brook 已提交
5908
                    tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 1));
5909
                    tcg_temp_free_i32(tmp);
P
Paul Brook 已提交
5910
                    tcg_gen_ext16u_i32(tmp3, tmp2);
5911
                    gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
P
Paul Brook 已提交
5912 5913
                    tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 2));
                    tcg_gen_shri_i32(tmp3, tmp2, 16);
5914
                    gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
P
Paul Brook 已提交
5915
                    tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 3));
5916 5917
                    tcg_temp_free_i32(tmp2);
                    tcg_temp_free_i32(tmp3);
P
Paul Brook 已提交
5918
                    break;
P
pbrook 已提交
5919 5920 5921
                default:
                elementwise:
                    for (pass = 0; pass < (q ? 4 : 2); pass++) {
5922
                        if (neon_2rm_is_float_op(op)) {
P
pbrook 已提交
5923 5924
                            tcg_gen_ld_f32(cpu_F0s, cpu_env,
                                           neon_reg_offset(rm, pass));
5925
                            TCGV_UNUSED_I32(tmp);
P
pbrook 已提交
5926
                        } else {
5927
                            tmp = neon_load_reg(rm, pass);
P
pbrook 已提交
5928 5929
                        }
                        switch (op) {
5930
                        case NEON_2RM_VREV32:
P
pbrook 已提交
5931
                            switch (size) {
5932 5933
                            case 0: tcg_gen_bswap32_i32(tmp, tmp); break;
                            case 1: gen_swap_half(tmp); break;
5934
                            default: abort();
P
pbrook 已提交
5935 5936
                            }
                            break;
5937
                        case NEON_2RM_VREV16:
5938
                            gen_rev16(tmp);
P
pbrook 已提交
5939
                            break;
5940
                        case NEON_2RM_VCLS:
P
pbrook 已提交
5941
                            switch (size) {
5942 5943 5944
                            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;
5945
                            default: abort();
P
pbrook 已提交
5946 5947
                            }
                            break;
5948
                        case NEON_2RM_VCLZ:
P
pbrook 已提交
5949
                            switch (size) {
5950 5951 5952
                            case 0: gen_helper_neon_clz_u8(tmp, tmp); break;
                            case 1: gen_helper_neon_clz_u16(tmp, tmp); break;
                            case 2: gen_helper_clz(tmp, tmp); break;
5953
                            default: abort();
P
pbrook 已提交
5954 5955
                            }
                            break;
5956
                        case NEON_2RM_VCNT:
5957
                            gen_helper_neon_cnt_u8(tmp, tmp);
P
pbrook 已提交
5958
                            break;
5959
                        case NEON_2RM_VMVN:
5960
                            tcg_gen_not_i32(tmp, tmp);
P
pbrook 已提交
5961
                            break;
5962
                        case NEON_2RM_VQABS:
P
pbrook 已提交
5963
                            switch (size) {
5964 5965 5966 5967 5968 5969 5970 5971 5972
                            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;
5973
                            default: abort();
P
pbrook 已提交
5974 5975
                            }
                            break;
5976
                        case NEON_2RM_VQNEG:
P
pbrook 已提交
5977
                            switch (size) {
5978 5979 5980 5981 5982 5983 5984 5985 5986
                            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;
5987
                            default: abort();
P
pbrook 已提交
5988 5989
                            }
                            break;
5990
                        case NEON_2RM_VCGT0: case NEON_2RM_VCLE0:
5991
                            tmp2 = tcg_const_i32(0);
P
pbrook 已提交
5992
                            switch(size) {
5993 5994 5995
                            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;
5996
                            default: abort();
P
pbrook 已提交
5997
                            }
5998
                            tcg_temp_free_i32(tmp2);
5999
                            if (op == NEON_2RM_VCLE0) {
6000
                                tcg_gen_not_i32(tmp, tmp);
6001
                            }
P
pbrook 已提交
6002
                            break;
6003
                        case NEON_2RM_VCGE0: case NEON_2RM_VCLT0:
6004
                            tmp2 = tcg_const_i32(0);
P
pbrook 已提交
6005
                            switch(size) {
6006 6007 6008
                            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;
6009
                            default: abort();
P
pbrook 已提交
6010
                            }
6011
                            tcg_temp_free_i32(tmp2);
6012
                            if (op == NEON_2RM_VCLT0) {
6013
                                tcg_gen_not_i32(tmp, tmp);
6014
                            }
P
pbrook 已提交
6015
                            break;
6016
                        case NEON_2RM_VCEQ0:
6017
                            tmp2 = tcg_const_i32(0);
P
pbrook 已提交
6018
                            switch(size) {
6019 6020 6021
                            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;
6022
                            default: abort();
P
pbrook 已提交
6023
                            }
6024
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
6025
                            break;
6026
                        case NEON_2RM_VABS:
P
pbrook 已提交
6027
                            switch(size) {
6028 6029 6030
                            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;
6031
                            default: abort();
P
pbrook 已提交
6032 6033
                            }
                            break;
6034
                        case NEON_2RM_VNEG:
6035 6036
                            tmp2 = tcg_const_i32(0);
                            gen_neon_rsb(size, tmp, tmp2);
6037
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
6038
                            break;
6039
                        case NEON_2RM_VCGT0_F:
6040 6041
                        {
                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
6042
                            tmp2 = tcg_const_i32(0);
6043
                            gen_helper_neon_cgt_f32(tmp, tmp, tmp2, fpstatus);
6044
                            tcg_temp_free_i32(tmp2);
6045
                            tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
6046
                            break;
6047
                        }
6048
                        case NEON_2RM_VCGE0_F:
6049 6050
                        {
                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
6051
                            tmp2 = tcg_const_i32(0);
6052
                            gen_helper_neon_cge_f32(tmp, tmp, tmp2, fpstatus);
6053
                            tcg_temp_free_i32(tmp2);
6054
                            tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
6055
                            break;
6056
                        }
6057
                        case NEON_2RM_VCEQ0_F:
6058 6059
                        {
                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
6060
                            tmp2 = tcg_const_i32(0);
6061
                            gen_helper_neon_ceq_f32(tmp, tmp, tmp2, fpstatus);
6062
                            tcg_temp_free_i32(tmp2);
6063
                            tcg_temp_free_ptr(fpstatus);
P
pbrook 已提交
6064
                            break;
6065
                        }
6066
                        case NEON_2RM_VCLE0_F:
6067 6068
                        {
                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
6069
                            tmp2 = tcg_const_i32(0);
6070
                            gen_helper_neon_cge_f32(tmp, tmp2, tmp, fpstatus);
6071
                            tcg_temp_free_i32(tmp2);
6072
                            tcg_temp_free_ptr(fpstatus);
6073
                            break;
6074
                        }
6075
                        case NEON_2RM_VCLT0_F:
6076 6077
                        {
                            TCGv_ptr fpstatus = get_fpstatus_ptr(1);
6078
                            tmp2 = tcg_const_i32(0);
6079
                            gen_helper_neon_cgt_f32(tmp, tmp2, tmp, fpstatus);
6080
                            tcg_temp_free_i32(tmp2);
6081
                            tcg_temp_free_ptr(fpstatus);
6082
                            break;
6083
                        }
6084
                        case NEON_2RM_VABS_F:
P
pbrook 已提交
6085
                            gen_vfp_abs(0);
P
pbrook 已提交
6086
                            break;
6087
                        case NEON_2RM_VNEG_F:
P
pbrook 已提交
6088
                            gen_vfp_neg(0);
P
pbrook 已提交
6089
                            break;
6090
                        case NEON_2RM_VSWP:
6091 6092
                            tmp2 = neon_load_reg(rd, pass);
                            neon_store_reg(rm, pass, tmp2);
P
pbrook 已提交
6093
                            break;
6094
                        case NEON_2RM_VTRN:
6095
                            tmp2 = neon_load_reg(rd, pass);
P
pbrook 已提交
6096
                            switch (size) {
6097 6098
                            case 0: gen_neon_trn_u8(tmp, tmp2); break;
                            case 1: gen_neon_trn_u16(tmp, tmp2); break;
6099
                            default: abort();
P
pbrook 已提交
6100
                            }
6101
                            neon_store_reg(rm, pass, tmp2);
P
pbrook 已提交
6102
                            break;
6103
                        case NEON_2RM_VRECPE:
6104
                            gen_helper_recpe_u32(tmp, tmp, cpu_env);
P
pbrook 已提交
6105
                            break;
6106
                        case NEON_2RM_VRSQRTE:
6107
                            gen_helper_rsqrte_u32(tmp, tmp, cpu_env);
P
pbrook 已提交
6108
                            break;
6109
                        case NEON_2RM_VRECPE_F:
P
pbrook 已提交
6110
                            gen_helper_recpe_f32(cpu_F0s, cpu_F0s, cpu_env);
P
pbrook 已提交
6111
                            break;
6112
                        case NEON_2RM_VRSQRTE_F:
P
pbrook 已提交
6113
                            gen_helper_rsqrte_f32(cpu_F0s, cpu_F0s, cpu_env);
P
pbrook 已提交
6114
                            break;
6115
                        case NEON_2RM_VCVT_FS: /* VCVT.F32.S32 */
6116
                            gen_vfp_sito(0, 1);
P
pbrook 已提交
6117
                            break;
6118
                        case NEON_2RM_VCVT_FU: /* VCVT.F32.U32 */
6119
                            gen_vfp_uito(0, 1);
P
pbrook 已提交
6120
                            break;
6121
                        case NEON_2RM_VCVT_SF: /* VCVT.S32.F32 */
6122
                            gen_vfp_tosiz(0, 1);
P
pbrook 已提交
6123
                            break;
6124
                        case NEON_2RM_VCVT_UF: /* VCVT.U32.F32 */
6125
                            gen_vfp_touiz(0, 1);
P
pbrook 已提交
6126 6127
                            break;
                        default:
6128 6129 6130 6131
                            /* Reserved op values were caught by the
                             * neon_2rm_sizes[] check earlier.
                             */
                            abort();
P
pbrook 已提交
6132
                        }
6133
                        if (neon_2rm_is_float_op(op)) {
P
pbrook 已提交
6134 6135
                            tcg_gen_st_f32(cpu_F0s, cpu_env,
                                           neon_reg_offset(rd, pass));
P
pbrook 已提交
6136
                        } else {
6137
                            neon_store_reg(rd, pass, tmp);
P
pbrook 已提交
6138 6139 6140 6141 6142 6143
                        }
                    }
                    break;
                }
            } else if ((insn & (1 << 10)) == 0) {
                /* VTBL, VTBX.  */
6144 6145 6146 6147 6148 6149 6150 6151
                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 已提交
6152
                if (insn & (1 << 6)) {
P
pbrook 已提交
6153
                    tmp = neon_load_reg(rd, 0);
P
pbrook 已提交
6154
                } else {
6155
                    tmp = tcg_temp_new_i32();
P
pbrook 已提交
6156
                    tcg_gen_movi_i32(tmp, 0);
P
pbrook 已提交
6157
                }
P
pbrook 已提交
6158
                tmp2 = neon_load_reg(rm, 0);
6159 6160
                tmp4 = tcg_const_i32(rn);
                tmp5 = tcg_const_i32(n);
6161
                gen_helper_neon_tbl(tmp2, cpu_env, tmp2, tmp, tmp4, tmp5);
6162
                tcg_temp_free_i32(tmp);
P
pbrook 已提交
6163
                if (insn & (1 << 6)) {
P
pbrook 已提交
6164
                    tmp = neon_load_reg(rd, 1);
P
pbrook 已提交
6165
                } else {
6166
                    tmp = tcg_temp_new_i32();
P
pbrook 已提交
6167
                    tcg_gen_movi_i32(tmp, 0);
P
pbrook 已提交
6168
                }
P
pbrook 已提交
6169
                tmp3 = neon_load_reg(rm, 1);
6170
                gen_helper_neon_tbl(tmp3, cpu_env, tmp3, tmp, tmp4, tmp5);
6171 6172
                tcg_temp_free_i32(tmp5);
                tcg_temp_free_i32(tmp4);
P
pbrook 已提交
6173
                neon_store_reg(rd, 0, tmp2);
P
pbrook 已提交
6174
                neon_store_reg(rd, 1, tmp3);
6175
                tcg_temp_free_i32(tmp);
P
pbrook 已提交
6176 6177
            } else if ((insn & 0x380) == 0) {
                /* VDUP */
6178 6179 6180
                if ((insn & (7 << 16)) == 0 || (q && (rd & 1))) {
                    return 1;
                }
P
pbrook 已提交
6181
                if (insn & (1 << 19)) {
6182
                    tmp = neon_load_reg(rm, 1);
P
pbrook 已提交
6183
                } else {
6184
                    tmp = neon_load_reg(rm, 0);
P
pbrook 已提交
6185 6186
                }
                if (insn & (1 << 16)) {
6187
                    gen_neon_dup_u8(tmp, ((insn >> 17) & 3) * 8);
P
pbrook 已提交
6188 6189
                } else if (insn & (1 << 17)) {
                    if ((insn >> 18) & 1)
6190
                        gen_neon_dup_high16(tmp);
P
pbrook 已提交
6191
                    else
6192
                        gen_neon_dup_low16(tmp);
P
pbrook 已提交
6193 6194
                }
                for (pass = 0; pass < (q ? 4 : 2); pass++) {
6195
                    tmp2 = tcg_temp_new_i32();
6196 6197
                    tcg_gen_mov_i32(tmp2, tmp);
                    neon_store_reg(rd, pass, tmp2);
P
pbrook 已提交
6198
                }
6199
                tcg_temp_free_i32(tmp);
P
pbrook 已提交
6200 6201 6202 6203 6204 6205 6206 6207
            } else {
                return 1;
            }
        }
    }
    return 0;
}

6208
static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
P
pbrook 已提交
6209
{
6210 6211 6212
    int cpnum, is64, crn, crm, opc1, opc2, isread, rt, rt2;
    const ARMCPRegInfo *ri;
    ARMCPU *cpu = arm_env_get_cpu(env);
P
pbrook 已提交
6213 6214 6215 6216 6217 6218

    cpnum = (insn >> 8) & 0xf;
    if (arm_feature(env, ARM_FEATURE_XSCALE)
	    && ((env->cp15.c15_cpar ^ 0x3fff) & (1 << cpnum)))
	return 1;

6219
    /* First check for coprocessor space used for actual instructions */
P
pbrook 已提交
6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231
    switch (cpnum) {
      case 0:
      case 1:
	if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
	    return disas_iwmmxt_insn(env, s, insn);
	} else if (arm_feature(env, ARM_FEATURE_XSCALE)) {
	    return disas_dsp_insn(env, s, insn);
	}
	return 1;
    case 10:
    case 11:
	return disas_vfp_insn (env, s, insn);
6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275
    default:
        break;
    }

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

    ri = get_arm_cp_reginfo(cpu,
                            ENCODE_CP_REG(cpnum, is64, crn, crm, opc1, opc2));
    if (ri) {
        /* Check access permissions */
        if (!cp_access_ok(env, ri, isread)) {
            return 1;
        }

        /* 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;
            }
            gen_set_pc_im(s->pc);
            s->is_jmp = DISAS_WFI;
P
Paul Brook 已提交
6276
            return 0;
6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302
        default:
            break;
        }

        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;
                    gen_set_pc_im(s->pc);
                    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();
                tcg_gen_trunc_i64_i32(tmp, tmp64);
                store_reg(s, rt, tmp);
                tcg_gen_shri_i64(tmp64, tmp64, 32);
6303
                tmp = tcg_temp_new_i32();
6304
                tcg_gen_trunc_i64_i32(tmp, tmp64);
6305
                tcg_temp_free_i64(tmp64);
6306 6307
                store_reg(s, rt2, tmp);
            } else {
6308
                TCGv_i32 tmp;
6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338
                if (ri->type & ARM_CP_CONST) {
                    tmp = tcg_const_i32(ri->resetvalue);
                } else if (ri->readfn) {
                    TCGv_ptr tmpptr;
                    gen_set_pc_im(s->pc);
                    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) {
6339
                TCGv_i32 tmplo, tmphi;
6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356
                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_set_pc_im(s->pc);
                    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) {
6357
                    TCGv_i32 tmp;
6358 6359 6360 6361 6362 6363 6364 6365
                    TCGv_ptr tmpptr;
                    gen_set_pc_im(s->pc);
                    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 {
6366
                    TCGv_i32 tmp = load_reg(s, rt);
6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380
                    store_cpu_offset(tmp, ri->fieldoffset);
                }
            }
            /* 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).
             */
            if (!(ri->type & ARM_CP_SUPPRESS_TB_END)) {
                gen_lookup_tb(s);
            }
        }
        return 0;
    }

6381
    return 1;
P
pbrook 已提交
6382 6383
}

P
pbrook 已提交
6384 6385

/* Store a 64-bit value to a register pair.  Clobbers val.  */
P
pbrook 已提交
6386
static void gen_storeq_reg(DisasContext *s, int rlow, int rhigh, TCGv_i64 val)
P
pbrook 已提交
6387
{
6388
    TCGv_i32 tmp;
6389
    tmp = tcg_temp_new_i32();
P
pbrook 已提交
6390 6391
    tcg_gen_trunc_i64_i32(tmp, val);
    store_reg(s, rlow, tmp);
6392
    tmp = tcg_temp_new_i32();
P
pbrook 已提交
6393 6394 6395 6396 6397 6398
    tcg_gen_shri_i64(val, val, 32);
    tcg_gen_trunc_i64_i32(tmp, val);
    store_reg(s, rhigh, tmp);
}

/* load a 32-bit value from a register and perform a 64-bit accumulate.  */
P
pbrook 已提交
6399
static void gen_addq_lo(DisasContext *s, TCGv_i64 val, int rlow)
P
pbrook 已提交
6400
{
P
pbrook 已提交
6401
    TCGv_i64 tmp;
6402
    TCGv_i32 tmp2;
P
pbrook 已提交
6403

P
pbrook 已提交
6404
    /* Load value and extend to 64 bits.  */
P
pbrook 已提交
6405
    tmp = tcg_temp_new_i64();
P
pbrook 已提交
6406 6407
    tmp2 = load_reg(s, rlow);
    tcg_gen_extu_i32_i64(tmp, tmp2);
6408
    tcg_temp_free_i32(tmp2);
P
pbrook 已提交
6409
    tcg_gen_add_i64(val, val, tmp);
6410
    tcg_temp_free_i64(tmp);
P
pbrook 已提交
6411 6412 6413
}

/* load and add a 64-bit value from a register pair.  */
P
pbrook 已提交
6414
static void gen_addq(DisasContext *s, TCGv_i64 val, int rlow, int rhigh)
P
pbrook 已提交
6415
{
P
pbrook 已提交
6416
    TCGv_i64 tmp;
6417 6418
    TCGv_i32 tmpl;
    TCGv_i32 tmph;
P
pbrook 已提交
6419 6420

    /* Load 64-bit value rd:rn.  */
P
pbrook 已提交
6421 6422
    tmpl = load_reg(s, rlow);
    tmph = load_reg(s, rhigh);
P
pbrook 已提交
6423
    tmp = tcg_temp_new_i64();
P
pbrook 已提交
6424
    tcg_gen_concat_i32_i64(tmp, tmpl, tmph);
6425 6426
    tcg_temp_free_i32(tmpl);
    tcg_temp_free_i32(tmph);
P
pbrook 已提交
6427
    tcg_gen_add_i64(val, val, tmp);
6428
    tcg_temp_free_i64(tmp);
P
pbrook 已提交
6429 6430
}

6431
/* Set N and Z flags from hi|lo.  */
6432
static void gen_logicq_cc(TCGv_i32 lo, TCGv_i32 hi)
P
pbrook 已提交
6433
{
6434 6435
    tcg_gen_mov_i32(cpu_NF, hi);
    tcg_gen_or_i32(cpu_ZF, lo, hi);
P
pbrook 已提交
6436 6437
}

P
Paul Brook 已提交
6438 6439
/* Load/Store exclusive instructions are implemented by remembering
   the value/address loaded, and seeing if these are the same
6440
   when the store is performed. This should be sufficient to implement
P
Paul Brook 已提交
6441 6442 6443 6444 6445 6446 6447
   the architecturally mandated semantics, and avoids having to monitor
   regular stores.

   In system emulation mode only one CPU will be running at once, so
   this sequence is effectively atomic.  In user emulation mode we
   throw an exception and handle the atomic operation elsewhere.  */
static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
6448
                               TCGv_i32 addr, int size)
P
Paul Brook 已提交
6449
{
6450
    TCGv_i32 tmp = tcg_temp_new_i32();
P
Paul Brook 已提交
6451 6452 6453

    switch (size) {
    case 0:
6454
        tcg_gen_qemu_ld8u(tmp, addr, IS_USER(s));
P
Paul Brook 已提交
6455 6456
        break;
    case 1:
6457
        tcg_gen_qemu_ld16u(tmp, addr, IS_USER(s));
P
Paul Brook 已提交
6458 6459 6460
        break;
    case 2:
    case 3:
6461
        tcg_gen_qemu_ld32u(tmp, addr, IS_USER(s));
P
Paul Brook 已提交
6462 6463 6464 6465 6466 6467 6468
        break;
    default:
        abort();
    }
    tcg_gen_mov_i32(cpu_exclusive_val, tmp);
    store_reg(s, rt, tmp);
    if (size == 3) {
6469
        TCGv_i32 tmp2 = tcg_temp_new_i32();
P
Peter Maydell 已提交
6470
        tcg_gen_addi_i32(tmp2, addr, 4);
6471 6472
        tmp = tcg_temp_new_i32();
        tcg_gen_qemu_ld32u(tmp, tmp2, IS_USER(s));
6473
        tcg_temp_free_i32(tmp2);
P
Paul Brook 已提交
6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486
        tcg_gen_mov_i32(cpu_exclusive_high, tmp);
        store_reg(s, rt2, tmp);
    }
    tcg_gen_mov_i32(cpu_exclusive_addr, addr);
}

static void gen_clrex(DisasContext *s)
{
    tcg_gen_movi_i32(cpu_exclusive_addr, -1);
}

#ifdef CONFIG_USER_ONLY
static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
6487
                                TCGv_i32 addr, int size)
P
Paul Brook 已提交
6488 6489 6490 6491
{
    tcg_gen_mov_i32(cpu_exclusive_test, addr);
    tcg_gen_movi_i32(cpu_exclusive_info,
                     size | (rd << 4) | (rt << 8) | (rt2 << 12));
6492
    gen_exception_insn(s, 4, EXCP_STREX);
P
Paul Brook 已提交
6493 6494 6495
}
#else
static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
6496
                                TCGv_i32 addr, int size)
P
Paul Brook 已提交
6497
{
6498
    TCGv_i32 tmp;
P
Paul Brook 已提交
6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510
    int done_label;
    int fail_label;

    /* 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();
    tcg_gen_brcond_i32(TCG_COND_NE, addr, cpu_exclusive_addr, fail_label);
6511
    tmp = tcg_temp_new_i32();
P
Paul Brook 已提交
6512 6513
    switch (size) {
    case 0:
6514
        tcg_gen_qemu_ld8u(tmp, addr, IS_USER(s));
P
Paul Brook 已提交
6515 6516
        break;
    case 1:
6517
        tcg_gen_qemu_ld16u(tmp, addr, IS_USER(s));
P
Paul Brook 已提交
6518 6519 6520
        break;
    case 2:
    case 3:
6521
        tcg_gen_qemu_ld32u(tmp, addr, IS_USER(s));
P
Paul Brook 已提交
6522 6523 6524 6525 6526
        break;
    default:
        abort();
    }
    tcg_gen_brcond_i32(TCG_COND_NE, tmp, cpu_exclusive_val, fail_label);
6527
    tcg_temp_free_i32(tmp);
P
Paul Brook 已提交
6528
    if (size == 3) {
6529
        TCGv_i32 tmp2 = tcg_temp_new_i32();
P
Paul Brook 已提交
6530
        tcg_gen_addi_i32(tmp2, addr, 4);
6531 6532
        tmp = tcg_temp_new_i32();
        tcg_gen_qemu_ld32u(tmp, tmp2, IS_USER(s));
6533
        tcg_temp_free_i32(tmp2);
P
Paul Brook 已提交
6534
        tcg_gen_brcond_i32(TCG_COND_NE, tmp, cpu_exclusive_high, fail_label);
6535
        tcg_temp_free_i32(tmp);
P
Paul Brook 已提交
6536 6537 6538 6539
    }
    tmp = load_reg(s, rt);
    switch (size) {
    case 0:
6540
        tcg_gen_qemu_st8(tmp, addr, IS_USER(s));
P
Paul Brook 已提交
6541 6542
        break;
    case 1:
6543
        tcg_gen_qemu_st16(tmp, addr, IS_USER(s));
P
Paul Brook 已提交
6544 6545 6546
        break;
    case 2:
    case 3:
6547
        tcg_gen_qemu_st32(tmp, addr, IS_USER(s));
P
Paul Brook 已提交
6548 6549 6550 6551
        break;
    default:
        abort();
    }
6552
    tcg_temp_free_i32(tmp);
P
Paul Brook 已提交
6553 6554 6555
    if (size == 3) {
        tcg_gen_addi_i32(addr, addr, 4);
        tmp = load_reg(s, rt2);
6556 6557
        tcg_gen_qemu_st32(tmp, addr, IS_USER(s));
        tcg_temp_free_i32(tmp);
P
Paul Brook 已提交
6558 6559 6560 6561 6562 6563 6564 6565 6566 6567
    }
    tcg_gen_movi_i32(cpu_R[rd], 0);
    tcg_gen_br(done_label);
    gen_set_label(fail_label);
    tcg_gen_movi_i32(cpu_R[rd], 1);
    gen_set_label(done_label);
    tcg_gen_movi_i32(cpu_exclusive_addr, -1);
}
#endif

6568 6569 6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 6580 6581 6582 6583 6584 6585 6586 6587 6588 6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602
/* 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;
    TCGv_i32 addr = tcg_temp_new_i32();
    TCGv_i32 tmp = tcg_const_i32(mode);
    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);
6603 6604
    tcg_gen_qemu_st32(tmp, addr, 0);
    tcg_temp_free_i32(tmp);
6605 6606
    tmp = load_cpu_field(spsr);
    tcg_gen_addi_i32(addr, addr, 4);
6607 6608
    tcg_gen_qemu_st32(tmp, addr, 0);
    tcg_temp_free_i32(tmp);
6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 6621 6622 6623 6624 6625 6626 6627 6628 6629 6630 6631 6632 6633
    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);
}

6634
static void disas_arm_insn(CPUARMState * env, DisasContext *s)
P
pbrook 已提交
6635 6636
{
    unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;
6637 6638 6639 6640
    TCGv_i32 tmp;
    TCGv_i32 tmp2;
    TCGv_i32 tmp3;
    TCGv_i32 addr;
P
pbrook 已提交
6641
    TCGv_i64 tmp64;
P
pbrook 已提交
6642

6643
    insn = arm_ldl_code(env, s->pc, s->bswap_code);
P
pbrook 已提交
6644 6645 6646 6647 6648 6649 6650
    s->pc += 4;

    /* M variants do not implement ARM mode.  */
    if (IS_M(env))
        goto illegal_op;
    cond = insn >> 28;
    if (cond == 0xf){
6651 6652 6653 6654 6655 6656
        /* 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 已提交
6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673 6674 6675
        /* Unconditional instructions.  */
        if (((insn >> 25) & 7) == 1) {
            /* NEON Data processing.  */
            if (!arm_feature(env, ARM_FEATURE_NEON))
                goto illegal_op;

            if (disas_neon_data_insn(env, s, insn))
                goto illegal_op;
            return;
        }
        if ((insn & 0x0f100000) == 0x04000000) {
            /* NEON load/store.  */
            if (!arm_feature(env, ARM_FEATURE_NEON))
                goto illegal_op;

            if (disas_neon_ls_insn(env, s, insn))
                goto illegal_op;
            return;
        }
6676 6677 6678 6679 6680 6681 6682 6683 6684
        if (((insn & 0x0f30f000) == 0x0510f000) ||
            ((insn & 0x0f30f010) == 0x0710f000)) {
            if ((insn & (1 << 22)) == 0) {
                /* PLDW; v7MP */
                if (!arm_feature(env, ARM_FEATURE_V7MP)) {
                    goto illegal_op;
                }
            }
            /* Otherwise PLD; v5TE+ */
6685
            ARCH(5TE);
6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701
            return;
        }
        if (((insn & 0x0f70f000) == 0x0450f000) ||
            ((insn & 0x0f70f010) == 0x0650f000)) {
            ARCH(7);
            return; /* PLI; V7 */
        }
        if (((insn & 0x0f700000) == 0x04100000) ||
            ((insn & 0x0f700010) == 0x06100000)) {
            if (!arm_feature(env, ARM_FEATURE_V7MP)) {
                goto illegal_op;
            }
            return; /* v7MP: Unallocated memory hint: must NOP */
        }

        if ((insn & 0x0ffffdff) == 0x01010000) {
P
pbrook 已提交
6702 6703
            ARCH(6);
            /* setend */
6704 6705
            if (((insn >> 9) & 1) != s->bswap_code) {
                /* Dynamic endianness switching not implemented. */
P
pbrook 已提交
6706 6707 6708 6709 6710 6711 6712
                goto illegal_op;
            }
            return;
        } else if ((insn & 0x0fffff00) == 0x057ff000) {
            switch ((insn >> 4) & 0xf) {
            case 1: /* clrex */
                ARCH(6K);
P
Paul Brook 已提交
6713
                gen_clrex(s);
P
pbrook 已提交
6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725
                return;
            case 4: /* dsb */
            case 5: /* dmb */
            case 6: /* isb */
                ARCH(7);
                /* We don't emulate caches so these are a no-op.  */
                return;
            default:
                goto illegal_op;
            }
        } else if ((insn & 0x0e5fffe0) == 0x084d0500) {
            /* srs */
6726
            if (IS_USER(s)) {
P
pbrook 已提交
6727 6728
                goto illegal_op;
            }
6729 6730
            ARCH(6);
            gen_srs(s, (insn & 0x1f), (insn >> 23) & 3, insn & (1 << 21));
6731
            return;
6732
        } else if ((insn & 0x0e50ffe0) == 0x08100a00) {
P
pbrook 已提交
6733
            /* rfe */
6734
            int32_t offset;
P
pbrook 已提交
6735 6736 6737 6738
            if (IS_USER(s))
                goto illegal_op;
            ARCH(6);
            rn = (insn >> 16) & 0xf;
P
pbrook 已提交
6739
            addr = load_reg(s, rn);
P
pbrook 已提交
6740 6741
            i = (insn >> 23) & 3;
            switch (i) {
P
pbrook 已提交
6742
            case 0: offset = -4; break; /* DA */
6743 6744
            case 1: offset = 0; break; /* IA */
            case 2: offset = -8; break; /* DB */
P
pbrook 已提交
6745
            case 3: offset = 4; break; /* IB */
P
pbrook 已提交
6746 6747 6748
            default: abort();
            }
            if (offset)
P
pbrook 已提交
6749 6750
                tcg_gen_addi_i32(addr, addr, offset);
            /* Load PC into tmp and CPSR into tmp2.  */
6751 6752
            tmp = tcg_temp_new_i32();
            tcg_gen_qemu_ld32u(tmp, addr, 0);
P
pbrook 已提交
6753
            tcg_gen_addi_i32(addr, addr, 4);
6754 6755
            tmp2 = tcg_temp_new_i32();
            tcg_gen_qemu_ld32u(tmp, addr, 0);
P
pbrook 已提交
6756 6757 6758
            if (insn & (1 << 21)) {
                /* Base writeback.  */
                switch (i) {
P
pbrook 已提交
6759
                case 0: offset = -8; break;
6760 6761
                case 1: offset = 4; break;
                case 2: offset = -4; break;
P
pbrook 已提交
6762
                case 3: offset = 0; break;
P
pbrook 已提交
6763 6764 6765
                default: abort();
                }
                if (offset)
P
pbrook 已提交
6766 6767 6768
                    tcg_gen_addi_i32(addr, addr, offset);
                store_reg(s, rn, addr);
            } else {
6769
                tcg_temp_free_i32(addr);
P
pbrook 已提交
6770
            }
P
pbrook 已提交
6771
            gen_rfe(s, tmp, tmp2);
6772
            return;
P
pbrook 已提交
6773 6774 6775 6776 6777
        } else if ((insn & 0x0e000000) == 0x0a000000) {
            /* branch link and change to thumb (blx <offset>) */
            int32_t offset;

            val = (uint32_t)s->pc;
6778
            tmp = tcg_temp_new_i32();
P
pbrook 已提交
6779 6780
            tcg_gen_movi_i32(tmp, val);
            store_reg(s, 14, tmp);
P
pbrook 已提交
6781 6782 6783 6784 6785 6786
            /* 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;
6787
            /* protected by ARCH(5); above, near the start of uncond block */
P
pbrook 已提交
6788
            gen_bx_im(s, val);
P
pbrook 已提交
6789 6790 6791 6792 6793 6794 6795 6796 6797 6798
            return;
        } else if ((insn & 0x0e000f00) == 0x0c000100) {
            if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
                /* iWMMXt register transfer.  */
                if (env->cp15.c15_cpar & (1 << 1))
                    if (!disas_iwmmxt_insn(env, s, insn))
                        return;
            }
        } else if ((insn & 0x0fe00000) == 0x0c400000) {
            /* Coprocessor double register transfer.  */
6799
            ARCH(5TE);
P
pbrook 已提交
6800 6801
        } else if ((insn & 0x0f000010) == 0x0e000010) {
            /* Additional coprocessor register transfer.  */
B
balrog 已提交
6802
        } else if ((insn & 0x0ff10020) == 0x01000000) {
P
pbrook 已提交
6803 6804 6805 6806 6807 6808 6809 6810 6811 6812 6813 6814 6815 6816 6817 6818
            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 已提交
6819
            if (insn & (1 << 17)) {
P
pbrook 已提交
6820 6821 6822 6823
                mask |= CPSR_M;
                val |= (insn & 0x1f);
            }
            if (mask) {
6824
                gen_set_psr_im(s, mask, 0, val);
P
pbrook 已提交
6825 6826 6827 6828 6829 6830 6831 6832 6833
            }
            return;
        }
        goto illegal_op;
    }
    if (cond != 0xe) {
        /* if not always execute, we generate a conditional jump to
           next instruction */
        s->condlabel = gen_new_label();
P
pbrook 已提交
6834
        gen_test_cc(cond ^ 1, s->condlabel);
P
pbrook 已提交
6835 6836 6837 6838 6839 6840 6841 6842 6843
        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 */
6844
                tmp = tcg_temp_new_i32();
P
pbrook 已提交
6845
                tcg_gen_movi_i32(tmp, val);
P
pbrook 已提交
6846 6847
            } else {
                /* MOVT */
P
pbrook 已提交
6848
                tmp = load_reg(s, rd);
P
pbrook 已提交
6849
                tcg_gen_ext16u_i32(tmp, tmp);
P
pbrook 已提交
6850
                tcg_gen_ori_i32(tmp, tmp, val << 16);
P
pbrook 已提交
6851
            }
P
pbrook 已提交
6852
            store_reg(s, rd, tmp);
P
pbrook 已提交
6853 6854 6855 6856 6857 6858 6859 6860 6861 6862 6863 6864
        } 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);
6865
                if (gen_set_psr_im(s, msr_mask(env, s, (insn >> 16) & 0xf, i), i, val))
P
pbrook 已提交
6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877 6878
                    goto illegal_op;
            }
        }
    } else if ((insn & 0x0f900000) == 0x01000000
               && (insn & 0x00000090) != 0x00000090) {
        /* miscellaneous instructions */
        op1 = (insn >> 21) & 3;
        sh = (insn >> 4) & 0xf;
        rm = insn & 0xf;
        switch (sh) {
        case 0x0: /* move program status register */
            if (op1 & 1) {
                /* PSR = reg */
6879
                tmp = load_reg(s, rm);
P
pbrook 已提交
6880
                i = ((op1 & 2) != 0);
6881
                if (gen_set_psr(s, msr_mask(env, s, (insn >> 16) & 0xf, i), i, tmp))
P
pbrook 已提交
6882 6883 6884 6885 6886 6887 6888
                    goto illegal_op;
            } else {
                /* reg = PSR */
                rd = (insn >> 12) & 0xf;
                if (op1 & 2) {
                    if (IS_USER(s))
                        goto illegal_op;
P
pbrook 已提交
6889
                    tmp = load_cpu_field(spsr);
P
pbrook 已提交
6890
                } else {
6891
                    tmp = tcg_temp_new_i32();
6892
                    gen_helper_cpsr_read(tmp, cpu_env);
P
pbrook 已提交
6893
                }
P
pbrook 已提交
6894
                store_reg(s, rd, tmp);
P
pbrook 已提交
6895 6896 6897 6898 6899
            }
            break;
        case 0x1:
            if (op1 == 1) {
                /* branch/exchange thumb (bx).  */
6900
                ARCH(4T);
P
pbrook 已提交
6901 6902
                tmp = load_reg(s, rm);
                gen_bx(s, tmp);
P
pbrook 已提交
6903 6904
            } else if (op1 == 3) {
                /* clz */
6905
                ARCH(5);
P
pbrook 已提交
6906
                rd = (insn >> 12) & 0xf;
P
pbrook 已提交
6907 6908 6909
                tmp = load_reg(s, rm);
                gen_helper_clz(tmp, tmp);
                store_reg(s, rd, tmp);
P
pbrook 已提交
6910 6911 6912 6913 6914 6915 6916 6917
            } else {
                goto illegal_op;
            }
            break;
        case 0x2:
            if (op1 == 1) {
                ARCH(5J); /* bxj */
                /* Trivial implementation equivalent to bx.  */
P
pbrook 已提交
6918 6919
                tmp = load_reg(s, rm);
                gen_bx(s, tmp);
P
pbrook 已提交
6920 6921 6922 6923 6924 6925 6926 6927
            } else {
                goto illegal_op;
            }
            break;
        case 0x3:
            if (op1 != 1)
              goto illegal_op;

6928
            ARCH(5);
P
pbrook 已提交
6929
            /* branch link/exchange thumb (blx) */
P
pbrook 已提交
6930
            tmp = load_reg(s, rm);
6931
            tmp2 = tcg_temp_new_i32();
P
pbrook 已提交
6932 6933 6934
            tcg_gen_movi_i32(tmp2, s->pc);
            store_reg(s, 14, tmp2);
            gen_bx(s, tmp);
P
pbrook 已提交
6935 6936
            break;
        case 0x5: /* saturating add/subtract */
6937
            ARCH(5TE);
P
pbrook 已提交
6938 6939
            rd = (insn >> 12) & 0xf;
            rn = (insn >> 16) & 0xf;
6940
            tmp = load_reg(s, rm);
P
pbrook 已提交
6941
            tmp2 = load_reg(s, rn);
P
pbrook 已提交
6942
            if (op1 & 2)
6943
                gen_helper_double_saturate(tmp2, cpu_env, tmp2);
P
pbrook 已提交
6944
            if (op1 & 1)
6945
                gen_helper_sub_saturate(tmp, cpu_env, tmp, tmp2);
P
pbrook 已提交
6946
            else
6947
                gen_helper_add_saturate(tmp, cpu_env, tmp, tmp2);
6948
            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
6949
            store_reg(s, rd, tmp);
P
pbrook 已提交
6950
            break;
6951 6952 6953 6954 6955 6956 6957 6958
        case 7:
            /* SMC instruction (op1 == 3)
               and undefined instructions (op1 == 0 || op1 == 2)
               will trap */
            if (op1 != 1) {
                goto illegal_op;
            }
            /* bkpt */
6959
            ARCH(5);
6960
            gen_exception_insn(s, 4, EXCP_BKPT);
P
pbrook 已提交
6961 6962 6963 6964 6965
            break;
        case 0x8: /* signed multiply */
        case 0xa:
        case 0xc:
        case 0xe:
6966
            ARCH(5TE);
P
pbrook 已提交
6967 6968 6969 6970 6971
            rs = (insn >> 8) & 0xf;
            rn = (insn >> 12) & 0xf;
            rd = (insn >> 16) & 0xf;
            if (op1 == 1) {
                /* (32 * 16) >> 16 */
P
pbrook 已提交
6972 6973
                tmp = load_reg(s, rm);
                tmp2 = load_reg(s, rs);
P
pbrook 已提交
6974
                if (sh & 4)
P
pbrook 已提交
6975
                    tcg_gen_sari_i32(tmp2, tmp2, 16);
P
pbrook 已提交
6976
                else
P
pbrook 已提交
6977
                    gen_sxth(tmp2);
P
pbrook 已提交
6978 6979
                tmp64 = gen_muls_i64_i32(tmp, tmp2);
                tcg_gen_shri_i64(tmp64, tmp64, 16);
6980
                tmp = tcg_temp_new_i32();
P
pbrook 已提交
6981
                tcg_gen_trunc_i64_i32(tmp, tmp64);
6982
                tcg_temp_free_i64(tmp64);
P
pbrook 已提交
6983
                if ((sh & 2) == 0) {
P
pbrook 已提交
6984
                    tmp2 = load_reg(s, rn);
6985
                    gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
6986
                    tcg_temp_free_i32(tmp2);
P
pbrook 已提交
6987
                }
P
pbrook 已提交
6988
                store_reg(s, rd, tmp);
P
pbrook 已提交
6989 6990
            } else {
                /* 16 * 16 */
P
pbrook 已提交
6991 6992 6993
                tmp = load_reg(s, rm);
                tmp2 = load_reg(s, rs);
                gen_mulxy(tmp, tmp2, sh & 2, sh & 4);
6994
                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
6995
                if (op1 == 2) {
P
pbrook 已提交
6996 6997
                    tmp64 = tcg_temp_new_i64();
                    tcg_gen_ext_i32_i64(tmp64, tmp);
6998
                    tcg_temp_free_i32(tmp);
P
pbrook 已提交
6999 7000
                    gen_addq(s, tmp64, rn, rd);
                    gen_storeq_reg(s, rn, rd, tmp64);
7001
                    tcg_temp_free_i64(tmp64);
P
pbrook 已提交
7002 7003
                } else {
                    if (op1 == 0) {
P
pbrook 已提交
7004
                        tmp2 = load_reg(s, rn);
7005
                        gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
7006
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
7007
                    }
P
pbrook 已提交
7008
                    store_reg(s, rd, tmp);
P
pbrook 已提交
7009 7010 7011 7012 7013 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 7028
                }
            }
            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;
7029
            if (shift) {
P
pbrook 已提交
7030
                val = (val >> shift) | (val << (32 - shift));
7031
            }
7032
            tmp2 = tcg_temp_new_i32();
7033 7034 7035 7036
            tcg_gen_movi_i32(tmp2, val);
            if (logic_cc && shift) {
                gen_set_CF_bit31(tmp2);
            }
P
pbrook 已提交
7037 7038 7039
        } else {
            /* register */
            rm = (insn) & 0xf;
7040
            tmp2 = load_reg(s, rm);
P
pbrook 已提交
7041 7042 7043
            shiftop = (insn >> 5) & 3;
            if (!(insn & (1 << 4))) {
                shift = (insn >> 7) & 0x1f;
7044
                gen_arm_shift_im(tmp2, shiftop, shift, logic_cc);
P
pbrook 已提交
7045 7046
            } else {
                rs = (insn >> 8) & 0xf;
P
pbrook 已提交
7047
                tmp = load_reg(s, rs);
7048
                gen_arm_shift_reg(tmp2, shiftop, tmp, logic_cc);
P
pbrook 已提交
7049 7050 7051 7052
            }
        }
        if (op1 != 0x0f && op1 != 0x0d) {
            rn = (insn >> 16) & 0xf;
7053 7054
            tmp = load_reg(s, rn);
        } else {
7055
            TCGV_UNUSED_I32(tmp);
P
pbrook 已提交
7056 7057 7058 7059
        }
        rd = (insn >> 12) & 0xf;
        switch(op1) {
        case 0x00:
7060 7061 7062 7063
            tcg_gen_and_i32(tmp, tmp, tmp2);
            if (logic_cc) {
                gen_logic_CC(tmp);
            }
7064
            store_reg_bx(env, s, rd, tmp);
P
pbrook 已提交
7065 7066
            break;
        case 0x01:
7067 7068 7069 7070
            tcg_gen_xor_i32(tmp, tmp, tmp2);
            if (logic_cc) {
                gen_logic_CC(tmp);
            }
7071
            store_reg_bx(env, s, rd, tmp);
P
pbrook 已提交
7072 7073 7074 7075
            break;
        case 0x02:
            if (set_cc && rd == 15) {
                /* SUBS r15, ... is used for exception return.  */
7076
                if (IS_USER(s)) {
P
pbrook 已提交
7077
                    goto illegal_op;
7078
                }
7079
                gen_sub_CC(tmp, tmp, tmp2);
7080
                gen_exception_return(s, tmp);
P
pbrook 已提交
7081
            } else {
7082
                if (set_cc) {
7083
                    gen_sub_CC(tmp, tmp, tmp2);
7084 7085 7086
                } else {
                    tcg_gen_sub_i32(tmp, tmp, tmp2);
                }
7087
                store_reg_bx(env, s, rd, tmp);
P
pbrook 已提交
7088 7089 7090
            }
            break;
        case 0x03:
7091
            if (set_cc) {
7092
                gen_sub_CC(tmp, tmp2, tmp);
7093 7094 7095
            } else {
                tcg_gen_sub_i32(tmp, tmp2, tmp);
            }
7096
            store_reg_bx(env, s, rd, tmp);
P
pbrook 已提交
7097 7098
            break;
        case 0x04:
7099
            if (set_cc) {
7100
                gen_add_CC(tmp, tmp, tmp2);
7101 7102 7103
            } else {
                tcg_gen_add_i32(tmp, tmp, tmp2);
            }
7104
            store_reg_bx(env, s, rd, tmp);
P
pbrook 已提交
7105 7106
            break;
        case 0x05:
7107
            if (set_cc) {
7108
                gen_adc_CC(tmp, tmp, tmp2);
7109 7110 7111
            } else {
                gen_add_carry(tmp, tmp, tmp2);
            }
7112
            store_reg_bx(env, s, rd, tmp);
P
pbrook 已提交
7113 7114
            break;
        case 0x06:
7115
            if (set_cc) {
7116
                gen_sbc_CC(tmp, tmp, tmp2);
7117 7118 7119
            } else {
                gen_sub_carry(tmp, tmp, tmp2);
            }
7120
            store_reg_bx(env, s, rd, tmp);
P
pbrook 已提交
7121 7122
            break;
        case 0x07:
7123
            if (set_cc) {
7124
                gen_sbc_CC(tmp, tmp2, tmp);
7125 7126 7127
            } else {
                gen_sub_carry(tmp, tmp2, tmp);
            }
7128
            store_reg_bx(env, s, rd, tmp);
P
pbrook 已提交
7129 7130 7131
            break;
        case 0x08:
            if (set_cc) {
7132 7133
                tcg_gen_and_i32(tmp, tmp, tmp2);
                gen_logic_CC(tmp);
P
pbrook 已提交
7134
            }
7135
            tcg_temp_free_i32(tmp);
P
pbrook 已提交
7136 7137 7138
            break;
        case 0x09:
            if (set_cc) {
7139 7140
                tcg_gen_xor_i32(tmp, tmp, tmp2);
                gen_logic_CC(tmp);
P
pbrook 已提交
7141
            }
7142
            tcg_temp_free_i32(tmp);
P
pbrook 已提交
7143 7144 7145
            break;
        case 0x0a:
            if (set_cc) {
7146
                gen_sub_CC(tmp, tmp, tmp2);
P
pbrook 已提交
7147
            }
7148
            tcg_temp_free_i32(tmp);
P
pbrook 已提交
7149 7150 7151
            break;
        case 0x0b:
            if (set_cc) {
7152
                gen_add_CC(tmp, tmp, tmp2);
P
pbrook 已提交
7153
            }
7154
            tcg_temp_free_i32(tmp);
P
pbrook 已提交
7155 7156
            break;
        case 0x0c:
7157 7158 7159 7160
            tcg_gen_or_i32(tmp, tmp, tmp2);
            if (logic_cc) {
                gen_logic_CC(tmp);
            }
7161
            store_reg_bx(env, s, rd, tmp);
P
pbrook 已提交
7162 7163 7164 7165
            break;
        case 0x0d:
            if (logic_cc && rd == 15) {
                /* MOVS r15, ... is used for exception return.  */
7166
                if (IS_USER(s)) {
P
pbrook 已提交
7167
                    goto illegal_op;
7168 7169
                }
                gen_exception_return(s, tmp2);
P
pbrook 已提交
7170
            } else {
7171 7172 7173
                if (logic_cc) {
                    gen_logic_CC(tmp2);
                }
7174
                store_reg_bx(env, s, rd, tmp2);
P
pbrook 已提交
7175 7176 7177
            }
            break;
        case 0x0e:
7178
            tcg_gen_andc_i32(tmp, tmp, tmp2);
7179 7180 7181
            if (logic_cc) {
                gen_logic_CC(tmp);
            }
7182
            store_reg_bx(env, s, rd, tmp);
P
pbrook 已提交
7183 7184 7185
            break;
        default:
        case 0x0f:
7186 7187 7188 7189
            tcg_gen_not_i32(tmp2, tmp2);
            if (logic_cc) {
                gen_logic_CC(tmp2);
            }
7190
            store_reg_bx(env, s, rd, tmp2);
P
pbrook 已提交
7191 7192
            break;
        }
7193
        if (op1 != 0x0f && op1 != 0x0d) {
7194
            tcg_temp_free_i32(tmp2);
7195
        }
P
pbrook 已提交
7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212 7213
    } 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 已提交
7214 7215 7216
                        tmp = load_reg(s, rs);
                        tmp2 = load_reg(s, rm);
                        tcg_gen_mul_i32(tmp, tmp, tmp2);
7217
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
7218 7219 7220
                        if (insn & (1 << 22)) {
                            /* Subtract (mls) */
                            ARCH(6T2);
P
pbrook 已提交
7221 7222
                            tmp2 = load_reg(s, rn);
                            tcg_gen_sub_i32(tmp, tmp2, tmp);
7223
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
7224 7225
                        } else if (insn & (1 << 21)) {
                            /* Add */
P
pbrook 已提交
7226 7227
                            tmp2 = load_reg(s, rn);
                            tcg_gen_add_i32(tmp, tmp, tmp2);
7228
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
7229 7230
                        }
                        if (insn & (1 << 20))
P
pbrook 已提交
7231 7232
                            gen_logic_CC(tmp);
                        store_reg(s, rd, tmp);
P
pbrook 已提交
7233
                        break;
A
Aurelien Jarno 已提交
7234 7235 7236 7237 7238 7239 7240 7241 7242 7243 7244 7245 7246 7247
                    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 已提交
7248 7249
                        tmp = load_reg(s, rs);
                        tmp2 = load_reg(s, rm);
A
Aurelien Jarno 已提交
7250
                        if (insn & (1 << 22)) {
7251
                            tcg_gen_muls2_i32(tmp, tmp2, tmp, tmp2);
A
Aurelien Jarno 已提交
7252
                        } else {
7253
                            tcg_gen_mulu2_i32(tmp, tmp2, tmp, tmp2);
A
Aurelien Jarno 已提交
7254 7255
                        }
                        if (insn & (1 << 21)) { /* mult accumulate */
7256 7257
                            TCGv_i32 al = load_reg(s, rn);
                            TCGv_i32 ah = load_reg(s, rd);
7258
                            tcg_gen_add2_i32(tmp, tmp2, tmp, tmp2, al, ah);
7259 7260
                            tcg_temp_free_i32(al);
                            tcg_temp_free_i32(ah);
P
pbrook 已提交
7261
                        }
A
Aurelien Jarno 已提交
7262
                        if (insn & (1 << 20)) {
7263
                            gen_logicq_cc(tmp, tmp2);
A
Aurelien Jarno 已提交
7264
                        }
7265 7266
                        store_reg(s, rn, tmp);
                        store_reg(s, rd, tmp2);
P
pbrook 已提交
7267
                        break;
A
Aurelien Jarno 已提交
7268 7269
                    default:
                        goto illegal_op;
P
pbrook 已提交
7270 7271 7272 7273 7274 7275
                    }
                } else {
                    rn = (insn >> 16) & 0xf;
                    rd = (insn >> 12) & 0xf;
                    if (insn & (1 << 23)) {
                        /* load/store exclusive */
P
pbrook 已提交
7276 7277
                        op1 = (insn >> 21) & 0x3;
                        if (op1)
7278
                            ARCH(6K);
P
pbrook 已提交
7279 7280
                        else
                            ARCH(6);
7281
                        addr = tcg_temp_local_new_i32();
7282
                        load_reg_var(s, addr, rn);
P
pbrook 已提交
7283
                        if (insn & (1 << 20)) {
P
pbrook 已提交
7284 7285
                            switch (op1) {
                            case 0: /* ldrex */
P
Paul Brook 已提交
7286
                                gen_load_exclusive(s, rd, 15, addr, 2);
P
pbrook 已提交
7287 7288
                                break;
                            case 1: /* ldrexd */
P
Paul Brook 已提交
7289
                                gen_load_exclusive(s, rd, rd + 1, addr, 3);
P
pbrook 已提交
7290 7291
                                break;
                            case 2: /* ldrexb */
P
Paul Brook 已提交
7292
                                gen_load_exclusive(s, rd, 15, addr, 0);
P
pbrook 已提交
7293 7294
                                break;
                            case 3: /* ldrexh */
P
Paul Brook 已提交
7295
                                gen_load_exclusive(s, rd, 15, addr, 1);
P
pbrook 已提交
7296 7297 7298 7299
                                break;
                            default:
                                abort();
                            }
P
pbrook 已提交
7300 7301
                        } else {
                            rm = insn & 0xf;
P
pbrook 已提交
7302 7303
                            switch (op1) {
                            case 0:  /*  strex */
P
Paul Brook 已提交
7304
                                gen_store_exclusive(s, rd, rm, 15, addr, 2);
P
pbrook 已提交
7305 7306
                                break;
                            case 1: /*  strexd */
A
Aurelien Jarno 已提交
7307
                                gen_store_exclusive(s, rd, rm, rm + 1, addr, 3);
P
pbrook 已提交
7308 7309
                                break;
                            case 2: /*  strexb */
P
Paul Brook 已提交
7310
                                gen_store_exclusive(s, rd, rm, 15, addr, 0);
P
pbrook 已提交
7311 7312
                                break;
                            case 3: /* strexh */
P
Paul Brook 已提交
7313
                                gen_store_exclusive(s, rd, rm, 15, addr, 1);
P
pbrook 已提交
7314 7315 7316 7317
                                break;
                            default:
                                abort();
                            }
P
pbrook 已提交
7318
                        }
7319
                        tcg_temp_free_i32(addr);
P
pbrook 已提交
7320 7321 7322 7323
                    } else {
                        /* SWP instruction */
                        rm = (insn) & 0xf;

P
pbrook 已提交
7324 7325 7326 7327 7328
                        /* ??? This is not really atomic.  However we know
                           we never have multiple CPUs running in parallel,
                           so it is good enough.  */
                        addr = load_reg(s, rn);
                        tmp = load_reg(s, rm);
7329
                        tmp2 = tcg_temp_new_i32();
P
pbrook 已提交
7330
                        if (insn & (1 << 22)) {
7331 7332
                            tcg_gen_qemu_ld8u(tmp2, addr, IS_USER(s));
                            tcg_gen_qemu_st8(tmp, addr, IS_USER(s));
P
pbrook 已提交
7333
                        } else {
7334 7335
                            tcg_gen_qemu_ld32u(tmp2, addr, IS_USER(s));
                            tcg_gen_qemu_st32(tmp, addr, IS_USER(s));
P
pbrook 已提交
7336
                        }
7337
                        tcg_temp_free_i32(tmp);
7338
                        tcg_temp_free_i32(addr);
P
pbrook 已提交
7339
                        store_reg(s, rd, tmp2);
P
pbrook 已提交
7340 7341 7342 7343 7344 7345 7346 7347
                    }
                }
            } else {
                int address_offset;
                int load;
                /* Misc load/store */
                rn = (insn >> 16) & 0xf;
                rd = (insn >> 12) & 0xf;
P
pbrook 已提交
7348
                addr = load_reg(s, rn);
P
pbrook 已提交
7349
                if (insn & (1 << 24))
P
pbrook 已提交
7350
                    gen_add_datah_offset(s, insn, 0, addr);
P
pbrook 已提交
7351 7352 7353
                address_offset = 0;
                if (insn & (1 << 20)) {
                    /* load */
7354
                    tmp = tcg_temp_new_i32();
P
pbrook 已提交
7355 7356
                    switch(sh) {
                    case 1:
7357
                        tcg_gen_qemu_ld16u(tmp, addr, IS_USER(s));
P
pbrook 已提交
7358 7359
                        break;
                    case 2:
7360
                        tcg_gen_qemu_ld8s(tmp, addr, IS_USER(s));
P
pbrook 已提交
7361 7362 7363
                        break;
                    default:
                    case 3:
7364
                        tcg_gen_qemu_ld16s(tmp, addr, IS_USER(s));
P
pbrook 已提交
7365 7366 7367 7368
                        break;
                    }
                    load = 1;
                } else if (sh & 2) {
7369
                    ARCH(5TE);
P
pbrook 已提交
7370 7371 7372
                    /* doubleword */
                    if (sh & 1) {
                        /* store */
P
pbrook 已提交
7373
                        tmp = load_reg(s, rd);
7374 7375
                        tcg_gen_qemu_st32(tmp, addr, IS_USER(s));
                        tcg_temp_free_i32(tmp);
P
pbrook 已提交
7376 7377
                        tcg_gen_addi_i32(addr, addr, 4);
                        tmp = load_reg(s, rd + 1);
7378 7379
                        tcg_gen_qemu_st32(tmp, addr, IS_USER(s));
                        tcg_temp_free_i32(tmp);
P
pbrook 已提交
7380 7381 7382
                        load = 0;
                    } else {
                        /* load */
7383 7384
                        tmp = tcg_temp_new_i32();
                        tcg_gen_qemu_ld32u(tmp, addr, IS_USER(s));
P
pbrook 已提交
7385 7386
                        store_reg(s, rd, tmp);
                        tcg_gen_addi_i32(addr, addr, 4);
7387 7388
                        tmp = tcg_temp_new_i32();
                        tcg_gen_qemu_ld32u(tmp, addr, IS_USER(s));
P
pbrook 已提交
7389 7390 7391 7392 7393 7394
                        rd++;
                        load = 1;
                    }
                    address_offset = -4;
                } else {
                    /* store */
P
pbrook 已提交
7395
                    tmp = load_reg(s, rd);
7396 7397
                    tcg_gen_qemu_st16(tmp, addr, IS_USER(s));
                    tcg_temp_free_i32(tmp);
P
pbrook 已提交
7398 7399 7400 7401 7402 7403 7404
                    load = 0;
                }
                /* Perform base writeback before the loaded value to
                   ensure correct behavior with overlapping index registers.
                   ldrd with base writeback is is undefined if the
                   destination and index registers overlap.  */
                if (!(insn & (1 << 24))) {
P
pbrook 已提交
7405 7406
                    gen_add_datah_offset(s, insn, address_offset, addr);
                    store_reg(s, rn, addr);
P
pbrook 已提交
7407 7408
                } else if (insn & (1 << 21)) {
                    if (address_offset)
P
pbrook 已提交
7409 7410 7411
                        tcg_gen_addi_i32(addr, addr, address_offset);
                    store_reg(s, rn, addr);
                } else {
7412
                    tcg_temp_free_i32(addr);
P
pbrook 已提交
7413 7414 7415
                }
                if (load) {
                    /* Complete the load.  */
P
pbrook 已提交
7416
                    store_reg(s, rd, tmp);
P
pbrook 已提交
7417 7418 7419 7420 7421 7422 7423 7424 7425 7426 7427 7428 7429
                }
            }
            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 已提交
7430
                rd = (insn >> 12) & 0xf;
P
pbrook 已提交
7431 7432 7433 7434
                rs = (insn >> 8) & 0xf;
                switch ((insn >> 23) & 3) {
                case 0: /* Parallel add/subtract.  */
                    op1 = (insn >> 20) & 7;
P
pbrook 已提交
7435 7436
                    tmp = load_reg(s, rn);
                    tmp2 = load_reg(s, rm);
P
pbrook 已提交
7437 7438 7439
                    sh = (insn >> 5) & 7;
                    if ((op1 & 3) == 0 || sh == 5 || sh == 6)
                        goto illegal_op;
P
pbrook 已提交
7440
                    gen_arm_parallel_addsub(op1, sh, tmp, tmp2);
7441
                    tcg_temp_free_i32(tmp2);
P
pbrook 已提交
7442
                    store_reg(s, rd, tmp);
P
pbrook 已提交
7443 7444 7445
                    break;
                case 1:
                    if ((insn & 0x00700020) == 0) {
B
balrog 已提交
7446
                        /* Halfword pack.  */
P
pbrook 已提交
7447 7448
                        tmp = load_reg(s, rn);
                        tmp2 = load_reg(s, rm);
P
pbrook 已提交
7449
                        shift = (insn >> 7) & 0x1f;
P
pbrook 已提交
7450 7451
                        if (insn & (1 << 6)) {
                            /* pkhtb */
7452 7453 7454
                            if (shift == 0)
                                shift = 31;
                            tcg_gen_sari_i32(tmp2, tmp2, shift);
P
pbrook 已提交
7455
                            tcg_gen_andi_i32(tmp, tmp, 0xffff0000);
P
pbrook 已提交
7456
                            tcg_gen_ext16u_i32(tmp2, tmp2);
P
pbrook 已提交
7457 7458
                        } else {
                            /* pkhbt */
7459 7460
                            if (shift)
                                tcg_gen_shli_i32(tmp2, tmp2, shift);
P
pbrook 已提交
7461
                            tcg_gen_ext16u_i32(tmp, tmp);
P
pbrook 已提交
7462 7463 7464
                            tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000);
                        }
                        tcg_gen_or_i32(tmp, tmp, tmp2);
7465
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
7466
                        store_reg(s, rd, tmp);
P
pbrook 已提交
7467 7468
                    } else if ((insn & 0x00200020) == 0x00200000) {
                        /* [us]sat */
P
pbrook 已提交
7469
                        tmp = load_reg(s, rm);
P
pbrook 已提交
7470 7471 7472 7473
                        shift = (insn >> 7) & 0x1f;
                        if (insn & (1 << 6)) {
                            if (shift == 0)
                                shift = 31;
P
pbrook 已提交
7474
                            tcg_gen_sari_i32(tmp, tmp, shift);
P
pbrook 已提交
7475
                        } else {
P
pbrook 已提交
7476
                            tcg_gen_shli_i32(tmp, tmp, shift);
P
pbrook 已提交
7477 7478
                        }
                        sh = (insn >> 16) & 0x1f;
7479 7480
                        tmp2 = tcg_const_i32(sh);
                        if (insn & (1 << 22))
7481
                          gen_helper_usat(tmp, cpu_env, tmp, tmp2);
7482
                        else
7483
                          gen_helper_ssat(tmp, cpu_env, tmp, tmp2);
7484
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
7485
                        store_reg(s, rd, tmp);
P
pbrook 已提交
7486 7487
                    } else if ((insn & 0x00300fe0) == 0x00200f20) {
                        /* [us]sat16 */
P
pbrook 已提交
7488
                        tmp = load_reg(s, rm);
P
pbrook 已提交
7489
                        sh = (insn >> 16) & 0x1f;
7490 7491
                        tmp2 = tcg_const_i32(sh);
                        if (insn & (1 << 22))
7492
                          gen_helper_usat16(tmp, cpu_env, tmp, tmp2);
7493
                        else
7494
                          gen_helper_ssat16(tmp, cpu_env, tmp, tmp2);
7495
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
7496
                        store_reg(s, rd, tmp);
P
pbrook 已提交
7497 7498
                    } else if ((insn & 0x00700fe0) == 0x00000fa0) {
                        /* Select bytes.  */
P
pbrook 已提交
7499 7500
                        tmp = load_reg(s, rn);
                        tmp2 = load_reg(s, rm);
7501
                        tmp3 = tcg_temp_new_i32();
7502
                        tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUARMState, GE));
P
pbrook 已提交
7503
                        gen_helper_sel_flags(tmp, tmp3, tmp, tmp2);
7504 7505
                        tcg_temp_free_i32(tmp3);
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
7506
                        store_reg(s, rd, tmp);
P
pbrook 已提交
7507
                    } else if ((insn & 0x000003e0) == 0x00000060) {
P
pbrook 已提交
7508
                        tmp = load_reg(s, rm);
P
pbrook 已提交
7509
                        shift = (insn >> 10) & 3;
7510
                        /* ??? In many cases it's not necessary to do a
P
pbrook 已提交
7511 7512
                           rotate, a shift is sufficient.  */
                        if (shift != 0)
7513
                            tcg_gen_rotri_i32(tmp, tmp, shift * 8);
P
pbrook 已提交
7514 7515
                        op1 = (insn >> 20) & 7;
                        switch (op1) {
P
pbrook 已提交
7516 7517 7518 7519 7520 7521
                        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 已提交
7522 7523 7524
                        default: goto illegal_op;
                        }
                        if (rn != 15) {
P
pbrook 已提交
7525
                            tmp2 = load_reg(s, rn);
P
pbrook 已提交
7526
                            if ((op1 & 3) == 0) {
P
pbrook 已提交
7527
                                gen_add16(tmp, tmp2);
P
pbrook 已提交
7528
                            } else {
P
pbrook 已提交
7529
                                tcg_gen_add_i32(tmp, tmp, tmp2);
7530
                                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
7531 7532
                            }
                        }
B
balrog 已提交
7533
                        store_reg(s, rd, tmp);
P
pbrook 已提交
7534 7535
                    } else if ((insn & 0x003f0f60) == 0x003f0f20) {
                        /* rev */
P
pbrook 已提交
7536
                        tmp = load_reg(s, rm);
P
pbrook 已提交
7537 7538
                        if (insn & (1 << 22)) {
                            if (insn & (1 << 7)) {
P
pbrook 已提交
7539
                                gen_revsh(tmp);
P
pbrook 已提交
7540 7541
                            } else {
                                ARCH(6T2);
P
pbrook 已提交
7542
                                gen_helper_rbit(tmp, tmp);
P
pbrook 已提交
7543 7544 7545
                            }
                        } else {
                            if (insn & (1 << 7))
P
pbrook 已提交
7546
                                gen_rev16(tmp);
P
pbrook 已提交
7547
                            else
A
aurel32 已提交
7548
                                tcg_gen_bswap32_i32(tmp, tmp);
P
pbrook 已提交
7549
                        }
P
pbrook 已提交
7550
                        store_reg(s, rd, tmp);
P
pbrook 已提交
7551 7552 7553 7554 7555
                    } else {
                        goto illegal_op;
                    }
                    break;
                case 2: /* Multiplies (Type 3).  */
7556 7557 7558 7559 7560 7561
                    switch ((insn >> 20) & 0x7) {
                    case 5:
                        if (((insn >> 6) ^ (insn >> 7)) & 1) {
                            /* op2 not 00x or 11x : UNDEF */
                            goto illegal_op;
                        }
7562 7563
                        /* Signed multiply most significant [accumulate].
                           (SMMUL, SMMLA, SMMLS) */
7564 7565
                        tmp = load_reg(s, rm);
                        tmp2 = load_reg(s, rs);
P
pbrook 已提交
7566
                        tmp64 = gen_muls_i64_i32(tmp, tmp2);
7567

7568
                        if (rd != 15) {
7569
                            tmp = load_reg(s, rd);
P
pbrook 已提交
7570
                            if (insn & (1 << 6)) {
7571
                                tmp64 = gen_subq_msw(tmp64, tmp);
P
pbrook 已提交
7572
                            } else {
7573
                                tmp64 = gen_addq_msw(tmp64, tmp);
P
pbrook 已提交
7574 7575
                            }
                        }
7576 7577 7578 7579
                        if (insn & (1 << 5)) {
                            tcg_gen_addi_i64(tmp64, tmp64, 0x80000000u);
                        }
                        tcg_gen_shri_i64(tmp64, tmp64, 32);
7580
                        tmp = tcg_temp_new_i32();
7581 7582
                        tcg_gen_trunc_i64_i32(tmp, tmp64);
                        tcg_temp_free_i64(tmp64);
7583
                        store_reg(s, rn, tmp);
7584 7585 7586 7587 7588 7589 7590 7591 7592
                        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 已提交
7593
                        if (insn & (1 << 5))
P
pbrook 已提交
7594 7595 7596
                            gen_swap_half(tmp2);
                        gen_smul_dual(tmp, tmp2);
                        if (insn & (1 << 6)) {
7597
                            /* This subtraction cannot overflow. */
P
pbrook 已提交
7598 7599
                            tcg_gen_sub_i32(tmp, tmp, tmp2);
                        } else {
7600 7601 7602 7603
                            /* This addition cannot overflow 32 bits;
                             * however it may overflow considered as a signed
                             * operation, in which case we must set the Q flag.
                             */
7604
                            gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
P
pbrook 已提交
7605
                        }
7606
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
7607
                        if (insn & (1 << 22)) {
P
pbrook 已提交
7608
                            /* smlald, smlsld */
P
pbrook 已提交
7609 7610
                            tmp64 = tcg_temp_new_i64();
                            tcg_gen_ext_i32_i64(tmp64, tmp);
7611
                            tcg_temp_free_i32(tmp);
P
pbrook 已提交
7612 7613
                            gen_addq(s, tmp64, rd, rn);
                            gen_storeq_reg(s, rd, rn, tmp64);
7614
                            tcg_temp_free_i64(tmp64);
P
pbrook 已提交
7615
                        } else {
P
pbrook 已提交
7616
                            /* smuad, smusd, smlad, smlsd */
7617
                            if (rd != 15)
P
pbrook 已提交
7618
                              {
7619
                                tmp2 = load_reg(s, rd);
7620
                                gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
7621
                                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
7622
                              }
7623
                            store_reg(s, rn, tmp);
P
pbrook 已提交
7624
                        }
7625
                        break;
7626 7627 7628 7629 7630 7631 7632 7633 7634 7635 7636 7637 7638 7639 7640 7641 7642 7643 7644
                    case 1:
                    case 3:
                        /* SDIV, UDIV */
                        if (!arm_feature(env, ARM_FEATURE_ARM_DIV)) {
                            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;
7645 7646
                    default:
                        goto illegal_op;
P
pbrook 已提交
7647 7648 7649 7650 7651 7652
                    }
                    break;
                case 3:
                    op1 = ((insn >> 17) & 0x38) | ((insn >> 5) & 7);
                    switch (op1) {
                    case 0: /* Unsigned sum of absolute differences.  */
P
pbrook 已提交
7653 7654 7655 7656
                        ARCH(6);
                        tmp = load_reg(s, rm);
                        tmp2 = load_reg(s, rs);
                        gen_helper_usad8(tmp, tmp, tmp2);
7657
                        tcg_temp_free_i32(tmp2);
7658 7659
                        if (rd != 15) {
                            tmp2 = load_reg(s, rd);
P
pbrook 已提交
7660
                            tcg_gen_add_i32(tmp, tmp, tmp2);
7661
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
7662
                        }
7663
                        store_reg(s, rn, tmp);
P
pbrook 已提交
7664 7665 7666 7667 7668 7669 7670 7671
                        break;
                    case 0x20: case 0x24: case 0x28: case 0x2c:
                        /* Bitfield insert/clear.  */
                        ARCH(6T2);
                        shift = (insn >> 7) & 0x1f;
                        i = (insn >> 16) & 0x1f;
                        i = i + 1 - shift;
                        if (rm == 15) {
7672
                            tmp = tcg_temp_new_i32();
P
pbrook 已提交
7673
                            tcg_gen_movi_i32(tmp, 0);
P
pbrook 已提交
7674
                        } else {
P
pbrook 已提交
7675
                            tmp = load_reg(s, rm);
P
pbrook 已提交
7676 7677
                        }
                        if (i != 32) {
P
pbrook 已提交
7678
                            tmp2 = load_reg(s, rd);
7679
                            tcg_gen_deposit_i32(tmp, tmp2, tmp, shift, i);
7680
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
7681
                        }
P
pbrook 已提交
7682
                        store_reg(s, rd, tmp);
P
pbrook 已提交
7683 7684 7685
                        break;
                    case 0x12: case 0x16: case 0x1a: case 0x1e: /* sbfx */
                    case 0x32: case 0x36: case 0x3a: case 0x3e: /* ubfx */
7686
                        ARCH(6T2);
P
pbrook 已提交
7687
                        tmp = load_reg(s, rm);
P
pbrook 已提交
7688 7689 7690 7691 7692 7693
                        shift = (insn >> 7) & 0x1f;
                        i = ((insn >> 16) & 0x1f) + 1;
                        if (shift + i > 32)
                            goto illegal_op;
                        if (i < 32) {
                            if (op1 & 0x20) {
P
pbrook 已提交
7694
                                gen_ubfx(tmp, shift, (1u << i) - 1);
P
pbrook 已提交
7695
                            } else {
P
pbrook 已提交
7696
                                gen_sbfx(tmp, shift, i);
P
pbrook 已提交
7697 7698
                            }
                        }
P
pbrook 已提交
7699
                        store_reg(s, rd, tmp);
P
pbrook 已提交
7700 7701 7702 7703 7704 7705 7706 7707 7708 7709 7710 7711 7712 7713 7714 7715 7716 7717 7718 7719 7720
                        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 已提交
7721
            tmp2 = load_reg(s, rn);
P
pbrook 已提交
7722 7723
            i = (IS_USER(s) || (insn & 0x01200000) == 0x00200000);
            if (insn & (1 << 24))
P
pbrook 已提交
7724
                gen_add_data_offset(s, insn, tmp2);
P
pbrook 已提交
7725 7726
            if (insn & (1 << 20)) {
                /* load */
7727
                tmp = tcg_temp_new_i32();
P
pbrook 已提交
7728
                if (insn & (1 << 22)) {
7729
                    tcg_gen_qemu_ld8u(tmp, tmp2, i);
P
pbrook 已提交
7730
                } else {
7731
                    tcg_gen_qemu_ld32u(tmp, tmp2, i);
P
pbrook 已提交
7732 7733 7734
                }
            } else {
                /* store */
P
pbrook 已提交
7735
                tmp = load_reg(s, rd);
7736 7737 7738 7739 7740 7741
                if (insn & (1 << 22)) {
                    tcg_gen_qemu_st8(tmp, tmp2, i);
                } else {
                    tcg_gen_qemu_st32(tmp, tmp2, i);
                }
                tcg_temp_free_i32(tmp);
P
pbrook 已提交
7742 7743
            }
            if (!(insn & (1 << 24))) {
P
pbrook 已提交
7744 7745 7746 7747 7748
                gen_add_data_offset(s, insn, tmp2);
                store_reg(s, rn, tmp2);
            } else if (insn & (1 << 21)) {
                store_reg(s, rn, tmp2);
            } else {
7749
                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
7750 7751 7752
            }
            if (insn & (1 << 20)) {
                /* Complete the load.  */
7753
                store_reg_from_load(env, s, rd, tmp);
P
pbrook 已提交
7754 7755 7756 7757 7758 7759
            }
            break;
        case 0x08:
        case 0x09:
            {
                int j, n, user, loaded_base;
7760
                TCGv_i32 loaded_var;
P
pbrook 已提交
7761 7762 7763 7764 7765 7766 7767 7768 7769 7770 7771
                /* load/store multiple words */
                /* XXX: store correct base if write back */
                user = 0;
                if (insn & (1 << 22)) {
                    if (IS_USER(s))
                        goto illegal_op; /* only usable in supervisor mode */

                    if ((insn & (1 << 15)) == 0)
                        user = 1;
                }
                rn = (insn >> 16) & 0xf;
P
pbrook 已提交
7772
                addr = load_reg(s, rn);
P
pbrook 已提交
7773 7774 7775

                /* compute total size */
                loaded_base = 0;
7776
                TCGV_UNUSED_I32(loaded_var);
P
pbrook 已提交
7777 7778 7779 7780 7781 7782 7783 7784 7785
                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 已提交
7786
                        tcg_gen_addi_i32(addr, addr, 4);
P
pbrook 已提交
7787 7788 7789 7790 7791 7792
                    } else {
                        /* post increment */
                    }
                } else {
                    if (insn & (1 << 24)) {
                        /* pre decrement */
P
pbrook 已提交
7793
                        tcg_gen_addi_i32(addr, addr, -(n * 4));
P
pbrook 已提交
7794 7795 7796
                    } else {
                        /* post decrement */
                        if (n != 1)
P
pbrook 已提交
7797
                        tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
P
pbrook 已提交
7798 7799 7800 7801 7802 7803 7804
                    }
                }
                j = 0;
                for(i=0;i<16;i++) {
                    if (insn & (1 << i)) {
                        if (insn & (1 << 20)) {
                            /* load */
7805 7806
                            tmp = tcg_temp_new_i32();
                            tcg_gen_qemu_ld32u(tmp, addr, IS_USER(s));
7807
                            if (user) {
7808
                                tmp2 = tcg_const_i32(i);
B
Blue Swirl 已提交
7809
                                gen_helper_set_user_reg(cpu_env, tmp2, tmp);
7810
                                tcg_temp_free_i32(tmp2);
7811
                                tcg_temp_free_i32(tmp);
P
pbrook 已提交
7812
                            } else if (i == rn) {
P
pbrook 已提交
7813
                                loaded_var = tmp;
P
pbrook 已提交
7814 7815
                                loaded_base = 1;
                            } else {
7816
                                store_reg_from_load(env, s, i, tmp);
P
pbrook 已提交
7817 7818 7819 7820 7821 7822
                            }
                        } else {
                            /* store */
                            if (i == 15) {
                                /* special case: r15 = PC + 8 */
                                val = (long)s->pc + 4;
7823
                                tmp = tcg_temp_new_i32();
P
pbrook 已提交
7824
                                tcg_gen_movi_i32(tmp, val);
P
pbrook 已提交
7825
                            } else if (user) {
7826
                                tmp = tcg_temp_new_i32();
7827
                                tmp2 = tcg_const_i32(i);
7828
                                gen_helper_get_user_reg(tmp, cpu_env, tmp2);
7829
                                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
7830
                            } else {
P
pbrook 已提交
7831
                                tmp = load_reg(s, i);
P
pbrook 已提交
7832
                            }
7833 7834
                            tcg_gen_qemu_st32(tmp, addr, IS_USER(s));
                            tcg_temp_free_i32(tmp);
P
pbrook 已提交
7835 7836 7837 7838
                        }
                        j++;
                        /* no need to add after the last transfer */
                        if (j != n)
P
pbrook 已提交
7839
                            tcg_gen_addi_i32(addr, addr, 4);
P
pbrook 已提交
7840 7841 7842 7843 7844 7845 7846 7847 7848
                    }
                }
                if (insn & (1 << 21)) {
                    /* write back */
                    if (insn & (1 << 23)) {
                        if (insn & (1 << 24)) {
                            /* pre increment */
                        } else {
                            /* post increment */
P
pbrook 已提交
7849
                            tcg_gen_addi_i32(addr, addr, 4);
P
pbrook 已提交
7850 7851 7852 7853 7854
                        }
                    } else {
                        if (insn & (1 << 24)) {
                            /* pre decrement */
                            if (n != 1)
P
pbrook 已提交
7855
                                tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
P
pbrook 已提交
7856 7857
                        } else {
                            /* post decrement */
P
pbrook 已提交
7858
                            tcg_gen_addi_i32(addr, addr, -(n * 4));
P
pbrook 已提交
7859 7860
                        }
                    }
P
pbrook 已提交
7861 7862
                    store_reg(s, rn, addr);
                } else {
7863
                    tcg_temp_free_i32(addr);
P
pbrook 已提交
7864 7865
                }
                if (loaded_base) {
P
pbrook 已提交
7866
                    store_reg(s, rn, loaded_var);
P
pbrook 已提交
7867 7868 7869
                }
                if ((insn & (1 << 22)) && !user) {
                    /* Restore CPSR from SPSR.  */
P
pbrook 已提交
7870 7871
                    tmp = load_cpu_field(spsr);
                    gen_set_cpsr(tmp, 0xffffffff);
7872
                    tcg_temp_free_i32(tmp);
P
pbrook 已提交
7873 7874 7875 7876 7877 7878 7879 7880 7881 7882 7883 7884
                    s->is_jmp = DISAS_UPDATE;
                }
            }
            break;
        case 0xa:
        case 0xb:
            {
                int32_t offset;

                /* branch (and link) */
                val = (int32_t)s->pc;
                if (insn & (1 << 24)) {
7885
                    tmp = tcg_temp_new_i32();
P
pbrook 已提交
7886 7887
                    tcg_gen_movi_i32(tmp, val);
                    store_reg(s, 14, tmp);
P
pbrook 已提交
7888 7889 7890 7891 7892 7893 7894 7895 7896 7897 7898 7899 7900 7901 7902
                }
                offset = (((int32_t)insn << 8) >> 8);
                val += (offset << 2) + 4;
                gen_jmp(s, val);
            }
            break;
        case 0xc:
        case 0xd:
        case 0xe:
            /* Coprocessor.  */
            if (disas_coproc_insn(env, s, insn))
                goto illegal_op;
            break;
        case 0xf:
            /* swi */
P
pbrook 已提交
7903
            gen_set_pc_im(s->pc);
P
pbrook 已提交
7904 7905 7906 7907
            s->is_jmp = DISAS_SWI;
            break;
        default:
        illegal_op:
7908
            gen_exception_insn(s, 4, EXCP_UDEF);
P
pbrook 已提交
7909 7910 7911 7912 7913 7914 7915 7916 7917 7918 7919 7920 7921 7922 7923 7924 7925 7926 7927
            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
7928 7929
gen_thumb2_data_op(DisasContext *s, int op, int conds, uint32_t shifter_out,
                   TCGv_i32 t0, TCGv_i32 t1)
P
pbrook 已提交
7930 7931 7932 7933 7934 7935
{
    int logic_cc;

    logic_cc = 0;
    switch (op) {
    case 0: /* and */
7936
        tcg_gen_and_i32(t0, t0, t1);
P
pbrook 已提交
7937 7938 7939
        logic_cc = conds;
        break;
    case 1: /* bic */
7940
        tcg_gen_andc_i32(t0, t0, t1);
P
pbrook 已提交
7941 7942 7943
        logic_cc = conds;
        break;
    case 2: /* orr */
7944
        tcg_gen_or_i32(t0, t0, t1);
P
pbrook 已提交
7945 7946 7947
        logic_cc = conds;
        break;
    case 3: /* orn */
7948
        tcg_gen_orc_i32(t0, t0, t1);
P
pbrook 已提交
7949 7950 7951
        logic_cc = conds;
        break;
    case 4: /* eor */
7952
        tcg_gen_xor_i32(t0, t0, t1);
P
pbrook 已提交
7953 7954 7955 7956
        logic_cc = conds;
        break;
    case 8: /* add */
        if (conds)
7957
            gen_add_CC(t0, t0, t1);
P
pbrook 已提交
7958
        else
7959
            tcg_gen_add_i32(t0, t0, t1);
P
pbrook 已提交
7960 7961 7962
        break;
    case 10: /* adc */
        if (conds)
7963
            gen_adc_CC(t0, t0, t1);
P
pbrook 已提交
7964
        else
7965
            gen_adc(t0, t1);
P
pbrook 已提交
7966 7967
        break;
    case 11: /* sbc */
7968 7969 7970
        if (conds) {
            gen_sbc_CC(t0, t0, t1);
        } else {
7971
            gen_sub_carry(t0, t0, t1);
7972
        }
P
pbrook 已提交
7973 7974 7975
        break;
    case 13: /* sub */
        if (conds)
7976
            gen_sub_CC(t0, t0, t1);
P
pbrook 已提交
7977
        else
7978
            tcg_gen_sub_i32(t0, t0, t1);
P
pbrook 已提交
7979 7980 7981
        break;
    case 14: /* rsb */
        if (conds)
7982
            gen_sub_CC(t0, t1, t0);
P
pbrook 已提交
7983
        else
7984
            tcg_gen_sub_i32(t0, t1, t0);
P
pbrook 已提交
7985 7986 7987 7988 7989
        break;
    default: /* 5, 6, 7, 9, 12, 15. */
        return 1;
    }
    if (logic_cc) {
7990
        gen_logic_CC(t0);
P
pbrook 已提交
7991
        if (shifter_out)
7992
            gen_set_CF_bit31(t1);
P
pbrook 已提交
7993 7994 7995 7996 7997 7998
    }
    return 0;
}

/* Translate a 32-bit thumb instruction.  Returns nonzero if the instruction
   is not legal.  */
7999
static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw1)
P
pbrook 已提交
8000
{
P
pbrook 已提交
8001
    uint32_t insn, imm, shift, offset;
P
pbrook 已提交
8002
    uint32_t rd, rn, rm, rs;
8003 8004 8005 8006
    TCGv_i32 tmp;
    TCGv_i32 tmp2;
    TCGv_i32 tmp3;
    TCGv_i32 addr;
P
pbrook 已提交
8007
    TCGv_i64 tmp64;
P
pbrook 已提交
8008 8009 8010 8011 8012 8013 8014
    int op;
    int shiftop;
    int conds;
    int logic_cc;

    if (!(arm_feature(env, ARM_FEATURE_THUMB2)
          || arm_feature (env, ARM_FEATURE_M))) {
8015
        /* Thumb-1 cores may need to treat bl and blx as a pair of
P
pbrook 已提交
8016 8017 8018
           16-bit instructions to get correct prefetch abort behavior.  */
        insn = insn_hw1;
        if ((insn & (1 << 12)) == 0) {
8019
            ARCH(5);
P
pbrook 已提交
8020 8021
            /* Second half of blx.  */
            offset = ((insn & 0x7ff) << 1);
P
pbrook 已提交
8022 8023 8024
            tmp = load_reg(s, 14);
            tcg_gen_addi_i32(tmp, tmp, offset);
            tcg_gen_andi_i32(tmp, tmp, 0xfffffffc);
P
pbrook 已提交
8025

8026
            tmp2 = tcg_temp_new_i32();
P
pbrook 已提交
8027
            tcg_gen_movi_i32(tmp2, s->pc | 1);
P
pbrook 已提交
8028 8029
            store_reg(s, 14, tmp2);
            gen_bx(s, tmp);
P
pbrook 已提交
8030 8031 8032 8033 8034
            return 0;
        }
        if (insn & (1 << 11)) {
            /* Second half of bl.  */
            offset = ((insn & 0x7ff) << 1) | 1;
P
pbrook 已提交
8035
            tmp = load_reg(s, 14);
B
balrog 已提交
8036
            tcg_gen_addi_i32(tmp, tmp, offset);
P
pbrook 已提交
8037

8038
            tmp2 = tcg_temp_new_i32();
P
pbrook 已提交
8039
            tcg_gen_movi_i32(tmp2, s->pc | 1);
P
pbrook 已提交
8040 8041
            store_reg(s, 14, tmp2);
            gen_bx(s, tmp);
P
pbrook 已提交
8042 8043 8044 8045 8046 8047 8048
            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;
8049
            tcg_gen_movi_i32(cpu_R[14], s->pc + 2 + offset);
P
pbrook 已提交
8050 8051 8052 8053 8054
            return 0;
        }
        /* Fall through to 32-bit decode.  */
    }

8055
    insn = arm_lduw_code(env, s->pc, s->bswap_code);
P
pbrook 已提交
8056 8057 8058 8059 8060 8061 8062 8063 8064 8065 8066 8067 8068 8069 8070 8071 8072 8073 8074 8075 8076
    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) {
8077
                    addr = tcg_temp_new_i32();
P
pbrook 已提交
8078
                    tcg_gen_movi_i32(addr, s->pc & ~3);
P
pbrook 已提交
8079
                } else {
P
pbrook 已提交
8080
                    addr = load_reg(s, rn);
P
pbrook 已提交
8081 8082 8083 8084 8085
                }
                offset = (insn & 0xff) * 4;
                if ((insn & (1 << 23)) == 0)
                    offset = -offset;
                if (insn & (1 << 24)) {
P
pbrook 已提交
8086
                    tcg_gen_addi_i32(addr, addr, offset);
P
pbrook 已提交
8087 8088 8089 8090
                    offset = 0;
                }
                if (insn & (1 << 20)) {
                    /* ldrd */
8091 8092
                    tmp = tcg_temp_new_i32();
                    tcg_gen_qemu_ld32u(tmp, addr, IS_USER(s));
P
pbrook 已提交
8093 8094
                    store_reg(s, rs, tmp);
                    tcg_gen_addi_i32(addr, addr, 4);
8095 8096
                    tmp = tcg_temp_new_i32();
                    tcg_gen_qemu_ld32u(tmp, addr, IS_USER(s));
P
pbrook 已提交
8097
                    store_reg(s, rd, tmp);
P
pbrook 已提交
8098 8099
                } else {
                    /* strd */
P
pbrook 已提交
8100
                    tmp = load_reg(s, rs);
8101 8102
                    tcg_gen_qemu_st32(tmp, addr, IS_USER(s));
                    tcg_temp_free_i32(tmp);
P
pbrook 已提交
8103 8104
                    tcg_gen_addi_i32(addr, addr, 4);
                    tmp = load_reg(s, rd);
8105 8106
                    tcg_gen_qemu_st32(tmp, addr, IS_USER(s));
                    tcg_temp_free_i32(tmp);
P
pbrook 已提交
8107 8108 8109 8110 8111
                }
                if (insn & (1 << 21)) {
                    /* Base writeback.  */
                    if (rn == 15)
                        goto illegal_op;
P
pbrook 已提交
8112 8113 8114
                    tcg_gen_addi_i32(addr, addr, offset - 4);
                    store_reg(s, rn, addr);
                } else {
8115
                    tcg_temp_free_i32(addr);
P
pbrook 已提交
8116 8117 8118
                }
            } else if ((insn & (1 << 23)) == 0) {
                /* Load/store exclusive word.  */
8119
                addr = tcg_temp_local_new_i32();
8120
                load_reg_var(s, addr, rn);
P
Paul Brook 已提交
8121
                tcg_gen_addi_i32(addr, addr, (insn & 0xff) << 2);
B
bellard 已提交
8122
                if (insn & (1 << 20)) {
P
Paul Brook 已提交
8123
                    gen_load_exclusive(s, rs, 15, addr, 2);
P
pbrook 已提交
8124
                } else {
P
Paul Brook 已提交
8125
                    gen_store_exclusive(s, rd, rs, 15, addr, 2);
P
pbrook 已提交
8126
                }
8127
                tcg_temp_free_i32(addr);
P
pbrook 已提交
8128 8129 8130
            } else if ((insn & (1 << 6)) == 0) {
                /* Table Branch.  */
                if (rn == 15) {
8131
                    addr = tcg_temp_new_i32();
P
pbrook 已提交
8132
                    tcg_gen_movi_i32(addr, s->pc);
P
pbrook 已提交
8133
                } else {
P
pbrook 已提交
8134
                    addr = load_reg(s, rn);
P
pbrook 已提交
8135
                }
P
pbrook 已提交
8136
                tmp = load_reg(s, rm);
P
pbrook 已提交
8137
                tcg_gen_add_i32(addr, addr, tmp);
P
pbrook 已提交
8138 8139
                if (insn & (1 << 4)) {
                    /* tbh */
P
pbrook 已提交
8140
                    tcg_gen_add_i32(addr, addr, tmp);
8141
                    tcg_temp_free_i32(tmp);
8142 8143
                    tmp = tcg_temp_new_i32();
                    tcg_gen_qemu_ld16u(tmp, addr, IS_USER(s));
P
pbrook 已提交
8144
                } else { /* tbb */
8145
                    tcg_temp_free_i32(tmp);
8146 8147
                    tmp = tcg_temp_new_i32();
                    tcg_gen_qemu_ld8u(tmp, addr, IS_USER(s));
P
pbrook 已提交
8148
                }
8149
                tcg_temp_free_i32(addr);
P
pbrook 已提交
8150 8151 8152
                tcg_gen_shli_i32(tmp, tmp, 1);
                tcg_gen_addi_i32(tmp, tmp, s->pc);
                store_reg(s, 15, tmp);
P
pbrook 已提交
8153 8154
            } else {
                /* Load/store exclusive byte/halfword/doubleword.  */
P
Paul Brook 已提交
8155
                ARCH(7);
P
pbrook 已提交
8156
                op = (insn >> 4) & 0x3;
P
Paul Brook 已提交
8157 8158 8159
                if (op == 2) {
                    goto illegal_op;
                }
8160
                addr = tcg_temp_local_new_i32();
8161
                load_reg_var(s, addr, rn);
P
pbrook 已提交
8162
                if (insn & (1 << 20)) {
P
Paul Brook 已提交
8163
                    gen_load_exclusive(s, rs, rd, addr, op);
P
pbrook 已提交
8164
                } else {
P
Paul Brook 已提交
8165
                    gen_store_exclusive(s, rm, rs, rd, addr, op);
P
pbrook 已提交
8166
                }
8167
                tcg_temp_free_i32(addr);
P
pbrook 已提交
8168 8169 8170 8171
            }
        } else {
            /* Load/store multiple, RFE, SRS.  */
            if (((insn >> 23) & 1) == ((insn >> 24) & 1)) {
8172 8173
                /* RFE, SRS: not available in user mode or on M profile */
                if (IS_USER(s) || IS_M(env)) {
P
pbrook 已提交
8174
                    goto illegal_op;
8175
                }
P
pbrook 已提交
8176 8177
                if (insn & (1 << 20)) {
                    /* rfe */
P
pbrook 已提交
8178 8179 8180 8181
                    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.  */
8182 8183
                    tmp = tcg_temp_new_i32();
                    tcg_gen_qemu_ld32u(tmp, addr, 0);
P
pbrook 已提交
8184
                    tcg_gen_addi_i32(addr, addr, 4);
8185 8186
                    tmp2 = tcg_temp_new_i32();
                    tcg_gen_qemu_ld32u(tmp2, addr, 0);
P
pbrook 已提交
8187 8188
                    if (insn & (1 << 21)) {
                        /* Base writeback.  */
P
pbrook 已提交
8189 8190 8191 8192 8193 8194 8195
                        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 {
8196
                        tcg_temp_free_i32(addr);
P
pbrook 已提交
8197
                    }
P
pbrook 已提交
8198
                    gen_rfe(s, tmp, tmp2);
P
pbrook 已提交
8199 8200
                } else {
                    /* srs */
8201 8202
                    gen_srs(s, (insn & 0x1f), (insn & (1 << 24)) ? 1 : 2,
                            insn & (1 << 21));
P
pbrook 已提交
8203 8204
                }
            } else {
8205
                int i, loaded_base = 0;
8206
                TCGv_i32 loaded_var;
P
pbrook 已提交
8207
                /* Load/store multiple.  */
P
pbrook 已提交
8208
                addr = load_reg(s, rn);
P
pbrook 已提交
8209 8210 8211 8212 8213 8214
                offset = 0;
                for (i = 0; i < 16; i++) {
                    if (insn & (1 << i))
                        offset += 4;
                }
                if (insn & (1 << 24)) {
P
pbrook 已提交
8215
                    tcg_gen_addi_i32(addr, addr, -offset);
P
pbrook 已提交
8216 8217
                }

8218
                TCGV_UNUSED_I32(loaded_var);
P
pbrook 已提交
8219 8220 8221 8222 8223
                for (i = 0; i < 16; i++) {
                    if ((insn & (1 << i)) == 0)
                        continue;
                    if (insn & (1 << 20)) {
                        /* Load.  */
8224 8225
                        tmp = tcg_temp_new_i32();
                        tcg_gen_qemu_ld32u(tmp, addr, IS_USER(s));
P
pbrook 已提交
8226
                        if (i == 15) {
P
pbrook 已提交
8227
                            gen_bx(s, tmp);
8228 8229 8230
                        } else if (i == rn) {
                            loaded_var = tmp;
                            loaded_base = 1;
P
pbrook 已提交
8231
                        } else {
P
pbrook 已提交
8232
                            store_reg(s, i, tmp);
P
pbrook 已提交
8233 8234 8235
                        }
                    } else {
                        /* Store.  */
P
pbrook 已提交
8236
                        tmp = load_reg(s, i);
8237 8238
                        tcg_gen_qemu_st32(tmp, addr, IS_USER(s));
                        tcg_temp_free_i32(tmp);
P
pbrook 已提交
8239
                    }
P
pbrook 已提交
8240
                    tcg_gen_addi_i32(addr, addr, 4);
P
pbrook 已提交
8241
                }
8242 8243 8244
                if (loaded_base) {
                    store_reg(s, rn, loaded_var);
                }
P
pbrook 已提交
8245 8246 8247
                if (insn & (1 << 21)) {
                    /* Base register writeback.  */
                    if (insn & (1 << 24)) {
P
pbrook 已提交
8248
                        tcg_gen_addi_i32(addr, addr, -offset);
P
pbrook 已提交
8249 8250 8251 8252
                    }
                    /* Fault if writeback register is in register list.  */
                    if (insn & (1 << rn))
                        goto illegal_op;
P
pbrook 已提交
8253 8254
                    store_reg(s, rn, addr);
                } else {
8255
                    tcg_temp_free_i32(addr);
P
pbrook 已提交
8256 8257 8258 8259
                }
            }
        }
        break;
8260 8261
    case 5:

P
pbrook 已提交
8262
        op = (insn >> 21) & 0xf;
8263 8264 8265 8266 8267 8268 8269 8270 8271 8272 8273 8274 8275 8276 8277 8278 8279 8280 8281 8282
        if (op == 6) {
            /* 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);
8283
            tcg_temp_free_i32(tmp2);
8284 8285
            store_reg(s, rd, tmp);
        } else {
8286 8287
            /* Data processing register constant shift.  */
            if (rn == 15) {
8288
                tmp = tcg_temp_new_i32();
8289 8290 8291 8292 8293 8294 8295 8296 8297 8298 8299 8300 8301
                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;
8302
            tcg_temp_free_i32(tmp2);
8303 8304 8305
            if (rd != 15) {
                store_reg(s, rd, tmp);
            } else {
8306
                tcg_temp_free_i32(tmp);
8307
            }
8308
        }
P
pbrook 已提交
8309 8310 8311 8312 8313 8314 8315
        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 已提交
8316 8317
            tmp = load_reg(s, rn);
            tmp2 = load_reg(s, rm);
P
pbrook 已提交
8318 8319 8320
            if ((insn & 0x70) != 0)
                goto illegal_op;
            op = (insn >> 21) & 3;
P
pbrook 已提交
8321 8322 8323 8324
            logic_cc = (insn & (1 << 20)) != 0;
            gen_arm_shift_reg(tmp, op, tmp2, logic_cc);
            if (logic_cc)
                gen_logic_CC(tmp);
8325
            store_reg_bx(env, s, rd, tmp);
P
pbrook 已提交
8326 8327
            break;
        case 1: /* Sign/zero extend.  */
P
pbrook 已提交
8328
            tmp = load_reg(s, rm);
P
pbrook 已提交
8329
            shift = (insn >> 4) & 3;
8330
            /* ??? In many cases it's not necessary to do a
P
pbrook 已提交
8331 8332
               rotate, a shift is sufficient.  */
            if (shift != 0)
8333
                tcg_gen_rotri_i32(tmp, tmp, shift * 8);
P
pbrook 已提交
8334 8335
            op = (insn >> 20) & 7;
            switch (op) {
P
pbrook 已提交
8336 8337 8338 8339 8340 8341
            case 0: gen_sxth(tmp);   break;
            case 1: gen_uxth(tmp);   break;
            case 2: gen_sxtb16(tmp); break;
            case 3: gen_uxtb16(tmp); break;
            case 4: gen_sxtb(tmp);   break;
            case 5: gen_uxtb(tmp);   break;
P
pbrook 已提交
8342 8343 8344
            default: goto illegal_op;
            }
            if (rn != 15) {
P
pbrook 已提交
8345
                tmp2 = load_reg(s, rn);
P
pbrook 已提交
8346
                if ((op >> 1) == 1) {
P
pbrook 已提交
8347
                    gen_add16(tmp, tmp2);
P
pbrook 已提交
8348
                } else {
P
pbrook 已提交
8349
                    tcg_gen_add_i32(tmp, tmp, tmp2);
8350
                    tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8351 8352
                }
            }
P
pbrook 已提交
8353
            store_reg(s, rd, tmp);
P
pbrook 已提交
8354 8355 8356 8357 8358 8359
            break;
        case 2: /* SIMD add/subtract.  */
            op = (insn >> 20) & 7;
            shift = (insn >> 4) & 7;
            if ((op & 3) == 3 || (shift & 3) == 3)
                goto illegal_op;
P
pbrook 已提交
8360 8361 8362
            tmp = load_reg(s, rn);
            tmp2 = load_reg(s, rm);
            gen_thumb2_parallel_addsub(op, shift, tmp, tmp2);
8363
            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8364
            store_reg(s, rd, tmp);
P
pbrook 已提交
8365 8366 8367 8368 8369
            break;
        case 3: /* Other data processing.  */
            op = ((insn >> 17) & 0x38) | ((insn >> 4) & 7);
            if (op < 4) {
                /* Saturating add/subtract.  */
P
pbrook 已提交
8370 8371
                tmp = load_reg(s, rn);
                tmp2 = load_reg(s, rm);
P
pbrook 已提交
8372
                if (op & 1)
8373
                    gen_helper_double_saturate(tmp, cpu_env, tmp);
8374
                if (op & 2)
8375
                    gen_helper_sub_saturate(tmp, cpu_env, tmp2, tmp);
P
pbrook 已提交
8376
                else
8377
                    gen_helper_add_saturate(tmp, cpu_env, tmp, tmp2);
8378
                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8379
            } else {
P
pbrook 已提交
8380
                tmp = load_reg(s, rn);
P
pbrook 已提交
8381 8382
                switch (op) {
                case 0x0a: /* rbit */
P
pbrook 已提交
8383
                    gen_helper_rbit(tmp, tmp);
P
pbrook 已提交
8384 8385
                    break;
                case 0x08: /* rev */
A
aurel32 已提交
8386
                    tcg_gen_bswap32_i32(tmp, tmp);
P
pbrook 已提交
8387 8388
                    break;
                case 0x09: /* rev16 */
P
pbrook 已提交
8389
                    gen_rev16(tmp);
P
pbrook 已提交
8390 8391
                    break;
                case 0x0b: /* revsh */
P
pbrook 已提交
8392
                    gen_revsh(tmp);
P
pbrook 已提交
8393 8394
                    break;
                case 0x10: /* sel */
P
pbrook 已提交
8395
                    tmp2 = load_reg(s, rm);
8396
                    tmp3 = tcg_temp_new_i32();
8397
                    tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUARMState, GE));
P
pbrook 已提交
8398
                    gen_helper_sel_flags(tmp, tmp3, tmp, tmp2);
8399 8400
                    tcg_temp_free_i32(tmp3);
                    tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8401 8402
                    break;
                case 0x18: /* clz */
P
pbrook 已提交
8403
                    gen_helper_clz(tmp, tmp);
P
pbrook 已提交
8404 8405 8406 8407 8408
                    break;
                default:
                    goto illegal_op;
                }
            }
P
pbrook 已提交
8409
            store_reg(s, rd, tmp);
P
pbrook 已提交
8410 8411 8412
            break;
        case 4: case 5: /* 32-bit multiply.  Sum of absolute differences.  */
            op = (insn >> 4) & 0xf;
P
pbrook 已提交
8413 8414
            tmp = load_reg(s, rn);
            tmp2 = load_reg(s, rm);
P
pbrook 已提交
8415 8416
            switch ((insn >> 20) & 7) {
            case 0: /* 32 x 32 -> 32 */
P
pbrook 已提交
8417
                tcg_gen_mul_i32(tmp, tmp, tmp2);
8418
                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8419
                if (rs != 15) {
P
pbrook 已提交
8420
                    tmp2 = load_reg(s, rs);
P
pbrook 已提交
8421
                    if (op)
P
pbrook 已提交
8422
                        tcg_gen_sub_i32(tmp, tmp2, tmp);
P
pbrook 已提交
8423
                    else
P
pbrook 已提交
8424
                        tcg_gen_add_i32(tmp, tmp, tmp2);
8425
                    tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8426 8427 8428
                }
                break;
            case 1: /* 16 x 16 -> 32 */
P
pbrook 已提交
8429
                gen_mulxy(tmp, tmp2, op & 2, op & 1);
8430
                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8431
                if (rs != 15) {
P
pbrook 已提交
8432
                    tmp2 = load_reg(s, rs);
8433
                    gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
8434
                    tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8435 8436 8437 8438 8439
                }
                break;
            case 2: /* Dual multiply add.  */
            case 4: /* Dual multiply subtract.  */
                if (op)
P
pbrook 已提交
8440 8441
                    gen_swap_half(tmp2);
                gen_smul_dual(tmp, tmp2);
P
pbrook 已提交
8442
                if (insn & (1 << 22)) {
8443
                    /* This subtraction cannot overflow. */
P
pbrook 已提交
8444
                    tcg_gen_sub_i32(tmp, tmp, tmp2);
P
pbrook 已提交
8445
                } else {
8446 8447 8448 8449
                    /* This addition cannot overflow 32 bits;
                     * however it may overflow considered as a signed
                     * operation, in which case we must set the Q flag.
                     */
8450
                    gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
P
pbrook 已提交
8451
                }
8452
                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8453 8454
                if (rs != 15)
                  {
P
pbrook 已提交
8455
                    tmp2 = load_reg(s, rs);
8456
                    gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
8457
                    tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8458 8459 8460 8461
                  }
                break;
            case 3: /* 32 * 16 -> 32msb */
                if (op)
P
pbrook 已提交
8462
                    tcg_gen_sari_i32(tmp2, tmp2, 16);
P
pbrook 已提交
8463
                else
P
pbrook 已提交
8464
                    gen_sxth(tmp2);
P
pbrook 已提交
8465 8466
                tmp64 = gen_muls_i64_i32(tmp, tmp2);
                tcg_gen_shri_i64(tmp64, tmp64, 16);
8467
                tmp = tcg_temp_new_i32();
P
pbrook 已提交
8468
                tcg_gen_trunc_i64_i32(tmp, tmp64);
8469
                tcg_temp_free_i64(tmp64);
P
pbrook 已提交
8470 8471
                if (rs != 15)
                  {
P
pbrook 已提交
8472
                    tmp2 = load_reg(s, rs);
8473
                    gen_helper_add_setq(tmp, cpu_env, tmp, tmp2);
8474
                    tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8475 8476
                  }
                break;
8477 8478
            case 5: case 6: /* 32 * 32 -> 32msb (SMMUL, SMMLA, SMMLS) */
                tmp64 = gen_muls_i64_i32(tmp, tmp2);
P
pbrook 已提交
8479
                if (rs != 15) {
8480 8481 8482
                    tmp = load_reg(s, rs);
                    if (insn & (1 << 20)) {
                        tmp64 = gen_addq_msw(tmp64, tmp);
B
bellard 已提交
8483
                    } else {
8484
                        tmp64 = gen_subq_msw(tmp64, tmp);
B
bellard 已提交
8485
                    }
B
bellard 已提交
8486
                }
8487 8488 8489 8490
                if (insn & (1 << 4)) {
                    tcg_gen_addi_i64(tmp64, tmp64, 0x80000000u);
                }
                tcg_gen_shri_i64(tmp64, tmp64, 32);
8491
                tmp = tcg_temp_new_i32();
8492 8493
                tcg_gen_trunc_i64_i32(tmp, tmp64);
                tcg_temp_free_i64(tmp64);
P
pbrook 已提交
8494 8495
                break;
            case 7: /* Unsigned sum of absolute differences.  */
P
pbrook 已提交
8496
                gen_helper_usad8(tmp, tmp, tmp2);
8497
                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8498
                if (rs != 15) {
P
pbrook 已提交
8499 8500
                    tmp2 = load_reg(s, rs);
                    tcg_gen_add_i32(tmp, tmp, tmp2);
8501
                    tcg_temp_free_i32(tmp2);
8502
                }
P
pbrook 已提交
8503
                break;
B
bellard 已提交
8504
            }
P
pbrook 已提交
8505
            store_reg(s, rd, tmp);
B
bellard 已提交
8506
            break;
P
pbrook 已提交
8507 8508
        case 6: case 7: /* 64-bit multiply, Divide.  */
            op = ((insn >> 4) & 0xf) | ((insn >> 16) & 0x70);
P
pbrook 已提交
8509 8510
            tmp = load_reg(s, rn);
            tmp2 = load_reg(s, rm);
P
pbrook 已提交
8511 8512
            if ((op & 0x50) == 0x10) {
                /* sdiv, udiv */
8513
                if (!arm_feature(env, ARM_FEATURE_THUMB_DIV)) {
P
pbrook 已提交
8514
                    goto illegal_op;
8515
                }
P
pbrook 已提交
8516
                if (op & 0x20)
P
pbrook 已提交
8517
                    gen_helper_udiv(tmp, tmp, tmp2);
B
bellard 已提交
8518
                else
P
pbrook 已提交
8519
                    gen_helper_sdiv(tmp, tmp, tmp2);
8520
                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8521
                store_reg(s, rd, tmp);
P
pbrook 已提交
8522 8523 8524
            } else if ((op & 0xe) == 0xc) {
                /* Dual multiply accumulate long.  */
                if (op & 1)
P
pbrook 已提交
8525 8526
                    gen_swap_half(tmp2);
                gen_smul_dual(tmp, tmp2);
P
pbrook 已提交
8527
                if (op & 0x10) {
P
pbrook 已提交
8528
                    tcg_gen_sub_i32(tmp, tmp, tmp2);
B
bellard 已提交
8529
                } else {
P
pbrook 已提交
8530
                    tcg_gen_add_i32(tmp, tmp, tmp2);
B
bellard 已提交
8531
                }
8532
                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8533 8534 8535
                /* BUGFIX */
                tmp64 = tcg_temp_new_i64();
                tcg_gen_ext_i32_i64(tmp64, tmp);
8536
                tcg_temp_free_i32(tmp);
P
pbrook 已提交
8537 8538
                gen_addq(s, tmp64, rs, rd);
                gen_storeq_reg(s, rs, rd, tmp64);
8539
                tcg_temp_free_i64(tmp64);
B
bellard 已提交
8540
            } else {
P
pbrook 已提交
8541 8542
                if (op & 0x20) {
                    /* Unsigned 64-bit multiply  */
P
pbrook 已提交
8543
                    tmp64 = gen_mulu_i64_i32(tmp, tmp2);
B
bellard 已提交
8544
                } else {
P
pbrook 已提交
8545 8546
                    if (op & 8) {
                        /* smlalxy */
P
pbrook 已提交
8547
                        gen_mulxy(tmp, tmp2, op & 2, op & 1);
8548
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8549 8550
                        tmp64 = tcg_temp_new_i64();
                        tcg_gen_ext_i32_i64(tmp64, tmp);
8551
                        tcg_temp_free_i32(tmp);
P
pbrook 已提交
8552 8553
                    } else {
                        /* Signed 64-bit multiply  */
P
pbrook 已提交
8554
                        tmp64 = gen_muls_i64_i32(tmp, tmp2);
P
pbrook 已提交
8555
                    }
B
bellard 已提交
8556
                }
P
pbrook 已提交
8557 8558
                if (op & 4) {
                    /* umaal */
P
pbrook 已提交
8559 8560
                    gen_addq_lo(s, tmp64, rs);
                    gen_addq_lo(s, tmp64, rd);
P
pbrook 已提交
8561 8562
                } else if (op & 0x40) {
                    /* 64-bit accumulate.  */
P
pbrook 已提交
8563
                    gen_addq(s, tmp64, rs, rd);
P
pbrook 已提交
8564
                }
P
pbrook 已提交
8565
                gen_storeq_reg(s, rs, rd, tmp64);
8566
                tcg_temp_free_i64(tmp64);
8567
            }
B
bellard 已提交
8568
            break;
P
pbrook 已提交
8569 8570 8571 8572 8573 8574
        }
        break;
    case 6: case 7: case 14: case 15:
        /* Coprocessor.  */
        if (((insn >> 24) & 3) == 3) {
            /* Translate into the equivalent ARM encoding.  */
8575
            insn = (insn & 0xe2ffffff) | ((insn & (1 << 28)) >> 4) | (1 << 28);
P
pbrook 已提交
8576 8577 8578 8579 8580 8581 8582 8583 8584 8585 8586 8587 8588 8589 8590 8591 8592 8593 8594 8595 8596 8597 8598 8599 8600 8601
            if (disas_neon_data_insn(env, s, insn))
                goto illegal_op;
        } else {
            if (insn & (1 << 28))
                goto illegal_op;
            if (disas_coproc_insn (env, s, insn))
                goto illegal_op;
        }
        break;
    case 8: case 9: case 10: case 11:
        if (insn & (1 << 15)) {
            /* Branches, misc control.  */
            if (insn & 0x5000) {
                /* Unconditional branch.  */
                /* signextend(hw1[10:0]) -> offset[:12].  */
                offset = ((int32_t)insn << 5) >> 9 & ~(int32_t)0xfff;
                /* hw1[10:0] -> offset[11:1].  */
                offset |= (insn & 0x7ff) << 1;
                /* (~hw2[13, 11] ^ offset[24]) -> offset[23,22]
                   offset[24:22] already have the same value because of the
                   sign extension above.  */
                offset ^= ((~insn) & (1 << 13)) << 10;
                offset ^= ((~insn) & (1 << 11)) << 11;

                if (insn & (1 << 14)) {
                    /* Branch and link.  */
8602
                    tcg_gen_movi_i32(cpu_R[14], s->pc | 1);
B
bellard 已提交
8603
                }
8604

P
pbrook 已提交
8605
                offset += s->pc;
P
pbrook 已提交
8606 8607
                if (insn & (1 << 12)) {
                    /* b/bl */
P
pbrook 已提交
8608
                    gen_jmp(s, offset);
P
pbrook 已提交
8609 8610
                } else {
                    /* blx */
P
pbrook 已提交
8611
                    offset &= ~(uint32_t)2;
8612
                    /* thumb2 bx, no need to check */
P
pbrook 已提交
8613
                    gen_bx_im(s, offset);
B
bellard 已提交
8614
                }
P
pbrook 已提交
8615 8616 8617 8618 8619 8620 8621 8622
            } else if (((insn >> 23) & 7) == 7) {
                /* Misc control */
                if (insn & (1 << 13))
                    goto illegal_op;

                if (insn & (1 << 26)) {
                    /* Secure monitor call (v6Z) */
                    goto illegal_op; /* not implemented.  */
B
bellard 已提交
8623
                } else {
P
pbrook 已提交
8624 8625 8626 8627
                    op = (insn >> 20) & 7;
                    switch (op) {
                    case 0: /* msr cpsr.  */
                        if (IS_M(env)) {
P
pbrook 已提交
8628 8629 8630
                            tmp = load_reg(s, rn);
                            addr = tcg_const_i32(insn & 0xff);
                            gen_helper_v7m_msr(cpu_env, addr, tmp);
8631
                            tcg_temp_free_i32(addr);
8632
                            tcg_temp_free_i32(tmp);
P
pbrook 已提交
8633 8634 8635 8636 8637 8638 8639
                            gen_lookup_tb(s);
                            break;
                        }
                        /* fall through */
                    case 1: /* msr spsr.  */
                        if (IS_M(env))
                            goto illegal_op;
8640 8641
                        tmp = load_reg(s, rn);
                        if (gen_set_psr(s,
P
pbrook 已提交
8642
                              msr_mask(env, s, (insn >> 8) & 0xf, op == 1),
8643
                              op == 1, tmp))
P
pbrook 已提交
8644 8645 8646 8647 8648 8649 8650 8651 8652 8653 8654 8655 8656 8657 8658 8659 8660 8661 8662 8663 8664 8665 8666 8667 8668 8669
                            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) {
8670
                            gen_set_psr_im(s, offset, 0, imm);
P
pbrook 已提交
8671 8672 8673
                        }
                        break;
                    case 3: /* Special control operations.  */
P
Paul Brook 已提交
8674
                        ARCH(7);
P
pbrook 已提交
8675 8676 8677
                        op = (insn >> 4) & 0xf;
                        switch (op) {
                        case 2: /* clrex */
P
Paul Brook 已提交
8678
                            gen_clrex(s);
P
pbrook 已提交
8679 8680 8681 8682 8683 8684 8685 8686 8687 8688 8689 8690
                            break;
                        case 4: /* dsb */
                        case 5: /* dmb */
                        case 6: /* isb */
                            /* These execute as NOPs.  */
                            break;
                        default:
                            goto illegal_op;
                        }
                        break;
                    case 4: /* bxj */
                        /* Trivial implementation equivalent to bx.  */
P
pbrook 已提交
8691 8692
                        tmp = load_reg(s, rn);
                        gen_bx(s, tmp);
P
pbrook 已提交
8693 8694
                        break;
                    case 5: /* Exception return.  */
8695 8696 8697 8698 8699 8700 8701 8702 8703 8704
                        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;
P
pbrook 已提交
8705
                    case 6: /* mrs cpsr.  */
8706
                        tmp = tcg_temp_new_i32();
P
pbrook 已提交
8707
                        if (IS_M(env)) {
P
pbrook 已提交
8708 8709
                            addr = tcg_const_i32(insn & 0xff);
                            gen_helper_v7m_mrs(tmp, cpu_env, addr);
8710
                            tcg_temp_free_i32(addr);
P
pbrook 已提交
8711
                        } else {
8712
                            gen_helper_cpsr_read(tmp, cpu_env);
P
pbrook 已提交
8713
                        }
P
pbrook 已提交
8714
                        store_reg(s, rd, tmp);
P
pbrook 已提交
8715 8716 8717 8718 8719
                        break;
                    case 7: /* mrs spsr.  */
                        /* Not accessible in user mode.  */
                        if (IS_USER(s) || IS_M(env))
                            goto illegal_op;
P
pbrook 已提交
8720 8721
                        tmp = load_cpu_field(spsr);
                        store_reg(s, rd, tmp);
P
pbrook 已提交
8722
                        break;
B
bellard 已提交
8723 8724
                    }
                }
P
pbrook 已提交
8725 8726 8727 8728 8729
            } else {
                /* Conditional branch.  */
                op = (insn >> 22) & 0xf;
                /* Generate a conditional jump to next instruction.  */
                s->condlabel = gen_new_label();
P
pbrook 已提交
8730
                gen_test_cc(op ^ 1, s->condlabel);
P
pbrook 已提交
8731 8732 8733 8734 8735 8736 8737 8738 8739 8740 8741 8742 8743 8744
                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 已提交
8745
                gen_jmp(s, s->pc + offset);
P
pbrook 已提交
8746 8747 8748 8749 8750 8751 8752 8753 8754 8755 8756
            }
        } 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 已提交
8757
                    if (rn == 15) {
8758
                        tmp = tcg_temp_new_i32();
P
pbrook 已提交
8759 8760 8761 8762
                        tcg_gen_movi_i32(tmp, 0);
                    } else {
                        tmp = load_reg(s, rn);
                    }
P
pbrook 已提交
8763 8764 8765 8766 8767 8768
                    switch (op) {
                    case 2: /* Signed bitfield extract.  */
                        imm++;
                        if (shift + imm > 32)
                            goto illegal_op;
                        if (imm < 32)
P
pbrook 已提交
8769
                            gen_sbfx(tmp, shift, imm);
P
pbrook 已提交
8770 8771 8772 8773 8774 8775
                        break;
                    case 6: /* Unsigned bitfield extract.  */
                        imm++;
                        if (shift + imm > 32)
                            goto illegal_op;
                        if (imm < 32)
P
pbrook 已提交
8776
                            gen_ubfx(tmp, shift, (1u << imm) - 1);
P
pbrook 已提交
8777 8778 8779 8780 8781 8782
                        break;
                    case 3: /* Bitfield insert/clear.  */
                        if (imm < shift)
                            goto illegal_op;
                        imm = imm + 1 - shift;
                        if (imm != 32) {
P
pbrook 已提交
8783
                            tmp2 = load_reg(s, rd);
8784
                            tcg_gen_deposit_i32(tmp, tmp2, tmp, shift, imm);
8785
                            tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8786 8787 8788 8789 8790 8791 8792
                        }
                        break;
                    case 7:
                        goto illegal_op;
                    default: /* Saturate.  */
                        if (shift) {
                            if (op & 1)
P
pbrook 已提交
8793
                                tcg_gen_sari_i32(tmp, tmp, shift);
P
pbrook 已提交
8794
                            else
P
pbrook 已提交
8795
                                tcg_gen_shli_i32(tmp, tmp, shift);
P
pbrook 已提交
8796
                        }
P
pbrook 已提交
8797
                        tmp2 = tcg_const_i32(imm);
P
pbrook 已提交
8798 8799 8800
                        if (op & 4) {
                            /* Unsigned.  */
                            if ((op & 1) && shift == 0)
8801
                                gen_helper_usat16(tmp, cpu_env, tmp, tmp2);
P
pbrook 已提交
8802
                            else
8803
                                gen_helper_usat(tmp, cpu_env, tmp, tmp2);
B
bellard 已提交
8804
                        } else {
P
pbrook 已提交
8805 8806
                            /* Signed.  */
                            if ((op & 1) && shift == 0)
8807
                                gen_helper_ssat16(tmp, cpu_env, tmp, tmp2);
P
pbrook 已提交
8808
                            else
8809
                                gen_helper_ssat(tmp, cpu_env, tmp, tmp2);
B
bellard 已提交
8810
                        }
8811
                        tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8812
                        break;
B
bellard 已提交
8813
                    }
P
pbrook 已提交
8814
                    store_reg(s, rd, tmp);
P
pbrook 已提交
8815 8816 8817 8818 8819 8820 8821 8822
                } 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 已提交
8823
                            tmp = load_reg(s, rd);
P
pbrook 已提交
8824
                            tcg_gen_ext16u_i32(tmp, tmp);
P
pbrook 已提交
8825
                            tcg_gen_ori_i32(tmp, tmp, imm << 16);
B
bellard 已提交
8826
                        } else {
P
pbrook 已提交
8827
                            /* movw */
8828
                            tmp = tcg_temp_new_i32();
P
pbrook 已提交
8829
                            tcg_gen_movi_i32(tmp, imm);
B
bellard 已提交
8830 8831
                        }
                    } else {
P
pbrook 已提交
8832 8833
                        /* Add/sub 12-bit immediate.  */
                        if (rn == 15) {
P
pbrook 已提交
8834
                            offset = s->pc & ~(uint32_t)3;
P
pbrook 已提交
8835
                            if (insn & (1 << 23))
P
pbrook 已提交
8836
                                offset -= imm;
P
pbrook 已提交
8837
                            else
P
pbrook 已提交
8838
                                offset += imm;
8839
                            tmp = tcg_temp_new_i32();
P
pbrook 已提交
8840
                            tcg_gen_movi_i32(tmp, offset);
B
bellard 已提交
8841
                        } else {
P
pbrook 已提交
8842
                            tmp = load_reg(s, rn);
P
pbrook 已提交
8843
                            if (insn & (1 << 23))
P
pbrook 已提交
8844
                                tcg_gen_subi_i32(tmp, tmp, imm);
P
pbrook 已提交
8845
                            else
P
pbrook 已提交
8846
                                tcg_gen_addi_i32(tmp, tmp, imm);
B
bellard 已提交
8847
                        }
P
pbrook 已提交
8848
                    }
P
pbrook 已提交
8849
                    store_reg(s, rd, tmp);
P
pbrook 已提交
8850
                }
P
pbrook 已提交
8851 8852 8853 8854 8855 8856 8857 8858 8859 8860 8861 8862 8863 8864 8865 8866 8867 8868 8869 8870 8871 8872 8873 8874 8875 8876
            } 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 已提交
8877
                }
8878
                tmp2 = tcg_temp_new_i32();
8879
                tcg_gen_movi_i32(tmp2, imm);
P
pbrook 已提交
8880
                rn = (insn >> 16) & 0xf;
8881
                if (rn == 15) {
8882
                    tmp = tcg_temp_new_i32();
8883 8884 8885 8886
                    tcg_gen_movi_i32(tmp, 0);
                } else {
                    tmp = load_reg(s, rn);
                }
P
pbrook 已提交
8887 8888
                op = (insn >> 21) & 0xf;
                if (gen_thumb2_data_op(s, op, (insn & (1 << 20)) != 0,
8889
                                       shifter_out, tmp, tmp2))
P
pbrook 已提交
8890
                    goto illegal_op;
8891
                tcg_temp_free_i32(tmp2);
P
pbrook 已提交
8892 8893
                rd = (insn >> 8) & 0xf;
                if (rd != 15) {
8894 8895
                    store_reg(s, rd, tmp);
                } else {
8896
                    tcg_temp_free_i32(tmp);
B
bellard 已提交
8897 8898
                }
            }
P
pbrook 已提交
8899 8900 8901 8902 8903 8904
        }
        break;
    case 12: /* Load/store single data item.  */
        {
        int postinc = 0;
        int writeback = 0;
P
pbrook 已提交
8905
        int user;
P
pbrook 已提交
8906 8907
        if ((insn & 0x01100000) == 0x01000000) {
            if (disas_neon_ls_insn(env, s, insn))
8908
                goto illegal_op;
P
pbrook 已提交
8909 8910
            break;
        }
8911 8912 8913 8914 8915 8916 8917 8918 8919 8920 8921 8922 8923 8924 8925 8926 8927 8928 8929 8930 8931 8932 8933
        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) {
8934 8935 8936
                    /* UNPREDICTABLE, unallocated hint or
                     * PLD/PLDW/PLI (literal)
                     */
8937 8938 8939
                    return 0;
                }
                if (op1 & 1) {
8940
                    return 0; /* PLD/PLDW/PLI or unallocated hint */
8941 8942
                }
                if ((op2 == 0) || ((op2 & 0x3c) == 0x30)) {
8943
                    return 0; /* PLD/PLDW/PLI or unallocated hint */
8944 8945 8946 8947 8948
                }
                /* UNDEF space, or an UNPREDICTABLE */
                return 1;
            }
        }
P
pbrook 已提交
8949
        user = IS_USER(s);
P
pbrook 已提交
8950
        if (rn == 15) {
8951
            addr = tcg_temp_new_i32();
P
pbrook 已提交
8952 8953 8954 8955 8956 8957 8958
            /* 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 已提交
8959
            tcg_gen_movi_i32(addr, imm);
P
pbrook 已提交
8960
        } else {
P
pbrook 已提交
8961
            addr = load_reg(s, rn);
P
pbrook 已提交
8962 8963 8964
            if (insn & (1 << 23)) {
                /* Positive offset.  */
                imm = insn & 0xfff;
P
pbrook 已提交
8965
                tcg_gen_addi_i32(addr, addr, imm);
P
pbrook 已提交
8966 8967
            } else {
                imm = insn & 0xff;
8968 8969
                switch ((insn >> 8) & 0xf) {
                case 0x0: /* Shifted Register.  */
P
pbrook 已提交
8970
                    shift = (insn >> 4) & 0xf;
8971 8972
                    if (shift > 3) {
                        tcg_temp_free_i32(addr);
8973
                        goto illegal_op;
8974
                    }
P
pbrook 已提交
8975
                    tmp = load_reg(s, rm);
P
pbrook 已提交
8976
                    if (shift)
P
pbrook 已提交
8977
                        tcg_gen_shli_i32(tmp, tmp, shift);
P
pbrook 已提交
8978
                    tcg_gen_add_i32(addr, addr, tmp);
8979
                    tcg_temp_free_i32(tmp);
P
pbrook 已提交
8980
                    break;
8981
                case 0xc: /* Negative offset.  */
P
pbrook 已提交
8982
                    tcg_gen_addi_i32(addr, addr, -imm);
P
pbrook 已提交
8983
                    break;
8984
                case 0xe: /* User privilege.  */
P
pbrook 已提交
8985 8986
                    tcg_gen_addi_i32(addr, addr, imm);
                    user = 1;
P
pbrook 已提交
8987
                    break;
8988
                case 0x9: /* Post-decrement.  */
P
pbrook 已提交
8989 8990
                    imm = -imm;
                    /* Fall through.  */
8991
                case 0xb: /* Post-increment.  */
P
pbrook 已提交
8992 8993 8994
                    postinc = 1;
                    writeback = 1;
                    break;
8995
                case 0xd: /* Pre-decrement.  */
P
pbrook 已提交
8996 8997
                    imm = -imm;
                    /* Fall through.  */
8998
                case 0xf: /* Pre-increment.  */
P
pbrook 已提交
8999
                    tcg_gen_addi_i32(addr, addr, imm);
P
pbrook 已提交
9000 9001 9002
                    writeback = 1;
                    break;
                default:
9003
                    tcg_temp_free_i32(addr);
B
bellard 已提交
9004
                    goto illegal_op;
P
pbrook 已提交
9005 9006 9007 9008 9009
                }
            }
        }
        if (insn & (1 << 20)) {
            /* Load.  */
9010
            tmp = tcg_temp_new_i32();
9011
            switch (op) {
9012 9013 9014 9015 9016 9017 9018 9019 9020 9021 9022 9023 9024 9025 9026
            case 0:
                tcg_gen_qemu_ld8u(tmp, addr, user);
                break;
            case 4:
                tcg_gen_qemu_ld8s(tmp, addr, user);
                break;
            case 1:
                tcg_gen_qemu_ld16u(tmp, addr, user);
                break;
            case 5:
                tcg_gen_qemu_ld16s(tmp, addr, user);
                break;
            case 2:
                tcg_gen_qemu_ld32u(tmp, addr, user);
                break;
9027
            default:
9028
                tcg_temp_free_i32(tmp);
9029 9030
                tcg_temp_free_i32(addr);
                goto illegal_op;
9031 9032 9033
            }
            if (rs == 15) {
                gen_bx(s, tmp);
P
pbrook 已提交
9034
            } else {
9035
                store_reg(s, rs, tmp);
P
pbrook 已提交
9036 9037 9038
            }
        } else {
            /* Store.  */
P
pbrook 已提交
9039
            tmp = load_reg(s, rs);
P
pbrook 已提交
9040
            switch (op) {
9041 9042 9043 9044 9045 9046 9047 9048 9049
            case 0:
                tcg_gen_qemu_st8(tmp, addr, user);
                break;
            case 1:
                tcg_gen_qemu_st16(tmp, addr, user);
                break;
            case 2:
                tcg_gen_qemu_st32(tmp, addr, user);
                break;
9050
            default:
9051
                tcg_temp_free_i32(tmp);
9052 9053
                tcg_temp_free_i32(addr);
                goto illegal_op;
B
bellard 已提交
9054
            }
9055
            tcg_temp_free_i32(tmp);
B
bellard 已提交
9056
        }
P
pbrook 已提交
9057
        if (postinc)
P
pbrook 已提交
9058 9059 9060 9061
            tcg_gen_addi_i32(addr, addr, imm);
        if (writeback) {
            store_reg(s, rn, addr);
        } else {
9062
            tcg_temp_free_i32(addr);
P
pbrook 已提交
9063
        }
P
pbrook 已提交
9064 9065 9066 9067
        }
        break;
    default:
        goto illegal_op;
B
bellard 已提交
9068
    }
P
pbrook 已提交
9069 9070 9071
    return 0;
illegal_op:
    return 1;
B
bellard 已提交
9072 9073
}

9074
static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
B
bellard 已提交
9075 9076 9077 9078
{
    uint32_t val, insn, op, rm, rn, rd, shift, cond;
    int32_t offset;
    int i;
9079 9080 9081
    TCGv_i32 tmp;
    TCGv_i32 tmp2;
    TCGv_i32 addr;
B
bellard 已提交
9082

P
pbrook 已提交
9083 9084
    if (s->condexec_mask) {
        cond = s->condexec_cond;
9085 9086 9087 9088 9089
        if (cond != 0x0e) {     /* Skip conditional when condition is AL. */
          s->condlabel = gen_new_label();
          gen_test_cc(cond ^ 1, s->condlabel);
          s->condjmp = 1;
        }
P
pbrook 已提交
9090 9091
    }

9092
    insn = arm_lduw_code(env, s->pc, s->bswap_code);
B
bellard 已提交
9093
    s->pc += 2;
B
bellard 已提交
9094

B
bellard 已提交
9095 9096
    switch (insn >> 12) {
    case 0: case 1:
9097

B
bellard 已提交
9098 9099 9100 9101 9102
        rd = insn & 7;
        op = (insn >> 11) & 3;
        if (op == 3) {
            /* add/subtract */
            rn = (insn >> 3) & 7;
9103
            tmp = load_reg(s, rn);
B
bellard 已提交
9104 9105
            if (insn & (1 << 10)) {
                /* immediate */
9106
                tmp2 = tcg_temp_new_i32();
9107
                tcg_gen_movi_i32(tmp2, (insn >> 6) & 7);
B
bellard 已提交
9108 9109 9110
            } else {
                /* reg */
                rm = (insn >> 6) & 7;
9111
                tmp2 = load_reg(s, rm);
B
bellard 已提交
9112
            }
P
pbrook 已提交
9113 9114
            if (insn & (1 << 9)) {
                if (s->condexec_mask)
9115
                    tcg_gen_sub_i32(tmp, tmp, tmp2);
P
pbrook 已提交
9116
                else
9117
                    gen_sub_CC(tmp, tmp, tmp2);
P
pbrook 已提交
9118 9119
            } else {
                if (s->condexec_mask)
9120
                    tcg_gen_add_i32(tmp, tmp, tmp2);
P
pbrook 已提交
9121
                else
9122
                    gen_add_CC(tmp, tmp, tmp2);
P
pbrook 已提交
9123
            }
9124
            tcg_temp_free_i32(tmp2);
9125
            store_reg(s, rd, tmp);
B
bellard 已提交
9126 9127 9128 9129
        } else {
            /* shift immediate */
            rm = (insn >> 3) & 7;
            shift = (insn >> 6) & 0x1f;
P
pbrook 已提交
9130 9131 9132 9133 9134
            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 已提交
9135 9136 9137 9138 9139 9140
        }
        break;
    case 2: case 3:
        /* arithmetic large immediate */
        op = (insn >> 11) & 3;
        rd = (insn >> 8) & 0x7;
9141
        if (op == 0) { /* mov */
9142
            tmp = tcg_temp_new_i32();
9143
            tcg_gen_movi_i32(tmp, insn & 0xff);
P
pbrook 已提交
9144
            if (!s->condexec_mask)
9145 9146 9147 9148
                gen_logic_CC(tmp);
            store_reg(s, rd, tmp);
        } else {
            tmp = load_reg(s, rd);
9149
            tmp2 = tcg_temp_new_i32();
9150 9151 9152
            tcg_gen_movi_i32(tmp2, insn & 0xff);
            switch (op) {
            case 1: /* cmp */
9153
                gen_sub_CC(tmp, tmp, tmp2);
9154 9155
                tcg_temp_free_i32(tmp);
                tcg_temp_free_i32(tmp2);
9156 9157 9158 9159 9160
                break;
            case 2: /* add */
                if (s->condexec_mask)
                    tcg_gen_add_i32(tmp, tmp, tmp2);
                else
9161
                    gen_add_CC(tmp, tmp, tmp2);
9162
                tcg_temp_free_i32(tmp2);
9163 9164 9165 9166 9167 9168
                store_reg(s, rd, tmp);
                break;
            case 3: /* sub */
                if (s->condexec_mask)
                    tcg_gen_sub_i32(tmp, tmp, tmp2);
                else
9169
                    gen_sub_CC(tmp, tmp, tmp2);
9170
                tcg_temp_free_i32(tmp2);
9171 9172 9173
                store_reg(s, rd, tmp);
                break;
            }
B
bellard 已提交
9174 9175 9176 9177 9178
        }
        break;
    case 4:
        if (insn & (1 << 11)) {
            rd = (insn >> 8) & 7;
B
bellard 已提交
9179 9180 9181
            /* load pc-relative.  Bit 1 of PC is ignored.  */
            val = s->pc + 2 + ((insn & 0xff) * 4);
            val &= ~(uint32_t)2;
9182
            addr = tcg_temp_new_i32();
P
pbrook 已提交
9183
            tcg_gen_movi_i32(addr, val);
9184 9185
            tmp = tcg_temp_new_i32();
            tcg_gen_qemu_ld32u(tmp, addr, IS_USER(s));
9186
            tcg_temp_free_i32(addr);
P
pbrook 已提交
9187
            store_reg(s, rd, tmp);
B
bellard 已提交
9188 9189 9190 9191 9192 9193 9194 9195 9196
            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 */
9197 9198 9199
                tmp = load_reg(s, rd);
                tmp2 = load_reg(s, rm);
                tcg_gen_add_i32(tmp, tmp, tmp2);
9200
                tcg_temp_free_i32(tmp2);
9201
                store_reg(s, rd, tmp);
B
bellard 已提交
9202 9203
                break;
            case 1: /* cmp */
9204 9205
                tmp = load_reg(s, rd);
                tmp2 = load_reg(s, rm);
9206
                gen_sub_CC(tmp, tmp, tmp2);
9207 9208
                tcg_temp_free_i32(tmp2);
                tcg_temp_free_i32(tmp);
B
bellard 已提交
9209 9210
                break;
            case 2: /* mov/cpy */
9211 9212
                tmp = load_reg(s, rm);
                store_reg(s, rd, tmp);
B
bellard 已提交
9213 9214
                break;
            case 3:/* branch [and link] exchange thumb register */
P
pbrook 已提交
9215
                tmp = load_reg(s, rm);
B
bellard 已提交
9216
                if (insn & (1 << 7)) {
9217
                    ARCH(5);
B
bellard 已提交
9218
                    val = (uint32_t)s->pc | 1;
9219
                    tmp2 = tcg_temp_new_i32();
P
pbrook 已提交
9220 9221
                    tcg_gen_movi_i32(tmp2, val);
                    store_reg(s, 14, tmp2);
B
bellard 已提交
9222
                }
9223
                /* already thumb, no need to check */
P
pbrook 已提交
9224
                gen_bx(s, tmp);
B
bellard 已提交
9225 9226 9227 9228 9229 9230 9231 9232 9233 9234 9235 9236 9237 9238 9239 9240 9241 9242 9243
                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;
        }

9244
        if (op == 9) { /* neg */
9245
            tmp = tcg_temp_new_i32();
9246 9247 9248 9249
            tcg_gen_movi_i32(tmp, 0);
        } else if (op != 0xf) { /* mvn doesn't read its first operand */
            tmp = load_reg(s, rd);
        } else {
9250
            TCGV_UNUSED_I32(tmp);
9251
        }
B
bellard 已提交
9252

9253
        tmp2 = load_reg(s, rm);
B
bellard 已提交
9254
        switch (op) {
B
bellard 已提交
9255
        case 0x0: /* and */
9256
            tcg_gen_and_i32(tmp, tmp, tmp2);
P
pbrook 已提交
9257
            if (!s->condexec_mask)
9258
                gen_logic_CC(tmp);
B
bellard 已提交
9259 9260
            break;
        case 0x1: /* eor */
9261
            tcg_gen_xor_i32(tmp, tmp, tmp2);
P
pbrook 已提交
9262
            if (!s->condexec_mask)
9263
                gen_logic_CC(tmp);
B
bellard 已提交
9264 9265
            break;
        case 0x2: /* lsl */
P
pbrook 已提交
9266
            if (s->condexec_mask) {
9267
                gen_shl(tmp2, tmp2, tmp);
P
pbrook 已提交
9268
            } else {
9269
                gen_helper_shl_cc(tmp2, cpu_env, tmp2, tmp);
9270
                gen_logic_CC(tmp2);
P
pbrook 已提交
9271
            }
B
bellard 已提交
9272 9273
            break;
        case 0x3: /* lsr */
P
pbrook 已提交
9274
            if (s->condexec_mask) {
9275
                gen_shr(tmp2, tmp2, tmp);
P
pbrook 已提交
9276
            } else {
9277
                gen_helper_shr_cc(tmp2, cpu_env, tmp2, tmp);
9278
                gen_logic_CC(tmp2);
P
pbrook 已提交
9279
            }
B
bellard 已提交
9280 9281
            break;
        case 0x4: /* asr */
P
pbrook 已提交
9282
            if (s->condexec_mask) {
9283
                gen_sar(tmp2, tmp2, tmp);
P
pbrook 已提交
9284
            } else {
9285
                gen_helper_sar_cc(tmp2, cpu_env, tmp2, tmp);
9286
                gen_logic_CC(tmp2);
P
pbrook 已提交
9287
            }
B
bellard 已提交
9288 9289
            break;
        case 0x5: /* adc */
9290
            if (s->condexec_mask) {
9291
                gen_adc(tmp, tmp2);
9292 9293 9294
            } else {
                gen_adc_CC(tmp, tmp, tmp2);
            }
B
bellard 已提交
9295 9296
            break;
        case 0x6: /* sbc */
9297
            if (s->condexec_mask) {
9298
                gen_sub_carry(tmp, tmp, tmp2);
9299 9300 9301
            } else {
                gen_sbc_CC(tmp, tmp, tmp2);
            }
B
bellard 已提交
9302 9303
            break;
        case 0x7: /* ror */
P
pbrook 已提交
9304
            if (s->condexec_mask) {
9305 9306
                tcg_gen_andi_i32(tmp, tmp, 0x1f);
                tcg_gen_rotr_i32(tmp2, tmp2, tmp);
P
pbrook 已提交
9307
            } else {
9308
                gen_helper_ror_cc(tmp2, cpu_env, tmp2, tmp);
9309
                gen_logic_CC(tmp2);
P
pbrook 已提交
9310
            }
B
bellard 已提交
9311 9312
            break;
        case 0x8: /* tst */
9313 9314
            tcg_gen_and_i32(tmp, tmp, tmp2);
            gen_logic_CC(tmp);
B
bellard 已提交
9315
            rd = 16;
B
bellard 已提交
9316
            break;
B
bellard 已提交
9317
        case 0x9: /* neg */
P
pbrook 已提交
9318
            if (s->condexec_mask)
9319
                tcg_gen_neg_i32(tmp, tmp2);
P
pbrook 已提交
9320
            else
9321
                gen_sub_CC(tmp, tmp, tmp2);
B
bellard 已提交
9322 9323
            break;
        case 0xa: /* cmp */
9324
            gen_sub_CC(tmp, tmp, tmp2);
B
bellard 已提交
9325 9326 9327
            rd = 16;
            break;
        case 0xb: /* cmn */
9328
            gen_add_CC(tmp, tmp, tmp2);
B
bellard 已提交
9329 9330 9331
            rd = 16;
            break;
        case 0xc: /* orr */
9332
            tcg_gen_or_i32(tmp, tmp, tmp2);
P
pbrook 已提交
9333
            if (!s->condexec_mask)
9334
                gen_logic_CC(tmp);
B
bellard 已提交
9335 9336
            break;
        case 0xd: /* mul */
9337
            tcg_gen_mul_i32(tmp, tmp, tmp2);
P
pbrook 已提交
9338
            if (!s->condexec_mask)
9339
                gen_logic_CC(tmp);
B
bellard 已提交
9340 9341
            break;
        case 0xe: /* bic */
9342
            tcg_gen_andc_i32(tmp, tmp, tmp2);
P
pbrook 已提交
9343
            if (!s->condexec_mask)
9344
                gen_logic_CC(tmp);
B
bellard 已提交
9345 9346
            break;
        case 0xf: /* mvn */
9347
            tcg_gen_not_i32(tmp2, tmp2);
P
pbrook 已提交
9348
            if (!s->condexec_mask)
9349
                gen_logic_CC(tmp2);
B
bellard 已提交
9350
            val = 1;
B
bellard 已提交
9351
            rm = rd;
B
bellard 已提交
9352 9353 9354
            break;
        }
        if (rd != 16) {
9355 9356 9357
            if (val) {
                store_reg(s, rm, tmp2);
                if (op != 0xf)
9358
                    tcg_temp_free_i32(tmp);
9359 9360
            } else {
                store_reg(s, rd, tmp);
9361
                tcg_temp_free_i32(tmp2);
9362 9363
            }
        } else {
9364 9365
            tcg_temp_free_i32(tmp);
            tcg_temp_free_i32(tmp2);
B
bellard 已提交
9366 9367 9368 9369 9370 9371 9372 9373 9374
        }
        break;

    case 5:
        /* load/store register offset.  */
        rd = insn & 7;
        rn = (insn >> 3) & 7;
        rm = (insn >> 6) & 7;
        op = (insn >> 9) & 7;
P
pbrook 已提交
9375
        addr = load_reg(s, rn);
P
pbrook 已提交
9376
        tmp = load_reg(s, rm);
P
pbrook 已提交
9377
        tcg_gen_add_i32(addr, addr, tmp);
9378
        tcg_temp_free_i32(tmp);
B
bellard 已提交
9379

9380
        if (op < 3) { /* store */
P
pbrook 已提交
9381
            tmp = load_reg(s, rd);
9382 9383 9384
        } else {
            tmp = tcg_temp_new_i32();
        }
B
bellard 已提交
9385 9386 9387

        switch (op) {
        case 0: /* str */
9388
            tcg_gen_qemu_st32(tmp, addr, IS_USER(s));
B
bellard 已提交
9389 9390
            break;
        case 1: /* strh */
9391
            tcg_gen_qemu_st16(tmp, addr, IS_USER(s));
B
bellard 已提交
9392 9393
            break;
        case 2: /* strb */
9394
            tcg_gen_qemu_st8(tmp, addr, IS_USER(s));
B
bellard 已提交
9395 9396
            break;
        case 3: /* ldrsb */
9397
            tcg_gen_qemu_ld8s(tmp, addr, IS_USER(s));
B
bellard 已提交
9398 9399
            break;
        case 4: /* ldr */
9400
            tcg_gen_qemu_ld32u(tmp, addr, IS_USER(s));
B
bellard 已提交
9401 9402
            break;
        case 5: /* ldrh */
9403
            tcg_gen_qemu_ld16u(tmp, addr, IS_USER(s));
B
bellard 已提交
9404 9405
            break;
        case 6: /* ldrb */
9406
            tcg_gen_qemu_ld8u(tmp, addr, IS_USER(s));
B
bellard 已提交
9407 9408
            break;
        case 7: /* ldrsh */
9409
            tcg_gen_qemu_ld16s(tmp, addr, IS_USER(s));
B
bellard 已提交
9410 9411
            break;
        }
9412
        if (op >= 3) { /* load */
P
pbrook 已提交
9413
            store_reg(s, rd, tmp);
9414 9415 9416
        } else {
            tcg_temp_free_i32(tmp);
        }
9417
        tcg_temp_free_i32(addr);
B
bellard 已提交
9418 9419 9420 9421 9422 9423
        break;

    case 6:
        /* load/store word immediate offset */
        rd = insn & 7;
        rn = (insn >> 3) & 7;
P
pbrook 已提交
9424
        addr = load_reg(s, rn);
B
bellard 已提交
9425
        val = (insn >> 4) & 0x7c;
P
pbrook 已提交
9426
        tcg_gen_addi_i32(addr, addr, val);
B
bellard 已提交
9427 9428 9429

        if (insn & (1 << 11)) {
            /* load */
9430 9431
            tmp = tcg_temp_new_i32();
            tcg_gen_qemu_ld32u(tmp, addr, IS_USER(s));
P
pbrook 已提交
9432
            store_reg(s, rd, tmp);
B
bellard 已提交
9433 9434
        } else {
            /* store */
P
pbrook 已提交
9435
            tmp = load_reg(s, rd);
9436 9437
            tcg_gen_qemu_st32(tmp, addr, IS_USER(s));
            tcg_temp_free_i32(tmp);
B
bellard 已提交
9438
        }
9439
        tcg_temp_free_i32(addr);
B
bellard 已提交
9440 9441 9442 9443 9444 9445
        break;

    case 7:
        /* load/store byte immediate offset */
        rd = insn & 7;
        rn = (insn >> 3) & 7;
P
pbrook 已提交
9446
        addr = load_reg(s, rn);
B
bellard 已提交
9447
        val = (insn >> 6) & 0x1f;
P
pbrook 已提交
9448
        tcg_gen_addi_i32(addr, addr, val);
B
bellard 已提交
9449 9450 9451

        if (insn & (1 << 11)) {
            /* load */
9452 9453
            tmp = tcg_temp_new_i32();
            tcg_gen_qemu_ld8u(tmp, addr, IS_USER(s));
P
pbrook 已提交
9454
            store_reg(s, rd, tmp);
B
bellard 已提交
9455 9456
        } else {
            /* store */
P
pbrook 已提交
9457
            tmp = load_reg(s, rd);
9458 9459
            tcg_gen_qemu_st8(tmp, addr, IS_USER(s));
            tcg_temp_free_i32(tmp);
B
bellard 已提交
9460
        }
9461
        tcg_temp_free_i32(addr);
B
bellard 已提交
9462 9463 9464 9465 9466 9467
        break;

    case 8:
        /* load/store halfword immediate offset */
        rd = insn & 7;
        rn = (insn >> 3) & 7;
P
pbrook 已提交
9468
        addr = load_reg(s, rn);
B
bellard 已提交
9469
        val = (insn >> 5) & 0x3e;
P
pbrook 已提交
9470
        tcg_gen_addi_i32(addr, addr, val);
B
bellard 已提交
9471 9472 9473

        if (insn & (1 << 11)) {
            /* load */
9474 9475
            tmp = tcg_temp_new_i32();
            tcg_gen_qemu_ld16u(tmp, addr, IS_USER(s));
P
pbrook 已提交
9476
            store_reg(s, rd, tmp);
B
bellard 已提交
9477 9478
        } else {
            /* store */
P
pbrook 已提交
9479
            tmp = load_reg(s, rd);
9480 9481
            tcg_gen_qemu_st16(tmp, addr, IS_USER(s));
            tcg_temp_free_i32(tmp);
B
bellard 已提交
9482
        }
9483
        tcg_temp_free_i32(addr);
B
bellard 已提交
9484 9485 9486 9487 9488
        break;

    case 9:
        /* load/store from stack */
        rd = (insn >> 8) & 7;
P
pbrook 已提交
9489
        addr = load_reg(s, 13);
B
bellard 已提交
9490
        val = (insn & 0xff) * 4;
P
pbrook 已提交
9491
        tcg_gen_addi_i32(addr, addr, val);
B
bellard 已提交
9492 9493 9494

        if (insn & (1 << 11)) {
            /* load */
9495 9496
            tmp = tcg_temp_new_i32();
            tcg_gen_qemu_ld32u(tmp, addr, IS_USER(s));
P
pbrook 已提交
9497
            store_reg(s, rd, tmp);
B
bellard 已提交
9498 9499
        } else {
            /* store */
P
pbrook 已提交
9500
            tmp = load_reg(s, rd);
9501 9502
            tcg_gen_qemu_st32(tmp, addr, IS_USER(s));
            tcg_temp_free_i32(tmp);
B
bellard 已提交
9503
        }
9504
        tcg_temp_free_i32(addr);
B
bellard 已提交
9505 9506 9507 9508 9509
        break;

    case 10:
        /* add to high reg */
        rd = (insn >> 8) & 7;
B
bellard 已提交
9510 9511
        if (insn & (1 << 11)) {
            /* SP */
P
pbrook 已提交
9512
            tmp = load_reg(s, 13);
B
bellard 已提交
9513 9514
        } else {
            /* PC. bit 1 is ignored.  */
9515
            tmp = tcg_temp_new_i32();
P
pbrook 已提交
9516
            tcg_gen_movi_i32(tmp, (s->pc + 2) & ~(uint32_t)2);
B
bellard 已提交
9517
        }
B
bellard 已提交
9518
        val = (insn & 0xff) * 4;
P
pbrook 已提交
9519 9520
        tcg_gen_addi_i32(tmp, tmp, val);
        store_reg(s, rd, tmp);
B
bellard 已提交
9521 9522 9523 9524 9525 9526 9527 9528
        break;

    case 11:
        /* misc */
        op = (insn >> 8) & 0xf;
        switch (op) {
        case 0:
            /* adjust stack pointer */
P
pbrook 已提交
9529
            tmp = load_reg(s, 13);
B
bellard 已提交
9530 9531
            val = (insn & 0x7f) * 4;
            if (insn & (1 << 7))
B
balrog 已提交
9532
                val = -(int32_t)val;
P
pbrook 已提交
9533 9534
            tcg_gen_addi_i32(tmp, tmp, val);
            store_reg(s, 13, tmp);
B
bellard 已提交
9535 9536
            break;

P
pbrook 已提交
9537 9538 9539 9540
        case 2: /* sign/zero extend.  */
            ARCH(6);
            rd = insn & 7;
            rm = (insn >> 3) & 7;
P
pbrook 已提交
9541
            tmp = load_reg(s, rm);
P
pbrook 已提交
9542
            switch ((insn >> 6) & 3) {
P
pbrook 已提交
9543 9544 9545 9546
            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 已提交
9547
            }
P
pbrook 已提交
9548
            store_reg(s, rd, tmp);
P
pbrook 已提交
9549
            break;
B
bellard 已提交
9550 9551
        case 4: case 5: case 0xc: case 0xd:
            /* push/pop */
P
pbrook 已提交
9552
            addr = load_reg(s, 13);
B
bellard 已提交
9553 9554
            if (insn & (1 << 8))
                offset = 4;
B
bellard 已提交
9555
            else
B
bellard 已提交
9556 9557 9558 9559 9560 9561
                offset = 0;
            for (i = 0; i < 8; i++) {
                if (insn & (1 << i))
                    offset += 4;
            }
            if ((insn & (1 << 11)) == 0) {
P
pbrook 已提交
9562
                tcg_gen_addi_i32(addr, addr, -offset);
B
bellard 已提交
9563
            }
B
bellard 已提交
9564 9565 9566 9567
            for (i = 0; i < 8; i++) {
                if (insn & (1 << i)) {
                    if (insn & (1 << 11)) {
                        /* pop */
9568 9569
                        tmp = tcg_temp_new_i32();
                        tcg_gen_qemu_ld32u(tmp, addr, IS_USER(s));
P
pbrook 已提交
9570
                        store_reg(s, i, tmp);
B
bellard 已提交
9571 9572
                    } else {
                        /* push */
P
pbrook 已提交
9573
                        tmp = load_reg(s, i);
9574 9575
                        tcg_gen_qemu_st32(tmp, addr, IS_USER(s));
                        tcg_temp_free_i32(tmp);
B
bellard 已提交
9576
                    }
B
bellard 已提交
9577
                    /* advance to the next address.  */
P
pbrook 已提交
9578
                    tcg_gen_addi_i32(addr, addr, 4);
B
bellard 已提交
9579 9580
                }
            }
9581
            TCGV_UNUSED_I32(tmp);
B
bellard 已提交
9582 9583 9584
            if (insn & (1 << 8)) {
                if (insn & (1 << 11)) {
                    /* pop pc */
9585 9586
                    tmp = tcg_temp_new_i32();
                    tcg_gen_qemu_ld32u(tmp, addr, IS_USER(s));
B
bellard 已提交
9587 9588 9589 9590
                    /* don't set the pc until the rest of the instruction
                       has completed */
                } else {
                    /* push lr */
P
pbrook 已提交
9591
                    tmp = load_reg(s, 14);
9592 9593
                    tcg_gen_qemu_st32(tmp, addr, IS_USER(s));
                    tcg_temp_free_i32(tmp);
B
bellard 已提交
9594
                }
P
pbrook 已提交
9595
                tcg_gen_addi_i32(addr, addr, 4);
B
bellard 已提交
9596
            }
B
bellard 已提交
9597
            if ((insn & (1 << 11)) == 0) {
P
pbrook 已提交
9598
                tcg_gen_addi_i32(addr, addr, -offset);
B
bellard 已提交
9599
            }
B
bellard 已提交
9600
            /* write back the new stack pointer */
P
pbrook 已提交
9601
            store_reg(s, 13, addr);
B
bellard 已提交
9602
            /* set the new PC value */
9603 9604 9605
            if ((insn & 0x0900) == 0x0900) {
                store_reg_from_load(env, s, 15, tmp);
            }
B
bellard 已提交
9606 9607
            break;

P
pbrook 已提交
9608 9609
        case 1: case 3: case 9: case 11: /* czb */
            rm = insn & 7;
P
pbrook 已提交
9610
            tmp = load_reg(s, rm);
P
pbrook 已提交
9611 9612 9613
            s->condlabel = gen_new_label();
            s->condjmp = 1;
            if (insn & (1 << 11))
P
pbrook 已提交
9614
                tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, s->condlabel);
P
pbrook 已提交
9615
            else
P
pbrook 已提交
9616
                tcg_gen_brcondi_i32(TCG_COND_NE, tmp, 0, s->condlabel);
9617
            tcg_temp_free_i32(tmp);
P
pbrook 已提交
9618 9619 9620 9621 9622 9623 9624 9625 9626 9627 9628 9629 9630 9631 9632 9633 9634
            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 已提交
9635
        case 0xe: /* bkpt */
9636
            ARCH(5);
9637
            gen_exception_insn(s, 2, EXCP_BKPT);
P
pbrook 已提交
9638 9639
            break;

P
pbrook 已提交
9640 9641 9642 9643
        case 0xa: /* rev */
            ARCH(6);
            rn = (insn >> 3) & 0x7;
            rd = insn & 0x7;
P
pbrook 已提交
9644
            tmp = load_reg(s, rn);
P
pbrook 已提交
9645
            switch ((insn >> 6) & 3) {
A
aurel32 已提交
9646
            case 0: tcg_gen_bswap32_i32(tmp, tmp); break;
P
pbrook 已提交
9647 9648
            case 1: gen_rev16(tmp); break;
            case 3: gen_revsh(tmp); break;
P
pbrook 已提交
9649 9650
            default: goto illegal_op;
            }
P
pbrook 已提交
9651
            store_reg(s, rd, tmp);
P
pbrook 已提交
9652 9653
            break;

9654 9655 9656 9657 9658
        case 6:
            switch ((insn >> 5) & 7) {
            case 2:
                /* setend */
                ARCH(6);
9659 9660
                if (((insn >> 3) & 1) != s->bswap_code) {
                    /* Dynamic endianness switching not implemented. */
9661 9662
                    goto illegal_op;
                }
P
pbrook 已提交
9663
                break;
9664 9665 9666 9667 9668
            case 3:
                /* cps */
                ARCH(6);
                if (IS_USER(s)) {
                    break;
P
pbrook 已提交
9669
                }
9670 9671 9672 9673 9674 9675 9676 9677 9678 9679 9680 9681 9682 9683 9684 9685 9686 9687 9688 9689 9690 9691 9692
                if (IS_M(env)) {
                    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 已提交
9693
                }
9694 9695 9696
                break;
            default:
                goto undef;
P
pbrook 已提交
9697 9698 9699
            }
            break;

B
bellard 已提交
9700 9701 9702 9703 9704 9705
        default:
            goto undef;
        }
        break;

    case 12:
9706
    {
B
bellard 已提交
9707
        /* load/store multiple */
9708 9709
        TCGv_i32 loaded_var;
        TCGV_UNUSED_I32(loaded_var);
B
bellard 已提交
9710
        rn = (insn >> 8) & 0x7;
P
pbrook 已提交
9711
        addr = load_reg(s, rn);
B
bellard 已提交
9712 9713 9714 9715
        for (i = 0; i < 8; i++) {
            if (insn & (1 << i)) {
                if (insn & (1 << 11)) {
                    /* load */
9716 9717
                    tmp = tcg_temp_new_i32();
                    tcg_gen_qemu_ld32u(tmp, addr, IS_USER(s));
9718 9719 9720 9721 9722
                    if (i == rn) {
                        loaded_var = tmp;
                    } else {
                        store_reg(s, i, tmp);
                    }
B
bellard 已提交
9723 9724
                } else {
                    /* store */
P
pbrook 已提交
9725
                    tmp = load_reg(s, i);
9726 9727
                    tcg_gen_qemu_st32(tmp, addr, IS_USER(s));
                    tcg_temp_free_i32(tmp);
B
bellard 已提交
9728
                }
B
bellard 已提交
9729
                /* advance to the next address */
P
pbrook 已提交
9730
                tcg_gen_addi_i32(addr, addr, 4);
B
bellard 已提交
9731 9732
            }
        }
P
pbrook 已提交
9733
        if ((insn & (1 << rn)) == 0) {
9734
            /* base reg not in list: base register writeback */
P
pbrook 已提交
9735 9736
            store_reg(s, rn, addr);
        } else {
9737 9738 9739 9740
            /* base reg in list: if load, complete it now */
            if (insn & (1 << 11)) {
                store_reg(s, rn, loaded_var);
            }
9741
            tcg_temp_free_i32(addr);
P
pbrook 已提交
9742
        }
B
bellard 已提交
9743
        break;
9744
    }
B
bellard 已提交
9745 9746 9747 9748 9749 9750 9751 9752
    case 13:
        /* conditional branch or swi */
        cond = (insn >> 8) & 0xf;
        if (cond == 0xe)
            goto undef;

        if (cond == 0xf) {
            /* swi */
9753
            gen_set_pc_im(s->pc);
P
pbrook 已提交
9754
            s->is_jmp = DISAS_SWI;
B
bellard 已提交
9755 9756 9757
            break;
        }
        /* generate a conditional jump to next instruction */
9758
        s->condlabel = gen_new_label();
P
pbrook 已提交
9759
        gen_test_cc(cond ^ 1, s->condlabel);
9760
        s->condjmp = 1;
B
bellard 已提交
9761 9762

        /* jump to the offset */
B
bellard 已提交
9763
        val = (uint32_t)s->pc + 2;
B
bellard 已提交
9764
        offset = ((int32_t)insn << 24) >> 24;
B
bellard 已提交
9765
        val += offset << 1;
B
bellard 已提交
9766
        gen_jmp(s, val);
B
bellard 已提交
9767 9768 9769
        break;

    case 14:
P
pbrook 已提交
9770
        if (insn & (1 << 11)) {
P
pbrook 已提交
9771 9772
            if (disas_thumb2_insn(env, s, insn))
              goto undef32;
P
pbrook 已提交
9773 9774
            break;
        }
P
pbrook 已提交
9775
        /* unconditional branch */
B
bellard 已提交
9776 9777 9778
        val = (uint32_t)s->pc;
        offset = ((int32_t)insn << 21) >> 21;
        val += (offset << 1) + 2;
B
bellard 已提交
9779
        gen_jmp(s, val);
B
bellard 已提交
9780 9781 9782
        break;

    case 15:
P
pbrook 已提交
9783
        if (disas_thumb2_insn(env, s, insn))
B
balrog 已提交
9784
            goto undef32;
P
pbrook 已提交
9785
        break;
B
bellard 已提交
9786 9787
    }
    return;
P
pbrook 已提交
9788
undef32:
9789
    gen_exception_insn(s, 4, EXCP_UDEF);
P
pbrook 已提交
9790 9791
    return;
illegal_op:
B
bellard 已提交
9792
undef:
9793
    gen_exception_insn(s, 2, EXCP_UDEF);
B
bellard 已提交
9794 9795
}

B
bellard 已提交
9796 9797 9798
/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
   basic block 'tb'. If search_pc is TRUE, also generate PC
   information for each intermediate instruction. */
9799
static inline void gen_intermediate_code_internal(CPUARMState *env,
9800 9801
                                                  TranslationBlock *tb,
                                                  int search_pc)
B
bellard 已提交
9802 9803
{
    DisasContext dc1, *dc = &dc1;
9804
    CPUBreakpoint *bp;
B
bellard 已提交
9805 9806
    uint16_t *gen_opc_end;
    int j, lj;
B
bellard 已提交
9807
    target_ulong pc_start;
B
bellard 已提交
9808
    uint32_t next_page_start;
P
pbrook 已提交
9809 9810
    int num_insns;
    int max_insns;
9811

B
bellard 已提交
9812
    /* generate intermediate code */
B
bellard 已提交
9813
    pc_start = tb->pc;
9814

B
bellard 已提交
9815 9816
    dc->tb = tb;

9817
    gen_opc_end = tcg_ctx.gen_opc_buf + OPC_MAX_SIZE;
B
bellard 已提交
9818 9819 9820

    dc->is_jmp = DISAS_NEXT;
    dc->pc = pc_start;
B
bellard 已提交
9821
    dc->singlestep_enabled = env->singlestep_enabled;
9822
    dc->condjmp = 0;
9823
    dc->thumb = ARM_TBFLAG_THUMB(tb->flags);
P
Paul Brook 已提交
9824
    dc->bswap_code = ARM_TBFLAG_BSWAP_CODE(tb->flags);
9825 9826
    dc->condexec_mask = (ARM_TBFLAG_CONDEXEC(tb->flags) & 0xf) << 1;
    dc->condexec_cond = ARM_TBFLAG_CONDEXEC(tb->flags) >> 4;
B
bellard 已提交
9827
#if !defined(CONFIG_USER_ONLY)
9828
    dc->user = (ARM_TBFLAG_PRIV(tb->flags) == 0);
B
bellard 已提交
9829
#endif
9830
    dc->vfp_enabled = ARM_TBFLAG_VFPEN(tb->flags);
9831 9832
    dc->vec_len = ARM_TBFLAG_VECLEN(tb->flags);
    dc->vec_stride = ARM_TBFLAG_VECSTRIDE(tb->flags);
P
pbrook 已提交
9833 9834 9835 9836
    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 已提交
9837 9838
    cpu_V0 = cpu_F0d;
    cpu_V1 = cpu_F1d;
P
pbrook 已提交
9839
    /* FIXME: cpu_M0 can probably be the same as cpu_V0.  */
P
pbrook 已提交
9840
    cpu_M0 = tcg_temp_new_i64();
B
bellard 已提交
9841
    next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
B
bellard 已提交
9842
    lj = -1;
P
pbrook 已提交
9843 9844 9845 9846 9847
    num_insns = 0;
    max_insns = tb->cflags & CF_COUNT_MASK;
    if (max_insns == 0)
        max_insns = CF_COUNT_MASK;

9848
    gen_tb_start();
9849

9850 9851
    tcg_clear_temp_count();

9852 9853 9854
    /* A note on handling of the condexec (IT) bits:
     *
     * We want to avoid the overhead of having to write the updated condexec
9855
     * bits back to the CPUARMState for every instruction in an IT block. So:
9856
     * (1) if the condexec bits are not already zero then we write
9857
     * zero back into the CPUARMState now. This avoids complications trying
9858 9859 9860 9861 9862
     * 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()
9863
     * which will write the correct value into CPUARMState if zero is wrong.
9864 9865 9866 9867 9868 9869
     * 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)
9870
     * then the CPUARMState will be wrong and we need to reset it.
9871 9872 9873
     * This is handled in the same way as restoration of the
     * PC in these situations: we will be called again with search_pc=1
     * and generate a mapping of the condexec bits for each PC in
9874 9875
     * gen_opc_condexec_bits[]. restore_state_to_opc() then uses
     * this to restore the condexec bits.
9876 9877 9878
     *
     * Note that there are no instructions which can read the condexec
     * bits, and none which can write non-static values to them, so
9879
     * we don't need to care about whether CPUARMState is correct in the
9880 9881 9882
     * middle of a TB.
     */

P
pbrook 已提交
9883 9884
    /* Reset the conditional execution bits immediately. This avoids
       complications trying to do it at the end of the block.  */
9885
    if (dc->condexec_mask || dc->condexec_cond)
P
pbrook 已提交
9886
      {
9887
        TCGv_i32 tmp = tcg_temp_new_i32();
P
pbrook 已提交
9888
        tcg_gen_movi_i32(tmp, 0);
P
pbrook 已提交
9889
        store_cpu_field(tmp, condexec_bits);
P
pbrook 已提交
9890
      }
B
bellard 已提交
9891
    do {
9892 9893 9894 9895 9896 9897 9898 9899 9900 9901
#ifdef CONFIG_USER_ONLY
        /* Intercept jump to the magic kernel page.  */
        if (dc->pc >= 0xffff0000) {
            /* We always get here via a jump, so know we are not in a
               conditional execution block.  */
            gen_exception(EXCP_KERNEL_TRAP);
            dc->is_jmp = DISAS_UPDATE;
            break;
        }
#else
P
pbrook 已提交
9902 9903 9904
        if (dc->pc >= 0xfffffff0 && IS_M(env)) {
            /* We always get here via a jump, so know we are not in a
               conditional execution block.  */
P
pbrook 已提交
9905
            gen_exception(EXCP_EXCEPTION_EXIT);
9906 9907
            dc->is_jmp = DISAS_UPDATE;
            break;
P
pbrook 已提交
9908 9909 9910
        }
#endif

B
Blue Swirl 已提交
9911 9912
        if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
            QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
9913
                if (bp->pc == dc->pc) {
9914
                    gen_exception_insn(dc, 0, EXCP_DEBUG);
P
pbrook 已提交
9915 9916 9917 9918
                    /* Advance PC so that clearing the breakpoint will
                       invalidate this TB.  */
                    dc->pc += 2;
                    goto done_generating;
B
bellard 已提交
9919 9920 9921 9922
                    break;
                }
            }
        }
B
bellard 已提交
9923
        if (search_pc) {
9924
            j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf;
B
bellard 已提交
9925 9926 9927
            if (lj < j) {
                lj++;
                while (lj < j)
9928
                    tcg_ctx.gen_opc_instr_start[lj++] = 0;
B
bellard 已提交
9929
            }
9930
            tcg_ctx.gen_opc_pc[lj] = dc->pc;
9931
            gen_opc_condexec_bits[lj] = (dc->condexec_cond << 4) | (dc->condexec_mask >> 1);
9932
            tcg_ctx.gen_opc_instr_start[lj] = 1;
9933
            tcg_ctx.gen_opc_icount[lj] = num_insns;
B
bellard 已提交
9934
        }
9935

P
pbrook 已提交
9936 9937 9938
        if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
            gen_io_start();

9939
        if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) {
9940 9941 9942
            tcg_gen_debug_insn_start(dc->pc);
        }

9943
        if (dc->thumb) {
P
pbrook 已提交
9944 9945 9946 9947 9948 9949 9950 9951 9952 9953 9954 9955
            disas_thumb_insn(env, dc);
            if (dc->condexec_mask) {
                dc->condexec_cond = (dc->condexec_cond & 0xe)
                                   | ((dc->condexec_mask >> 4) & 1);
                dc->condexec_mask = (dc->condexec_mask << 1) & 0x1f;
                if (dc->condexec_mask == 0) {
                    dc->condexec_cond = 0;
                }
            }
        } else {
            disas_arm_insn(env, dc);
        }
9956 9957 9958 9959 9960

        if (dc->condjmp && !dc->is_jmp) {
            gen_set_label(dc->condlabel);
            dc->condjmp = 0;
        }
9961 9962 9963 9964 9965

        if (tcg_check_temp_count()) {
            fprintf(stderr, "TCG temporary leak before %08x\n", dc->pc);
        }

B
balrog 已提交
9966
        /* Translation stops when a conditional branch is encountered.
9967
         * Otherwise the subsequent code could get translated several times.
B
bellard 已提交
9968
         * Also stop translation when a page boundary is reached.  This
T
ths 已提交
9969
         * ensures prefetch aborts occur at the right place.  */
P
pbrook 已提交
9970
        num_insns ++;
9971
    } while (!dc->is_jmp && tcg_ctx.gen_opc_ptr < gen_opc_end &&
B
bellard 已提交
9972
             !env->singlestep_enabled &&
9973
             !singlestep &&
P
pbrook 已提交
9974 9975 9976 9977 9978 9979 9980 9981 9982 9983 9984
             dc->pc < next_page_start &&
             num_insns < max_insns);

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

B
bellard 已提交
9986
    /* At this stage dc->condjmp will only be set when the skipped
P
pbrook 已提交
9987 9988
       instruction was a conditional branch or trap, and the PC has
       already been written.  */
9989
    if (unlikely(env->singlestep_enabled)) {
B
bellard 已提交
9990
        /* Make sure the pc is updated, and raise a debug exception.  */
9991
        if (dc->condjmp) {
P
pbrook 已提交
9992 9993
            gen_set_condexec(dc);
            if (dc->is_jmp == DISAS_SWI) {
P
pbrook 已提交
9994
                gen_exception(EXCP_SWI);
P
pbrook 已提交
9995
            } else {
P
pbrook 已提交
9996
                gen_exception(EXCP_DEBUG);
P
pbrook 已提交
9997
            }
9998 9999 10000
            gen_set_label(dc->condlabel);
        }
        if (dc->condjmp || !dc->is_jmp) {
P
pbrook 已提交
10001
            gen_set_pc_im(dc->pc);
10002
            dc->condjmp = 0;
B
bellard 已提交
10003
        }
P
pbrook 已提交
10004 10005
        gen_set_condexec(dc);
        if (dc->is_jmp == DISAS_SWI && !dc->condjmp) {
P
pbrook 已提交
10006
            gen_exception(EXCP_SWI);
P
pbrook 已提交
10007 10008 10009
        } else {
            /* FIXME: Single stepping a WFI insn will not halt
               the CPU.  */
P
pbrook 已提交
10010
            gen_exception(EXCP_DEBUG);
P
pbrook 已提交
10011
        }
B
bellard 已提交
10012
    } else {
P
pbrook 已提交
10013 10014
        /* While branches must always occur at the end of an IT block,
           there are a few other things that can cause us to terminate
10015
           the TB in the middle of an IT block:
P
pbrook 已提交
10016 10017 10018 10019 10020 10021
            - 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 已提交
10022 10023
        switch(dc->is_jmp) {
        case DISAS_NEXT:
10024
            gen_goto_tb(dc, 1, dc->pc);
B
bellard 已提交
10025 10026 10027 10028 10029
            break;
        default:
        case DISAS_JUMP:
        case DISAS_UPDATE:
            /* indicate that the hash table must be used to find the next TB */
B
bellard 已提交
10030
            tcg_gen_exit_tb(0);
B
bellard 已提交
10031 10032 10033 10034
            break;
        case DISAS_TB_JUMP:
            /* nothing more to generate */
            break;
P
pbrook 已提交
10035
        case DISAS_WFI:
B
Blue Swirl 已提交
10036
            gen_helper_wfi(cpu_env);
P
pbrook 已提交
10037 10038
            break;
        case DISAS_SWI:
P
pbrook 已提交
10039
            gen_exception(EXCP_SWI);
P
pbrook 已提交
10040
            break;
B
bellard 已提交
10041
        }
10042 10043
        if (dc->condjmp) {
            gen_set_label(dc->condlabel);
P
pbrook 已提交
10044
            gen_set_condexec(dc);
10045
            gen_goto_tb(dc, 1, dc->pc);
10046 10047
            dc->condjmp = 0;
        }
B
bellard 已提交
10048
    }
P
pbrook 已提交
10049

P
pbrook 已提交
10050
done_generating:
10051
    gen_tb_end(tb, num_insns);
10052
    *tcg_ctx.gen_opc_ptr = INDEX_op_end;
B
bellard 已提交
10053 10054

#ifdef DEBUG_DISAS
10055
    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
10056 10057
        qemu_log("----------------\n");
        qemu_log("IN: %s\n", lookup_symbol(pc_start));
B
Blue Swirl 已提交
10058
        log_target_disas(env, pc_start, dc->pc - pc_start,
P
Paul Brook 已提交
10059
                         dc->thumb | (dc->bswap_code << 1));
10060
        qemu_log("\n");
B
bellard 已提交
10061 10062
    }
#endif
B
bellard 已提交
10063
    if (search_pc) {
10064
        j = tcg_ctx.gen_opc_ptr - tcg_ctx.gen_opc_buf;
B
bellard 已提交
10065 10066
        lj++;
        while (lj <= j)
10067
            tcg_ctx.gen_opc_instr_start[lj++] = 0;
B
bellard 已提交
10068
    } else {
B
bellard 已提交
10069
        tb->size = dc->pc - pc_start;
P
pbrook 已提交
10070
        tb->icount = num_insns;
B
bellard 已提交
10071
    }
B
bellard 已提交
10072 10073
}

10074
void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
B
bellard 已提交
10075
{
10076
    gen_intermediate_code_internal(env, tb, 0);
B
bellard 已提交
10077 10078
}

10079
void gen_intermediate_code_pc(CPUARMState *env, TranslationBlock *tb)
B
bellard 已提交
10080
{
10081
    gen_intermediate_code_internal(env, tb, 1);
B
bellard 已提交
10082 10083
}

B
bellard 已提交
10084 10085 10086 10087
static const char *cpu_mode_names[16] = {
  "usr", "fiq", "irq", "svc", "???", "???", "???", "abt",
  "???", "???", "???", "und", "???", "???", "???", "sys"
};
P
pbrook 已提交
10088

10089
void cpu_dump_state(CPUARMState *env, FILE *f, fprintf_function cpu_fprintf,
B
bellard 已提交
10090
                    int flags)
B
bellard 已提交
10091 10092
{
    int i;
B
bellard 已提交
10093
    uint32_t psr;
B
bellard 已提交
10094 10095

    for(i=0;i<16;i++) {
B
bellard 已提交
10096
        cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
B
bellard 已提交
10097
        if ((i % 4) == 3)
B
bellard 已提交
10098
            cpu_fprintf(f, "\n");
B
bellard 已提交
10099
        else
B
bellard 已提交
10100
            cpu_fprintf(f, " ");
B
bellard 已提交
10101
    }
B
bellard 已提交
10102
    psr = cpsr_read(env);
10103 10104
    cpu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%d\n",
                psr,
B
bellard 已提交
10105 10106 10107 10108
                psr & (1 << 31) ? 'N' : '-',
                psr & (1 << 30) ? 'Z' : '-',
                psr & (1 << 29) ? 'C' : '-',
                psr & (1 << 28) ? 'V' : '-',
10109
                psr & CPSR_T ? 'T' : 'A',
B
bellard 已提交
10110
                cpu_mode_names[psr & 0xf], (psr & 0x10) ? 32 : 26);
B
bellard 已提交
10111

10112 10113 10114 10115 10116 10117 10118 10119 10120 10121 10122 10123 10124 10125 10126 10127
    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 已提交
10128
    }
B
bellard 已提交
10129
}
B
bellard 已提交
10130

10131
void restore_state_to_opc(CPUARMState *env, TranslationBlock *tb, int pc_pos)
A
aurel32 已提交
10132
{
10133
    env->regs[15] = tcg_ctx.gen_opc_pc[pc_pos];
10134
    env->condexec_bits = gen_opc_condexec_bits[pc_pos];
A
aurel32 已提交
10135
}