]> git.proxmox.com Git - qemu.git/blame - target-arm/translate.c
ARM TCG conversion 7/16.
[qemu.git] / target-arm / translate.c
CommitLineData
2c0262af
FB
1/*
2 * ARM translation
5fafdf24 3 *
2c0262af 4 * Copyright (c) 2003 Fabrice Bellard
9ee6e8bb 5 * Copyright (c) 2005-2007 CodeSourcery
18c9b560 6 * Copyright (c) 2007 OpenedHand, Ltd.
2c0262af
FB
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22#include <stdarg.h>
23#include <stdlib.h>
24#include <stdio.h>
25#include <string.h>
26#include <inttypes.h>
27
28#include "cpu.h"
29#include "exec-all.h"
30#include "disas.h"
57fec1fe 31#include "tcg-op.h"
1497c961
PB
32
33#define GEN_HELPER 1
b26eefb6 34#include "helpers.h"
2c0262af 35
9ee6e8bb
PB
36#define ENABLE_ARCH_5J 0
37#define ENABLE_ARCH_6 arm_feature(env, ARM_FEATURE_V6)
38#define ENABLE_ARCH_6K arm_feature(env, ARM_FEATURE_V6K)
39#define ENABLE_ARCH_6T2 arm_feature(env, ARM_FEATURE_THUMB2)
40#define ENABLE_ARCH_7 arm_feature(env, ARM_FEATURE_V7)
b5ff1b31
FB
41
42#define ARCH(x) if (!ENABLE_ARCH_##x) goto illegal_op;
43
2c0262af
FB
44/* internal defines */
45typedef struct DisasContext {
0fa85d43 46 target_ulong pc;
2c0262af 47 int is_jmp;
e50e6a20
FB
48 /* Nonzero if this instruction has been conditionally skipped. */
49 int condjmp;
50 /* The label that will be jumped to when the instruction is skipped. */
51 int condlabel;
9ee6e8bb
PB
52 /* Thumb-2 condtional execution bits. */
53 int condexec_mask;
54 int condexec_cond;
2c0262af 55 struct TranslationBlock *tb;
8aaca4c0 56 int singlestep_enabled;
5899f386 57 int thumb;
6658ffb8 58 int is_mem;
b5ff1b31
FB
59#if !defined(CONFIG_USER_ONLY)
60 int user;
61#endif
2c0262af
FB
62} DisasContext;
63
b5ff1b31
FB
64#if defined(CONFIG_USER_ONLY)
65#define IS_USER(s) 1
66#else
67#define IS_USER(s) (s->user)
68#endif
69
9ee6e8bb
PB
70/* These instructions trap after executing, so defer them until after the
71 conditional executions state has been updated. */
72#define DISAS_WFI 4
73#define DISAS_SWI 5
2c0262af
FB
74
75/* XXX: move that elsewhere */
2c0262af
FB
76extern FILE *logfile;
77extern int loglevel;
78
b26eefb6
PB
79static TCGv cpu_env;
80/* FIXME: These should be removed. */
81static TCGv cpu_T[3];
82
83/* initialize TCG globals. */
84void arm_translate_init(void)
85{
86 cpu_env = tcg_global_reg_new(TCG_TYPE_PTR, TCG_AREG0, "env");
87
88 cpu_T[0] = tcg_global_reg_new(TCG_TYPE_I32, TCG_AREG1, "T0");
89 cpu_T[1] = tcg_global_reg_new(TCG_TYPE_I32, TCG_AREG2, "T1");
90 cpu_T[2] = tcg_global_reg_new(TCG_TYPE_I32, TCG_AREG3, "T2");
91}
92
93/* The code generator doesn't like lots of temporaries, so maintain our own
94 cache for reuse within a function. */
95#define MAX_TEMPS 8
96static int num_temps;
97static TCGv temps[MAX_TEMPS];
98
99/* Allocate a temporary variable. */
100static TCGv new_tmp(void)
101{
102 TCGv tmp;
103 if (num_temps == MAX_TEMPS)
104 abort();
105
106 if (GET_TCGV(temps[num_temps]))
107 return temps[num_temps++];
108
109 tmp = tcg_temp_new(TCG_TYPE_I32);
110 temps[num_temps++] = tmp;
111 return tmp;
112}
113
114/* Release a temporary variable. */
115static void dead_tmp(TCGv tmp)
116{
117 int i;
118 num_temps--;
119 i = num_temps;
120 if (GET_TCGV(temps[i]) == GET_TCGV(tmp))
121 return;
122
123 /* Shuffle this temp to the last slot. */
124 while (GET_TCGV(temps[i]) != GET_TCGV(tmp))
125 i--;
126 while (i < num_temps) {
127 temps[i] = temps[i + 1];
128 i++;
129 }
130 temps[i] = tmp;
131}
132
133/* Set a variable to the value of a CPU register. */
134static void load_reg_var(DisasContext *s, TCGv var, int reg)
135{
136 if (reg == 15) {
137 uint32_t addr;
138 /* normaly, since we updated PC, we need only to add one insn */
139 if (s->thumb)
140 addr = (long)s->pc + 2;
141 else
142 addr = (long)s->pc + 4;
143 tcg_gen_movi_i32(var, addr);
144 } else {
145 tcg_gen_ld_i32(var, cpu_env, offsetof(CPUState, regs[reg]));
146 }
147}
148
149/* Create a new temporary and set it to the value of a CPU register. */
150static inline TCGv load_reg(DisasContext *s, int reg)
151{
152 TCGv tmp = new_tmp();
153 load_reg_var(s, tmp, reg);
154 return tmp;
155}
156
157/* Set a CPU register. The source must be a temporary and will be
158 marked as dead. */
159static void store_reg(DisasContext *s, int reg, TCGv var)
160{
161 if (reg == 15) {
162 tcg_gen_andi_i32(var, var, ~1);
163 s->is_jmp = DISAS_JUMP;
164 }
165 tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, regs[reg]));
166 dead_tmp(var);
167}
168
169
170/* Basic operations. */
171#define gen_op_movl_T0_T1() tcg_gen_mov_i32(cpu_T[0], cpu_T[1])
172#define gen_op_movl_T0_T2() tcg_gen_mov_i32(cpu_T[0], cpu_T[2])
173#define gen_op_movl_T1_T0() tcg_gen_mov_i32(cpu_T[1], cpu_T[0])
174#define gen_op_movl_T1_T2() tcg_gen_mov_i32(cpu_T[1], cpu_T[2])
175#define gen_op_movl_T2_T0() tcg_gen_mov_i32(cpu_T[2], cpu_T[0])
176#define gen_op_movl_T0_im(im) tcg_gen_movi_i32(cpu_T[0], im)
177#define gen_op_movl_T1_im(im) tcg_gen_movi_i32(cpu_T[1], im)
178#define gen_op_movl_T2_im(im) tcg_gen_movi_i32(cpu_T[2], im)
179
180#define gen_op_addl_T1_im(im) tcg_gen_addi_i32(cpu_T[1], cpu_T[1], im)
181#define gen_op_addl_T0_T1() tcg_gen_add_i32(cpu_T[0], cpu_T[0], cpu_T[1])
182#define gen_op_subl_T0_T1() tcg_gen_sub_i32(cpu_T[0], cpu_T[0], cpu_T[1])
183#define gen_op_rsbl_T0_T1() tcg_gen_sub_i32(cpu_T[0], cpu_T[1], cpu_T[0])
184
185#define gen_op_andl_T0_T1() tcg_gen_and_i32(cpu_T[0], cpu_T[0], cpu_T[1])
186#define gen_op_xorl_T0_T1() tcg_gen_xor_i32(cpu_T[0], cpu_T[0], cpu_T[1])
187#define gen_op_orl_T0_T1() tcg_gen_or_i32(cpu_T[0], cpu_T[0], cpu_T[1])
188#define gen_op_notl_T0() tcg_gen_not_i32(cpu_T[0], cpu_T[0])
189#define gen_op_notl_T1() tcg_gen_not_i32(cpu_T[1], cpu_T[1])
190#define gen_op_logic_T0_cc() gen_logic_CC(cpu_T[0]);
191#define gen_op_logic_T1_cc() gen_logic_CC(cpu_T[1]);
192
193#define gen_op_shll_T0_im(im) tcg_gen_shli_i32(cpu_T[0], cpu_T[0], im)
194#define gen_op_shll_T1_im(im) tcg_gen_shli_i32(cpu_T[1], cpu_T[1], im)
195#define gen_op_shrl_T1_im(im) tcg_gen_shri_i32(cpu_T[1], cpu_T[1], im)
196#define gen_op_sarl_T1_im(im) tcg_gen_sari_i32(cpu_T[1], cpu_T[1], im)
197#define gen_op_rorl_T1_im(im) tcg_gen_rori_i32(cpu_T[1], cpu_T[1], im)
198
199/* Value extensions. */
200#define gen_uxtb(var) tcg_gen_andi_i32(var, var, 0xff)
201#define gen_uxth(var) tcg_gen_andi_i32(var, var, 0xffff)
202#define gen_sxtb(var) tcg_gen_ext8s_i32(var, var)
203#define gen_sxth(var) tcg_gen_ext16s_i32(var, var)
204
1497c961
PB
205#define gen_sxtb16(var) gen_helper_sxtb16(var, var)
206#define gen_uxtb16(var) gen_helper_uxtb16(var, var)
8f01245e
PB
207#define gen_op_rev_T0() tcg_gen_bswap_i32(cpu_T[0], cpu_T[0])
208
209#define gen_op_mul_T0_T1() tcg_gen_mul_i32(cpu_T[0], cpu_T[0], cpu_T[1])
b26eefb6 210
1497c961
PB
211#define gen_op_addl_T0_T1_setq() \
212 gen_helper_add_setq(cpu_T[0], cpu_T[0], cpu_T[1])
213#define gen_op_addl_T0_T1_saturate() \
214 gen_helper_add_saturate(cpu_T[0], cpu_T[0], cpu_T[1])
215#define gen_op_subl_T0_T1_saturate() \
216 gen_helper_sub_saturate(cpu_T[0], cpu_T[0], cpu_T[1])
217#define gen_op_addl_T0_T1_usaturate() \
218 gen_helper_add_usaturate(cpu_T[0], cpu_T[0], cpu_T[1])
219#define gen_op_subl_T0_T1_usaturate() \
220 gen_helper_sub_usaturate(cpu_T[0], cpu_T[0], cpu_T[1])
f51bbbfe 221
3670669c
PB
222/* Copy the most significant bit of T0 to all bits of T1. */
223#define gen_op_signbit_T1_T0() tcg_gen_sari_i32(cpu_T[1], cpu_T[0], 31)
224
225static void gen_smul_dual(TCGv a, TCGv b)
226{
227 TCGv tmp1 = new_tmp();
228 TCGv tmp2 = new_tmp();
3670669c
PB
229 tcg_gen_ext8s_i32(tmp1, a);
230 tcg_gen_ext8s_i32(tmp2, b);
231 tcg_gen_mul_i32(tmp1, tmp1, tmp2);
232 dead_tmp(tmp2);
233 tcg_gen_sari_i32(a, a, 16);
234 tcg_gen_sari_i32(b, b, 16);
235 tcg_gen_mul_i32(b, b, a);
236 tcg_gen_mov_i32(a, tmp1);
237 dead_tmp(tmp1);
238}
239
240/* Byteswap each halfword. */
241static void gen_rev16(TCGv var)
242{
243 TCGv tmp = new_tmp();
244 tcg_gen_shri_i32(tmp, var, 8);
245 tcg_gen_andi_i32(tmp, tmp, 0x00ff00ff);
246 tcg_gen_shli_i32(var, var, 8);
247 tcg_gen_andi_i32(var, var, 0xff00ff00);
248 tcg_gen_or_i32(var, var, tmp);
249 dead_tmp(tmp);
250}
251
252/* Byteswap low halfword and sign extend. */
253static void gen_revsh(TCGv var)
254{
255 TCGv tmp = new_tmp();
256 tcg_gen_shri_i32(tmp, var, 8);
257 tcg_gen_andi_i32(tmp, tmp, 0x00ff);
258 tcg_gen_shli_i32(var, var, 8);
259 tcg_gen_ext8s_i32(var, var);
260 tcg_gen_or_i32(var, var, tmp);
261 dead_tmp(tmp);
262}
263
264/* Unsigned bitfield extract. */
265static void gen_ubfx(TCGv var, int shift, uint32_t mask)
266{
267 if (shift)
268 tcg_gen_shri_i32(var, var, shift);
269 tcg_gen_andi_i32(var, var, mask);
270}
271
272/* Signed bitfield extract. */
273static void gen_sbfx(TCGv var, int shift, int width)
274{
275 uint32_t signbit;
276
277 if (shift)
278 tcg_gen_sari_i32(var, var, shift);
279 if (shift + width < 32) {
280 signbit = 1u << (width - 1);
281 tcg_gen_andi_i32(var, var, (1u << width) - 1);
282 tcg_gen_xori_i32(var, var, signbit);
283 tcg_gen_subi_i32(var, var, signbit);
284 }
285}
286
287/* Bitfield insertion. Insert val into base. Clobbers base and val. */
288static void gen_bfi(TCGv dest, TCGv base, TCGv val, int shift, uint32_t mask)
289{
290 tcg_gen_shli_i32(val, val, shift);
291 tcg_gen_andi_i32(val, val, mask);
292 tcg_gen_andi_i32(base, base, ~mask);
293 tcg_gen_or_i32(dest, base, val);
294}
295
296static void gen_op_roundqd_T0_T1(void)
297{
298 tcg_gen_shri_i32(cpu_T[0], cpu_T[0], 31);
299 tcg_gen_add_i32(cpu_T[0], cpu_T[0], cpu_T[1]);
300}
301
8f01245e
PB
302/* FIXME: Most targets have native widening multiplication.
303 It would be good to use that instead of a full wide multiply. */
304/* Unsigned 32x32->64 multiply. */
305static void gen_op_mull_T0_T1(void)
306{
307 TCGv tmp1 = tcg_temp_new(TCG_TYPE_I64);
308 TCGv tmp2 = tcg_temp_new(TCG_TYPE_I64);
309
310 tcg_gen_extu_i32_i64(tmp1, cpu_T[0]);
311 tcg_gen_extu_i32_i64(tmp2, cpu_T[1]);
312 tcg_gen_mul_i64(tmp1, tmp1, tmp2);
313 tcg_gen_trunc_i64_i32(cpu_T[0], tmp1);
314 tcg_gen_shri_i64(tmp1, tmp1, 32);
315 tcg_gen_trunc_i64_i32(cpu_T[1], tmp1);
316}
317
318/* Signed 32x32->64 multiply. */
319static void gen_op_imull_T0_T1(void)
320{
321 TCGv tmp1 = tcg_temp_new(TCG_TYPE_I64);
322 TCGv tmp2 = tcg_temp_new(TCG_TYPE_I64);
323
324 tcg_gen_ext_i32_i64(tmp1, cpu_T[0]);
325 tcg_gen_ext_i32_i64(tmp2, cpu_T[1]);
326 tcg_gen_mul_i64(tmp1, tmp1, tmp2);
327 tcg_gen_trunc_i64_i32(cpu_T[0], tmp1);
328 tcg_gen_shri_i64(tmp1, tmp1, 32);
329 tcg_gen_trunc_i64_i32(cpu_T[1], tmp1);
330}
331
332/* Swap low and high halfwords. */
333static void gen_swap_half(TCGv var)
334{
335 TCGv tmp = new_tmp();
336 tcg_gen_shri_i32(tmp, var, 16);
337 tcg_gen_shli_i32(var, var, 16);
338 tcg_gen_or_i32(var, var, tmp);
3670669c 339 dead_tmp(tmp);
8f01245e
PB
340}
341
b26eefb6
PB
342/* Dual 16-bit add. Result placed in t0 and t1 is marked as dead.
343 tmp = (t0 ^ t1) & 0x8000;
344 t0 &= ~0x8000;
345 t1 &= ~0x8000;
346 t0 = (t0 + t1) ^ tmp;
347 */
348
349static void gen_add16(TCGv t0, TCGv t1)
350{
351 TCGv tmp = new_tmp();
352 tcg_gen_xor_i32(tmp, t0, t1);
353 tcg_gen_andi_i32(tmp, tmp, 0x8000);
354 tcg_gen_andi_i32(t0, t0, ~0x8000);
355 tcg_gen_andi_i32(t1, t1, ~0x8000);
356 tcg_gen_add_i32(t0, t0, t1);
357 tcg_gen_xor_i32(t0, t0, tmp);
358 dead_tmp(tmp);
359 dead_tmp(t1);
360}
361
9a119ff6
PB
362#define gen_set_CF(var) tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, CF))
363
b26eefb6
PB
364/* Set CF to the top bit of var. */
365static void gen_set_CF_bit31(TCGv var)
366{
367 TCGv tmp = new_tmp();
368 tcg_gen_shri_i32(tmp, var, 31);
9a119ff6 369 gen_set_CF(var);
b26eefb6
PB
370 dead_tmp(tmp);
371}
372
373/* Set N and Z flags from var. */
374static inline void gen_logic_CC(TCGv var)
375{
376 tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, NZF));
377}
378
379/* T0 += T1 + CF. */
380static void gen_adc_T0_T1(void)
381{
382 TCGv tmp = new_tmp();
383 gen_op_addl_T0_T1();
384 tcg_gen_ld_i32(tmp, cpu_env, offsetof(CPUState, CF));
385 tcg_gen_add_i32(cpu_T[0], cpu_T[0], tmp);
386 dead_tmp(tmp);
387}
388
3670669c
PB
389/* dest = T0 - T1 + CF - 1. */
390static void gen_sub_carry(TCGv dest, TCGv t0, TCGv t1)
391{
392 TCGv tmp = new_tmp();
393 tcg_gen_sub_i32(dest, t0, t1);
394 tcg_gen_ld_i32(tmp, cpu_env, offsetof(CPUState, CF));
395 tcg_gen_add_i32(dest, dest, tmp);
396 tcg_gen_subi_i32(dest, dest, 1);
397 dead_tmp(tmp);
398}
399
400#define gen_sbc_T0_T1() gen_sub_carry(cpu_T[0], cpu_T[0], cpu_T[1])
401#define gen_rsc_T0_T1() gen_sub_carry(cpu_T[0], cpu_T[1], cpu_T[0])
402
b26eefb6
PB
403/* FIXME: Implement this natively. */
404static inline void tcg_gen_not_i32(TCGv t0, TCGv t1)
405{
406 tcg_gen_xori_i32(t0, t1, ~0);
407}
408
409/* T0 &= ~T1. Clobbers T1. */
410/* FIXME: Implement bic natively. */
411static inline void gen_op_bicl_T0_T1(void)
412{
413 gen_op_notl_T1();
414 gen_op_andl_T0_T1();
415}
416
417/* FIXME: Implement this natively. */
418static void tcg_gen_rori_i32(TCGv t0, TCGv t1, int i)
419{
420 TCGv tmp;
421
422 if (i == 0)
423 return;
424
425 tmp = new_tmp();
426 tcg_gen_shri_i32(tmp, t1, i);
427 tcg_gen_shli_i32(t1, t1, 32 - i);
428 tcg_gen_or_i32(t0, t1, tmp);
429 dead_tmp(tmp);
430}
431
9a119ff6 432static void shifter_out_im(TCGv var, int shift)
b26eefb6 433{
9a119ff6
PB
434 TCGv tmp = new_tmp();
435 if (shift == 0) {
436 tcg_gen_andi_i32(tmp, var, 1);
b26eefb6 437 } else {
9a119ff6
PB
438 tcg_gen_shri_i32(tmp, var, shift);
439 if (shift != 31);
440 tcg_gen_andi_i32(tmp, tmp, 1);
441 }
442 gen_set_CF(tmp);
443 dead_tmp(tmp);
444}
b26eefb6 445
9a119ff6
PB
446/* Shift by immediate. Includes special handling for shift == 0. */
447static inline void gen_arm_shift_im(TCGv var, int shiftop, int shift, int flags)
448{
449 switch (shiftop) {
450 case 0: /* LSL */
451 if (shift != 0) {
452 if (flags)
453 shifter_out_im(var, 32 - shift);
454 tcg_gen_shli_i32(var, var, shift);
455 }
456 break;
457 case 1: /* LSR */
458 if (shift == 0) {
459 if (flags) {
460 tcg_gen_shri_i32(var, var, 31);
461 gen_set_CF(var);
462 }
463 tcg_gen_movi_i32(var, 0);
464 } else {
465 if (flags)
466 shifter_out_im(var, shift - 1);
467 tcg_gen_shri_i32(var, var, shift);
468 }
469 break;
470 case 2: /* ASR */
471 if (shift == 0)
472 shift = 32;
473 if (flags)
474 shifter_out_im(var, shift - 1);
475 if (shift == 32)
476 shift = 31;
477 tcg_gen_sari_i32(var, var, shift);
478 break;
479 case 3: /* ROR/RRX */
480 if (shift != 0) {
481 if (flags)
482 shifter_out_im(var, shift - 1);
483 tcg_gen_rori_i32(var, var, shift); break;
484 } else {
485 TCGv tmp = new_tmp();
b26eefb6 486 tcg_gen_ld_i32(tmp, cpu_env, offsetof(CPUState, CF));
9a119ff6
PB
487 if (flags)
488 shifter_out_im(var, 0);
489 tcg_gen_shri_i32(var, var, 1);
b26eefb6
PB
490 tcg_gen_shli_i32(tmp, tmp, 31);
491 tcg_gen_or_i32(var, var, tmp);
492 dead_tmp(tmp);
b26eefb6
PB
493 }
494 }
495};
496
6ddbc6e4
PB
497#define PAS_OP(pfx) \
498 switch (op2) { \
499 case 0: gen_pas_helper(glue(pfx,add16)); break; \
500 case 1: gen_pas_helper(glue(pfx,addsubx)); break; \
501 case 2: gen_pas_helper(glue(pfx,subaddx)); break; \
502 case 3: gen_pas_helper(glue(pfx,sub16)); break; \
503 case 4: gen_pas_helper(glue(pfx,add8)); break; \
504 case 7: gen_pas_helper(glue(pfx,sub8)); break; \
505 }
506void gen_arm_parallel_addsub(int op1, int op2, TCGv a, TCGv b)
507{
508 TCGv tmp;
509
510 switch (op1) {
511#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp)
512 case 1:
513 tmp = tcg_temp_new(TCG_TYPE_PTR);
514 tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
515 PAS_OP(s)
516 break;
517 case 5:
518 tmp = tcg_temp_new(TCG_TYPE_PTR);
519 tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
520 PAS_OP(u)
521 break;
522#undef gen_pas_helper
523#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b)
524 case 2:
525 PAS_OP(q);
526 break;
527 case 3:
528 PAS_OP(sh);
529 break;
530 case 6:
531 PAS_OP(uq);
532 break;
533 case 7:
534 PAS_OP(uh);
535 break;
536#undef gen_pas_helper
537 }
538}
9ee6e8bb
PB
539#undef PAS_OP
540
6ddbc6e4
PB
541/* For unknown reasons Arm and Thumb-2 use arbitrarily different encodings. */
542#define PAS_OP(pfx) \
543 switch (op2) { \
544 case 0: gen_pas_helper(glue(pfx,add8)); break; \
545 case 1: gen_pas_helper(glue(pfx,add16)); break; \
546 case 2: gen_pas_helper(glue(pfx,addsubx)); break; \
547 case 4: gen_pas_helper(glue(pfx,sub8)); break; \
548 case 5: gen_pas_helper(glue(pfx,sub16)); break; \
549 case 6: gen_pas_helper(glue(pfx,subaddx)); break; \
550 }
551void gen_thumb2_parallel_addsub(int op1, int op2, TCGv a, TCGv b)
552{
553 TCGv tmp;
554
555 switch (op1) {
556#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp)
557 case 0:
558 tmp = tcg_temp_new(TCG_TYPE_PTR);
559 tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
560 PAS_OP(s)
561 break;
562 case 4:
563 tmp = tcg_temp_new(TCG_TYPE_PTR);
564 tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
565 PAS_OP(u)
566 break;
567#undef gen_pas_helper
568#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b)
569 case 1:
570 PAS_OP(q);
571 break;
572 case 2:
573 PAS_OP(sh);
574 break;
575 case 5:
576 PAS_OP(uq);
577 break;
578 case 6:
579 PAS_OP(uh);
580 break;
581#undef gen_pas_helper
582 }
583}
9ee6e8bb
PB
584#undef PAS_OP
585
e50e6a20 586static GenOpFunc1 *gen_test_cc[14] = {
2c0262af
FB
587 gen_op_test_eq,
588 gen_op_test_ne,
589 gen_op_test_cs,
590 gen_op_test_cc,
591 gen_op_test_mi,
592 gen_op_test_pl,
593 gen_op_test_vs,
594 gen_op_test_vc,
595 gen_op_test_hi,
596 gen_op_test_ls,
597 gen_op_test_ge,
598 gen_op_test_lt,
599 gen_op_test_gt,
600 gen_op_test_le,
601};
602
603const uint8_t table_logic_cc[16] = {
604 1, /* and */
605 1, /* xor */
606 0, /* sub */
607 0, /* rsb */
608 0, /* add */
609 0, /* adc */
610 0, /* sbc */
611 0, /* rsc */
612 1, /* andl */
613 1, /* xorl */
614 0, /* cmp */
615 0, /* cmn */
616 1, /* orr */
617 1, /* mov */
618 1, /* bic */
619 1, /* mvn */
620};
3b46e624 621
2c0262af
FB
622static GenOpFunc *gen_shift_T1_T0[4] = {
623 gen_op_shll_T1_T0,
624 gen_op_shrl_T1_T0,
625 gen_op_sarl_T1_T0,
626 gen_op_rorl_T1_T0,
627};
628
629static GenOpFunc *gen_shift_T1_T0_cc[4] = {
630 gen_op_shll_T1_T0_cc,
631 gen_op_shrl_T1_T0_cc,
632 gen_op_sarl_T1_T0_cc,
633 gen_op_rorl_T1_T0_cc,
634};
635
b26eefb6 636/* Set PC and thumb state from T0. Clobbers T0. */
99c475ab
FB
637static inline void gen_bx(DisasContext *s)
638{
b26eefb6 639 TCGv tmp;
99c475ab 640
b26eefb6
PB
641 s->is_jmp = DISAS_UPDATE;
642 tmp = new_tmp();
643 tcg_gen_andi_i32(tmp, cpu_T[0], 1);
644 tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, thumb));
645 dead_tmp(tmp);
646 tcg_gen_andi_i32(cpu_T[0], cpu_T[0], ~1);
647 tcg_gen_st_i32(cpu_T[0], cpu_env, offsetof(CPUState, regs[15]));
648}
b5ff1b31
FB
649
650#if defined(CONFIG_USER_ONLY)
651#define gen_ldst(name, s) gen_op_##name##_raw()
652#else
653#define gen_ldst(name, s) do { \
6658ffb8 654 s->is_mem = 1; \
b5ff1b31
FB
655 if (IS_USER(s)) \
656 gen_op_##name##_user(); \
657 else \
658 gen_op_##name##_kernel(); \
659 } while (0)
660#endif
661
2c0262af
FB
662static inline void gen_movl_T0_reg(DisasContext *s, int reg)
663{
b26eefb6 664 load_reg_var(s, cpu_T[0], reg);
2c0262af
FB
665}
666
667static inline void gen_movl_T1_reg(DisasContext *s, int reg)
668{
b26eefb6 669 load_reg_var(s, cpu_T[1], reg);
2c0262af
FB
670}
671
672static inline void gen_movl_T2_reg(DisasContext *s, int reg)
673{
b26eefb6
PB
674 load_reg_var(s, cpu_T[2], reg);
675}
676
677static inline void gen_set_pc_T0(void)
678{
679 tcg_gen_st_i32(cpu_T[0], cpu_env, offsetof(CPUState, regs[15]));
2c0262af
FB
680}
681
682static inline void gen_movl_reg_TN(DisasContext *s, int reg, int t)
683{
b26eefb6
PB
684 TCGv tmp;
685 if (reg == 15) {
686 tmp = new_tmp();
687 tcg_gen_andi_i32(tmp, cpu_T[t], ~1);
688 } else {
689 tmp = cpu_T[t];
690 }
691 tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, regs[reg]));
2c0262af 692 if (reg == 15) {
b26eefb6 693 dead_tmp(tmp);
2c0262af
FB
694 s->is_jmp = DISAS_JUMP;
695 }
696}
697
698static inline void gen_movl_reg_T0(DisasContext *s, int reg)
699{
700 gen_movl_reg_TN(s, reg, 0);
701}
702
703static inline void gen_movl_reg_T1(DisasContext *s, int reg)
704{
705 gen_movl_reg_TN(s, reg, 1);
706}
707
b5ff1b31
FB
708/* Force a TB lookup after an instruction that changes the CPU state. */
709static inline void gen_lookup_tb(DisasContext *s)
710{
711 gen_op_movl_T0_im(s->pc);
712 gen_movl_reg_T0(s, 15);
713 s->is_jmp = DISAS_UPDATE;
714}
715
2c0262af
FB
716static inline void gen_add_data_offset(DisasContext *s, unsigned int insn)
717{
1e8d4eec 718 int val, rm, shift, shiftop;
b26eefb6 719 TCGv offset;
2c0262af
FB
720
721 if (!(insn & (1 << 25))) {
722 /* immediate */
723 val = insn & 0xfff;
724 if (!(insn & (1 << 23)))
725 val = -val;
537730b9
FB
726 if (val != 0)
727 gen_op_addl_T1_im(val);
2c0262af
FB
728 } else {
729 /* shift/register */
730 rm = (insn) & 0xf;
731 shift = (insn >> 7) & 0x1f;
1e8d4eec 732 shiftop = (insn >> 5) & 3;
b26eefb6 733 offset = load_reg(s, rm);
9a119ff6 734 gen_arm_shift_im(offset, shiftop, shift, 0);
2c0262af 735 if (!(insn & (1 << 23)))
b26eefb6 736 tcg_gen_sub_i32(cpu_T[1], cpu_T[1], offset);
2c0262af 737 else
b26eefb6
PB
738 tcg_gen_add_i32(cpu_T[1], cpu_T[1], offset);
739 dead_tmp(offset);
2c0262af
FB
740 }
741}
742
191f9a93
PB
743static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn,
744 int extra)
2c0262af
FB
745{
746 int val, rm;
b26eefb6 747 TCGv offset;
3b46e624 748
2c0262af
FB
749 if (insn & (1 << 22)) {
750 /* immediate */
751 val = (insn & 0xf) | ((insn >> 4) & 0xf0);
752 if (!(insn & (1 << 23)))
753 val = -val;
18acad92 754 val += extra;
537730b9
FB
755 if (val != 0)
756 gen_op_addl_T1_im(val);
2c0262af
FB
757 } else {
758 /* register */
191f9a93
PB
759 if (extra)
760 gen_op_addl_T1_im(extra);
2c0262af 761 rm = (insn) & 0xf;
b26eefb6 762 offset = load_reg(s, rm);
2c0262af 763 if (!(insn & (1 << 23)))
b26eefb6 764 tcg_gen_sub_i32(cpu_T[1], cpu_T[1], offset);
2c0262af 765 else
b26eefb6
PB
766 tcg_gen_add_i32(cpu_T[1], cpu_T[1], offset);
767 dead_tmp(offset);
2c0262af
FB
768 }
769}
770
b7bcbe95
FB
771#define VFP_OP(name) \
772static inline void gen_vfp_##name(int dp) \
773{ \
774 if (dp) \
775 gen_op_vfp_##name##d(); \
776 else \
777 gen_op_vfp_##name##s(); \
778}
779
9ee6e8bb
PB
780#define VFP_OP1(name) \
781static inline void gen_vfp_##name(int dp, int arg) \
782{ \
783 if (dp) \
784 gen_op_vfp_##name##d(arg); \
785 else \
786 gen_op_vfp_##name##s(arg); \
787}
788
b7bcbe95
FB
789VFP_OP(add)
790VFP_OP(sub)
791VFP_OP(mul)
792VFP_OP(div)
793VFP_OP(neg)
794VFP_OP(abs)
795VFP_OP(sqrt)
796VFP_OP(cmp)
797VFP_OP(cmpe)
798VFP_OP(F1_ld0)
799VFP_OP(uito)
800VFP_OP(sito)
801VFP_OP(toui)
802VFP_OP(touiz)
803VFP_OP(tosi)
804VFP_OP(tosiz)
9ee6e8bb
PB
805VFP_OP1(tosh)
806VFP_OP1(tosl)
807VFP_OP1(touh)
808VFP_OP1(toul)
809VFP_OP1(shto)
810VFP_OP1(slto)
811VFP_OP1(uhto)
812VFP_OP1(ulto)
b7bcbe95
FB
813
814#undef VFP_OP
815
9ee6e8bb
PB
816static inline void gen_vfp_fconst(int dp, uint32_t val)
817{
818 if (dp)
819 gen_op_vfp_fconstd(val);
820 else
821 gen_op_vfp_fconsts(val);
822}
823
b5ff1b31
FB
824static inline void gen_vfp_ld(DisasContext *s, int dp)
825{
826 if (dp)
827 gen_ldst(vfp_ldd, s);
828 else
829 gen_ldst(vfp_lds, s);
830}
831
832static inline void gen_vfp_st(DisasContext *s, int dp)
833{
834 if (dp)
835 gen_ldst(vfp_std, s);
836 else
837 gen_ldst(vfp_sts, s);
838}
839
8e96005d
FB
840static inline long
841vfp_reg_offset (int dp, int reg)
842{
843 if (dp)
844 return offsetof(CPUARMState, vfp.regs[reg]);
845 else if (reg & 1) {
846 return offsetof(CPUARMState, vfp.regs[reg >> 1])
847 + offsetof(CPU_DoubleU, l.upper);
848 } else {
849 return offsetof(CPUARMState, vfp.regs[reg >> 1])
850 + offsetof(CPU_DoubleU, l.lower);
851 }
852}
9ee6e8bb
PB
853
854/* Return the offset of a 32-bit piece of a NEON register.
855 zero is the least significant end of the register. */
856static inline long
857neon_reg_offset (int reg, int n)
858{
859 int sreg;
860 sreg = reg * 2 + n;
861 return vfp_reg_offset(0, sreg);
862}
863
864#define NEON_GET_REG(T, reg, n) gen_op_neon_getreg_##T(neon_reg_offset(reg, n))
865#define NEON_SET_REG(T, reg, n) gen_op_neon_setreg_##T(neon_reg_offset(reg, n))
866
b7bcbe95
FB
867static inline void gen_mov_F0_vreg(int dp, int reg)
868{
869 if (dp)
8e96005d 870 gen_op_vfp_getreg_F0d(vfp_reg_offset(dp, reg));
b7bcbe95 871 else
8e96005d 872 gen_op_vfp_getreg_F0s(vfp_reg_offset(dp, reg));
b7bcbe95
FB
873}
874
875static inline void gen_mov_F1_vreg(int dp, int reg)
876{
877 if (dp)
8e96005d 878 gen_op_vfp_getreg_F1d(vfp_reg_offset(dp, reg));
b7bcbe95 879 else
8e96005d 880 gen_op_vfp_getreg_F1s(vfp_reg_offset(dp, reg));
b7bcbe95
FB
881}
882
883static inline void gen_mov_vreg_F0(int dp, int reg)
884{
885 if (dp)
8e96005d 886 gen_op_vfp_setreg_F0d(vfp_reg_offset(dp, reg));
b7bcbe95 887 else
8e96005d 888 gen_op_vfp_setreg_F0s(vfp_reg_offset(dp, reg));
b7bcbe95
FB
889}
890
18c9b560
AZ
891#define ARM_CP_RW_BIT (1 << 20)
892
893static inline int gen_iwmmxt_address(DisasContext *s, uint32_t insn)
894{
895 int rd;
896 uint32_t offset;
897
898 rd = (insn >> 16) & 0xf;
899 gen_movl_T1_reg(s, rd);
900
901 offset = (insn & 0xff) << ((insn >> 7) & 2);
902 if (insn & (1 << 24)) {
903 /* Pre indexed */
904 if (insn & (1 << 23))
905 gen_op_addl_T1_im(offset);
906 else
907 gen_op_addl_T1_im(-offset);
908
909 if (insn & (1 << 21))
910 gen_movl_reg_T1(s, rd);
911 } else if (insn & (1 << 21)) {
912 /* Post indexed */
913 if (insn & (1 << 23))
914 gen_op_movl_T0_im(offset);
915 else
916 gen_op_movl_T0_im(- offset);
917 gen_op_addl_T0_T1();
918 gen_movl_reg_T0(s, rd);
919 } else if (!(insn & (1 << 23)))
920 return 1;
921 return 0;
922}
923
924static inline int gen_iwmmxt_shift(uint32_t insn, uint32_t mask)
925{
926 int rd = (insn >> 0) & 0xf;
927
928 if (insn & (1 << 8))
929 if (rd < ARM_IWMMXT_wCGR0 || rd > ARM_IWMMXT_wCGR3)
930 return 1;
931 else
932 gen_op_iwmmxt_movl_T0_wCx(rd);
933 else
934 gen_op_iwmmxt_movl_T0_T1_wRn(rd);
935
936 gen_op_movl_T1_im(mask);
937 gen_op_andl_T0_T1();
938 return 0;
939}
940
941/* Disassemble an iwMMXt instruction. Returns nonzero if an error occured
942 (ie. an undefined instruction). */
943static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
944{
945 int rd, wrd;
946 int rdhi, rdlo, rd0, rd1, i;
947
948 if ((insn & 0x0e000e00) == 0x0c000000) {
949 if ((insn & 0x0fe00ff0) == 0x0c400000) {
950 wrd = insn & 0xf;
951 rdlo = (insn >> 12) & 0xf;
952 rdhi = (insn >> 16) & 0xf;
953 if (insn & ARM_CP_RW_BIT) { /* TMRRC */
954 gen_op_iwmmxt_movl_T0_T1_wRn(wrd);
955 gen_movl_reg_T0(s, rdlo);
956 gen_movl_reg_T1(s, rdhi);
957 } else { /* TMCRR */
958 gen_movl_T0_reg(s, rdlo);
959 gen_movl_T1_reg(s, rdhi);
960 gen_op_iwmmxt_movl_wRn_T0_T1(wrd);
961 gen_op_iwmmxt_set_mup();
962 }
963 return 0;
964 }
965
966 wrd = (insn >> 12) & 0xf;
967 if (gen_iwmmxt_address(s, insn))
968 return 1;
969 if (insn & ARM_CP_RW_BIT) {
970 if ((insn >> 28) == 0xf) { /* WLDRW wCx */
971 gen_ldst(ldl, s);
972 gen_op_iwmmxt_movl_wCx_T0(wrd);
973 } else {
974 if (insn & (1 << 8))
975 if (insn & (1 << 22)) /* WLDRD */
976 gen_ldst(iwmmxt_ldq, s);
977 else /* WLDRW wRd */
978 gen_ldst(iwmmxt_ldl, s);
979 else
980 if (insn & (1 << 22)) /* WLDRH */
981 gen_ldst(iwmmxt_ldw, s);
982 else /* WLDRB */
983 gen_ldst(iwmmxt_ldb, s);
984 gen_op_iwmmxt_movq_wRn_M0(wrd);
985 }
986 } else {
987 if ((insn >> 28) == 0xf) { /* WSTRW wCx */
988 gen_op_iwmmxt_movl_T0_wCx(wrd);
989 gen_ldst(stl, s);
990 } else {
991 gen_op_iwmmxt_movq_M0_wRn(wrd);
992 if (insn & (1 << 8))
993 if (insn & (1 << 22)) /* WSTRD */
994 gen_ldst(iwmmxt_stq, s);
995 else /* WSTRW wRd */
996 gen_ldst(iwmmxt_stl, s);
997 else
998 if (insn & (1 << 22)) /* WSTRH */
999 gen_ldst(iwmmxt_ldw, s);
1000 else /* WSTRB */
1001 gen_ldst(iwmmxt_stb, s);
1002 }
1003 }
1004 return 0;
1005 }
1006
1007 if ((insn & 0x0f000000) != 0x0e000000)
1008 return 1;
1009
1010 switch (((insn >> 12) & 0xf00) | ((insn >> 4) & 0xff)) {
1011 case 0x000: /* WOR */
1012 wrd = (insn >> 12) & 0xf;
1013 rd0 = (insn >> 0) & 0xf;
1014 rd1 = (insn >> 16) & 0xf;
1015 gen_op_iwmmxt_movq_M0_wRn(rd0);
1016 gen_op_iwmmxt_orq_M0_wRn(rd1);
1017 gen_op_iwmmxt_setpsr_nz();
1018 gen_op_iwmmxt_movq_wRn_M0(wrd);
1019 gen_op_iwmmxt_set_mup();
1020 gen_op_iwmmxt_set_cup();
1021 break;
1022 case 0x011: /* TMCR */
1023 if (insn & 0xf)
1024 return 1;
1025 rd = (insn >> 12) & 0xf;
1026 wrd = (insn >> 16) & 0xf;
1027 switch (wrd) {
1028 case ARM_IWMMXT_wCID:
1029 case ARM_IWMMXT_wCASF:
1030 break;
1031 case ARM_IWMMXT_wCon:
1032 gen_op_iwmmxt_set_cup();
1033 /* Fall through. */
1034 case ARM_IWMMXT_wCSSF:
1035 gen_op_iwmmxt_movl_T0_wCx(wrd);
1036 gen_movl_T1_reg(s, rd);
1037 gen_op_bicl_T0_T1();
1038 gen_op_iwmmxt_movl_wCx_T0(wrd);
1039 break;
1040 case ARM_IWMMXT_wCGR0:
1041 case ARM_IWMMXT_wCGR1:
1042 case ARM_IWMMXT_wCGR2:
1043 case ARM_IWMMXT_wCGR3:
1044 gen_op_iwmmxt_set_cup();
1045 gen_movl_reg_T0(s, rd);
1046 gen_op_iwmmxt_movl_wCx_T0(wrd);
1047 break;
1048 default:
1049 return 1;
1050 }
1051 break;
1052 case 0x100: /* WXOR */
1053 wrd = (insn >> 12) & 0xf;
1054 rd0 = (insn >> 0) & 0xf;
1055 rd1 = (insn >> 16) & 0xf;
1056 gen_op_iwmmxt_movq_M0_wRn(rd0);
1057 gen_op_iwmmxt_xorq_M0_wRn(rd1);
1058 gen_op_iwmmxt_setpsr_nz();
1059 gen_op_iwmmxt_movq_wRn_M0(wrd);
1060 gen_op_iwmmxt_set_mup();
1061 gen_op_iwmmxt_set_cup();
1062 break;
1063 case 0x111: /* TMRC */
1064 if (insn & 0xf)
1065 return 1;
1066 rd = (insn >> 12) & 0xf;
1067 wrd = (insn >> 16) & 0xf;
1068 gen_op_iwmmxt_movl_T0_wCx(wrd);
1069 gen_movl_reg_T0(s, rd);
1070 break;
1071 case 0x300: /* WANDN */
1072 wrd = (insn >> 12) & 0xf;
1073 rd0 = (insn >> 0) & 0xf;
1074 rd1 = (insn >> 16) & 0xf;
1075 gen_op_iwmmxt_movq_M0_wRn(rd0);
1076 gen_op_iwmmxt_negq_M0();
1077 gen_op_iwmmxt_andq_M0_wRn(rd1);
1078 gen_op_iwmmxt_setpsr_nz();
1079 gen_op_iwmmxt_movq_wRn_M0(wrd);
1080 gen_op_iwmmxt_set_mup();
1081 gen_op_iwmmxt_set_cup();
1082 break;
1083 case 0x200: /* WAND */
1084 wrd = (insn >> 12) & 0xf;
1085 rd0 = (insn >> 0) & 0xf;
1086 rd1 = (insn >> 16) & 0xf;
1087 gen_op_iwmmxt_movq_M0_wRn(rd0);
1088 gen_op_iwmmxt_andq_M0_wRn(rd1);
1089 gen_op_iwmmxt_setpsr_nz();
1090 gen_op_iwmmxt_movq_wRn_M0(wrd);
1091 gen_op_iwmmxt_set_mup();
1092 gen_op_iwmmxt_set_cup();
1093 break;
1094 case 0x810: case 0xa10: /* WMADD */
1095 wrd = (insn >> 12) & 0xf;
1096 rd0 = (insn >> 0) & 0xf;
1097 rd1 = (insn >> 16) & 0xf;
1098 gen_op_iwmmxt_movq_M0_wRn(rd0);
1099 if (insn & (1 << 21))
1100 gen_op_iwmmxt_maddsq_M0_wRn(rd1);
1101 else
1102 gen_op_iwmmxt_madduq_M0_wRn(rd1);
1103 gen_op_iwmmxt_movq_wRn_M0(wrd);
1104 gen_op_iwmmxt_set_mup();
1105 break;
1106 case 0x10e: case 0x50e: case 0x90e: case 0xd0e: /* WUNPCKIL */
1107 wrd = (insn >> 12) & 0xf;
1108 rd0 = (insn >> 16) & 0xf;
1109 rd1 = (insn >> 0) & 0xf;
1110 gen_op_iwmmxt_movq_M0_wRn(rd0);
1111 switch ((insn >> 22) & 3) {
1112 case 0:
1113 gen_op_iwmmxt_unpacklb_M0_wRn(rd1);
1114 break;
1115 case 1:
1116 gen_op_iwmmxt_unpacklw_M0_wRn(rd1);
1117 break;
1118 case 2:
1119 gen_op_iwmmxt_unpackll_M0_wRn(rd1);
1120 break;
1121 case 3:
1122 return 1;
1123 }
1124 gen_op_iwmmxt_movq_wRn_M0(wrd);
1125 gen_op_iwmmxt_set_mup();
1126 gen_op_iwmmxt_set_cup();
1127 break;
1128 case 0x10c: case 0x50c: case 0x90c: case 0xd0c: /* WUNPCKIH */
1129 wrd = (insn >> 12) & 0xf;
1130 rd0 = (insn >> 16) & 0xf;
1131 rd1 = (insn >> 0) & 0xf;
1132 gen_op_iwmmxt_movq_M0_wRn(rd0);
1133 switch ((insn >> 22) & 3) {
1134 case 0:
1135 gen_op_iwmmxt_unpackhb_M0_wRn(rd1);
1136 break;
1137 case 1:
1138 gen_op_iwmmxt_unpackhw_M0_wRn(rd1);
1139 break;
1140 case 2:
1141 gen_op_iwmmxt_unpackhl_M0_wRn(rd1);
1142 break;
1143 case 3:
1144 return 1;
1145 }
1146 gen_op_iwmmxt_movq_wRn_M0(wrd);
1147 gen_op_iwmmxt_set_mup();
1148 gen_op_iwmmxt_set_cup();
1149 break;
1150 case 0x012: case 0x112: case 0x412: case 0x512: /* WSAD */
1151 wrd = (insn >> 12) & 0xf;
1152 rd0 = (insn >> 16) & 0xf;
1153 rd1 = (insn >> 0) & 0xf;
1154 gen_op_iwmmxt_movq_M0_wRn(rd0);
1155 if (insn & (1 << 22))
1156 gen_op_iwmmxt_sadw_M0_wRn(rd1);
1157 else
1158 gen_op_iwmmxt_sadb_M0_wRn(rd1);
1159 if (!(insn & (1 << 20)))
1160 gen_op_iwmmxt_addl_M0_wRn(wrd);
1161 gen_op_iwmmxt_movq_wRn_M0(wrd);
1162 gen_op_iwmmxt_set_mup();
1163 break;
1164 case 0x010: case 0x110: case 0x210: case 0x310: /* WMUL */
1165 wrd = (insn >> 12) & 0xf;
1166 rd0 = (insn >> 16) & 0xf;
1167 rd1 = (insn >> 0) & 0xf;
1168 gen_op_iwmmxt_movq_M0_wRn(rd0);
1169 if (insn & (1 << 21))
1170 gen_op_iwmmxt_mulsw_M0_wRn(rd1, (insn & (1 << 20)) ? 16 : 0);
1171 else
1172 gen_op_iwmmxt_muluw_M0_wRn(rd1, (insn & (1 << 20)) ? 16 : 0);
1173 gen_op_iwmmxt_movq_wRn_M0(wrd);
1174 gen_op_iwmmxt_set_mup();
1175 break;
1176 case 0x410: case 0x510: case 0x610: case 0x710: /* WMAC */
1177 wrd = (insn >> 12) & 0xf;
1178 rd0 = (insn >> 16) & 0xf;
1179 rd1 = (insn >> 0) & 0xf;
1180 gen_op_iwmmxt_movq_M0_wRn(rd0);
1181 if (insn & (1 << 21))
1182 gen_op_iwmmxt_macsw_M0_wRn(rd1);
1183 else
1184 gen_op_iwmmxt_macuw_M0_wRn(rd1);
1185 if (!(insn & (1 << 20))) {
1186 if (insn & (1 << 21))
1187 gen_op_iwmmxt_addsq_M0_wRn(wrd);
1188 else
1189 gen_op_iwmmxt_adduq_M0_wRn(wrd);
1190 }
1191 gen_op_iwmmxt_movq_wRn_M0(wrd);
1192 gen_op_iwmmxt_set_mup();
1193 break;
1194 case 0x006: case 0x406: case 0x806: case 0xc06: /* WCMPEQ */
1195 wrd = (insn >> 12) & 0xf;
1196 rd0 = (insn >> 16) & 0xf;
1197 rd1 = (insn >> 0) & 0xf;
1198 gen_op_iwmmxt_movq_M0_wRn(rd0);
1199 switch ((insn >> 22) & 3) {
1200 case 0:
1201 gen_op_iwmmxt_cmpeqb_M0_wRn(rd1);
1202 break;
1203 case 1:
1204 gen_op_iwmmxt_cmpeqw_M0_wRn(rd1);
1205 break;
1206 case 2:
1207 gen_op_iwmmxt_cmpeql_M0_wRn(rd1);
1208 break;
1209 case 3:
1210 return 1;
1211 }
1212 gen_op_iwmmxt_movq_wRn_M0(wrd);
1213 gen_op_iwmmxt_set_mup();
1214 gen_op_iwmmxt_set_cup();
1215 break;
1216 case 0x800: case 0x900: case 0xc00: case 0xd00: /* WAVG2 */
1217 wrd = (insn >> 12) & 0xf;
1218 rd0 = (insn >> 16) & 0xf;
1219 rd1 = (insn >> 0) & 0xf;
1220 gen_op_iwmmxt_movq_M0_wRn(rd0);
1221 if (insn & (1 << 22))
1222 gen_op_iwmmxt_avgw_M0_wRn(rd1, (insn >> 20) & 1);
1223 else
1224 gen_op_iwmmxt_avgb_M0_wRn(rd1, (insn >> 20) & 1);
1225 gen_op_iwmmxt_movq_wRn_M0(wrd);
1226 gen_op_iwmmxt_set_mup();
1227 gen_op_iwmmxt_set_cup();
1228 break;
1229 case 0x802: case 0x902: case 0xa02: case 0xb02: /* WALIGNR */
1230 wrd = (insn >> 12) & 0xf;
1231 rd0 = (insn >> 16) & 0xf;
1232 rd1 = (insn >> 0) & 0xf;
1233 gen_op_iwmmxt_movq_M0_wRn(rd0);
1234 gen_op_iwmmxt_movl_T0_wCx(ARM_IWMMXT_wCGR0 + ((insn >> 20) & 3));
1235 gen_op_movl_T1_im(7);
1236 gen_op_andl_T0_T1();
1237 gen_op_iwmmxt_align_M0_T0_wRn(rd1);
1238 gen_op_iwmmxt_movq_wRn_M0(wrd);
1239 gen_op_iwmmxt_set_mup();
1240 break;
1241 case 0x601: case 0x605: case 0x609: case 0x60d: /* TINSR */
1242 rd = (insn >> 12) & 0xf;
1243 wrd = (insn >> 16) & 0xf;
1244 gen_movl_T0_reg(s, rd);
1245 gen_op_iwmmxt_movq_M0_wRn(wrd);
1246 switch ((insn >> 6) & 3) {
1247 case 0:
1248 gen_op_movl_T1_im(0xff);
1249 gen_op_iwmmxt_insr_M0_T0_T1((insn & 7) << 3);
1250 break;
1251 case 1:
1252 gen_op_movl_T1_im(0xffff);
1253 gen_op_iwmmxt_insr_M0_T0_T1((insn & 3) << 4);
1254 break;
1255 case 2:
1256 gen_op_movl_T1_im(0xffffffff);
1257 gen_op_iwmmxt_insr_M0_T0_T1((insn & 1) << 5);
1258 break;
1259 case 3:
1260 return 1;
1261 }
1262 gen_op_iwmmxt_movq_wRn_M0(wrd);
1263 gen_op_iwmmxt_set_mup();
1264 break;
1265 case 0x107: case 0x507: case 0x907: case 0xd07: /* TEXTRM */
1266 rd = (insn >> 12) & 0xf;
1267 wrd = (insn >> 16) & 0xf;
1268 if (rd == 15)
1269 return 1;
1270 gen_op_iwmmxt_movq_M0_wRn(wrd);
1271 switch ((insn >> 22) & 3) {
1272 case 0:
1273 if (insn & 8)
1274 gen_op_iwmmxt_extrsb_T0_M0((insn & 7) << 3);
1275 else {
1276 gen_op_movl_T1_im(0xff);
1277 gen_op_iwmmxt_extru_T0_M0_T1((insn & 7) << 3);
1278 }
1279 break;
1280 case 1:
1281 if (insn & 8)
1282 gen_op_iwmmxt_extrsw_T0_M0((insn & 3) << 4);
1283 else {
1284 gen_op_movl_T1_im(0xffff);
1285 gen_op_iwmmxt_extru_T0_M0_T1((insn & 3) << 4);
1286 }
1287 break;
1288 case 2:
1289 gen_op_movl_T1_im(0xffffffff);
1290 gen_op_iwmmxt_extru_T0_M0_T1((insn & 1) << 5);
1291 break;
1292 case 3:
1293 return 1;
1294 }
b26eefb6 1295 gen_movl_reg_T0(s, rd);
18c9b560
AZ
1296 break;
1297 case 0x117: case 0x517: case 0x917: case 0xd17: /* TEXTRC */
1298 if ((insn & 0x000ff008) != 0x0003f000)
1299 return 1;
1300 gen_op_iwmmxt_movl_T1_wCx(ARM_IWMMXT_wCASF);
1301 switch ((insn >> 22) & 3) {
1302 case 0:
1303 gen_op_shrl_T1_im(((insn & 7) << 2) + 0);
1304 break;
1305 case 1:
1306 gen_op_shrl_T1_im(((insn & 3) << 3) + 4);
1307 break;
1308 case 2:
1309 gen_op_shrl_T1_im(((insn & 1) << 4) + 12);
1310 break;
1311 case 3:
1312 return 1;
1313 }
1314 gen_op_shll_T1_im(28);
1315 gen_op_movl_T0_T1();
1316 gen_op_movl_cpsr_T0(0xf0000000);
1317 break;
1318 case 0x401: case 0x405: case 0x409: case 0x40d: /* TBCST */
1319 rd = (insn >> 12) & 0xf;
1320 wrd = (insn >> 16) & 0xf;
1321 gen_movl_T0_reg(s, rd);
1322 switch ((insn >> 6) & 3) {
1323 case 0:
1324 gen_op_iwmmxt_bcstb_M0_T0();
1325 break;
1326 case 1:
1327 gen_op_iwmmxt_bcstw_M0_T0();
1328 break;
1329 case 2:
1330 gen_op_iwmmxt_bcstl_M0_T0();
1331 break;
1332 case 3:
1333 return 1;
1334 }
1335 gen_op_iwmmxt_movq_wRn_M0(wrd);
1336 gen_op_iwmmxt_set_mup();
1337 break;
1338 case 0x113: case 0x513: case 0x913: case 0xd13: /* TANDC */
1339 if ((insn & 0x000ff00f) != 0x0003f000)
1340 return 1;
1341 gen_op_iwmmxt_movl_T1_wCx(ARM_IWMMXT_wCASF);
1342 switch ((insn >> 22) & 3) {
1343 case 0:
1344 for (i = 0; i < 7; i ++) {
1345 gen_op_shll_T1_im(4);
1346 gen_op_andl_T0_T1();
1347 }
1348 break;
1349 case 1:
1350 for (i = 0; i < 3; i ++) {
1351 gen_op_shll_T1_im(8);
1352 gen_op_andl_T0_T1();
1353 }
1354 break;
1355 case 2:
1356 gen_op_shll_T1_im(16);
1357 gen_op_andl_T0_T1();
1358 break;
1359 case 3:
1360 return 1;
1361 }
1362 gen_op_movl_cpsr_T0(0xf0000000);
1363 break;
1364 case 0x01c: case 0x41c: case 0x81c: case 0xc1c: /* WACC */
1365 wrd = (insn >> 12) & 0xf;
1366 rd0 = (insn >> 16) & 0xf;
1367 gen_op_iwmmxt_movq_M0_wRn(rd0);
1368 switch ((insn >> 22) & 3) {
1369 case 0:
1370 gen_op_iwmmxt_addcb_M0();
1371 break;
1372 case 1:
1373 gen_op_iwmmxt_addcw_M0();
1374 break;
1375 case 2:
1376 gen_op_iwmmxt_addcl_M0();
1377 break;
1378 case 3:
1379 return 1;
1380 }
1381 gen_op_iwmmxt_movq_wRn_M0(wrd);
1382 gen_op_iwmmxt_set_mup();
1383 break;
1384 case 0x115: case 0x515: case 0x915: case 0xd15: /* TORC */
1385 if ((insn & 0x000ff00f) != 0x0003f000)
1386 return 1;
1387 gen_op_iwmmxt_movl_T1_wCx(ARM_IWMMXT_wCASF);
1388 switch ((insn >> 22) & 3) {
1389 case 0:
1390 for (i = 0; i < 7; i ++) {
1391 gen_op_shll_T1_im(4);
1392 gen_op_orl_T0_T1();
1393 }
1394 break;
1395 case 1:
1396 for (i = 0; i < 3; i ++) {
1397 gen_op_shll_T1_im(8);
1398 gen_op_orl_T0_T1();
1399 }
1400 break;
1401 case 2:
1402 gen_op_shll_T1_im(16);
1403 gen_op_orl_T0_T1();
1404 break;
1405 case 3:
1406 return 1;
1407 }
1408 gen_op_movl_T1_im(0xf0000000);
1409 gen_op_andl_T0_T1();
1410 gen_op_movl_cpsr_T0(0xf0000000);
1411 break;
1412 case 0x103: case 0x503: case 0x903: case 0xd03: /* TMOVMSK */
1413 rd = (insn >> 12) & 0xf;
1414 rd0 = (insn >> 16) & 0xf;
1415 if ((insn & 0xf) != 0)
1416 return 1;
1417 gen_op_iwmmxt_movq_M0_wRn(rd0);
1418 switch ((insn >> 22) & 3) {
1419 case 0:
1420 gen_op_iwmmxt_msbb_T0_M0();
1421 break;
1422 case 1:
1423 gen_op_iwmmxt_msbw_T0_M0();
1424 break;
1425 case 2:
1426 gen_op_iwmmxt_msbl_T0_M0();
1427 break;
1428 case 3:
1429 return 1;
1430 }
1431 gen_movl_reg_T0(s, rd);
1432 break;
1433 case 0x106: case 0x306: case 0x506: case 0x706: /* WCMPGT */
1434 case 0x906: case 0xb06: case 0xd06: case 0xf06:
1435 wrd = (insn >> 12) & 0xf;
1436 rd0 = (insn >> 16) & 0xf;
1437 rd1 = (insn >> 0) & 0xf;
1438 gen_op_iwmmxt_movq_M0_wRn(rd0);
1439 switch ((insn >> 22) & 3) {
1440 case 0:
1441 if (insn & (1 << 21))
1442 gen_op_iwmmxt_cmpgtsb_M0_wRn(rd1);
1443 else
1444 gen_op_iwmmxt_cmpgtub_M0_wRn(rd1);
1445 break;
1446 case 1:
1447 if (insn & (1 << 21))
1448 gen_op_iwmmxt_cmpgtsw_M0_wRn(rd1);
1449 else
1450 gen_op_iwmmxt_cmpgtuw_M0_wRn(rd1);
1451 break;
1452 case 2:
1453 if (insn & (1 << 21))
1454 gen_op_iwmmxt_cmpgtsl_M0_wRn(rd1);
1455 else
1456 gen_op_iwmmxt_cmpgtul_M0_wRn(rd1);
1457 break;
1458 case 3:
1459 return 1;
1460 }
1461 gen_op_iwmmxt_movq_wRn_M0(wrd);
1462 gen_op_iwmmxt_set_mup();
1463 gen_op_iwmmxt_set_cup();
1464 break;
1465 case 0x00e: case 0x20e: case 0x40e: case 0x60e: /* WUNPCKEL */
1466 case 0x80e: case 0xa0e: case 0xc0e: case 0xe0e:
1467 wrd = (insn >> 12) & 0xf;
1468 rd0 = (insn >> 16) & 0xf;
1469 gen_op_iwmmxt_movq_M0_wRn(rd0);
1470 switch ((insn >> 22) & 3) {
1471 case 0:
1472 if (insn & (1 << 21))
1473 gen_op_iwmmxt_unpacklsb_M0();
1474 else
1475 gen_op_iwmmxt_unpacklub_M0();
1476 break;
1477 case 1:
1478 if (insn & (1 << 21))
1479 gen_op_iwmmxt_unpacklsw_M0();
1480 else
1481 gen_op_iwmmxt_unpackluw_M0();
1482 break;
1483 case 2:
1484 if (insn & (1 << 21))
1485 gen_op_iwmmxt_unpacklsl_M0();
1486 else
1487 gen_op_iwmmxt_unpacklul_M0();
1488 break;
1489 case 3:
1490 return 1;
1491 }
1492 gen_op_iwmmxt_movq_wRn_M0(wrd);
1493 gen_op_iwmmxt_set_mup();
1494 gen_op_iwmmxt_set_cup();
1495 break;
1496 case 0x00c: case 0x20c: case 0x40c: case 0x60c: /* WUNPCKEH */
1497 case 0x80c: case 0xa0c: case 0xc0c: case 0xe0c:
1498 wrd = (insn >> 12) & 0xf;
1499 rd0 = (insn >> 16) & 0xf;
1500 gen_op_iwmmxt_movq_M0_wRn(rd0);
1501 switch ((insn >> 22) & 3) {
1502 case 0:
1503 if (insn & (1 << 21))
1504 gen_op_iwmmxt_unpackhsb_M0();
1505 else
1506 gen_op_iwmmxt_unpackhub_M0();
1507 break;
1508 case 1:
1509 if (insn & (1 << 21))
1510 gen_op_iwmmxt_unpackhsw_M0();
1511 else
1512 gen_op_iwmmxt_unpackhuw_M0();
1513 break;
1514 case 2:
1515 if (insn & (1 << 21))
1516 gen_op_iwmmxt_unpackhsl_M0();
1517 else
1518 gen_op_iwmmxt_unpackhul_M0();
1519 break;
1520 case 3:
1521 return 1;
1522 }
1523 gen_op_iwmmxt_movq_wRn_M0(wrd);
1524 gen_op_iwmmxt_set_mup();
1525 gen_op_iwmmxt_set_cup();
1526 break;
1527 case 0x204: case 0x604: case 0xa04: case 0xe04: /* WSRL */
1528 case 0x214: case 0x614: case 0xa14: case 0xe14:
1529 wrd = (insn >> 12) & 0xf;
1530 rd0 = (insn >> 16) & 0xf;
1531 gen_op_iwmmxt_movq_M0_wRn(rd0);
1532 if (gen_iwmmxt_shift(insn, 0xff))
1533 return 1;
1534 switch ((insn >> 22) & 3) {
1535 case 0:
1536 return 1;
1537 case 1:
1538 gen_op_iwmmxt_srlw_M0_T0();
1539 break;
1540 case 2:
1541 gen_op_iwmmxt_srll_M0_T0();
1542 break;
1543 case 3:
1544 gen_op_iwmmxt_srlq_M0_T0();
1545 break;
1546 }
1547 gen_op_iwmmxt_movq_wRn_M0(wrd);
1548 gen_op_iwmmxt_set_mup();
1549 gen_op_iwmmxt_set_cup();
1550 break;
1551 case 0x004: case 0x404: case 0x804: case 0xc04: /* WSRA */
1552 case 0x014: case 0x414: case 0x814: case 0xc14:
1553 wrd = (insn >> 12) & 0xf;
1554 rd0 = (insn >> 16) & 0xf;
1555 gen_op_iwmmxt_movq_M0_wRn(rd0);
1556 if (gen_iwmmxt_shift(insn, 0xff))
1557 return 1;
1558 switch ((insn >> 22) & 3) {
1559 case 0:
1560 return 1;
1561 case 1:
1562 gen_op_iwmmxt_sraw_M0_T0();
1563 break;
1564 case 2:
1565 gen_op_iwmmxt_sral_M0_T0();
1566 break;
1567 case 3:
1568 gen_op_iwmmxt_sraq_M0_T0();
1569 break;
1570 }
1571 gen_op_iwmmxt_movq_wRn_M0(wrd);
1572 gen_op_iwmmxt_set_mup();
1573 gen_op_iwmmxt_set_cup();
1574 break;
1575 case 0x104: case 0x504: case 0x904: case 0xd04: /* WSLL */
1576 case 0x114: case 0x514: case 0x914: case 0xd14:
1577 wrd = (insn >> 12) & 0xf;
1578 rd0 = (insn >> 16) & 0xf;
1579 gen_op_iwmmxt_movq_M0_wRn(rd0);
1580 if (gen_iwmmxt_shift(insn, 0xff))
1581 return 1;
1582 switch ((insn >> 22) & 3) {
1583 case 0:
1584 return 1;
1585 case 1:
1586 gen_op_iwmmxt_sllw_M0_T0();
1587 break;
1588 case 2:
1589 gen_op_iwmmxt_slll_M0_T0();
1590 break;
1591 case 3:
1592 gen_op_iwmmxt_sllq_M0_T0();
1593 break;
1594 }
1595 gen_op_iwmmxt_movq_wRn_M0(wrd);
1596 gen_op_iwmmxt_set_mup();
1597 gen_op_iwmmxt_set_cup();
1598 break;
1599 case 0x304: case 0x704: case 0xb04: case 0xf04: /* WROR */
1600 case 0x314: case 0x714: case 0xb14: case 0xf14:
1601 wrd = (insn >> 12) & 0xf;
1602 rd0 = (insn >> 16) & 0xf;
1603 gen_op_iwmmxt_movq_M0_wRn(rd0);
1604 switch ((insn >> 22) & 3) {
1605 case 0:
1606 return 1;
1607 case 1:
1608 if (gen_iwmmxt_shift(insn, 0xf))
1609 return 1;
1610 gen_op_iwmmxt_rorw_M0_T0();
1611 break;
1612 case 2:
1613 if (gen_iwmmxt_shift(insn, 0x1f))
1614 return 1;
1615 gen_op_iwmmxt_rorl_M0_T0();
1616 break;
1617 case 3:
1618 if (gen_iwmmxt_shift(insn, 0x3f))
1619 return 1;
1620 gen_op_iwmmxt_rorq_M0_T0();
1621 break;
1622 }
1623 gen_op_iwmmxt_movq_wRn_M0(wrd);
1624 gen_op_iwmmxt_set_mup();
1625 gen_op_iwmmxt_set_cup();
1626 break;
1627 case 0x116: case 0x316: case 0x516: case 0x716: /* WMIN */
1628 case 0x916: case 0xb16: case 0xd16: case 0xf16:
1629 wrd = (insn >> 12) & 0xf;
1630 rd0 = (insn >> 16) & 0xf;
1631 rd1 = (insn >> 0) & 0xf;
1632 gen_op_iwmmxt_movq_M0_wRn(rd0);
1633 switch ((insn >> 22) & 3) {
1634 case 0:
1635 if (insn & (1 << 21))
1636 gen_op_iwmmxt_minsb_M0_wRn(rd1);
1637 else
1638 gen_op_iwmmxt_minub_M0_wRn(rd1);
1639 break;
1640 case 1:
1641 if (insn & (1 << 21))
1642 gen_op_iwmmxt_minsw_M0_wRn(rd1);
1643 else
1644 gen_op_iwmmxt_minuw_M0_wRn(rd1);
1645 break;
1646 case 2:
1647 if (insn & (1 << 21))
1648 gen_op_iwmmxt_minsl_M0_wRn(rd1);
1649 else
1650 gen_op_iwmmxt_minul_M0_wRn(rd1);
1651 break;
1652 case 3:
1653 return 1;
1654 }
1655 gen_op_iwmmxt_movq_wRn_M0(wrd);
1656 gen_op_iwmmxt_set_mup();
1657 break;
1658 case 0x016: case 0x216: case 0x416: case 0x616: /* WMAX */
1659 case 0x816: case 0xa16: case 0xc16: case 0xe16:
1660 wrd = (insn >> 12) & 0xf;
1661 rd0 = (insn >> 16) & 0xf;
1662 rd1 = (insn >> 0) & 0xf;
1663 gen_op_iwmmxt_movq_M0_wRn(rd0);
1664 switch ((insn >> 22) & 3) {
1665 case 0:
1666 if (insn & (1 << 21))
1667 gen_op_iwmmxt_maxsb_M0_wRn(rd1);
1668 else
1669 gen_op_iwmmxt_maxub_M0_wRn(rd1);
1670 break;
1671 case 1:
1672 if (insn & (1 << 21))
1673 gen_op_iwmmxt_maxsw_M0_wRn(rd1);
1674 else
1675 gen_op_iwmmxt_maxuw_M0_wRn(rd1);
1676 break;
1677 case 2:
1678 if (insn & (1 << 21))
1679 gen_op_iwmmxt_maxsl_M0_wRn(rd1);
1680 else
1681 gen_op_iwmmxt_maxul_M0_wRn(rd1);
1682 break;
1683 case 3:
1684 return 1;
1685 }
1686 gen_op_iwmmxt_movq_wRn_M0(wrd);
1687 gen_op_iwmmxt_set_mup();
1688 break;
1689 case 0x002: case 0x102: case 0x202: case 0x302: /* WALIGNI */
1690 case 0x402: case 0x502: case 0x602: case 0x702:
1691 wrd = (insn >> 12) & 0xf;
1692 rd0 = (insn >> 16) & 0xf;
1693 rd1 = (insn >> 0) & 0xf;
1694 gen_op_iwmmxt_movq_M0_wRn(rd0);
1695 gen_op_movl_T0_im((insn >> 20) & 3);
1696 gen_op_iwmmxt_align_M0_T0_wRn(rd1);
1697 gen_op_iwmmxt_movq_wRn_M0(wrd);
1698 gen_op_iwmmxt_set_mup();
1699 break;
1700 case 0x01a: case 0x11a: case 0x21a: case 0x31a: /* WSUB */
1701 case 0x41a: case 0x51a: case 0x61a: case 0x71a:
1702 case 0x81a: case 0x91a: case 0xa1a: case 0xb1a:
1703 case 0xc1a: case 0xd1a: case 0xe1a: case 0xf1a:
1704 wrd = (insn >> 12) & 0xf;
1705 rd0 = (insn >> 16) & 0xf;
1706 rd1 = (insn >> 0) & 0xf;
1707 gen_op_iwmmxt_movq_M0_wRn(rd0);
1708 switch ((insn >> 20) & 0xf) {
1709 case 0x0:
1710 gen_op_iwmmxt_subnb_M0_wRn(rd1);
1711 break;
1712 case 0x1:
1713 gen_op_iwmmxt_subub_M0_wRn(rd1);
1714 break;
1715 case 0x3:
1716 gen_op_iwmmxt_subsb_M0_wRn(rd1);
1717 break;
1718 case 0x4:
1719 gen_op_iwmmxt_subnw_M0_wRn(rd1);
1720 break;
1721 case 0x5:
1722 gen_op_iwmmxt_subuw_M0_wRn(rd1);
1723 break;
1724 case 0x7:
1725 gen_op_iwmmxt_subsw_M0_wRn(rd1);
1726 break;
1727 case 0x8:
1728 gen_op_iwmmxt_subnl_M0_wRn(rd1);
1729 break;
1730 case 0x9:
1731 gen_op_iwmmxt_subul_M0_wRn(rd1);
1732 break;
1733 case 0xb:
1734 gen_op_iwmmxt_subsl_M0_wRn(rd1);
1735 break;
1736 default:
1737 return 1;
1738 }
1739 gen_op_iwmmxt_movq_wRn_M0(wrd);
1740 gen_op_iwmmxt_set_mup();
1741 gen_op_iwmmxt_set_cup();
1742 break;
1743 case 0x01e: case 0x11e: case 0x21e: case 0x31e: /* WSHUFH */
1744 case 0x41e: case 0x51e: case 0x61e: case 0x71e:
1745 case 0x81e: case 0x91e: case 0xa1e: case 0xb1e:
1746 case 0xc1e: case 0xd1e: case 0xe1e: case 0xf1e:
1747 wrd = (insn >> 12) & 0xf;
1748 rd0 = (insn >> 16) & 0xf;
1749 gen_op_iwmmxt_movq_M0_wRn(rd0);
1750 gen_op_movl_T0_im(((insn >> 16) & 0xf0) | (insn & 0x0f));
1751 gen_op_iwmmxt_shufh_M0_T0();
1752 gen_op_iwmmxt_movq_wRn_M0(wrd);
1753 gen_op_iwmmxt_set_mup();
1754 gen_op_iwmmxt_set_cup();
1755 break;
1756 case 0x018: case 0x118: case 0x218: case 0x318: /* WADD */
1757 case 0x418: case 0x518: case 0x618: case 0x718:
1758 case 0x818: case 0x918: case 0xa18: case 0xb18:
1759 case 0xc18: case 0xd18: case 0xe18: case 0xf18:
1760 wrd = (insn >> 12) & 0xf;
1761 rd0 = (insn >> 16) & 0xf;
1762 rd1 = (insn >> 0) & 0xf;
1763 gen_op_iwmmxt_movq_M0_wRn(rd0);
1764 switch ((insn >> 20) & 0xf) {
1765 case 0x0:
1766 gen_op_iwmmxt_addnb_M0_wRn(rd1);
1767 break;
1768 case 0x1:
1769 gen_op_iwmmxt_addub_M0_wRn(rd1);
1770 break;
1771 case 0x3:
1772 gen_op_iwmmxt_addsb_M0_wRn(rd1);
1773 break;
1774 case 0x4:
1775 gen_op_iwmmxt_addnw_M0_wRn(rd1);
1776 break;
1777 case 0x5:
1778 gen_op_iwmmxt_adduw_M0_wRn(rd1);
1779 break;
1780 case 0x7:
1781 gen_op_iwmmxt_addsw_M0_wRn(rd1);
1782 break;
1783 case 0x8:
1784 gen_op_iwmmxt_addnl_M0_wRn(rd1);
1785 break;
1786 case 0x9:
1787 gen_op_iwmmxt_addul_M0_wRn(rd1);
1788 break;
1789 case 0xb:
1790 gen_op_iwmmxt_addsl_M0_wRn(rd1);
1791 break;
1792 default:
1793 return 1;
1794 }
1795 gen_op_iwmmxt_movq_wRn_M0(wrd);
1796 gen_op_iwmmxt_set_mup();
1797 gen_op_iwmmxt_set_cup();
1798 break;
1799 case 0x008: case 0x108: case 0x208: case 0x308: /* WPACK */
1800 case 0x408: case 0x508: case 0x608: case 0x708:
1801 case 0x808: case 0x908: case 0xa08: case 0xb08:
1802 case 0xc08: case 0xd08: case 0xe08: case 0xf08:
1803 wrd = (insn >> 12) & 0xf;
1804 rd0 = (insn >> 16) & 0xf;
1805 rd1 = (insn >> 0) & 0xf;
1806 gen_op_iwmmxt_movq_M0_wRn(rd0);
1807 if (!(insn & (1 << 20)))
1808 return 1;
1809 switch ((insn >> 22) & 3) {
1810 case 0:
1811 return 1;
1812 case 1:
1813 if (insn & (1 << 21))
1814 gen_op_iwmmxt_packsw_M0_wRn(rd1);
1815 else
1816 gen_op_iwmmxt_packuw_M0_wRn(rd1);
1817 break;
1818 case 2:
1819 if (insn & (1 << 21))
1820 gen_op_iwmmxt_packsl_M0_wRn(rd1);
1821 else
1822 gen_op_iwmmxt_packul_M0_wRn(rd1);
1823 break;
1824 case 3:
1825 if (insn & (1 << 21))
1826 gen_op_iwmmxt_packsq_M0_wRn(rd1);
1827 else
1828 gen_op_iwmmxt_packuq_M0_wRn(rd1);
1829 break;
1830 }
1831 gen_op_iwmmxt_movq_wRn_M0(wrd);
1832 gen_op_iwmmxt_set_mup();
1833 gen_op_iwmmxt_set_cup();
1834 break;
1835 case 0x201: case 0x203: case 0x205: case 0x207:
1836 case 0x209: case 0x20b: case 0x20d: case 0x20f:
1837 case 0x211: case 0x213: case 0x215: case 0x217:
1838 case 0x219: case 0x21b: case 0x21d: case 0x21f:
1839 wrd = (insn >> 5) & 0xf;
1840 rd0 = (insn >> 12) & 0xf;
1841 rd1 = (insn >> 0) & 0xf;
1842 if (rd0 == 0xf || rd1 == 0xf)
1843 return 1;
1844 gen_op_iwmmxt_movq_M0_wRn(wrd);
1845 switch ((insn >> 16) & 0xf) {
1846 case 0x0: /* TMIA */
b26eefb6
PB
1847 gen_movl_T0_reg(s, rd0);
1848 gen_movl_T1_reg(s, rd1);
18c9b560
AZ
1849 gen_op_iwmmxt_muladdsl_M0_T0_T1();
1850 break;
1851 case 0x8: /* TMIAPH */
b26eefb6
PB
1852 gen_movl_T0_reg(s, rd0);
1853 gen_movl_T1_reg(s, rd1);
18c9b560
AZ
1854 gen_op_iwmmxt_muladdsw_M0_T0_T1();
1855 break;
1856 case 0xc: case 0xd: case 0xe: case 0xf: /* TMIAxy */
b26eefb6 1857 gen_movl_T1_reg(s, rd0);
18c9b560
AZ
1858 if (insn & (1 << 16))
1859 gen_op_shrl_T1_im(16);
1860 gen_op_movl_T0_T1();
b26eefb6 1861 gen_movl_T1_reg(s, rd1);
18c9b560
AZ
1862 if (insn & (1 << 17))
1863 gen_op_shrl_T1_im(16);
1864 gen_op_iwmmxt_muladdswl_M0_T0_T1();
1865 break;
1866 default:
1867 return 1;
1868 }
1869 gen_op_iwmmxt_movq_wRn_M0(wrd);
1870 gen_op_iwmmxt_set_mup();
1871 break;
1872 default:
1873 return 1;
1874 }
1875
1876 return 0;
1877}
1878
1879/* Disassemble an XScale DSP instruction. Returns nonzero if an error occured
1880 (ie. an undefined instruction). */
1881static int disas_dsp_insn(CPUState *env, DisasContext *s, uint32_t insn)
1882{
1883 int acc, rd0, rd1, rdhi, rdlo;
1884
1885 if ((insn & 0x0ff00f10) == 0x0e200010) {
1886 /* Multiply with Internal Accumulate Format */
1887 rd0 = (insn >> 12) & 0xf;
1888 rd1 = insn & 0xf;
1889 acc = (insn >> 5) & 7;
1890
1891 if (acc != 0)
1892 return 1;
1893
1894 switch ((insn >> 16) & 0xf) {
1895 case 0x0: /* MIA */
b26eefb6
PB
1896 gen_movl_T0_reg(s, rd0);
1897 gen_movl_T1_reg(s, rd1);
18c9b560
AZ
1898 gen_op_iwmmxt_muladdsl_M0_T0_T1();
1899 break;
1900 case 0x8: /* MIAPH */
b26eefb6
PB
1901 gen_movl_T0_reg(s, rd0);
1902 gen_movl_T1_reg(s, rd1);
18c9b560
AZ
1903 gen_op_iwmmxt_muladdsw_M0_T0_T1();
1904 break;
1905 case 0xc: /* MIABB */
1906 case 0xd: /* MIABT */
1907 case 0xe: /* MIATB */
1908 case 0xf: /* MIATT */
b26eefb6 1909 gen_movl_T1_reg(s, rd0);
18c9b560
AZ
1910 if (insn & (1 << 16))
1911 gen_op_shrl_T1_im(16);
1912 gen_op_movl_T0_T1();
b26eefb6 1913 gen_movl_T1_reg(s, rd1);
18c9b560
AZ
1914 if (insn & (1 << 17))
1915 gen_op_shrl_T1_im(16);
1916 gen_op_iwmmxt_muladdswl_M0_T0_T1();
1917 break;
1918 default:
1919 return 1;
1920 }
1921
1922 gen_op_iwmmxt_movq_wRn_M0(acc);
1923 return 0;
1924 }
1925
1926 if ((insn & 0x0fe00ff8) == 0x0c400000) {
1927 /* Internal Accumulator Access Format */
1928 rdhi = (insn >> 16) & 0xf;
1929 rdlo = (insn >> 12) & 0xf;
1930 acc = insn & 7;
1931
1932 if (acc != 0)
1933 return 1;
1934
1935 if (insn & ARM_CP_RW_BIT) { /* MRA */
1936 gen_op_iwmmxt_movl_T0_T1_wRn(acc);
b26eefb6 1937 gen_movl_reg_T0(s, rdlo);
18c9b560
AZ
1938 gen_op_movl_T0_im((1 << (40 - 32)) - 1);
1939 gen_op_andl_T0_T1();
b26eefb6 1940 gen_movl_reg_T0(s, rdhi);
18c9b560 1941 } else { /* MAR */
b26eefb6
PB
1942 gen_movl_T0_reg(s, rdlo);
1943 gen_movl_T1_reg(s, rdhi);
18c9b560
AZ
1944 gen_op_iwmmxt_movl_wRn_T0_T1(acc);
1945 }
1946 return 0;
1947 }
1948
1949 return 1;
1950}
1951
c1713132
AZ
1952/* Disassemble system coprocessor instruction. Return nonzero if
1953 instruction is not defined. */
1954static int disas_cp_insn(CPUState *env, DisasContext *s, uint32_t insn)
1955{
1956 uint32_t rd = (insn >> 12) & 0xf;
1957 uint32_t cp = (insn >> 8) & 0xf;
1958 if (IS_USER(s)) {
1959 return 1;
1960 }
1961
18c9b560 1962 if (insn & ARM_CP_RW_BIT) {
c1713132
AZ
1963 if (!env->cp[cp].cp_read)
1964 return 1;
1965 gen_op_movl_T0_im((uint32_t) s->pc);
b26eefb6 1966 gen_set_pc_T0();
c1713132
AZ
1967 gen_op_movl_T0_cp(insn);
1968 gen_movl_reg_T0(s, rd);
1969 } else {
1970 if (!env->cp[cp].cp_write)
1971 return 1;
1972 gen_op_movl_T0_im((uint32_t) s->pc);
b26eefb6 1973 gen_set_pc_T0();
c1713132
AZ
1974 gen_movl_T0_reg(s, rd);
1975 gen_op_movl_cp_T0(insn);
1976 }
1977 return 0;
1978}
1979
9ee6e8bb
PB
1980static int cp15_user_ok(uint32_t insn)
1981{
1982 int cpn = (insn >> 16) & 0xf;
1983 int cpm = insn & 0xf;
1984 int op = ((insn >> 5) & 7) | ((insn >> 18) & 0x38);
1985
1986 if (cpn == 13 && cpm == 0) {
1987 /* TLS register. */
1988 if (op == 2 || (op == 3 && (insn & ARM_CP_RW_BIT)))
1989 return 1;
1990 }
1991 if (cpn == 7) {
1992 /* ISB, DSB, DMB. */
1993 if ((cpm == 5 && op == 4)
1994 || (cpm == 10 && (op == 4 || op == 5)))
1995 return 1;
1996 }
1997 return 0;
1998}
1999
b5ff1b31
FB
2000/* Disassemble system coprocessor (cp15) instruction. Return nonzero if
2001 instruction is not defined. */
a90b7318 2002static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn)
b5ff1b31
FB
2003{
2004 uint32_t rd;
2005
9ee6e8bb
PB
2006 /* M profile cores use memory mapped registers instead of cp15. */
2007 if (arm_feature(env, ARM_FEATURE_M))
2008 return 1;
2009
2010 if ((insn & (1 << 25)) == 0) {
2011 if (insn & (1 << 20)) {
2012 /* mrrc */
2013 return 1;
2014 }
2015 /* mcrr. Used for block cache operations, so implement as no-op. */
2016 return 0;
2017 }
2018 if ((insn & (1 << 4)) == 0) {
2019 /* cdp */
2020 return 1;
2021 }
2022 if (IS_USER(s) && !cp15_user_ok(insn)) {
b5ff1b31
FB
2023 return 1;
2024 }
9332f9da
FB
2025 if ((insn & 0x0fff0fff) == 0x0e070f90
2026 || (insn & 0x0fff0fff) == 0x0e070f58) {
2027 /* Wait for interrupt. */
2028 gen_op_movl_T0_im((long)s->pc);
b26eefb6 2029 gen_set_pc_T0();
9ee6e8bb 2030 s->is_jmp = DISAS_WFI;
9332f9da
FB
2031 return 0;
2032 }
b5ff1b31 2033 rd = (insn >> 12) & 0xf;
18c9b560 2034 if (insn & ARM_CP_RW_BIT) {
b5ff1b31
FB
2035 gen_op_movl_T0_cp15(insn);
2036 /* If the destination register is r15 then sets condition codes. */
2037 if (rd != 15)
2038 gen_movl_reg_T0(s, rd);
2039 } else {
2040 gen_movl_T0_reg(s, rd);
2041 gen_op_movl_cp15_T0(insn);
a90b7318
AZ
2042 /* Normally we would always end the TB here, but Linux
2043 * arch/arm/mach-pxa/sleep.S expects two instructions following
2044 * an MMU enable to execute from cache. Imitate this behaviour. */
2045 if (!arm_feature(env, ARM_FEATURE_XSCALE) ||
2046 (insn & 0x0fff0fff) != 0x0e010f10)
2047 gen_lookup_tb(s);
b5ff1b31 2048 }
b5ff1b31
FB
2049 return 0;
2050}
2051
9ee6e8bb
PB
2052#define VFP_REG_SHR(x, n) (((n) > 0) ? (x) >> (n) : (x) << -(n))
2053#define VFP_SREG(insn, bigbit, smallbit) \
2054 ((VFP_REG_SHR(insn, bigbit - 1) & 0x1e) | (((insn) >> (smallbit)) & 1))
2055#define VFP_DREG(reg, insn, bigbit, smallbit) do { \
2056 if (arm_feature(env, ARM_FEATURE_VFP3)) { \
2057 reg = (((insn) >> (bigbit)) & 0x0f) \
2058 | (((insn) >> ((smallbit) - 4)) & 0x10); \
2059 } else { \
2060 if (insn & (1 << (smallbit))) \
2061 return 1; \
2062 reg = ((insn) >> (bigbit)) & 0x0f; \
2063 }} while (0)
2064
2065#define VFP_SREG_D(insn) VFP_SREG(insn, 12, 22)
2066#define VFP_DREG_D(reg, insn) VFP_DREG(reg, insn, 12, 22)
2067#define VFP_SREG_N(insn) VFP_SREG(insn, 16, 7)
2068#define VFP_DREG_N(reg, insn) VFP_DREG(reg, insn, 16, 7)
2069#define VFP_SREG_M(insn) VFP_SREG(insn, 0, 5)
2070#define VFP_DREG_M(reg, insn) VFP_DREG(reg, insn, 0, 5)
2071
2072static inline int
2073vfp_enabled(CPUState * env)
2074{
2075 return ((env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) != 0);
2076}
2077
b7bcbe95
FB
2078/* Disassemble a VFP instruction. Returns nonzero if an error occured
2079 (ie. an undefined instruction). */
2080static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
2081{
2082 uint32_t rd, rn, rm, op, i, n, offset, delta_d, delta_m, bank_mask;
2083 int dp, veclen;
2084
40f137e1
PB
2085 if (!arm_feature(env, ARM_FEATURE_VFP))
2086 return 1;
2087
9ee6e8bb
PB
2088 if (!vfp_enabled(env)) {
2089 /* VFP disabled. Only allow fmxr/fmrx to/from some control regs. */
40f137e1
PB
2090 if ((insn & 0x0fe00fff) != 0x0ee00a10)
2091 return 1;
2092 rn = (insn >> 16) & 0xf;
9ee6e8bb
PB
2093 if (rn != ARM_VFP_FPSID && rn != ARM_VFP_FPEXC
2094 && rn != ARM_VFP_MVFR1 && rn != ARM_VFP_MVFR0)
40f137e1
PB
2095 return 1;
2096 }
b7bcbe95
FB
2097 dp = ((insn & 0xf00) == 0xb00);
2098 switch ((insn >> 24) & 0xf) {
2099 case 0xe:
2100 if (insn & (1 << 4)) {
2101 /* single register transfer */
b7bcbe95
FB
2102 rd = (insn >> 12) & 0xf;
2103 if (dp) {
9ee6e8bb
PB
2104 int size;
2105 int pass;
2106
2107 VFP_DREG_N(rn, insn);
2108 if (insn & 0xf)
b7bcbe95 2109 return 1;
9ee6e8bb
PB
2110 if (insn & 0x00c00060
2111 && !arm_feature(env, ARM_FEATURE_NEON))
2112 return 1;
2113
2114 pass = (insn >> 21) & 1;
2115 if (insn & (1 << 22)) {
2116 size = 0;
2117 offset = ((insn >> 5) & 3) * 8;
2118 } else if (insn & (1 << 5)) {
2119 size = 1;
2120 offset = (insn & (1 << 6)) ? 16 : 0;
2121 } else {
2122 size = 2;
2123 offset = 0;
2124 }
18c9b560 2125 if (insn & ARM_CP_RW_BIT) {
b7bcbe95 2126 /* vfp->arm */
9ee6e8bb
PB
2127 switch (size) {
2128 case 0:
2129 NEON_GET_REG(T1, rn, pass);
2130 if (offset)
2131 gen_op_shrl_T1_im(offset);
2132 if (insn & (1 << 23))
b26eefb6 2133 gen_uxtb(cpu_T[1]);
9ee6e8bb 2134 else
b26eefb6 2135 gen_sxtb(cpu_T[1]);
9ee6e8bb
PB
2136 break;
2137 case 1:
2138 NEON_GET_REG(T1, rn, pass);
2139 if (insn & (1 << 23)) {
2140 if (offset) {
2141 gen_op_shrl_T1_im(16);
2142 } else {
b26eefb6 2143 gen_uxth(cpu_T[1]);
9ee6e8bb
PB
2144 }
2145 } else {
2146 if (offset) {
2147 gen_op_sarl_T1_im(16);
2148 } else {
b26eefb6 2149 gen_sxth(cpu_T[1]);
9ee6e8bb
PB
2150 }
2151 }
2152 break;
2153 case 2:
2154 NEON_GET_REG(T1, rn, pass);
2155 break;
2156 }
2157 gen_movl_reg_T1(s, rd);
b7bcbe95
FB
2158 } else {
2159 /* arm->vfp */
9ee6e8bb
PB
2160 gen_movl_T0_reg(s, rd);
2161 if (insn & (1 << 23)) {
2162 /* VDUP */
2163 if (size == 0) {
2164 gen_op_neon_dup_u8(0);
2165 } else if (size == 1) {
2166 gen_op_neon_dup_low16();
2167 }
2168 NEON_SET_REG(T0, rn, 0);
2169 NEON_SET_REG(T0, rn, 1);
2170 } else {
2171 /* VMOV */
2172 switch (size) {
2173 case 0:
2174 NEON_GET_REG(T2, rn, pass);
2175 gen_op_movl_T1_im(0xff);
2176 gen_op_andl_T0_T1();
2177 gen_op_neon_insert_elt(offset, ~(0xff << offset));
2178 NEON_SET_REG(T2, rn, pass);
2179 break;
2180 case 1:
2181 NEON_GET_REG(T2, rn, pass);
2182 gen_op_movl_T1_im(0xffff);
2183 gen_op_andl_T0_T1();
2184 bank_mask = offset ? 0xffff : 0xffff0000;
2185 gen_op_neon_insert_elt(offset, bank_mask);
2186 NEON_SET_REG(T2, rn, pass);
2187 break;
2188 case 2:
2189 NEON_SET_REG(T0, rn, pass);
2190 break;
2191 }
2192 }
b7bcbe95 2193 }
9ee6e8bb
PB
2194 } else { /* !dp */
2195 if ((insn & 0x6f) != 0x00)
2196 return 1;
2197 rn = VFP_SREG_N(insn);
18c9b560 2198 if (insn & ARM_CP_RW_BIT) {
b7bcbe95
FB
2199 /* vfp->arm */
2200 if (insn & (1 << 21)) {
2201 /* system register */
40f137e1 2202 rn >>= 1;
9ee6e8bb 2203
b7bcbe95 2204 switch (rn) {
40f137e1 2205 case ARM_VFP_FPSID:
9ee6e8bb
PB
2206 /* VFP2 allows access for FSID from userspace.
2207 VFP3 restricts all id registers to privileged
2208 accesses. */
2209 if (IS_USER(s)
2210 && arm_feature(env, ARM_FEATURE_VFP3))
2211 return 1;
2212 gen_op_vfp_movl_T0_xreg(rn);
2213 break;
40f137e1 2214 case ARM_VFP_FPEXC:
9ee6e8bb
PB
2215 if (IS_USER(s))
2216 return 1;
2217 gen_op_vfp_movl_T0_xreg(rn);
2218 break;
40f137e1
PB
2219 case ARM_VFP_FPINST:
2220 case ARM_VFP_FPINST2:
9ee6e8bb
PB
2221 /* Not present in VFP3. */
2222 if (IS_USER(s)
2223 || arm_feature(env, ARM_FEATURE_VFP3))
2224 return 1;
40f137e1 2225 gen_op_vfp_movl_T0_xreg(rn);
b7bcbe95 2226 break;
40f137e1 2227 case ARM_VFP_FPSCR:
b7bcbe95
FB
2228 if (rd == 15)
2229 gen_op_vfp_movl_T0_fpscr_flags();
2230 else
2231 gen_op_vfp_movl_T0_fpscr();
2232 break;
9ee6e8bb
PB
2233 case ARM_VFP_MVFR0:
2234 case ARM_VFP_MVFR1:
2235 if (IS_USER(s)
2236 || !arm_feature(env, ARM_FEATURE_VFP3))
2237 return 1;
2238 gen_op_vfp_movl_T0_xreg(rn);
2239 break;
b7bcbe95
FB
2240 default:
2241 return 1;
2242 }
2243 } else {
2244 gen_mov_F0_vreg(0, rn);
2245 gen_op_vfp_mrs();
2246 }
2247 if (rd == 15) {
b5ff1b31
FB
2248 /* Set the 4 flag bits in the CPSR. */
2249 gen_op_movl_cpsr_T0(0xf0000000);
b7bcbe95
FB
2250 } else
2251 gen_movl_reg_T0(s, rd);
2252 } else {
2253 /* arm->vfp */
2254 gen_movl_T0_reg(s, rd);
2255 if (insn & (1 << 21)) {
40f137e1 2256 rn >>= 1;
b7bcbe95
FB
2257 /* system register */
2258 switch (rn) {
40f137e1 2259 case ARM_VFP_FPSID:
9ee6e8bb
PB
2260 case ARM_VFP_MVFR0:
2261 case ARM_VFP_MVFR1:
b7bcbe95
FB
2262 /* Writes are ignored. */
2263 break;
40f137e1 2264 case ARM_VFP_FPSCR:
b7bcbe95 2265 gen_op_vfp_movl_fpscr_T0();
b5ff1b31 2266 gen_lookup_tb(s);
b7bcbe95 2267 break;
40f137e1 2268 case ARM_VFP_FPEXC:
9ee6e8bb
PB
2269 if (IS_USER(s))
2270 return 1;
40f137e1
PB
2271 gen_op_vfp_movl_xreg_T0(rn);
2272 gen_lookup_tb(s);
2273 break;
2274 case ARM_VFP_FPINST:
2275 case ARM_VFP_FPINST2:
2276 gen_op_vfp_movl_xreg_T0(rn);
2277 break;
b7bcbe95
FB
2278 default:
2279 return 1;
2280 }
2281 } else {
2282 gen_op_vfp_msr();
2283 gen_mov_vreg_F0(0, rn);
2284 }
2285 }
2286 }
2287 } else {
2288 /* data processing */
2289 /* The opcode is in bits 23, 21, 20 and 6. */
2290 op = ((insn >> 20) & 8) | ((insn >> 19) & 6) | ((insn >> 6) & 1);
2291 if (dp) {
2292 if (op == 15) {
2293 /* rn is opcode */
2294 rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1);
2295 } else {
2296 /* rn is register number */
9ee6e8bb 2297 VFP_DREG_N(rn, insn);
b7bcbe95
FB
2298 }
2299
2300 if (op == 15 && (rn == 15 || rn > 17)) {
2301 /* Integer or single precision destination. */
9ee6e8bb 2302 rd = VFP_SREG_D(insn);
b7bcbe95 2303 } else {
9ee6e8bb 2304 VFP_DREG_D(rd, insn);
b7bcbe95
FB
2305 }
2306
2307 if (op == 15 && (rn == 16 || rn == 17)) {
2308 /* Integer source. */
2309 rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1);
2310 } else {
9ee6e8bb 2311 VFP_DREG_M(rm, insn);
b7bcbe95
FB
2312 }
2313 } else {
9ee6e8bb 2314 rn = VFP_SREG_N(insn);
b7bcbe95
FB
2315 if (op == 15 && rn == 15) {
2316 /* Double precision destination. */
9ee6e8bb
PB
2317 VFP_DREG_D(rd, insn);
2318 } else {
2319 rd = VFP_SREG_D(insn);
2320 }
2321 rm = VFP_SREG_M(insn);
b7bcbe95
FB
2322 }
2323
2324 veclen = env->vfp.vec_len;
2325 if (op == 15 && rn > 3)
2326 veclen = 0;
2327
2328 /* Shut up compiler warnings. */
2329 delta_m = 0;
2330 delta_d = 0;
2331 bank_mask = 0;
3b46e624 2332
b7bcbe95
FB
2333 if (veclen > 0) {
2334 if (dp)
2335 bank_mask = 0xc;
2336 else
2337 bank_mask = 0x18;
2338
2339 /* Figure out what type of vector operation this is. */
2340 if ((rd & bank_mask) == 0) {
2341 /* scalar */
2342 veclen = 0;
2343 } else {
2344 if (dp)
2345 delta_d = (env->vfp.vec_stride >> 1) + 1;
2346 else
2347 delta_d = env->vfp.vec_stride + 1;
2348
2349 if ((rm & bank_mask) == 0) {
2350 /* mixed scalar/vector */
2351 delta_m = 0;
2352 } else {
2353 /* vector */
2354 delta_m = delta_d;
2355 }
2356 }
2357 }
2358
2359 /* Load the initial operands. */
2360 if (op == 15) {
2361 switch (rn) {
2362 case 16:
2363 case 17:
2364 /* Integer source */
2365 gen_mov_F0_vreg(0, rm);
2366 break;
2367 case 8:
2368 case 9:
2369 /* Compare */
2370 gen_mov_F0_vreg(dp, rd);
2371 gen_mov_F1_vreg(dp, rm);
2372 break;
2373 case 10:
2374 case 11:
2375 /* Compare with zero */
2376 gen_mov_F0_vreg(dp, rd);
2377 gen_vfp_F1_ld0(dp);
2378 break;
9ee6e8bb
PB
2379 case 20:
2380 case 21:
2381 case 22:
2382 case 23:
2383 /* Source and destination the same. */
2384 gen_mov_F0_vreg(dp, rd);
2385 break;
b7bcbe95
FB
2386 default:
2387 /* One source operand. */
2388 gen_mov_F0_vreg(dp, rm);
9ee6e8bb 2389 break;
b7bcbe95
FB
2390 }
2391 } else {
2392 /* Two source operands. */
2393 gen_mov_F0_vreg(dp, rn);
2394 gen_mov_F1_vreg(dp, rm);
2395 }
2396
2397 for (;;) {
2398 /* Perform the calculation. */
2399 switch (op) {
2400 case 0: /* mac: fd + (fn * fm) */
2401 gen_vfp_mul(dp);
2402 gen_mov_F1_vreg(dp, rd);
2403 gen_vfp_add(dp);
2404 break;
2405 case 1: /* nmac: fd - (fn * fm) */
2406 gen_vfp_mul(dp);
2407 gen_vfp_neg(dp);
2408 gen_mov_F1_vreg(dp, rd);
2409 gen_vfp_add(dp);
2410 break;
2411 case 2: /* msc: -fd + (fn * fm) */
2412 gen_vfp_mul(dp);
2413 gen_mov_F1_vreg(dp, rd);
2414 gen_vfp_sub(dp);
2415 break;
2416 case 3: /* nmsc: -fd - (fn * fm) */
2417 gen_vfp_mul(dp);
2418 gen_mov_F1_vreg(dp, rd);
2419 gen_vfp_add(dp);
2420 gen_vfp_neg(dp);
2421 break;
2422 case 4: /* mul: fn * fm */
2423 gen_vfp_mul(dp);
2424 break;
2425 case 5: /* nmul: -(fn * fm) */
2426 gen_vfp_mul(dp);
2427 gen_vfp_neg(dp);
2428 break;
2429 case 6: /* add: fn + fm */
2430 gen_vfp_add(dp);
2431 break;
2432 case 7: /* sub: fn - fm */
2433 gen_vfp_sub(dp);
2434 break;
2435 case 8: /* div: fn / fm */
2436 gen_vfp_div(dp);
2437 break;
9ee6e8bb
PB
2438 case 14: /* fconst */
2439 if (!arm_feature(env, ARM_FEATURE_VFP3))
2440 return 1;
2441
2442 n = (insn << 12) & 0x80000000;
2443 i = ((insn >> 12) & 0x70) | (insn & 0xf);
2444 if (dp) {
2445 if (i & 0x40)
2446 i |= 0x3f80;
2447 else
2448 i |= 0x4000;
2449 n |= i << 16;
2450 } else {
2451 if (i & 0x40)
2452 i |= 0x780;
2453 else
2454 i |= 0x800;
2455 n |= i << 19;
2456 }
2457 gen_vfp_fconst(dp, n);
2458 break;
b7bcbe95
FB
2459 case 15: /* extension space */
2460 switch (rn) {
2461 case 0: /* cpy */
2462 /* no-op */
2463 break;
2464 case 1: /* abs */
2465 gen_vfp_abs(dp);
2466 break;
2467 case 2: /* neg */
2468 gen_vfp_neg(dp);
2469 break;
2470 case 3: /* sqrt */
2471 gen_vfp_sqrt(dp);
2472 break;
2473 case 8: /* cmp */
2474 gen_vfp_cmp(dp);
2475 break;
2476 case 9: /* cmpe */
2477 gen_vfp_cmpe(dp);
2478 break;
2479 case 10: /* cmpz */
2480 gen_vfp_cmp(dp);
2481 break;
2482 case 11: /* cmpez */
2483 gen_vfp_F1_ld0(dp);
2484 gen_vfp_cmpe(dp);
2485 break;
2486 case 15: /* single<->double conversion */
2487 if (dp)
2488 gen_op_vfp_fcvtsd();
2489 else
2490 gen_op_vfp_fcvtds();
2491 break;
2492 case 16: /* fuito */
2493 gen_vfp_uito(dp);
2494 break;
2495 case 17: /* fsito */
2496 gen_vfp_sito(dp);
2497 break;
9ee6e8bb
PB
2498 case 20: /* fshto */
2499 if (!arm_feature(env, ARM_FEATURE_VFP3))
2500 return 1;
2501 gen_vfp_shto(dp, rm);
2502 break;
2503 case 21: /* fslto */
2504 if (!arm_feature(env, ARM_FEATURE_VFP3))
2505 return 1;
2506 gen_vfp_slto(dp, rm);
2507 break;
2508 case 22: /* fuhto */
2509 if (!arm_feature(env, ARM_FEATURE_VFP3))
2510 return 1;
2511 gen_vfp_uhto(dp, rm);
2512 break;
2513 case 23: /* fulto */
2514 if (!arm_feature(env, ARM_FEATURE_VFP3))
2515 return 1;
2516 gen_vfp_ulto(dp, rm);
2517 break;
b7bcbe95
FB
2518 case 24: /* ftoui */
2519 gen_vfp_toui(dp);
2520 break;
2521 case 25: /* ftouiz */
2522 gen_vfp_touiz(dp);
2523 break;
2524 case 26: /* ftosi */
2525 gen_vfp_tosi(dp);
2526 break;
2527 case 27: /* ftosiz */
2528 gen_vfp_tosiz(dp);
2529 break;
9ee6e8bb
PB
2530 case 28: /* ftosh */
2531 if (!arm_feature(env, ARM_FEATURE_VFP3))
2532 return 1;
2533 gen_vfp_tosh(dp, rm);
2534 break;
2535 case 29: /* ftosl */
2536 if (!arm_feature(env, ARM_FEATURE_VFP3))
2537 return 1;
2538 gen_vfp_tosl(dp, rm);
2539 break;
2540 case 30: /* ftouh */
2541 if (!arm_feature(env, ARM_FEATURE_VFP3))
2542 return 1;
2543 gen_vfp_touh(dp, rm);
2544 break;
2545 case 31: /* ftoul */
2546 if (!arm_feature(env, ARM_FEATURE_VFP3))
2547 return 1;
2548 gen_vfp_toul(dp, rm);
2549 break;
b7bcbe95
FB
2550 default: /* undefined */
2551 printf ("rn:%d\n", rn);
2552 return 1;
2553 }
2554 break;
2555 default: /* undefined */
2556 printf ("op:%d\n", op);
2557 return 1;
2558 }
2559
2560 /* Write back the result. */
2561 if (op == 15 && (rn >= 8 && rn <= 11))
2562 ; /* Comparison, do nothing. */
2563 else if (op == 15 && rn > 17)
2564 /* Integer result. */
2565 gen_mov_vreg_F0(0, rd);
2566 else if (op == 15 && rn == 15)
2567 /* conversion */
2568 gen_mov_vreg_F0(!dp, rd);
2569 else
2570 gen_mov_vreg_F0(dp, rd);
2571
2572 /* break out of the loop if we have finished */
2573 if (veclen == 0)
2574 break;
2575
2576 if (op == 15 && delta_m == 0) {
2577 /* single source one-many */
2578 while (veclen--) {
2579 rd = ((rd + delta_d) & (bank_mask - 1))
2580 | (rd & bank_mask);
2581 gen_mov_vreg_F0(dp, rd);
2582 }
2583 break;
2584 }
2585 /* Setup the next operands. */
2586 veclen--;
2587 rd = ((rd + delta_d) & (bank_mask - 1))
2588 | (rd & bank_mask);
2589
2590 if (op == 15) {
2591 /* One source operand. */
2592 rm = ((rm + delta_m) & (bank_mask - 1))
2593 | (rm & bank_mask);
2594 gen_mov_F0_vreg(dp, rm);
2595 } else {
2596 /* Two source operands. */
2597 rn = ((rn + delta_d) & (bank_mask - 1))
2598 | (rn & bank_mask);
2599 gen_mov_F0_vreg(dp, rn);
2600 if (delta_m) {
2601 rm = ((rm + delta_m) & (bank_mask - 1))
2602 | (rm & bank_mask);
2603 gen_mov_F1_vreg(dp, rm);
2604 }
2605 }
2606 }
2607 }
2608 break;
2609 case 0xc:
2610 case 0xd:
9ee6e8bb 2611 if (dp && (insn & 0x03e00000) == 0x00400000) {
b7bcbe95
FB
2612 /* two-register transfer */
2613 rn = (insn >> 16) & 0xf;
2614 rd = (insn >> 12) & 0xf;
2615 if (dp) {
9ee6e8bb
PB
2616 VFP_DREG_M(rm, insn);
2617 } else {
2618 rm = VFP_SREG_M(insn);
2619 }
b7bcbe95 2620
18c9b560 2621 if (insn & ARM_CP_RW_BIT) {
b7bcbe95
FB
2622 /* vfp->arm */
2623 if (dp) {
2624 gen_mov_F0_vreg(1, rm);
2625 gen_op_vfp_mrrd();
2626 gen_movl_reg_T0(s, rd);
2627 gen_movl_reg_T1(s, rn);
2628 } else {
2629 gen_mov_F0_vreg(0, rm);
2630 gen_op_vfp_mrs();
2631 gen_movl_reg_T0(s, rn);
2632 gen_mov_F0_vreg(0, rm + 1);
2633 gen_op_vfp_mrs();
2634 gen_movl_reg_T0(s, rd);
2635 }
2636 } else {
2637 /* arm->vfp */
2638 if (dp) {
2639 gen_movl_T0_reg(s, rd);
2640 gen_movl_T1_reg(s, rn);
2641 gen_op_vfp_mdrr();
2642 gen_mov_vreg_F0(1, rm);
2643 } else {
2644 gen_movl_T0_reg(s, rn);
2645 gen_op_vfp_msr();
2646 gen_mov_vreg_F0(0, rm);
2647 gen_movl_T0_reg(s, rd);
2648 gen_op_vfp_msr();
2649 gen_mov_vreg_F0(0, rm + 1);
2650 }
2651 }
2652 } else {
2653 /* Load/store */
2654 rn = (insn >> 16) & 0xf;
2655 if (dp)
9ee6e8bb 2656 VFP_DREG_D(rd, insn);
b7bcbe95 2657 else
9ee6e8bb
PB
2658 rd = VFP_SREG_D(insn);
2659 if (s->thumb && rn == 15) {
2660 gen_op_movl_T1_im(s->pc & ~2);
2661 } else {
2662 gen_movl_T1_reg(s, rn);
2663 }
b7bcbe95
FB
2664 if ((insn & 0x01200000) == 0x01000000) {
2665 /* Single load/store */
2666 offset = (insn & 0xff) << 2;
2667 if ((insn & (1 << 23)) == 0)
2668 offset = -offset;
2669 gen_op_addl_T1_im(offset);
2670 if (insn & (1 << 20)) {
b5ff1b31 2671 gen_vfp_ld(s, dp);
b7bcbe95
FB
2672 gen_mov_vreg_F0(dp, rd);
2673 } else {
2674 gen_mov_F0_vreg(dp, rd);
b5ff1b31 2675 gen_vfp_st(s, dp);
b7bcbe95
FB
2676 }
2677 } else {
2678 /* load/store multiple */
2679 if (dp)
2680 n = (insn >> 1) & 0x7f;
2681 else
2682 n = insn & 0xff;
2683
2684 if (insn & (1 << 24)) /* pre-decrement */
2685 gen_op_addl_T1_im(-((insn & 0xff) << 2));
2686
2687 if (dp)
2688 offset = 8;
2689 else
2690 offset = 4;
2691 for (i = 0; i < n; i++) {
18c9b560 2692 if (insn & ARM_CP_RW_BIT) {
b7bcbe95 2693 /* load */
b5ff1b31 2694 gen_vfp_ld(s, dp);
b7bcbe95
FB
2695 gen_mov_vreg_F0(dp, rd + i);
2696 } else {
2697 /* store */
2698 gen_mov_F0_vreg(dp, rd + i);
b5ff1b31 2699 gen_vfp_st(s, dp);
b7bcbe95
FB
2700 }
2701 gen_op_addl_T1_im(offset);
2702 }
2703 if (insn & (1 << 21)) {
2704 /* writeback */
2705 if (insn & (1 << 24))
2706 offset = -offset * n;
2707 else if (dp && (insn & 1))
2708 offset = 4;
2709 else
2710 offset = 0;
2711
2712 if (offset != 0)
2713 gen_op_addl_T1_im(offset);
2714 gen_movl_reg_T1(s, rn);
2715 }
2716 }
2717 }
2718 break;
2719 default:
2720 /* Should never happen. */
2721 return 1;
2722 }
2723 return 0;
2724}
2725
6e256c93 2726static inline void gen_goto_tb(DisasContext *s, int n, uint32_t dest)
c53be334 2727{
6e256c93
FB
2728 TranslationBlock *tb;
2729
2730 tb = s->tb;
2731 if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
57fec1fe 2732 tcg_gen_goto_tb(n);
6e256c93 2733 gen_op_movl_T0_im(dest);
b26eefb6 2734 gen_set_pc_T0();
57fec1fe 2735 tcg_gen_exit_tb((long)tb + n);
6e256c93
FB
2736 } else {
2737 gen_op_movl_T0_im(dest);
b26eefb6 2738 gen_set_pc_T0();
57fec1fe 2739 tcg_gen_exit_tb(0);
6e256c93 2740 }
c53be334
FB
2741}
2742
8aaca4c0
FB
2743static inline void gen_jmp (DisasContext *s, uint32_t dest)
2744{
2745 if (__builtin_expect(s->singlestep_enabled, 0)) {
2746 /* An indirect jump so that we still trigger the debug exception. */
5899f386
FB
2747 if (s->thumb)
2748 dest |= 1;
8aaca4c0
FB
2749 gen_op_movl_T0_im(dest);
2750 gen_bx(s);
2751 } else {
6e256c93 2752 gen_goto_tb(s, 0, dest);
8aaca4c0
FB
2753 s->is_jmp = DISAS_TB_JUMP;
2754 }
2755}
2756
b5ff1b31
FB
2757static inline void gen_mulxy(int x, int y)
2758{
ee097184 2759 if (x)
b26eefb6 2760 tcg_gen_sari_i32(cpu_T[0], cpu_T[0], 16);
b5ff1b31 2761 else
b26eefb6 2762 gen_sxth(cpu_T[0]);
ee097184 2763 if (y)
b5ff1b31
FB
2764 gen_op_sarl_T1_im(16);
2765 else
b26eefb6 2766 gen_sxth(cpu_T[1]);
b5ff1b31
FB
2767 gen_op_mul_T0_T1();
2768}
2769
2770/* Return the mask of PSR bits set by a MSR instruction. */
9ee6e8bb 2771static uint32_t msr_mask(CPUState *env, DisasContext *s, int flags, int spsr) {
b5ff1b31
FB
2772 uint32_t mask;
2773
2774 mask = 0;
2775 if (flags & (1 << 0))
2776 mask |= 0xff;
2777 if (flags & (1 << 1))
2778 mask |= 0xff00;
2779 if (flags & (1 << 2))
2780 mask |= 0xff0000;
2781 if (flags & (1 << 3))
2782 mask |= 0xff000000;
9ee6e8bb 2783
2ae23e75 2784 /* Mask out undefined bits. */
9ee6e8bb
PB
2785 mask &= ~CPSR_RESERVED;
2786 if (!arm_feature(env, ARM_FEATURE_V6))
e160c51c 2787 mask &= ~(CPSR_E | CPSR_GE);
9ee6e8bb 2788 if (!arm_feature(env, ARM_FEATURE_THUMB2))
e160c51c 2789 mask &= ~CPSR_IT;
9ee6e8bb 2790 /* Mask out execution state bits. */
2ae23e75 2791 if (!spsr)
e160c51c 2792 mask &= ~CPSR_EXEC;
b5ff1b31
FB
2793 /* Mask out privileged bits. */
2794 if (IS_USER(s))
9ee6e8bb 2795 mask &= CPSR_USER;
b5ff1b31
FB
2796 return mask;
2797}
2798
2799/* Returns nonzero if access to the PSR is not permitted. */
2800static int gen_set_psr_T0(DisasContext *s, uint32_t mask, int spsr)
2801{
2802 if (spsr) {
2803 /* ??? This is also undefined in system mode. */
2804 if (IS_USER(s))
2805 return 1;
2806 gen_op_movl_spsr_T0(mask);
2807 } else {
2808 gen_op_movl_cpsr_T0(mask);
2809 }
2810 gen_lookup_tb(s);
2811 return 0;
2812}
2813
9ee6e8bb 2814/* Generate an old-style exception return. */
b5ff1b31
FB
2815static void gen_exception_return(DisasContext *s)
2816{
b26eefb6 2817 gen_set_pc_T0();
b5ff1b31
FB
2818 gen_op_movl_T0_spsr();
2819 gen_op_movl_cpsr_T0(0xffffffff);
2820 s->is_jmp = DISAS_UPDATE;
2821}
2822
9ee6e8bb
PB
2823/* Generate a v6 exception return. */
2824static void gen_rfe(DisasContext *s)
2c0262af 2825{
9ee6e8bb
PB
2826 gen_op_movl_cpsr_T0(0xffffffff);
2827 gen_op_movl_T0_T2();
b26eefb6 2828 gen_set_pc_T0();
9ee6e8bb
PB
2829 s->is_jmp = DISAS_UPDATE;
2830}
3b46e624 2831
9ee6e8bb
PB
2832static inline void
2833gen_set_condexec (DisasContext *s)
2834{
2835 if (s->condexec_mask) {
8f01245e
PB
2836 uint32_t val = (s->condexec_cond << 4) | (s->condexec_mask >> 1);
2837 TCGv tmp = new_tmp();
2838 tcg_gen_movi_i32(tmp, val);
2839 tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, condexec_bits));
2840 dead_tmp(tmp);
9ee6e8bb
PB
2841 }
2842}
3b46e624 2843
9ee6e8bb
PB
2844static void gen_nop_hint(DisasContext *s, int val)
2845{
2846 switch (val) {
2847 case 3: /* wfi */
2848 gen_op_movl_T0_im((long)s->pc);
b26eefb6 2849 gen_set_pc_T0();
9ee6e8bb
PB
2850 s->is_jmp = DISAS_WFI;
2851 break;
2852 case 2: /* wfe */
2853 case 4: /* sev */
2854 /* TODO: Implement SEV and WFE. May help SMP performance. */
2855 default: /* nop */
2856 break;
2857 }
2858}
99c475ab 2859
9ee6e8bb
PB
2860/* Neon shift by constant. The actual ops are the same as used for variable
2861 shifts. [OP][U][SIZE] */
2862static GenOpFunc *gen_neon_shift_im[8][2][4] = {
2863 { /* 0 */ /* VSHR */
2864 {
2865 gen_op_neon_shl_u8,
2866 gen_op_neon_shl_u16,
2867 gen_op_neon_shl_u32,
2868 gen_op_neon_shl_u64
2869 }, {
2870 gen_op_neon_shl_s8,
2871 gen_op_neon_shl_s16,
2872 gen_op_neon_shl_s32,
2873 gen_op_neon_shl_s64
2874 }
2875 }, { /* 1 */ /* VSRA */
2876 {
2877 gen_op_neon_shl_u8,
2878 gen_op_neon_shl_u16,
2879 gen_op_neon_shl_u32,
2880 gen_op_neon_shl_u64
2881 }, {
2882 gen_op_neon_shl_s8,
2883 gen_op_neon_shl_s16,
2884 gen_op_neon_shl_s32,
2885 gen_op_neon_shl_s64
2886 }
2887 }, { /* 2 */ /* VRSHR */
2888 {
2889 gen_op_neon_rshl_u8,
2890 gen_op_neon_rshl_u16,
2891 gen_op_neon_rshl_u32,
2892 gen_op_neon_rshl_u64
2893 }, {
2894 gen_op_neon_rshl_s8,
2895 gen_op_neon_rshl_s16,
2896 gen_op_neon_rshl_s32,
2897 gen_op_neon_rshl_s64
2898 }
2899 }, { /* 3 */ /* VRSRA */
2900 {
2901 gen_op_neon_rshl_u8,
2902 gen_op_neon_rshl_u16,
2903 gen_op_neon_rshl_u32,
2904 gen_op_neon_rshl_u64
2905 }, {
2906 gen_op_neon_rshl_s8,
2907 gen_op_neon_rshl_s16,
2908 gen_op_neon_rshl_s32,
2909 gen_op_neon_rshl_s64
2910 }
2911 }, { /* 4 */
2912 {
2913 NULL, NULL, NULL, NULL
2914 }, { /* VSRI */
2915 gen_op_neon_shl_u8,
2916 gen_op_neon_shl_u16,
2917 gen_op_neon_shl_u32,
2918 gen_op_neon_shl_u64,
2919 }
2920 }, { /* 5 */
2921 { /* VSHL */
2922 gen_op_neon_shl_u8,
2923 gen_op_neon_shl_u16,
2924 gen_op_neon_shl_u32,
2925 gen_op_neon_shl_u64,
2926 }, { /* VSLI */
2927 gen_op_neon_shl_u8,
2928 gen_op_neon_shl_u16,
2929 gen_op_neon_shl_u32,
2930 gen_op_neon_shl_u64,
2931 }
2932 }, { /* 6 */ /* VQSHL */
2933 {
2934 gen_op_neon_qshl_u8,
2935 gen_op_neon_qshl_u16,
2936 gen_op_neon_qshl_u32,
2937 gen_op_neon_qshl_u64
2938 }, {
2939 gen_op_neon_qshl_s8,
2940 gen_op_neon_qshl_s16,
2941 gen_op_neon_qshl_s32,
2942 gen_op_neon_qshl_s64
2943 }
2944 }, { /* 7 */ /* VQSHLU */
2945 {
2946 gen_op_neon_qshl_u8,
2947 gen_op_neon_qshl_u16,
2948 gen_op_neon_qshl_u32,
2949 gen_op_neon_qshl_u64
2950 }, {
2951 gen_op_neon_qshl_u8,
2952 gen_op_neon_qshl_u16,
2953 gen_op_neon_qshl_u32,
2954 gen_op_neon_qshl_u64
2955 }
99c475ab 2956 }
9ee6e8bb
PB
2957};
2958
2959/* [R][U][size - 1] */
2960static GenOpFunc *gen_neon_shift_im_narrow[2][2][3] = {
2961 {
2962 {
2963 gen_op_neon_shl_u16,
2964 gen_op_neon_shl_u32,
2965 gen_op_neon_shl_u64
2966 }, {
2967 gen_op_neon_shl_s16,
2968 gen_op_neon_shl_s32,
2969 gen_op_neon_shl_s64
2970 }
2971 }, {
2972 {
2973 gen_op_neon_rshl_u16,
2974 gen_op_neon_rshl_u32,
2975 gen_op_neon_rshl_u64
2976 }, {
2977 gen_op_neon_rshl_s16,
2978 gen_op_neon_rshl_s32,
2979 gen_op_neon_rshl_s64
2980 }
2c0262af 2981 }
9ee6e8bb 2982};
99c475ab 2983
9ee6e8bb
PB
2984static inline void
2985gen_op_neon_narrow_u32 ()
2986{
2987 /* No-op. */
2988}
2989
2990static GenOpFunc *gen_neon_narrow[3] = {
2991 gen_op_neon_narrow_u8,
2992 gen_op_neon_narrow_u16,
2993 gen_op_neon_narrow_u32
2994};
2995
2996static GenOpFunc *gen_neon_narrow_satu[3] = {
2997 gen_op_neon_narrow_sat_u8,
2998 gen_op_neon_narrow_sat_u16,
2999 gen_op_neon_narrow_sat_u32
3000};
3001
3002static GenOpFunc *gen_neon_narrow_sats[3] = {
3003 gen_op_neon_narrow_sat_s8,
3004 gen_op_neon_narrow_sat_s16,
3005 gen_op_neon_narrow_sat_s32
3006};
3007
3008static inline int gen_neon_add(int size)
3009{
3010 switch (size) {
3011 case 0: gen_op_neon_add_u8(); break;
3012 case 1: gen_op_neon_add_u16(); break;
3013 case 2: gen_op_addl_T0_T1(); break;
3014 default: return 1;
3015 }
3016 return 0;
3017}
3018
3019/* 32-bit pairwise ops end up the same as the elementsise versions. */
3020#define gen_op_neon_pmax_s32 gen_op_neon_max_s32
3021#define gen_op_neon_pmax_u32 gen_op_neon_max_u32
3022#define gen_op_neon_pmin_s32 gen_op_neon_min_s32
3023#define gen_op_neon_pmin_u32 gen_op_neon_min_u32
3024
3025#define GEN_NEON_INTEGER_OP(name) do { \
3026 switch ((size << 1) | u) { \
3027 case 0: gen_op_neon_##name##_s8(); break; \
3028 case 1: gen_op_neon_##name##_u8(); break; \
3029 case 2: gen_op_neon_##name##_s16(); break; \
3030 case 3: gen_op_neon_##name##_u16(); break; \
3031 case 4: gen_op_neon_##name##_s32(); break; \
3032 case 5: gen_op_neon_##name##_u32(); break; \
3033 default: return 1; \
3034 }} while (0)
3035
3036static inline void
3037gen_neon_movl_scratch_T0(int scratch)
3038{
3039 uint32_t offset;
3040
3041 offset = offsetof(CPUARMState, vfp.scratch[scratch]);
3042 gen_op_neon_setreg_T0(offset);
3043}
3044
3045static inline void
3046gen_neon_movl_scratch_T1(int scratch)
3047{
3048 uint32_t offset;
3049
3050 offset = offsetof(CPUARMState, vfp.scratch[scratch]);
3051 gen_op_neon_setreg_T1(offset);
3052}
3053
3054static inline void
3055gen_neon_movl_T0_scratch(int scratch)
3056{
3057 uint32_t offset;
3058
3059 offset = offsetof(CPUARMState, vfp.scratch[scratch]);
3060 gen_op_neon_getreg_T0(offset);
3061}
3062
3063static inline void
3064gen_neon_movl_T1_scratch(int scratch)
3065{
3066 uint32_t offset;
3067
3068 offset = offsetof(CPUARMState, vfp.scratch[scratch]);
3069 gen_op_neon_getreg_T1(offset);
3070}
3071
3072static inline void gen_op_neon_widen_u32(void)
3073{
3074 gen_op_movl_T1_im(0);
3075}
3076
3077static inline void gen_neon_get_scalar(int size, int reg)
3078{
3079 if (size == 1) {
3080 NEON_GET_REG(T0, reg >> 1, reg & 1);
3081 } else {
3082 NEON_GET_REG(T0, reg >> 2, (reg >> 1) & 1);
3083 if (reg & 1)
3084 gen_op_neon_dup_low16();
3085 else
3086 gen_op_neon_dup_high16();
3087 }
3088}
3089
3090static void gen_neon_unzip(int reg, int q, int tmp, int size)
3091{
3092 int n;
3093
3094 for (n = 0; n < q + 1; n += 2) {
3095 NEON_GET_REG(T0, reg, n);
3096 NEON_GET_REG(T0, reg, n + n);
3097 switch (size) {
3098 case 0: gen_op_neon_unzip_u8(); break;
3099 case 1: gen_op_neon_zip_u16(); break; /* zip and unzip are the same. */
3100 case 2: /* no-op */; break;
3101 default: abort();
3102 }
3103 gen_neon_movl_scratch_T0(tmp + n);
3104 gen_neon_movl_scratch_T1(tmp + n + 1);
3105 }
3106}
3107
3108static struct {
3109 int nregs;
3110 int interleave;
3111 int spacing;
3112} neon_ls_element_type[11] = {
3113 {4, 4, 1},
3114 {4, 4, 2},
3115 {4, 1, 1},
3116 {4, 2, 1},
3117 {3, 3, 1},
3118 {3, 3, 2},
3119 {3, 1, 1},
3120 {1, 1, 1},
3121 {2, 2, 1},
3122 {2, 2, 2},
3123 {2, 1, 1}
3124};
3125
3126/* Translate a NEON load/store element instruction. Return nonzero if the
3127 instruction is invalid. */
3128static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn)
3129{
3130 int rd, rn, rm;
3131 int op;
3132 int nregs;
3133 int interleave;
3134 int stride;
3135 int size;
3136 int reg;
3137 int pass;
3138 int load;
3139 int shift;
3140 uint32_t mask;
3141 int n;
3142
3143 if (!vfp_enabled(env))
3144 return 1;
3145 VFP_DREG_D(rd, insn);
3146 rn = (insn >> 16) & 0xf;
3147 rm = insn & 0xf;
3148 load = (insn & (1 << 21)) != 0;
3149 if ((insn & (1 << 23)) == 0) {
3150 /* Load store all elements. */
3151 op = (insn >> 8) & 0xf;
3152 size = (insn >> 6) & 3;
3153 if (op > 10 || size == 3)
3154 return 1;
3155 nregs = neon_ls_element_type[op].nregs;
3156 interleave = neon_ls_element_type[op].interleave;
3157 gen_movl_T1_reg(s, rn);
3158 stride = (1 << size) * interleave;
3159 for (reg = 0; reg < nregs; reg++) {
3160 if (interleave > 2 || (interleave == 2 && nregs == 2)) {
3161 gen_movl_T1_reg(s, rn);
3162 gen_op_addl_T1_im((1 << size) * reg);
3163 } else if (interleave == 2 && nregs == 4 && reg == 2) {
3164 gen_movl_T1_reg(s, rn);
3165 gen_op_addl_T1_im(1 << size);
3166 }
3167 for (pass = 0; pass < 2; pass++) {
3168 if (size == 2) {
3169 if (load) {
3170 gen_ldst(ldl, s);
3171 NEON_SET_REG(T0, rd, pass);
3172 } else {
3173 NEON_GET_REG(T0, rd, pass);
3174 gen_ldst(stl, s);
3175 }
3176 gen_op_addl_T1_im(stride);
3177 } else if (size == 1) {
3178 if (load) {
3179 gen_ldst(lduw, s);
3180 gen_op_addl_T1_im(stride);
3181 gen_op_movl_T2_T0();
3182 gen_ldst(lduw, s);
3183 gen_op_addl_T1_im(stride);
3184 gen_op_neon_insert_elt(16, 0xffff);
3185 NEON_SET_REG(T2, rd, pass);
3186 } else {
3187 NEON_GET_REG(T2, rd, pass);
3188 gen_op_movl_T0_T2();
3189 gen_ldst(stw, s);
3190 gen_op_addl_T1_im(stride);
3191 gen_op_neon_extract_elt(16, 0xffff0000);
3192 gen_ldst(stw, s);
3193 gen_op_addl_T1_im(stride);
3194 }
3195 } else /* size == 0 */ {
3196 if (load) {
3197 mask = 0xff;
3198 for (n = 0; n < 4; n++) {
3199 gen_ldst(ldub, s);
3200 gen_op_addl_T1_im(stride);
3201 if (n == 0) {
3202 gen_op_movl_T2_T0();
3203 } else {
3204 gen_op_neon_insert_elt(n * 8, ~mask);
3205 }
3206 mask <<= 8;
3207 }
3208 NEON_SET_REG(T2, rd, pass);
3209 } else {
3210 NEON_GET_REG(T2, rd, pass);
3211 mask = 0xff;
3212 for (n = 0; n < 4; n++) {
3213 if (n == 0) {
3214 gen_op_movl_T0_T2();
3215 } else {
3216 gen_op_neon_extract_elt(n * 8, mask);
3217 }
3218 gen_ldst(stb, s);
3219 gen_op_addl_T1_im(stride);
3220 mask <<= 8;
3221 }
3222 }
3223 }
3224 }
3225 rd += neon_ls_element_type[op].spacing;
3226 }
3227 stride = nregs * 8;
3228 } else {
3229 size = (insn >> 10) & 3;
3230 if (size == 3) {
3231 /* Load single element to all lanes. */
3232 if (!load)
3233 return 1;
3234 size = (insn >> 6) & 3;
3235 nregs = ((insn >> 8) & 3) + 1;
3236 stride = (insn & (1 << 5)) ? 2 : 1;
ff8263a9 3237 gen_movl_T1_reg(s, rn);
9ee6e8bb
PB
3238 for (reg = 0; reg < nregs; reg++) {
3239 switch (size) {
3240 case 0:
3241 gen_ldst(ldub, s);
3242 gen_op_neon_dup_u8(0);
3243 break;
3244 case 1:
3245 gen_ldst(lduw, s);
3246 gen_op_neon_dup_low16();
3247 break;
3248 case 2:
3249 gen_ldst(ldl, s);
3250 break;
3251 case 3:
3252 return 1;
99c475ab 3253 }
9ee6e8bb
PB
3254 gen_op_addl_T1_im(1 << size);
3255 NEON_SET_REG(T0, rd, 0);
3256 NEON_SET_REG(T0, rd, 1);
3257 rd += stride;
3258 }
3259 stride = (1 << size) * nregs;
3260 } else {
3261 /* Single element. */
3262 pass = (insn >> 7) & 1;
3263 switch (size) {
3264 case 0:
3265 shift = ((insn >> 5) & 3) * 8;
3266 mask = 0xff << shift;
3267 stride = 1;
3268 break;
3269 case 1:
3270 shift = ((insn >> 6) & 1) * 16;
3271 mask = shift ? 0xffff0000 : 0xffff;
3272 stride = (insn & (1 << 5)) ? 2 : 1;
3273 break;
3274 case 2:
3275 shift = 0;
3276 mask = 0xffffffff;
3277 stride = (insn & (1 << 6)) ? 2 : 1;
3278 break;
3279 default:
3280 abort();
3281 }
3282 nregs = ((insn >> 8) & 3) + 1;
3283 gen_movl_T1_reg(s, rn);
3284 for (reg = 0; reg < nregs; reg++) {
3285 if (load) {
3286 if (size != 2) {
3287 NEON_GET_REG(T2, rd, pass);
3288 }
3289 switch (size) {
3290 case 0:
3291 gen_ldst(ldub, s);
3292 break;
3293 case 1:
3294 gen_ldst(lduw, s);
3295 break;
3296 case 2:
3297 gen_ldst(ldl, s);
3298 NEON_SET_REG(T0, rd, pass);
3299 break;
3300 }
3301 if (size != 2) {
3302 gen_op_neon_insert_elt(shift, ~mask);
3303 NEON_SET_REG(T0, rd, pass);
3304 }
3305 } else { /* Store */
3306 if (size == 2) {
3307 NEON_GET_REG(T0, rd, pass);
3308 } else {
3309 NEON_GET_REG(T2, rd, pass);
3310 gen_op_neon_extract_elt(shift, mask);
3311 }
3312 switch (size) {
3313 case 0:
3314 gen_ldst(stb, s);
3315 break;
3316 case 1:
3317 gen_ldst(stw, s);
3318 break;
3319 case 2:
3320 gen_ldst(stl, s);
3321 break;
99c475ab 3322 }
99c475ab 3323 }
9ee6e8bb
PB
3324 rd += stride;
3325 gen_op_addl_T1_im(1 << size);
99c475ab 3326 }
9ee6e8bb 3327 stride = nregs * (1 << size);
99c475ab 3328 }
9ee6e8bb
PB
3329 }
3330 if (rm != 15) {
b26eefb6
PB
3331 TCGv base;
3332
3333 base = load_reg(s, rn);
9ee6e8bb 3334 if (rm == 13) {
b26eefb6 3335 tcg_gen_addi_i32(base, base, stride);
9ee6e8bb 3336 } else {
b26eefb6
PB
3337 TCGv index;
3338 index = load_reg(s, rm);
3339 tcg_gen_add_i32(base, base, index);
3340 dead_tmp(index);
9ee6e8bb 3341 }
b26eefb6 3342 store_reg(s, rn, base);
9ee6e8bb
PB
3343 }
3344 return 0;
3345}
3b46e624 3346
9ee6e8bb
PB
3347/* Translate a NEON data processing instruction. Return nonzero if the
3348 instruction is invalid.
3349 In general we process vectors in 32-bit chunks. This means we can reuse
3350 some of the scalar ops, and hopefully the code generated for 32-bit
3351 hosts won't be too awful. The downside is that the few 64-bit operations
3352 (mainly shifts) get complicated. */
2c0262af 3353
9ee6e8bb
PB
3354static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
3355{
3356 int op;
3357 int q;
3358 int rd, rn, rm;
3359 int size;
3360 int shift;
3361 int pass;
3362 int count;
3363 int pairwise;
3364 int u;
3365 int n;
3366 uint32_t imm;
3367
3368 if (!vfp_enabled(env))
3369 return 1;
3370 q = (insn & (1 << 6)) != 0;
3371 u = (insn >> 24) & 1;
3372 VFP_DREG_D(rd, insn);
3373 VFP_DREG_N(rn, insn);
3374 VFP_DREG_M(rm, insn);
3375 size = (insn >> 20) & 3;
3376 if ((insn & (1 << 23)) == 0) {
3377 /* Three register same length. */
3378 op = ((insn >> 7) & 0x1e) | ((insn >> 4) & 1);
3379 if (size == 3 && (op == 1 || op == 5 || op == 16)) {
3380 for (pass = 0; pass < (q ? 2 : 1); pass++) {
3381 NEON_GET_REG(T0, rm, pass * 2);
3382 NEON_GET_REG(T1, rm, pass * 2 + 1);
3383 gen_neon_movl_scratch_T0(0);
3384 gen_neon_movl_scratch_T1(1);
3385 NEON_GET_REG(T0, rn, pass * 2);
3386 NEON_GET_REG(T1, rn, pass * 2 + 1);
3387 switch (op) {
3388 case 1: /* VQADD */
3389 if (u) {
3390 gen_op_neon_addl_saturate_u64();
2c0262af 3391 } else {
9ee6e8bb 3392 gen_op_neon_addl_saturate_s64();
2c0262af 3393 }
9ee6e8bb
PB
3394 break;
3395 case 5: /* VQSUB */
3396 if (u) {
3397 gen_op_neon_subl_saturate_u64();
1e8d4eec 3398 } else {
9ee6e8bb 3399 gen_op_neon_subl_saturate_s64();
1e8d4eec 3400 }
9ee6e8bb
PB
3401 break;
3402 case 16:
3403 if (u) {
3404 gen_op_neon_subl_u64();
3405 } else {
3406 gen_op_neon_addl_u64();
3407 }
3408 break;
3409 default:
3410 abort();
2c0262af 3411 }
9ee6e8bb
PB
3412 NEON_SET_REG(T0, rd, pass * 2);
3413 NEON_SET_REG(T1, rd, pass * 2 + 1);
2c0262af 3414 }
9ee6e8bb 3415 return 0;
2c0262af 3416 }
9ee6e8bb
PB
3417 switch (op) {
3418 case 8: /* VSHL */
3419 case 9: /* VQSHL */
3420 case 10: /* VRSHL */
3421 case 11: /* VQSHL */
3422 /* Shift operations have Rn and Rm reversed. */
3423 {
3424 int tmp;
3425 tmp = rn;
3426 rn = rm;
3427 rm = tmp;
3428 pairwise = 0;
3429 }
2c0262af 3430 break;
9ee6e8bb
PB
3431 case 20: /* VPMAX */
3432 case 21: /* VPMIN */
3433 case 23: /* VPADD */
3434 pairwise = 1;
2c0262af 3435 break;
9ee6e8bb
PB
3436 case 26: /* VPADD (float) */
3437 pairwise = (u && size < 2);
2c0262af 3438 break;
9ee6e8bb
PB
3439 case 30: /* VPMIN/VPMAX (float) */
3440 pairwise = u;
2c0262af 3441 break;
9ee6e8bb
PB
3442 default:
3443 pairwise = 0;
2c0262af 3444 break;
9ee6e8bb
PB
3445 }
3446 for (pass = 0; pass < (q ? 4 : 2); pass++) {
3447
3448 if (pairwise) {
3449 /* Pairwise. */
3450 if (q)
3451 n = (pass & 1) * 2;
2c0262af 3452 else
9ee6e8bb
PB
3453 n = 0;
3454 if (pass < q + 1) {
3455 NEON_GET_REG(T0, rn, n);
3456 NEON_GET_REG(T1, rn, n + 1);
3457 } else {
3458 NEON_GET_REG(T0, rm, n);
3459 NEON_GET_REG(T1, rm, n + 1);
3460 }
3461 } else {
3462 /* Elementwise. */
3463 NEON_GET_REG(T0, rn, pass);
3464 NEON_GET_REG(T1, rm, pass);
3465 }
3466 switch (op) {
3467 case 0: /* VHADD */
3468 GEN_NEON_INTEGER_OP(hadd);
3469 break;
3470 case 1: /* VQADD */
3471 switch (size << 1| u) {
3472 case 0: gen_op_neon_qadd_s8(); break;
3473 case 1: gen_op_neon_qadd_u8(); break;
3474 case 2: gen_op_neon_qadd_s16(); break;
3475 case 3: gen_op_neon_qadd_u16(); break;
3476 case 4: gen_op_addl_T0_T1_saturate(); break;
3477 case 5: gen_op_addl_T0_T1_usaturate(); break;
3478 default: abort();
3479 }
2c0262af 3480 break;
9ee6e8bb
PB
3481 case 2: /* VRHADD */
3482 GEN_NEON_INTEGER_OP(rhadd);
2c0262af 3483 break;
9ee6e8bb
PB
3484 case 3: /* Logic ops. */
3485 switch ((u << 2) | size) {
3486 case 0: /* VAND */
2c0262af 3487 gen_op_andl_T0_T1();
9ee6e8bb
PB
3488 break;
3489 case 1: /* BIC */
3490 gen_op_bicl_T0_T1();
3491 break;
3492 case 2: /* VORR */
3493 gen_op_orl_T0_T1();
3494 break;
3495 case 3: /* VORN */
3496 gen_op_notl_T1();
3497 gen_op_orl_T0_T1();
3498 break;
3499 case 4: /* VEOR */
3500 gen_op_xorl_T0_T1();
3501 break;
3502 case 5: /* VBSL */
3503 NEON_GET_REG(T2, rd, pass);
3504 gen_op_neon_bsl();
3505 break;
3506 case 6: /* VBIT */
3507 NEON_GET_REG(T2, rd, pass);
3508 gen_op_neon_bit();
3509 break;
3510 case 7: /* VBIF */
3511 NEON_GET_REG(T2, rd, pass);
3512 gen_op_neon_bif();
3513 break;
2c0262af
FB
3514 }
3515 break;
9ee6e8bb
PB
3516 case 4: /* VHSUB */
3517 GEN_NEON_INTEGER_OP(hsub);
3518 break;
3519 case 5: /* VQSUB */
3520 switch ((size << 1) | u) {
3521 case 0: gen_op_neon_qsub_s8(); break;
3522 case 1: gen_op_neon_qsub_u8(); break;
3523 case 2: gen_op_neon_qsub_s16(); break;
3524 case 3: gen_op_neon_qsub_u16(); break;
3525 case 4: gen_op_subl_T0_T1_saturate(); break;
3526 case 5: gen_op_subl_T0_T1_usaturate(); break;
3527 default: abort();
2c0262af
FB
3528 }
3529 break;
9ee6e8bb
PB
3530 case 6: /* VCGT */
3531 GEN_NEON_INTEGER_OP(cgt);
3532 break;
3533 case 7: /* VCGE */
3534 GEN_NEON_INTEGER_OP(cge);
3535 break;
3536 case 8: /* VSHL */
3537 switch ((size << 1) | u) {
3538 case 0: gen_op_neon_shl_s8(); break;
3539 case 1: gen_op_neon_shl_u8(); break;
3540 case 2: gen_op_neon_shl_s16(); break;
3541 case 3: gen_op_neon_shl_u16(); break;
3542 case 4: gen_op_neon_shl_s32(); break;
3543 case 5: gen_op_neon_shl_u32(); break;
3544#if 0
3545 /* ??? Implementing these is tricky because the vector ops work
3546 on 32-bit pieces. */
3547 case 6: gen_op_neon_shl_s64(); break;
3548 case 7: gen_op_neon_shl_u64(); break;
3549#else
3550 case 6: case 7: cpu_abort(env, "VSHL.64 not implemented");
3551#endif
2c0262af
FB
3552 }
3553 break;
9ee6e8bb
PB
3554 case 9: /* VQSHL */
3555 switch ((size << 1) | u) {
3556 case 0: gen_op_neon_qshl_s8(); break;
3557 case 1: gen_op_neon_qshl_u8(); break;
3558 case 2: gen_op_neon_qshl_s16(); break;
3559 case 3: gen_op_neon_qshl_u16(); break;
3560 case 4: gen_op_neon_qshl_s32(); break;
3561 case 5: gen_op_neon_qshl_u32(); break;
3562#if 0
3563 /* ??? Implementing these is tricky because the vector ops work
3564 on 32-bit pieces. */
3565 case 6: gen_op_neon_qshl_s64(); break;
3566 case 7: gen_op_neon_qshl_u64(); break;
3567#else
3568 case 6: case 7: cpu_abort(env, "VQSHL.64 not implemented");
3569#endif
2c0262af
FB
3570 }
3571 break;
9ee6e8bb
PB
3572 case 10: /* VRSHL */
3573 switch ((size << 1) | u) {
3574 case 0: gen_op_neon_rshl_s8(); break;
3575 case 1: gen_op_neon_rshl_u8(); break;
3576 case 2: gen_op_neon_rshl_s16(); break;
3577 case 3: gen_op_neon_rshl_u16(); break;
3578 case 4: gen_op_neon_rshl_s32(); break;
3579 case 5: gen_op_neon_rshl_u32(); break;
3580#if 0
3581 /* ??? Implementing these is tricky because the vector ops work
3582 on 32-bit pieces. */
3583 case 6: gen_op_neon_rshl_s64(); break;
3584 case 7: gen_op_neon_rshl_u64(); break;
3585#else
3586 case 6: case 7: cpu_abort(env, "VRSHL.64 not implemented");
3587#endif
3588 }
2c0262af 3589 break;
9ee6e8bb
PB
3590 case 11: /* VQRSHL */
3591 switch ((size << 1) | u) {
3592 case 0: gen_op_neon_qrshl_s8(); break;
3593 case 1: gen_op_neon_qrshl_u8(); break;
3594 case 2: gen_op_neon_qrshl_s16(); break;
3595 case 3: gen_op_neon_qrshl_u16(); break;
3596 case 4: gen_op_neon_qrshl_s32(); break;
3597 case 5: gen_op_neon_qrshl_u32(); break;
3598#if 0
3599 /* ??? Implementing these is tricky because the vector ops work
3600 on 32-bit pieces. */
3601 case 6: gen_op_neon_qrshl_s64(); break;
3602 case 7: gen_op_neon_qrshl_u64(); break;
3603#else
3604 case 6: case 7: cpu_abort(env, "VQRSHL.64 not implemented");
3605#endif
3606 }
3607 break;
3608 case 12: /* VMAX */
3609 GEN_NEON_INTEGER_OP(max);
3610 break;
3611 case 13: /* VMIN */
3612 GEN_NEON_INTEGER_OP(min);
3613 break;
3614 case 14: /* VABD */
3615 GEN_NEON_INTEGER_OP(abd);
3616 break;
3617 case 15: /* VABA */
3618 GEN_NEON_INTEGER_OP(abd);
3619 NEON_GET_REG(T1, rd, pass);
3620 gen_neon_add(size);
3621 break;
3622 case 16:
3623 if (!u) { /* VADD */
3624 if (gen_neon_add(size))
3625 return 1;
3626 } else { /* VSUB */
3627 switch (size) {
3628 case 0: gen_op_neon_sub_u8(); break;
3629 case 1: gen_op_neon_sub_u16(); break;
3630 case 2: gen_op_subl_T0_T1(); break;
3631 default: return 1;
3632 }
3633 }
3634 break;
3635 case 17:
3636 if (!u) { /* VTST */
3637 switch (size) {
3638 case 0: gen_op_neon_tst_u8(); break;
3639 case 1: gen_op_neon_tst_u16(); break;
3640 case 2: gen_op_neon_tst_u32(); break;
3641 default: return 1;
3642 }
3643 } else { /* VCEQ */
3644 switch (size) {
3645 case 0: gen_op_neon_ceq_u8(); break;
3646 case 1: gen_op_neon_ceq_u16(); break;
3647 case 2: gen_op_neon_ceq_u32(); break;
3648 default: return 1;
3649 }
3650 }
3651 break;
3652 case 18: /* Multiply. */
3653 switch (size) {
3654 case 0: gen_op_neon_mul_u8(); break;
3655 case 1: gen_op_neon_mul_u16(); break;
3656 case 2: gen_op_mul_T0_T1(); break;
3657 default: return 1;
3658 }
3659 NEON_GET_REG(T1, rd, pass);
3660 if (u) { /* VMLS */
3661 switch (size) {
3662 case 0: gen_op_neon_rsb_u8(); break;
3663 case 1: gen_op_neon_rsb_u16(); break;
3664 case 2: gen_op_rsbl_T0_T1(); break;
3665 default: return 1;
3666 }
3667 } else { /* VMLA */
3668 gen_neon_add(size);
3669 }
3670 break;
3671 case 19: /* VMUL */
3672 if (u) { /* polynomial */
3673 gen_op_neon_mul_p8();
3674 } else { /* Integer */
3675 switch (size) {
3676 case 0: gen_op_neon_mul_u8(); break;
3677 case 1: gen_op_neon_mul_u16(); break;
3678 case 2: gen_op_mul_T0_T1(); break;
3679 default: return 1;
3680 }
3681 }
3682 break;
3683 case 20: /* VPMAX */
3684 GEN_NEON_INTEGER_OP(pmax);
3685 break;
3686 case 21: /* VPMIN */
3687 GEN_NEON_INTEGER_OP(pmin);
3688 break;
3689 case 22: /* Hultiply high. */
3690 if (!u) { /* VQDMULH */
3691 switch (size) {
3692 case 1: gen_op_neon_qdmulh_s16(); break;
3693 case 2: gen_op_neon_qdmulh_s32(); break;
3694 default: return 1;
3695 }
3696 } else { /* VQRDHMUL */
3697 switch (size) {
3698 case 1: gen_op_neon_qrdmulh_s16(); break;
3699 case 2: gen_op_neon_qrdmulh_s32(); break;
3700 default: return 1;
3701 }
3702 }
3703 break;
3704 case 23: /* VPADD */
3705 if (u)
3706 return 1;
3707 switch (size) {
3708 case 0: gen_op_neon_padd_u8(); break;
3709 case 1: gen_op_neon_padd_u16(); break;
3710 case 2: gen_op_addl_T0_T1(); break;
3711 default: return 1;
3712 }
3713 break;
3714 case 26: /* Floating point arithnetic. */
3715 switch ((u << 2) | size) {
3716 case 0: /* VADD */
3717 gen_op_neon_add_f32();
3718 break;
3719 case 2: /* VSUB */
3720 gen_op_neon_sub_f32();
3721 break;
3722 case 4: /* VPADD */
3723 gen_op_neon_add_f32();
3724 break;
3725 case 6: /* VABD */
3726 gen_op_neon_abd_f32();
3727 break;
3728 default:
3729 return 1;
3730 }
3731 break;
3732 case 27: /* Float multiply. */
3733 gen_op_neon_mul_f32();
3734 if (!u) {
3735 NEON_GET_REG(T1, rd, pass);
3736 if (size == 0) {
3737 gen_op_neon_add_f32();
3738 } else {
3739 gen_op_neon_rsb_f32();
3740 }
3741 }
3742 break;
3743 case 28: /* Float compare. */
3744 if (!u) {
3745 gen_op_neon_ceq_f32();
b5ff1b31 3746 } else {
9ee6e8bb
PB
3747 if (size == 0)
3748 gen_op_neon_cge_f32();
3749 else
3750 gen_op_neon_cgt_f32();
b5ff1b31 3751 }
2c0262af 3752 break;
9ee6e8bb
PB
3753 case 29: /* Float compare absolute. */
3754 if (!u)
3755 return 1;
3756 if (size == 0)
3757 gen_op_neon_acge_f32();
3758 else
3759 gen_op_neon_acgt_f32();
2c0262af 3760 break;
9ee6e8bb
PB
3761 case 30: /* Float min/max. */
3762 if (size == 0)
3763 gen_op_neon_max_f32();
3764 else
3765 gen_op_neon_min_f32();
3766 break;
3767 case 31:
3768 if (size == 0)
3769 gen_op_neon_recps_f32();
3770 else
3771 gen_op_neon_rsqrts_f32();
2c0262af 3772 break;
9ee6e8bb
PB
3773 default:
3774 abort();
2c0262af 3775 }
9ee6e8bb
PB
3776 /* Save the result. For elementwise operations we can put it
3777 straight into the destination register. For pairwise operations
3778 we have to be careful to avoid clobbering the source operands. */
3779 if (pairwise && rd == rm) {
3780 gen_neon_movl_scratch_T0(pass);
3781 } else {
3782 NEON_SET_REG(T0, rd, pass);
3783 }
3784
3785 } /* for pass */
3786 if (pairwise && rd == rm) {
3787 for (pass = 0; pass < (q ? 4 : 2); pass++) {
3788 gen_neon_movl_T0_scratch(pass);
3789 NEON_SET_REG(T0, rd, pass);
3790 }
3791 }
3792 } else if (insn & (1 << 4)) {
3793 if ((insn & 0x00380080) != 0) {
3794 /* Two registers and shift. */
3795 op = (insn >> 8) & 0xf;
3796 if (insn & (1 << 7)) {
3797 /* 64-bit shift. */
3798 size = 3;
3799 } else {
3800 size = 2;
3801 while ((insn & (1 << (size + 19))) == 0)
3802 size--;
3803 }
3804 shift = (insn >> 16) & ((1 << (3 + size)) - 1);
3805 /* To avoid excessive dumplication of ops we implement shift
3806 by immediate using the variable shift operations. */
3807 if (op < 8) {
3808 /* Shift by immediate:
3809 VSHR, VSRA, VRSHR, VRSRA, VSRI, VSHL, VQSHL, VQSHLU. */
3810 /* Right shifts are encoded as N - shift, where N is the
3811 element size in bits. */
3812 if (op <= 4)
3813 shift = shift - (1 << (size + 3));
3814 else
3815 shift++;
3816 if (size == 3) {
3817 count = q + 1;
3818 } else {
3819 count = q ? 4: 2;
3820 }
3821 switch (size) {
3822 case 0:
3823 imm = (uint8_t) shift;
3824 imm |= imm << 8;
3825 imm |= imm << 16;
3826 break;
3827 case 1:
3828 imm = (uint16_t) shift;
3829 imm |= imm << 16;
3830 break;
3831 case 2:
3832 case 3:
3833 imm = shift;
3834 break;
3835 default:
3836 abort();
3837 }
3838
3839 for (pass = 0; pass < count; pass++) {
3840 if (size < 3) {
3841 /* Operands in T0 and T1. */
3842 gen_op_movl_T1_im(imm);
3843 NEON_GET_REG(T0, rm, pass);
2c0262af 3844 } else {
9ee6e8bb
PB
3845 /* Operands in {T0, T1} and env->vfp.scratch. */
3846 gen_op_movl_T0_im(imm);
3847 gen_neon_movl_scratch_T0(0);
3848 gen_op_movl_T0_im((int32_t)imm >> 31);
3849 gen_neon_movl_scratch_T0(1);
3850 NEON_GET_REG(T0, rm, pass * 2);
3851 NEON_GET_REG(T1, rm, pass * 2 + 1);
3852 }
3853
3854 if (gen_neon_shift_im[op][u][size] == NULL)
3855 return 1;
3856 gen_neon_shift_im[op][u][size]();
3857
3858 if (op == 1 || op == 3) {
3859 /* Accumulate. */
3860 if (size == 3) {
3861 gen_neon_movl_scratch_T0(0);
3862 gen_neon_movl_scratch_T1(1);
3863 NEON_GET_REG(T0, rd, pass * 2);
3864 NEON_GET_REG(T1, rd, pass * 2 + 1);
3865 gen_op_neon_addl_u64();
3866 } else {
3867 NEON_GET_REG(T1, rd, pass);
3868 gen_neon_add(size);
99c475ab 3869 }
9ee6e8bb
PB
3870 } else if (op == 4 || (op == 5 && u)) {
3871 /* Insert */
3872 if (size == 3) {
3873 cpu_abort(env, "VS[LR]I.64 not implemented");
3874 }
3875 switch (size) {
3876 case 0:
3877 if (op == 4)
3878 imm = 0xff >> -shift;
3879 else
3880 imm = (uint8_t)(0xff << shift);
3881 imm |= imm << 8;
3882 imm |= imm << 16;
3883 break;
3884 case 1:
3885 if (op == 4)
3886 imm = 0xffff >> -shift;
3887 else
3888 imm = (uint16_t)(0xffff << shift);
3889 imm |= imm << 16;
3890 break;
3891 case 2:
3892 if (op == 4)
3893 imm = 0xffffffffu >> -shift;
3894 else
3895 imm = 0xffffffffu << shift;
3896 break;
3897 default:
3898 abort();
3899 }
3900 NEON_GET_REG(T1, rd, pass);
3901 gen_op_movl_T2_im(imm);
3902 gen_op_neon_bsl();
2c0262af 3903 }
9ee6e8bb
PB
3904 if (size == 3) {
3905 NEON_SET_REG(T0, rd, pass * 2);
3906 NEON_SET_REG(T1, rd, pass * 2 + 1);
3907 } else {
3908 NEON_SET_REG(T0, rd, pass);
3909 }
3910 } /* for pass */
3911 } else if (op < 10) {
3912 /* Shift by immedaiate and narrow:
3913 VSHRN, VRSHRN, VQSHRN, VQRSHRN. */
3914 shift = shift - (1 << (size + 3));
3915 size++;
3916 if (size == 3) {
3917 count = q + 1;
2c0262af 3918 } else {
9ee6e8bb
PB
3919 count = q ? 4: 2;
3920 }
3921 switch (size) {
3922 case 1:
3923 imm = (uint16_t) shift;
3924 imm |= imm << 16;
3925 break;
3926 case 2:
3927 case 3:
3928 imm = shift;
3929 break;
3930 default:
3931 abort();
3932 }
3933
3934 /* Processing MSB first means we need to do less shuffling at
3935 the end. */
3936 for (pass = count - 1; pass >= 0; pass--) {
3937 /* Avoid clobbering the second operand before it has been
3938 written. */
3939 n = pass;
3940 if (rd == rm)
3941 n ^= (count - 1);
3942 else
3943 n = pass;
3944
3945 if (size < 3) {
3946 /* Operands in T0 and T1. */
3947 gen_op_movl_T1_im(imm);
3948 NEON_GET_REG(T0, rm, n);
2c0262af 3949 } else {
9ee6e8bb
PB
3950 /* Operands in {T0, T1} and env->vfp.scratch. */
3951 gen_op_movl_T0_im(imm);
3952 gen_neon_movl_scratch_T0(0);
3953 gen_op_movl_T0_im((int32_t)imm >> 31);
3954 gen_neon_movl_scratch_T0(1);
3955 NEON_GET_REG(T0, rm, n * 2);
3956 NEON_GET_REG(T0, rm, n * 2 + 1);
3957 }
3b46e624 3958
9ee6e8bb
PB
3959 gen_neon_shift_im_narrow[q][u][size - 1]();
3960
3961 if (size < 3 && (pass & 1) == 0) {
3962 gen_neon_movl_scratch_T0(0);
3963 } else {
3964 uint32_t offset;
3965
3966 if (size < 3)
3967 gen_neon_movl_T1_scratch(0);
3968
3969 if (op == 8 && !u) {
3970 gen_neon_narrow[size - 1]();
99c475ab 3971 } else {
9ee6e8bb
PB
3972 if (op == 8)
3973 gen_neon_narrow_sats[size - 2]();
3974 else
3975 gen_neon_narrow_satu[size - 1]();
99c475ab 3976 }
9ee6e8bb
PB
3977 if (size == 3)
3978 offset = neon_reg_offset(rd, n);
3979 else
3980 offset = neon_reg_offset(rd, n >> 1);
3981 gen_op_neon_setreg_T0(offset);
3982 }
3983 } /* for pass */
3984 } else if (op == 10) {
3985 /* VSHLL */
3986 if (q)
3987 return 1;
3988 for (pass = 0; pass < 2; pass++) {
3989 /* Avoid clobbering the input operand. */
3990 if (rd == rm)
3991 n = 1 - pass;
3992 else
3993 n = pass;
3994
3995 NEON_GET_REG(T0, rm, n);
3996 GEN_NEON_INTEGER_OP(widen);
3997 if (shift != 0) {
3998 /* The shift is less than the width of the source
3999 type, so in some cases we can just
4000 shift the whole register. */
4001 if (size == 1 || (size == 0 && u)) {
4002 gen_op_shll_T0_im(shift);
4003 gen_op_shll_T1_im(shift);
4004 } else {
4005 switch (size) {
4006 case 0: gen_op_neon_shll_u16(shift); break;
4007 case 2: gen_op_neon_shll_u64(shift); break;
4008 default: abort();
4009 }
4010 }
4011 }
4012 NEON_SET_REG(T0, rd, n * 2);
4013 NEON_SET_REG(T1, rd, n * 2 + 1);
4014 }
4015 } else if (op == 15 || op == 16) {
4016 /* VCVT fixed-point. */
4017 for (pass = 0; pass < (q ? 4 : 2); pass++) {
4018 gen_op_vfp_getreg_F0s(neon_reg_offset(rm, pass));
4019 if (op & 1) {
4020 if (u)
4021 gen_op_vfp_ultos(shift);
4022 else
4023 gen_op_vfp_sltos(shift);
4024 } else {
4025 if (u)
4026 gen_op_vfp_touls(shift);
4027 else
4028 gen_op_vfp_tosls(shift);
2c0262af 4029 }
9ee6e8bb 4030 gen_op_vfp_setreg_F0s(neon_reg_offset(rd, pass));
2c0262af
FB
4031 }
4032 } else {
9ee6e8bb
PB
4033 return 1;
4034 }
4035 } else { /* (insn & 0x00380080) == 0 */
4036 int invert;
4037
4038 op = (insn >> 8) & 0xf;
4039 /* One register and immediate. */
4040 imm = (u << 7) | ((insn >> 12) & 0x70) | (insn & 0xf);
4041 invert = (insn & (1 << 5)) != 0;
4042 switch (op) {
4043 case 0: case 1:
4044 /* no-op */
4045 break;
4046 case 2: case 3:
4047 imm <<= 8;
4048 break;
4049 case 4: case 5:
4050 imm <<= 16;
4051 break;
4052 case 6: case 7:
4053 imm <<= 24;
4054 break;
4055 case 8: case 9:
4056 imm |= imm << 16;
4057 break;
4058 case 10: case 11:
4059 imm = (imm << 8) | (imm << 24);
4060 break;
4061 case 12:
4062 imm = (imm < 8) | 0xff;
4063 break;
4064 case 13:
4065 imm = (imm << 16) | 0xffff;
4066 break;
4067 case 14:
4068 imm |= (imm << 8) | (imm << 16) | (imm << 24);
4069 if (invert)
4070 imm = ~imm;
4071 break;
4072 case 15:
4073 imm = ((imm & 0x80) << 24) | ((imm & 0x3f) << 19)
4074 | ((imm & 0x40) ? (0x1f << 25) : (1 << 30));
4075 break;
4076 }
4077 if (invert)
4078 imm = ~imm;
4079
4080 if (op != 14 || !invert)
4081 gen_op_movl_T1_im(imm);
4082
4083 for (pass = 0; pass < (q ? 4 : 2); pass++) {
4084 if (op & 1 && op < 12) {
4085 NEON_GET_REG(T0, rd, pass);
4086 if (invert) {
4087 /* The immediate value has already been inverted, so
4088 BIC becomes AND. */
4089 gen_op_andl_T0_T1();
4090 } else {
4091 gen_op_orl_T0_T1();
4092 }
4093 NEON_SET_REG(T0, rd, pass);
4094 } else {
4095 if (op == 14 && invert) {
4096 uint32_t tmp;
4097 tmp = 0;
4098 for (n = 0; n < 4; n++) {
4099 if (imm & (1 << (n + (pass & 1) * 4)))
4100 tmp |= 0xff << (n * 8);
4101 }
4102 gen_op_movl_T1_im(tmp);
4103 }
4104 /* VMOV, VMVN. */
4105 NEON_SET_REG(T1, rd, pass);
4106 }
4107 }
4108 }
4109 } else { /* (insn & 0x00800010 == 0x00800010) */
4110 if (size != 3) {
4111 op = (insn >> 8) & 0xf;
4112 if ((insn & (1 << 6)) == 0) {
4113 /* Three registers of different lengths. */
4114 int src1_wide;
4115 int src2_wide;
4116 int prewiden;
4117 /* prewiden, src1_wide, src2_wide */
4118 static const int neon_3reg_wide[16][3] = {
4119 {1, 0, 0}, /* VADDL */
4120 {1, 1, 0}, /* VADDW */
4121 {1, 0, 0}, /* VSUBL */
4122 {1, 1, 0}, /* VSUBW */
4123 {0, 1, 1}, /* VADDHN */
4124 {0, 0, 0}, /* VABAL */
4125 {0, 1, 1}, /* VSUBHN */
4126 {0, 0, 0}, /* VABDL */
4127 {0, 0, 0}, /* VMLAL */
4128 {0, 0, 0}, /* VQDMLAL */
4129 {0, 0, 0}, /* VMLSL */
4130 {0, 0, 0}, /* VQDMLSL */
4131 {0, 0, 0}, /* Integer VMULL */
4132 {0, 0, 0}, /* VQDMULL */
4133 {0, 0, 0} /* Polynomial VMULL */
4134 };
4135
4136 prewiden = neon_3reg_wide[op][0];
4137 src1_wide = neon_3reg_wide[op][1];
4138 src2_wide = neon_3reg_wide[op][2];
4139
4140 /* Avoid overlapping operands. Wide source operands are
4141 always aligned so will never overlap with wide
4142 destinations in problematic ways. */
4143 if (rd == rm) {
4144 NEON_GET_REG(T2, rm, 1);
4145 } else if (rd == rn) {
4146 NEON_GET_REG(T2, rn, 1);
4147 }
4148 for (pass = 0; pass < 2; pass++) {
4149 /* Load the second operand into env->vfp.scratch.
4150 Also widen narrow operands. */
4151 if (pass == 1 && rd == rm) {
4152 if (prewiden) {
4153 gen_op_movl_T0_T2();
4154 } else {
4155 gen_op_movl_T1_T2();
4156 }
4157 } else {
4158 if (src2_wide) {
4159 NEON_GET_REG(T0, rm, pass * 2);
4160 NEON_GET_REG(T1, rm, pass * 2 + 1);
4161 } else {
4162 if (prewiden) {
4163 NEON_GET_REG(T0, rm, pass);
4164 } else {
4165 NEON_GET_REG(T1, rm, pass);
4166 }
4167 }
4168 }
4169 if (prewiden && !src2_wide) {
4170 GEN_NEON_INTEGER_OP(widen);
4171 }
4172 if (prewiden || src2_wide) {
4173 gen_neon_movl_scratch_T0(0);
4174 gen_neon_movl_scratch_T1(1);
4175 }
4176
4177 /* Load the first operand. */
4178 if (pass == 1 && rd == rn) {
4179 gen_op_movl_T0_T2();
4180 } else {
4181 if (src1_wide) {
4182 NEON_GET_REG(T0, rn, pass * 2);
4183 NEON_GET_REG(T1, rn, pass * 2 + 1);
4184 } else {
4185 NEON_GET_REG(T0, rn, pass);
4186 }
4187 }
4188 if (prewiden && !src1_wide) {
4189 GEN_NEON_INTEGER_OP(widen);
4190 }
4191 switch (op) {
4192 case 0: case 1: case 4: /* VADDL, VADDW, VADDHN, VRADDHN */
4193 switch (size) {
4194 case 0: gen_op_neon_addl_u16(); break;
4195 case 1: gen_op_neon_addl_u32(); break;
4196 case 2: gen_op_neon_addl_u64(); break;
4197 default: abort();
4198 }
4199 break;
4200 case 2: case 3: case 6: /* VSUBL, VSUBW, VSUBHL, VRSUBHL */
4201 switch (size) {
4202 case 0: gen_op_neon_subl_u16(); break;
4203 case 1: gen_op_neon_subl_u32(); break;
4204 case 2: gen_op_neon_subl_u64(); break;
4205 default: abort();
4206 }
4207 break;
4208 case 5: case 7: /* VABAL, VABDL */
4209 switch ((size << 1) | u) {
4210 case 0: gen_op_neon_abdl_s16(); break;
4211 case 1: gen_op_neon_abdl_u16(); break;
4212 case 2: gen_op_neon_abdl_s32(); break;
4213 case 3: gen_op_neon_abdl_u32(); break;
4214 case 4: gen_op_neon_abdl_s64(); break;
4215 case 5: gen_op_neon_abdl_u64(); break;
4216 default: abort();
4217 }
4218 break;
4219 case 8: case 9: case 10: case 11: case 12: case 13:
4220 /* VMLAL, VQDMLAL, VMLSL, VQDMLSL, VMULL, VQDMULL */
4221 switch ((size << 1) | u) {
4222 case 0: gen_op_neon_mull_s8(); break;
4223 case 1: gen_op_neon_mull_u8(); break;
4224 case 2: gen_op_neon_mull_s16(); break;
4225 case 3: gen_op_neon_mull_u16(); break;
4226 case 4: gen_op_imull_T0_T1(); break;
4227 case 5: gen_op_mull_T0_T1(); break;
4228 default: abort();
4229 }
4230 break;
4231 case 14: /* Polynomial VMULL */
4232 cpu_abort(env, "Polynomial VMULL not implemented");
4233
4234 default: /* 15 is RESERVED. */
4235 return 1;
4236 }
4237 if (op == 5 || op == 13 || (op >= 8 && op <= 11)) {
4238 /* Accumulate. */
4239 if (op == 10 || op == 11) {
4240 switch (size) {
4241 case 0: gen_op_neon_negl_u16(); break;
4242 case 1: gen_op_neon_negl_u32(); break;
4243 case 2: gen_op_neon_negl_u64(); break;
4244 default: abort();
4245 }
4246 }
4247
4248 gen_neon_movl_scratch_T0(0);
4249 gen_neon_movl_scratch_T1(1);
4250
4251 if (op != 13) {
4252 NEON_GET_REG(T0, rd, pass * 2);
4253 NEON_GET_REG(T1, rd, pass * 2 + 1);
4254 }
4255
4256 switch (op) {
4257 case 5: case 8: case 10: /* VABAL, VMLAL, VMLSL */
4258 switch (size) {
4259 case 0: gen_op_neon_addl_u16(); break;
4260 case 1: gen_op_neon_addl_u32(); break;
4261 case 2: gen_op_neon_addl_u64(); break;
4262 default: abort();
4263 }
4264 break;
4265 case 9: case 11: /* VQDMLAL, VQDMLSL */
4266 switch (size) {
4267 case 1: gen_op_neon_addl_saturate_s32(); break;
4268 case 2: gen_op_neon_addl_saturate_s64(); break;
4269 default: abort();
4270 }
4271 /* Fall through. */
4272 case 13: /* VQDMULL */
4273 switch (size) {
4274 case 1: gen_op_neon_addl_saturate_s32(); break;
4275 case 2: gen_op_neon_addl_saturate_s64(); break;
4276 default: abort();
4277 }
4278 break;
4279 default:
4280 abort();
4281 }
4282 NEON_SET_REG(T0, rd, pass * 2);
4283 NEON_SET_REG(T1, rd, pass * 2 + 1);
4284 } else if (op == 4 || op == 6) {
4285 /* Narrowing operation. */
4286 if (u) {
4287 switch (size) {
4288 case 0: gen_op_neon_narrow_high_u8(); break;
4289 case 1: gen_op_neon_narrow_high_u16(); break;
4290 case 2: gen_op_movl_T0_T1(); break;
4291 default: abort();
4292 }
4293 } else {
4294 switch (size) {
4295 case 0: gen_op_neon_narrow_high_round_u8(); break;
4296 case 1: gen_op_neon_narrow_high_round_u16(); break;
4297 case 2: gen_op_neon_narrow_high_round_u32(); break;
4298 default: abort();
4299 }
4300 }
4301 NEON_SET_REG(T0, rd, pass);
4302 } else {
4303 /* Write back the result. */
4304 NEON_SET_REG(T0, rd, pass * 2);
4305 NEON_SET_REG(T1, rd, pass * 2 + 1);
4306 }
4307 }
4308 } else {
4309 /* Two registers and a scalar. */
4310 switch (op) {
4311 case 0: /* Integer VMLA scalar */
4312 case 1: /* Float VMLA scalar */
4313 case 4: /* Integer VMLS scalar */
4314 case 5: /* Floating point VMLS scalar */
4315 case 8: /* Integer VMUL scalar */
4316 case 9: /* Floating point VMUL scalar */
4317 case 12: /* VQDMULH scalar */
4318 case 13: /* VQRDMULH scalar */
4319 gen_neon_get_scalar(size, rm);
4320 gen_op_movl_T2_T0();
4321 for (pass = 0; pass < (u ? 4 : 2); pass++) {
4322 if (pass != 0)
4323 gen_op_movl_T0_T2();
4324 NEON_GET_REG(T1, rn, pass);
4325 if (op == 12) {
4326 if (size == 1) {
4327 gen_op_neon_qdmulh_s16();
4328 } else {
4329 gen_op_neon_qdmulh_s32();
4330 }
4331 } else if (op == 13) {
4332 if (size == 1) {
4333 gen_op_neon_qrdmulh_s16();
4334 } else {
4335 gen_op_neon_qrdmulh_s32();
4336 }
4337 } else if (op & 1) {
4338 gen_op_neon_mul_f32();
4339 } else {
4340 switch (size) {
4341 case 0: gen_op_neon_mul_u8(); break;
4342 case 1: gen_op_neon_mul_u16(); break;
4343 case 2: gen_op_mul_T0_T1(); break;
4344 default: return 1;
4345 }
4346 }
4347 if (op < 8) {
4348 /* Accumulate. */
4349 NEON_GET_REG(T1, rd, pass);
4350 switch (op) {
4351 case 0:
4352 gen_neon_add(size);
4353 break;
4354 case 1:
4355 gen_op_neon_add_f32();
4356 break;
4357 case 4:
4358 switch (size) {
4359 case 0: gen_op_neon_rsb_u8(); break;
4360 case 1: gen_op_neon_rsb_u16(); break;
4361 case 2: gen_op_rsbl_T0_T1(); break;
4362 default: return 1;
4363 }
4364 break;
4365 case 5:
4366 gen_op_neon_rsb_f32();
4367 break;
4368 default:
4369 abort();
4370 }
4371 }
4372 NEON_SET_REG(T0, rd, pass);
4373 }
4374 break;
4375 case 2: /* VMLAL sclar */
4376 case 3: /* VQDMLAL scalar */
4377 case 6: /* VMLSL scalar */
4378 case 7: /* VQDMLSL scalar */
4379 case 10: /* VMULL scalar */
4380 case 11: /* VQDMULL scalar */
4381 if (rd == rn) {
4382 /* Save overlapping operands before they are
4383 clobbered. */
4384 NEON_GET_REG(T0, rn, 1);
4385 gen_neon_movl_scratch_T0(2);
4386 }
4387 gen_neon_get_scalar(size, rm);
4388 gen_op_movl_T2_T0();
4389 for (pass = 0; pass < 2; pass++) {
4390 if (pass != 0) {
4391 gen_op_movl_T0_T2();
4392 }
4393 if (pass != 0 && rd == rn) {
4394 gen_neon_movl_T1_scratch(2);
4395 } else {
4396 NEON_GET_REG(T1, rn, pass);
4397 }
4398 switch ((size << 1) | u) {
4399 case 0: gen_op_neon_mull_s8(); break;
4400 case 1: gen_op_neon_mull_u8(); break;
4401 case 2: gen_op_neon_mull_s16(); break;
4402 case 3: gen_op_neon_mull_u16(); break;
4403 case 4: gen_op_imull_T0_T1(); break;
4404 case 5: gen_op_mull_T0_T1(); break;
4405 default: abort();
4406 }
4407 if (op == 6 || op == 7) {
4408 switch (size) {
4409 case 0: gen_op_neon_negl_u16(); break;
4410 case 1: gen_op_neon_negl_u32(); break;
4411 case 2: gen_op_neon_negl_u64(); break;
4412 default: abort();
4413 }
4414 }
4415 gen_neon_movl_scratch_T0(0);
4416 gen_neon_movl_scratch_T1(1);
4417 NEON_GET_REG(T0, rd, pass * 2);
4418 NEON_GET_REG(T1, rd, pass * 2 + 1);
4419 switch (op) {
4420 case 2: case 6:
4421 switch (size) {
4422 case 0: gen_op_neon_addl_u16(); break;
4423 case 1: gen_op_neon_addl_u32(); break;
4424 case 2: gen_op_neon_addl_u64(); break;
4425 default: abort();
4426 }
4427 break;
4428 case 3: case 7:
4429 switch (size) {
4430 case 1:
4431 gen_op_neon_addl_saturate_s32();
4432 gen_op_neon_addl_saturate_s32();
4433 break;
4434 case 2:
4435 gen_op_neon_addl_saturate_s64();
4436 gen_op_neon_addl_saturate_s64();
4437 break;
4438 default: abort();
4439 }
4440 break;
4441 case 10:
4442 /* no-op */
4443 break;
4444 case 11:
4445 switch (size) {
4446 case 1: gen_op_neon_addl_saturate_s32(); break;
4447 case 2: gen_op_neon_addl_saturate_s64(); break;
4448 default: abort();
4449 }
4450 break;
4451 default:
4452 abort();
4453 }
4454 NEON_SET_REG(T0, rd, pass * 2);
4455 NEON_SET_REG(T1, rd, pass * 2 + 1);
4456 }
4457 break;
4458 default: /* 14 and 15 are RESERVED */
4459 return 1;
4460 }
4461 }
4462 } else { /* size == 3 */
4463 if (!u) {
4464 /* Extract. */
4465 int reg;
4466 imm = (insn >> 8) & 0xf;
4467 reg = rn;
4468 count = q ? 4 : 2;
4469 n = imm >> 2;
4470 NEON_GET_REG(T0, reg, n);
4471 for (pass = 0; pass < count; pass++) {
4472 n++;
4473 if (n > count) {
4474 reg = rm;
4475 n -= count;
4476 }
4477 if (imm & 3) {
4478 NEON_GET_REG(T1, reg, n);
4479 gen_op_neon_extract((insn << 3) & 0x1f);
4480 }
4481 /* ??? This is broken if rd and rm overlap */
4482 NEON_SET_REG(T0, rd, pass);
4483 if (imm & 3) {
4484 gen_op_movl_T0_T1();
4485 } else {
4486 NEON_GET_REG(T0, reg, n);
4487 }
4488 }
4489 } else if ((insn & (1 << 11)) == 0) {
4490 /* Two register misc. */
4491 op = ((insn >> 12) & 0x30) | ((insn >> 7) & 0xf);
4492 size = (insn >> 18) & 3;
4493 switch (op) {
4494 case 0: /* VREV64 */
4495 if (size == 3)
4496 return 1;
4497 for (pass = 0; pass < (q ? 2 : 1); pass++) {
4498 NEON_GET_REG(T0, rm, pass * 2);
4499 NEON_GET_REG(T1, rm, pass * 2 + 1);
4500 switch (size) {
4501 case 0: gen_op_rev_T0(); break;
8f01245e 4502 case 1: gen_swap_half(cpu_T[0]); break;
9ee6e8bb
PB
4503 case 2: /* no-op */ break;
4504 default: abort();
4505 }
4506 NEON_SET_REG(T0, rd, pass * 2 + 1);
4507 if (size == 2) {
4508 NEON_SET_REG(T1, rd, pass * 2);
4509 } else {
4510 gen_op_movl_T0_T1();
4511 switch (size) {
4512 case 0: gen_op_rev_T0(); break;
8f01245e 4513 case 1: gen_swap_half(cpu_T[0]); break;
9ee6e8bb
PB
4514 default: abort();
4515 }
4516 NEON_SET_REG(T0, rd, pass * 2);
4517 }
4518 }
4519 break;
4520 case 4: case 5: /* VPADDL */
4521 case 12: case 13: /* VPADAL */
4522 if (size < 2)
4523 goto elementwise;
4524 if (size == 3)
4525 return 1;
4526 for (pass = 0; pass < (q ? 2 : 1); pass++) {
4527 NEON_GET_REG(T0, rm, pass * 2);
4528 NEON_GET_REG(T1, rm, pass * 2 + 1);
4529 if (op & 1)
4530 gen_op_neon_paddl_u32();
4531 else
4532 gen_op_neon_paddl_s32();
4533 if (op >= 12) {
4534 /* Accumulate. */
4535 gen_neon_movl_scratch_T0(0);
4536 gen_neon_movl_scratch_T1(1);
4537
4538 NEON_GET_REG(T0, rd, pass * 2);
4539 NEON_GET_REG(T1, rd, pass * 2 + 1);
4540 gen_op_neon_addl_u64();
4541 }
4542 NEON_SET_REG(T0, rd, pass * 2);
4543 NEON_SET_REG(T1, rd, pass * 2 + 1);
4544 }
4545 break;
4546 case 33: /* VTRN */
4547 if (size == 2) {
4548 for (n = 0; n < (q ? 4 : 2); n += 2) {
4549 NEON_GET_REG(T0, rm, n);
4550 NEON_GET_REG(T1, rd, n + 1);
4551 NEON_SET_REG(T1, rm, n);
4552 NEON_SET_REG(T0, rd, n + 1);
4553 }
4554 } else {
4555 goto elementwise;
4556 }
4557 break;
4558 case 34: /* VUZP */
4559 /* Reg Before After
4560 Rd A3 A2 A1 A0 B2 B0 A2 A0
4561 Rm B3 B2 B1 B0 B3 B1 A3 A1
4562 */
4563 if (size == 3)
4564 return 1;
4565 gen_neon_unzip(rd, q, 0, size);
4566 gen_neon_unzip(rm, q, 4, size);
4567 if (q) {
4568 static int unzip_order_q[8] =
4569 {0, 2, 4, 6, 1, 3, 5, 7};
4570 for (n = 0; n < 8; n++) {
4571 int reg = (n < 4) ? rd : rm;
4572 gen_neon_movl_T0_scratch(unzip_order_q[n]);
4573 NEON_SET_REG(T0, reg, n % 4);
4574 }
4575 } else {
4576 static int unzip_order[4] =
4577 {0, 4, 1, 5};
4578 for (n = 0; n < 4; n++) {
4579 int reg = (n < 2) ? rd : rm;
4580 gen_neon_movl_T0_scratch(unzip_order[n]);
4581 NEON_SET_REG(T0, reg, n % 2);
4582 }
4583 }
4584 break;
4585 case 35: /* VZIP */
4586 /* Reg Before After
4587 Rd A3 A2 A1 A0 B1 A1 B0 A0
4588 Rm B3 B2 B1 B0 B3 A3 B2 A2
4589 */
4590 if (size == 3)
4591 return 1;
4592 count = (q ? 4 : 2);
4593 for (n = 0; n < count; n++) {
4594 NEON_GET_REG(T0, rd, n);
4595 NEON_GET_REG(T1, rd, n);
4596 switch (size) {
4597 case 0: gen_op_neon_zip_u8(); break;
4598 case 1: gen_op_neon_zip_u16(); break;
4599 case 2: /* no-op */; break;
4600 default: abort();
4601 }
4602 gen_neon_movl_scratch_T0(n * 2);
4603 gen_neon_movl_scratch_T1(n * 2 + 1);
4604 }
4605 for (n = 0; n < count * 2; n++) {
4606 int reg = (n < count) ? rd : rm;
4607 gen_neon_movl_T0_scratch(n);
4608 NEON_SET_REG(T0, reg, n % count);
4609 }
4610 break;
4611 case 36: case 37: /* VMOVN, VQMOVUN, VQMOVN */
4612 for (pass = 0; pass < 2; pass++) {
4613 if (rd == rm + 1) {
4614 n = 1 - pass;
4615 } else {
4616 n = pass;
4617 }
4618 NEON_GET_REG(T0, rm, n * 2);
4619 NEON_GET_REG(T1, rm, n * 2 + 1);
4620 if (op == 36 && q == 0) {
4621 switch (size) {
4622 case 0: gen_op_neon_narrow_u8(); break;
4623 case 1: gen_op_neon_narrow_u16(); break;
4624 case 2: /* no-op */ break;
4625 default: return 1;
4626 }
4627 } else if (q) {
4628 switch (size) {
4629 case 0: gen_op_neon_narrow_sat_u8(); break;
4630 case 1: gen_op_neon_narrow_sat_u16(); break;
4631 case 2: gen_op_neon_narrow_sat_u32(); break;
4632 default: return 1;
4633 }
4634 } else {
4635 switch (size) {
4636 case 0: gen_op_neon_narrow_sat_s8(); break;
4637 case 1: gen_op_neon_narrow_sat_s16(); break;
4638 case 2: gen_op_neon_narrow_sat_s32(); break;
4639 default: return 1;
4640 }
4641 }
4642 NEON_SET_REG(T0, rd, n);
4643 }
4644 break;
4645 case 38: /* VSHLL */
4646 if (q)
4647 return 1;
4648 if (rm == rd) {
4649 NEON_GET_REG(T2, rm, 1);
4650 }
4651 for (pass = 0; pass < 2; pass++) {
4652 if (pass == 1 && rm == rd) {
4653 gen_op_movl_T0_T2();
4654 } else {
4655 NEON_GET_REG(T0, rm, pass);
4656 }
4657 switch (size) {
4658 case 0: gen_op_neon_widen_high_u8(); break;
4659 case 1: gen_op_neon_widen_high_u16(); break;
4660 case 2:
4661 gen_op_movl_T1_T0();
4662 gen_op_movl_T0_im(0);
4663 break;
4664 default: return 1;
4665 }
4666 NEON_SET_REG(T0, rd, pass * 2);
4667 NEON_SET_REG(T1, rd, pass * 2 + 1);
4668 }
4669 break;
4670 default:
4671 elementwise:
4672 for (pass = 0; pass < (q ? 4 : 2); pass++) {
4673 if (op == 30 || op == 31 || op >= 58) {
4674 gen_op_vfp_getreg_F0s(neon_reg_offset(rm, pass));
4675 } else {
4676 NEON_GET_REG(T0, rm, pass);
4677 }
4678 switch (op) {
4679 case 1: /* VREV32 */
4680 switch (size) {
4681 case 0: gen_op_rev_T0(); break;
8f01245e 4682 case 1: gen_swap_half(cpu_T[0]); break;
9ee6e8bb
PB
4683 default: return 1;
4684 }
4685 break;
4686 case 2: /* VREV16 */
4687 if (size != 0)
4688 return 1;
3670669c 4689 gen_rev16(cpu_T[0]);
9ee6e8bb
PB
4690 break;
4691 case 4: case 5: /* VPADDL */
4692 case 12: case 13: /* VPADAL */
4693 switch ((size << 1) | (op & 1)) {
4694 case 0: gen_op_neon_paddl_s8(); break;
4695 case 1: gen_op_neon_paddl_u8(); break;
4696 case 2: gen_op_neon_paddl_s16(); break;
4697 case 3: gen_op_neon_paddl_u16(); break;
4698 default: abort();
4699 }
4700 if (op >= 12) {
4701 /* Accumulate */
4702 NEON_GET_REG(T1, rd, pass);
4703 switch (size) {
4704 case 0: gen_op_neon_add_u16(); break;
4705 case 1: gen_op_addl_T0_T1(); break;
4706 default: abort();
4707 }
4708 }
4709 break;
4710 case 8: /* CLS */
4711 switch (size) {
4712 case 0: gen_op_neon_cls_s8(); break;
4713 case 1: gen_op_neon_cls_s16(); break;
4714 case 2: gen_op_neon_cls_s32(); break;
4715 default: return 1;
4716 }
4717 break;
4718 case 9: /* CLZ */
4719 switch (size) {
4720 case 0: gen_op_neon_clz_u8(); break;
4721 case 1: gen_op_neon_clz_u16(); break;
1497c961 4722 case 2: gen_helper_clz(cpu_T[0], cpu_T[0]); break;
9ee6e8bb
PB
4723 default: return 1;
4724 }
4725 break;
4726 case 10: /* CNT */
4727 if (size != 0)
4728 return 1;
4729 gen_op_neon_cnt_u8();
4730 break;
4731 case 11: /* VNOT */
4732 if (size != 0)
4733 return 1;
4734 gen_op_notl_T0();
4735 break;
4736 case 14: /* VQABS */
4737 switch (size) {
4738 case 0: gen_op_neon_qabs_s8(); break;
4739 case 1: gen_op_neon_qabs_s16(); break;
4740 case 2: gen_op_neon_qabs_s32(); break;
4741 default: return 1;
4742 }
4743 break;
4744 case 15: /* VQNEG */
4745 switch (size) {
4746 case 0: gen_op_neon_qneg_s8(); break;
4747 case 1: gen_op_neon_qneg_s16(); break;
4748 case 2: gen_op_neon_qneg_s32(); break;
4749 default: return 1;
4750 }
4751 break;
4752 case 16: case 19: /* VCGT #0, VCLE #0 */
4753 gen_op_movl_T1_im(0);
4754 switch(size) {
4755 case 0: gen_op_neon_cgt_s8(); break;
4756 case 1: gen_op_neon_cgt_s16(); break;
4757 case 2: gen_op_neon_cgt_s32(); break;
4758 default: return 1;
4759 }
4760 if (op == 19)
4761 gen_op_notl_T0();
4762 break;
4763 case 17: case 20: /* VCGE #0, VCLT #0 */
4764 gen_op_movl_T1_im(0);
4765 switch(size) {
4766 case 0: gen_op_neon_cge_s8(); break;
4767 case 1: gen_op_neon_cge_s16(); break;
4768 case 2: gen_op_neon_cge_s32(); break;
4769 default: return 1;
4770 }
4771 if (op == 20)
4772 gen_op_notl_T0();
4773 break;
4774 case 18: /* VCEQ #0 */
4775 gen_op_movl_T1_im(0);
4776 switch(size) {
4777 case 0: gen_op_neon_ceq_u8(); break;
4778 case 1: gen_op_neon_ceq_u16(); break;
4779 case 2: gen_op_neon_ceq_u32(); break;
4780 default: return 1;
4781 }
4782 break;
4783 case 22: /* VABS */
4784 switch(size) {
4785 case 0: gen_op_neon_abs_s8(); break;
4786 case 1: gen_op_neon_abs_s16(); break;
4787 case 2: gen_op_neon_abs_s32(); break;
4788 default: return 1;
4789 }
4790 break;
4791 case 23: /* VNEG */
4792 gen_op_movl_T1_im(0);
4793 switch(size) {
4794 case 0: gen_op_neon_rsb_u8(); break;
4795 case 1: gen_op_neon_rsb_u16(); break;
4796 case 2: gen_op_rsbl_T0_T1(); break;
4797 default: return 1;
4798 }
4799 break;
4800 case 24: case 27: /* Float VCGT #0, Float VCLE #0 */
4801 gen_op_movl_T1_im(0);
4802 gen_op_neon_cgt_f32();
4803 if (op == 27)
4804 gen_op_notl_T0();
4805 break;
4806 case 25: case 28: /* Float VCGE #0, Float VCLT #0 */
4807 gen_op_movl_T1_im(0);
4808 gen_op_neon_cge_f32();
4809 if (op == 28)
4810 gen_op_notl_T0();
4811 break;
4812 case 26: /* Float VCEQ #0 */
4813 gen_op_movl_T1_im(0);
4814 gen_op_neon_ceq_f32();
4815 break;
4816 case 30: /* Float VABS */
4817 gen_op_vfp_abss();
4818 break;
4819 case 31: /* Float VNEG */
4820 gen_op_vfp_negs();
4821 break;
4822 case 32: /* VSWP */
4823 NEON_GET_REG(T1, rd, pass);
4824 NEON_SET_REG(T1, rm, pass);
4825 break;
4826 case 33: /* VTRN */
4827 NEON_GET_REG(T1, rd, pass);
4828 switch (size) {
4829 case 0: gen_op_neon_trn_u8(); break;
4830 case 1: gen_op_neon_trn_u16(); break;
4831 case 2: abort();
4832 default: return 1;
4833 }
4834 NEON_SET_REG(T1, rm, pass);
4835 break;
4836 case 56: /* Integer VRECPE */
4837 gen_op_neon_recpe_u32();
4838 break;
4839 case 57: /* Integer VRSQRTE */
4840 gen_op_neon_rsqrte_u32();
4841 break;
4842 case 58: /* Float VRECPE */
4843 gen_op_neon_recpe_f32();
4844 break;
4845 case 59: /* Float VRSQRTE */
4846 gen_op_neon_rsqrte_f32();
4847 break;
4848 case 60: /* VCVT.F32.S32 */
4849 gen_op_vfp_tosizs();
4850 break;
4851 case 61: /* VCVT.F32.U32 */
4852 gen_op_vfp_touizs();
4853 break;
4854 case 62: /* VCVT.S32.F32 */
4855 gen_op_vfp_sitos();
4856 break;
4857 case 63: /* VCVT.U32.F32 */
4858 gen_op_vfp_uitos();
4859 break;
4860 default:
4861 /* Reserved: 21, 29, 39-56 */
4862 return 1;
4863 }
4864 if (op == 30 || op == 31 || op >= 58) {
4865 gen_op_vfp_setreg_F0s(neon_reg_offset(rm, pass));
4866 } else {
4867 NEON_SET_REG(T0, rd, pass);
4868 }
4869 }
4870 break;
4871 }
4872 } else if ((insn & (1 << 10)) == 0) {
4873 /* VTBL, VTBX. */
4874 n = (insn >> 5) & 0x18;
4875 NEON_GET_REG(T1, rm, 0);
4876 if (insn & (1 << 6)) {
4877 NEON_GET_REG(T0, rd, 0);
4878 } else {
4879 gen_op_movl_T0_im(0);
4880 }
4881 gen_op_neon_tbl(rn, n);
4882 gen_op_movl_T2_T0();
4883 NEON_GET_REG(T1, rm, 1);
4884 if (insn & (1 << 6)) {
4885 NEON_GET_REG(T0, rd, 0);
4886 } else {
4887 gen_op_movl_T0_im(0);
4888 }
4889 gen_op_neon_tbl(rn, n);
4890 NEON_SET_REG(T2, rd, 0);
4891 NEON_SET_REG(T0, rd, 1);
4892 } else if ((insn & 0x380) == 0) {
4893 /* VDUP */
4894 if (insn & (1 << 19)) {
4895 NEON_SET_REG(T0, rm, 1);
4896 } else {
4897 NEON_SET_REG(T0, rm, 0);
4898 }
4899 if (insn & (1 << 16)) {
4900 gen_op_neon_dup_u8(((insn >> 17) & 3) * 8);
4901 } else if (insn & (1 << 17)) {
4902 if ((insn >> 18) & 1)
4903 gen_op_neon_dup_high16();
4904 else
4905 gen_op_neon_dup_low16();
4906 }
4907 for (pass = 0; pass < (q ? 4 : 2); pass++) {
4908 NEON_SET_REG(T0, rd, pass);
4909 }
4910 } else {
4911 return 1;
4912 }
4913 }
4914 }
4915 return 0;
4916}
4917
4918static int disas_coproc_insn(CPUState * env, DisasContext *s, uint32_t insn)
4919{
4920 int cpnum;
4921
4922 cpnum = (insn >> 8) & 0xf;
4923 if (arm_feature(env, ARM_FEATURE_XSCALE)
4924 && ((env->cp15.c15_cpar ^ 0x3fff) & (1 << cpnum)))
4925 return 1;
4926
4927 switch (cpnum) {
4928 case 0:
4929 case 1:
4930 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
4931 return disas_iwmmxt_insn(env, s, insn);
4932 } else if (arm_feature(env, ARM_FEATURE_XSCALE)) {
4933 return disas_dsp_insn(env, s, insn);
4934 }
4935 return 1;
4936 case 10:
4937 case 11:
4938 return disas_vfp_insn (env, s, insn);
4939 case 15:
4940 return disas_cp15_insn (env, s, insn);
4941 default:
4942 /* Unknown coprocessor. See if the board has hooked it. */
4943 return disas_cp_insn (env, s, insn);
4944 }
4945}
4946
4947static void disas_arm_insn(CPUState * env, DisasContext *s)
4948{
4949 unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;
b26eefb6 4950 TCGv tmp;
3670669c 4951 TCGv tmp2;
6ddbc6e4 4952 TCGv tmp3;
9ee6e8bb
PB
4953
4954 insn = ldl_code(s->pc);
4955 s->pc += 4;
4956
4957 /* M variants do not implement ARM mode. */
4958 if (IS_M(env))
4959 goto illegal_op;
4960 cond = insn >> 28;
4961 if (cond == 0xf){
4962 /* Unconditional instructions. */
4963 if (((insn >> 25) & 7) == 1) {
4964 /* NEON Data processing. */
4965 if (!arm_feature(env, ARM_FEATURE_NEON))
4966 goto illegal_op;
4967
4968 if (disas_neon_data_insn(env, s, insn))
4969 goto illegal_op;
4970 return;
4971 }
4972 if ((insn & 0x0f100000) == 0x04000000) {
4973 /* NEON load/store. */
4974 if (!arm_feature(env, ARM_FEATURE_NEON))
4975 goto illegal_op;
4976
4977 if (disas_neon_ls_insn(env, s, insn))
4978 goto illegal_op;
4979 return;
4980 }
4981 if ((insn & 0x0d70f000) == 0x0550f000)
4982 return; /* PLD */
4983 else if ((insn & 0x0ffffdff) == 0x01010000) {
4984 ARCH(6);
4985 /* setend */
4986 if (insn & (1 << 9)) {
4987 /* BE8 mode not implemented. */
4988 goto illegal_op;
4989 }
4990 return;
4991 } else if ((insn & 0x0fffff00) == 0x057ff000) {
4992 switch ((insn >> 4) & 0xf) {
4993 case 1: /* clrex */
4994 ARCH(6K);
4995 gen_op_clrex();
4996 return;
4997 case 4: /* dsb */
4998 case 5: /* dmb */
4999 case 6: /* isb */
5000 ARCH(7);
5001 /* We don't emulate caches so these are a no-op. */
5002 return;
5003 default:
5004 goto illegal_op;
5005 }
5006 } else if ((insn & 0x0e5fffe0) == 0x084d0500) {
5007 /* srs */
5008 uint32_t offset;
5009 if (IS_USER(s))
5010 goto illegal_op;
5011 ARCH(6);
5012 op1 = (insn & 0x1f);
5013 if (op1 == (env->uncached_cpsr & CPSR_M)) {
5014 gen_movl_T1_reg(s, 13);
5015 } else {
5016 gen_op_movl_T1_r13_banked(op1);
5017 }
5018 i = (insn >> 23) & 3;
5019 switch (i) {
5020 case 0: offset = -4; break; /* DA */
5021 case 1: offset = -8; break; /* DB */
5022 case 2: offset = 0; break; /* IA */
5023 case 3: offset = 4; break; /* IB */
5024 default: abort();
5025 }
5026 if (offset)
5027 gen_op_addl_T1_im(offset);
5028 gen_movl_T0_reg(s, 14);
5029 gen_ldst(stl, s);
5030 gen_op_movl_T0_cpsr();
5031 gen_op_addl_T1_im(4);
5032 gen_ldst(stl, s);
5033 if (insn & (1 << 21)) {
5034 /* Base writeback. */
5035 switch (i) {
5036 case 0: offset = -8; break;
5037 case 1: offset = -4; break;
5038 case 2: offset = 4; break;
5039 case 3: offset = 0; break;
5040 default: abort();
5041 }
5042 if (offset)
5043 gen_op_addl_T1_im(offset);
5044 if (op1 == (env->uncached_cpsr & CPSR_M)) {
5045 gen_movl_reg_T1(s, 13);
5046 } else {
5047 gen_op_movl_r13_T1_banked(op1);
5048 }
5049 }
5050 } else if ((insn & 0x0e5fffe0) == 0x081d0a00) {
5051 /* rfe */
5052 uint32_t offset;
5053 if (IS_USER(s))
5054 goto illegal_op;
5055 ARCH(6);
5056 rn = (insn >> 16) & 0xf;
5057 gen_movl_T1_reg(s, rn);
5058 i = (insn >> 23) & 3;
5059 switch (i) {
5060 case 0: offset = 0; break; /* DA */
5061 case 1: offset = -4; break; /* DB */
5062 case 2: offset = 4; break; /* IA */
5063 case 3: offset = 8; break; /* IB */
5064 default: abort();
5065 }
5066 if (offset)
5067 gen_op_addl_T1_im(offset);
5068 /* Load CPSR into T2 and PC into T0. */
5069 gen_ldst(ldl, s);
5070 gen_op_movl_T2_T0();
5071 gen_op_addl_T1_im(-4);
5072 gen_ldst(ldl, s);
5073 if (insn & (1 << 21)) {
5074 /* Base writeback. */
5075 switch (i) {
5076 case 0: offset = -4; break;
5077 case 1: offset = 0; break;
5078 case 2: offset = 8; break;
5079 case 3: offset = 4; break;
5080 default: abort();
5081 }
5082 if (offset)
5083 gen_op_addl_T1_im(offset);
5084 gen_movl_reg_T1(s, rn);
5085 }
5086 gen_rfe(s);
5087 } else if ((insn & 0x0e000000) == 0x0a000000) {
5088 /* branch link and change to thumb (blx <offset>) */
5089 int32_t offset;
5090
5091 val = (uint32_t)s->pc;
5092 gen_op_movl_T0_im(val);
5093 gen_movl_reg_T0(s, 14);
5094 /* Sign-extend the 24-bit offset */
5095 offset = (((int32_t)insn) << 8) >> 8;
5096 /* offset * 4 + bit24 * 2 + (thumb bit) */
5097 val += (offset << 2) | ((insn >> 23) & 2) | 1;
5098 /* pipeline offset */
5099 val += 4;
5100 gen_op_movl_T0_im(val);
5101 gen_bx(s);
5102 return;
5103 } else if ((insn & 0x0e000f00) == 0x0c000100) {
5104 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
5105 /* iWMMXt register transfer. */
5106 if (env->cp15.c15_cpar & (1 << 1))
5107 if (!disas_iwmmxt_insn(env, s, insn))
5108 return;
5109 }
5110 } else if ((insn & 0x0fe00000) == 0x0c400000) {
5111 /* Coprocessor double register transfer. */
5112 } else if ((insn & 0x0f000010) == 0x0e000010) {
5113 /* Additional coprocessor register transfer. */
5114 } else if ((insn & 0x0ff10010) == 0x01000000) {
5115 uint32_t mask;
5116 uint32_t val;
5117 /* cps (privileged) */
5118 if (IS_USER(s))
5119 return;
5120 mask = val = 0;
5121 if (insn & (1 << 19)) {
5122 if (insn & (1 << 8))
5123 mask |= CPSR_A;
5124 if (insn & (1 << 7))
5125 mask |= CPSR_I;
5126 if (insn & (1 << 6))
5127 mask |= CPSR_F;
5128 if (insn & (1 << 18))
5129 val |= mask;
5130 }
5131 if (insn & (1 << 14)) {
5132 mask |= CPSR_M;
5133 val |= (insn & 0x1f);
5134 }
5135 if (mask) {
5136 gen_op_movl_T0_im(val);
5137 gen_set_psr_T0(s, mask, 0);
5138 }
5139 return;
5140 }
5141 goto illegal_op;
5142 }
5143 if (cond != 0xe) {
5144 /* if not always execute, we generate a conditional jump to
5145 next instruction */
5146 s->condlabel = gen_new_label();
5147 gen_test_cc[cond ^ 1](s->condlabel);
5148 s->condjmp = 1;
5149 }
5150 if ((insn & 0x0f900000) == 0x03000000) {
5151 if ((insn & (1 << 21)) == 0) {
5152 ARCH(6T2);
5153 rd = (insn >> 12) & 0xf;
5154 val = ((insn >> 4) & 0xf000) | (insn & 0xfff);
5155 if ((insn & (1 << 22)) == 0) {
5156 /* MOVW */
5157 gen_op_movl_T0_im(val);
5158 } else {
5159 /* MOVT */
5160 gen_movl_T0_reg(s, rd);
5161 gen_op_movl_T1_im(0xffff);
5162 gen_op_andl_T0_T1();
5163 gen_op_movl_T1_im(val << 16);
5164 gen_op_orl_T0_T1();
5165 }
5166 gen_movl_reg_T0(s, rd);
5167 } else {
5168 if (((insn >> 12) & 0xf) != 0xf)
5169 goto illegal_op;
5170 if (((insn >> 16) & 0xf) == 0) {
5171 gen_nop_hint(s, insn & 0xff);
5172 } else {
5173 /* CPSR = immediate */
5174 val = insn & 0xff;
5175 shift = ((insn >> 8) & 0xf) * 2;
5176 if (shift)
5177 val = (val >> shift) | (val << (32 - shift));
5178 gen_op_movl_T0_im(val);
5179 i = ((insn & (1 << 22)) != 0);
5180 if (gen_set_psr_T0(s, msr_mask(env, s, (insn >> 16) & 0xf, i), i))
5181 goto illegal_op;
5182 }
5183 }
5184 } else if ((insn & 0x0f900000) == 0x01000000
5185 && (insn & 0x00000090) != 0x00000090) {
5186 /* miscellaneous instructions */
5187 op1 = (insn >> 21) & 3;
5188 sh = (insn >> 4) & 0xf;
5189 rm = insn & 0xf;
5190 switch (sh) {
5191 case 0x0: /* move program status register */
5192 if (op1 & 1) {
5193 /* PSR = reg */
5194 gen_movl_T0_reg(s, rm);
5195 i = ((op1 & 2) != 0);
5196 if (gen_set_psr_T0(s, msr_mask(env, s, (insn >> 16) & 0xf, i), i))
5197 goto illegal_op;
5198 } else {
5199 /* reg = PSR */
5200 rd = (insn >> 12) & 0xf;
5201 if (op1 & 2) {
5202 if (IS_USER(s))
5203 goto illegal_op;
5204 gen_op_movl_T0_spsr();
5205 } else {
5206 gen_op_movl_T0_cpsr();
5207 }
5208 gen_movl_reg_T0(s, rd);
5209 }
5210 break;
5211 case 0x1:
5212 if (op1 == 1) {
5213 /* branch/exchange thumb (bx). */
5214 gen_movl_T0_reg(s, rm);
5215 gen_bx(s);
5216 } else if (op1 == 3) {
5217 /* clz */
5218 rd = (insn >> 12) & 0xf;
1497c961
PB
5219 tmp = load_reg(s, rm);
5220 gen_helper_clz(tmp, tmp);
5221 store_reg(s, rd, tmp);
9ee6e8bb
PB
5222 } else {
5223 goto illegal_op;
5224 }
5225 break;
5226 case 0x2:
5227 if (op1 == 1) {
5228 ARCH(5J); /* bxj */
5229 /* Trivial implementation equivalent to bx. */
5230 gen_movl_T0_reg(s, rm);
5231 gen_bx(s);
5232 } else {
5233 goto illegal_op;
5234 }
5235 break;
5236 case 0x3:
5237 if (op1 != 1)
5238 goto illegal_op;
5239
5240 /* branch link/exchange thumb (blx) */
5241 val = (uint32_t)s->pc;
5242 gen_op_movl_T1_im(val);
5243 gen_movl_T0_reg(s, rm);
5244 gen_movl_reg_T1(s, 14);
5245 gen_bx(s);
5246 break;
5247 case 0x5: /* saturating add/subtract */
5248 rd = (insn >> 12) & 0xf;
5249 rn = (insn >> 16) & 0xf;
5250 gen_movl_T0_reg(s, rm);
5251 gen_movl_T1_reg(s, rn);
5252 if (op1 & 2)
1497c961 5253 gen_helper_double_saturate(cpu_T[1], cpu_T[1]);
9ee6e8bb
PB
5254 if (op1 & 1)
5255 gen_op_subl_T0_T1_saturate();
5256 else
5257 gen_op_addl_T0_T1_saturate();
5258 gen_movl_reg_T0(s, rd);
5259 break;
5260 case 7: /* bkpt */
5261 gen_set_condexec(s);
5262 gen_op_movl_T0_im((long)s->pc - 4);
b26eefb6 5263 gen_set_pc_T0();
9ee6e8bb
PB
5264 gen_op_bkpt();
5265 s->is_jmp = DISAS_JUMP;
5266 break;
5267 case 0x8: /* signed multiply */
5268 case 0xa:
5269 case 0xc:
5270 case 0xe:
5271 rs = (insn >> 8) & 0xf;
5272 rn = (insn >> 12) & 0xf;
5273 rd = (insn >> 16) & 0xf;
5274 if (op1 == 1) {
5275 /* (32 * 16) >> 16 */
5276 gen_movl_T0_reg(s, rm);
5277 gen_movl_T1_reg(s, rs);
5278 if (sh & 4)
5279 gen_op_sarl_T1_im(16);
5280 else
b26eefb6 5281 gen_sxth(cpu_T[1]);
9ee6e8bb
PB
5282 gen_op_imulw_T0_T1();
5283 if ((sh & 2) == 0) {
5284 gen_movl_T1_reg(s, rn);
5285 gen_op_addl_T0_T1_setq();
5286 }
5287 gen_movl_reg_T0(s, rd);
5288 } else {
5289 /* 16 * 16 */
5290 gen_movl_T0_reg(s, rm);
5291 gen_movl_T1_reg(s, rs);
5292 gen_mulxy(sh & 2, sh & 4);
5293 if (op1 == 2) {
5294 gen_op_signbit_T1_T0();
5295 gen_op_addq_T0_T1(rn, rd);
5296 gen_movl_reg_T0(s, rn);
5297 gen_movl_reg_T1(s, rd);
5298 } else {
5299 if (op1 == 0) {
5300 gen_movl_T1_reg(s, rn);
5301 gen_op_addl_T0_T1_setq();
5302 }
5303 gen_movl_reg_T0(s, rd);
5304 }
5305 }
5306 break;
5307 default:
5308 goto illegal_op;
5309 }
5310 } else if (((insn & 0x0e000000) == 0 &&
5311 (insn & 0x00000090) != 0x90) ||
5312 ((insn & 0x0e000000) == (1 << 25))) {
5313 int set_cc, logic_cc, shiftop;
5314
5315 op1 = (insn >> 21) & 0xf;
5316 set_cc = (insn >> 20) & 1;
5317 logic_cc = table_logic_cc[op1] & set_cc;
5318
5319 /* data processing instruction */
5320 if (insn & (1 << 25)) {
5321 /* immediate operand */
5322 val = insn & 0xff;
5323 shift = ((insn >> 8) & 0xf) * 2;
5324 if (shift)
5325 val = (val >> shift) | (val << (32 - shift));
5326 gen_op_movl_T1_im(val);
5327 if (logic_cc && shift)
b26eefb6 5328 gen_set_CF_bit31(cpu_T[1]);
9ee6e8bb
PB
5329 } else {
5330 /* register */
5331 rm = (insn) & 0xf;
5332 gen_movl_T1_reg(s, rm);
5333 shiftop = (insn >> 5) & 3;
5334 if (!(insn & (1 << 4))) {
5335 shift = (insn >> 7) & 0x1f;
9a119ff6 5336 gen_arm_shift_im(cpu_T[1], shiftop, shift, logic_cc);
9ee6e8bb
PB
5337 } else {
5338 rs = (insn >> 8) & 0xf;
5339 gen_movl_T0_reg(s, rs);
5340 if (logic_cc) {
5341 gen_shift_T1_T0_cc[shiftop]();
5342 } else {
5343 gen_shift_T1_T0[shiftop]();
5344 }
5345 }
5346 }
5347 if (op1 != 0x0f && op1 != 0x0d) {
5348 rn = (insn >> 16) & 0xf;
5349 gen_movl_T0_reg(s, rn);
5350 }
5351 rd = (insn >> 12) & 0xf;
5352 switch(op1) {
5353 case 0x00:
5354 gen_op_andl_T0_T1();
5355 gen_movl_reg_T0(s, rd);
5356 if (logic_cc)
5357 gen_op_logic_T0_cc();
5358 break;
5359 case 0x01:
5360 gen_op_xorl_T0_T1();
5361 gen_movl_reg_T0(s, rd);
5362 if (logic_cc)
5363 gen_op_logic_T0_cc();
5364 break;
5365 case 0x02:
5366 if (set_cc && rd == 15) {
5367 /* SUBS r15, ... is used for exception return. */
5368 if (IS_USER(s))
5369 goto illegal_op;
5370 gen_op_subl_T0_T1_cc();
5371 gen_exception_return(s);
5372 } else {
5373 if (set_cc)
5374 gen_op_subl_T0_T1_cc();
5375 else
5376 gen_op_subl_T0_T1();
5377 gen_movl_reg_T0(s, rd);
5378 }
5379 break;
5380 case 0x03:
5381 if (set_cc)
5382 gen_op_rsbl_T0_T1_cc();
5383 else
5384 gen_op_rsbl_T0_T1();
5385 gen_movl_reg_T0(s, rd);
5386 break;
5387 case 0x04:
5388 if (set_cc)
5389 gen_op_addl_T0_T1_cc();
5390 else
5391 gen_op_addl_T0_T1();
5392 gen_movl_reg_T0(s, rd);
5393 break;
5394 case 0x05:
5395 if (set_cc)
5396 gen_op_adcl_T0_T1_cc();
5397 else
b26eefb6 5398 gen_adc_T0_T1();
9ee6e8bb
PB
5399 gen_movl_reg_T0(s, rd);
5400 break;
5401 case 0x06:
5402 if (set_cc)
5403 gen_op_sbcl_T0_T1_cc();
5404 else
3670669c 5405 gen_sbc_T0_T1();
9ee6e8bb
PB
5406 gen_movl_reg_T0(s, rd);
5407 break;
5408 case 0x07:
5409 if (set_cc)
5410 gen_op_rscl_T0_T1_cc();
5411 else
3670669c 5412 gen_rsc_T0_T1();
9ee6e8bb
PB
5413 gen_movl_reg_T0(s, rd);
5414 break;
5415 case 0x08:
5416 if (set_cc) {
5417 gen_op_andl_T0_T1();
5418 gen_op_logic_T0_cc();
5419 }
5420 break;
5421 case 0x09:
5422 if (set_cc) {
5423 gen_op_xorl_T0_T1();
5424 gen_op_logic_T0_cc();
5425 }
5426 break;
5427 case 0x0a:
5428 if (set_cc) {
5429 gen_op_subl_T0_T1_cc();
5430 }
5431 break;
5432 case 0x0b:
5433 if (set_cc) {
5434 gen_op_addl_T0_T1_cc();
5435 }
5436 break;
5437 case 0x0c:
5438 gen_op_orl_T0_T1();
5439 gen_movl_reg_T0(s, rd);
5440 if (logic_cc)
5441 gen_op_logic_T0_cc();
5442 break;
5443 case 0x0d:
5444 if (logic_cc && rd == 15) {
5445 /* MOVS r15, ... is used for exception return. */
5446 if (IS_USER(s))
5447 goto illegal_op;
5448 gen_op_movl_T0_T1();
5449 gen_exception_return(s);
5450 } else {
5451 gen_movl_reg_T1(s, rd);
5452 if (logic_cc)
5453 gen_op_logic_T1_cc();
5454 }
5455 break;
5456 case 0x0e:
5457 gen_op_bicl_T0_T1();
5458 gen_movl_reg_T0(s, rd);
5459 if (logic_cc)
5460 gen_op_logic_T0_cc();
5461 break;
5462 default:
5463 case 0x0f:
5464 gen_op_notl_T1();
5465 gen_movl_reg_T1(s, rd);
5466 if (logic_cc)
5467 gen_op_logic_T1_cc();
5468 break;
5469 }
5470 } else {
5471 /* other instructions */
5472 op1 = (insn >> 24) & 0xf;
5473 switch(op1) {
5474 case 0x0:
5475 case 0x1:
5476 /* multiplies, extra load/stores */
5477 sh = (insn >> 5) & 3;
5478 if (sh == 0) {
5479 if (op1 == 0x0) {
5480 rd = (insn >> 16) & 0xf;
5481 rn = (insn >> 12) & 0xf;
5482 rs = (insn >> 8) & 0xf;
5483 rm = (insn) & 0xf;
5484 op1 = (insn >> 20) & 0xf;
5485 switch (op1) {
5486 case 0: case 1: case 2: case 3: case 6:
5487 /* 32 bit mul */
5488 gen_movl_T0_reg(s, rs);
5489 gen_movl_T1_reg(s, rm);
5490 gen_op_mul_T0_T1();
5491 if (insn & (1 << 22)) {
5492 /* Subtract (mls) */
5493 ARCH(6T2);
5494 gen_movl_T1_reg(s, rn);
5495 gen_op_rsbl_T0_T1();
5496 } else if (insn & (1 << 21)) {
5497 /* Add */
5498 gen_movl_T1_reg(s, rn);
5499 gen_op_addl_T0_T1();
5500 }
5501 if (insn & (1 << 20))
5502 gen_op_logic_T0_cc();
5503 gen_movl_reg_T0(s, rd);
5504 break;
5505 default:
5506 /* 64 bit mul */
5507 gen_movl_T0_reg(s, rs);
5508 gen_movl_T1_reg(s, rm);
5509 if (insn & (1 << 22))
5510 gen_op_imull_T0_T1();
5511 else
5512 gen_op_mull_T0_T1();
5513 if (insn & (1 << 21)) /* mult accumulate */
5514 gen_op_addq_T0_T1(rn, rd);
5515 if (!(insn & (1 << 23))) { /* double accumulate */
5516 ARCH(6);
5517 gen_op_addq_lo_T0_T1(rn);
5518 gen_op_addq_lo_T0_T1(rd);
5519 }
5520 if (insn & (1 << 20))
5521 gen_op_logicq_cc();
5522 gen_movl_reg_T0(s, rn);
5523 gen_movl_reg_T1(s, rd);
5524 break;
5525 }
5526 } else {
5527 rn = (insn >> 16) & 0xf;
5528 rd = (insn >> 12) & 0xf;
5529 if (insn & (1 << 23)) {
5530 /* load/store exclusive */
5531 gen_movl_T1_reg(s, rn);
5532 if (insn & (1 << 20)) {
5533 gen_ldst(ldlex, s);
5534 } else {
5535 rm = insn & 0xf;
5536 gen_movl_T0_reg(s, rm);
5537 gen_ldst(stlex, s);
5538 }
5539 gen_movl_reg_T0(s, rd);
5540 } else {
5541 /* SWP instruction */
5542 rm = (insn) & 0xf;
5543
5544 gen_movl_T0_reg(s, rm);
5545 gen_movl_T1_reg(s, rn);
5546 if (insn & (1 << 22)) {
5547 gen_ldst(swpb, s);
5548 } else {
5549 gen_ldst(swpl, s);
5550 }
5551 gen_movl_reg_T0(s, rd);
5552 }
5553 }
5554 } else {
5555 int address_offset;
5556 int load;
5557 /* Misc load/store */
5558 rn = (insn >> 16) & 0xf;
5559 rd = (insn >> 12) & 0xf;
5560 gen_movl_T1_reg(s, rn);
5561 if (insn & (1 << 24))
5562 gen_add_datah_offset(s, insn, 0);
5563 address_offset = 0;
5564 if (insn & (1 << 20)) {
5565 /* load */
5566 switch(sh) {
5567 case 1:
5568 gen_ldst(lduw, s);
5569 break;
5570 case 2:
5571 gen_ldst(ldsb, s);
5572 break;
5573 default:
5574 case 3:
5575 gen_ldst(ldsw, s);
5576 break;
5577 }
5578 load = 1;
5579 } else if (sh & 2) {
5580 /* doubleword */
5581 if (sh & 1) {
5582 /* store */
5583 gen_movl_T0_reg(s, rd);
5584 gen_ldst(stl, s);
5585 gen_op_addl_T1_im(4);
5586 gen_movl_T0_reg(s, rd + 1);
5587 gen_ldst(stl, s);
5588 load = 0;
5589 } else {
5590 /* load */
5591 gen_ldst(ldl, s);
5592 gen_movl_reg_T0(s, rd);
5593 gen_op_addl_T1_im(4);
5594 gen_ldst(ldl, s);
5595 rd++;
5596 load = 1;
5597 }
5598 address_offset = -4;
5599 } else {
5600 /* store */
5601 gen_movl_T0_reg(s, rd);
5602 gen_ldst(stw, s);
5603 load = 0;
5604 }
5605 /* Perform base writeback before the loaded value to
5606 ensure correct behavior with overlapping index registers.
5607 ldrd with base writeback is is undefined if the
5608 destination and index registers overlap. */
5609 if (!(insn & (1 << 24))) {
5610 gen_add_datah_offset(s, insn, address_offset);
5611 gen_movl_reg_T1(s, rn);
5612 } else if (insn & (1 << 21)) {
5613 if (address_offset)
5614 gen_op_addl_T1_im(address_offset);
5615 gen_movl_reg_T1(s, rn);
5616 }
5617 if (load) {
5618 /* Complete the load. */
5619 gen_movl_reg_T0(s, rd);
5620 }
5621 }
5622 break;
5623 case 0x4:
5624 case 0x5:
5625 goto do_ldst;
5626 case 0x6:
5627 case 0x7:
5628 if (insn & (1 << 4)) {
5629 ARCH(6);
5630 /* Armv6 Media instructions. */
5631 rm = insn & 0xf;
5632 rn = (insn >> 16) & 0xf;
2c0262af 5633 rd = (insn >> 12) & 0xf;
9ee6e8bb
PB
5634 rs = (insn >> 8) & 0xf;
5635 switch ((insn >> 23) & 3) {
5636 case 0: /* Parallel add/subtract. */
5637 op1 = (insn >> 20) & 7;
6ddbc6e4
PB
5638 tmp = load_reg(s, rn);
5639 tmp2 = load_reg(s, rm);
9ee6e8bb
PB
5640 sh = (insn >> 5) & 7;
5641 if ((op1 & 3) == 0 || sh == 5 || sh == 6)
5642 goto illegal_op;
6ddbc6e4
PB
5643 gen_arm_parallel_addsub(op1, sh, tmp, tmp2);
5644 dead_tmp(tmp2);
5645 store_reg(s, rd, tmp);
9ee6e8bb
PB
5646 break;
5647 case 1:
5648 if ((insn & 0x00700020) == 0) {
5649 /* Hafword pack. */
3670669c
PB
5650 tmp = load_reg(s, rn);
5651 tmp2 = load_reg(s, rm);
9ee6e8bb
PB
5652 shift = (insn >> 7) & 0x1f;
5653 if (shift)
3670669c
PB
5654 tcg_gen_shli_i32(tmp2, tmp2, shift);
5655 if (insn & (1 << 6)) {
5656 /* pkhtb */
5657 tcg_gen_andi_i32(tmp, tmp, 0xffff0000);
5658 tcg_gen_andi_i32(tmp2, tmp2, 0xffff);
5659 } else {
5660 /* pkhbt */
5661 tcg_gen_andi_i32(tmp, tmp, 0xffff);
5662 tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000);
5663 }
5664 tcg_gen_or_i32(tmp, tmp, tmp2);
5665 store_reg(s, rd, tmp);
9ee6e8bb
PB
5666 } else if ((insn & 0x00200020) == 0x00200000) {
5667 /* [us]sat */
6ddbc6e4 5668 tmp = load_reg(s, rm);
9ee6e8bb
PB
5669 shift = (insn >> 7) & 0x1f;
5670 if (insn & (1 << 6)) {
5671 if (shift == 0)
5672 shift = 31;
6ddbc6e4 5673 tcg_gen_sari_i32(tmp, tmp, shift);
9ee6e8bb 5674 } else {
6ddbc6e4 5675 tcg_gen_shli_i32(tmp, tmp, shift);
9ee6e8bb
PB
5676 }
5677 sh = (insn >> 16) & 0x1f;
5678 if (sh != 0) {
5679 if (insn & (1 << 22))
6ddbc6e4 5680 gen_helper_usat(tmp, tmp, tcg_const_i32(sh));
9ee6e8bb 5681 else
6ddbc6e4 5682 gen_helper_ssat(tmp, tmp, tcg_const_i32(sh));
9ee6e8bb 5683 }
6ddbc6e4 5684 store_reg(s, rd, tmp);
9ee6e8bb
PB
5685 } else if ((insn & 0x00300fe0) == 0x00200f20) {
5686 /* [us]sat16 */
6ddbc6e4 5687 tmp = load_reg(s, rm);
9ee6e8bb
PB
5688 sh = (insn >> 16) & 0x1f;
5689 if (sh != 0) {
5690 if (insn & (1 << 22))
6ddbc6e4 5691 gen_helper_usat16(tmp, tmp, tcg_const_i32(sh));
9ee6e8bb 5692 else
6ddbc6e4 5693 gen_helper_ssat16(tmp, tmp, tcg_const_i32(sh));
9ee6e8bb 5694 }
6ddbc6e4 5695 store_reg(s, rd, tmp);
9ee6e8bb
PB
5696 } else if ((insn & 0x00700fe0) == 0x00000fa0) {
5697 /* Select bytes. */
6ddbc6e4
PB
5698 tmp = load_reg(s, rn);
5699 tmp2 = load_reg(s, rm);
5700 tmp3 = new_tmp();
5701 tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUState, GE));
5702 gen_helper_sel_flags(tmp, tmp3, tmp, tmp2);
5703 dead_tmp(tmp3);
5704 dead_tmp(tmp2);
5705 store_reg(s, rd, tmp);
9ee6e8bb
PB
5706 } else if ((insn & 0x000003e0) == 0x00000060) {
5707 gen_movl_T1_reg(s, rm);
5708 shift = (insn >> 10) & 3;
5709 /* ??? In many cases it's not neccessary to do a
5710 rotate, a shift is sufficient. */
5711 if (shift != 0)
5712 gen_op_rorl_T1_im(shift * 8);
5713 op1 = (insn >> 20) & 7;
5714 switch (op1) {
b26eefb6
PB
5715 case 0: gen_sxtb16(cpu_T[1]); break;
5716 case 2: gen_sxtb(cpu_T[1]); break;
5717 case 3: gen_sxth(cpu_T[1]); break;
5718 case 4: gen_uxtb16(cpu_T[1]); break;
5719 case 6: gen_uxtb(cpu_T[1]); break;
5720 case 7: gen_uxth(cpu_T[1]); break;
9ee6e8bb
PB
5721 default: goto illegal_op;
5722 }
5723 if (rn != 15) {
b26eefb6 5724 tmp = load_reg(s, rn);
9ee6e8bb 5725 if ((op1 & 3) == 0) {
b26eefb6 5726 gen_add16(cpu_T[1], tmp);
9ee6e8bb 5727 } else {
b26eefb6
PB
5728 tcg_gen_add_i32(cpu_T[1], cpu_T[1], tmp);
5729 dead_tmp(tmp);
9ee6e8bb
PB
5730 }
5731 }
5732 gen_movl_reg_T1(s, rd);
5733 } else if ((insn & 0x003f0f60) == 0x003f0f20) {
5734 /* rev */
5735 gen_movl_T0_reg(s, rm);
5736 if (insn & (1 << 22)) {
5737 if (insn & (1 << 7)) {
3670669c 5738 gen_revsh(cpu_T[0]);
9ee6e8bb
PB
5739 } else {
5740 ARCH(6T2);
3670669c 5741 gen_helper_rbit(cpu_T[0], cpu_T[0]);
9ee6e8bb
PB
5742 }
5743 } else {
5744 if (insn & (1 << 7))
3670669c 5745 gen_rev16(cpu_T[0]);
9ee6e8bb
PB
5746 else
5747 gen_op_rev_T0();
5748 }
5749 gen_movl_reg_T0(s, rd);
5750 } else {
5751 goto illegal_op;
5752 }
5753 break;
5754 case 2: /* Multiplies (Type 3). */
5755 gen_movl_T0_reg(s, rm);
5756 gen_movl_T1_reg(s, rs);
5757 if (insn & (1 << 20)) {
5758 /* Signed multiply most significant [accumulate]. */
5759 gen_op_imull_T0_T1();
5760 if (insn & (1 << 5))
5761 gen_op_roundqd_T0_T1();
5762 else
5763 gen_op_movl_T0_T1();
5764 if (rn != 15) {
5765 gen_movl_T1_reg(s, rn);
5766 if (insn & (1 << 6)) {
5767 gen_op_addl_T0_T1();
5768 } else {
5769 gen_op_rsbl_T0_T1();
5770 }
5771 }
5772 gen_movl_reg_T0(s, rd);
5773 } else {
5774 if (insn & (1 << 5))
8f01245e 5775 gen_swap_half(cpu_T[1]);
3670669c 5776 gen_smul_dual(cpu_T[0], cpu_T[1]);
9ee6e8bb
PB
5777 if (insn & (1 << 22)) {
5778 if (insn & (1 << 6)) {
5779 /* smlald */
5780 gen_op_addq_T0_T1_dual(rn, rd);
5781 } else {
5782 /* smlsld */
5783 gen_op_subq_T0_T1_dual(rn, rd);
5784 }
5785 } else {
5786 /* This addition cannot overflow. */
5787 if (insn & (1 << 6)) {
5788 /* sm[ul]sd */
5789 gen_op_subl_T0_T1();
5790 } else {
5791 /* sm[ul]ad */
5792 gen_op_addl_T0_T1();
5793 }
5794 if (rn != 15)
5795 {
5796 gen_movl_T1_reg(s, rn);
5797 gen_op_addl_T0_T1_setq();
5798 }
5799 gen_movl_reg_T0(s, rd);
5800 }
5801 }
5802 break;
5803 case 3:
5804 op1 = ((insn >> 17) & 0x38) | ((insn >> 5) & 7);
5805 switch (op1) {
5806 case 0: /* Unsigned sum of absolute differences. */
6ddbc6e4
PB
5807 ARCH(6);
5808 tmp = load_reg(s, rm);
5809 tmp2 = load_reg(s, rs);
5810 gen_helper_usad8(tmp, tmp, tmp2);
5811 dead_tmp(tmp2);
9ee6e8bb 5812 if (rn != 15) {
6ddbc6e4
PB
5813 tmp2 = load_reg(s, rn);
5814 tcg_gen_add_i32(tmp, tmp, tmp2);
5815 dead_tmp(tmp2);
9ee6e8bb 5816 }
6ddbc6e4 5817 store_reg(s, rd, tmp);
9ee6e8bb
PB
5818 break;
5819 case 0x20: case 0x24: case 0x28: case 0x2c:
5820 /* Bitfield insert/clear. */
5821 ARCH(6T2);
5822 shift = (insn >> 7) & 0x1f;
5823 i = (insn >> 16) & 0x1f;
5824 i = i + 1 - shift;
5825 if (rm == 15) {
5826 gen_op_movl_T1_im(0);
5827 } else {
5828 gen_movl_T1_reg(s, rm);
5829 }
5830 if (i != 32) {
5831 gen_movl_T0_reg(s, rd);
3670669c
PB
5832 gen_bfi(cpu_T[1], cpu_T[0], cpu_T[1],
5833 shift, ((1u << i) - 1) << shift);
9ee6e8bb
PB
5834 }
5835 gen_movl_reg_T1(s, rd);
5836 break;
5837 case 0x12: case 0x16: case 0x1a: case 0x1e: /* sbfx */
5838 case 0x32: case 0x36: case 0x3a: case 0x3e: /* ubfx */
5839 gen_movl_T1_reg(s, rm);
5840 shift = (insn >> 7) & 0x1f;
5841 i = ((insn >> 16) & 0x1f) + 1;
5842 if (shift + i > 32)
5843 goto illegal_op;
5844 if (i < 32) {
5845 if (op1 & 0x20) {
3670669c 5846 gen_ubfx(cpu_T[1], shift, (1u << i) - 1);
9ee6e8bb 5847 } else {
3670669c 5848 gen_sbfx(cpu_T[1], shift, i);
9ee6e8bb
PB
5849 }
5850 }
5851 gen_movl_reg_T1(s, rd);
5852 break;
5853 default:
5854 goto illegal_op;
5855 }
5856 break;
5857 }
5858 break;
5859 }
5860 do_ldst:
5861 /* Check for undefined extension instructions
5862 * per the ARM Bible IE:
5863 * xxxx 0111 1111 xxxx xxxx xxxx 1111 xxxx
5864 */
5865 sh = (0xf << 20) | (0xf << 4);
5866 if (op1 == 0x7 && ((insn & sh) == sh))
5867 {
5868 goto illegal_op;
5869 }
5870 /* load/store byte/word */
5871 rn = (insn >> 16) & 0xf;
5872 rd = (insn >> 12) & 0xf;
5873 gen_movl_T1_reg(s, rn);
5874 i = (IS_USER(s) || (insn & 0x01200000) == 0x00200000);
5875 if (insn & (1 << 24))
5876 gen_add_data_offset(s, insn);
5877 if (insn & (1 << 20)) {
5878 /* load */
5879 s->is_mem = 1;
5880#if defined(CONFIG_USER_ONLY)
5881 if (insn & (1 << 22))
5882 gen_op_ldub_raw();
5883 else
5884 gen_op_ldl_raw();
5885#else
5886 if (insn & (1 << 22)) {
5887 if (i)
5888 gen_op_ldub_user();
5889 else
5890 gen_op_ldub_kernel();
5891 } else {
5892 if (i)
5893 gen_op_ldl_user();
5894 else
5895 gen_op_ldl_kernel();
5896 }
5897#endif
5898 } else {
5899 /* store */
5900 gen_movl_T0_reg(s, rd);
5901#if defined(CONFIG_USER_ONLY)
5902 if (insn & (1 << 22))
5903 gen_op_stb_raw();
5904 else
5905 gen_op_stl_raw();
5906#else
5907 if (insn & (1 << 22)) {
5908 if (i)
5909 gen_op_stb_user();
5910 else
5911 gen_op_stb_kernel();
5912 } else {
5913 if (i)
5914 gen_op_stl_user();
5915 else
5916 gen_op_stl_kernel();
5917 }
5918#endif
5919 }
5920 if (!(insn & (1 << 24))) {
5921 gen_add_data_offset(s, insn);
5922 gen_movl_reg_T1(s, rn);
5923 } else if (insn & (1 << 21))
5924 gen_movl_reg_T1(s, rn); {
5925 }
5926 if (insn & (1 << 20)) {
5927 /* Complete the load. */
5928 if (rd == 15)
5929 gen_bx(s);
5930 else
5931 gen_movl_reg_T0(s, rd);
5932 }
5933 break;
5934 case 0x08:
5935 case 0x09:
5936 {
5937 int j, n, user, loaded_base;
5938 /* load/store multiple words */
5939 /* XXX: store correct base if write back */
5940 user = 0;
5941 if (insn & (1 << 22)) {
5942 if (IS_USER(s))
5943 goto illegal_op; /* only usable in supervisor mode */
5944
5945 if ((insn & (1 << 15)) == 0)
5946 user = 1;
5947 }
5948 rn = (insn >> 16) & 0xf;
5949 gen_movl_T1_reg(s, rn);
5950
5951 /* compute total size */
5952 loaded_base = 0;
5953 n = 0;
5954 for(i=0;i<16;i++) {
5955 if (insn & (1 << i))
5956 n++;
5957 }
5958 /* XXX: test invalid n == 0 case ? */
5959 if (insn & (1 << 23)) {
5960 if (insn & (1 << 24)) {
5961 /* pre increment */
5962 gen_op_addl_T1_im(4);
5963 } else {
5964 /* post increment */
5965 }
5966 } else {
5967 if (insn & (1 << 24)) {
5968 /* pre decrement */
5969 gen_op_addl_T1_im(-(n * 4));
5970 } else {
5971 /* post decrement */
5972 if (n != 1)
5973 gen_op_addl_T1_im(-((n - 1) * 4));
5974 }
5975 }
5976 j = 0;
5977 for(i=0;i<16;i++) {
5978 if (insn & (1 << i)) {
5979 if (insn & (1 << 20)) {
5980 /* load */
5981 gen_ldst(ldl, s);
5982 if (i == 15) {
5983 gen_bx(s);
5984 } else if (user) {
5985 gen_op_movl_user_T0(i);
5986 } else if (i == rn) {
5987 gen_op_movl_T2_T0();
5988 loaded_base = 1;
5989 } else {
5990 gen_movl_reg_T0(s, i);
5991 }
5992 } else {
5993 /* store */
5994 if (i == 15) {
5995 /* special case: r15 = PC + 8 */
5996 val = (long)s->pc + 4;
b26eefb6 5997 gen_op_movl_T0_im(val);
9ee6e8bb
PB
5998 } else if (user) {
5999 gen_op_movl_T0_user(i);
6000 } else {
6001 gen_movl_T0_reg(s, i);
6002 }
6003 gen_ldst(stl, s);
6004 }
6005 j++;
6006 /* no need to add after the last transfer */
6007 if (j != n)
6008 gen_op_addl_T1_im(4);
6009 }
6010 }
6011 if (insn & (1 << 21)) {
6012 /* write back */
6013 if (insn & (1 << 23)) {
6014 if (insn & (1 << 24)) {
6015 /* pre increment */
6016 } else {
6017 /* post increment */
6018 gen_op_addl_T1_im(4);
6019 }
6020 } else {
6021 if (insn & (1 << 24)) {
6022 /* pre decrement */
6023 if (n != 1)
6024 gen_op_addl_T1_im(-((n - 1) * 4));
6025 } else {
6026 /* post decrement */
6027 gen_op_addl_T1_im(-(n * 4));
6028 }
6029 }
6030 gen_movl_reg_T1(s, rn);
6031 }
6032 if (loaded_base) {
6033 gen_op_movl_T0_T2();
6034 gen_movl_reg_T0(s, rn);
6035 }
6036 if ((insn & (1 << 22)) && !user) {
6037 /* Restore CPSR from SPSR. */
6038 gen_op_movl_T0_spsr();
6039 gen_op_movl_cpsr_T0(0xffffffff);
6040 s->is_jmp = DISAS_UPDATE;
6041 }
6042 }
6043 break;
6044 case 0xa:
6045 case 0xb:
6046 {
6047 int32_t offset;
6048
6049 /* branch (and link) */
6050 val = (int32_t)s->pc;
6051 if (insn & (1 << 24)) {
6052 gen_op_movl_T0_im(val);
b26eefb6 6053 gen_movl_reg_T0(s, 14);
9ee6e8bb
PB
6054 }
6055 offset = (((int32_t)insn << 8) >> 8);
6056 val += (offset << 2) + 4;
6057 gen_jmp(s, val);
6058 }
6059 break;
6060 case 0xc:
6061 case 0xd:
6062 case 0xe:
6063 /* Coprocessor. */
6064 if (disas_coproc_insn(env, s, insn))
6065 goto illegal_op;
6066 break;
6067 case 0xf:
6068 /* swi */
6069 gen_op_movl_T0_im((long)s->pc);
b26eefb6 6070 gen_set_pc_T0();
9ee6e8bb
PB
6071 s->is_jmp = DISAS_SWI;
6072 break;
6073 default:
6074 illegal_op:
6075 gen_set_condexec(s);
6076 gen_op_movl_T0_im((long)s->pc - 4);
b26eefb6 6077 gen_set_pc_T0();
9ee6e8bb
PB
6078 gen_op_undef_insn();
6079 s->is_jmp = DISAS_JUMP;
6080 break;
6081 }
6082 }
6083}
6084
6085/* Return true if this is a Thumb-2 logical op. */
6086static int
6087thumb2_logic_op(int op)
6088{
6089 return (op < 8);
6090}
6091
6092/* Generate code for a Thumb-2 data processing operation. If CONDS is nonzero
6093 then set condition code flags based on the result of the operation.
6094 If SHIFTER_OUT is nonzero then set the carry flag for logical operations
6095 to the high bit of T1.
6096 Returns zero if the opcode is valid. */
6097
6098static int
6099gen_thumb2_data_op(DisasContext *s, int op, int conds, uint32_t shifter_out)
6100{
6101 int logic_cc;
6102
6103 logic_cc = 0;
6104 switch (op) {
6105 case 0: /* and */
6106 gen_op_andl_T0_T1();
6107 logic_cc = conds;
6108 break;
6109 case 1: /* bic */
6110 gen_op_bicl_T0_T1();
6111 logic_cc = conds;
6112 break;
6113 case 2: /* orr */
6114 gen_op_orl_T0_T1();
6115 logic_cc = conds;
6116 break;
6117 case 3: /* orn */
6118 gen_op_notl_T1();
6119 gen_op_orl_T0_T1();
6120 logic_cc = conds;
6121 break;
6122 case 4: /* eor */
6123 gen_op_xorl_T0_T1();
6124 logic_cc = conds;
6125 break;
6126 case 8: /* add */
6127 if (conds)
6128 gen_op_addl_T0_T1_cc();
6129 else
6130 gen_op_addl_T0_T1();
6131 break;
6132 case 10: /* adc */
6133 if (conds)
6134 gen_op_adcl_T0_T1_cc();
6135 else
b26eefb6 6136 gen_adc_T0_T1();
9ee6e8bb
PB
6137 break;
6138 case 11: /* sbc */
6139 if (conds)
6140 gen_op_sbcl_T0_T1_cc();
6141 else
3670669c 6142 gen_sbc_T0_T1();
9ee6e8bb
PB
6143 break;
6144 case 13: /* sub */
6145 if (conds)
6146 gen_op_subl_T0_T1_cc();
6147 else
6148 gen_op_subl_T0_T1();
6149 break;
6150 case 14: /* rsb */
6151 if (conds)
6152 gen_op_rsbl_T0_T1_cc();
6153 else
6154 gen_op_rsbl_T0_T1();
6155 break;
6156 default: /* 5, 6, 7, 9, 12, 15. */
6157 return 1;
6158 }
6159 if (logic_cc) {
6160 gen_op_logic_T0_cc();
6161 if (shifter_out)
b26eefb6 6162 gen_set_CF_bit31(cpu_T[1]);
9ee6e8bb
PB
6163 }
6164 return 0;
6165}
6166
6167/* Translate a 32-bit thumb instruction. Returns nonzero if the instruction
6168 is not legal. */
6169static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
6170{
6171 uint32_t insn, imm, shift, offset, addr;
6172 uint32_t rd, rn, rm, rs;
b26eefb6 6173 TCGv tmp;
6ddbc6e4
PB
6174 TCGv tmp2;
6175 TCGv tmp3;
9ee6e8bb
PB
6176 int op;
6177 int shiftop;
6178 int conds;
6179 int logic_cc;
6180
6181 if (!(arm_feature(env, ARM_FEATURE_THUMB2)
6182 || arm_feature (env, ARM_FEATURE_M))) {
6183 /* Thumb-1 cores may need to tread bl and blx as a pair of
6184 16-bit instructions to get correct prefetch abort behavior. */
6185 insn = insn_hw1;
6186 if ((insn & (1 << 12)) == 0) {
6187 /* Second half of blx. */
6188 offset = ((insn & 0x7ff) << 1);
6189 gen_movl_T0_reg(s, 14);
6190 gen_op_movl_T1_im(offset);
6191 gen_op_addl_T0_T1();
6192 gen_op_movl_T1_im(0xfffffffc);
6193 gen_op_andl_T0_T1();
6194
6195 addr = (uint32_t)s->pc;
6196 gen_op_movl_T1_im(addr | 1);
6197 gen_movl_reg_T1(s, 14);
6198 gen_bx(s);
6199 return 0;
6200 }
6201 if (insn & (1 << 11)) {
6202 /* Second half of bl. */
6203 offset = ((insn & 0x7ff) << 1) | 1;
6204 gen_movl_T0_reg(s, 14);
6205 gen_op_movl_T1_im(offset);
6206 gen_op_addl_T0_T1();
6207
6208 addr = (uint32_t)s->pc;
6209 gen_op_movl_T1_im(addr | 1);
6210 gen_movl_reg_T1(s, 14);
6211 gen_bx(s);
6212 return 0;
6213 }
6214 if ((s->pc & ~TARGET_PAGE_MASK) == 0) {
6215 /* Instruction spans a page boundary. Implement it as two
6216 16-bit instructions in case the second half causes an
6217 prefetch abort. */
6218 offset = ((int32_t)insn << 21) >> 9;
6219 addr = s->pc + 2 + offset;
6220 gen_op_movl_T0_im(addr);
6221 gen_movl_reg_T0(s, 14);
6222 return 0;
6223 }
6224 /* Fall through to 32-bit decode. */
6225 }
6226
6227 insn = lduw_code(s->pc);
6228 s->pc += 2;
6229 insn |= (uint32_t)insn_hw1 << 16;
6230
6231 if ((insn & 0xf800e800) != 0xf000e800) {
6232 ARCH(6T2);
6233 }
6234
6235 rn = (insn >> 16) & 0xf;
6236 rs = (insn >> 12) & 0xf;
6237 rd = (insn >> 8) & 0xf;
6238 rm = insn & 0xf;
6239 switch ((insn >> 25) & 0xf) {
6240 case 0: case 1: case 2: case 3:
6241 /* 16-bit instructions. Should never happen. */
6242 abort();
6243 case 4:
6244 if (insn & (1 << 22)) {
6245 /* Other load/store, table branch. */
6246 if (insn & 0x01200000) {
6247 /* Load/store doubleword. */
6248 if (rn == 15) {
6249 gen_op_movl_T1_im(s->pc & ~3);
6250 } else {
6251 gen_movl_T1_reg(s, rn);
6252 }
6253 offset = (insn & 0xff) * 4;
6254 if ((insn & (1 << 23)) == 0)
6255 offset = -offset;
6256 if (insn & (1 << 24)) {
6257 gen_op_addl_T1_im(offset);
6258 offset = 0;
6259 }
6260 if (insn & (1 << 20)) {
6261 /* ldrd */
6262 gen_ldst(ldl, s);
6263 gen_movl_reg_T0(s, rs);
6264 gen_op_addl_T1_im(4);
6265 gen_ldst(ldl, s);
6266 gen_movl_reg_T0(s, rd);
6267 } else {
6268 /* strd */
6269 gen_movl_T0_reg(s, rs);
6270 gen_ldst(stl, s);
6271 gen_op_addl_T1_im(4);
6272 gen_movl_T0_reg(s, rd);
6273 gen_ldst(stl, s);
6274 }
6275 if (insn & (1 << 21)) {
6276 /* Base writeback. */
6277 if (rn == 15)
6278 goto illegal_op;
6279 gen_op_addl_T1_im(offset - 4);
6280 gen_movl_reg_T1(s, rn);
6281 }
6282 } else if ((insn & (1 << 23)) == 0) {
6283 /* Load/store exclusive word. */
6284 gen_movl_T0_reg(s, rd);
2c0262af 6285 gen_movl_T1_reg(s, rn);
2c0262af 6286 if (insn & (1 << 20)) {
9ee6e8bb
PB
6287 gen_ldst(ldlex, s);
6288 } else {
6289 gen_ldst(stlex, s);
6290 }
6291 gen_movl_reg_T0(s, rd);
6292 } else if ((insn & (1 << 6)) == 0) {
6293 /* Table Branch. */
6294 if (rn == 15) {
6295 gen_op_movl_T1_im(s->pc);
6296 } else {
6297 gen_movl_T1_reg(s, rn);
6298 }
b26eefb6
PB
6299 tmp = load_reg(s, rm);
6300 tcg_gen_add_i32(cpu_T[1], cpu_T[1], tmp);
9ee6e8bb
PB
6301 if (insn & (1 << 4)) {
6302 /* tbh */
b26eefb6
PB
6303 tcg_gen_add_i32(cpu_T[1], cpu_T[1], tmp);
6304 dead_tmp(tmp);
9ee6e8bb
PB
6305 gen_ldst(lduw, s);
6306 } else { /* tbb */
b26eefb6 6307 dead_tmp(tmp);
9ee6e8bb
PB
6308 gen_ldst(ldub, s);
6309 }
8f01245e
PB
6310 tcg_gen_shli_i32(cpu_T[0], cpu_T[0], 1);
6311 tcg_gen_addi_i32(cpu_T[0], cpu_T[0], s->pc);
6312 gen_movl_reg_T0(s, 15);
9ee6e8bb
PB
6313 } else {
6314 /* Load/store exclusive byte/halfword/doubleword. */
6315 op = (insn >> 4) & 0x3;
6316 gen_movl_T1_reg(s, rn);
6317 if (insn & (1 << 20)) {
6318 switch (op) {
6319 case 0:
6320 gen_ldst(ldbex, s);
6321 break;
2c0262af 6322 case 1:
9ee6e8bb 6323 gen_ldst(ldwex, s);
2c0262af 6324 break;
9ee6e8bb
PB
6325 case 3:
6326 gen_ldst(ldqex, s);
6327 gen_movl_reg_T1(s, rd);
2c0262af
FB
6328 break;
6329 default:
9ee6e8bb
PB
6330 goto illegal_op;
6331 }
6332 gen_movl_reg_T0(s, rs);
6333 } else {
6334 gen_movl_T0_reg(s, rs);
6335 switch (op) {
6336 case 0:
6337 gen_ldst(stbex, s);
6338 break;
6339 case 1:
6340 gen_ldst(stwex, s);
6341 break;
2c0262af 6342 case 3:
9ee6e8bb
PB
6343 gen_movl_T2_reg(s, rd);
6344 gen_ldst(stqex, s);
2c0262af 6345 break;
9ee6e8bb
PB
6346 default:
6347 goto illegal_op;
2c0262af 6348 }
9ee6e8bb
PB
6349 gen_movl_reg_T0(s, rm);
6350 }
6351 }
6352 } else {
6353 /* Load/store multiple, RFE, SRS. */
6354 if (((insn >> 23) & 1) == ((insn >> 24) & 1)) {
6355 /* Not available in user mode. */
6356 if (!IS_USER(s))
6357 goto illegal_op;
6358 if (insn & (1 << 20)) {
6359 /* rfe */
6360 gen_movl_T1_reg(s, rn);
6361 if (insn & (1 << 24)) {
99c475ab 6362 gen_op_addl_T1_im(4);
9ee6e8bb
PB
6363 } else {
6364 gen_op_addl_T1_im(-4);
6365 }
6366 /* Load CPSR into T2 and PC into T0. */
6367 gen_ldst(ldl, s);
6368 gen_op_movl_T2_T0();
6369 gen_op_addl_T1_im(-4);
6370 gen_ldst(ldl, s);
6371 if (insn & (1 << 21)) {
6372 /* Base writeback. */
6373 if (insn & (1 << 24))
6374 gen_op_addl_T1_im(8);
6375 gen_movl_reg_T1(s, rn);
6376 }
6377 gen_rfe(s);
6378 } else {
6379 /* srs */
6380 op = (insn & 0x1f);
6381 if (op == (env->uncached_cpsr & CPSR_M)) {
6382 gen_movl_T1_reg(s, 13);
6383 } else {
6384 gen_op_movl_T1_r13_banked(op);
6385 }
6386 if ((insn & (1 << 24)) == 0) {
6387 gen_op_addl_T1_im(-8);
6388 }
6389 gen_movl_T0_reg(s, 14);
6390 gen_ldst(stl, s);
6391 gen_op_movl_T0_cpsr();
6392 gen_op_addl_T1_im(4);
6393 gen_ldst(stl, s);
6394 if (insn & (1 << 21)) {
6395 if ((insn & (1 << 24)) == 0) {
6396 gen_op_addl_T1_im(-4);
6397 } else {
6398 gen_op_addl_T1_im(4);
6399 }
6400 if (op == (env->uncached_cpsr & CPSR_M)) {
6401 gen_movl_reg_T1(s, 13);
6402 } else {
6403 gen_op_movl_r13_T1_banked(op);
6404 }
6405 }
6406 }
6407 } else {
6408 int i;
6409 /* Load/store multiple. */
6410 gen_movl_T1_reg(s, rn);
6411 offset = 0;
6412 for (i = 0; i < 16; i++) {
6413 if (insn & (1 << i))
6414 offset += 4;
6415 }
6416 if (insn & (1 << 24)) {
6417 gen_op_addl_T1_im(-offset);
6418 }
6419
6420 for (i = 0; i < 16; i++) {
6421 if ((insn & (1 << i)) == 0)
6422 continue;
6423 if (insn & (1 << 20)) {
6424 /* Load. */
6425 gen_ldst(ldl, s);
6426 if (i == 15) {
6427 gen_bx(s);
6428 } else {
6429 gen_movl_reg_T0(s, i);
6430 }
6431 } else {
6432 /* Store. */
6433 gen_movl_T0_reg(s, i);
b5ff1b31 6434 gen_ldst(stl, s);
9ee6e8bb
PB
6435 }
6436 gen_op_addl_T1_im(4);
6437 }
6438 if (insn & (1 << 21)) {
6439 /* Base register writeback. */
6440 if (insn & (1 << 24)) {
6441 gen_op_addl_T1_im(-offset);
6442 }
6443 /* Fault if writeback register is in register list. */
6444 if (insn & (1 << rn))
6445 goto illegal_op;
6446 gen_movl_reg_T1(s, rn);
6447 }
6448 }
6449 }
6450 break;
6451 case 5: /* Data processing register constant shift. */
6452 if (rn == 15)
6453 gen_op_movl_T0_im(0);
6454 else
6455 gen_movl_T0_reg(s, rn);
6456 gen_movl_T1_reg(s, rm);
6457 op = (insn >> 21) & 0xf;
6458 shiftop = (insn >> 4) & 3;
6459 shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c);
6460 conds = (insn & (1 << 20)) != 0;
6461 logic_cc = (conds && thumb2_logic_op(op));
9a119ff6 6462 gen_arm_shift_im(cpu_T[1], shiftop, shift, logic_cc);
9ee6e8bb
PB
6463 if (gen_thumb2_data_op(s, op, conds, 0))
6464 goto illegal_op;
6465 if (rd != 15)
6466 gen_movl_reg_T0(s, rd);
6467 break;
6468 case 13: /* Misc data processing. */
6469 op = ((insn >> 22) & 6) | ((insn >> 7) & 1);
6470 if (op < 4 && (insn & 0xf000) != 0xf000)
6471 goto illegal_op;
6472 switch (op) {
6473 case 0: /* Register controlled shift. */
6474 gen_movl_T0_reg(s, rm);
6475 gen_movl_T1_reg(s, rn);
6476 if ((insn & 0x70) != 0)
6477 goto illegal_op;
6478 op = (insn >> 21) & 3;
6479 if (insn & (1 << 20)) {
6480 gen_shift_T1_T0_cc[op]();
6481 gen_op_logic_T1_cc();
6482 } else {
6483 gen_shift_T1_T0[op]();
6484 }
6485 gen_movl_reg_T1(s, rd);
6486 break;
6487 case 1: /* Sign/zero extend. */
6488 gen_movl_T1_reg(s, rm);
6489 shift = (insn >> 4) & 3;
6490 /* ??? In many cases it's not neccessary to do a
6491 rotate, a shift is sufficient. */
6492 if (shift != 0)
6493 gen_op_rorl_T1_im(shift * 8);
6494 op = (insn >> 20) & 7;
6495 switch (op) {
b26eefb6
PB
6496 case 0: gen_sxth(cpu_T[1]); break;
6497 case 1: gen_uxth(cpu_T[1]); break;
6498 case 2: gen_sxtb16(cpu_T[1]); break;
6499 case 3: gen_uxtb16(cpu_T[1]); break;
6500 case 4: gen_sxtb(cpu_T[1]); break;
6501 case 5: gen_uxtb(cpu_T[1]); break;
9ee6e8bb
PB
6502 default: goto illegal_op;
6503 }
6504 if (rn != 15) {
b26eefb6 6505 tmp = load_reg(s, rn);
9ee6e8bb 6506 if ((op >> 1) == 1) {
b26eefb6 6507 gen_add16(cpu_T[1], tmp);
9ee6e8bb 6508 } else {
b26eefb6
PB
6509 tcg_gen_add_i32(cpu_T[1], cpu_T[1], tmp);
6510 dead_tmp(tmp);
9ee6e8bb
PB
6511 }
6512 }
6513 gen_movl_reg_T1(s, rd);
6514 break;
6515 case 2: /* SIMD add/subtract. */
6516 op = (insn >> 20) & 7;
6517 shift = (insn >> 4) & 7;
6518 if ((op & 3) == 3 || (shift & 3) == 3)
6519 goto illegal_op;
6ddbc6e4
PB
6520 tmp = load_reg(s, rn);
6521 tmp2 = load_reg(s, rm);
6522 gen_thumb2_parallel_addsub(op, shift, tmp, tmp2);
6523 dead_tmp(tmp2);
6524 store_reg(s, rd, tmp);
9ee6e8bb
PB
6525 break;
6526 case 3: /* Other data processing. */
6527 op = ((insn >> 17) & 0x38) | ((insn >> 4) & 7);
6528 if (op < 4) {
6529 /* Saturating add/subtract. */
6530 gen_movl_T0_reg(s, rm);
6531 gen_movl_T1_reg(s, rn);
6532 if (op & 2)
1497c961 6533 gen_helper_double_saturate(cpu_T[1], cpu_T[1]);
9ee6e8bb
PB
6534 if (op & 1)
6535 gen_op_subl_T0_T1_saturate();
6536 else
6537 gen_op_addl_T0_T1_saturate();
6538 } else {
6539 gen_movl_T0_reg(s, rn);
6540 switch (op) {
6541 case 0x0a: /* rbit */
3670669c 6542 gen_helper_rbit(cpu_T[0], cpu_T[0]);
9ee6e8bb
PB
6543 break;
6544 case 0x08: /* rev */
6545 gen_op_rev_T0();
6546 break;
6547 case 0x09: /* rev16 */
3670669c 6548 gen_rev16(cpu_T[0]);
9ee6e8bb
PB
6549 break;
6550 case 0x0b: /* revsh */
3670669c 6551 gen_revsh(cpu_T[0]);
9ee6e8bb
PB
6552 break;
6553 case 0x10: /* sel */
6554 gen_movl_T1_reg(s, rm);
6ddbc6e4
PB
6555 tmp3 = new_tmp();
6556 tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUState, GE));
6557 gen_helper_sel_flags(cpu_T[0], tmp3, cpu_T[0], cpu_T[1]);
6558 dead_tmp(tmp3);
9ee6e8bb
PB
6559 break;
6560 case 0x18: /* clz */
1497c961 6561 gen_helper_clz(cpu_T[0], cpu_T[0]);
9ee6e8bb
PB
6562 break;
6563 default:
6564 goto illegal_op;
6565 }
6566 }
6567 gen_movl_reg_T0(s, rd);
6568 break;
6569 case 4: case 5: /* 32-bit multiply. Sum of absolute differences. */
6570 op = (insn >> 4) & 0xf;
6571 gen_movl_T0_reg(s, rn);
6572 gen_movl_T1_reg(s, rm);
6573 switch ((insn >> 20) & 7) {
6574 case 0: /* 32 x 32 -> 32 */
6575 gen_op_mul_T0_T1();
6576 if (rs != 15) {
6577 gen_movl_T1_reg(s, rs);
6578 if (op)
6579 gen_op_rsbl_T0_T1();
6580 else
6581 gen_op_addl_T0_T1();
6582 }
6583 gen_movl_reg_T0(s, rd);
6584 break;
6585 case 1: /* 16 x 16 -> 32 */
6586 gen_mulxy(op & 2, op & 1);
6587 if (rs != 15) {
6588 gen_movl_T1_reg(s, rs);
6589 gen_op_addl_T0_T1_setq();
6590 }
6591 gen_movl_reg_T0(s, rd);
6592 break;
6593 case 2: /* Dual multiply add. */
6594 case 4: /* Dual multiply subtract. */
6595 if (op)
8f01245e 6596 gen_swap_half(cpu_T[1]);
3670669c 6597 gen_smul_dual(cpu_T[0], cpu_T[1]);
9ee6e8bb
PB
6598 /* This addition cannot overflow. */
6599 if (insn & (1 << 22)) {
6600 gen_op_subl_T0_T1();
6601 } else {
6602 gen_op_addl_T0_T1();
6603 }
6604 if (rs != 15)
6605 {
6606 gen_movl_T1_reg(s, rs);
6607 gen_op_addl_T0_T1_setq();
6608 }
6609 gen_movl_reg_T0(s, rd);
6610 break;
6611 case 3: /* 32 * 16 -> 32msb */
6612 if (op)
6613 gen_op_sarl_T1_im(16);
6614 else
b26eefb6 6615 gen_sxth(cpu_T[1]);
9ee6e8bb
PB
6616 gen_op_imulw_T0_T1();
6617 if (rs != 15)
6618 {
6619 gen_movl_T1_reg(s, rs);
6620 gen_op_addl_T0_T1_setq();
6621 }
6622 gen_movl_reg_T0(s, rd);
6623 break;
6624 case 5: case 6: /* 32 * 32 -> 32msb */
6625 gen_op_imull_T0_T1();
6626 if (insn & (1 << 5))
6627 gen_op_roundqd_T0_T1();
6628 else
6629 gen_op_movl_T0_T1();
6630 if (rs != 15) {
6631 gen_movl_T1_reg(s, rs);
6632 if (insn & (1 << 21)) {
6633 gen_op_addl_T0_T1();
99c475ab 6634 } else {
9ee6e8bb 6635 gen_op_rsbl_T0_T1();
99c475ab 6636 }
2c0262af 6637 }
9ee6e8bb
PB
6638 gen_movl_reg_T0(s, rd);
6639 break;
6640 case 7: /* Unsigned sum of absolute differences. */
6ddbc6e4 6641 gen_helper_usad8(cpu_T[0], cpu_T[0], cpu_T[1]);
9ee6e8bb
PB
6642 if (rs != 15) {
6643 gen_movl_T1_reg(s, rs);
6644 gen_op_addl_T0_T1();
5fd46862 6645 }
9ee6e8bb
PB
6646 gen_movl_reg_T0(s, rd);
6647 break;
2c0262af
FB
6648 }
6649 break;
9ee6e8bb
PB
6650 case 6: case 7: /* 64-bit multiply, Divide. */
6651 op = ((insn >> 4) & 0xf) | ((insn >> 16) & 0x70);
6652 gen_movl_T0_reg(s, rn);
6653 gen_movl_T1_reg(s, rm);
6654 if ((op & 0x50) == 0x10) {
6655 /* sdiv, udiv */
6656 if (!arm_feature(env, ARM_FEATURE_DIV))
6657 goto illegal_op;
6658 if (op & 0x20)
3670669c 6659 gen_helper_udiv(cpu_T[0], cpu_T[0], cpu_T[1]);
2c0262af 6660 else
3670669c 6661 gen_helper_sdiv(cpu_T[0], cpu_T[0], cpu_T[1]);
9ee6e8bb
PB
6662 gen_movl_reg_T0(s, rd);
6663 } else if ((op & 0xe) == 0xc) {
6664 /* Dual multiply accumulate long. */
6665 if (op & 1)
8f01245e 6666 gen_swap_half(cpu_T[1]);
3670669c 6667 gen_smul_dual(cpu_T[0], cpu_T[1]);
9ee6e8bb
PB
6668 if (op & 0x10) {
6669 gen_op_subl_T0_T1();
b5ff1b31 6670 } else {
9ee6e8bb 6671 gen_op_addl_T0_T1();
b5ff1b31 6672 }
9ee6e8bb
PB
6673 gen_op_signbit_T1_T0();
6674 gen_op_addq_T0_T1(rs, rd);
6675 gen_movl_reg_T0(s, rs);
6676 gen_movl_reg_T1(s, rd);
2c0262af 6677 } else {
9ee6e8bb
PB
6678 if (op & 0x20) {
6679 /* Unsigned 64-bit multiply */
6680 gen_op_mull_T0_T1();
b5ff1b31 6681 } else {
9ee6e8bb
PB
6682 if (op & 8) {
6683 /* smlalxy */
6684 gen_mulxy(op & 2, op & 1);
6685 gen_op_signbit_T1_T0();
6686 } else {
6687 /* Signed 64-bit multiply */
6688 gen_op_imull_T0_T1();
6689 }
b5ff1b31 6690 }
9ee6e8bb
PB
6691 if (op & 4) {
6692 /* umaal */
6693 gen_op_addq_lo_T0_T1(rs);
6694 gen_op_addq_lo_T0_T1(rd);
6695 } else if (op & 0x40) {
6696 /* 64-bit accumulate. */
6697 gen_op_addq_T0_T1(rs, rd);
6698 }
6699 gen_movl_reg_T0(s, rs);
6700 gen_movl_reg_T1(s, rd);
5fd46862 6701 }
2c0262af 6702 break;
9ee6e8bb
PB
6703 }
6704 break;
6705 case 6: case 7: case 14: case 15:
6706 /* Coprocessor. */
6707 if (((insn >> 24) & 3) == 3) {
6708 /* Translate into the equivalent ARM encoding. */
6709 insn = (insn & 0xe2ffffff) | ((insn & (1 << 28)) >> 4);
6710 if (disas_neon_data_insn(env, s, insn))
6711 goto illegal_op;
6712 } else {
6713 if (insn & (1 << 28))
6714 goto illegal_op;
6715 if (disas_coproc_insn (env, s, insn))
6716 goto illegal_op;
6717 }
6718 break;
6719 case 8: case 9: case 10: case 11:
6720 if (insn & (1 << 15)) {
6721 /* Branches, misc control. */
6722 if (insn & 0x5000) {
6723 /* Unconditional branch. */
6724 /* signextend(hw1[10:0]) -> offset[:12]. */
6725 offset = ((int32_t)insn << 5) >> 9 & ~(int32_t)0xfff;
6726 /* hw1[10:0] -> offset[11:1]. */
6727 offset |= (insn & 0x7ff) << 1;
6728 /* (~hw2[13, 11] ^ offset[24]) -> offset[23,22]
6729 offset[24:22] already have the same value because of the
6730 sign extension above. */
6731 offset ^= ((~insn) & (1 << 13)) << 10;
6732 offset ^= ((~insn) & (1 << 11)) << 11;
6733
6734 addr = s->pc;
6735 if (insn & (1 << 14)) {
6736 /* Branch and link. */
6737 gen_op_movl_T1_im(addr | 1);
6738 gen_movl_reg_T1(s, 14);
b5ff1b31 6739 }
3b46e624 6740
9ee6e8bb
PB
6741 addr += offset;
6742 if (insn & (1 << 12)) {
6743 /* b/bl */
6744 gen_jmp(s, addr);
6745 } else {
6746 /* blx */
6747 addr &= ~(uint32_t)2;
6748 gen_op_movl_T0_im(addr);
6749 gen_bx(s);
2c0262af 6750 }
9ee6e8bb
PB
6751 } else if (((insn >> 23) & 7) == 7) {
6752 /* Misc control */
6753 if (insn & (1 << 13))
6754 goto illegal_op;
6755
6756 if (insn & (1 << 26)) {
6757 /* Secure monitor call (v6Z) */
6758 goto illegal_op; /* not implemented. */
2c0262af 6759 } else {
9ee6e8bb
PB
6760 op = (insn >> 20) & 7;
6761 switch (op) {
6762 case 0: /* msr cpsr. */
6763 if (IS_M(env)) {
6764 gen_op_v7m_msr_T0(insn & 0xff);
6765 gen_movl_reg_T0(s, rn);
6766 gen_lookup_tb(s);
6767 break;
6768 }
6769 /* fall through */
6770 case 1: /* msr spsr. */
6771 if (IS_M(env))
6772 goto illegal_op;
6773 gen_movl_T0_reg(s, rn);
6774 if (gen_set_psr_T0(s,
6775 msr_mask(env, s, (insn >> 8) & 0xf, op == 1),
6776 op == 1))
6777 goto illegal_op;
6778 break;
6779 case 2: /* cps, nop-hint. */
6780 if (((insn >> 8) & 7) == 0) {
6781 gen_nop_hint(s, insn & 0xff);
6782 }
6783 /* Implemented as NOP in user mode. */
6784 if (IS_USER(s))
6785 break;
6786 offset = 0;
6787 imm = 0;
6788 if (insn & (1 << 10)) {
6789 if (insn & (1 << 7))
6790 offset |= CPSR_A;
6791 if (insn & (1 << 6))
6792 offset |= CPSR_I;
6793 if (insn & (1 << 5))
6794 offset |= CPSR_F;
6795 if (insn & (1 << 9))
6796 imm = CPSR_A | CPSR_I | CPSR_F;
6797 }
6798 if (insn & (1 << 8)) {
6799 offset |= 0x1f;
6800 imm |= (insn & 0x1f);
6801 }
6802 if (offset) {
6803 gen_op_movl_T0_im(imm);
6804 gen_set_psr_T0(s, offset, 0);
6805 }
6806 break;
6807 case 3: /* Special control operations. */
6808 op = (insn >> 4) & 0xf;
6809 switch (op) {
6810 case 2: /* clrex */
6811 gen_op_clrex();
6812 break;
6813 case 4: /* dsb */
6814 case 5: /* dmb */
6815 case 6: /* isb */
6816 /* These execute as NOPs. */
6817 ARCH(7);
6818 break;
6819 default:
6820 goto illegal_op;
6821 }
6822 break;
6823 case 4: /* bxj */
6824 /* Trivial implementation equivalent to bx. */
6825 gen_movl_T0_reg(s, rn);
6826 gen_bx(s);
6827 break;
6828 case 5: /* Exception return. */
6829 /* Unpredictable in user mode. */
6830 goto illegal_op;
6831 case 6: /* mrs cpsr. */
6832 if (IS_M(env)) {
6833 gen_op_v7m_mrs_T0(insn & 0xff);
6834 } else {
6835 gen_op_movl_T0_cpsr();
6836 }
6837 gen_movl_reg_T0(s, rd);
6838 break;
6839 case 7: /* mrs spsr. */
6840 /* Not accessible in user mode. */
6841 if (IS_USER(s) || IS_M(env))
6842 goto illegal_op;
6843 gen_op_movl_T0_spsr();
6844 gen_movl_reg_T0(s, rd);
6845 break;
2c0262af
FB
6846 }
6847 }
9ee6e8bb
PB
6848 } else {
6849 /* Conditional branch. */
6850 op = (insn >> 22) & 0xf;
6851 /* Generate a conditional jump to next instruction. */
6852 s->condlabel = gen_new_label();
6853 gen_test_cc[op ^ 1](s->condlabel);
6854 s->condjmp = 1;
6855
6856 /* offset[11:1] = insn[10:0] */
6857 offset = (insn & 0x7ff) << 1;
6858 /* offset[17:12] = insn[21:16]. */
6859 offset |= (insn & 0x003f0000) >> 4;
6860 /* offset[31:20] = insn[26]. */
6861 offset |= ((int32_t)((insn << 5) & 0x80000000)) >> 11;
6862 /* offset[18] = insn[13]. */
6863 offset |= (insn & (1 << 13)) << 5;
6864 /* offset[19] = insn[11]. */
6865 offset |= (insn & (1 << 11)) << 8;
6866
6867 /* jump to the offset */
6868 addr = s->pc + offset;
6869 gen_jmp(s, addr);
6870 }
6871 } else {
6872 /* Data processing immediate. */
6873 if (insn & (1 << 25)) {
6874 if (insn & (1 << 24)) {
6875 if (insn & (1 << 20))
6876 goto illegal_op;
6877 /* Bitfield/Saturate. */
6878 op = (insn >> 21) & 7;
6879 imm = insn & 0x1f;
6880 shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c);
6ddbc6e4
PB
6881 if (rn == 15) {
6882 tmp = new_tmp();
6883 tcg_gen_movi_i32(tmp, 0);
6884 } else {
6885 tmp = load_reg(s, rn);
6886 }
9ee6e8bb
PB
6887 switch (op) {
6888 case 2: /* Signed bitfield extract. */
6889 imm++;
6890 if (shift + imm > 32)
6891 goto illegal_op;
6892 if (imm < 32)
6ddbc6e4 6893 gen_sbfx(tmp, shift, imm);
9ee6e8bb
PB
6894 break;
6895 case 6: /* Unsigned bitfield extract. */
6896 imm++;
6897 if (shift + imm > 32)
6898 goto illegal_op;
6899 if (imm < 32)
6ddbc6e4 6900 gen_ubfx(tmp, shift, (1u << imm) - 1);
9ee6e8bb
PB
6901 break;
6902 case 3: /* Bitfield insert/clear. */
6903 if (imm < shift)
6904 goto illegal_op;
6905 imm = imm + 1 - shift;
6906 if (imm != 32) {
6ddbc6e4
PB
6907 tmp2 = load_reg(s, rd);
6908 gen_bfi(tmp, tmp2, tmp,
3670669c 6909 shift, ((1u << imm) - 1) << shift);
6ddbc6e4 6910 dead_tmp(tmp2);
9ee6e8bb
PB
6911 }
6912 break;
6913 case 7:
6914 goto illegal_op;
6915 default: /* Saturate. */
9ee6e8bb
PB
6916 if (shift) {
6917 if (op & 1)
6ddbc6e4 6918 tcg_gen_sari_i32(tmp, tmp, shift);
9ee6e8bb 6919 else
6ddbc6e4 6920 tcg_gen_shli_i32(tmp, tmp, shift);
9ee6e8bb 6921 }
6ddbc6e4 6922 tmp2 = tcg_const_i32(imm);
9ee6e8bb
PB
6923 if (op & 4) {
6924 /* Unsigned. */
9ee6e8bb 6925 if ((op & 1) && shift == 0)
6ddbc6e4 6926 gen_helper_usat16(tmp, tmp, tmp2);
9ee6e8bb 6927 else
6ddbc6e4 6928 gen_helper_usat(tmp, tmp, tmp2);
2c0262af 6929 } else {
9ee6e8bb 6930 /* Signed. */
9ee6e8bb 6931 if ((op & 1) && shift == 0)
6ddbc6e4 6932 gen_helper_ssat16(tmp, tmp, tmp2);
9ee6e8bb 6933 else
6ddbc6e4 6934 gen_helper_ssat(tmp, tmp, tmp2);
2c0262af 6935 }
9ee6e8bb 6936 break;
2c0262af 6937 }
6ddbc6e4 6938 store_reg(s, rd, tmp);
9ee6e8bb
PB
6939 } else {
6940 imm = ((insn & 0x04000000) >> 15)
6941 | ((insn & 0x7000) >> 4) | (insn & 0xff);
6942 if (insn & (1 << 22)) {
6943 /* 16-bit immediate. */
6944 imm |= (insn >> 4) & 0xf000;
6945 if (insn & (1 << 23)) {
6946 /* movt */
6947 gen_movl_T0_reg(s, rd);
8f01245e
PB
6948 tcg_gen_andi_i32(cpu_T[0], cpu_T[0], 0xffff);
6949 tcg_gen_ori_i32(cpu_T[0], cpu_T[0], imm << 16);
2c0262af 6950 } else {
9ee6e8bb
PB
6951 /* movw */
6952 gen_op_movl_T0_im(imm);
2c0262af
FB
6953 }
6954 } else {
9ee6e8bb
PB
6955 /* Add/sub 12-bit immediate. */
6956 if (rn == 15) {
6957 addr = s->pc & ~(uint32_t)3;
6958 if (insn & (1 << 23))
6959 addr -= imm;
6960 else
6961 addr += imm;
6962 gen_op_movl_T0_im(addr);
2c0262af 6963 } else {
9ee6e8bb
PB
6964 gen_movl_T0_reg(s, rn);
6965 gen_op_movl_T1_im(imm);
6966 if (insn & (1 << 23))
6967 gen_op_subl_T0_T1();
6968 else
6969 gen_op_addl_T0_T1();
2c0262af 6970 }
9ee6e8bb
PB
6971 }
6972 gen_movl_reg_T0(s, rd);
191abaa2 6973 }
9ee6e8bb
PB
6974 } else {
6975 int shifter_out = 0;
6976 /* modified 12-bit immediate. */
6977 shift = ((insn & 0x04000000) >> 23) | ((insn & 0x7000) >> 12);
6978 imm = (insn & 0xff);
6979 switch (shift) {
6980 case 0: /* XY */
6981 /* Nothing to do. */
6982 break;
6983 case 1: /* 00XY00XY */
6984 imm |= imm << 16;
6985 break;
6986 case 2: /* XY00XY00 */
6987 imm |= imm << 16;
6988 imm <<= 8;
6989 break;
6990 case 3: /* XYXYXYXY */
6991 imm |= imm << 16;
6992 imm |= imm << 8;
6993 break;
6994 default: /* Rotated constant. */
6995 shift = (shift << 1) | (imm >> 7);
6996 imm |= 0x80;
6997 imm = imm << (32 - shift);
6998 shifter_out = 1;
6999 break;
b5ff1b31 7000 }
9ee6e8bb
PB
7001 gen_op_movl_T1_im(imm);
7002 rn = (insn >> 16) & 0xf;
7003 if (rn == 15)
7004 gen_op_movl_T0_im(0);
7005 else
7006 gen_movl_T0_reg(s, rn);
7007 op = (insn >> 21) & 0xf;
7008 if (gen_thumb2_data_op(s, op, (insn & (1 << 20)) != 0,
7009 shifter_out))
7010 goto illegal_op;
7011 rd = (insn >> 8) & 0xf;
7012 if (rd != 15) {
7013 gen_movl_reg_T0(s, rd);
2c0262af 7014 }
2c0262af 7015 }
9ee6e8bb
PB
7016 }
7017 break;
7018 case 12: /* Load/store single data item. */
7019 {
7020 int postinc = 0;
7021 int writeback = 0;
7022 if ((insn & 0x01100000) == 0x01000000) {
7023 if (disas_neon_ls_insn(env, s, insn))
c1713132 7024 goto illegal_op;
9ee6e8bb
PB
7025 break;
7026 }
7027 if (rn == 15) {
7028 /* PC relative. */
7029 /* s->pc has already been incremented by 4. */
7030 imm = s->pc & 0xfffffffc;
7031 if (insn & (1 << 23))
7032 imm += insn & 0xfff;
7033 else
7034 imm -= insn & 0xfff;
7035 gen_op_movl_T1_im(imm);
7036 } else {
7037 gen_movl_T1_reg(s, rn);
7038 if (insn & (1 << 23)) {
7039 /* Positive offset. */
7040 imm = insn & 0xfff;
7041 gen_op_addl_T1_im(imm);
7042 } else {
7043 op = (insn >> 8) & 7;
7044 imm = insn & 0xff;
7045 switch (op) {
7046 case 0: case 8: /* Shifted Register. */
7047 shift = (insn >> 4) & 0xf;
7048 if (shift > 3)
18c9b560 7049 goto illegal_op;
b26eefb6 7050 tmp = load_reg(s, rm);
9ee6e8bb 7051 if (shift)
b26eefb6
PB
7052 tcg_gen_shli_i32(tmp, tmp, shift);
7053 tcg_gen_add_i32(cpu_T[1], cpu_T[1], tmp);
7054 dead_tmp(tmp);
9ee6e8bb
PB
7055 break;
7056 case 4: /* Negative offset. */
7057 gen_op_addl_T1_im(-imm);
7058 break;
7059 case 6: /* User privilege. */
7060 gen_op_addl_T1_im(imm);
7061 break;
7062 case 1: /* Post-decrement. */
7063 imm = -imm;
7064 /* Fall through. */
7065 case 3: /* Post-increment. */
9ee6e8bb
PB
7066 postinc = 1;
7067 writeback = 1;
7068 break;
7069 case 5: /* Pre-decrement. */
7070 imm = -imm;
7071 /* Fall through. */
7072 case 7: /* Pre-increment. */
7073 gen_op_addl_T1_im(imm);
7074 writeback = 1;
7075 break;
7076 default:
b7bcbe95 7077 goto illegal_op;
9ee6e8bb
PB
7078 }
7079 }
7080 }
7081 op = ((insn >> 21) & 3) | ((insn >> 22) & 4);
7082 if (insn & (1 << 20)) {
7083 /* Load. */
7084 if (rs == 15 && op != 2) {
7085 if (op & 2)
b5ff1b31 7086 goto illegal_op;
9ee6e8bb
PB
7087 /* Memory hint. Implemented as NOP. */
7088 } else {
7089 switch (op) {
7090 case 0: gen_ldst(ldub, s); break;
7091 case 4: gen_ldst(ldsb, s); break;
7092 case 1: gen_ldst(lduw, s); break;
7093 case 5: gen_ldst(ldsw, s); break;
7094 case 2: gen_ldst(ldl, s); break;
7095 default: goto illegal_op;
7096 }
7097 if (rs == 15) {
7098 gen_bx(s);
7099 } else {
7100 gen_movl_reg_T0(s, rs);
7101 }
7102 }
7103 } else {
7104 /* Store. */
7105 if (rs == 15)
b7bcbe95 7106 goto illegal_op;
9ee6e8bb
PB
7107 gen_movl_T0_reg(s, rs);
7108 switch (op) {
7109 case 0: gen_ldst(stb, s); break;
7110 case 1: gen_ldst(stw, s); break;
7111 case 2: gen_ldst(stl, s); break;
7112 default: goto illegal_op;
b7bcbe95 7113 }
2c0262af 7114 }
9ee6e8bb
PB
7115 if (postinc)
7116 gen_op_addl_T1_im(imm);
7117 if (writeback)
7118 gen_movl_reg_T1(s, rn);
7119 }
7120 break;
7121 default:
7122 goto illegal_op;
2c0262af 7123 }
9ee6e8bb
PB
7124 return 0;
7125illegal_op:
7126 return 1;
2c0262af
FB
7127}
7128
9ee6e8bb 7129static void disas_thumb_insn(CPUState *env, DisasContext *s)
99c475ab
FB
7130{
7131 uint32_t val, insn, op, rm, rn, rd, shift, cond;
7132 int32_t offset;
7133 int i;
b26eefb6 7134 TCGv tmp;
99c475ab 7135
9ee6e8bb
PB
7136 if (s->condexec_mask) {
7137 cond = s->condexec_cond;
7138 s->condlabel = gen_new_label();
7139 gen_test_cc[cond ^ 1](s->condlabel);
7140 s->condjmp = 1;
7141 }
7142
b5ff1b31 7143 insn = lduw_code(s->pc);
99c475ab 7144 s->pc += 2;
b5ff1b31 7145
99c475ab
FB
7146 switch (insn >> 12) {
7147 case 0: case 1:
7148 rd = insn & 7;
7149 op = (insn >> 11) & 3;
7150 if (op == 3) {
7151 /* add/subtract */
7152 rn = (insn >> 3) & 7;
7153 gen_movl_T0_reg(s, rn);
7154 if (insn & (1 << 10)) {
7155 /* immediate */
7156 gen_op_movl_T1_im((insn >> 6) & 7);
7157 } else {
7158 /* reg */
7159 rm = (insn >> 6) & 7;
7160 gen_movl_T1_reg(s, rm);
7161 }
9ee6e8bb
PB
7162 if (insn & (1 << 9)) {
7163 if (s->condexec_mask)
7164 gen_op_subl_T0_T1();
7165 else
7166 gen_op_subl_T0_T1_cc();
7167 } else {
7168 if (s->condexec_mask)
7169 gen_op_addl_T0_T1();
7170 else
7171 gen_op_addl_T0_T1_cc();
7172 }
99c475ab
FB
7173 gen_movl_reg_T0(s, rd);
7174 } else {
7175 /* shift immediate */
7176 rm = (insn >> 3) & 7;
7177 shift = (insn >> 6) & 0x1f;
9a119ff6
PB
7178 tmp = load_reg(s, rm);
7179 gen_arm_shift_im(tmp, op, shift, s->condexec_mask == 0);
7180 if (!s->condexec_mask)
7181 gen_logic_CC(tmp);
7182 store_reg(s, rd, tmp);
99c475ab
FB
7183 }
7184 break;
7185 case 2: case 3:
7186 /* arithmetic large immediate */
7187 op = (insn >> 11) & 3;
7188 rd = (insn >> 8) & 0x7;
7189 if (op == 0) {
7190 gen_op_movl_T0_im(insn & 0xff);
7191 } else {
7192 gen_movl_T0_reg(s, rd);
7193 gen_op_movl_T1_im(insn & 0xff);
7194 }
7195 switch (op) {
7196 case 0: /* mov */
9ee6e8bb
PB
7197 if (!s->condexec_mask)
7198 gen_op_logic_T0_cc();
99c475ab
FB
7199 break;
7200 case 1: /* cmp */
7201 gen_op_subl_T0_T1_cc();
7202 break;
7203 case 2: /* add */
9ee6e8bb
PB
7204 if (s->condexec_mask)
7205 gen_op_addl_T0_T1();
7206 else
7207 gen_op_addl_T0_T1_cc();
99c475ab
FB
7208 break;
7209 case 3: /* sub */
9ee6e8bb
PB
7210 if (s->condexec_mask)
7211 gen_op_subl_T0_T1();
7212 else
7213 gen_op_subl_T0_T1_cc();
99c475ab
FB
7214 break;
7215 }
7216 if (op != 1)
7217 gen_movl_reg_T0(s, rd);
7218 break;
7219 case 4:
7220 if (insn & (1 << 11)) {
7221 rd = (insn >> 8) & 7;
5899f386
FB
7222 /* load pc-relative. Bit 1 of PC is ignored. */
7223 val = s->pc + 2 + ((insn & 0xff) * 4);
7224 val &= ~(uint32_t)2;
99c475ab 7225 gen_op_movl_T1_im(val);
b5ff1b31 7226 gen_ldst(ldl, s);
99c475ab
FB
7227 gen_movl_reg_T0(s, rd);
7228 break;
7229 }
7230 if (insn & (1 << 10)) {
7231 /* data processing extended or blx */
7232 rd = (insn & 7) | ((insn >> 4) & 8);
7233 rm = (insn >> 3) & 0xf;
7234 op = (insn >> 8) & 3;
7235 switch (op) {
7236 case 0: /* add */
7237 gen_movl_T0_reg(s, rd);
7238 gen_movl_T1_reg(s, rm);
7239 gen_op_addl_T0_T1();
7240 gen_movl_reg_T0(s, rd);
7241 break;
7242 case 1: /* cmp */
7243 gen_movl_T0_reg(s, rd);
7244 gen_movl_T1_reg(s, rm);
7245 gen_op_subl_T0_T1_cc();
7246 break;
7247 case 2: /* mov/cpy */
7248 gen_movl_T0_reg(s, rm);
7249 gen_movl_reg_T0(s, rd);
7250 break;
7251 case 3:/* branch [and link] exchange thumb register */
7252 if (insn & (1 << 7)) {
7253 val = (uint32_t)s->pc | 1;
7254 gen_op_movl_T1_im(val);
7255 gen_movl_reg_T1(s, 14);
7256 }
7257 gen_movl_T0_reg(s, rm);
7258 gen_bx(s);
7259 break;
7260 }
7261 break;
7262 }
7263
7264 /* data processing register */
7265 rd = insn & 7;
7266 rm = (insn >> 3) & 7;
7267 op = (insn >> 6) & 0xf;
7268 if (op == 2 || op == 3 || op == 4 || op == 7) {
7269 /* the shift/rotate ops want the operands backwards */
7270 val = rm;
7271 rm = rd;
7272 rd = val;
7273 val = 1;
7274 } else {
7275 val = 0;
7276 }
7277
7278 if (op == 9) /* neg */
7279 gen_op_movl_T0_im(0);
7280 else if (op != 0xf) /* mvn doesn't read its first operand */
7281 gen_movl_T0_reg(s, rd);
7282
7283 gen_movl_T1_reg(s, rm);
5899f386 7284 switch (op) {
99c475ab
FB
7285 case 0x0: /* and */
7286 gen_op_andl_T0_T1();
9ee6e8bb
PB
7287 if (!s->condexec_mask)
7288 gen_op_logic_T0_cc();
99c475ab
FB
7289 break;
7290 case 0x1: /* eor */
7291 gen_op_xorl_T0_T1();
9ee6e8bb
PB
7292 if (!s->condexec_mask)
7293 gen_op_logic_T0_cc();
99c475ab
FB
7294 break;
7295 case 0x2: /* lsl */
9ee6e8bb
PB
7296 if (s->condexec_mask) {
7297 gen_op_shll_T1_T0();
7298 } else {
7299 gen_op_shll_T1_T0_cc();
7300 gen_op_logic_T1_cc();
7301 }
99c475ab
FB
7302 break;
7303 case 0x3: /* lsr */
9ee6e8bb
PB
7304 if (s->condexec_mask) {
7305 gen_op_shrl_T1_T0();
7306 } else {
7307 gen_op_shrl_T1_T0_cc();
7308 gen_op_logic_T1_cc();
7309 }
99c475ab
FB
7310 break;
7311 case 0x4: /* asr */
9ee6e8bb
PB
7312 if (s->condexec_mask) {
7313 gen_op_sarl_T1_T0();
7314 } else {
7315 gen_op_sarl_T1_T0_cc();
7316 gen_op_logic_T1_cc();
7317 }
99c475ab
FB
7318 break;
7319 case 0x5: /* adc */
9ee6e8bb 7320 if (s->condexec_mask)
b26eefb6 7321 gen_adc_T0_T1();
9ee6e8bb
PB
7322 else
7323 gen_op_adcl_T0_T1_cc();
99c475ab
FB
7324 break;
7325 case 0x6: /* sbc */
9ee6e8bb 7326 if (s->condexec_mask)
3670669c 7327 gen_sbc_T0_T1();
9ee6e8bb
PB
7328 else
7329 gen_op_sbcl_T0_T1_cc();
99c475ab
FB
7330 break;
7331 case 0x7: /* ror */
9ee6e8bb
PB
7332 if (s->condexec_mask) {
7333 gen_op_rorl_T1_T0();
7334 } else {
7335 gen_op_rorl_T1_T0_cc();
7336 gen_op_logic_T1_cc();
7337 }
99c475ab
FB
7338 break;
7339 case 0x8: /* tst */
7340 gen_op_andl_T0_T1();
7341 gen_op_logic_T0_cc();
7342 rd = 16;
5899f386 7343 break;
99c475ab 7344 case 0x9: /* neg */
9ee6e8bb
PB
7345 if (s->condexec_mask)
7346 gen_op_subl_T0_T1();
7347 else
7348 gen_op_subl_T0_T1_cc();
99c475ab
FB
7349 break;
7350 case 0xa: /* cmp */
7351 gen_op_subl_T0_T1_cc();
7352 rd = 16;
7353 break;
7354 case 0xb: /* cmn */
7355 gen_op_addl_T0_T1_cc();
7356 rd = 16;
7357 break;
7358 case 0xc: /* orr */
7359 gen_op_orl_T0_T1();
9ee6e8bb
PB
7360 if (!s->condexec_mask)
7361 gen_op_logic_T0_cc();
99c475ab
FB
7362 break;
7363 case 0xd: /* mul */
7364 gen_op_mull_T0_T1();
9ee6e8bb
PB
7365 if (!s->condexec_mask)
7366 gen_op_logic_T0_cc();
99c475ab
FB
7367 break;
7368 case 0xe: /* bic */
7369 gen_op_bicl_T0_T1();
9ee6e8bb
PB
7370 if (!s->condexec_mask)
7371 gen_op_logic_T0_cc();
99c475ab
FB
7372 break;
7373 case 0xf: /* mvn */
7374 gen_op_notl_T1();
9ee6e8bb
PB
7375 if (!s->condexec_mask)
7376 gen_op_logic_T1_cc();
99c475ab 7377 val = 1;
5899f386 7378 rm = rd;
99c475ab
FB
7379 break;
7380 }
7381 if (rd != 16) {
7382 if (val)
5899f386 7383 gen_movl_reg_T1(s, rm);
99c475ab
FB
7384 else
7385 gen_movl_reg_T0(s, rd);
7386 }
7387 break;
7388
7389 case 5:
7390 /* load/store register offset. */
7391 rd = insn & 7;
7392 rn = (insn >> 3) & 7;
7393 rm = (insn >> 6) & 7;
7394 op = (insn >> 9) & 7;
7395 gen_movl_T1_reg(s, rn);
b26eefb6
PB
7396 tmp = load_reg(s, rm);
7397 tcg_gen_add_i32(cpu_T[1], cpu_T[1], tmp);
7398 dead_tmp(tmp);
99c475ab
FB
7399
7400 if (op < 3) /* store */
7401 gen_movl_T0_reg(s, rd);
7402
7403 switch (op) {
7404 case 0: /* str */
b5ff1b31 7405 gen_ldst(stl, s);
99c475ab
FB
7406 break;
7407 case 1: /* strh */
b5ff1b31 7408 gen_ldst(stw, s);
99c475ab
FB
7409 break;
7410 case 2: /* strb */
b5ff1b31 7411 gen_ldst(stb, s);
99c475ab
FB
7412 break;
7413 case 3: /* ldrsb */
b5ff1b31 7414 gen_ldst(ldsb, s);
99c475ab
FB
7415 break;
7416 case 4: /* ldr */
b5ff1b31 7417 gen_ldst(ldl, s);
99c475ab
FB
7418 break;
7419 case 5: /* ldrh */
b5ff1b31 7420 gen_ldst(lduw, s);
99c475ab
FB
7421 break;
7422 case 6: /* ldrb */
b5ff1b31 7423 gen_ldst(ldub, s);
99c475ab
FB
7424 break;
7425 case 7: /* ldrsh */
b5ff1b31 7426 gen_ldst(ldsw, s);
99c475ab
FB
7427 break;
7428 }
7429 if (op >= 3) /* load */
7430 gen_movl_reg_T0(s, rd);
7431 break;
7432
7433 case 6:
7434 /* load/store word immediate offset */
7435 rd = insn & 7;
7436 rn = (insn >> 3) & 7;
7437 gen_movl_T1_reg(s, rn);
7438 val = (insn >> 4) & 0x7c;
b26eefb6 7439 tcg_gen_addi_i32(cpu_T[1], cpu_T[1], val);
99c475ab
FB
7440
7441 if (insn & (1 << 11)) {
7442 /* load */
b5ff1b31 7443 gen_ldst(ldl, s);
99c475ab
FB
7444 gen_movl_reg_T0(s, rd);
7445 } else {
7446 /* store */
7447 gen_movl_T0_reg(s, rd);
b5ff1b31 7448 gen_ldst(stl, s);
99c475ab
FB
7449 }
7450 break;
7451
7452 case 7:
7453 /* load/store byte immediate offset */
7454 rd = insn & 7;
7455 rn = (insn >> 3) & 7;
7456 gen_movl_T1_reg(s, rn);
7457 val = (insn >> 6) & 0x1f;
b26eefb6 7458 tcg_gen_addi_i32(cpu_T[1], cpu_T[1], val);
99c475ab
FB
7459
7460 if (insn & (1 << 11)) {
7461 /* load */
b5ff1b31 7462 gen_ldst(ldub, s);
99c475ab
FB
7463 gen_movl_reg_T0(s, rd);
7464 } else {
7465 /* store */
7466 gen_movl_T0_reg(s, rd);
b5ff1b31 7467 gen_ldst(stb, s);
99c475ab
FB
7468 }
7469 break;
7470
7471 case 8:
7472 /* load/store halfword immediate offset */
7473 rd = insn & 7;
7474 rn = (insn >> 3) & 7;
7475 gen_movl_T1_reg(s, rn);
7476 val = (insn >> 5) & 0x3e;
b26eefb6 7477 tcg_gen_addi_i32(cpu_T[1], cpu_T[1], val);
99c475ab
FB
7478
7479 if (insn & (1 << 11)) {
7480 /* load */
b5ff1b31 7481 gen_ldst(lduw, s);
99c475ab
FB
7482 gen_movl_reg_T0(s, rd);
7483 } else {
7484 /* store */
7485 gen_movl_T0_reg(s, rd);
b5ff1b31 7486 gen_ldst(stw, s);
99c475ab
FB
7487 }
7488 break;
7489
7490 case 9:
7491 /* load/store from stack */
7492 rd = (insn >> 8) & 7;
7493 gen_movl_T1_reg(s, 13);
7494 val = (insn & 0xff) * 4;
b26eefb6 7495 tcg_gen_addi_i32(cpu_T[1], cpu_T[1], val);
99c475ab
FB
7496
7497 if (insn & (1 << 11)) {
7498 /* load */
b5ff1b31 7499 gen_ldst(ldl, s);
99c475ab
FB
7500 gen_movl_reg_T0(s, rd);
7501 } else {
7502 /* store */
7503 gen_movl_T0_reg(s, rd);
b5ff1b31 7504 gen_ldst(stl, s);
99c475ab
FB
7505 }
7506 break;
7507
7508 case 10:
7509 /* add to high reg */
7510 rd = (insn >> 8) & 7;
5899f386
FB
7511 if (insn & (1 << 11)) {
7512 /* SP */
7513 gen_movl_T0_reg(s, 13);
7514 } else {
7515 /* PC. bit 1 is ignored. */
7516 gen_op_movl_T0_im((s->pc + 2) & ~(uint32_t)2);
7517 }
99c475ab
FB
7518 val = (insn & 0xff) * 4;
7519 gen_op_movl_T1_im(val);
7520 gen_op_addl_T0_T1();
7521 gen_movl_reg_T0(s, rd);
7522 break;
7523
7524 case 11:
7525 /* misc */
7526 op = (insn >> 8) & 0xf;
7527 switch (op) {
7528 case 0:
7529 /* adjust stack pointer */
b26eefb6 7530 tmp = load_reg(s, 13);
99c475ab
FB
7531 val = (insn & 0x7f) * 4;
7532 if (insn & (1 << 7))
7533 val = -(int32_t)val;
b26eefb6
PB
7534 tcg_gen_addi_i32(tmp, tmp, val);
7535 store_reg(s, 13, tmp);
99c475ab
FB
7536 break;
7537
9ee6e8bb
PB
7538 case 2: /* sign/zero extend. */
7539 ARCH(6);
7540 rd = insn & 7;
7541 rm = (insn >> 3) & 7;
7542 gen_movl_T1_reg(s, rm);
7543 switch ((insn >> 6) & 3) {
b26eefb6
PB
7544 case 0: gen_sxth(cpu_T[1]); break;
7545 case 1: gen_sxtb(cpu_T[1]); break;
7546 case 2: gen_uxth(cpu_T[1]); break;
7547 case 3: gen_uxtb(cpu_T[1]); break;
9ee6e8bb
PB
7548 }
7549 gen_movl_reg_T1(s, rd);
7550 break;
99c475ab
FB
7551 case 4: case 5: case 0xc: case 0xd:
7552 /* push/pop */
7553 gen_movl_T1_reg(s, 13);
5899f386
FB
7554 if (insn & (1 << 8))
7555 offset = 4;
99c475ab 7556 else
5899f386
FB
7557 offset = 0;
7558 for (i = 0; i < 8; i++) {
7559 if (insn & (1 << i))
7560 offset += 4;
7561 }
7562 if ((insn & (1 << 11)) == 0) {
b26eefb6 7563 gen_op_addl_T1_im(-offset);
5899f386 7564 }
99c475ab
FB
7565 for (i = 0; i < 8; i++) {
7566 if (insn & (1 << i)) {
7567 if (insn & (1 << 11)) {
7568 /* pop */
b5ff1b31 7569 gen_ldst(ldl, s);
99c475ab
FB
7570 gen_movl_reg_T0(s, i);
7571 } else {
7572 /* push */
7573 gen_movl_T0_reg(s, i);
b5ff1b31 7574 gen_ldst(stl, s);
99c475ab 7575 }
5899f386 7576 /* advance to the next address. */
b26eefb6 7577 gen_op_addl_T1_im(4);
99c475ab
FB
7578 }
7579 }
7580 if (insn & (1 << 8)) {
7581 if (insn & (1 << 11)) {
7582 /* pop pc */
b5ff1b31 7583 gen_ldst(ldl, s);
99c475ab
FB
7584 /* don't set the pc until the rest of the instruction
7585 has completed */
7586 } else {
7587 /* push lr */
7588 gen_movl_T0_reg(s, 14);
b5ff1b31 7589 gen_ldst(stl, s);
99c475ab 7590 }
b26eefb6 7591 gen_op_addl_T1_im(4);
99c475ab 7592 }
5899f386 7593 if ((insn & (1 << 11)) == 0) {
b26eefb6 7594 gen_op_addl_T1_im(-offset);
5899f386 7595 }
99c475ab
FB
7596 /* write back the new stack pointer */
7597 gen_movl_reg_T1(s, 13);
7598 /* set the new PC value */
7599 if ((insn & 0x0900) == 0x0900)
7600 gen_bx(s);
7601 break;
7602
9ee6e8bb
PB
7603 case 1: case 3: case 9: case 11: /* czb */
7604 rm = insn & 7;
7605 gen_movl_T0_reg(s, rm);
7606 s->condlabel = gen_new_label();
7607 s->condjmp = 1;
7608 if (insn & (1 << 11))
7609 gen_op_testn_T0(s->condlabel);
7610 else
7611 gen_op_test_T0(s->condlabel);
7612
7613 offset = ((insn & 0xf8) >> 2) | (insn & 0x200) >> 3;
7614 val = (uint32_t)s->pc + 2;
7615 val += offset;
7616 gen_jmp(s, val);
7617 break;
7618
7619 case 15: /* IT, nop-hint. */
7620 if ((insn & 0xf) == 0) {
7621 gen_nop_hint(s, (insn >> 4) & 0xf);
7622 break;
7623 }
7624 /* If Then. */
7625 s->condexec_cond = (insn >> 4) & 0xe;
7626 s->condexec_mask = insn & 0x1f;
7627 /* No actual code generated for this insn, just setup state. */
7628 break;
7629
06c949e6 7630 case 0xe: /* bkpt */
9ee6e8bb 7631 gen_set_condexec(s);
06c949e6 7632 gen_op_movl_T0_im((long)s->pc - 2);
b26eefb6 7633 gen_set_pc_T0();
06c949e6
PB
7634 gen_op_bkpt();
7635 s->is_jmp = DISAS_JUMP;
7636 break;
7637
9ee6e8bb
PB
7638 case 0xa: /* rev */
7639 ARCH(6);
7640 rn = (insn >> 3) & 0x7;
7641 rd = insn & 0x7;
7642 gen_movl_T0_reg(s, rn);
7643 switch ((insn >> 6) & 3) {
7644 case 0: gen_op_rev_T0(); break;
3670669c
PB
7645 case 1: gen_rev16(cpu_T[0]); break;
7646 case 3: gen_revsh(cpu_T[0]); break;
9ee6e8bb
PB
7647 default: goto illegal_op;
7648 }
7649 gen_movl_reg_T0(s, rd);
7650 break;
7651
7652 case 6: /* cps */
7653 ARCH(6);
7654 if (IS_USER(s))
7655 break;
7656 if (IS_M(env)) {
7657 val = (insn & (1 << 4)) != 0;
7658 gen_op_movl_T0_im(val);
7659 /* PRIMASK */
7660 if (insn & 1)
7661 gen_op_v7m_msr_T0(16);
7662 /* FAULTMASK */
7663 if (insn & 2)
7664 gen_op_v7m_msr_T0(17);
7665
7666 gen_lookup_tb(s);
7667 } else {
7668 if (insn & (1 << 4))
7669 shift = CPSR_A | CPSR_I | CPSR_F;
7670 else
7671 shift = 0;
7672
7673 val = ((insn & 7) << 6) & shift;
7674 gen_op_movl_T0_im(val);
7675 gen_set_psr_T0(s, shift, 0);
7676 }
7677 break;
7678
99c475ab
FB
7679 default:
7680 goto undef;
7681 }
7682 break;
7683
7684 case 12:
7685 /* load/store multiple */
7686 rn = (insn >> 8) & 0x7;
7687 gen_movl_T1_reg(s, rn);
99c475ab
FB
7688 for (i = 0; i < 8; i++) {
7689 if (insn & (1 << i)) {
99c475ab
FB
7690 if (insn & (1 << 11)) {
7691 /* load */
b5ff1b31 7692 gen_ldst(ldl, s);
99c475ab
FB
7693 gen_movl_reg_T0(s, i);
7694 } else {
7695 /* store */
7696 gen_movl_T0_reg(s, i);
b5ff1b31 7697 gen_ldst(stl, s);
99c475ab 7698 }
5899f386 7699 /* advance to the next address */
b26eefb6 7700 gen_op_addl_T1_im(4);
99c475ab
FB
7701 }
7702 }
5899f386 7703 /* Base register writeback. */
b5ff1b31
FB
7704 if ((insn & (1 << rn)) == 0)
7705 gen_movl_reg_T1(s, rn);
99c475ab
FB
7706 break;
7707
7708 case 13:
7709 /* conditional branch or swi */
7710 cond = (insn >> 8) & 0xf;
7711 if (cond == 0xe)
7712 goto undef;
7713
7714 if (cond == 0xf) {
7715 /* swi */
9ee6e8bb 7716 gen_set_condexec(s);
99c475ab
FB
7717 gen_op_movl_T0_im((long)s->pc | 1);
7718 /* Don't set r15. */
b26eefb6 7719 gen_set_pc_T0();
9ee6e8bb 7720 s->is_jmp = DISAS_SWI;
99c475ab
FB
7721 break;
7722 }
7723 /* generate a conditional jump to next instruction */
e50e6a20
FB
7724 s->condlabel = gen_new_label();
7725 gen_test_cc[cond ^ 1](s->condlabel);
7726 s->condjmp = 1;
99c475ab
FB
7727 gen_movl_T1_reg(s, 15);
7728
7729 /* jump to the offset */
5899f386 7730 val = (uint32_t)s->pc + 2;
99c475ab 7731 offset = ((int32_t)insn << 24) >> 24;
5899f386 7732 val += offset << 1;
8aaca4c0 7733 gen_jmp(s, val);
99c475ab
FB
7734 break;
7735
7736 case 14:
358bf29e 7737 if (insn & (1 << 11)) {
9ee6e8bb
PB
7738 if (disas_thumb2_insn(env, s, insn))
7739 goto undef32;
358bf29e
PB
7740 break;
7741 }
9ee6e8bb 7742 /* unconditional branch */
99c475ab
FB
7743 val = (uint32_t)s->pc;
7744 offset = ((int32_t)insn << 21) >> 21;
7745 val += (offset << 1) + 2;
8aaca4c0 7746 gen_jmp(s, val);
99c475ab
FB
7747 break;
7748
7749 case 15:
9ee6e8bb
PB
7750 if (disas_thumb2_insn(env, s, insn))
7751 goto undef32;
7752 break;
99c475ab
FB
7753 }
7754 return;
9ee6e8bb
PB
7755undef32:
7756 gen_set_condexec(s);
7757 gen_op_movl_T0_im((long)s->pc - 4);
b26eefb6 7758 gen_set_pc_T0();
9ee6e8bb
PB
7759 gen_op_undef_insn();
7760 s->is_jmp = DISAS_JUMP;
7761 return;
7762illegal_op:
99c475ab 7763undef:
9ee6e8bb 7764 gen_set_condexec(s);
5899f386 7765 gen_op_movl_T0_im((long)s->pc - 2);
b26eefb6 7766 gen_set_pc_T0();
99c475ab
FB
7767 gen_op_undef_insn();
7768 s->is_jmp = DISAS_JUMP;
7769}
7770
2c0262af
FB
7771/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
7772 basic block 'tb'. If search_pc is TRUE, also generate PC
7773 information for each intermediate instruction. */
5fafdf24
TS
7774static inline int gen_intermediate_code_internal(CPUState *env,
7775 TranslationBlock *tb,
2c0262af
FB
7776 int search_pc)
7777{
7778 DisasContext dc1, *dc = &dc1;
7779 uint16_t *gen_opc_end;
7780 int j, lj;
0fa85d43 7781 target_ulong pc_start;
b5ff1b31 7782 uint32_t next_page_start;
3b46e624 7783
2c0262af 7784 /* generate intermediate code */
b26eefb6
PB
7785 num_temps = 0;
7786 memset(temps, 0, sizeof(temps));
7787
0fa85d43 7788 pc_start = tb->pc;
3b46e624 7789
2c0262af
FB
7790 dc->tb = tb;
7791
2c0262af 7792 gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
2c0262af
FB
7793
7794 dc->is_jmp = DISAS_NEXT;
7795 dc->pc = pc_start;
8aaca4c0 7796 dc->singlestep_enabled = env->singlestep_enabled;
e50e6a20 7797 dc->condjmp = 0;
5899f386 7798 dc->thumb = env->thumb;
9ee6e8bb
PB
7799 dc->condexec_mask = (env->condexec_bits & 0xf) << 1;
7800 dc->condexec_cond = env->condexec_bits >> 4;
6658ffb8 7801 dc->is_mem = 0;
b5ff1b31 7802#if !defined(CONFIG_USER_ONLY)
9ee6e8bb
PB
7803 if (IS_M(env)) {
7804 dc->user = ((env->v7m.exception == 0) && (env->v7m.control & 1));
7805 } else {
7806 dc->user = (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_USR;
7807 }
b5ff1b31
FB
7808#endif
7809 next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
2c0262af 7810 lj = -1;
9ee6e8bb
PB
7811 /* Reset the conditional execution bits immediately. This avoids
7812 complications trying to do it at the end of the block. */
7813 if (env->condexec_bits)
8f01245e
PB
7814 {
7815 TCGv tmp = new_tmp();
7816 tcg_gen_movi_i32(tmp, 0);
7817 tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, condexec_bits));
7818 dead_tmp(tmp);
7819 }
2c0262af 7820 do {
9ee6e8bb
PB
7821#ifndef CONFIG_USER_ONLY
7822 if (dc->pc >= 0xfffffff0 && IS_M(env)) {
7823 /* We always get here via a jump, so know we are not in a
7824 conditional execution block. */
7825 gen_op_exception_exit();
7826 }
7827#endif
7828
1fddef4b
FB
7829 if (env->nb_breakpoints > 0) {
7830 for(j = 0; j < env->nb_breakpoints; j++) {
7831 if (env->breakpoints[j] == dc->pc) {
9ee6e8bb 7832 gen_set_condexec(dc);
1fddef4b 7833 gen_op_movl_T0_im((long)dc->pc);
b26eefb6 7834 gen_set_pc_T0();
1fddef4b
FB
7835 gen_op_debug();
7836 dc->is_jmp = DISAS_JUMP;
9ee6e8bb
PB
7837 /* Advance PC so that clearing the breakpoint will
7838 invalidate this TB. */
7839 dc->pc += 2;
7840 goto done_generating;
1fddef4b
FB
7841 break;
7842 }
7843 }
7844 }
2c0262af
FB
7845 if (search_pc) {
7846 j = gen_opc_ptr - gen_opc_buf;
7847 if (lj < j) {
7848 lj++;
7849 while (lj < j)
7850 gen_opc_instr_start[lj++] = 0;
7851 }
0fa85d43 7852 gen_opc_pc[lj] = dc->pc;
2c0262af
FB
7853 gen_opc_instr_start[lj] = 1;
7854 }
e50e6a20 7855
9ee6e8bb
PB
7856 if (env->thumb) {
7857 disas_thumb_insn(env, dc);
7858 if (dc->condexec_mask) {
7859 dc->condexec_cond = (dc->condexec_cond & 0xe)
7860 | ((dc->condexec_mask >> 4) & 1);
7861 dc->condexec_mask = (dc->condexec_mask << 1) & 0x1f;
7862 if (dc->condexec_mask == 0) {
7863 dc->condexec_cond = 0;
7864 }
7865 }
7866 } else {
7867 disas_arm_insn(env, dc);
7868 }
b26eefb6
PB
7869 if (num_temps) {
7870 fprintf(stderr, "Internal resource leak before %08x\n", dc->pc);
7871 num_temps = 0;
7872 }
e50e6a20
FB
7873
7874 if (dc->condjmp && !dc->is_jmp) {
7875 gen_set_label(dc->condlabel);
7876 dc->condjmp = 0;
7877 }
6658ffb8
PB
7878 /* Terminate the TB on memory ops if watchpoints are present. */
7879 /* FIXME: This should be replacd by the deterministic execution
7880 * IRQ raising bits. */
7881 if (dc->is_mem && env->nb_watchpoints)
7882 break;
7883
e50e6a20
FB
7884 /* Translation stops when a conditional branch is enoutered.
7885 * Otherwise the subsequent code could get translated several times.
b5ff1b31
FB
7886 * Also stop translation when a page boundary is reached. This
7887 * ensures prefech aborts occur at the right place. */
1fddef4b
FB
7888 } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
7889 !env->singlestep_enabled &&
b5ff1b31 7890 dc->pc < next_page_start);
9ee6e8bb 7891
b5ff1b31 7892 /* At this stage dc->condjmp will only be set when the skipped
9ee6e8bb
PB
7893 instruction was a conditional branch or trap, and the PC has
7894 already been written. */
8aaca4c0
FB
7895 if (__builtin_expect(env->singlestep_enabled, 0)) {
7896 /* Make sure the pc is updated, and raise a debug exception. */
e50e6a20 7897 if (dc->condjmp) {
9ee6e8bb
PB
7898 gen_set_condexec(dc);
7899 if (dc->is_jmp == DISAS_SWI) {
7900 gen_op_swi();
7901 } else {
7902 gen_op_debug();
7903 }
e50e6a20
FB
7904 gen_set_label(dc->condlabel);
7905 }
7906 if (dc->condjmp || !dc->is_jmp) {
8aaca4c0 7907 gen_op_movl_T0_im((long)dc->pc);
b26eefb6 7908 gen_set_pc_T0();
e50e6a20 7909 dc->condjmp = 0;
8aaca4c0 7910 }
9ee6e8bb
PB
7911 gen_set_condexec(dc);
7912 if (dc->is_jmp == DISAS_SWI && !dc->condjmp) {
7913 gen_op_swi();
7914 } else {
7915 /* FIXME: Single stepping a WFI insn will not halt
7916 the CPU. */
7917 gen_op_debug();
7918 }
8aaca4c0 7919 } else {
9ee6e8bb
PB
7920 /* While branches must always occur at the end of an IT block,
7921 there are a few other things that can cause us to terminate
7922 the TB in the middel of an IT block:
7923 - Exception generating instructions (bkpt, swi, undefined).
7924 - Page boundaries.
7925 - Hardware watchpoints.
7926 Hardware breakpoints have already been handled and skip this code.
7927 */
7928 gen_set_condexec(dc);
8aaca4c0 7929 switch(dc->is_jmp) {
8aaca4c0 7930 case DISAS_NEXT:
6e256c93 7931 gen_goto_tb(dc, 1, dc->pc);
8aaca4c0
FB
7932 break;
7933 default:
7934 case DISAS_JUMP:
7935 case DISAS_UPDATE:
7936 /* indicate that the hash table must be used to find the next TB */
57fec1fe 7937 tcg_gen_exit_tb(0);
8aaca4c0
FB
7938 break;
7939 case DISAS_TB_JUMP:
7940 /* nothing more to generate */
7941 break;
9ee6e8bb
PB
7942 case DISAS_WFI:
7943 gen_op_wfi();
7944 break;
7945 case DISAS_SWI:
7946 gen_op_swi();
7947 break;
8aaca4c0 7948 }
e50e6a20
FB
7949 if (dc->condjmp) {
7950 gen_set_label(dc->condlabel);
9ee6e8bb 7951 gen_set_condexec(dc);
6e256c93 7952 gen_goto_tb(dc, 1, dc->pc);
e50e6a20
FB
7953 dc->condjmp = 0;
7954 }
2c0262af 7955 }
9ee6e8bb 7956done_generating:
2c0262af
FB
7957 *gen_opc_ptr = INDEX_op_end;
7958
7959#ifdef DEBUG_DISAS
e19e89a5 7960 if (loglevel & CPU_LOG_TB_IN_ASM) {
2c0262af
FB
7961 fprintf(logfile, "----------------\n");
7962 fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
5899f386 7963 target_disas(logfile, pc_start, dc->pc - pc_start, env->thumb);
2c0262af
FB
7964 fprintf(logfile, "\n");
7965 }
7966#endif
b5ff1b31
FB
7967 if (search_pc) {
7968 j = gen_opc_ptr - gen_opc_buf;
7969 lj++;
7970 while (lj <= j)
7971 gen_opc_instr_start[lj++] = 0;
b5ff1b31 7972 } else {
2c0262af 7973 tb->size = dc->pc - pc_start;
b5ff1b31 7974 }
2c0262af
FB
7975 return 0;
7976}
7977
7978int gen_intermediate_code(CPUState *env, TranslationBlock *tb)
7979{
7980 return gen_intermediate_code_internal(env, tb, 0);
7981}
7982
7983int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
7984{
7985 return gen_intermediate_code_internal(env, tb, 1);
7986}
7987
b5ff1b31
FB
7988static const char *cpu_mode_names[16] = {
7989 "usr", "fiq", "irq", "svc", "???", "???", "???", "abt",
7990 "???", "???", "???", "und", "???", "???", "???", "sys"
7991};
9ee6e8bb 7992
5fafdf24 7993void cpu_dump_state(CPUState *env, FILE *f,
7fe48483
FB
7994 int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
7995 int flags)
2c0262af
FB
7996{
7997 int i;
bc380d17 7998 union {
b7bcbe95
FB
7999 uint32_t i;
8000 float s;
8001 } s0, s1;
8002 CPU_DoubleU d;
a94a6abf
PB
8003 /* ??? This assumes float64 and double have the same layout.
8004 Oh well, it's only debug dumps. */
8005 union {
8006 float64 f64;
8007 double d;
8008 } d0;
b5ff1b31 8009 uint32_t psr;
2c0262af
FB
8010
8011 for(i=0;i<16;i++) {
7fe48483 8012 cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
2c0262af 8013 if ((i % 4) == 3)
7fe48483 8014 cpu_fprintf(f, "\n");
2c0262af 8015 else
7fe48483 8016 cpu_fprintf(f, " ");
2c0262af 8017 }
b5ff1b31 8018 psr = cpsr_read(env);
687fa640
TS
8019 cpu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%d\n",
8020 psr,
b5ff1b31
FB
8021 psr & (1 << 31) ? 'N' : '-',
8022 psr & (1 << 30) ? 'Z' : '-',
8023 psr & (1 << 29) ? 'C' : '-',
8024 psr & (1 << 28) ? 'V' : '-',
5fafdf24 8025 psr & CPSR_T ? 'T' : 'A',
b5ff1b31 8026 cpu_mode_names[psr & 0xf], (psr & 0x10) ? 32 : 26);
b7bcbe95
FB
8027
8028 for (i = 0; i < 16; i++) {
8e96005d
FB
8029 d.d = env->vfp.regs[i];
8030 s0.i = d.l.lower;
8031 s1.i = d.l.upper;
a94a6abf
PB
8032 d0.f64 = d.d;
8033 cpu_fprintf(f, "s%02d=%08x(%8g) s%02d=%08x(%8g) d%02d=%08x%08x(%8g)\n",
b7bcbe95 8034 i * 2, (int)s0.i, s0.s,
a94a6abf 8035 i * 2 + 1, (int)s1.i, s1.s,
b7bcbe95 8036 i, (int)(uint32_t)d.l.upper, (int)(uint32_t)d.l.lower,
a94a6abf 8037 d0.d);
b7bcbe95 8038 }
40f137e1 8039 cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.xregs[ARM_VFP_FPSCR]);
2c0262af 8040}
a6b025d3 8041