blob: fdba7ddccbb92138e1f4cd41ea59e6187aef6225 [file] [log] [blame]
bellard2c0262a2003-09-30 20:34:21 +00001/*
2 * ARM translation
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard2c0262a2003-09-30 20:34:21 +00004 * Copyright (c) 2003 Fabrice Bellard
pbrook9ee6e8b2007-11-11 00:04:49 +00005 * Copyright (c) 2005-2007 CodeSourcery
balrog18c9b562007-04-30 02:02:17 +00006 * Copyright (c) 2007 OpenedHand, Ltd.
bellard2c0262a2003-09-30 20:34:21 +00007 *
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"
bellard57fec1f2008-02-01 10:50:11 +000031#include "tcg-op.h"
pbrook1497c962008-03-31 03:45:50 +000032
33#define GEN_HELPER 1
pbrookb26eefb2008-03-31 03:44:26 +000034#include "helpers.h"
bellard2c0262a2003-09-30 20:34:21 +000035
pbrook9ee6e8b2007-11-11 00:04:49 +000036#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)
bellardb5ff1b32005-11-26 10:38:39 +000041
42#define ARCH(x) if (!ENABLE_ARCH_##x) goto illegal_op;
43
bellard2c0262a2003-09-30 20:34:21 +000044/* internal defines */
45typedef struct DisasContext {
bellard0fa85d42005-01-03 23:43:32 +000046 target_ulong pc;
bellard2c0262a2003-09-30 20:34:21 +000047 int is_jmp;
bellarde50e6a22005-04-26 20:36:11 +000048 /* 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;
pbrook9ee6e8b2007-11-11 00:04:49 +000052 /* Thumb-2 condtional execution bits. */
53 int condexec_mask;
54 int condexec_cond;
bellard2c0262a2003-09-30 20:34:21 +000055 struct TranslationBlock *tb;
bellard8aaca4c2005-04-23 18:27:52 +000056 int singlestep_enabled;
bellard5899f382005-04-27 20:25:20 +000057 int thumb;
pbrook6658ffb2007-03-16 23:58:11 +000058 int is_mem;
bellardb5ff1b32005-11-26 10:38:39 +000059#if !defined(CONFIG_USER_ONLY)
60 int user;
61#endif
bellard2c0262a2003-09-30 20:34:21 +000062} DisasContext;
63
bellardb5ff1b32005-11-26 10:38:39 +000064#if defined(CONFIG_USER_ONLY)
65#define IS_USER(s) 1
66#else
67#define IS_USER(s) (s->user)
68#endif
69
pbrook9ee6e8b2007-11-11 00:04:49 +000070/* 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
bellard2c0262a2003-09-30 20:34:21 +000074
75/* XXX: move that elsewhere */
bellard2c0262a2003-09-30 20:34:21 +000076extern FILE *logfile;
77extern int loglevel;
78
pbrookb26eefb2008-03-31 03:44:26 +000079static TCGv cpu_env;
pbrookad694712008-03-31 03:48:30 +000080/* We reuse the same 64-bit temporaries for efficiency. */
pbrooke6771372008-03-31 03:49:05 +000081static TCGv cpu_V0, cpu_V1, cpu_M0;
pbrookad694712008-03-31 03:48:30 +000082
pbrookb26eefb2008-03-31 03:44:26 +000083/* FIXME: These should be removed. */
pbrook8f8e3aa2008-03-31 03:48:01 +000084static TCGv cpu_T[2];
pbrook4373f3c2008-03-31 03:47:19 +000085static TCGv cpu_F0s, cpu_F1s, cpu_F0d, cpu_F1d;
pbrookb26eefb2008-03-31 03:44:26 +000086
87/* initialize TCG globals. */
88void arm_translate_init(void)
89{
90 cpu_env = tcg_global_reg_new(TCG_TYPE_PTR, TCG_AREG0, "env");
91
92 cpu_T[0] = tcg_global_reg_new(TCG_TYPE_I32, TCG_AREG1, "T0");
93 cpu_T[1] = tcg_global_reg_new(TCG_TYPE_I32, TCG_AREG2, "T1");
pbrookb26eefb2008-03-31 03:44:26 +000094}
95
96/* The code generator doesn't like lots of temporaries, so maintain our own
97 cache for reuse within a function. */
98#define MAX_TEMPS 8
99static int num_temps;
100static TCGv temps[MAX_TEMPS];
101
102/* Allocate a temporary variable. */
103static TCGv new_tmp(void)
104{
105 TCGv tmp;
106 if (num_temps == MAX_TEMPS)
107 abort();
108
109 if (GET_TCGV(temps[num_temps]))
110 return temps[num_temps++];
111
112 tmp = tcg_temp_new(TCG_TYPE_I32);
113 temps[num_temps++] = tmp;
114 return tmp;
115}
116
117/* Release a temporary variable. */
118static void dead_tmp(TCGv tmp)
119{
120 int i;
121 num_temps--;
122 i = num_temps;
123 if (GET_TCGV(temps[i]) == GET_TCGV(tmp))
124 return;
125
126 /* Shuffle this temp to the last slot. */
127 while (GET_TCGV(temps[i]) != GET_TCGV(tmp))
128 i--;
129 while (i < num_temps) {
130 temps[i] = temps[i + 1];
131 i++;
132 }
133 temps[i] = tmp;
134}
135
pbrookd9ba4832008-03-31 03:46:50 +0000136static inline TCGv load_cpu_offset(int offset)
137{
138 TCGv tmp = new_tmp();
139 tcg_gen_ld_i32(tmp, cpu_env, offset);
140 return tmp;
141}
142
143#define load_cpu_field(name) load_cpu_offset(offsetof(CPUState, name))
144
145static inline void store_cpu_offset(TCGv var, int offset)
146{
147 tcg_gen_st_i32(var, cpu_env, offset);
148 dead_tmp(var);
149}
150
151#define store_cpu_field(var, name) \
152 store_cpu_offset(var, offsetof(CPUState, name))
153
pbrookb26eefb2008-03-31 03:44:26 +0000154/* Set a variable to the value of a CPU register. */
155static void load_reg_var(DisasContext *s, TCGv var, int reg)
156{
157 if (reg == 15) {
158 uint32_t addr;
159 /* normaly, since we updated PC, we need only to add one insn */
160 if (s->thumb)
161 addr = (long)s->pc + 2;
162 else
163 addr = (long)s->pc + 4;
164 tcg_gen_movi_i32(var, addr);
165 } else {
166 tcg_gen_ld_i32(var, cpu_env, offsetof(CPUState, regs[reg]));
167 }
168}
169
170/* Create a new temporary and set it to the value of a CPU register. */
171static inline TCGv load_reg(DisasContext *s, int reg)
172{
173 TCGv tmp = new_tmp();
174 load_reg_var(s, tmp, reg);
175 return tmp;
176}
177
178/* Set a CPU register. The source must be a temporary and will be
179 marked as dead. */
180static void store_reg(DisasContext *s, int reg, TCGv var)
181{
182 if (reg == 15) {
183 tcg_gen_andi_i32(var, var, ~1);
184 s->is_jmp = DISAS_JUMP;
185 }
186 tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, regs[reg]));
187 dead_tmp(var);
188}
189
190
191/* Basic operations. */
192#define gen_op_movl_T0_T1() tcg_gen_mov_i32(cpu_T[0], cpu_T[1])
pbrookb26eefb2008-03-31 03:44:26 +0000193#define gen_op_movl_T1_T0() tcg_gen_mov_i32(cpu_T[1], cpu_T[0])
pbrookb26eefb2008-03-31 03:44:26 +0000194#define gen_op_movl_T0_im(im) tcg_gen_movi_i32(cpu_T[0], im)
195#define gen_op_movl_T1_im(im) tcg_gen_movi_i32(cpu_T[1], im)
pbrookb26eefb2008-03-31 03:44:26 +0000196
197#define gen_op_addl_T1_im(im) tcg_gen_addi_i32(cpu_T[1], cpu_T[1], im)
198#define gen_op_addl_T0_T1() tcg_gen_add_i32(cpu_T[0], cpu_T[0], cpu_T[1])
199#define gen_op_subl_T0_T1() tcg_gen_sub_i32(cpu_T[0], cpu_T[0], cpu_T[1])
200#define gen_op_rsbl_T0_T1() tcg_gen_sub_i32(cpu_T[0], cpu_T[1], cpu_T[0])
201
pbrook8984bd22008-03-31 03:47:48 +0000202#define gen_op_addl_T0_T1_cc() gen_helper_add_cc(cpu_T[0], cpu_T[0], cpu_T[1])
203#define gen_op_adcl_T0_T1_cc() gen_helper_adc_cc(cpu_T[0], cpu_T[0], cpu_T[1])
204#define gen_op_subl_T0_T1_cc() gen_helper_sub_cc(cpu_T[0], cpu_T[0], cpu_T[1])
205#define gen_op_sbcl_T0_T1_cc() gen_helper_sbc_cc(cpu_T[0], cpu_T[0], cpu_T[1])
206#define gen_op_rsbl_T0_T1_cc() gen_helper_sub_cc(cpu_T[0], cpu_T[1], cpu_T[0])
207#define gen_op_rscl_T0_T1_cc() gen_helper_sbc_cc(cpu_T[0], cpu_T[1], cpu_T[0])
208
pbrookb26eefb2008-03-31 03:44:26 +0000209#define gen_op_andl_T0_T1() tcg_gen_and_i32(cpu_T[0], cpu_T[0], cpu_T[1])
210#define gen_op_xorl_T0_T1() tcg_gen_xor_i32(cpu_T[0], cpu_T[0], cpu_T[1])
211#define gen_op_orl_T0_T1() tcg_gen_or_i32(cpu_T[0], cpu_T[0], cpu_T[1])
212#define gen_op_notl_T0() tcg_gen_not_i32(cpu_T[0], cpu_T[0])
213#define gen_op_notl_T1() tcg_gen_not_i32(cpu_T[1], cpu_T[1])
214#define gen_op_logic_T0_cc() gen_logic_CC(cpu_T[0]);
215#define gen_op_logic_T1_cc() gen_logic_CC(cpu_T[1]);
216
217#define gen_op_shll_T0_im(im) tcg_gen_shli_i32(cpu_T[0], cpu_T[0], im)
218#define gen_op_shll_T1_im(im) tcg_gen_shli_i32(cpu_T[1], cpu_T[1], im)
219#define gen_op_shrl_T1_im(im) tcg_gen_shri_i32(cpu_T[1], cpu_T[1], im)
220#define gen_op_sarl_T1_im(im) tcg_gen_sari_i32(cpu_T[1], cpu_T[1], im)
221#define gen_op_rorl_T1_im(im) tcg_gen_rori_i32(cpu_T[1], cpu_T[1], im)
222
223/* Value extensions. */
224#define gen_uxtb(var) tcg_gen_andi_i32(var, var, 0xff)
225#define gen_uxth(var) tcg_gen_andi_i32(var, var, 0xffff)
226#define gen_sxtb(var) tcg_gen_ext8s_i32(var, var)
227#define gen_sxth(var) tcg_gen_ext16s_i32(var, var)
228
pbrook1497c962008-03-31 03:45:50 +0000229#define gen_sxtb16(var) gen_helper_sxtb16(var, var)
230#define gen_uxtb16(var) gen_helper_uxtb16(var, var)
pbrook8f012452008-03-31 03:46:03 +0000231
232#define gen_op_mul_T0_T1() tcg_gen_mul_i32(cpu_T[0], cpu_T[0], cpu_T[1])
pbrookb26eefb2008-03-31 03:44:26 +0000233
pbrookd9ba4832008-03-31 03:46:50 +0000234#define gen_set_cpsr(var, mask) gen_helper_cpsr_write(var, tcg_const_i32(mask))
235/* Set NZCV flags from the high 4 bits of var. */
236#define gen_set_nzcv(var) gen_set_cpsr(var, CPSR_NZCV)
237
238static void gen_exception(int excp)
239{
240 TCGv tmp = new_tmp();
241 tcg_gen_movi_i32(tmp, excp);
242 gen_helper_exception(tmp);
243 dead_tmp(tmp);
244}
245
pbrook36706692008-03-31 03:46:19 +0000246static void gen_smul_dual(TCGv a, TCGv b)
247{
248 TCGv tmp1 = new_tmp();
249 TCGv tmp2 = new_tmp();
pbrook36706692008-03-31 03:46:19 +0000250 tcg_gen_ext8s_i32(tmp1, a);
251 tcg_gen_ext8s_i32(tmp2, b);
252 tcg_gen_mul_i32(tmp1, tmp1, tmp2);
253 dead_tmp(tmp2);
254 tcg_gen_sari_i32(a, a, 16);
255 tcg_gen_sari_i32(b, b, 16);
256 tcg_gen_mul_i32(b, b, a);
257 tcg_gen_mov_i32(a, tmp1);
258 dead_tmp(tmp1);
259}
260
261/* Byteswap each halfword. */
262static void gen_rev16(TCGv var)
263{
264 TCGv tmp = new_tmp();
265 tcg_gen_shri_i32(tmp, var, 8);
266 tcg_gen_andi_i32(tmp, tmp, 0x00ff00ff);
267 tcg_gen_shli_i32(var, var, 8);
268 tcg_gen_andi_i32(var, var, 0xff00ff00);
269 tcg_gen_or_i32(var, var, tmp);
270 dead_tmp(tmp);
271}
272
273/* Byteswap low halfword and sign extend. */
274static void gen_revsh(TCGv var)
275{
276 TCGv tmp = new_tmp();
277 tcg_gen_shri_i32(tmp, var, 8);
278 tcg_gen_andi_i32(tmp, tmp, 0x00ff);
279 tcg_gen_shli_i32(var, var, 8);
280 tcg_gen_ext8s_i32(var, var);
281 tcg_gen_or_i32(var, var, tmp);
282 dead_tmp(tmp);
283}
284
285/* Unsigned bitfield extract. */
286static void gen_ubfx(TCGv var, int shift, uint32_t mask)
287{
288 if (shift)
289 tcg_gen_shri_i32(var, var, shift);
290 tcg_gen_andi_i32(var, var, mask);
291}
292
293/* Signed bitfield extract. */
294static void gen_sbfx(TCGv var, int shift, int width)
295{
296 uint32_t signbit;
297
298 if (shift)
299 tcg_gen_sari_i32(var, var, shift);
300 if (shift + width < 32) {
301 signbit = 1u << (width - 1);
302 tcg_gen_andi_i32(var, var, (1u << width) - 1);
303 tcg_gen_xori_i32(var, var, signbit);
304 tcg_gen_subi_i32(var, var, signbit);
305 }
306}
307
308/* Bitfield insertion. Insert val into base. Clobbers base and val. */
309static void gen_bfi(TCGv dest, TCGv base, TCGv val, int shift, uint32_t mask)
310{
pbrook36706692008-03-31 03:46:19 +0000311 tcg_gen_andi_i32(val, val, mask);
pbrook8f8e3aa2008-03-31 03:48:01 +0000312 tcg_gen_shli_i32(val, val, shift);
313 tcg_gen_andi_i32(base, base, ~(mask << shift));
pbrook36706692008-03-31 03:46:19 +0000314 tcg_gen_or_i32(dest, base, val);
315}
316
pbrookd9ba4832008-03-31 03:46:50 +0000317/* Round the top 32 bits of a 64-bit value. */
318static void gen_roundqd(TCGv a, TCGv b)
pbrook36706692008-03-31 03:46:19 +0000319{
pbrookd9ba4832008-03-31 03:46:50 +0000320 tcg_gen_shri_i32(a, a, 31);
321 tcg_gen_add_i32(a, a, b);
pbrook36706692008-03-31 03:46:19 +0000322}
323
pbrook8f012452008-03-31 03:46:03 +0000324/* FIXME: Most targets have native widening multiplication.
325 It would be good to use that instead of a full wide multiply. */
pbrook5e3f8782008-03-31 03:47:34 +0000326/* 32x32->64 multiply. Marks inputs as dead. */
327static TCGv gen_mulu_i64_i32(TCGv a, TCGv b)
328{
329 TCGv tmp1 = tcg_temp_new(TCG_TYPE_I64);
330 TCGv tmp2 = tcg_temp_new(TCG_TYPE_I64);
331
332 tcg_gen_extu_i32_i64(tmp1, a);
333 dead_tmp(a);
334 tcg_gen_extu_i32_i64(tmp2, b);
335 dead_tmp(b);
336 tcg_gen_mul_i64(tmp1, tmp1, tmp2);
337 return tmp1;
338}
339
340static TCGv gen_muls_i64_i32(TCGv a, TCGv b)
341{
342 TCGv tmp1 = tcg_temp_new(TCG_TYPE_I64);
343 TCGv tmp2 = tcg_temp_new(TCG_TYPE_I64);
344
345 tcg_gen_ext_i32_i64(tmp1, a);
346 dead_tmp(a);
347 tcg_gen_ext_i32_i64(tmp2, b);
348 dead_tmp(b);
349 tcg_gen_mul_i64(tmp1, tmp1, tmp2);
350 return tmp1;
351}
352
pbrook8f012452008-03-31 03:46:03 +0000353/* Unsigned 32x32->64 multiply. */
354static void gen_op_mull_T0_T1(void)
355{
356 TCGv tmp1 = tcg_temp_new(TCG_TYPE_I64);
357 TCGv tmp2 = tcg_temp_new(TCG_TYPE_I64);
358
359 tcg_gen_extu_i32_i64(tmp1, cpu_T[0]);
360 tcg_gen_extu_i32_i64(tmp2, cpu_T[1]);
361 tcg_gen_mul_i64(tmp1, tmp1, tmp2);
362 tcg_gen_trunc_i64_i32(cpu_T[0], tmp1);
363 tcg_gen_shri_i64(tmp1, tmp1, 32);
364 tcg_gen_trunc_i64_i32(cpu_T[1], tmp1);
365}
366
367/* Signed 32x32->64 multiply. */
pbrookd9ba4832008-03-31 03:46:50 +0000368static void gen_imull(TCGv a, TCGv b)
pbrook8f012452008-03-31 03:46:03 +0000369{
370 TCGv tmp1 = tcg_temp_new(TCG_TYPE_I64);
371 TCGv tmp2 = tcg_temp_new(TCG_TYPE_I64);
372
pbrookd9ba4832008-03-31 03:46:50 +0000373 tcg_gen_ext_i32_i64(tmp1, a);
374 tcg_gen_ext_i32_i64(tmp2, b);
pbrook8f012452008-03-31 03:46:03 +0000375 tcg_gen_mul_i64(tmp1, tmp1, tmp2);
pbrookd9ba4832008-03-31 03:46:50 +0000376 tcg_gen_trunc_i64_i32(a, tmp1);
pbrook8f012452008-03-31 03:46:03 +0000377 tcg_gen_shri_i64(tmp1, tmp1, 32);
pbrookd9ba4832008-03-31 03:46:50 +0000378 tcg_gen_trunc_i64_i32(b, tmp1);
379}
380#define gen_op_imull_T0_T1() gen_imull(cpu_T[0], cpu_T[1])
381
pbrook8f012452008-03-31 03:46:03 +0000382/* Swap low and high halfwords. */
383static void gen_swap_half(TCGv var)
384{
385 TCGv tmp = new_tmp();
386 tcg_gen_shri_i32(tmp, var, 16);
387 tcg_gen_shli_i32(var, var, 16);
388 tcg_gen_or_i32(var, var, tmp);
pbrook36706692008-03-31 03:46:19 +0000389 dead_tmp(tmp);
pbrook8f012452008-03-31 03:46:03 +0000390}
391
pbrookb26eefb2008-03-31 03:44:26 +0000392/* Dual 16-bit add. Result placed in t0 and t1 is marked as dead.
393 tmp = (t0 ^ t1) & 0x8000;
394 t0 &= ~0x8000;
395 t1 &= ~0x8000;
396 t0 = (t0 + t1) ^ tmp;
397 */
398
399static void gen_add16(TCGv t0, TCGv t1)
400{
401 TCGv tmp = new_tmp();
402 tcg_gen_xor_i32(tmp, t0, t1);
403 tcg_gen_andi_i32(tmp, tmp, 0x8000);
404 tcg_gen_andi_i32(t0, t0, ~0x8000);
405 tcg_gen_andi_i32(t1, t1, ~0x8000);
406 tcg_gen_add_i32(t0, t0, t1);
407 tcg_gen_xor_i32(t0, t0, tmp);
408 dead_tmp(tmp);
409 dead_tmp(t1);
410}
411
pbrook9a119ff2008-03-31 03:45:35 +0000412#define gen_set_CF(var) tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, CF))
413
pbrookb26eefb2008-03-31 03:44:26 +0000414/* Set CF to the top bit of var. */
415static void gen_set_CF_bit31(TCGv var)
416{
417 TCGv tmp = new_tmp();
418 tcg_gen_shri_i32(tmp, var, 31);
pbrook9a119ff2008-03-31 03:45:35 +0000419 gen_set_CF(var);
pbrookb26eefb2008-03-31 03:44:26 +0000420 dead_tmp(tmp);
421}
422
423/* Set N and Z flags from var. */
424static inline void gen_logic_CC(TCGv var)
425{
426 tcg_gen_st_i32(var, cpu_env, offsetof(CPUState, NZF));
427}
428
429/* T0 += T1 + CF. */
430static void gen_adc_T0_T1(void)
431{
pbrookd9ba4832008-03-31 03:46:50 +0000432 TCGv tmp;
pbrookb26eefb2008-03-31 03:44:26 +0000433 gen_op_addl_T0_T1();
pbrookd9ba4832008-03-31 03:46:50 +0000434 tmp = load_cpu_field(CF);
pbrookb26eefb2008-03-31 03:44:26 +0000435 tcg_gen_add_i32(cpu_T[0], cpu_T[0], tmp);
436 dead_tmp(tmp);
437}
438
pbrook36706692008-03-31 03:46:19 +0000439/* dest = T0 - T1 + CF - 1. */
440static void gen_sub_carry(TCGv dest, TCGv t0, TCGv t1)
441{
pbrookd9ba4832008-03-31 03:46:50 +0000442 TCGv tmp;
pbrook36706692008-03-31 03:46:19 +0000443 tcg_gen_sub_i32(dest, t0, t1);
pbrookd9ba4832008-03-31 03:46:50 +0000444 tmp = load_cpu_field(CF);
pbrook36706692008-03-31 03:46:19 +0000445 tcg_gen_add_i32(dest, dest, tmp);
446 tcg_gen_subi_i32(dest, dest, 1);
447 dead_tmp(tmp);
448}
449
450#define gen_sbc_T0_T1() gen_sub_carry(cpu_T[0], cpu_T[0], cpu_T[1])
451#define gen_rsc_T0_T1() gen_sub_carry(cpu_T[0], cpu_T[1], cpu_T[0])
452
pbrookb26eefb2008-03-31 03:44:26 +0000453/* FIXME: Implement this natively. */
454static inline void tcg_gen_not_i32(TCGv t0, TCGv t1)
455{
456 tcg_gen_xori_i32(t0, t1, ~0);
457}
458
pbrooke6771372008-03-31 03:49:05 +0000459/* FIXME: Implement this natively. */
460static inline void tcg_gen_neg_i64(TCGv dest, TCGv src)
461{
462 tcg_gen_sub_i64(dest, tcg_const_i64(0), src);
463}
464
pbrookb26eefb2008-03-31 03:44:26 +0000465/* T0 &= ~T1. Clobbers T1. */
466/* FIXME: Implement bic natively. */
pbrook8f8e3aa2008-03-31 03:48:01 +0000467static inline void tcg_gen_bic_i32(TCGv dest, TCGv t0, TCGv t1)
468{
469 TCGv tmp = new_tmp();
470 tcg_gen_not_i32(tmp, t1);
471 tcg_gen_and_i32(dest, t0, tmp);
472 dead_tmp(tmp);
473}
pbrookb26eefb2008-03-31 03:44:26 +0000474static inline void gen_op_bicl_T0_T1(void)
475{
476 gen_op_notl_T1();
477 gen_op_andl_T0_T1();
478}
479
480/* FIXME: Implement this natively. */
pbrookad694712008-03-31 03:48:30 +0000481#define tcg_gen_abs_i32(t0, t1) gen_helper_abs(t0, t1)
482
483/* FIXME: Implement this natively. */
pbrookb26eefb2008-03-31 03:44:26 +0000484static void tcg_gen_rori_i32(TCGv t0, TCGv t1, int i)
485{
486 TCGv tmp;
487
488 if (i == 0)
489 return;
490
491 tmp = new_tmp();
492 tcg_gen_shri_i32(tmp, t1, i);
493 tcg_gen_shli_i32(t1, t1, 32 - i);
494 tcg_gen_or_i32(t0, t1, tmp);
495 dead_tmp(tmp);
496}
497
pbrook9a119ff2008-03-31 03:45:35 +0000498static void shifter_out_im(TCGv var, int shift)
pbrookb26eefb2008-03-31 03:44:26 +0000499{
pbrook9a119ff2008-03-31 03:45:35 +0000500 TCGv tmp = new_tmp();
501 if (shift == 0) {
502 tcg_gen_andi_i32(tmp, var, 1);
pbrookb26eefb2008-03-31 03:44:26 +0000503 } else {
pbrook9a119ff2008-03-31 03:45:35 +0000504 tcg_gen_shri_i32(tmp, var, shift);
505 if (shift != 31);
506 tcg_gen_andi_i32(tmp, tmp, 1);
507 }
508 gen_set_CF(tmp);
509 dead_tmp(tmp);
510}
pbrookb26eefb2008-03-31 03:44:26 +0000511
pbrook9a119ff2008-03-31 03:45:35 +0000512/* Shift by immediate. Includes special handling for shift == 0. */
513static inline void gen_arm_shift_im(TCGv var, int shiftop, int shift, int flags)
514{
515 switch (shiftop) {
516 case 0: /* LSL */
517 if (shift != 0) {
518 if (flags)
519 shifter_out_im(var, 32 - shift);
520 tcg_gen_shli_i32(var, var, shift);
521 }
522 break;
523 case 1: /* LSR */
524 if (shift == 0) {
525 if (flags) {
526 tcg_gen_shri_i32(var, var, 31);
527 gen_set_CF(var);
528 }
529 tcg_gen_movi_i32(var, 0);
530 } else {
531 if (flags)
532 shifter_out_im(var, shift - 1);
533 tcg_gen_shri_i32(var, var, shift);
534 }
535 break;
536 case 2: /* ASR */
537 if (shift == 0)
538 shift = 32;
539 if (flags)
540 shifter_out_im(var, shift - 1);
541 if (shift == 32)
542 shift = 31;
543 tcg_gen_sari_i32(var, var, shift);
544 break;
545 case 3: /* ROR/RRX */
546 if (shift != 0) {
547 if (flags)
548 shifter_out_im(var, shift - 1);
549 tcg_gen_rori_i32(var, var, shift); break;
550 } else {
pbrookd9ba4832008-03-31 03:46:50 +0000551 TCGv tmp = load_cpu_field(CF);
pbrook9a119ff2008-03-31 03:45:35 +0000552 if (flags)
553 shifter_out_im(var, 0);
554 tcg_gen_shri_i32(var, var, 1);
pbrookb26eefb2008-03-31 03:44:26 +0000555 tcg_gen_shli_i32(tmp, tmp, 31);
556 tcg_gen_or_i32(var, var, tmp);
557 dead_tmp(tmp);
pbrookb26eefb2008-03-31 03:44:26 +0000558 }
559 }
560};
561
pbrook8984bd22008-03-31 03:47:48 +0000562static inline void gen_arm_shift_reg(TCGv var, int shiftop,
563 TCGv shift, int flags)
564{
565 if (flags) {
566 switch (shiftop) {
567 case 0: gen_helper_shl_cc(var, var, shift); break;
568 case 1: gen_helper_shr_cc(var, var, shift); break;
569 case 2: gen_helper_sar_cc(var, var, shift); break;
570 case 3: gen_helper_ror_cc(var, var, shift); break;
571 }
572 } else {
573 switch (shiftop) {
574 case 0: gen_helper_shl(var, var, shift); break;
575 case 1: gen_helper_shr(var, var, shift); break;
576 case 2: gen_helper_sar(var, var, shift); break;
577 case 3: gen_helper_ror(var, var, shift); break;
578 }
579 }
580 dead_tmp(shift);
581}
582
pbrook6ddbc6e2008-03-31 03:46:33 +0000583#define PAS_OP(pfx) \
584 switch (op2) { \
585 case 0: gen_pas_helper(glue(pfx,add16)); break; \
586 case 1: gen_pas_helper(glue(pfx,addsubx)); break; \
587 case 2: gen_pas_helper(glue(pfx,subaddx)); break; \
588 case 3: gen_pas_helper(glue(pfx,sub16)); break; \
589 case 4: gen_pas_helper(glue(pfx,add8)); break; \
590 case 7: gen_pas_helper(glue(pfx,sub8)); break; \
591 }
pbrookd9ba4832008-03-31 03:46:50 +0000592static void gen_arm_parallel_addsub(int op1, int op2, TCGv a, TCGv b)
pbrook6ddbc6e2008-03-31 03:46:33 +0000593{
594 TCGv tmp;
pbrook9ee6e8b2007-11-11 00:04:49 +0000595
pbrook6ddbc6e2008-03-31 03:46:33 +0000596 switch (op1) {
597#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp)
598 case 1:
599 tmp = tcg_temp_new(TCG_TYPE_PTR);
600 tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
601 PAS_OP(s)
602 break;
603 case 5:
604 tmp = tcg_temp_new(TCG_TYPE_PTR);
605 tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
606 PAS_OP(u)
607 break;
608#undef gen_pas_helper
609#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b)
610 case 2:
611 PAS_OP(q);
612 break;
613 case 3:
614 PAS_OP(sh);
615 break;
616 case 6:
617 PAS_OP(uq);
618 break;
619 case 7:
620 PAS_OP(uh);
621 break;
622#undef gen_pas_helper
623 }
624}
pbrook9ee6e8b2007-11-11 00:04:49 +0000625#undef PAS_OP
626
pbrook6ddbc6e2008-03-31 03:46:33 +0000627/* For unknown reasons Arm and Thumb-2 use arbitrarily different encodings. */
628#define PAS_OP(pfx) \
629 switch (op2) { \
630 case 0: gen_pas_helper(glue(pfx,add8)); break; \
631 case 1: gen_pas_helper(glue(pfx,add16)); break; \
632 case 2: gen_pas_helper(glue(pfx,addsubx)); break; \
633 case 4: gen_pas_helper(glue(pfx,sub8)); break; \
634 case 5: gen_pas_helper(glue(pfx,sub16)); break; \
635 case 6: gen_pas_helper(glue(pfx,subaddx)); break; \
636 }
pbrookd9ba4832008-03-31 03:46:50 +0000637static void gen_thumb2_parallel_addsub(int op1, int op2, TCGv a, TCGv b)
pbrook6ddbc6e2008-03-31 03:46:33 +0000638{
639 TCGv tmp;
pbrook9ee6e8b2007-11-11 00:04:49 +0000640
pbrook6ddbc6e2008-03-31 03:46:33 +0000641 switch (op1) {
642#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b, tmp)
643 case 0:
644 tmp = tcg_temp_new(TCG_TYPE_PTR);
645 tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
646 PAS_OP(s)
647 break;
648 case 4:
649 tmp = tcg_temp_new(TCG_TYPE_PTR);
650 tcg_gen_addi_ptr(tmp, cpu_env, offsetof(CPUState, GE));
651 PAS_OP(u)
652 break;
653#undef gen_pas_helper
654#define gen_pas_helper(name) glue(gen_helper_,name)(a, a, b)
655 case 1:
656 PAS_OP(q);
657 break;
658 case 2:
659 PAS_OP(sh);
660 break;
661 case 5:
662 PAS_OP(uq);
663 break;
664 case 6:
665 PAS_OP(uh);
666 break;
667#undef gen_pas_helper
668 }
669}
pbrook9ee6e8b2007-11-11 00:04:49 +0000670#undef PAS_OP
671
pbrookd9ba4832008-03-31 03:46:50 +0000672static void gen_test_cc(int cc, int label)
673{
674 TCGv tmp;
675 TCGv tmp2;
676 TCGv zero;
677 int inv;
678
679 zero = tcg_const_i32(0);
680 switch (cc) {
681 case 0: /* eq: Z */
682 tmp = load_cpu_field(NZF);
683 tcg_gen_brcond_i32(TCG_COND_EQ, tmp, zero, label);
684 break;
685 case 1: /* ne: !Z */
686 tmp = load_cpu_field(NZF);
687 tcg_gen_brcond_i32(TCG_COND_NE, tmp, zero, label);
688 break;
689 case 2: /* cs: C */
690 tmp = load_cpu_field(CF);
691 tcg_gen_brcond_i32(TCG_COND_NE, tmp, zero, label);
692 break;
693 case 3: /* cc: !C */
694 tmp = load_cpu_field(CF);
695 tcg_gen_brcond_i32(TCG_COND_EQ, tmp, zero, label);
696 break;
697 case 4: /* mi: N */
698 tmp = load_cpu_field(NZF);
699 tcg_gen_brcond_i32(TCG_COND_LT, tmp, zero, label);
700 break;
701 case 5: /* pl: !N */
702 tmp = load_cpu_field(NZF);
703 tcg_gen_brcond_i32(TCG_COND_GE, tmp, zero, label);
704 break;
705 case 6: /* vs: V */
706 tmp = load_cpu_field(VF);
707 tcg_gen_brcond_i32(TCG_COND_LT, tmp, zero, label);
708 break;
709 case 7: /* vc: !V */
710 tmp = load_cpu_field(VF);
711 tcg_gen_brcond_i32(TCG_COND_GE, tmp, zero, label);
712 break;
713 case 8: /* hi: C && !Z */
714 inv = gen_new_label();
715 tmp = load_cpu_field(CF);
716 tcg_gen_brcond_i32(TCG_COND_EQ, tmp, zero, inv);
717 dead_tmp(tmp);
718 tmp = load_cpu_field(NZF);
719 tcg_gen_brcond_i32(TCG_COND_NE, tmp, zero, label);
720 gen_set_label(inv);
721 break;
722 case 9: /* ls: !C || Z */
723 tmp = load_cpu_field(CF);
724 tcg_gen_brcond_i32(TCG_COND_EQ, tmp, zero, label);
725 dead_tmp(tmp);
726 tmp = load_cpu_field(NZF);
727 tcg_gen_brcond_i32(TCG_COND_EQ, tmp, zero, label);
728 break;
729 case 10: /* ge: N == V -> N ^ V == 0 */
730 tmp = load_cpu_field(VF);
731 tmp2 = load_cpu_field(NZF);
732 tcg_gen_xor_i32(tmp, tmp, tmp2);
733 dead_tmp(tmp2);
734 tcg_gen_brcond_i32(TCG_COND_GE, tmp, zero, label);
735 break;
736 case 11: /* lt: N != V -> N ^ V != 0 */
737 tmp = load_cpu_field(VF);
738 tmp2 = load_cpu_field(NZF);
739 tcg_gen_xor_i32(tmp, tmp, tmp2);
740 dead_tmp(tmp2);
741 tcg_gen_brcond_i32(TCG_COND_LT, tmp, zero, label);
742 break;
743 case 12: /* gt: !Z && N == V */
744 inv = gen_new_label();
745 tmp = load_cpu_field(NZF);
746 tcg_gen_brcond_i32(TCG_COND_EQ, tmp, zero, inv);
747 dead_tmp(tmp);
748 tmp = load_cpu_field(VF);
749 tmp2 = load_cpu_field(NZF);
750 tcg_gen_xor_i32(tmp, tmp, tmp2);
751 dead_tmp(tmp2);
752 tcg_gen_brcond_i32(TCG_COND_GE, tmp, zero, label);
753 gen_set_label(inv);
754 break;
755 case 13: /* le: Z || N != V */
756 tmp = load_cpu_field(NZF);
757 tcg_gen_brcond_i32(TCG_COND_EQ, tmp, zero, label);
758 dead_tmp(tmp);
759 tmp = load_cpu_field(VF);
760 tmp2 = load_cpu_field(NZF);
761 tcg_gen_xor_i32(tmp, tmp, tmp2);
762 dead_tmp(tmp2);
763 tcg_gen_brcond_i32(TCG_COND_LT, tmp, zero, label);
764 break;
765 default:
766 fprintf(stderr, "Bad condition code 0x%x\n", cc);
767 abort();
768 }
769 dead_tmp(tmp);
770}
bellard2c0262a2003-09-30 20:34:21 +0000771
772const uint8_t table_logic_cc[16] = {
773 1, /* and */
774 1, /* xor */
775 0, /* sub */
776 0, /* rsb */
777 0, /* add */
778 0, /* adc */
779 0, /* sbc */
780 0, /* rsc */
781 1, /* andl */
782 1, /* xorl */
783 0, /* cmp */
784 0, /* cmn */
785 1, /* orr */
786 1, /* mov */
787 1, /* bic */
788 1, /* mvn */
789};
ths3b46e622007-09-17 08:09:54 +0000790
pbrookd9ba4832008-03-31 03:46:50 +0000791/* Set PC and Thumb state from an immediate address. */
792static inline void gen_bx_im(DisasContext *s, uint32_t addr)
bellard99c475a2005-01-31 20:45:13 +0000793{
pbrookb26eefb2008-03-31 03:44:26 +0000794 TCGv tmp;
bellard99c475a2005-01-31 20:45:13 +0000795
pbrookb26eefb2008-03-31 03:44:26 +0000796 s->is_jmp = DISAS_UPDATE;
797 tmp = new_tmp();
pbrookd9ba4832008-03-31 03:46:50 +0000798 if (s->thumb != (addr & 1)) {
799 tcg_gen_movi_i32(tmp, addr & 1);
800 tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, thumb));
801 }
802 tcg_gen_movi_i32(tmp, addr & ~1);
803 tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, regs[15]));
pbrookb26eefb2008-03-31 03:44:26 +0000804 dead_tmp(tmp);
pbrookd9ba4832008-03-31 03:46:50 +0000805}
806
807/* Set PC and Thumb state from var. var is marked as dead. */
808static inline void gen_bx(DisasContext *s, TCGv var)
809{
810 TCGv tmp;
811
812 s->is_jmp = DISAS_UPDATE;
813 tmp = new_tmp();
814 tcg_gen_andi_i32(tmp, var, 1);
815 store_cpu_field(tmp, thumb);
816 tcg_gen_andi_i32(var, var, ~1);
817 store_cpu_field(var, regs[15]);
818}
819
820/* TODO: This should be removed. Use gen_bx instead. */
821static inline void gen_bx_T0(DisasContext *s)
822{
823 TCGv tmp = new_tmp();
824 tcg_gen_mov_i32(tmp, cpu_T[0]);
825 gen_bx(s, tmp);
pbrookb26eefb2008-03-31 03:44:26 +0000826}
bellardb5ff1b32005-11-26 10:38:39 +0000827
828#if defined(CONFIG_USER_ONLY)
829#define gen_ldst(name, s) gen_op_##name##_raw()
830#else
831#define gen_ldst(name, s) do { \
pbrook6658ffb2007-03-16 23:58:11 +0000832 s->is_mem = 1; \
bellardb5ff1b32005-11-26 10:38:39 +0000833 if (IS_USER(s)) \
834 gen_op_##name##_user(); \
835 else \
836 gen_op_##name##_kernel(); \
837 } while (0)
838#endif
pbrookb0109802008-03-31 03:47:03 +0000839static inline TCGv gen_ld8s(TCGv addr, int index)
840{
841 TCGv tmp = new_tmp();
842 tcg_gen_qemu_ld8s(tmp, addr, index);
843 return tmp;
844}
845static inline TCGv gen_ld8u(TCGv addr, int index)
846{
847 TCGv tmp = new_tmp();
848 tcg_gen_qemu_ld8u(tmp, addr, index);
849 return tmp;
850}
851static inline TCGv gen_ld16s(TCGv addr, int index)
852{
853 TCGv tmp = new_tmp();
854 tcg_gen_qemu_ld16s(tmp, addr, index);
855 return tmp;
856}
857static inline TCGv gen_ld16u(TCGv addr, int index)
858{
859 TCGv tmp = new_tmp();
860 tcg_gen_qemu_ld16u(tmp, addr, index);
861 return tmp;
862}
863static inline TCGv gen_ld32(TCGv addr, int index)
864{
865 TCGv tmp = new_tmp();
866 tcg_gen_qemu_ld32u(tmp, addr, index);
867 return tmp;
868}
869static inline void gen_st8(TCGv val, TCGv addr, int index)
870{
871 tcg_gen_qemu_st8(val, addr, index);
872 dead_tmp(val);
873}
874static inline void gen_st16(TCGv val, TCGv addr, int index)
875{
876 tcg_gen_qemu_st16(val, addr, index);
877 dead_tmp(val);
878}
879static inline void gen_st32(TCGv val, TCGv addr, int index)
880{
881 tcg_gen_qemu_st32(val, addr, index);
882 dead_tmp(val);
883}
bellardb5ff1b32005-11-26 10:38:39 +0000884
bellard2c0262a2003-09-30 20:34:21 +0000885static inline void gen_movl_T0_reg(DisasContext *s, int reg)
886{
pbrookb26eefb2008-03-31 03:44:26 +0000887 load_reg_var(s, cpu_T[0], reg);
bellard2c0262a2003-09-30 20:34:21 +0000888}
889
890static inline void gen_movl_T1_reg(DisasContext *s, int reg)
891{
pbrookb26eefb2008-03-31 03:44:26 +0000892 load_reg_var(s, cpu_T[1], reg);
bellard2c0262a2003-09-30 20:34:21 +0000893}
894
895static inline void gen_movl_T2_reg(DisasContext *s, int reg)
896{
pbrookb26eefb2008-03-31 03:44:26 +0000897 load_reg_var(s, cpu_T[2], reg);
898}
899
pbrook5e3f8782008-03-31 03:47:34 +0000900static inline void gen_set_pc_im(uint32_t val)
901{
902 TCGv tmp = new_tmp();
903 tcg_gen_movi_i32(tmp, val);
904 store_cpu_field(tmp, regs[15]);
905}
906
pbrookb26eefb2008-03-31 03:44:26 +0000907static inline void gen_set_pc_T0(void)
908{
909 tcg_gen_st_i32(cpu_T[0], cpu_env, offsetof(CPUState, regs[15]));
bellard2c0262a2003-09-30 20:34:21 +0000910}
911
912static inline void gen_movl_reg_TN(DisasContext *s, int reg, int t)
913{
pbrookb26eefb2008-03-31 03:44:26 +0000914 TCGv tmp;
bellard2c0262a2003-09-30 20:34:21 +0000915 if (reg == 15) {
pbrookb26eefb2008-03-31 03:44:26 +0000916 tmp = new_tmp();
917 tcg_gen_andi_i32(tmp, cpu_T[t], ~1);
918 } else {
919 tmp = cpu_T[t];
920 }
921 tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUState, regs[reg]));
922 if (reg == 15) {
923 dead_tmp(tmp);
bellard2c0262a2003-09-30 20:34:21 +0000924 s->is_jmp = DISAS_JUMP;
925 }
926}
927
928static inline void gen_movl_reg_T0(DisasContext *s, int reg)
929{
930 gen_movl_reg_TN(s, reg, 0);
931}
932
933static inline void gen_movl_reg_T1(DisasContext *s, int reg)
934{
935 gen_movl_reg_TN(s, reg, 1);
936}
937
bellardb5ff1b32005-11-26 10:38:39 +0000938/* Force a TB lookup after an instruction that changes the CPU state. */
939static inline void gen_lookup_tb(DisasContext *s)
940{
941 gen_op_movl_T0_im(s->pc);
942 gen_movl_reg_T0(s, 15);
943 s->is_jmp = DISAS_UPDATE;
944}
945
pbrookb0109802008-03-31 03:47:03 +0000946static inline void gen_add_data_offset(DisasContext *s, unsigned int insn,
947 TCGv var)
bellard2c0262a2003-09-30 20:34:21 +0000948{
bellard1e8d4ee2004-12-08 23:40:14 +0000949 int val, rm, shift, shiftop;
pbrookb26eefb2008-03-31 03:44:26 +0000950 TCGv offset;
bellard2c0262a2003-09-30 20:34:21 +0000951
952 if (!(insn & (1 << 25))) {
953 /* immediate */
954 val = insn & 0xfff;
955 if (!(insn & (1 << 23)))
956 val = -val;
bellard537730b2004-02-22 13:40:57 +0000957 if (val != 0)
pbrookb0109802008-03-31 03:47:03 +0000958 tcg_gen_addi_i32(var, var, val);
bellard2c0262a2003-09-30 20:34:21 +0000959 } else {
960 /* shift/register */
961 rm = (insn) & 0xf;
962 shift = (insn >> 7) & 0x1f;
bellard1e8d4ee2004-12-08 23:40:14 +0000963 shiftop = (insn >> 5) & 3;
pbrookb26eefb2008-03-31 03:44:26 +0000964 offset = load_reg(s, rm);
pbrook9a119ff2008-03-31 03:45:35 +0000965 gen_arm_shift_im(offset, shiftop, shift, 0);
bellard2c0262a2003-09-30 20:34:21 +0000966 if (!(insn & (1 << 23)))
pbrookb0109802008-03-31 03:47:03 +0000967 tcg_gen_sub_i32(var, var, offset);
bellard2c0262a2003-09-30 20:34:21 +0000968 else
pbrookb0109802008-03-31 03:47:03 +0000969 tcg_gen_add_i32(var, var, offset);
pbrookb26eefb2008-03-31 03:44:26 +0000970 dead_tmp(offset);
bellard2c0262a2003-09-30 20:34:21 +0000971 }
972}
973
pbrook191f9a92006-06-14 14:36:07 +0000974static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn,
pbrookb0109802008-03-31 03:47:03 +0000975 int extra, TCGv var)
bellard2c0262a2003-09-30 20:34:21 +0000976{
977 int val, rm;
pbrookb26eefb2008-03-31 03:44:26 +0000978 TCGv offset;
ths3b46e622007-09-17 08:09:54 +0000979
bellard2c0262a2003-09-30 20:34:21 +0000980 if (insn & (1 << 22)) {
981 /* immediate */
982 val = (insn & 0xf) | ((insn >> 4) & 0xf0);
983 if (!(insn & (1 << 23)))
984 val = -val;
pbrook18acad92007-02-14 20:17:03 +0000985 val += extra;
bellard537730b2004-02-22 13:40:57 +0000986 if (val != 0)
pbrookb0109802008-03-31 03:47:03 +0000987 tcg_gen_addi_i32(var, var, val);
bellard2c0262a2003-09-30 20:34:21 +0000988 } else {
989 /* register */
pbrook191f9a92006-06-14 14:36:07 +0000990 if (extra)
pbrookb0109802008-03-31 03:47:03 +0000991 tcg_gen_addi_i32(var, var, extra);
bellard2c0262a2003-09-30 20:34:21 +0000992 rm = (insn) & 0xf;
pbrookb26eefb2008-03-31 03:44:26 +0000993 offset = load_reg(s, rm);
bellard2c0262a2003-09-30 20:34:21 +0000994 if (!(insn & (1 << 23)))
pbrookb0109802008-03-31 03:47:03 +0000995 tcg_gen_sub_i32(var, var, offset);
bellard2c0262a2003-09-30 20:34:21 +0000996 else
pbrookb0109802008-03-31 03:47:03 +0000997 tcg_gen_add_i32(var, var, offset);
pbrookb26eefb2008-03-31 03:44:26 +0000998 dead_tmp(offset);
bellard2c0262a2003-09-30 20:34:21 +0000999 }
1000}
1001
pbrook4373f3c2008-03-31 03:47:19 +00001002#define VFP_OP2(name) \
1003static inline void gen_vfp_##name(int dp) \
1004{ \
1005 if (dp) \
1006 gen_helper_vfp_##name##d(cpu_F0d, cpu_F0d, cpu_F1d, cpu_env); \
1007 else \
1008 gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, cpu_F1s, cpu_env); \
bellardb7bcbe92005-02-22 19:27:29 +00001009}
1010
pbrook4373f3c2008-03-31 03:47:19 +00001011#define VFP_OP1i(name) \
pbrook9ee6e8b2007-11-11 00:04:49 +00001012static inline void gen_vfp_##name(int dp, int arg) \
1013{ \
1014 if (dp) \
1015 gen_op_vfp_##name##d(arg); \
1016 else \
1017 gen_op_vfp_##name##s(arg); \
1018}
1019
pbrook4373f3c2008-03-31 03:47:19 +00001020VFP_OP2(add)
1021VFP_OP2(sub)
1022VFP_OP2(mul)
1023VFP_OP2(div)
bellardb7bcbe92005-02-22 19:27:29 +00001024
pbrook4373f3c2008-03-31 03:47:19 +00001025#undef VFP_OP2
bellardb7bcbe92005-02-22 19:27:29 +00001026
pbrook4373f3c2008-03-31 03:47:19 +00001027static inline void gen_vfp_abs(int dp)
pbrook9ee6e8b2007-11-11 00:04:49 +00001028{
1029 if (dp)
pbrook4373f3c2008-03-31 03:47:19 +00001030 gen_helper_vfp_absd(cpu_F0d, cpu_F0d);
pbrook9ee6e8b2007-11-11 00:04:49 +00001031 else
pbrook4373f3c2008-03-31 03:47:19 +00001032 gen_helper_vfp_abss(cpu_F0s, cpu_F0s);
pbrook9ee6e8b2007-11-11 00:04:49 +00001033}
1034
pbrook4373f3c2008-03-31 03:47:19 +00001035static inline void gen_vfp_neg(int dp)
1036{
1037 if (dp)
1038 gen_helper_vfp_negd(cpu_F0d, cpu_F0d);
1039 else
1040 gen_helper_vfp_negs(cpu_F0s, cpu_F0s);
1041}
1042
1043static inline void gen_vfp_sqrt(int dp)
1044{
1045 if (dp)
1046 gen_helper_vfp_sqrtd(cpu_F0d, cpu_F0d, cpu_env);
1047 else
1048 gen_helper_vfp_sqrts(cpu_F0s, cpu_F0s, cpu_env);
1049}
1050
1051static inline void gen_vfp_cmp(int dp)
1052{
1053 if (dp)
1054 gen_helper_vfp_cmpd(cpu_F0d, cpu_F1d, cpu_env);
1055 else
1056 gen_helper_vfp_cmps(cpu_F0s, cpu_F1s, cpu_env);
1057}
1058
1059static inline void gen_vfp_cmpe(int dp)
1060{
1061 if (dp)
1062 gen_helper_vfp_cmped(cpu_F0d, cpu_F1d, cpu_env);
1063 else
1064 gen_helper_vfp_cmpes(cpu_F0s, cpu_F1s, cpu_env);
1065}
1066
1067static inline void gen_vfp_F1_ld0(int dp)
1068{
1069 if (dp)
1070 tcg_gen_movi_i64(cpu_F0d, 0);
1071 else
1072 tcg_gen_movi_i32(cpu_F0s, 0);
1073}
1074
1075static inline void gen_vfp_uito(int dp)
1076{
1077 if (dp)
1078 gen_helper_vfp_uitod(cpu_F0d, cpu_F0s, cpu_env);
1079 else
1080 gen_helper_vfp_uitos(cpu_F0s, cpu_F0s, cpu_env);
1081}
1082
1083static inline void gen_vfp_sito(int dp)
1084{
1085 if (dp)
1086 gen_helper_vfp_uitod(cpu_F0d, cpu_F0s, cpu_env);
1087 else
1088 gen_helper_vfp_uitos(cpu_F0s, cpu_F0s, cpu_env);
1089}
1090
1091static inline void gen_vfp_toui(int dp)
1092{
1093 if (dp)
1094 gen_helper_vfp_touid(cpu_F0s, cpu_F0d, cpu_env);
1095 else
1096 gen_helper_vfp_touis(cpu_F0s, cpu_F0s, cpu_env);
1097}
1098
1099static inline void gen_vfp_touiz(int dp)
1100{
1101 if (dp)
1102 gen_helper_vfp_touizd(cpu_F0s, cpu_F0d, cpu_env);
1103 else
1104 gen_helper_vfp_touizs(cpu_F0s, cpu_F0s, cpu_env);
1105}
1106
1107static inline void gen_vfp_tosi(int dp)
1108{
1109 if (dp)
1110 gen_helper_vfp_tosid(cpu_F0s, cpu_F0d, cpu_env);
1111 else
1112 gen_helper_vfp_tosis(cpu_F0s, cpu_F0s, cpu_env);
1113}
1114
1115static inline void gen_vfp_tosiz(int dp)
1116{
1117 if (dp)
1118 gen_helper_vfp_tosizd(cpu_F0s, cpu_F0d, cpu_env);
1119 else
1120 gen_helper_vfp_tosizs(cpu_F0s, cpu_F0s, cpu_env);
1121}
1122
1123#define VFP_GEN_FIX(name) \
1124static inline void gen_vfp_##name(int dp, int shift) \
1125{ \
1126 if (dp) \
1127 gen_helper_vfp_##name##d(cpu_F0d, cpu_F0d, tcg_const_i32(shift), cpu_env);\
1128 else \
1129 gen_helper_vfp_##name##s(cpu_F0s, cpu_F0s, tcg_const_i32(shift), cpu_env);\
1130}
1131VFP_GEN_FIX(tosh)
1132VFP_GEN_FIX(tosl)
1133VFP_GEN_FIX(touh)
1134VFP_GEN_FIX(toul)
1135VFP_GEN_FIX(shto)
1136VFP_GEN_FIX(slto)
1137VFP_GEN_FIX(uhto)
1138VFP_GEN_FIX(ulto)
1139#undef VFP_GEN_FIX
1140
bellardb5ff1b32005-11-26 10:38:39 +00001141static inline void gen_vfp_ld(DisasContext *s, int dp)
1142{
1143 if (dp)
pbrook4373f3c2008-03-31 03:47:19 +00001144 tcg_gen_qemu_ld64(cpu_F0d, cpu_T[1], IS_USER(s));
bellardb5ff1b32005-11-26 10:38:39 +00001145 else
pbrook4373f3c2008-03-31 03:47:19 +00001146 tcg_gen_qemu_ld32u(cpu_F0s, cpu_T[1], IS_USER(s));
bellardb5ff1b32005-11-26 10:38:39 +00001147}
1148
1149static inline void gen_vfp_st(DisasContext *s, int dp)
1150{
1151 if (dp)
pbrook4373f3c2008-03-31 03:47:19 +00001152 tcg_gen_qemu_st64(cpu_F0d, cpu_T[1], IS_USER(s));
bellardb5ff1b32005-11-26 10:38:39 +00001153 else
pbrook4373f3c2008-03-31 03:47:19 +00001154 tcg_gen_qemu_st32(cpu_F0s, cpu_T[1], IS_USER(s));
bellardb5ff1b32005-11-26 10:38:39 +00001155}
1156
bellard8e960052005-04-07 19:42:46 +00001157static inline long
1158vfp_reg_offset (int dp, int reg)
1159{
1160 if (dp)
1161 return offsetof(CPUARMState, vfp.regs[reg]);
1162 else if (reg & 1) {
1163 return offsetof(CPUARMState, vfp.regs[reg >> 1])
1164 + offsetof(CPU_DoubleU, l.upper);
1165 } else {
1166 return offsetof(CPUARMState, vfp.regs[reg >> 1])
1167 + offsetof(CPU_DoubleU, l.lower);
1168 }
1169}
pbrook9ee6e8b2007-11-11 00:04:49 +00001170
1171/* Return the offset of a 32-bit piece of a NEON register.
1172 zero is the least significant end of the register. */
1173static inline long
1174neon_reg_offset (int reg, int n)
1175{
1176 int sreg;
1177 sreg = reg * 2 + n;
1178 return vfp_reg_offset(0, sreg);
1179}
1180
pbrookad694712008-03-31 03:48:30 +00001181/* FIXME: Remove these. */
1182#define neon_T0 cpu_T[0]
1183#define neon_T1 cpu_T[1]
1184#define NEON_GET_REG(T, reg, n) \
1185 tcg_gen_ld_i32(neon_##T, cpu_env, neon_reg_offset(reg, n))
1186#define NEON_SET_REG(T, reg, n) \
1187 tcg_gen_st_i32(neon_##T, cpu_env, neon_reg_offset(reg, n))
pbrook9ee6e8b2007-11-11 00:04:49 +00001188
pbrook8f8e3aa2008-03-31 03:48:01 +00001189static TCGv neon_load_reg(int reg, int pass)
1190{
1191 TCGv tmp = new_tmp();
1192 tcg_gen_ld_i32(tmp, cpu_env, neon_reg_offset(reg, pass));
1193 return tmp;
1194}
1195
1196static void neon_store_reg(int reg, int pass, TCGv var)
1197{
1198 tcg_gen_st_i32(var, cpu_env, neon_reg_offset(reg, pass));
1199 dead_tmp(var);
1200}
1201
pbrookad694712008-03-31 03:48:30 +00001202static inline void neon_load_reg64(TCGv var, int reg)
1203{
1204 tcg_gen_ld_i64(var, cpu_env, vfp_reg_offset(1, reg));
1205}
1206
1207static inline void neon_store_reg64(TCGv var, int reg)
1208{
1209 tcg_gen_st_i64(var, cpu_env, vfp_reg_offset(1, reg));
1210}
1211
pbrook4373f3c2008-03-31 03:47:19 +00001212#define tcg_gen_ld_f32 tcg_gen_ld_i32
1213#define tcg_gen_ld_f64 tcg_gen_ld_i64
1214#define tcg_gen_st_f32 tcg_gen_st_i32
1215#define tcg_gen_st_f64 tcg_gen_st_i64
1216
bellardb7bcbe92005-02-22 19:27:29 +00001217static inline void gen_mov_F0_vreg(int dp, int reg)
1218{
1219 if (dp)
pbrook4373f3c2008-03-31 03:47:19 +00001220 tcg_gen_ld_f64(cpu_F0d, cpu_env, vfp_reg_offset(dp, reg));
bellardb7bcbe92005-02-22 19:27:29 +00001221 else
pbrook4373f3c2008-03-31 03:47:19 +00001222 tcg_gen_ld_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg));
bellardb7bcbe92005-02-22 19:27:29 +00001223}
1224
1225static inline void gen_mov_F1_vreg(int dp, int reg)
1226{
1227 if (dp)
pbrook4373f3c2008-03-31 03:47:19 +00001228 tcg_gen_ld_f64(cpu_F1d, cpu_env, vfp_reg_offset(dp, reg));
bellardb7bcbe92005-02-22 19:27:29 +00001229 else
pbrook4373f3c2008-03-31 03:47:19 +00001230 tcg_gen_ld_f32(cpu_F1s, cpu_env, vfp_reg_offset(dp, reg));
bellardb7bcbe92005-02-22 19:27:29 +00001231}
1232
1233static inline void gen_mov_vreg_F0(int dp, int reg)
1234{
1235 if (dp)
pbrook4373f3c2008-03-31 03:47:19 +00001236 tcg_gen_st_f64(cpu_F0d, cpu_env, vfp_reg_offset(dp, reg));
bellardb7bcbe92005-02-22 19:27:29 +00001237 else
pbrook4373f3c2008-03-31 03:47:19 +00001238 tcg_gen_st_f32(cpu_F0s, cpu_env, vfp_reg_offset(dp, reg));
bellardb7bcbe92005-02-22 19:27:29 +00001239}
1240
balrog18c9b562007-04-30 02:02:17 +00001241#define ARM_CP_RW_BIT (1 << 20)
1242
pbrooke6771372008-03-31 03:49:05 +00001243static inline void iwmmxt_load_reg(TCGv var, int reg)
1244{
1245 tcg_gen_ld_i64(var, cpu_env, offsetof(CPUState, iwmmxt.regs[reg]));
1246}
1247
1248static inline void iwmmxt_store_reg(TCGv var, int reg)
1249{
1250 tcg_gen_st_i64(var, cpu_env, offsetof(CPUState, iwmmxt.regs[reg]));
1251}
1252
1253static inline void gen_op_iwmmxt_movl_wCx_T0(int reg)
1254{
1255 tcg_gen_st_i32(cpu_T[0], cpu_env, offsetof(CPUState, iwmmxt.cregs[reg]));
1256}
1257
1258static inline void gen_op_iwmmxt_movl_T0_wCx(int reg)
1259{
1260 tcg_gen_ld_i32(cpu_T[0], cpu_env, offsetof(CPUState, iwmmxt.cregs[reg]));
1261}
1262
1263static inline void gen_op_iwmmxt_movl_T1_wCx(int reg)
1264{
1265 tcg_gen_ld_i32(cpu_T[1], cpu_env, offsetof(CPUState, iwmmxt.cregs[reg]));
1266}
1267
1268static inline void gen_op_iwmmxt_movq_wRn_M0(int rn)
1269{
1270 iwmmxt_store_reg(cpu_M0, rn);
1271}
1272
1273static inline void gen_op_iwmmxt_movq_M0_wRn(int rn)
1274{
1275 iwmmxt_load_reg(cpu_M0, rn);
1276}
1277
1278static inline void gen_op_iwmmxt_orq_M0_wRn(int rn)
1279{
1280 iwmmxt_load_reg(cpu_V1, rn);
1281 tcg_gen_or_i64(cpu_M0, cpu_M0, cpu_V1);
1282}
1283
1284static inline void gen_op_iwmmxt_andq_M0_wRn(int rn)
1285{
1286 iwmmxt_load_reg(cpu_V1, rn);
1287 tcg_gen_and_i64(cpu_M0, cpu_M0, cpu_V1);
1288}
1289
1290static inline void gen_op_iwmmxt_xorq_M0_wRn(int rn)
1291{
1292 iwmmxt_load_reg(cpu_V1, rn);
1293 tcg_gen_xor_i64(cpu_M0, cpu_M0, cpu_V1);
1294}
1295
1296#define IWMMXT_OP(name) \
1297static inline void gen_op_iwmmxt_##name##_M0_wRn(int rn) \
1298{ \
1299 iwmmxt_load_reg(cpu_V1, rn); \
1300 gen_helper_iwmmxt_##name(cpu_M0, cpu_M0, cpu_V1); \
1301}
1302
1303#define IWMMXT_OP_ENV(name) \
1304static inline void gen_op_iwmmxt_##name##_M0_wRn(int rn) \
1305{ \
1306 iwmmxt_load_reg(cpu_V1, rn); \
1307 gen_helper_iwmmxt_##name(cpu_M0, cpu_env, cpu_M0, cpu_V1); \
1308}
1309
1310#define IWMMXT_OP_ENV_SIZE(name) \
1311IWMMXT_OP_ENV(name##b) \
1312IWMMXT_OP_ENV(name##w) \
1313IWMMXT_OP_ENV(name##l)
1314
1315#define IWMMXT_OP_ENV1(name) \
1316static inline void gen_op_iwmmxt_##name##_M0(void) \
1317{ \
1318 gen_helper_iwmmxt_##name(cpu_M0, cpu_env, cpu_M0); \
1319}
1320
1321IWMMXT_OP(maddsq)
1322IWMMXT_OP(madduq)
1323IWMMXT_OP(sadb)
1324IWMMXT_OP(sadw)
1325IWMMXT_OP(mulslw)
1326IWMMXT_OP(mulshw)
1327IWMMXT_OP(mululw)
1328IWMMXT_OP(muluhw)
1329IWMMXT_OP(macsw)
1330IWMMXT_OP(macuw)
1331
1332IWMMXT_OP_ENV_SIZE(unpackl)
1333IWMMXT_OP_ENV_SIZE(unpackh)
1334
1335IWMMXT_OP_ENV1(unpacklub)
1336IWMMXT_OP_ENV1(unpackluw)
1337IWMMXT_OP_ENV1(unpacklul)
1338IWMMXT_OP_ENV1(unpackhub)
1339IWMMXT_OP_ENV1(unpackhuw)
1340IWMMXT_OP_ENV1(unpackhul)
1341IWMMXT_OP_ENV1(unpacklsb)
1342IWMMXT_OP_ENV1(unpacklsw)
1343IWMMXT_OP_ENV1(unpacklsl)
1344IWMMXT_OP_ENV1(unpackhsb)
1345IWMMXT_OP_ENV1(unpackhsw)
1346IWMMXT_OP_ENV1(unpackhsl)
1347
1348IWMMXT_OP_ENV_SIZE(cmpeq)
1349IWMMXT_OP_ENV_SIZE(cmpgtu)
1350IWMMXT_OP_ENV_SIZE(cmpgts)
1351
1352IWMMXT_OP_ENV_SIZE(mins)
1353IWMMXT_OP_ENV_SIZE(minu)
1354IWMMXT_OP_ENV_SIZE(maxs)
1355IWMMXT_OP_ENV_SIZE(maxu)
1356
1357IWMMXT_OP_ENV_SIZE(subn)
1358IWMMXT_OP_ENV_SIZE(addn)
1359IWMMXT_OP_ENV_SIZE(subu)
1360IWMMXT_OP_ENV_SIZE(addu)
1361IWMMXT_OP_ENV_SIZE(subs)
1362IWMMXT_OP_ENV_SIZE(adds)
1363
1364IWMMXT_OP_ENV(avgb0)
1365IWMMXT_OP_ENV(avgb1)
1366IWMMXT_OP_ENV(avgw0)
1367IWMMXT_OP_ENV(avgw1)
1368
1369IWMMXT_OP(msadb)
1370
1371IWMMXT_OP_ENV(packuw)
1372IWMMXT_OP_ENV(packul)
1373IWMMXT_OP_ENV(packuq)
1374IWMMXT_OP_ENV(packsw)
1375IWMMXT_OP_ENV(packsl)
1376IWMMXT_OP_ENV(packsq)
1377
1378static inline void gen_op_iwmmxt_muladdsl_M0_T0_T1(void)
1379{
1380 gen_helper_iwmmxt_muladdsl(cpu_M0, cpu_M0, cpu_T[0], cpu_T[1]);
1381}
1382
1383static inline void gen_op_iwmmxt_muladdsw_M0_T0_T1(void)
1384{
1385 gen_helper_iwmmxt_muladdsw(cpu_M0, cpu_M0, cpu_T[0], cpu_T[1]);
1386}
1387
1388static inline void gen_op_iwmmxt_muladdswl_M0_T0_T1(void)
1389{
1390 gen_helper_iwmmxt_muladdswl(cpu_M0, cpu_M0, cpu_T[0], cpu_T[1]);
1391}
1392
1393static inline void gen_op_iwmmxt_align_M0_T0_wRn(int rn)
1394{
1395 iwmmxt_load_reg(cpu_V1, rn);
1396 gen_helper_iwmmxt_align(cpu_M0, cpu_M0, cpu_V1, cpu_T[0]);
1397}
1398
1399static inline void gen_op_iwmmxt_insr_M0_T0_T1(int shift)
1400{
1401 TCGv tmp = tcg_const_i32(shift);
1402 gen_helper_iwmmxt_insr(cpu_M0, cpu_M0, cpu_T[0], cpu_T[1], tmp);
1403}
1404
1405static inline void gen_op_iwmmxt_extrsb_T0_M0(int shift)
1406{
1407 tcg_gen_shri_i64(cpu_M0, cpu_M0, shift);
1408 tcg_gen_trunc_i64_i32(cpu_T[0], cpu_M0);
1409 tcg_gen_ext8s_i32(cpu_T[0], cpu_T[0]);
1410}
1411
1412static inline void gen_op_iwmmxt_extrsw_T0_M0(int shift)
1413{
1414 tcg_gen_shri_i64(cpu_M0, cpu_M0, shift);
1415 tcg_gen_trunc_i64_i32(cpu_T[0], cpu_M0);
1416 tcg_gen_ext16s_i32(cpu_T[0], cpu_T[0]);
1417}
1418
1419static inline void gen_op_iwmmxt_extru_T0_M0(int shift, uint32_t mask)
1420{
1421 tcg_gen_shri_i64(cpu_M0, cpu_M0, shift);
1422 tcg_gen_trunc_i64_i32(cpu_T[0], cpu_M0);
1423 if (mask != ~0u)
1424 tcg_gen_andi_i32(cpu_T[0], cpu_T[0], mask);
1425}
1426
1427static void gen_op_iwmmxt_set_mup(void)
1428{
1429 TCGv tmp;
1430 tmp = load_cpu_field(iwmmxt.cregs[ARM_IWMMXT_wCon]);
1431 tcg_gen_ori_i32(tmp, tmp, 2);
1432 store_cpu_field(tmp, iwmmxt.cregs[ARM_IWMMXT_wCon]);
1433}
1434
1435static void gen_op_iwmmxt_set_cup(void)
1436{
1437 TCGv tmp;
1438 tmp = load_cpu_field(iwmmxt.cregs[ARM_IWMMXT_wCon]);
1439 tcg_gen_ori_i32(tmp, tmp, 1);
1440 store_cpu_field(tmp, iwmmxt.cregs[ARM_IWMMXT_wCon]);
1441}
1442
1443static void gen_op_iwmmxt_setpsr_nz(void)
1444{
1445 TCGv tmp = new_tmp();
1446 gen_helper_iwmmxt_setpsr_nz(tmp, cpu_M0);
1447 store_cpu_field(tmp, iwmmxt.cregs[ARM_IWMMXT_wCASF]);
1448}
1449
1450static inline void gen_op_iwmmxt_addl_M0_wRn(int rn)
1451{
1452 iwmmxt_load_reg(cpu_V1, rn);
1453 tcg_gen_andi_i64(cpu_V1, cpu_V1, 0xffffffffu);
1454 tcg_gen_add_i64(cpu_M0, cpu_M0, cpu_V1);
1455}
1456
1457
1458static void gen_iwmmxt_movl_T0_T1_wRn(int rn)
1459{
1460 iwmmxt_load_reg(cpu_V0, rn);
1461 tcg_gen_trunc_i64_i32(cpu_T[0], cpu_V0);
1462 tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
1463 tcg_gen_trunc_i64_i32(cpu_T[1], cpu_V0);
1464}
1465
1466static void gen_iwmmxt_movl_wRn_T0_T1(int rn)
1467{
1468 tcg_gen_extu_i32_i64(cpu_V0, cpu_T[0]);
1469 tcg_gen_extu_i32_i64(cpu_V1, cpu_T[0]);
1470 tcg_gen_shli_i64(cpu_V1, cpu_V1, 32);
1471 tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1);
1472 iwmmxt_store_reg(cpu_V0, rn);
1473}
1474
balrog18c9b562007-04-30 02:02:17 +00001475static inline int gen_iwmmxt_address(DisasContext *s, uint32_t insn)
1476{
1477 int rd;
1478 uint32_t offset;
1479
1480 rd = (insn >> 16) & 0xf;
1481 gen_movl_T1_reg(s, rd);
1482
1483 offset = (insn & 0xff) << ((insn >> 7) & 2);
1484 if (insn & (1 << 24)) {
1485 /* Pre indexed */
1486 if (insn & (1 << 23))
1487 gen_op_addl_T1_im(offset);
1488 else
1489 gen_op_addl_T1_im(-offset);
1490
1491 if (insn & (1 << 21))
1492 gen_movl_reg_T1(s, rd);
1493 } else if (insn & (1 << 21)) {
1494 /* Post indexed */
1495 if (insn & (1 << 23))
1496 gen_op_movl_T0_im(offset);
1497 else
1498 gen_op_movl_T0_im(- offset);
1499 gen_op_addl_T0_T1();
1500 gen_movl_reg_T0(s, rd);
1501 } else if (!(insn & (1 << 23)))
1502 return 1;
1503 return 0;
1504}
1505
1506static inline int gen_iwmmxt_shift(uint32_t insn, uint32_t mask)
1507{
1508 int rd = (insn >> 0) & 0xf;
1509
1510 if (insn & (1 << 8))
1511 if (rd < ARM_IWMMXT_wCGR0 || rd > ARM_IWMMXT_wCGR3)
1512 return 1;
1513 else
1514 gen_op_iwmmxt_movl_T0_wCx(rd);
1515 else
pbrooke6771372008-03-31 03:49:05 +00001516 gen_iwmmxt_movl_T0_T1_wRn(rd);
balrog18c9b562007-04-30 02:02:17 +00001517
1518 gen_op_movl_T1_im(mask);
1519 gen_op_andl_T0_T1();
1520 return 0;
1521}
1522
1523/* Disassemble an iwMMXt instruction. Returns nonzero if an error occured
1524 (ie. an undefined instruction). */
1525static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
1526{
1527 int rd, wrd;
1528 int rdhi, rdlo, rd0, rd1, i;
pbrookb0109802008-03-31 03:47:03 +00001529 TCGv tmp;
balrog18c9b562007-04-30 02:02:17 +00001530
1531 if ((insn & 0x0e000e00) == 0x0c000000) {
1532 if ((insn & 0x0fe00ff0) == 0x0c400000) {
1533 wrd = insn & 0xf;
1534 rdlo = (insn >> 12) & 0xf;
1535 rdhi = (insn >> 16) & 0xf;
1536 if (insn & ARM_CP_RW_BIT) { /* TMRRC */
pbrooke6771372008-03-31 03:49:05 +00001537 gen_iwmmxt_movl_T0_T1_wRn(wrd);
balrog18c9b562007-04-30 02:02:17 +00001538 gen_movl_reg_T0(s, rdlo);
1539 gen_movl_reg_T1(s, rdhi);
1540 } else { /* TMCRR */
1541 gen_movl_T0_reg(s, rdlo);
1542 gen_movl_T1_reg(s, rdhi);
pbrooke6771372008-03-31 03:49:05 +00001543 gen_iwmmxt_movl_wRn_T0_T1(wrd);
balrog18c9b562007-04-30 02:02:17 +00001544 gen_op_iwmmxt_set_mup();
1545 }
1546 return 0;
1547 }
1548
1549 wrd = (insn >> 12) & 0xf;
1550 if (gen_iwmmxt_address(s, insn))
1551 return 1;
1552 if (insn & ARM_CP_RW_BIT) {
1553 if ((insn >> 28) == 0xf) { /* WLDRW wCx */
pbrookb0109802008-03-31 03:47:03 +00001554 tmp = gen_ld32(cpu_T[1], IS_USER(s));
1555 tcg_gen_mov_i32(cpu_T[0], tmp);
1556 dead_tmp(tmp);
balrog18c9b562007-04-30 02:02:17 +00001557 gen_op_iwmmxt_movl_wCx_T0(wrd);
1558 } else {
pbrooke6771372008-03-31 03:49:05 +00001559 i = 1;
1560 if (insn & (1 << 8)) {
1561 if (insn & (1 << 22)) { /* WLDRD */
1562 tcg_gen_qemu_ld64(cpu_M0, cpu_T[1], IS_USER(s));
1563 i = 0;
1564 } else { /* WLDRW wRd */
1565 tmp = gen_ld32(cpu_T[1], IS_USER(s));
1566 }
1567 } else {
1568 if (insn & (1 << 22)) { /* WLDRH */
1569 tmp = gen_ld16u(cpu_T[1], IS_USER(s));
1570 } else { /* WLDRB */
1571 tmp = gen_ld8u(cpu_T[1], IS_USER(s));
1572 }
1573 }
1574 if (i) {
1575 tcg_gen_extu_i32_i64(cpu_M0, tmp);
1576 dead_tmp(tmp);
1577 }
balrog18c9b562007-04-30 02:02:17 +00001578 gen_op_iwmmxt_movq_wRn_M0(wrd);
1579 }
1580 } else {
1581 if ((insn >> 28) == 0xf) { /* WSTRW wCx */
1582 gen_op_iwmmxt_movl_T0_wCx(wrd);
pbrookb0109802008-03-31 03:47:03 +00001583 tmp = new_tmp();
1584 tcg_gen_mov_i32(tmp, cpu_T[0]);
1585 gen_st32(tmp, cpu_T[1], IS_USER(s));
balrog18c9b562007-04-30 02:02:17 +00001586 } else {
1587 gen_op_iwmmxt_movq_M0_wRn(wrd);
pbrooke6771372008-03-31 03:49:05 +00001588 tmp = new_tmp();
1589 if (insn & (1 << 8)) {
1590 if (insn & (1 << 22)) { /* WSTRD */
1591 dead_tmp(tmp);
1592 tcg_gen_qemu_st64(cpu_M0, cpu_T[1], IS_USER(s));
1593 } else { /* WSTRW wRd */
1594 tcg_gen_trunc_i64_i32(tmp, cpu_M0);
1595 gen_st32(tmp, cpu_T[1], IS_USER(s));
1596 }
1597 } else {
1598 if (insn & (1 << 22)) { /* WSTRH */
1599 tcg_gen_trunc_i64_i32(tmp, cpu_M0);
1600 gen_st16(tmp, cpu_T[1], IS_USER(s));
1601 } else { /* WSTRB */
1602 tcg_gen_trunc_i64_i32(tmp, cpu_M0);
1603 gen_st8(tmp, cpu_T[1], IS_USER(s));
1604 }
1605 }
balrog18c9b562007-04-30 02:02:17 +00001606 }
1607 }
1608 return 0;
1609 }
1610
1611 if ((insn & 0x0f000000) != 0x0e000000)
1612 return 1;
1613
1614 switch (((insn >> 12) & 0xf00) | ((insn >> 4) & 0xff)) {
1615 case 0x000: /* WOR */
1616 wrd = (insn >> 12) & 0xf;
1617 rd0 = (insn >> 0) & 0xf;
1618 rd1 = (insn >> 16) & 0xf;
1619 gen_op_iwmmxt_movq_M0_wRn(rd0);
1620 gen_op_iwmmxt_orq_M0_wRn(rd1);
1621 gen_op_iwmmxt_setpsr_nz();
1622 gen_op_iwmmxt_movq_wRn_M0(wrd);
1623 gen_op_iwmmxt_set_mup();
1624 gen_op_iwmmxt_set_cup();
1625 break;
1626 case 0x011: /* TMCR */
1627 if (insn & 0xf)
1628 return 1;
1629 rd = (insn >> 12) & 0xf;
1630 wrd = (insn >> 16) & 0xf;
1631 switch (wrd) {
1632 case ARM_IWMMXT_wCID:
1633 case ARM_IWMMXT_wCASF:
1634 break;
1635 case ARM_IWMMXT_wCon:
1636 gen_op_iwmmxt_set_cup();
1637 /* Fall through. */
1638 case ARM_IWMMXT_wCSSF:
1639 gen_op_iwmmxt_movl_T0_wCx(wrd);
1640 gen_movl_T1_reg(s, rd);
1641 gen_op_bicl_T0_T1();
1642 gen_op_iwmmxt_movl_wCx_T0(wrd);
1643 break;
1644 case ARM_IWMMXT_wCGR0:
1645 case ARM_IWMMXT_wCGR1:
1646 case ARM_IWMMXT_wCGR2:
1647 case ARM_IWMMXT_wCGR3:
1648 gen_op_iwmmxt_set_cup();
1649 gen_movl_reg_T0(s, rd);
1650 gen_op_iwmmxt_movl_wCx_T0(wrd);
1651 break;
1652 default:
1653 return 1;
1654 }
1655 break;
1656 case 0x100: /* WXOR */
1657 wrd = (insn >> 12) & 0xf;
1658 rd0 = (insn >> 0) & 0xf;
1659 rd1 = (insn >> 16) & 0xf;
1660 gen_op_iwmmxt_movq_M0_wRn(rd0);
1661 gen_op_iwmmxt_xorq_M0_wRn(rd1);
1662 gen_op_iwmmxt_setpsr_nz();
1663 gen_op_iwmmxt_movq_wRn_M0(wrd);
1664 gen_op_iwmmxt_set_mup();
1665 gen_op_iwmmxt_set_cup();
1666 break;
1667 case 0x111: /* TMRC */
1668 if (insn & 0xf)
1669 return 1;
1670 rd = (insn >> 12) & 0xf;
1671 wrd = (insn >> 16) & 0xf;
1672 gen_op_iwmmxt_movl_T0_wCx(wrd);
1673 gen_movl_reg_T0(s, rd);
1674 break;
1675 case 0x300: /* WANDN */
1676 wrd = (insn >> 12) & 0xf;
1677 rd0 = (insn >> 0) & 0xf;
1678 rd1 = (insn >> 16) & 0xf;
1679 gen_op_iwmmxt_movq_M0_wRn(rd0);
pbrooke6771372008-03-31 03:49:05 +00001680 tcg_gen_neg_i64(cpu_M0, cpu_M0);
balrog18c9b562007-04-30 02:02:17 +00001681 gen_op_iwmmxt_andq_M0_wRn(rd1);
1682 gen_op_iwmmxt_setpsr_nz();
1683 gen_op_iwmmxt_movq_wRn_M0(wrd);
1684 gen_op_iwmmxt_set_mup();
1685 gen_op_iwmmxt_set_cup();
1686 break;
1687 case 0x200: /* WAND */
1688 wrd = (insn >> 12) & 0xf;
1689 rd0 = (insn >> 0) & 0xf;
1690 rd1 = (insn >> 16) & 0xf;
1691 gen_op_iwmmxt_movq_M0_wRn(rd0);
1692 gen_op_iwmmxt_andq_M0_wRn(rd1);
1693 gen_op_iwmmxt_setpsr_nz();
1694 gen_op_iwmmxt_movq_wRn_M0(wrd);
1695 gen_op_iwmmxt_set_mup();
1696 gen_op_iwmmxt_set_cup();
1697 break;
1698 case 0x810: case 0xa10: /* WMADD */
1699 wrd = (insn >> 12) & 0xf;
1700 rd0 = (insn >> 0) & 0xf;
1701 rd1 = (insn >> 16) & 0xf;
1702 gen_op_iwmmxt_movq_M0_wRn(rd0);
1703 if (insn & (1 << 21))
1704 gen_op_iwmmxt_maddsq_M0_wRn(rd1);
1705 else
1706 gen_op_iwmmxt_madduq_M0_wRn(rd1);
1707 gen_op_iwmmxt_movq_wRn_M0(wrd);
1708 gen_op_iwmmxt_set_mup();
1709 break;
1710 case 0x10e: case 0x50e: case 0x90e: case 0xd0e: /* WUNPCKIL */
1711 wrd = (insn >> 12) & 0xf;
1712 rd0 = (insn >> 16) & 0xf;
1713 rd1 = (insn >> 0) & 0xf;
1714 gen_op_iwmmxt_movq_M0_wRn(rd0);
1715 switch ((insn >> 22) & 3) {
1716 case 0:
1717 gen_op_iwmmxt_unpacklb_M0_wRn(rd1);
1718 break;
1719 case 1:
1720 gen_op_iwmmxt_unpacklw_M0_wRn(rd1);
1721 break;
1722 case 2:
1723 gen_op_iwmmxt_unpackll_M0_wRn(rd1);
1724 break;
1725 case 3:
1726 return 1;
1727 }
1728 gen_op_iwmmxt_movq_wRn_M0(wrd);
1729 gen_op_iwmmxt_set_mup();
1730 gen_op_iwmmxt_set_cup();
1731 break;
1732 case 0x10c: case 0x50c: case 0x90c: case 0xd0c: /* WUNPCKIH */
1733 wrd = (insn >> 12) & 0xf;
1734 rd0 = (insn >> 16) & 0xf;
1735 rd1 = (insn >> 0) & 0xf;
1736 gen_op_iwmmxt_movq_M0_wRn(rd0);
1737 switch ((insn >> 22) & 3) {
1738 case 0:
1739 gen_op_iwmmxt_unpackhb_M0_wRn(rd1);
1740 break;
1741 case 1:
1742 gen_op_iwmmxt_unpackhw_M0_wRn(rd1);
1743 break;
1744 case 2:
1745 gen_op_iwmmxt_unpackhl_M0_wRn(rd1);
1746 break;
1747 case 3:
1748 return 1;
1749 }
1750 gen_op_iwmmxt_movq_wRn_M0(wrd);
1751 gen_op_iwmmxt_set_mup();
1752 gen_op_iwmmxt_set_cup();
1753 break;
1754 case 0x012: case 0x112: case 0x412: case 0x512: /* WSAD */
1755 wrd = (insn >> 12) & 0xf;
1756 rd0 = (insn >> 16) & 0xf;
1757 rd1 = (insn >> 0) & 0xf;
1758 gen_op_iwmmxt_movq_M0_wRn(rd0);
1759 if (insn & (1 << 22))
1760 gen_op_iwmmxt_sadw_M0_wRn(rd1);
1761 else
1762 gen_op_iwmmxt_sadb_M0_wRn(rd1);
1763 if (!(insn & (1 << 20)))
1764 gen_op_iwmmxt_addl_M0_wRn(wrd);
1765 gen_op_iwmmxt_movq_wRn_M0(wrd);
1766 gen_op_iwmmxt_set_mup();
1767 break;
1768 case 0x010: case 0x110: case 0x210: case 0x310: /* WMUL */
1769 wrd = (insn >> 12) & 0xf;
1770 rd0 = (insn >> 16) & 0xf;
1771 rd1 = (insn >> 0) & 0xf;
1772 gen_op_iwmmxt_movq_M0_wRn(rd0);
pbrooke6771372008-03-31 03:49:05 +00001773 if (insn & (1 << 21)) {
1774 if (insn & (1 << 20))
1775 gen_op_iwmmxt_mulshw_M0_wRn(rd1);
1776 else
1777 gen_op_iwmmxt_mulslw_M0_wRn(rd1);
1778 } else {
1779 if (insn & (1 << 20))
1780 gen_op_iwmmxt_muluhw_M0_wRn(rd1);
1781 else
1782 gen_op_iwmmxt_mululw_M0_wRn(rd1);
1783 }
balrog18c9b562007-04-30 02:02:17 +00001784 gen_op_iwmmxt_movq_wRn_M0(wrd);
1785 gen_op_iwmmxt_set_mup();
1786 break;
1787 case 0x410: case 0x510: case 0x610: case 0x710: /* WMAC */
1788 wrd = (insn >> 12) & 0xf;
1789 rd0 = (insn >> 16) & 0xf;
1790 rd1 = (insn >> 0) & 0xf;
1791 gen_op_iwmmxt_movq_M0_wRn(rd0);
1792 if (insn & (1 << 21))
1793 gen_op_iwmmxt_macsw_M0_wRn(rd1);
1794 else
1795 gen_op_iwmmxt_macuw_M0_wRn(rd1);
1796 if (!(insn & (1 << 20))) {
pbrooke6771372008-03-31 03:49:05 +00001797 iwmmxt_load_reg(cpu_V1, wrd);
1798 tcg_gen_add_i64(cpu_M0, cpu_M0, cpu_V1);
balrog18c9b562007-04-30 02:02:17 +00001799 }
1800 gen_op_iwmmxt_movq_wRn_M0(wrd);
1801 gen_op_iwmmxt_set_mup();
1802 break;
1803 case 0x006: case 0x406: case 0x806: case 0xc06: /* WCMPEQ */
1804 wrd = (insn >> 12) & 0xf;
1805 rd0 = (insn >> 16) & 0xf;
1806 rd1 = (insn >> 0) & 0xf;
1807 gen_op_iwmmxt_movq_M0_wRn(rd0);
1808 switch ((insn >> 22) & 3) {
1809 case 0:
1810 gen_op_iwmmxt_cmpeqb_M0_wRn(rd1);
1811 break;
1812 case 1:
1813 gen_op_iwmmxt_cmpeqw_M0_wRn(rd1);
1814 break;
1815 case 2:
1816 gen_op_iwmmxt_cmpeql_M0_wRn(rd1);
1817 break;
1818 case 3:
1819 return 1;
1820 }
1821 gen_op_iwmmxt_movq_wRn_M0(wrd);
1822 gen_op_iwmmxt_set_mup();
1823 gen_op_iwmmxt_set_cup();
1824 break;
1825 case 0x800: case 0x900: case 0xc00: case 0xd00: /* WAVG2 */
1826 wrd = (insn >> 12) & 0xf;
1827 rd0 = (insn >> 16) & 0xf;
1828 rd1 = (insn >> 0) & 0xf;
1829 gen_op_iwmmxt_movq_M0_wRn(rd0);
pbrooke6771372008-03-31 03:49:05 +00001830 if (insn & (1 << 22)) {
1831 if (insn & (1 << 20))
1832 gen_op_iwmmxt_avgw1_M0_wRn(rd1);
1833 else
1834 gen_op_iwmmxt_avgw0_M0_wRn(rd1);
1835 } else {
1836 if (insn & (1 << 20))
1837 gen_op_iwmmxt_avgb1_M0_wRn(rd1);
1838 else
1839 gen_op_iwmmxt_avgb0_M0_wRn(rd1);
1840 }
balrog18c9b562007-04-30 02:02:17 +00001841 gen_op_iwmmxt_movq_wRn_M0(wrd);
1842 gen_op_iwmmxt_set_mup();
1843 gen_op_iwmmxt_set_cup();
1844 break;
1845 case 0x802: case 0x902: case 0xa02: case 0xb02: /* WALIGNR */
1846 wrd = (insn >> 12) & 0xf;
1847 rd0 = (insn >> 16) & 0xf;
1848 rd1 = (insn >> 0) & 0xf;
1849 gen_op_iwmmxt_movq_M0_wRn(rd0);
1850 gen_op_iwmmxt_movl_T0_wCx(ARM_IWMMXT_wCGR0 + ((insn >> 20) & 3));
1851 gen_op_movl_T1_im(7);
1852 gen_op_andl_T0_T1();
1853 gen_op_iwmmxt_align_M0_T0_wRn(rd1);
1854 gen_op_iwmmxt_movq_wRn_M0(wrd);
1855 gen_op_iwmmxt_set_mup();
1856 break;
1857 case 0x601: case 0x605: case 0x609: case 0x60d: /* TINSR */
1858 rd = (insn >> 12) & 0xf;
1859 wrd = (insn >> 16) & 0xf;
1860 gen_movl_T0_reg(s, rd);
1861 gen_op_iwmmxt_movq_M0_wRn(wrd);
1862 switch ((insn >> 6) & 3) {
1863 case 0:
1864 gen_op_movl_T1_im(0xff);
1865 gen_op_iwmmxt_insr_M0_T0_T1((insn & 7) << 3);
1866 break;
1867 case 1:
1868 gen_op_movl_T1_im(0xffff);
1869 gen_op_iwmmxt_insr_M0_T0_T1((insn & 3) << 4);
1870 break;
1871 case 2:
1872 gen_op_movl_T1_im(0xffffffff);
1873 gen_op_iwmmxt_insr_M0_T0_T1((insn & 1) << 5);
1874 break;
1875 case 3:
1876 return 1;
1877 }
1878 gen_op_iwmmxt_movq_wRn_M0(wrd);
1879 gen_op_iwmmxt_set_mup();
1880 break;
1881 case 0x107: case 0x507: case 0x907: case 0xd07: /* TEXTRM */
1882 rd = (insn >> 12) & 0xf;
1883 wrd = (insn >> 16) & 0xf;
1884 if (rd == 15)
1885 return 1;
1886 gen_op_iwmmxt_movq_M0_wRn(wrd);
1887 switch ((insn >> 22) & 3) {
1888 case 0:
1889 if (insn & 8)
1890 gen_op_iwmmxt_extrsb_T0_M0((insn & 7) << 3);
1891 else {
pbrooke6771372008-03-31 03:49:05 +00001892 gen_op_iwmmxt_extru_T0_M0((insn & 7) << 3, 0xff);
balrog18c9b562007-04-30 02:02:17 +00001893 }
1894 break;
1895 case 1:
1896 if (insn & 8)
1897 gen_op_iwmmxt_extrsw_T0_M0((insn & 3) << 4);
1898 else {
pbrooke6771372008-03-31 03:49:05 +00001899 gen_op_iwmmxt_extru_T0_M0((insn & 3) << 4, 0xffff);
balrog18c9b562007-04-30 02:02:17 +00001900 }
1901 break;
1902 case 2:
pbrooke6771372008-03-31 03:49:05 +00001903 gen_op_iwmmxt_extru_T0_M0((insn & 1) << 5, ~0u);
balrog18c9b562007-04-30 02:02:17 +00001904 break;
1905 case 3:
1906 return 1;
1907 }
pbrookb26eefb2008-03-31 03:44:26 +00001908 gen_movl_reg_T0(s, rd);
balrog18c9b562007-04-30 02:02:17 +00001909 break;
1910 case 0x117: case 0x517: case 0x917: case 0xd17: /* TEXTRC */
1911 if ((insn & 0x000ff008) != 0x0003f000)
1912 return 1;
1913 gen_op_iwmmxt_movl_T1_wCx(ARM_IWMMXT_wCASF);
1914 switch ((insn >> 22) & 3) {
1915 case 0:
1916 gen_op_shrl_T1_im(((insn & 7) << 2) + 0);
1917 break;
1918 case 1:
1919 gen_op_shrl_T1_im(((insn & 3) << 3) + 4);
1920 break;
1921 case 2:
1922 gen_op_shrl_T1_im(((insn & 1) << 4) + 12);
1923 break;
1924 case 3:
1925 return 1;
1926 }
1927 gen_op_shll_T1_im(28);
pbrookd9ba4832008-03-31 03:46:50 +00001928 gen_set_nzcv(cpu_T[1]);
balrog18c9b562007-04-30 02:02:17 +00001929 break;
1930 case 0x401: case 0x405: case 0x409: case 0x40d: /* TBCST */
1931 rd = (insn >> 12) & 0xf;
1932 wrd = (insn >> 16) & 0xf;
1933 gen_movl_T0_reg(s, rd);
1934 switch ((insn >> 6) & 3) {
1935 case 0:
pbrooke6771372008-03-31 03:49:05 +00001936 gen_helper_iwmmxt_bcstb(cpu_M0, cpu_T[0]);
balrog18c9b562007-04-30 02:02:17 +00001937 break;
1938 case 1:
pbrooke6771372008-03-31 03:49:05 +00001939 gen_helper_iwmmxt_bcstw(cpu_M0, cpu_T[0]);
balrog18c9b562007-04-30 02:02:17 +00001940 break;
1941 case 2:
pbrooke6771372008-03-31 03:49:05 +00001942 gen_helper_iwmmxt_bcstl(cpu_M0, cpu_T[0]);
balrog18c9b562007-04-30 02:02:17 +00001943 break;
1944 case 3:
1945 return 1;
1946 }
1947 gen_op_iwmmxt_movq_wRn_M0(wrd);
1948 gen_op_iwmmxt_set_mup();
1949 break;
1950 case 0x113: case 0x513: case 0x913: case 0xd13: /* TANDC */
1951 if ((insn & 0x000ff00f) != 0x0003f000)
1952 return 1;
1953 gen_op_iwmmxt_movl_T1_wCx(ARM_IWMMXT_wCASF);
1954 switch ((insn >> 22) & 3) {
1955 case 0:
1956 for (i = 0; i < 7; i ++) {
1957 gen_op_shll_T1_im(4);
1958 gen_op_andl_T0_T1();
1959 }
1960 break;
1961 case 1:
1962 for (i = 0; i < 3; i ++) {
1963 gen_op_shll_T1_im(8);
1964 gen_op_andl_T0_T1();
1965 }
1966 break;
1967 case 2:
1968 gen_op_shll_T1_im(16);
1969 gen_op_andl_T0_T1();
1970 break;
1971 case 3:
1972 return 1;
1973 }
pbrookd9ba4832008-03-31 03:46:50 +00001974 gen_set_nzcv(cpu_T[0]);
balrog18c9b562007-04-30 02:02:17 +00001975 break;
1976 case 0x01c: case 0x41c: case 0x81c: case 0xc1c: /* WACC */
1977 wrd = (insn >> 12) & 0xf;
1978 rd0 = (insn >> 16) & 0xf;
1979 gen_op_iwmmxt_movq_M0_wRn(rd0);
1980 switch ((insn >> 22) & 3) {
1981 case 0:
pbrooke6771372008-03-31 03:49:05 +00001982 gen_helper_iwmmxt_addcb(cpu_M0, cpu_M0);
balrog18c9b562007-04-30 02:02:17 +00001983 break;
1984 case 1:
pbrooke6771372008-03-31 03:49:05 +00001985 gen_helper_iwmmxt_addcw(cpu_M0, cpu_M0);
balrog18c9b562007-04-30 02:02:17 +00001986 break;
1987 case 2:
pbrooke6771372008-03-31 03:49:05 +00001988 gen_helper_iwmmxt_addcl(cpu_M0, cpu_M0);
balrog18c9b562007-04-30 02:02:17 +00001989 break;
1990 case 3:
1991 return 1;
1992 }
1993 gen_op_iwmmxt_movq_wRn_M0(wrd);
1994 gen_op_iwmmxt_set_mup();
1995 break;
1996 case 0x115: case 0x515: case 0x915: case 0xd15: /* TORC */
1997 if ((insn & 0x000ff00f) != 0x0003f000)
1998 return 1;
1999 gen_op_iwmmxt_movl_T1_wCx(ARM_IWMMXT_wCASF);
2000 switch ((insn >> 22) & 3) {
2001 case 0:
2002 for (i = 0; i < 7; i ++) {
2003 gen_op_shll_T1_im(4);
2004 gen_op_orl_T0_T1();
2005 }
2006 break;
2007 case 1:
2008 for (i = 0; i < 3; i ++) {
2009 gen_op_shll_T1_im(8);
2010 gen_op_orl_T0_T1();
2011 }
2012 break;
2013 case 2:
2014 gen_op_shll_T1_im(16);
2015 gen_op_orl_T0_T1();
2016 break;
2017 case 3:
2018 return 1;
2019 }
pbrookd9ba4832008-03-31 03:46:50 +00002020 gen_set_nzcv(cpu_T[0]);
balrog18c9b562007-04-30 02:02:17 +00002021 break;
2022 case 0x103: case 0x503: case 0x903: case 0xd03: /* TMOVMSK */
2023 rd = (insn >> 12) & 0xf;
2024 rd0 = (insn >> 16) & 0xf;
2025 if ((insn & 0xf) != 0)
2026 return 1;
2027 gen_op_iwmmxt_movq_M0_wRn(rd0);
2028 switch ((insn >> 22) & 3) {
2029 case 0:
pbrooke6771372008-03-31 03:49:05 +00002030 gen_helper_iwmmxt_msbb(cpu_T[0], cpu_M0);
balrog18c9b562007-04-30 02:02:17 +00002031 break;
2032 case 1:
pbrooke6771372008-03-31 03:49:05 +00002033 gen_helper_iwmmxt_msbw(cpu_T[0], cpu_M0);
balrog18c9b562007-04-30 02:02:17 +00002034 break;
2035 case 2:
pbrooke6771372008-03-31 03:49:05 +00002036 gen_helper_iwmmxt_msbl(cpu_T[0], cpu_M0);
balrog18c9b562007-04-30 02:02:17 +00002037 break;
2038 case 3:
2039 return 1;
2040 }
2041 gen_movl_reg_T0(s, rd);
2042 break;
2043 case 0x106: case 0x306: case 0x506: case 0x706: /* WCMPGT */
2044 case 0x906: case 0xb06: case 0xd06: case 0xf06:
2045 wrd = (insn >> 12) & 0xf;
2046 rd0 = (insn >> 16) & 0xf;
2047 rd1 = (insn >> 0) & 0xf;
2048 gen_op_iwmmxt_movq_M0_wRn(rd0);
2049 switch ((insn >> 22) & 3) {
2050 case 0:
2051 if (insn & (1 << 21))
2052 gen_op_iwmmxt_cmpgtsb_M0_wRn(rd1);
2053 else
2054 gen_op_iwmmxt_cmpgtub_M0_wRn(rd1);
2055 break;
2056 case 1:
2057 if (insn & (1 << 21))
2058 gen_op_iwmmxt_cmpgtsw_M0_wRn(rd1);
2059 else
2060 gen_op_iwmmxt_cmpgtuw_M0_wRn(rd1);
2061 break;
2062 case 2:
2063 if (insn & (1 << 21))
2064 gen_op_iwmmxt_cmpgtsl_M0_wRn(rd1);
2065 else
2066 gen_op_iwmmxt_cmpgtul_M0_wRn(rd1);
2067 break;
2068 case 3:
2069 return 1;
2070 }
2071 gen_op_iwmmxt_movq_wRn_M0(wrd);
2072 gen_op_iwmmxt_set_mup();
2073 gen_op_iwmmxt_set_cup();
2074 break;
2075 case 0x00e: case 0x20e: case 0x40e: case 0x60e: /* WUNPCKEL */
2076 case 0x80e: case 0xa0e: case 0xc0e: case 0xe0e:
2077 wrd = (insn >> 12) & 0xf;
2078 rd0 = (insn >> 16) & 0xf;
2079 gen_op_iwmmxt_movq_M0_wRn(rd0);
2080 switch ((insn >> 22) & 3) {
2081 case 0:
2082 if (insn & (1 << 21))
2083 gen_op_iwmmxt_unpacklsb_M0();
2084 else
2085 gen_op_iwmmxt_unpacklub_M0();
2086 break;
2087 case 1:
2088 if (insn & (1 << 21))
2089 gen_op_iwmmxt_unpacklsw_M0();
2090 else
2091 gen_op_iwmmxt_unpackluw_M0();
2092 break;
2093 case 2:
2094 if (insn & (1 << 21))
2095 gen_op_iwmmxt_unpacklsl_M0();
2096 else
2097 gen_op_iwmmxt_unpacklul_M0();
2098 break;
2099 case 3:
2100 return 1;
2101 }
2102 gen_op_iwmmxt_movq_wRn_M0(wrd);
2103 gen_op_iwmmxt_set_mup();
2104 gen_op_iwmmxt_set_cup();
2105 break;
2106 case 0x00c: case 0x20c: case 0x40c: case 0x60c: /* WUNPCKEH */
2107 case 0x80c: case 0xa0c: case 0xc0c: case 0xe0c:
2108 wrd = (insn >> 12) & 0xf;
2109 rd0 = (insn >> 16) & 0xf;
2110 gen_op_iwmmxt_movq_M0_wRn(rd0);
2111 switch ((insn >> 22) & 3) {
2112 case 0:
2113 if (insn & (1 << 21))
2114 gen_op_iwmmxt_unpackhsb_M0();
2115 else
2116 gen_op_iwmmxt_unpackhub_M0();
2117 break;
2118 case 1:
2119 if (insn & (1 << 21))
2120 gen_op_iwmmxt_unpackhsw_M0();
2121 else
2122 gen_op_iwmmxt_unpackhuw_M0();
2123 break;
2124 case 2:
2125 if (insn & (1 << 21))
2126 gen_op_iwmmxt_unpackhsl_M0();
2127 else
2128 gen_op_iwmmxt_unpackhul_M0();
2129 break;
2130 case 3:
2131 return 1;
2132 }
2133 gen_op_iwmmxt_movq_wRn_M0(wrd);
2134 gen_op_iwmmxt_set_mup();
2135 gen_op_iwmmxt_set_cup();
2136 break;
2137 case 0x204: case 0x604: case 0xa04: case 0xe04: /* WSRL */
2138 case 0x214: case 0x614: case 0xa14: case 0xe14:
2139 wrd = (insn >> 12) & 0xf;
2140 rd0 = (insn >> 16) & 0xf;
2141 gen_op_iwmmxt_movq_M0_wRn(rd0);
2142 if (gen_iwmmxt_shift(insn, 0xff))
2143 return 1;
2144 switch ((insn >> 22) & 3) {
2145 case 0:
2146 return 1;
2147 case 1:
pbrooke6771372008-03-31 03:49:05 +00002148 gen_helper_iwmmxt_srlw(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
balrog18c9b562007-04-30 02:02:17 +00002149 break;
2150 case 2:
pbrooke6771372008-03-31 03:49:05 +00002151 gen_helper_iwmmxt_srll(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
balrog18c9b562007-04-30 02:02:17 +00002152 break;
2153 case 3:
pbrooke6771372008-03-31 03:49:05 +00002154 gen_helper_iwmmxt_srlq(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
balrog18c9b562007-04-30 02:02:17 +00002155 break;
2156 }
2157 gen_op_iwmmxt_movq_wRn_M0(wrd);
2158 gen_op_iwmmxt_set_mup();
2159 gen_op_iwmmxt_set_cup();
2160 break;
2161 case 0x004: case 0x404: case 0x804: case 0xc04: /* WSRA */
2162 case 0x014: case 0x414: case 0x814: case 0xc14:
2163 wrd = (insn >> 12) & 0xf;
2164 rd0 = (insn >> 16) & 0xf;
2165 gen_op_iwmmxt_movq_M0_wRn(rd0);
2166 if (gen_iwmmxt_shift(insn, 0xff))
2167 return 1;
2168 switch ((insn >> 22) & 3) {
2169 case 0:
2170 return 1;
2171 case 1:
pbrooke6771372008-03-31 03:49:05 +00002172 gen_helper_iwmmxt_sraw(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
balrog18c9b562007-04-30 02:02:17 +00002173 break;
2174 case 2:
pbrooke6771372008-03-31 03:49:05 +00002175 gen_helper_iwmmxt_sral(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
balrog18c9b562007-04-30 02:02:17 +00002176 break;
2177 case 3:
pbrooke6771372008-03-31 03:49:05 +00002178 gen_helper_iwmmxt_sraq(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
balrog18c9b562007-04-30 02:02:17 +00002179 break;
2180 }
2181 gen_op_iwmmxt_movq_wRn_M0(wrd);
2182 gen_op_iwmmxt_set_mup();
2183 gen_op_iwmmxt_set_cup();
2184 break;
2185 case 0x104: case 0x504: case 0x904: case 0xd04: /* WSLL */
2186 case 0x114: case 0x514: case 0x914: case 0xd14:
2187 wrd = (insn >> 12) & 0xf;
2188 rd0 = (insn >> 16) & 0xf;
2189 gen_op_iwmmxt_movq_M0_wRn(rd0);
2190 if (gen_iwmmxt_shift(insn, 0xff))
2191 return 1;
2192 switch ((insn >> 22) & 3) {
2193 case 0:
2194 return 1;
2195 case 1:
pbrooke6771372008-03-31 03:49:05 +00002196 gen_helper_iwmmxt_sllw(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
balrog18c9b562007-04-30 02:02:17 +00002197 break;
2198 case 2:
pbrooke6771372008-03-31 03:49:05 +00002199 gen_helper_iwmmxt_slll(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
balrog18c9b562007-04-30 02:02:17 +00002200 break;
2201 case 3:
pbrooke6771372008-03-31 03:49:05 +00002202 gen_helper_iwmmxt_sllq(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
balrog18c9b562007-04-30 02:02:17 +00002203 break;
2204 }
2205 gen_op_iwmmxt_movq_wRn_M0(wrd);
2206 gen_op_iwmmxt_set_mup();
2207 gen_op_iwmmxt_set_cup();
2208 break;
2209 case 0x304: case 0x704: case 0xb04: case 0xf04: /* WROR */
2210 case 0x314: case 0x714: case 0xb14: case 0xf14:
2211 wrd = (insn >> 12) & 0xf;
2212 rd0 = (insn >> 16) & 0xf;
2213 gen_op_iwmmxt_movq_M0_wRn(rd0);
2214 switch ((insn >> 22) & 3) {
2215 case 0:
2216 return 1;
2217 case 1:
2218 if (gen_iwmmxt_shift(insn, 0xf))
2219 return 1;
pbrooke6771372008-03-31 03:49:05 +00002220 gen_helper_iwmmxt_rorw(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
balrog18c9b562007-04-30 02:02:17 +00002221 break;
2222 case 2:
2223 if (gen_iwmmxt_shift(insn, 0x1f))
2224 return 1;
pbrooke6771372008-03-31 03:49:05 +00002225 gen_helper_iwmmxt_rorl(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
balrog18c9b562007-04-30 02:02:17 +00002226 break;
2227 case 3:
2228 if (gen_iwmmxt_shift(insn, 0x3f))
2229 return 1;
pbrooke6771372008-03-31 03:49:05 +00002230 gen_helper_iwmmxt_rorq(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
balrog18c9b562007-04-30 02:02:17 +00002231 break;
2232 }
2233 gen_op_iwmmxt_movq_wRn_M0(wrd);
2234 gen_op_iwmmxt_set_mup();
2235 gen_op_iwmmxt_set_cup();
2236 break;
2237 case 0x116: case 0x316: case 0x516: case 0x716: /* WMIN */
2238 case 0x916: case 0xb16: case 0xd16: case 0xf16:
2239 wrd = (insn >> 12) & 0xf;
2240 rd0 = (insn >> 16) & 0xf;
2241 rd1 = (insn >> 0) & 0xf;
2242 gen_op_iwmmxt_movq_M0_wRn(rd0);
2243 switch ((insn >> 22) & 3) {
2244 case 0:
2245 if (insn & (1 << 21))
2246 gen_op_iwmmxt_minsb_M0_wRn(rd1);
2247 else
2248 gen_op_iwmmxt_minub_M0_wRn(rd1);
2249 break;
2250 case 1:
2251 if (insn & (1 << 21))
2252 gen_op_iwmmxt_minsw_M0_wRn(rd1);
2253 else
2254 gen_op_iwmmxt_minuw_M0_wRn(rd1);
2255 break;
2256 case 2:
2257 if (insn & (1 << 21))
2258 gen_op_iwmmxt_minsl_M0_wRn(rd1);
2259 else
2260 gen_op_iwmmxt_minul_M0_wRn(rd1);
2261 break;
2262 case 3:
2263 return 1;
2264 }
2265 gen_op_iwmmxt_movq_wRn_M0(wrd);
2266 gen_op_iwmmxt_set_mup();
2267 break;
2268 case 0x016: case 0x216: case 0x416: case 0x616: /* WMAX */
2269 case 0x816: case 0xa16: case 0xc16: case 0xe16:
2270 wrd = (insn >> 12) & 0xf;
2271 rd0 = (insn >> 16) & 0xf;
2272 rd1 = (insn >> 0) & 0xf;
2273 gen_op_iwmmxt_movq_M0_wRn(rd0);
2274 switch ((insn >> 22) & 3) {
2275 case 0:
2276 if (insn & (1 << 21))
2277 gen_op_iwmmxt_maxsb_M0_wRn(rd1);
2278 else
2279 gen_op_iwmmxt_maxub_M0_wRn(rd1);
2280 break;
2281 case 1:
2282 if (insn & (1 << 21))
2283 gen_op_iwmmxt_maxsw_M0_wRn(rd1);
2284 else
2285 gen_op_iwmmxt_maxuw_M0_wRn(rd1);
2286 break;
2287 case 2:
2288 if (insn & (1 << 21))
2289 gen_op_iwmmxt_maxsl_M0_wRn(rd1);
2290 else
2291 gen_op_iwmmxt_maxul_M0_wRn(rd1);
2292 break;
2293 case 3:
2294 return 1;
2295 }
2296 gen_op_iwmmxt_movq_wRn_M0(wrd);
2297 gen_op_iwmmxt_set_mup();
2298 break;
2299 case 0x002: case 0x102: case 0x202: case 0x302: /* WALIGNI */
2300 case 0x402: case 0x502: case 0x602: case 0x702:
2301 wrd = (insn >> 12) & 0xf;
2302 rd0 = (insn >> 16) & 0xf;
2303 rd1 = (insn >> 0) & 0xf;
2304 gen_op_iwmmxt_movq_M0_wRn(rd0);
2305 gen_op_movl_T0_im((insn >> 20) & 3);
2306 gen_op_iwmmxt_align_M0_T0_wRn(rd1);
2307 gen_op_iwmmxt_movq_wRn_M0(wrd);
2308 gen_op_iwmmxt_set_mup();
2309 break;
2310 case 0x01a: case 0x11a: case 0x21a: case 0x31a: /* WSUB */
2311 case 0x41a: case 0x51a: case 0x61a: case 0x71a:
2312 case 0x81a: case 0x91a: case 0xa1a: case 0xb1a:
2313 case 0xc1a: case 0xd1a: case 0xe1a: case 0xf1a:
2314 wrd = (insn >> 12) & 0xf;
2315 rd0 = (insn >> 16) & 0xf;
2316 rd1 = (insn >> 0) & 0xf;
2317 gen_op_iwmmxt_movq_M0_wRn(rd0);
2318 switch ((insn >> 20) & 0xf) {
2319 case 0x0:
2320 gen_op_iwmmxt_subnb_M0_wRn(rd1);
2321 break;
2322 case 0x1:
2323 gen_op_iwmmxt_subub_M0_wRn(rd1);
2324 break;
2325 case 0x3:
2326 gen_op_iwmmxt_subsb_M0_wRn(rd1);
2327 break;
2328 case 0x4:
2329 gen_op_iwmmxt_subnw_M0_wRn(rd1);
2330 break;
2331 case 0x5:
2332 gen_op_iwmmxt_subuw_M0_wRn(rd1);
2333 break;
2334 case 0x7:
2335 gen_op_iwmmxt_subsw_M0_wRn(rd1);
2336 break;
2337 case 0x8:
2338 gen_op_iwmmxt_subnl_M0_wRn(rd1);
2339 break;
2340 case 0x9:
2341 gen_op_iwmmxt_subul_M0_wRn(rd1);
2342 break;
2343 case 0xb:
2344 gen_op_iwmmxt_subsl_M0_wRn(rd1);
2345 break;
2346 default:
2347 return 1;
2348 }
2349 gen_op_iwmmxt_movq_wRn_M0(wrd);
2350 gen_op_iwmmxt_set_mup();
2351 gen_op_iwmmxt_set_cup();
2352 break;
2353 case 0x01e: case 0x11e: case 0x21e: case 0x31e: /* WSHUFH */
2354 case 0x41e: case 0x51e: case 0x61e: case 0x71e:
2355 case 0x81e: case 0x91e: case 0xa1e: case 0xb1e:
2356 case 0xc1e: case 0xd1e: case 0xe1e: case 0xf1e:
2357 wrd = (insn >> 12) & 0xf;
2358 rd0 = (insn >> 16) & 0xf;
2359 gen_op_iwmmxt_movq_M0_wRn(rd0);
2360 gen_op_movl_T0_im(((insn >> 16) & 0xf0) | (insn & 0x0f));
pbrooke6771372008-03-31 03:49:05 +00002361 gen_helper_iwmmxt_shufh(cpu_M0, cpu_env, cpu_M0, cpu_T[0]);
balrog18c9b562007-04-30 02:02:17 +00002362 gen_op_iwmmxt_movq_wRn_M0(wrd);
2363 gen_op_iwmmxt_set_mup();
2364 gen_op_iwmmxt_set_cup();
2365 break;
2366 case 0x018: case 0x118: case 0x218: case 0x318: /* WADD */
2367 case 0x418: case 0x518: case 0x618: case 0x718:
2368 case 0x818: case 0x918: case 0xa18: case 0xb18:
2369 case 0xc18: case 0xd18: case 0xe18: case 0xf18:
2370 wrd = (insn >> 12) & 0xf;
2371 rd0 = (insn >> 16) & 0xf;
2372 rd1 = (insn >> 0) & 0xf;
2373 gen_op_iwmmxt_movq_M0_wRn(rd0);
2374 switch ((insn >> 20) & 0xf) {
2375 case 0x0:
2376 gen_op_iwmmxt_addnb_M0_wRn(rd1);
2377 break;
2378 case 0x1:
2379 gen_op_iwmmxt_addub_M0_wRn(rd1);
2380 break;
2381 case 0x3:
2382 gen_op_iwmmxt_addsb_M0_wRn(rd1);
2383 break;
2384 case 0x4:
2385 gen_op_iwmmxt_addnw_M0_wRn(rd1);
2386 break;
2387 case 0x5:
2388 gen_op_iwmmxt_adduw_M0_wRn(rd1);
2389 break;
2390 case 0x7:
2391 gen_op_iwmmxt_addsw_M0_wRn(rd1);
2392 break;
2393 case 0x8:
2394 gen_op_iwmmxt_addnl_M0_wRn(rd1);
2395 break;
2396 case 0x9:
2397 gen_op_iwmmxt_addul_M0_wRn(rd1);
2398 break;
2399 case 0xb:
2400 gen_op_iwmmxt_addsl_M0_wRn(rd1);
2401 break;
2402 default:
2403 return 1;
2404 }
2405 gen_op_iwmmxt_movq_wRn_M0(wrd);
2406 gen_op_iwmmxt_set_mup();
2407 gen_op_iwmmxt_set_cup();
2408 break;
2409 case 0x008: case 0x108: case 0x208: case 0x308: /* WPACK */
2410 case 0x408: case 0x508: case 0x608: case 0x708:
2411 case 0x808: case 0x908: case 0xa08: case 0xb08:
2412 case 0xc08: case 0xd08: case 0xe08: case 0xf08:
2413 wrd = (insn >> 12) & 0xf;
2414 rd0 = (insn >> 16) & 0xf;
2415 rd1 = (insn >> 0) & 0xf;
2416 gen_op_iwmmxt_movq_M0_wRn(rd0);
2417 if (!(insn & (1 << 20)))
2418 return 1;
2419 switch ((insn >> 22) & 3) {
2420 case 0:
2421 return 1;
2422 case 1:
2423 if (insn & (1 << 21))
2424 gen_op_iwmmxt_packsw_M0_wRn(rd1);
2425 else
2426 gen_op_iwmmxt_packuw_M0_wRn(rd1);
2427 break;
2428 case 2:
2429 if (insn & (1 << 21))
2430 gen_op_iwmmxt_packsl_M0_wRn(rd1);
2431 else
2432 gen_op_iwmmxt_packul_M0_wRn(rd1);
2433 break;
2434 case 3:
2435 if (insn & (1 << 21))
2436 gen_op_iwmmxt_packsq_M0_wRn(rd1);
2437 else
2438 gen_op_iwmmxt_packuq_M0_wRn(rd1);
2439 break;
2440 }
2441 gen_op_iwmmxt_movq_wRn_M0(wrd);
2442 gen_op_iwmmxt_set_mup();
2443 gen_op_iwmmxt_set_cup();
2444 break;
2445 case 0x201: case 0x203: case 0x205: case 0x207:
2446 case 0x209: case 0x20b: case 0x20d: case 0x20f:
2447 case 0x211: case 0x213: case 0x215: case 0x217:
2448 case 0x219: case 0x21b: case 0x21d: case 0x21f:
2449 wrd = (insn >> 5) & 0xf;
2450 rd0 = (insn >> 12) & 0xf;
2451 rd1 = (insn >> 0) & 0xf;
2452 if (rd0 == 0xf || rd1 == 0xf)
2453 return 1;
2454 gen_op_iwmmxt_movq_M0_wRn(wrd);
2455 switch ((insn >> 16) & 0xf) {
2456 case 0x0: /* TMIA */
pbrookb26eefb2008-03-31 03:44:26 +00002457 gen_movl_T0_reg(s, rd0);
2458 gen_movl_T1_reg(s, rd1);
balrog18c9b562007-04-30 02:02:17 +00002459 gen_op_iwmmxt_muladdsl_M0_T0_T1();
2460 break;
2461 case 0x8: /* TMIAPH */
pbrookb26eefb2008-03-31 03:44:26 +00002462 gen_movl_T0_reg(s, rd0);
2463 gen_movl_T1_reg(s, rd1);
balrog18c9b562007-04-30 02:02:17 +00002464 gen_op_iwmmxt_muladdsw_M0_T0_T1();
2465 break;
2466 case 0xc: case 0xd: case 0xe: case 0xf: /* TMIAxy */
pbrookb26eefb2008-03-31 03:44:26 +00002467 gen_movl_T1_reg(s, rd0);
balrog18c9b562007-04-30 02:02:17 +00002468 if (insn & (1 << 16))
2469 gen_op_shrl_T1_im(16);
2470 gen_op_movl_T0_T1();
pbrookb26eefb2008-03-31 03:44:26 +00002471 gen_movl_T1_reg(s, rd1);
balrog18c9b562007-04-30 02:02:17 +00002472 if (insn & (1 << 17))
2473 gen_op_shrl_T1_im(16);
2474 gen_op_iwmmxt_muladdswl_M0_T0_T1();
2475 break;
2476 default:
2477 return 1;
2478 }
2479 gen_op_iwmmxt_movq_wRn_M0(wrd);
2480 gen_op_iwmmxt_set_mup();
2481 break;
2482 default:
2483 return 1;
2484 }
2485
2486 return 0;
2487}
2488
2489/* Disassemble an XScale DSP instruction. Returns nonzero if an error occured
2490 (ie. an undefined instruction). */
2491static int disas_dsp_insn(CPUState *env, DisasContext *s, uint32_t insn)
2492{
2493 int acc, rd0, rd1, rdhi, rdlo;
2494
2495 if ((insn & 0x0ff00f10) == 0x0e200010) {
2496 /* Multiply with Internal Accumulate Format */
2497 rd0 = (insn >> 12) & 0xf;
2498 rd1 = insn & 0xf;
2499 acc = (insn >> 5) & 7;
2500
2501 if (acc != 0)
2502 return 1;
2503
2504 switch ((insn >> 16) & 0xf) {
2505 case 0x0: /* MIA */
pbrookb26eefb2008-03-31 03:44:26 +00002506 gen_movl_T0_reg(s, rd0);
2507 gen_movl_T1_reg(s, rd1);
balrog18c9b562007-04-30 02:02:17 +00002508 gen_op_iwmmxt_muladdsl_M0_T0_T1();
2509 break;
2510 case 0x8: /* MIAPH */
pbrookb26eefb2008-03-31 03:44:26 +00002511 gen_movl_T0_reg(s, rd0);
2512 gen_movl_T1_reg(s, rd1);
balrog18c9b562007-04-30 02:02:17 +00002513 gen_op_iwmmxt_muladdsw_M0_T0_T1();
2514 break;
2515 case 0xc: /* MIABB */
2516 case 0xd: /* MIABT */
2517 case 0xe: /* MIATB */
2518 case 0xf: /* MIATT */
pbrookb26eefb2008-03-31 03:44:26 +00002519 gen_movl_T1_reg(s, rd0);
balrog18c9b562007-04-30 02:02:17 +00002520 if (insn & (1 << 16))
2521 gen_op_shrl_T1_im(16);
2522 gen_op_movl_T0_T1();
pbrookb26eefb2008-03-31 03:44:26 +00002523 gen_movl_T1_reg(s, rd1);
balrog18c9b562007-04-30 02:02:17 +00002524 if (insn & (1 << 17))
2525 gen_op_shrl_T1_im(16);
2526 gen_op_iwmmxt_muladdswl_M0_T0_T1();
2527 break;
2528 default:
2529 return 1;
2530 }
2531
2532 gen_op_iwmmxt_movq_wRn_M0(acc);
2533 return 0;
2534 }
2535
2536 if ((insn & 0x0fe00ff8) == 0x0c400000) {
2537 /* Internal Accumulator Access Format */
2538 rdhi = (insn >> 16) & 0xf;
2539 rdlo = (insn >> 12) & 0xf;
2540 acc = insn & 7;
2541
2542 if (acc != 0)
2543 return 1;
2544
2545 if (insn & ARM_CP_RW_BIT) { /* MRA */
pbrooke6771372008-03-31 03:49:05 +00002546 gen_iwmmxt_movl_T0_T1_wRn(acc);
pbrookb26eefb2008-03-31 03:44:26 +00002547 gen_movl_reg_T0(s, rdlo);
balrog18c9b562007-04-30 02:02:17 +00002548 gen_op_movl_T0_im((1 << (40 - 32)) - 1);
2549 gen_op_andl_T0_T1();
pbrookb26eefb2008-03-31 03:44:26 +00002550 gen_movl_reg_T0(s, rdhi);
balrog18c9b562007-04-30 02:02:17 +00002551 } else { /* MAR */
pbrookb26eefb2008-03-31 03:44:26 +00002552 gen_movl_T0_reg(s, rdlo);
2553 gen_movl_T1_reg(s, rdhi);
pbrooke6771372008-03-31 03:49:05 +00002554 gen_iwmmxt_movl_wRn_T0_T1(acc);
balrog18c9b562007-04-30 02:02:17 +00002555 }
2556 return 0;
2557 }
2558
2559 return 1;
2560}
2561
balrogc1713132007-04-30 01:26:42 +00002562/* Disassemble system coprocessor instruction. Return nonzero if
2563 instruction is not defined. */
2564static int disas_cp_insn(CPUState *env, DisasContext *s, uint32_t insn)
2565{
pbrook8984bd22008-03-31 03:47:48 +00002566 TCGv tmp;
balrogc1713132007-04-30 01:26:42 +00002567 uint32_t rd = (insn >> 12) & 0xf;
2568 uint32_t cp = (insn >> 8) & 0xf;
2569 if (IS_USER(s)) {
2570 return 1;
2571 }
2572
balrog18c9b562007-04-30 02:02:17 +00002573 if (insn & ARM_CP_RW_BIT) {
balrogc1713132007-04-30 01:26:42 +00002574 if (!env->cp[cp].cp_read)
2575 return 1;
pbrook8984bd22008-03-31 03:47:48 +00002576 gen_set_pc_im(s->pc);
2577 tmp = new_tmp();
2578 gen_helper_get_cp(tmp, cpu_env, tcg_const_i32(insn));
2579 store_reg(s, rd, tmp);
balrogc1713132007-04-30 01:26:42 +00002580 } else {
2581 if (!env->cp[cp].cp_write)
2582 return 1;
pbrook8984bd22008-03-31 03:47:48 +00002583 gen_set_pc_im(s->pc);
2584 tmp = load_reg(s, rd);
2585 gen_helper_set_cp(cpu_env, tcg_const_i32(insn), tmp);
balrogc1713132007-04-30 01:26:42 +00002586 }
2587 return 0;
2588}
2589
pbrook9ee6e8b2007-11-11 00:04:49 +00002590static int cp15_user_ok(uint32_t insn)
2591{
2592 int cpn = (insn >> 16) & 0xf;
2593 int cpm = insn & 0xf;
2594 int op = ((insn >> 5) & 7) | ((insn >> 18) & 0x38);
2595
2596 if (cpn == 13 && cpm == 0) {
2597 /* TLS register. */
2598 if (op == 2 || (op == 3 && (insn & ARM_CP_RW_BIT)))
2599 return 1;
2600 }
2601 if (cpn == 7) {
2602 /* ISB, DSB, DMB. */
2603 if ((cpm == 5 && op == 4)
2604 || (cpm == 10 && (op == 4 || op == 5)))
2605 return 1;
2606 }
2607 return 0;
2608}
2609
bellardb5ff1b32005-11-26 10:38:39 +00002610/* Disassemble system coprocessor (cp15) instruction. Return nonzero if
2611 instruction is not defined. */
balroga90b7312007-05-01 01:28:01 +00002612static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn)
bellardb5ff1b32005-11-26 10:38:39 +00002613{
2614 uint32_t rd;
pbrook8984bd22008-03-31 03:47:48 +00002615 TCGv tmp;
bellardb5ff1b32005-11-26 10:38:39 +00002616
pbrook9ee6e8b2007-11-11 00:04:49 +00002617 /* M profile cores use memory mapped registers instead of cp15. */
2618 if (arm_feature(env, ARM_FEATURE_M))
2619 return 1;
2620
2621 if ((insn & (1 << 25)) == 0) {
2622 if (insn & (1 << 20)) {
2623 /* mrrc */
2624 return 1;
2625 }
2626 /* mcrr. Used for block cache operations, so implement as no-op. */
2627 return 0;
2628 }
2629 if ((insn & (1 << 4)) == 0) {
2630 /* cdp */
2631 return 1;
2632 }
2633 if (IS_USER(s) && !cp15_user_ok(insn)) {
bellardb5ff1b32005-11-26 10:38:39 +00002634 return 1;
2635 }
bellard9332f9d2005-11-26 10:46:39 +00002636 if ((insn & 0x0fff0fff) == 0x0e070f90
2637 || (insn & 0x0fff0fff) == 0x0e070f58) {
2638 /* Wait for interrupt. */
pbrook8984bd22008-03-31 03:47:48 +00002639 gen_set_pc_im(s->pc);
pbrook9ee6e8b2007-11-11 00:04:49 +00002640 s->is_jmp = DISAS_WFI;
bellard9332f9d2005-11-26 10:46:39 +00002641 return 0;
2642 }
bellardb5ff1b32005-11-26 10:38:39 +00002643 rd = (insn >> 12) & 0xf;
balrog18c9b562007-04-30 02:02:17 +00002644 if (insn & ARM_CP_RW_BIT) {
pbrook8984bd22008-03-31 03:47:48 +00002645 tmp = new_tmp();
2646 gen_helper_get_cp15(tmp, cpu_env, tcg_const_i32(insn));
bellardb5ff1b32005-11-26 10:38:39 +00002647 /* If the destination register is r15 then sets condition codes. */
2648 if (rd != 15)
pbrook8984bd22008-03-31 03:47:48 +00002649 store_reg(s, rd, tmp);
2650 else
2651 dead_tmp(tmp);
bellardb5ff1b32005-11-26 10:38:39 +00002652 } else {
pbrook8984bd22008-03-31 03:47:48 +00002653 tmp = load_reg(s, rd);
2654 gen_helper_set_cp15(cpu_env, tcg_const_i32(insn), tmp);
2655 dead_tmp(tmp);
balroga90b7312007-05-01 01:28:01 +00002656 /* Normally we would always end the TB here, but Linux
2657 * arch/arm/mach-pxa/sleep.S expects two instructions following
2658 * an MMU enable to execute from cache. Imitate this behaviour. */
2659 if (!arm_feature(env, ARM_FEATURE_XSCALE) ||
2660 (insn & 0x0fff0fff) != 0x0e010f10)
2661 gen_lookup_tb(s);
bellardb5ff1b32005-11-26 10:38:39 +00002662 }
bellardb5ff1b32005-11-26 10:38:39 +00002663 return 0;
2664}
2665
pbrook9ee6e8b2007-11-11 00:04:49 +00002666#define VFP_REG_SHR(x, n) (((n) > 0) ? (x) >> (n) : (x) << -(n))
2667#define VFP_SREG(insn, bigbit, smallbit) \
2668 ((VFP_REG_SHR(insn, bigbit - 1) & 0x1e) | (((insn) >> (smallbit)) & 1))
2669#define VFP_DREG(reg, insn, bigbit, smallbit) do { \
2670 if (arm_feature(env, ARM_FEATURE_VFP3)) { \
2671 reg = (((insn) >> (bigbit)) & 0x0f) \
2672 | (((insn) >> ((smallbit) - 4)) & 0x10); \
2673 } else { \
2674 if (insn & (1 << (smallbit))) \
2675 return 1; \
2676 reg = ((insn) >> (bigbit)) & 0x0f; \
2677 }} while (0)
2678
2679#define VFP_SREG_D(insn) VFP_SREG(insn, 12, 22)
2680#define VFP_DREG_D(reg, insn) VFP_DREG(reg, insn, 12, 22)
2681#define VFP_SREG_N(insn) VFP_SREG(insn, 16, 7)
2682#define VFP_DREG_N(reg, insn) VFP_DREG(reg, insn, 16, 7)
2683#define VFP_SREG_M(insn) VFP_SREG(insn, 0, 5)
2684#define VFP_DREG_M(reg, insn) VFP_DREG(reg, insn, 0, 5)
2685
pbrook4373f3c2008-03-31 03:47:19 +00002686/* Move between integer and VFP cores. */
2687static TCGv gen_vfp_mrs(void)
2688{
2689 TCGv tmp = new_tmp();
2690 tcg_gen_mov_i32(tmp, cpu_F0s);
2691 return tmp;
2692}
2693
2694static void gen_vfp_msr(TCGv tmp)
2695{
2696 tcg_gen_mov_i32(cpu_F0s, tmp);
2697 dead_tmp(tmp);
2698}
2699
pbrook9ee6e8b2007-11-11 00:04:49 +00002700static inline int
2701vfp_enabled(CPUState * env)
2702{
2703 return ((env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) != 0);
2704}
2705
pbrookad694712008-03-31 03:48:30 +00002706static void gen_neon_dup_u8(TCGv var, int shift)
2707{
2708 TCGv tmp = new_tmp();
2709 if (shift)
2710 tcg_gen_shri_i32(var, var, shift);
2711 tcg_gen_andi_i32(var, var, 0xff);
2712 tcg_gen_shli_i32(tmp, var, 8);
2713 tcg_gen_or_i32(var, var, tmp);
2714 tcg_gen_shli_i32(tmp, var, 16);
2715 tcg_gen_or_i32(var, var, tmp);
2716 dead_tmp(tmp);
2717}
2718
2719static void gen_neon_dup_low16(TCGv var)
2720{
2721 TCGv tmp = new_tmp();
2722 tcg_gen_andi_i32(var, var, 0xffff);
2723 tcg_gen_shli_i32(tmp, var, 16);
2724 tcg_gen_or_i32(var, var, tmp);
2725 dead_tmp(tmp);
2726}
2727
2728static void gen_neon_dup_high16(TCGv var)
2729{
2730 TCGv tmp = new_tmp();
2731 tcg_gen_andi_i32(var, var, 0xffff0000);
2732 tcg_gen_shri_i32(tmp, var, 16);
2733 tcg_gen_or_i32(var, var, tmp);
2734 dead_tmp(tmp);
2735}
2736
bellardb7bcbe92005-02-22 19:27:29 +00002737/* Disassemble a VFP instruction. Returns nonzero if an error occured
2738 (ie. an undefined instruction). */
2739static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
2740{
2741 uint32_t rd, rn, rm, op, i, n, offset, delta_d, delta_m, bank_mask;
2742 int dp, veclen;
pbrook4373f3c2008-03-31 03:47:19 +00002743 TCGv tmp;
pbrookad694712008-03-31 03:48:30 +00002744 TCGv tmp2;
bellardb7bcbe92005-02-22 19:27:29 +00002745
pbrook40f137e2006-02-20 00:33:36 +00002746 if (!arm_feature(env, ARM_FEATURE_VFP))
2747 return 1;
2748
pbrook9ee6e8b2007-11-11 00:04:49 +00002749 if (!vfp_enabled(env)) {
2750 /* VFP disabled. Only allow fmxr/fmrx to/from some control regs. */
pbrook40f137e2006-02-20 00:33:36 +00002751 if ((insn & 0x0fe00fff) != 0x0ee00a10)
2752 return 1;
2753 rn = (insn >> 16) & 0xf;
pbrook9ee6e8b2007-11-11 00:04:49 +00002754 if (rn != ARM_VFP_FPSID && rn != ARM_VFP_FPEXC
2755 && rn != ARM_VFP_MVFR1 && rn != ARM_VFP_MVFR0)
pbrook40f137e2006-02-20 00:33:36 +00002756 return 1;
2757 }
bellardb7bcbe92005-02-22 19:27:29 +00002758 dp = ((insn & 0xf00) == 0xb00);
2759 switch ((insn >> 24) & 0xf) {
2760 case 0xe:
2761 if (insn & (1 << 4)) {
2762 /* single register transfer */
bellardb7bcbe92005-02-22 19:27:29 +00002763 rd = (insn >> 12) & 0xf;
2764 if (dp) {
pbrook9ee6e8b2007-11-11 00:04:49 +00002765 int size;
2766 int pass;
2767
2768 VFP_DREG_N(rn, insn);
2769 if (insn & 0xf)
bellardb7bcbe92005-02-22 19:27:29 +00002770 return 1;
pbrook9ee6e8b2007-11-11 00:04:49 +00002771 if (insn & 0x00c00060
2772 && !arm_feature(env, ARM_FEATURE_NEON))
2773 return 1;
2774
2775 pass = (insn >> 21) & 1;
2776 if (insn & (1 << 22)) {
2777 size = 0;
2778 offset = ((insn >> 5) & 3) * 8;
2779 } else if (insn & (1 << 5)) {
2780 size = 1;
2781 offset = (insn & (1 << 6)) ? 16 : 0;
2782 } else {
2783 size = 2;
2784 offset = 0;
2785 }
balrog18c9b562007-04-30 02:02:17 +00002786 if (insn & ARM_CP_RW_BIT) {
bellardb7bcbe92005-02-22 19:27:29 +00002787 /* vfp->arm */
pbrookad694712008-03-31 03:48:30 +00002788 tmp = neon_load_reg(rn, pass);
pbrook9ee6e8b2007-11-11 00:04:49 +00002789 switch (size) {
2790 case 0:
pbrook9ee6e8b2007-11-11 00:04:49 +00002791 if (offset)
pbrookad694712008-03-31 03:48:30 +00002792 tcg_gen_shri_i32(tmp, tmp, offset);
pbrook9ee6e8b2007-11-11 00:04:49 +00002793 if (insn & (1 << 23))
pbrookad694712008-03-31 03:48:30 +00002794 gen_uxtb(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00002795 else
pbrookad694712008-03-31 03:48:30 +00002796 gen_sxtb(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00002797 break;
2798 case 1:
pbrook9ee6e8b2007-11-11 00:04:49 +00002799 if (insn & (1 << 23)) {
2800 if (offset) {
pbrookad694712008-03-31 03:48:30 +00002801 tcg_gen_shri_i32(tmp, tmp, 16);
pbrook9ee6e8b2007-11-11 00:04:49 +00002802 } else {
pbrookad694712008-03-31 03:48:30 +00002803 gen_uxth(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00002804 }
2805 } else {
2806 if (offset) {
pbrookad694712008-03-31 03:48:30 +00002807 tcg_gen_sari_i32(tmp, tmp, 16);
pbrook9ee6e8b2007-11-11 00:04:49 +00002808 } else {
pbrookad694712008-03-31 03:48:30 +00002809 gen_sxth(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00002810 }
2811 }
2812 break;
2813 case 2:
pbrook9ee6e8b2007-11-11 00:04:49 +00002814 break;
2815 }
pbrookad694712008-03-31 03:48:30 +00002816 store_reg(s, rd, tmp);
bellardb7bcbe92005-02-22 19:27:29 +00002817 } else {
2818 /* arm->vfp */
pbrookad694712008-03-31 03:48:30 +00002819 tmp = load_reg(s, rd);
pbrook9ee6e8b2007-11-11 00:04:49 +00002820 if (insn & (1 << 23)) {
2821 /* VDUP */
2822 if (size == 0) {
pbrookad694712008-03-31 03:48:30 +00002823 gen_neon_dup_u8(tmp, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00002824 } else if (size == 1) {
pbrookad694712008-03-31 03:48:30 +00002825 gen_neon_dup_low16(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00002826 }
pbrookad694712008-03-31 03:48:30 +00002827 tmp2 = new_tmp();
2828 tcg_gen_mov_i32(tmp2, tmp);
2829 neon_store_reg(rn, 0, tmp2);
2830 neon_store_reg(rn, 0, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00002831 } else {
2832 /* VMOV */
2833 switch (size) {
2834 case 0:
pbrookad694712008-03-31 03:48:30 +00002835 tmp2 = neon_load_reg(rn, pass);
2836 gen_bfi(tmp, tmp2, tmp, offset, 0xff);
2837 dead_tmp(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00002838 break;
2839 case 1:
pbrookad694712008-03-31 03:48:30 +00002840 tmp2 = neon_load_reg(rn, pass);
2841 gen_bfi(tmp, tmp2, tmp, offset, 0xffff);
2842 dead_tmp(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00002843 break;
2844 case 2:
pbrook9ee6e8b2007-11-11 00:04:49 +00002845 break;
2846 }
pbrookad694712008-03-31 03:48:30 +00002847 neon_store_reg(rn, pass, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00002848 }
bellardb7bcbe92005-02-22 19:27:29 +00002849 }
pbrook9ee6e8b2007-11-11 00:04:49 +00002850 } else { /* !dp */
2851 if ((insn & 0x6f) != 0x00)
2852 return 1;
2853 rn = VFP_SREG_N(insn);
balrog18c9b562007-04-30 02:02:17 +00002854 if (insn & ARM_CP_RW_BIT) {
bellardb7bcbe92005-02-22 19:27:29 +00002855 /* vfp->arm */
2856 if (insn & (1 << 21)) {
2857 /* system register */
pbrook40f137e2006-02-20 00:33:36 +00002858 rn >>= 1;
pbrook9ee6e8b2007-11-11 00:04:49 +00002859
bellardb7bcbe92005-02-22 19:27:29 +00002860 switch (rn) {
pbrook40f137e2006-02-20 00:33:36 +00002861 case ARM_VFP_FPSID:
pbrook4373f3c2008-03-31 03:47:19 +00002862 /* VFP2 allows access to FSID from userspace.
pbrook9ee6e8b2007-11-11 00:04:49 +00002863 VFP3 restricts all id registers to privileged
2864 accesses. */
2865 if (IS_USER(s)
2866 && arm_feature(env, ARM_FEATURE_VFP3))
2867 return 1;
pbrook4373f3c2008-03-31 03:47:19 +00002868 tmp = load_cpu_field(vfp.xregs[rn]);
pbrook9ee6e8b2007-11-11 00:04:49 +00002869 break;
pbrook40f137e2006-02-20 00:33:36 +00002870 case ARM_VFP_FPEXC:
pbrook9ee6e8b2007-11-11 00:04:49 +00002871 if (IS_USER(s))
2872 return 1;
pbrook4373f3c2008-03-31 03:47:19 +00002873 tmp = load_cpu_field(vfp.xregs[rn]);
pbrook9ee6e8b2007-11-11 00:04:49 +00002874 break;
pbrook40f137e2006-02-20 00:33:36 +00002875 case ARM_VFP_FPINST:
2876 case ARM_VFP_FPINST2:
pbrook9ee6e8b2007-11-11 00:04:49 +00002877 /* Not present in VFP3. */
2878 if (IS_USER(s)
2879 || arm_feature(env, ARM_FEATURE_VFP3))
2880 return 1;
pbrook4373f3c2008-03-31 03:47:19 +00002881 tmp = load_cpu_field(vfp.xregs[rn]);
bellardb7bcbe92005-02-22 19:27:29 +00002882 break;
pbrook40f137e2006-02-20 00:33:36 +00002883 case ARM_VFP_FPSCR:
pbrook4373f3c2008-03-31 03:47:19 +00002884 if (rd == 15) {
2885 tmp = load_cpu_field(vfp.xregs[ARM_VFP_FPSCR]);
2886 tcg_gen_andi_i32(tmp, tmp, 0xf0000000);
2887 } else {
2888 tmp = new_tmp();
2889 gen_helper_vfp_get_fpscr(tmp, cpu_env);
2890 }
bellardb7bcbe92005-02-22 19:27:29 +00002891 break;
pbrook9ee6e8b2007-11-11 00:04:49 +00002892 case ARM_VFP_MVFR0:
2893 case ARM_VFP_MVFR1:
2894 if (IS_USER(s)
2895 || !arm_feature(env, ARM_FEATURE_VFP3))
2896 return 1;
pbrook4373f3c2008-03-31 03:47:19 +00002897 tmp = load_cpu_field(vfp.xregs[rn]);
pbrook9ee6e8b2007-11-11 00:04:49 +00002898 break;
bellardb7bcbe92005-02-22 19:27:29 +00002899 default:
2900 return 1;
2901 }
2902 } else {
2903 gen_mov_F0_vreg(0, rn);
pbrook4373f3c2008-03-31 03:47:19 +00002904 tmp = gen_vfp_mrs();
bellardb7bcbe92005-02-22 19:27:29 +00002905 }
2906 if (rd == 15) {
bellardb5ff1b32005-11-26 10:38:39 +00002907 /* Set the 4 flag bits in the CPSR. */
pbrook4373f3c2008-03-31 03:47:19 +00002908 gen_set_nzcv(tmp);
2909 dead_tmp(tmp);
2910 } else {
2911 store_reg(s, rd, tmp);
2912 }
bellardb7bcbe92005-02-22 19:27:29 +00002913 } else {
2914 /* arm->vfp */
pbrook4373f3c2008-03-31 03:47:19 +00002915 tmp = load_reg(s, rd);
bellardb7bcbe92005-02-22 19:27:29 +00002916 if (insn & (1 << 21)) {
pbrook40f137e2006-02-20 00:33:36 +00002917 rn >>= 1;
bellardb7bcbe92005-02-22 19:27:29 +00002918 /* system register */
2919 switch (rn) {
pbrook40f137e2006-02-20 00:33:36 +00002920 case ARM_VFP_FPSID:
pbrook9ee6e8b2007-11-11 00:04:49 +00002921 case ARM_VFP_MVFR0:
2922 case ARM_VFP_MVFR1:
bellardb7bcbe92005-02-22 19:27:29 +00002923 /* Writes are ignored. */
2924 break;
pbrook40f137e2006-02-20 00:33:36 +00002925 case ARM_VFP_FPSCR:
pbrook4373f3c2008-03-31 03:47:19 +00002926 gen_helper_vfp_set_fpscr(cpu_env, tmp);
2927 dead_tmp(tmp);
bellardb5ff1b32005-11-26 10:38:39 +00002928 gen_lookup_tb(s);
bellardb7bcbe92005-02-22 19:27:29 +00002929 break;
pbrook40f137e2006-02-20 00:33:36 +00002930 case ARM_VFP_FPEXC:
pbrook9ee6e8b2007-11-11 00:04:49 +00002931 if (IS_USER(s))
2932 return 1;
pbrook4373f3c2008-03-31 03:47:19 +00002933 store_cpu_field(tmp, vfp.xregs[rn]);
pbrook40f137e2006-02-20 00:33:36 +00002934 gen_lookup_tb(s);
2935 break;
2936 case ARM_VFP_FPINST:
2937 case ARM_VFP_FPINST2:
pbrook4373f3c2008-03-31 03:47:19 +00002938 store_cpu_field(tmp, vfp.xregs[rn]);
pbrook40f137e2006-02-20 00:33:36 +00002939 break;
bellardb7bcbe92005-02-22 19:27:29 +00002940 default:
2941 return 1;
2942 }
2943 } else {
pbrook4373f3c2008-03-31 03:47:19 +00002944 gen_vfp_msr(tmp);
bellardb7bcbe92005-02-22 19:27:29 +00002945 gen_mov_vreg_F0(0, rn);
2946 }
2947 }
2948 }
2949 } else {
2950 /* data processing */
2951 /* The opcode is in bits 23, 21, 20 and 6. */
2952 op = ((insn >> 20) & 8) | ((insn >> 19) & 6) | ((insn >> 6) & 1);
2953 if (dp) {
2954 if (op == 15) {
2955 /* rn is opcode */
2956 rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1);
2957 } else {
2958 /* rn is register number */
pbrook9ee6e8b2007-11-11 00:04:49 +00002959 VFP_DREG_N(rn, insn);
bellardb7bcbe92005-02-22 19:27:29 +00002960 }
2961
2962 if (op == 15 && (rn == 15 || rn > 17)) {
2963 /* Integer or single precision destination. */
pbrook9ee6e8b2007-11-11 00:04:49 +00002964 rd = VFP_SREG_D(insn);
bellardb7bcbe92005-02-22 19:27:29 +00002965 } else {
pbrook9ee6e8b2007-11-11 00:04:49 +00002966 VFP_DREG_D(rd, insn);
bellardb7bcbe92005-02-22 19:27:29 +00002967 }
2968
2969 if (op == 15 && (rn == 16 || rn == 17)) {
2970 /* Integer source. */
2971 rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1);
2972 } else {
pbrook9ee6e8b2007-11-11 00:04:49 +00002973 VFP_DREG_M(rm, insn);
bellardb7bcbe92005-02-22 19:27:29 +00002974 }
2975 } else {
pbrook9ee6e8b2007-11-11 00:04:49 +00002976 rn = VFP_SREG_N(insn);
bellardb7bcbe92005-02-22 19:27:29 +00002977 if (op == 15 && rn == 15) {
2978 /* Double precision destination. */
pbrook9ee6e8b2007-11-11 00:04:49 +00002979 VFP_DREG_D(rd, insn);
2980 } else {
2981 rd = VFP_SREG_D(insn);
2982 }
2983 rm = VFP_SREG_M(insn);
bellardb7bcbe92005-02-22 19:27:29 +00002984 }
2985
2986 veclen = env->vfp.vec_len;
2987 if (op == 15 && rn > 3)
2988 veclen = 0;
2989
2990 /* Shut up compiler warnings. */
2991 delta_m = 0;
2992 delta_d = 0;
2993 bank_mask = 0;
ths3b46e622007-09-17 08:09:54 +00002994
bellardb7bcbe92005-02-22 19:27:29 +00002995 if (veclen > 0) {
2996 if (dp)
2997 bank_mask = 0xc;
2998 else
2999 bank_mask = 0x18;
3000
3001 /* Figure out what type of vector operation this is. */
3002 if ((rd & bank_mask) == 0) {
3003 /* scalar */
3004 veclen = 0;
3005 } else {
3006 if (dp)
3007 delta_d = (env->vfp.vec_stride >> 1) + 1;
3008 else
3009 delta_d = env->vfp.vec_stride + 1;
3010
3011 if ((rm & bank_mask) == 0) {
3012 /* mixed scalar/vector */
3013 delta_m = 0;
3014 } else {
3015 /* vector */
3016 delta_m = delta_d;
3017 }
3018 }
3019 }
3020
3021 /* Load the initial operands. */
3022 if (op == 15) {
3023 switch (rn) {
3024 case 16:
3025 case 17:
3026 /* Integer source */
3027 gen_mov_F0_vreg(0, rm);
3028 break;
3029 case 8:
3030 case 9:
3031 /* Compare */
3032 gen_mov_F0_vreg(dp, rd);
3033 gen_mov_F1_vreg(dp, rm);
3034 break;
3035 case 10:
3036 case 11:
3037 /* Compare with zero */
3038 gen_mov_F0_vreg(dp, rd);
3039 gen_vfp_F1_ld0(dp);
3040 break;
pbrook9ee6e8b2007-11-11 00:04:49 +00003041 case 20:
3042 case 21:
3043 case 22:
3044 case 23:
3045 /* Source and destination the same. */
3046 gen_mov_F0_vreg(dp, rd);
3047 break;
bellardb7bcbe92005-02-22 19:27:29 +00003048 default:
3049 /* One source operand. */
3050 gen_mov_F0_vreg(dp, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00003051 break;
bellardb7bcbe92005-02-22 19:27:29 +00003052 }
3053 } else {
3054 /* Two source operands. */
3055 gen_mov_F0_vreg(dp, rn);
3056 gen_mov_F1_vreg(dp, rm);
3057 }
3058
3059 for (;;) {
3060 /* Perform the calculation. */
3061 switch (op) {
3062 case 0: /* mac: fd + (fn * fm) */
3063 gen_vfp_mul(dp);
3064 gen_mov_F1_vreg(dp, rd);
3065 gen_vfp_add(dp);
3066 break;
3067 case 1: /* nmac: fd - (fn * fm) */
3068 gen_vfp_mul(dp);
3069 gen_vfp_neg(dp);
3070 gen_mov_F1_vreg(dp, rd);
3071 gen_vfp_add(dp);
3072 break;
3073 case 2: /* msc: -fd + (fn * fm) */
3074 gen_vfp_mul(dp);
3075 gen_mov_F1_vreg(dp, rd);
3076 gen_vfp_sub(dp);
3077 break;
3078 case 3: /* nmsc: -fd - (fn * fm) */
3079 gen_vfp_mul(dp);
3080 gen_mov_F1_vreg(dp, rd);
3081 gen_vfp_add(dp);
3082 gen_vfp_neg(dp);
3083 break;
3084 case 4: /* mul: fn * fm */
3085 gen_vfp_mul(dp);
3086 break;
3087 case 5: /* nmul: -(fn * fm) */
3088 gen_vfp_mul(dp);
3089 gen_vfp_neg(dp);
3090 break;
3091 case 6: /* add: fn + fm */
3092 gen_vfp_add(dp);
3093 break;
3094 case 7: /* sub: fn - fm */
3095 gen_vfp_sub(dp);
3096 break;
3097 case 8: /* div: fn / fm */
3098 gen_vfp_div(dp);
3099 break;
pbrook9ee6e8b2007-11-11 00:04:49 +00003100 case 14: /* fconst */
3101 if (!arm_feature(env, ARM_FEATURE_VFP3))
3102 return 1;
3103
3104 n = (insn << 12) & 0x80000000;
3105 i = ((insn >> 12) & 0x70) | (insn & 0xf);
3106 if (dp) {
3107 if (i & 0x40)
3108 i |= 0x3f80;
3109 else
3110 i |= 0x4000;
3111 n |= i << 16;
pbrook4373f3c2008-03-31 03:47:19 +00003112 tcg_gen_movi_i64(cpu_F0d, ((uint64_t)n) << 32);
pbrook9ee6e8b2007-11-11 00:04:49 +00003113 } else {
3114 if (i & 0x40)
3115 i |= 0x780;
3116 else
3117 i |= 0x800;
3118 n |= i << 19;
pbrook4373f3c2008-03-31 03:47:19 +00003119 tcg_gen_movi_i32(cpu_F0d, ((uint64_t)n) << 32);
pbrook9ee6e8b2007-11-11 00:04:49 +00003120 }
pbrook9ee6e8b2007-11-11 00:04:49 +00003121 break;
bellardb7bcbe92005-02-22 19:27:29 +00003122 case 15: /* extension space */
3123 switch (rn) {
3124 case 0: /* cpy */
3125 /* no-op */
3126 break;
3127 case 1: /* abs */
3128 gen_vfp_abs(dp);
3129 break;
3130 case 2: /* neg */
3131 gen_vfp_neg(dp);
3132 break;
3133 case 3: /* sqrt */
3134 gen_vfp_sqrt(dp);
3135 break;
3136 case 8: /* cmp */
3137 gen_vfp_cmp(dp);
3138 break;
3139 case 9: /* cmpe */
3140 gen_vfp_cmpe(dp);
3141 break;
3142 case 10: /* cmpz */
3143 gen_vfp_cmp(dp);
3144 break;
3145 case 11: /* cmpez */
3146 gen_vfp_F1_ld0(dp);
3147 gen_vfp_cmpe(dp);
3148 break;
3149 case 15: /* single<->double conversion */
3150 if (dp)
pbrook4373f3c2008-03-31 03:47:19 +00003151 gen_helper_vfp_fcvtsd(cpu_F0s, cpu_F0d, cpu_env);
bellardb7bcbe92005-02-22 19:27:29 +00003152 else
pbrook4373f3c2008-03-31 03:47:19 +00003153 gen_helper_vfp_fcvtds(cpu_F0d, cpu_F0s, cpu_env);
bellardb7bcbe92005-02-22 19:27:29 +00003154 break;
3155 case 16: /* fuito */
3156 gen_vfp_uito(dp);
3157 break;
3158 case 17: /* fsito */
3159 gen_vfp_sito(dp);
3160 break;
pbrook9ee6e8b2007-11-11 00:04:49 +00003161 case 20: /* fshto */
3162 if (!arm_feature(env, ARM_FEATURE_VFP3))
3163 return 1;
3164 gen_vfp_shto(dp, rm);
3165 break;
3166 case 21: /* fslto */
3167 if (!arm_feature(env, ARM_FEATURE_VFP3))
3168 return 1;
3169 gen_vfp_slto(dp, rm);
3170 break;
3171 case 22: /* fuhto */
3172 if (!arm_feature(env, ARM_FEATURE_VFP3))
3173 return 1;
3174 gen_vfp_uhto(dp, rm);
3175 break;
3176 case 23: /* fulto */
3177 if (!arm_feature(env, ARM_FEATURE_VFP3))
3178 return 1;
3179 gen_vfp_ulto(dp, rm);
3180 break;
bellardb7bcbe92005-02-22 19:27:29 +00003181 case 24: /* ftoui */
3182 gen_vfp_toui(dp);
3183 break;
3184 case 25: /* ftouiz */
3185 gen_vfp_touiz(dp);
3186 break;
3187 case 26: /* ftosi */
3188 gen_vfp_tosi(dp);
3189 break;
3190 case 27: /* ftosiz */
3191 gen_vfp_tosiz(dp);
3192 break;
pbrook9ee6e8b2007-11-11 00:04:49 +00003193 case 28: /* ftosh */
3194 if (!arm_feature(env, ARM_FEATURE_VFP3))
3195 return 1;
3196 gen_vfp_tosh(dp, rm);
3197 break;
3198 case 29: /* ftosl */
3199 if (!arm_feature(env, ARM_FEATURE_VFP3))
3200 return 1;
3201 gen_vfp_tosl(dp, rm);
3202 break;
3203 case 30: /* ftouh */
3204 if (!arm_feature(env, ARM_FEATURE_VFP3))
3205 return 1;
3206 gen_vfp_touh(dp, rm);
3207 break;
3208 case 31: /* ftoul */
3209 if (!arm_feature(env, ARM_FEATURE_VFP3))
3210 return 1;
3211 gen_vfp_toul(dp, rm);
3212 break;
bellardb7bcbe92005-02-22 19:27:29 +00003213 default: /* undefined */
3214 printf ("rn:%d\n", rn);
3215 return 1;
3216 }
3217 break;
3218 default: /* undefined */
3219 printf ("op:%d\n", op);
3220 return 1;
3221 }
3222
3223 /* Write back the result. */
3224 if (op == 15 && (rn >= 8 && rn <= 11))
3225 ; /* Comparison, do nothing. */
3226 else if (op == 15 && rn > 17)
3227 /* Integer result. */
3228 gen_mov_vreg_F0(0, rd);
3229 else if (op == 15 && rn == 15)
3230 /* conversion */
3231 gen_mov_vreg_F0(!dp, rd);
3232 else
3233 gen_mov_vreg_F0(dp, rd);
3234
3235 /* break out of the loop if we have finished */
3236 if (veclen == 0)
3237 break;
3238
3239 if (op == 15 && delta_m == 0) {
3240 /* single source one-many */
3241 while (veclen--) {
3242 rd = ((rd + delta_d) & (bank_mask - 1))
3243 | (rd & bank_mask);
3244 gen_mov_vreg_F0(dp, rd);
3245 }
3246 break;
3247 }
3248 /* Setup the next operands. */
3249 veclen--;
3250 rd = ((rd + delta_d) & (bank_mask - 1))
3251 | (rd & bank_mask);
3252
3253 if (op == 15) {
3254 /* One source operand. */
3255 rm = ((rm + delta_m) & (bank_mask - 1))
3256 | (rm & bank_mask);
3257 gen_mov_F0_vreg(dp, rm);
3258 } else {
3259 /* Two source operands. */
3260 rn = ((rn + delta_d) & (bank_mask - 1))
3261 | (rn & bank_mask);
3262 gen_mov_F0_vreg(dp, rn);
3263 if (delta_m) {
3264 rm = ((rm + delta_m) & (bank_mask - 1))
3265 | (rm & bank_mask);
3266 gen_mov_F1_vreg(dp, rm);
3267 }
3268 }
3269 }
3270 }
3271 break;
3272 case 0xc:
3273 case 0xd:
pbrook9ee6e8b2007-11-11 00:04:49 +00003274 if (dp && (insn & 0x03e00000) == 0x00400000) {
bellardb7bcbe92005-02-22 19:27:29 +00003275 /* two-register transfer */
3276 rn = (insn >> 16) & 0xf;
3277 rd = (insn >> 12) & 0xf;
3278 if (dp) {
pbrook9ee6e8b2007-11-11 00:04:49 +00003279 VFP_DREG_M(rm, insn);
3280 } else {
3281 rm = VFP_SREG_M(insn);
3282 }
bellardb7bcbe92005-02-22 19:27:29 +00003283
balrog18c9b562007-04-30 02:02:17 +00003284 if (insn & ARM_CP_RW_BIT) {
bellardb7bcbe92005-02-22 19:27:29 +00003285 /* vfp->arm */
3286 if (dp) {
pbrook4373f3c2008-03-31 03:47:19 +00003287 gen_mov_F0_vreg(0, rm * 2);
3288 tmp = gen_vfp_mrs();
3289 store_reg(s, rd, tmp);
3290 gen_mov_F0_vreg(0, rm * 2 + 1);
3291 tmp = gen_vfp_mrs();
3292 store_reg(s, rn, tmp);
bellardb7bcbe92005-02-22 19:27:29 +00003293 } else {
3294 gen_mov_F0_vreg(0, rm);
pbrook4373f3c2008-03-31 03:47:19 +00003295 tmp = gen_vfp_mrs();
3296 store_reg(s, rn, tmp);
bellardb7bcbe92005-02-22 19:27:29 +00003297 gen_mov_F0_vreg(0, rm + 1);
pbrook4373f3c2008-03-31 03:47:19 +00003298 tmp = gen_vfp_mrs();
3299 store_reg(s, rd, tmp);
bellardb7bcbe92005-02-22 19:27:29 +00003300 }
3301 } else {
3302 /* arm->vfp */
3303 if (dp) {
pbrook4373f3c2008-03-31 03:47:19 +00003304 tmp = load_reg(s, rd);
3305 gen_vfp_msr(tmp);
3306 gen_mov_vreg_F0(0, rm * 2);
3307 tmp = load_reg(s, rn);
3308 gen_vfp_msr(tmp);
3309 gen_mov_vreg_F0(0, rm * 2 + 1);
bellardb7bcbe92005-02-22 19:27:29 +00003310 } else {
pbrook4373f3c2008-03-31 03:47:19 +00003311 tmp = load_reg(s, rn);
3312 gen_vfp_msr(tmp);
bellardb7bcbe92005-02-22 19:27:29 +00003313 gen_mov_vreg_F0(0, rm);
pbrook4373f3c2008-03-31 03:47:19 +00003314 tmp = load_reg(s, rd);
3315 gen_vfp_msr(tmp);
bellardb7bcbe92005-02-22 19:27:29 +00003316 gen_mov_vreg_F0(0, rm + 1);
3317 }
3318 }
3319 } else {
3320 /* Load/store */
3321 rn = (insn >> 16) & 0xf;
3322 if (dp)
pbrook9ee6e8b2007-11-11 00:04:49 +00003323 VFP_DREG_D(rd, insn);
bellardb7bcbe92005-02-22 19:27:29 +00003324 else
pbrook9ee6e8b2007-11-11 00:04:49 +00003325 rd = VFP_SREG_D(insn);
3326 if (s->thumb && rn == 15) {
3327 gen_op_movl_T1_im(s->pc & ~2);
3328 } else {
3329 gen_movl_T1_reg(s, rn);
3330 }
bellardb7bcbe92005-02-22 19:27:29 +00003331 if ((insn & 0x01200000) == 0x01000000) {
3332 /* Single load/store */
3333 offset = (insn & 0xff) << 2;
3334 if ((insn & (1 << 23)) == 0)
3335 offset = -offset;
3336 gen_op_addl_T1_im(offset);
3337 if (insn & (1 << 20)) {
bellardb5ff1b32005-11-26 10:38:39 +00003338 gen_vfp_ld(s, dp);
bellardb7bcbe92005-02-22 19:27:29 +00003339 gen_mov_vreg_F0(dp, rd);
3340 } else {
3341 gen_mov_F0_vreg(dp, rd);
bellardb5ff1b32005-11-26 10:38:39 +00003342 gen_vfp_st(s, dp);
bellardb7bcbe92005-02-22 19:27:29 +00003343 }
3344 } else {
3345 /* load/store multiple */
3346 if (dp)
3347 n = (insn >> 1) & 0x7f;
3348 else
3349 n = insn & 0xff;
3350
3351 if (insn & (1 << 24)) /* pre-decrement */
3352 gen_op_addl_T1_im(-((insn & 0xff) << 2));
3353
3354 if (dp)
3355 offset = 8;
3356 else
3357 offset = 4;
3358 for (i = 0; i < n; i++) {
balrog18c9b562007-04-30 02:02:17 +00003359 if (insn & ARM_CP_RW_BIT) {
bellardb7bcbe92005-02-22 19:27:29 +00003360 /* load */
bellardb5ff1b32005-11-26 10:38:39 +00003361 gen_vfp_ld(s, dp);
bellardb7bcbe92005-02-22 19:27:29 +00003362 gen_mov_vreg_F0(dp, rd + i);
3363 } else {
3364 /* store */
3365 gen_mov_F0_vreg(dp, rd + i);
bellardb5ff1b32005-11-26 10:38:39 +00003366 gen_vfp_st(s, dp);
bellardb7bcbe92005-02-22 19:27:29 +00003367 }
3368 gen_op_addl_T1_im(offset);
3369 }
3370 if (insn & (1 << 21)) {
3371 /* writeback */
3372 if (insn & (1 << 24))
3373 offset = -offset * n;
3374 else if (dp && (insn & 1))
3375 offset = 4;
3376 else
3377 offset = 0;
3378
3379 if (offset != 0)
3380 gen_op_addl_T1_im(offset);
3381 gen_movl_reg_T1(s, rn);
3382 }
3383 }
3384 }
3385 break;
3386 default:
3387 /* Should never happen. */
3388 return 1;
3389 }
3390 return 0;
3391}
3392
bellard6e256c92005-11-20 10:32:05 +00003393static inline void gen_goto_tb(DisasContext *s, int n, uint32_t dest)
bellardc53be332005-10-30 21:39:19 +00003394{
bellard6e256c92005-11-20 10:32:05 +00003395 TranslationBlock *tb;
3396
3397 tb = s->tb;
3398 if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
bellard57fec1f2008-02-01 10:50:11 +00003399 tcg_gen_goto_tb(n);
pbrook8984bd22008-03-31 03:47:48 +00003400 gen_set_pc_im(dest);
bellard57fec1f2008-02-01 10:50:11 +00003401 tcg_gen_exit_tb((long)tb + n);
bellard6e256c92005-11-20 10:32:05 +00003402 } else {
pbrook8984bd22008-03-31 03:47:48 +00003403 gen_set_pc_im(dest);
bellard57fec1f2008-02-01 10:50:11 +00003404 tcg_gen_exit_tb(0);
bellard6e256c92005-11-20 10:32:05 +00003405 }
bellardc53be332005-10-30 21:39:19 +00003406}
3407
bellard8aaca4c2005-04-23 18:27:52 +00003408static inline void gen_jmp (DisasContext *s, uint32_t dest)
3409{
3410 if (__builtin_expect(s->singlestep_enabled, 0)) {
3411 /* An indirect jump so that we still trigger the debug exception. */
bellard5899f382005-04-27 20:25:20 +00003412 if (s->thumb)
pbrookd9ba4832008-03-31 03:46:50 +00003413 dest |= 1;
3414 gen_bx_im(s, dest);
bellard8aaca4c2005-04-23 18:27:52 +00003415 } else {
bellard6e256c92005-11-20 10:32:05 +00003416 gen_goto_tb(s, 0, dest);
bellard8aaca4c2005-04-23 18:27:52 +00003417 s->is_jmp = DISAS_TB_JUMP;
3418 }
3419}
3420
pbrookd9ba4832008-03-31 03:46:50 +00003421static inline void gen_mulxy(TCGv t0, TCGv t1, int x, int y)
bellardb5ff1b32005-11-26 10:38:39 +00003422{
bellardee097182005-12-04 18:56:28 +00003423 if (x)
pbrookd9ba4832008-03-31 03:46:50 +00003424 tcg_gen_sari_i32(t0, t0, 16);
bellardb5ff1b32005-11-26 10:38:39 +00003425 else
pbrookd9ba4832008-03-31 03:46:50 +00003426 gen_sxth(t0);
bellardee097182005-12-04 18:56:28 +00003427 if (y)
pbrookd9ba4832008-03-31 03:46:50 +00003428 tcg_gen_sari_i32(t1, t1, 16);
bellardb5ff1b32005-11-26 10:38:39 +00003429 else
pbrookd9ba4832008-03-31 03:46:50 +00003430 gen_sxth(t1);
3431 tcg_gen_mul_i32(t0, t0, t1);
bellardb5ff1b32005-11-26 10:38:39 +00003432}
3433
3434/* Return the mask of PSR bits set by a MSR instruction. */
pbrook9ee6e8b2007-11-11 00:04:49 +00003435static uint32_t msr_mask(CPUState *env, DisasContext *s, int flags, int spsr) {
bellardb5ff1b32005-11-26 10:38:39 +00003436 uint32_t mask;
3437
3438 mask = 0;
3439 if (flags & (1 << 0))
3440 mask |= 0xff;
3441 if (flags & (1 << 1))
3442 mask |= 0xff00;
3443 if (flags & (1 << 2))
3444 mask |= 0xff0000;
3445 if (flags & (1 << 3))
3446 mask |= 0xff000000;
pbrook9ee6e8b2007-11-11 00:04:49 +00003447
pbrook2ae23e72006-02-11 16:20:39 +00003448 /* Mask out undefined bits. */
pbrook9ee6e8b2007-11-11 00:04:49 +00003449 mask &= ~CPSR_RESERVED;
3450 if (!arm_feature(env, ARM_FEATURE_V6))
pbrooke160c512007-11-11 14:36:36 +00003451 mask &= ~(CPSR_E | CPSR_GE);
pbrook9ee6e8b2007-11-11 00:04:49 +00003452 if (!arm_feature(env, ARM_FEATURE_THUMB2))
pbrooke160c512007-11-11 14:36:36 +00003453 mask &= ~CPSR_IT;
pbrook9ee6e8b2007-11-11 00:04:49 +00003454 /* Mask out execution state bits. */
pbrook2ae23e72006-02-11 16:20:39 +00003455 if (!spsr)
pbrooke160c512007-11-11 14:36:36 +00003456 mask &= ~CPSR_EXEC;
bellardb5ff1b32005-11-26 10:38:39 +00003457 /* Mask out privileged bits. */
3458 if (IS_USER(s))
pbrook9ee6e8b2007-11-11 00:04:49 +00003459 mask &= CPSR_USER;
bellardb5ff1b32005-11-26 10:38:39 +00003460 return mask;
3461}
3462
3463/* Returns nonzero if access to the PSR is not permitted. */
3464static int gen_set_psr_T0(DisasContext *s, uint32_t mask, int spsr)
3465{
pbrookd9ba4832008-03-31 03:46:50 +00003466 TCGv tmp;
bellardb5ff1b32005-11-26 10:38:39 +00003467 if (spsr) {
3468 /* ??? This is also undefined in system mode. */
3469 if (IS_USER(s))
3470 return 1;
pbrookd9ba4832008-03-31 03:46:50 +00003471
3472 tmp = load_cpu_field(spsr);
3473 tcg_gen_andi_i32(tmp, tmp, ~mask);
3474 tcg_gen_andi_i32(cpu_T[0], cpu_T[0], mask);
3475 tcg_gen_or_i32(tmp, tmp, cpu_T[0]);
3476 store_cpu_field(tmp, spsr);
bellardb5ff1b32005-11-26 10:38:39 +00003477 } else {
pbrookd9ba4832008-03-31 03:46:50 +00003478 gen_set_cpsr(cpu_T[0], mask);
bellardb5ff1b32005-11-26 10:38:39 +00003479 }
3480 gen_lookup_tb(s);
3481 return 0;
3482}
3483
pbrook9ee6e8b2007-11-11 00:04:49 +00003484/* Generate an old-style exception return. */
bellardb5ff1b32005-11-26 10:38:39 +00003485static void gen_exception_return(DisasContext *s)
3486{
pbrookd9ba4832008-03-31 03:46:50 +00003487 TCGv tmp;
pbrookb26eefb2008-03-31 03:44:26 +00003488 gen_set_pc_T0();
pbrookd9ba4832008-03-31 03:46:50 +00003489 tmp = load_cpu_field(spsr);
3490 gen_set_cpsr(tmp, 0xffffffff);
3491 dead_tmp(tmp);
bellardb5ff1b32005-11-26 10:38:39 +00003492 s->is_jmp = DISAS_UPDATE;
3493}
3494
pbrookb0109802008-03-31 03:47:03 +00003495/* Generate a v6 exception return. Marks both values as dead. */
3496static void gen_rfe(DisasContext *s, TCGv pc, TCGv cpsr)
pbrook9ee6e8b2007-11-11 00:04:49 +00003497{
pbrookb0109802008-03-31 03:47:03 +00003498 gen_set_cpsr(cpsr, 0xffffffff);
3499 dead_tmp(cpsr);
3500 store_reg(s, 15, pc);
pbrook9ee6e8b2007-11-11 00:04:49 +00003501 s->is_jmp = DISAS_UPDATE;
3502}
3503
3504static inline void
3505gen_set_condexec (DisasContext *s)
3506{
3507 if (s->condexec_mask) {
pbrook8f012452008-03-31 03:46:03 +00003508 uint32_t val = (s->condexec_cond << 4) | (s->condexec_mask >> 1);
3509 TCGv tmp = new_tmp();
3510 tcg_gen_movi_i32(tmp, val);
pbrookd9ba4832008-03-31 03:46:50 +00003511 store_cpu_field(tmp, condexec_bits);
pbrook9ee6e8b2007-11-11 00:04:49 +00003512 }
3513}
3514
3515static void gen_nop_hint(DisasContext *s, int val)
3516{
3517 switch (val) {
3518 case 3: /* wfi */
pbrook8984bd22008-03-31 03:47:48 +00003519 gen_set_pc_im(s->pc);
pbrook9ee6e8b2007-11-11 00:04:49 +00003520 s->is_jmp = DISAS_WFI;
3521 break;
3522 case 2: /* wfe */
3523 case 4: /* sev */
3524 /* TODO: Implement SEV and WFE. May help SMP performance. */
3525 default: /* nop */
3526 break;
3527 }
3528}
3529
pbrookad694712008-03-31 03:48:30 +00003530/* These macros help make the code more readable when migrating from the
3531 old dyngen helpers. They should probably be removed when
3532 T0/T1 are removed. */
3533#define CPU_T001 cpu_T[0], cpu_T[0], cpu_T[1]
3534#define CPU_T0E01 cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]
pbrook9ee6e8b2007-11-11 00:04:49 +00003535
pbrookad694712008-03-31 03:48:30 +00003536#define CPU_V001 cpu_V0, cpu_V0, cpu_V1
pbrook9ee6e8b2007-11-11 00:04:49 +00003537
3538static inline int gen_neon_add(int size)
3539{
3540 switch (size) {
pbrookad694712008-03-31 03:48:30 +00003541 case 0: gen_helper_neon_add_u8(CPU_T001); break;
3542 case 1: gen_helper_neon_add_u16(CPU_T001); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00003543 case 2: gen_op_addl_T0_T1(); break;
3544 default: return 1;
3545 }
3546 return 0;
3547}
3548
pbrookad694712008-03-31 03:48:30 +00003549static inline void gen_neon_rsb(int size)
3550{
3551 switch (size) {
3552 case 0: gen_helper_neon_sub_u8(cpu_T[0], cpu_T[1], cpu_T[0]); break;
3553 case 1: gen_helper_neon_sub_u16(cpu_T[0], cpu_T[1], cpu_T[0]); break;
3554 case 2: gen_op_rsbl_T0_T1(); break;
3555 default: return;
3556 }
3557}
3558
3559/* 32-bit pairwise ops end up the same as the elementwise versions. */
3560#define gen_helper_neon_pmax_s32 gen_helper_neon_max_s32
3561#define gen_helper_neon_pmax_u32 gen_helper_neon_max_u32
3562#define gen_helper_neon_pmin_s32 gen_helper_neon_min_s32
3563#define gen_helper_neon_pmin_u32 gen_helper_neon_min_u32
3564
3565/* FIXME: This is wrong. They set the wrong overflow bit. */
3566#define gen_helper_neon_qadd_s32(a, e, b, c) gen_helper_add_saturate(a, b, c)
3567#define gen_helper_neon_qadd_u32(a, e, b, c) gen_helper_add_usaturate(a, b, c)
3568#define gen_helper_neon_qsub_s32(a, e, b, c) gen_helper_sub_saturate(a, b, c)
3569#define gen_helper_neon_qsub_u32(a, e, b, c) gen_helper_sub_usaturate(a, b, c)
3570
3571#define GEN_NEON_INTEGER_OP_ENV(name) do { \
3572 switch ((size << 1) | u) { \
3573 case 0: \
3574 gen_helper_neon_##name##_s8(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]); \
3575 break; \
3576 case 1: \
3577 gen_helper_neon_##name##_u8(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]); \
3578 break; \
3579 case 2: \
3580 gen_helper_neon_##name##_s16(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]); \
3581 break; \
3582 case 3: \
3583 gen_helper_neon_##name##_u16(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]); \
3584 break; \
3585 case 4: \
3586 gen_helper_neon_##name##_s32(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]); \
3587 break; \
3588 case 5: \
3589 gen_helper_neon_##name##_u32(cpu_T[0], cpu_env, cpu_T[0], cpu_T[1]); \
3590 break; \
3591 default: return 1; \
3592 }} while (0)
pbrook9ee6e8b2007-11-11 00:04:49 +00003593
3594#define GEN_NEON_INTEGER_OP(name) do { \
3595 switch ((size << 1) | u) { \
pbrookad694712008-03-31 03:48:30 +00003596 case 0: \
3597 gen_helper_neon_##name##_s8(cpu_T[0], cpu_T[0], cpu_T[1]); \
3598 break; \
3599 case 1: \
3600 gen_helper_neon_##name##_u8(cpu_T[0], cpu_T[0], cpu_T[1]); \
3601 break; \
3602 case 2: \
3603 gen_helper_neon_##name##_s16(cpu_T[0], cpu_T[0], cpu_T[1]); \
3604 break; \
3605 case 3: \
3606 gen_helper_neon_##name##_u16(cpu_T[0], cpu_T[0], cpu_T[1]); \
3607 break; \
3608 case 4: \
3609 gen_helper_neon_##name##_s32(cpu_T[0], cpu_T[0], cpu_T[1]); \
3610 break; \
3611 case 5: \
3612 gen_helper_neon_##name##_u32(cpu_T[0], cpu_T[0], cpu_T[1]); \
3613 break; \
pbrook9ee6e8b2007-11-11 00:04:49 +00003614 default: return 1; \
3615 }} while (0)
3616
3617static inline void
3618gen_neon_movl_scratch_T0(int scratch)
3619{
3620 uint32_t offset;
3621
3622 offset = offsetof(CPUARMState, vfp.scratch[scratch]);
pbrookad694712008-03-31 03:48:30 +00003623 tcg_gen_st_i32(cpu_T[0], cpu_env, offset);
pbrook9ee6e8b2007-11-11 00:04:49 +00003624}
3625
3626static inline void
3627gen_neon_movl_scratch_T1(int scratch)
3628{
3629 uint32_t offset;
3630
3631 offset = offsetof(CPUARMState, vfp.scratch[scratch]);
pbrookad694712008-03-31 03:48:30 +00003632 tcg_gen_st_i32(cpu_T[1], cpu_env, offset);
pbrook9ee6e8b2007-11-11 00:04:49 +00003633}
3634
3635static inline void
3636gen_neon_movl_T0_scratch(int scratch)
3637{
3638 uint32_t offset;
3639
3640 offset = offsetof(CPUARMState, vfp.scratch[scratch]);
pbrookad694712008-03-31 03:48:30 +00003641 tcg_gen_ld_i32(cpu_T[0], cpu_env, offset);
pbrook9ee6e8b2007-11-11 00:04:49 +00003642}
3643
3644static inline void
3645gen_neon_movl_T1_scratch(int scratch)
3646{
3647 uint32_t offset;
3648
3649 offset = offsetof(CPUARMState, vfp.scratch[scratch]);
pbrookad694712008-03-31 03:48:30 +00003650 tcg_gen_ld_i32(cpu_T[1], cpu_env, offset);
pbrook9ee6e8b2007-11-11 00:04:49 +00003651}
3652
3653static inline void gen_neon_get_scalar(int size, int reg)
3654{
3655 if (size == 1) {
3656 NEON_GET_REG(T0, reg >> 1, reg & 1);
3657 } else {
3658 NEON_GET_REG(T0, reg >> 2, (reg >> 1) & 1);
3659 if (reg & 1)
pbrookad694712008-03-31 03:48:30 +00003660 gen_neon_dup_low16(cpu_T[0]);
pbrook9ee6e8b2007-11-11 00:04:49 +00003661 else
pbrookad694712008-03-31 03:48:30 +00003662 gen_neon_dup_high16(cpu_T[0]);
pbrook9ee6e8b2007-11-11 00:04:49 +00003663 }
3664}
3665
3666static void gen_neon_unzip(int reg, int q, int tmp, int size)
3667{
3668 int n;
3669
3670 for (n = 0; n < q + 1; n += 2) {
3671 NEON_GET_REG(T0, reg, n);
3672 NEON_GET_REG(T0, reg, n + n);
3673 switch (size) {
pbrookad694712008-03-31 03:48:30 +00003674 case 0: gen_helper_neon_unzip_u8(); break;
3675 case 1: gen_helper_neon_zip_u16(); break; /* zip and unzip are the same. */
pbrook9ee6e8b2007-11-11 00:04:49 +00003676 case 2: /* no-op */; break;
3677 default: abort();
3678 }
3679 gen_neon_movl_scratch_T0(tmp + n);
3680 gen_neon_movl_scratch_T1(tmp + n + 1);
3681 }
3682}
3683
3684static struct {
3685 int nregs;
3686 int interleave;
3687 int spacing;
3688} neon_ls_element_type[11] = {
3689 {4, 4, 1},
3690 {4, 4, 2},
3691 {4, 1, 1},
3692 {4, 2, 1},
3693 {3, 3, 1},
3694 {3, 3, 2},
3695 {3, 1, 1},
3696 {1, 1, 1},
3697 {2, 2, 1},
3698 {2, 2, 2},
3699 {2, 1, 1}
3700};
3701
3702/* Translate a NEON load/store element instruction. Return nonzero if the
3703 instruction is invalid. */
3704static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn)
3705{
3706 int rd, rn, rm;
3707 int op;
3708 int nregs;
3709 int interleave;
3710 int stride;
3711 int size;
3712 int reg;
3713 int pass;
3714 int load;
3715 int shift;
pbrook9ee6e8b2007-11-11 00:04:49 +00003716 int n;
pbrookb0109802008-03-31 03:47:03 +00003717 TCGv tmp;
pbrook8f8e3aa2008-03-31 03:48:01 +00003718 TCGv tmp2;
pbrook9ee6e8b2007-11-11 00:04:49 +00003719
3720 if (!vfp_enabled(env))
3721 return 1;
3722 VFP_DREG_D(rd, insn);
3723 rn = (insn >> 16) & 0xf;
3724 rm = insn & 0xf;
3725 load = (insn & (1 << 21)) != 0;
3726 if ((insn & (1 << 23)) == 0) {
3727 /* Load store all elements. */
3728 op = (insn >> 8) & 0xf;
3729 size = (insn >> 6) & 3;
3730 if (op > 10 || size == 3)
3731 return 1;
3732 nregs = neon_ls_element_type[op].nregs;
3733 interleave = neon_ls_element_type[op].interleave;
3734 gen_movl_T1_reg(s, rn);
3735 stride = (1 << size) * interleave;
3736 for (reg = 0; reg < nregs; reg++) {
3737 if (interleave > 2 || (interleave == 2 && nregs == 2)) {
3738 gen_movl_T1_reg(s, rn);
3739 gen_op_addl_T1_im((1 << size) * reg);
3740 } else if (interleave == 2 && nregs == 4 && reg == 2) {
3741 gen_movl_T1_reg(s, rn);
3742 gen_op_addl_T1_im(1 << size);
3743 }
3744 for (pass = 0; pass < 2; pass++) {
3745 if (size == 2) {
3746 if (load) {
pbrookb0109802008-03-31 03:47:03 +00003747 tmp = gen_ld32(cpu_T[1], IS_USER(s));
pbrookad694712008-03-31 03:48:30 +00003748 neon_store_reg(rd, pass, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00003749 } else {
pbrookad694712008-03-31 03:48:30 +00003750 tmp = neon_load_reg(rd, pass);
pbrookb0109802008-03-31 03:47:03 +00003751 gen_st32(tmp, cpu_T[1], IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00003752 }
3753 gen_op_addl_T1_im(stride);
3754 } else if (size == 1) {
3755 if (load) {
pbrookb0109802008-03-31 03:47:03 +00003756 tmp = gen_ld16u(cpu_T[1], IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00003757 gen_op_addl_T1_im(stride);
pbrook8f8e3aa2008-03-31 03:48:01 +00003758 tmp2 = gen_ld16u(cpu_T[1], IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00003759 gen_op_addl_T1_im(stride);
pbrook8f8e3aa2008-03-31 03:48:01 +00003760 gen_bfi(tmp, tmp, tmp2, 16, 0xffff);
3761 dead_tmp(tmp2);
3762 neon_store_reg(rd, pass, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00003763 } else {
pbrook8f8e3aa2008-03-31 03:48:01 +00003764 tmp = neon_load_reg(rd, pass);
3765 tmp2 = new_tmp();
3766 tcg_gen_shri_i32(tmp2, tmp, 16);
pbrookb0109802008-03-31 03:47:03 +00003767 gen_st16(tmp, cpu_T[1], IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00003768 gen_op_addl_T1_im(stride);
pbrook8f8e3aa2008-03-31 03:48:01 +00003769 gen_st16(tmp2, cpu_T[1], IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00003770 gen_op_addl_T1_im(stride);
3771 }
3772 } else /* size == 0 */ {
3773 if (load) {
pbrook9ee6e8b2007-11-11 00:04:49 +00003774 for (n = 0; n < 4; n++) {
pbrookb0109802008-03-31 03:47:03 +00003775 tmp = gen_ld8u(cpu_T[1], IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00003776 gen_op_addl_T1_im(stride);
3777 if (n == 0) {
pbrook8f8e3aa2008-03-31 03:48:01 +00003778 tmp2 = tmp;
pbrook9ee6e8b2007-11-11 00:04:49 +00003779 } else {
pbrook8f8e3aa2008-03-31 03:48:01 +00003780 gen_bfi(tmp2, tmp2, tmp, n * 8, 0xff);
3781 dead_tmp(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00003782 }
pbrook9ee6e8b2007-11-11 00:04:49 +00003783 }
pbrook8f8e3aa2008-03-31 03:48:01 +00003784 neon_store_reg(rd, pass, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00003785 } else {
pbrook8f8e3aa2008-03-31 03:48:01 +00003786 tmp2 = neon_load_reg(rd, pass);
pbrook9ee6e8b2007-11-11 00:04:49 +00003787 for (n = 0; n < 4; n++) {
pbrookb0109802008-03-31 03:47:03 +00003788 tmp = new_tmp();
pbrook8f8e3aa2008-03-31 03:48:01 +00003789 if (n == 0) {
3790 tcg_gen_mov_i32(tmp, tmp2);
3791 } else {
3792 tcg_gen_shri_i32(tmp, tmp2, n * 8);
3793 }
pbrookb0109802008-03-31 03:47:03 +00003794 gen_st8(tmp, cpu_T[1], IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00003795 gen_op_addl_T1_im(stride);
pbrook9ee6e8b2007-11-11 00:04:49 +00003796 }
pbrook8f8e3aa2008-03-31 03:48:01 +00003797 dead_tmp(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00003798 }
3799 }
3800 }
3801 rd += neon_ls_element_type[op].spacing;
3802 }
3803 stride = nregs * 8;
3804 } else {
3805 size = (insn >> 10) & 3;
3806 if (size == 3) {
3807 /* Load single element to all lanes. */
3808 if (!load)
3809 return 1;
3810 size = (insn >> 6) & 3;
3811 nregs = ((insn >> 8) & 3) + 1;
3812 stride = (insn & (1 << 5)) ? 2 : 1;
3813 gen_movl_T1_reg(s, rn);
3814 for (reg = 0; reg < nregs; reg++) {
3815 switch (size) {
3816 case 0:
pbrookb0109802008-03-31 03:47:03 +00003817 tmp = gen_ld8u(cpu_T[1], IS_USER(s));
pbrookad694712008-03-31 03:48:30 +00003818 gen_neon_dup_u8(tmp, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00003819 break;
3820 case 1:
pbrookb0109802008-03-31 03:47:03 +00003821 tmp = gen_ld16u(cpu_T[1], IS_USER(s));
pbrookad694712008-03-31 03:48:30 +00003822 gen_neon_dup_low16(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00003823 break;
3824 case 2:
pbrookb0109802008-03-31 03:47:03 +00003825 tmp = gen_ld32(cpu_T[0], IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00003826 break;
3827 case 3:
3828 return 1;
3829 }
3830 gen_op_addl_T1_im(1 << size);
pbrookad694712008-03-31 03:48:30 +00003831 tmp2 = new_tmp();
3832 tcg_gen_mov_i32(tmp2, tmp);
3833 neon_store_reg(rd, 0, tmp2);
3834 neon_store_reg(rd, 0, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00003835 rd += stride;
3836 }
3837 stride = (1 << size) * nregs;
3838 } else {
3839 /* Single element. */
3840 pass = (insn >> 7) & 1;
3841 switch (size) {
3842 case 0:
3843 shift = ((insn >> 5) & 3) * 8;
pbrook9ee6e8b2007-11-11 00:04:49 +00003844 stride = 1;
3845 break;
3846 case 1:
3847 shift = ((insn >> 6) & 1) * 16;
pbrook9ee6e8b2007-11-11 00:04:49 +00003848 stride = (insn & (1 << 5)) ? 2 : 1;
3849 break;
3850 case 2:
3851 shift = 0;
pbrook9ee6e8b2007-11-11 00:04:49 +00003852 stride = (insn & (1 << 6)) ? 2 : 1;
3853 break;
3854 default:
3855 abort();
3856 }
3857 nregs = ((insn >> 8) & 3) + 1;
3858 gen_movl_T1_reg(s, rn);
3859 for (reg = 0; reg < nregs; reg++) {
3860 if (load) {
pbrook9ee6e8b2007-11-11 00:04:49 +00003861 switch (size) {
3862 case 0:
pbrookb0109802008-03-31 03:47:03 +00003863 tmp = gen_ld8u(cpu_T[1], IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00003864 break;
3865 case 1:
pbrookb0109802008-03-31 03:47:03 +00003866 tmp = gen_ld16u(cpu_T[1], IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00003867 break;
3868 case 2:
pbrookb0109802008-03-31 03:47:03 +00003869 tmp = gen_ld32(cpu_T[1], IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00003870 break;
3871 }
3872 if (size != 2) {
pbrook8f8e3aa2008-03-31 03:48:01 +00003873 tmp2 = neon_load_reg(rd, pass);
3874 gen_bfi(tmp, tmp2, tmp, shift, size ? 0xffff : 0xff);
3875 dead_tmp(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00003876 }
pbrook8f8e3aa2008-03-31 03:48:01 +00003877 neon_store_reg(rd, pass, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00003878 } else { /* Store */
pbrook8f8e3aa2008-03-31 03:48:01 +00003879 tmp = neon_load_reg(rd, pass);
3880 if (shift)
3881 tcg_gen_shri_i32(tmp, tmp, shift);
pbrook9ee6e8b2007-11-11 00:04:49 +00003882 switch (size) {
3883 case 0:
pbrookb0109802008-03-31 03:47:03 +00003884 gen_st8(tmp, cpu_T[1], IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00003885 break;
3886 case 1:
pbrookb0109802008-03-31 03:47:03 +00003887 gen_st16(tmp, cpu_T[1], IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00003888 break;
3889 case 2:
pbrookb0109802008-03-31 03:47:03 +00003890 gen_st32(tmp, cpu_T[1], IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00003891 break;
3892 }
3893 }
3894 rd += stride;
3895 gen_op_addl_T1_im(1 << size);
3896 }
3897 stride = nregs * (1 << size);
3898 }
3899 }
3900 if (rm != 15) {
pbrookb26eefb2008-03-31 03:44:26 +00003901 TCGv base;
3902
3903 base = load_reg(s, rn);
pbrook9ee6e8b2007-11-11 00:04:49 +00003904 if (rm == 13) {
pbrookb26eefb2008-03-31 03:44:26 +00003905 tcg_gen_addi_i32(base, base, stride);
pbrook9ee6e8b2007-11-11 00:04:49 +00003906 } else {
pbrookb26eefb2008-03-31 03:44:26 +00003907 TCGv index;
3908 index = load_reg(s, rm);
3909 tcg_gen_add_i32(base, base, index);
3910 dead_tmp(index);
pbrook9ee6e8b2007-11-11 00:04:49 +00003911 }
pbrookb26eefb2008-03-31 03:44:26 +00003912 store_reg(s, rn, base);
pbrook9ee6e8b2007-11-11 00:04:49 +00003913 }
3914 return 0;
3915}
3916
pbrook8f8e3aa2008-03-31 03:48:01 +00003917/* Bitwise select. dest = c ? t : f. Clobbers T and F. */
3918static void gen_neon_bsl(TCGv dest, TCGv t, TCGv f, TCGv c)
3919{
3920 tcg_gen_and_i32(t, t, c);
3921 tcg_gen_bic_i32(f, f, c);
3922 tcg_gen_or_i32(dest, t, f);
3923}
3924
pbrookad694712008-03-31 03:48:30 +00003925static inline void gen_neon_narrow(int size, TCGv dest, TCGv src)
3926{
3927 switch (size) {
3928 case 0: gen_helper_neon_narrow_u8(dest, src); break;
3929 case 1: gen_helper_neon_narrow_u16(dest, src); break;
3930 case 2: tcg_gen_trunc_i64_i32(dest, src); break;
3931 default: abort();
3932 }
3933}
3934
3935static inline void gen_neon_narrow_sats(int size, TCGv dest, TCGv src)
3936{
3937 switch (size) {
3938 case 0: gen_helper_neon_narrow_sat_s8(dest, cpu_env, src); break;
3939 case 1: gen_helper_neon_narrow_sat_s16(dest, cpu_env, src); break;
3940 case 2: gen_helper_neon_narrow_sat_s32(dest, cpu_env, src); break;
3941 default: abort();
3942 }
3943}
3944
3945static inline void gen_neon_narrow_satu(int size, TCGv dest, TCGv src)
3946{
3947 switch (size) {
3948 case 0: gen_helper_neon_narrow_sat_u8(dest, cpu_env, src); break;
3949 case 1: gen_helper_neon_narrow_sat_u16(dest, cpu_env, src); break;
3950 case 2: gen_helper_neon_narrow_sat_u32(dest, cpu_env, src); break;
3951 default: abort();
3952 }
3953}
3954
3955static inline void gen_neon_shift_narrow(int size, TCGv var, TCGv shift,
3956 int q, int u)
3957{
3958 if (q) {
3959 if (u) {
3960 switch (size) {
3961 case 1: gen_helper_neon_rshl_u16(var, var, shift); break;
3962 case 2: gen_helper_neon_rshl_u32(var, var, shift); break;
3963 default: abort();
3964 }
3965 } else {
3966 switch (size) {
3967 case 1: gen_helper_neon_rshl_s16(var, var, shift); break;
3968 case 2: gen_helper_neon_rshl_s32(var, var, shift); break;
3969 default: abort();
3970 }
3971 }
3972 } else {
3973 if (u) {
3974 switch (size) {
3975 case 1: gen_helper_neon_rshl_u16(var, var, shift); break;
3976 case 2: gen_helper_neon_rshl_u32(var, var, shift); break;
3977 default: abort();
3978 }
3979 } else {
3980 switch (size) {
3981 case 1: gen_helper_neon_shl_s16(var, var, shift); break;
3982 case 2: gen_helper_neon_shl_s32(var, var, shift); break;
3983 default: abort();
3984 }
3985 }
3986 }
3987}
3988
3989static inline void gen_neon_widen(TCGv dest, TCGv src, int size, int u)
3990{
3991 if (u) {
3992 switch (size) {
3993 case 0: gen_helper_neon_widen_u8(dest, src); break;
3994 case 1: gen_helper_neon_widen_u16(dest, src); break;
3995 case 2: tcg_gen_extu_i32_i64(dest, src); break;
3996 default: abort();
3997 }
3998 } else {
3999 switch (size) {
4000 case 0: gen_helper_neon_widen_s8(dest, src); break;
4001 case 1: gen_helper_neon_widen_s16(dest, src); break;
4002 case 2: tcg_gen_ext_i32_i64(dest, src); break;
4003 default: abort();
4004 }
4005 }
4006 dead_tmp(src);
4007}
4008
4009static inline void gen_neon_addl(int size)
4010{
4011 switch (size) {
4012 case 0: gen_helper_neon_addl_u16(CPU_V001); break;
4013 case 1: gen_helper_neon_addl_u32(CPU_V001); break;
4014 case 2: tcg_gen_add_i64(CPU_V001); break;
4015 default: abort();
4016 }
4017}
4018
4019static inline void gen_neon_subl(int size)
4020{
4021 switch (size) {
4022 case 0: gen_helper_neon_subl_u16(CPU_V001); break;
4023 case 1: gen_helper_neon_subl_u32(CPU_V001); break;
4024 case 2: tcg_gen_sub_i64(CPU_V001); break;
4025 default: abort();
4026 }
4027}
4028
4029static inline void gen_neon_negl(TCGv var, int size)
4030{
4031 switch (size) {
4032 case 0: gen_helper_neon_negl_u16(var, var); break;
4033 case 1: gen_helper_neon_negl_u32(var, var); break;
4034 case 2: gen_helper_neon_negl_u64(var, var); break;
4035 default: abort();
4036 }
4037}
4038
4039static inline void gen_neon_addl_saturate(TCGv op0, TCGv op1, int size)
4040{
4041 switch (size) {
4042 case 1: gen_helper_neon_addl_saturate_s32(op0, cpu_env, op0, op1); break;
4043 case 2: gen_helper_neon_addl_saturate_s64(op0, cpu_env, op0, op1); break;
4044 default: abort();
4045 }
4046}
4047
4048static inline void gen_neon_mull(TCGv dest, TCGv a, TCGv b, int size, int u)
4049{
4050 TCGv tmp;
4051
4052 switch ((size << 1) | u) {
4053 case 0: gen_helper_neon_mull_s8(dest, a, b); break;
4054 case 1: gen_helper_neon_mull_u8(dest, a, b); break;
4055 case 2: gen_helper_neon_mull_s16(dest, a, b); break;
4056 case 3: gen_helper_neon_mull_u16(dest, a, b); break;
4057 case 4:
4058 tmp = gen_muls_i64_i32(a, b);
4059 tcg_gen_mov_i64(dest, tmp);
4060 break;
4061 case 5:
4062 tmp = gen_mulu_i64_i32(a, b);
4063 tcg_gen_mov_i64(dest, tmp);
4064 break;
4065 default: abort();
4066 }
4067 if (size < 2) {
4068 dead_tmp(b);
4069 dead_tmp(a);
4070 }
4071}
4072
pbrook9ee6e8b2007-11-11 00:04:49 +00004073/* Translate a NEON data processing instruction. Return nonzero if the
4074 instruction is invalid.
pbrookad694712008-03-31 03:48:30 +00004075 We process data in a mixture of 32-bit and 64-bit chunks.
4076 Mostly we use 32-bit chunks so we can use normal scalar instructions. */
pbrook9ee6e8b2007-11-11 00:04:49 +00004077
4078static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
4079{
4080 int op;
4081 int q;
4082 int rd, rn, rm;
4083 int size;
4084 int shift;
4085 int pass;
4086 int count;
4087 int pairwise;
4088 int u;
4089 int n;
4090 uint32_t imm;
pbrook8f8e3aa2008-03-31 03:48:01 +00004091 TCGv tmp;
4092 TCGv tmp2;
4093 TCGv tmp3;
pbrook9ee6e8b2007-11-11 00:04:49 +00004094
4095 if (!vfp_enabled(env))
4096 return 1;
4097 q = (insn & (1 << 6)) != 0;
4098 u = (insn >> 24) & 1;
4099 VFP_DREG_D(rd, insn);
4100 VFP_DREG_N(rn, insn);
4101 VFP_DREG_M(rm, insn);
4102 size = (insn >> 20) & 3;
4103 if ((insn & (1 << 23)) == 0) {
4104 /* Three register same length. */
4105 op = ((insn >> 7) & 0x1e) | ((insn >> 4) & 1);
pbrookad694712008-03-31 03:48:30 +00004106 if (size == 3 && (op == 1 || op == 5 || op == 8 || op == 9
4107 || op == 10 || op == 11 || op == 16)) {
4108 /* 64-bit element instructions. */
pbrook9ee6e8b2007-11-11 00:04:49 +00004109 for (pass = 0; pass < (q ? 2 : 1); pass++) {
pbrookad694712008-03-31 03:48:30 +00004110 neon_load_reg64(cpu_V0, rn + pass);
4111 neon_load_reg64(cpu_V1, rm + pass);
pbrook9ee6e8b2007-11-11 00:04:49 +00004112 switch (op) {
4113 case 1: /* VQADD */
4114 if (u) {
pbrookad694712008-03-31 03:48:30 +00004115 gen_helper_neon_add_saturate_u64(CPU_V001);
pbrook9ee6e8b2007-11-11 00:04:49 +00004116 } else {
pbrookad694712008-03-31 03:48:30 +00004117 gen_helper_neon_add_saturate_s64(CPU_V001);
pbrook9ee6e8b2007-11-11 00:04:49 +00004118 }
4119 break;
4120 case 5: /* VQSUB */
4121 if (u) {
pbrookad694712008-03-31 03:48:30 +00004122 gen_helper_neon_sub_saturate_u64(CPU_V001);
pbrook9ee6e8b2007-11-11 00:04:49 +00004123 } else {
pbrookad694712008-03-31 03:48:30 +00004124 gen_helper_neon_sub_saturate_s64(CPU_V001);
4125 }
4126 break;
4127 case 8: /* VSHL */
4128 if (u) {
4129 gen_helper_neon_shl_u64(cpu_V0, cpu_V1, cpu_V0);
4130 } else {
4131 gen_helper_neon_shl_s64(cpu_V0, cpu_V1, cpu_V0);
4132 }
4133 break;
4134 case 9: /* VQSHL */
4135 if (u) {
4136 gen_helper_neon_qshl_u64(cpu_V0, cpu_env,
4137 cpu_V0, cpu_V0);
4138 } else {
4139 gen_helper_neon_qshl_s64(cpu_V1, cpu_env,
4140 cpu_V1, cpu_V0);
4141 }
4142 break;
4143 case 10: /* VRSHL */
4144 if (u) {
4145 gen_helper_neon_rshl_u64(cpu_V0, cpu_V1, cpu_V0);
4146 } else {
4147 gen_helper_neon_rshl_s64(cpu_V0, cpu_V1, cpu_V0);
4148 }
4149 break;
4150 case 11: /* VQRSHL */
4151 if (u) {
4152 gen_helper_neon_qrshl_u64(cpu_V0, cpu_env,
4153 cpu_V1, cpu_V0);
4154 } else {
4155 gen_helper_neon_qrshl_s64(cpu_V0, cpu_env,
4156 cpu_V1, cpu_V0);
pbrook9ee6e8b2007-11-11 00:04:49 +00004157 }
4158 break;
4159 case 16:
4160 if (u) {
pbrookad694712008-03-31 03:48:30 +00004161 tcg_gen_sub_i64(CPU_V001);
pbrook9ee6e8b2007-11-11 00:04:49 +00004162 } else {
pbrookad694712008-03-31 03:48:30 +00004163 tcg_gen_add_i64(CPU_V001);
pbrook9ee6e8b2007-11-11 00:04:49 +00004164 }
4165 break;
4166 default:
4167 abort();
4168 }
pbrookad694712008-03-31 03:48:30 +00004169 neon_store_reg64(cpu_V0, rd + pass);
pbrook9ee6e8b2007-11-11 00:04:49 +00004170 }
4171 return 0;
4172 }
4173 switch (op) {
4174 case 8: /* VSHL */
4175 case 9: /* VQSHL */
4176 case 10: /* VRSHL */
pbrookad694712008-03-31 03:48:30 +00004177 case 11: /* VQRSHL */
pbrook9ee6e8b2007-11-11 00:04:49 +00004178 {
pbrookad694712008-03-31 03:48:30 +00004179 int rtmp;
4180 /* Shift instruction operands are reversed. */
4181 rtmp = rn;
pbrook9ee6e8b2007-11-11 00:04:49 +00004182 rn = rm;
pbrookad694712008-03-31 03:48:30 +00004183 rm = rtmp;
pbrook9ee6e8b2007-11-11 00:04:49 +00004184 pairwise = 0;
4185 }
4186 break;
4187 case 20: /* VPMAX */
4188 case 21: /* VPMIN */
4189 case 23: /* VPADD */
4190 pairwise = 1;
4191 break;
4192 case 26: /* VPADD (float) */
4193 pairwise = (u && size < 2);
4194 break;
4195 case 30: /* VPMIN/VPMAX (float) */
4196 pairwise = u;
4197 break;
4198 default:
4199 pairwise = 0;
4200 break;
4201 }
4202 for (pass = 0; pass < (q ? 4 : 2); pass++) {
4203
4204 if (pairwise) {
4205 /* Pairwise. */
4206 if (q)
4207 n = (pass & 1) * 2;
4208 else
4209 n = 0;
4210 if (pass < q + 1) {
4211 NEON_GET_REG(T0, rn, n);
4212 NEON_GET_REG(T1, rn, n + 1);
4213 } else {
4214 NEON_GET_REG(T0, rm, n);
4215 NEON_GET_REG(T1, rm, n + 1);
4216 }
4217 } else {
4218 /* Elementwise. */
4219 NEON_GET_REG(T0, rn, pass);
4220 NEON_GET_REG(T1, rm, pass);
4221 }
4222 switch (op) {
4223 case 0: /* VHADD */
4224 GEN_NEON_INTEGER_OP(hadd);
4225 break;
4226 case 1: /* VQADD */
pbrookad694712008-03-31 03:48:30 +00004227 GEN_NEON_INTEGER_OP_ENV(qadd);
pbrook9ee6e8b2007-11-11 00:04:49 +00004228 break;
4229 case 2: /* VRHADD */
4230 GEN_NEON_INTEGER_OP(rhadd);
4231 break;
4232 case 3: /* Logic ops. */
4233 switch ((u << 2) | size) {
4234 case 0: /* VAND */
4235 gen_op_andl_T0_T1();
4236 break;
4237 case 1: /* BIC */
4238 gen_op_bicl_T0_T1();
4239 break;
4240 case 2: /* VORR */
4241 gen_op_orl_T0_T1();
4242 break;
4243 case 3: /* VORN */
4244 gen_op_notl_T1();
4245 gen_op_orl_T0_T1();
4246 break;
4247 case 4: /* VEOR */
4248 gen_op_xorl_T0_T1();
4249 break;
4250 case 5: /* VBSL */
pbrook8f8e3aa2008-03-31 03:48:01 +00004251 tmp = neon_load_reg(rd, pass);
4252 gen_neon_bsl(cpu_T[0], cpu_T[0], cpu_T[1], tmp);
4253 dead_tmp(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00004254 break;
4255 case 6: /* VBIT */
pbrook8f8e3aa2008-03-31 03:48:01 +00004256 tmp = neon_load_reg(rd, pass);
4257 gen_neon_bsl(cpu_T[0], cpu_T[0], tmp, cpu_T[1]);
4258 dead_tmp(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00004259 break;
4260 case 7: /* VBIF */
pbrook8f8e3aa2008-03-31 03:48:01 +00004261 tmp = neon_load_reg(rd, pass);
4262 gen_neon_bsl(cpu_T[0], tmp, cpu_T[0], cpu_T[1]);
4263 dead_tmp(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00004264 break;
4265 }
4266 break;
4267 case 4: /* VHSUB */
4268 GEN_NEON_INTEGER_OP(hsub);
4269 break;
4270 case 5: /* VQSUB */
pbrookad694712008-03-31 03:48:30 +00004271 GEN_NEON_INTEGER_OP_ENV(qsub);
pbrook9ee6e8b2007-11-11 00:04:49 +00004272 break;
4273 case 6: /* VCGT */
4274 GEN_NEON_INTEGER_OP(cgt);
4275 break;
4276 case 7: /* VCGE */
4277 GEN_NEON_INTEGER_OP(cge);
4278 break;
4279 case 8: /* VSHL */
pbrookad694712008-03-31 03:48:30 +00004280 GEN_NEON_INTEGER_OP(shl);
pbrook9ee6e8b2007-11-11 00:04:49 +00004281 break;
4282 case 9: /* VQSHL */
pbrookad694712008-03-31 03:48:30 +00004283 GEN_NEON_INTEGER_OP_ENV(qshl);
pbrook9ee6e8b2007-11-11 00:04:49 +00004284 break;
4285 case 10: /* VRSHL */
pbrookad694712008-03-31 03:48:30 +00004286 GEN_NEON_INTEGER_OP(rshl);
pbrook9ee6e8b2007-11-11 00:04:49 +00004287 break;
4288 case 11: /* VQRSHL */
pbrookad694712008-03-31 03:48:30 +00004289 GEN_NEON_INTEGER_OP_ENV(qrshl);
pbrook9ee6e8b2007-11-11 00:04:49 +00004290 break;
4291 case 12: /* VMAX */
4292 GEN_NEON_INTEGER_OP(max);
4293 break;
4294 case 13: /* VMIN */
4295 GEN_NEON_INTEGER_OP(min);
4296 break;
4297 case 14: /* VABD */
4298 GEN_NEON_INTEGER_OP(abd);
4299 break;
4300 case 15: /* VABA */
4301 GEN_NEON_INTEGER_OP(abd);
4302 NEON_GET_REG(T1, rd, pass);
4303 gen_neon_add(size);
4304 break;
4305 case 16:
4306 if (!u) { /* VADD */
4307 if (gen_neon_add(size))
4308 return 1;
4309 } else { /* VSUB */
4310 switch (size) {
pbrookad694712008-03-31 03:48:30 +00004311 case 0: gen_helper_neon_sub_u8(CPU_T001); break;
4312 case 1: gen_helper_neon_sub_u16(CPU_T001); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00004313 case 2: gen_op_subl_T0_T1(); break;
4314 default: return 1;
4315 }
4316 }
4317 break;
4318 case 17:
4319 if (!u) { /* VTST */
4320 switch (size) {
pbrookad694712008-03-31 03:48:30 +00004321 case 0: gen_helper_neon_tst_u8(CPU_T001); break;
4322 case 1: gen_helper_neon_tst_u16(CPU_T001); break;
4323 case 2: gen_helper_neon_tst_u32(CPU_T001); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00004324 default: return 1;
4325 }
4326 } else { /* VCEQ */
4327 switch (size) {
pbrookad694712008-03-31 03:48:30 +00004328 case 0: gen_helper_neon_ceq_u8(CPU_T001); break;
4329 case 1: gen_helper_neon_ceq_u16(CPU_T001); break;
4330 case 2: gen_helper_neon_ceq_u32(CPU_T001); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00004331 default: return 1;
4332 }
4333 }
4334 break;
4335 case 18: /* Multiply. */
4336 switch (size) {
pbrookad694712008-03-31 03:48:30 +00004337 case 0: gen_helper_neon_mul_u8(CPU_T001); break;
4338 case 1: gen_helper_neon_mul_u16(CPU_T001); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00004339 case 2: gen_op_mul_T0_T1(); break;
4340 default: return 1;
4341 }
4342 NEON_GET_REG(T1, rd, pass);
4343 if (u) { /* VMLS */
pbrookad694712008-03-31 03:48:30 +00004344 gen_neon_rsb(size);
pbrook9ee6e8b2007-11-11 00:04:49 +00004345 } else { /* VMLA */
4346 gen_neon_add(size);
4347 }
4348 break;
4349 case 19: /* VMUL */
4350 if (u) { /* polynomial */
pbrookad694712008-03-31 03:48:30 +00004351 gen_helper_neon_mul_p8(CPU_T001);
pbrook9ee6e8b2007-11-11 00:04:49 +00004352 } else { /* Integer */
4353 switch (size) {
pbrookad694712008-03-31 03:48:30 +00004354 case 0: gen_helper_neon_mul_u8(CPU_T001); break;
4355 case 1: gen_helper_neon_mul_u16(CPU_T001); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00004356 case 2: gen_op_mul_T0_T1(); break;
4357 default: return 1;
4358 }
4359 }
4360 break;
4361 case 20: /* VPMAX */
4362 GEN_NEON_INTEGER_OP(pmax);
4363 break;
4364 case 21: /* VPMIN */
4365 GEN_NEON_INTEGER_OP(pmin);
4366 break;
4367 case 22: /* Hultiply high. */
4368 if (!u) { /* VQDMULH */
4369 switch (size) {
pbrookad694712008-03-31 03:48:30 +00004370 case 1: gen_helper_neon_qdmulh_s16(CPU_T0E01); break;
4371 case 2: gen_helper_neon_qdmulh_s32(CPU_T0E01); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00004372 default: return 1;
4373 }
4374 } else { /* VQRDHMUL */
4375 switch (size) {
pbrookad694712008-03-31 03:48:30 +00004376 case 1: gen_helper_neon_qrdmulh_s16(CPU_T0E01); break;
4377 case 2: gen_helper_neon_qrdmulh_s32(CPU_T0E01); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00004378 default: return 1;
4379 }
4380 }
4381 break;
4382 case 23: /* VPADD */
4383 if (u)
4384 return 1;
4385 switch (size) {
pbrookad694712008-03-31 03:48:30 +00004386 case 0: gen_helper_neon_padd_u8(CPU_T001); break;
4387 case 1: gen_helper_neon_padd_u16(CPU_T001); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00004388 case 2: gen_op_addl_T0_T1(); break;
4389 default: return 1;
4390 }
4391 break;
4392 case 26: /* Floating point arithnetic. */
4393 switch ((u << 2) | size) {
4394 case 0: /* VADD */
pbrookad694712008-03-31 03:48:30 +00004395 gen_helper_neon_add_f32(CPU_T001);
pbrook9ee6e8b2007-11-11 00:04:49 +00004396 break;
4397 case 2: /* VSUB */
pbrookad694712008-03-31 03:48:30 +00004398 gen_helper_neon_sub_f32(CPU_T001);
pbrook9ee6e8b2007-11-11 00:04:49 +00004399 break;
4400 case 4: /* VPADD */
pbrookad694712008-03-31 03:48:30 +00004401 gen_helper_neon_add_f32(CPU_T001);
pbrook9ee6e8b2007-11-11 00:04:49 +00004402 break;
4403 case 6: /* VABD */
pbrookad694712008-03-31 03:48:30 +00004404 gen_helper_neon_abd_f32(CPU_T001);
pbrook9ee6e8b2007-11-11 00:04:49 +00004405 break;
4406 default:
4407 return 1;
4408 }
4409 break;
4410 case 27: /* Float multiply. */
pbrookad694712008-03-31 03:48:30 +00004411 gen_helper_neon_mul_f32(CPU_T001);
pbrook9ee6e8b2007-11-11 00:04:49 +00004412 if (!u) {
4413 NEON_GET_REG(T1, rd, pass);
4414 if (size == 0) {
pbrookad694712008-03-31 03:48:30 +00004415 gen_helper_neon_add_f32(CPU_T001);
pbrook9ee6e8b2007-11-11 00:04:49 +00004416 } else {
pbrookad694712008-03-31 03:48:30 +00004417 gen_helper_neon_sub_f32(cpu_T[0], cpu_T[1], cpu_T[0]);
pbrook9ee6e8b2007-11-11 00:04:49 +00004418 }
4419 }
4420 break;
4421 case 28: /* Float compare. */
4422 if (!u) {
pbrookad694712008-03-31 03:48:30 +00004423 gen_helper_neon_ceq_f32(CPU_T001);
pbrook9ee6e8b2007-11-11 00:04:49 +00004424 } else {
4425 if (size == 0)
pbrookad694712008-03-31 03:48:30 +00004426 gen_helper_neon_cge_f32(CPU_T001);
pbrook9ee6e8b2007-11-11 00:04:49 +00004427 else
pbrookad694712008-03-31 03:48:30 +00004428 gen_helper_neon_cgt_f32(CPU_T001);
pbrook9ee6e8b2007-11-11 00:04:49 +00004429 }
4430 break;
4431 case 29: /* Float compare absolute. */
4432 if (!u)
4433 return 1;
4434 if (size == 0)
pbrookad694712008-03-31 03:48:30 +00004435 gen_helper_neon_acge_f32(CPU_T001);
pbrook9ee6e8b2007-11-11 00:04:49 +00004436 else
pbrookad694712008-03-31 03:48:30 +00004437 gen_helper_neon_acgt_f32(CPU_T001);
pbrook9ee6e8b2007-11-11 00:04:49 +00004438 break;
4439 case 30: /* Float min/max. */
4440 if (size == 0)
pbrookad694712008-03-31 03:48:30 +00004441 gen_helper_neon_max_f32(CPU_T001);
pbrook9ee6e8b2007-11-11 00:04:49 +00004442 else
pbrookad694712008-03-31 03:48:30 +00004443 gen_helper_neon_min_f32(CPU_T001);
pbrook9ee6e8b2007-11-11 00:04:49 +00004444 break;
4445 case 31:
4446 if (size == 0)
pbrook4373f3c2008-03-31 03:47:19 +00004447 gen_helper_recps_f32(cpu_T[0], cpu_T[0], cpu_T[1], cpu_env);
pbrook9ee6e8b2007-11-11 00:04:49 +00004448 else
pbrook4373f3c2008-03-31 03:47:19 +00004449 gen_helper_rsqrts_f32(cpu_T[0], cpu_T[0], cpu_T[1], cpu_env);
pbrook9ee6e8b2007-11-11 00:04:49 +00004450 break;
4451 default:
4452 abort();
4453 }
4454 /* Save the result. For elementwise operations we can put it
4455 straight into the destination register. For pairwise operations
4456 we have to be careful to avoid clobbering the source operands. */
4457 if (pairwise && rd == rm) {
4458 gen_neon_movl_scratch_T0(pass);
4459 } else {
4460 NEON_SET_REG(T0, rd, pass);
4461 }
4462
4463 } /* for pass */
4464 if (pairwise && rd == rm) {
4465 for (pass = 0; pass < (q ? 4 : 2); pass++) {
4466 gen_neon_movl_T0_scratch(pass);
4467 NEON_SET_REG(T0, rd, pass);
4468 }
4469 }
pbrookad694712008-03-31 03:48:30 +00004470 /* End of 3 register same size operations. */
pbrook9ee6e8b2007-11-11 00:04:49 +00004471 } else if (insn & (1 << 4)) {
4472 if ((insn & 0x00380080) != 0) {
4473 /* Two registers and shift. */
4474 op = (insn >> 8) & 0xf;
4475 if (insn & (1 << 7)) {
4476 /* 64-bit shift. */
4477 size = 3;
4478 } else {
4479 size = 2;
4480 while ((insn & (1 << (size + 19))) == 0)
4481 size--;
4482 }
4483 shift = (insn >> 16) & ((1 << (3 + size)) - 1);
4484 /* To avoid excessive dumplication of ops we implement shift
4485 by immediate using the variable shift operations. */
4486 if (op < 8) {
4487 /* Shift by immediate:
4488 VSHR, VSRA, VRSHR, VRSRA, VSRI, VSHL, VQSHL, VQSHLU. */
4489 /* Right shifts are encoded as N - shift, where N is the
4490 element size in bits. */
4491 if (op <= 4)
4492 shift = shift - (1 << (size + 3));
pbrook9ee6e8b2007-11-11 00:04:49 +00004493 if (size == 3) {
4494 count = q + 1;
4495 } else {
4496 count = q ? 4: 2;
4497 }
4498 switch (size) {
4499 case 0:
4500 imm = (uint8_t) shift;
4501 imm |= imm << 8;
4502 imm |= imm << 16;
4503 break;
4504 case 1:
4505 imm = (uint16_t) shift;
4506 imm |= imm << 16;
4507 break;
4508 case 2:
4509 case 3:
4510 imm = shift;
4511 break;
4512 default:
4513 abort();
4514 }
4515
4516 for (pass = 0; pass < count; pass++) {
pbrookad694712008-03-31 03:48:30 +00004517 if (size == 3) {
4518 neon_load_reg64(cpu_V0, rm + pass);
4519 tcg_gen_movi_i64(cpu_V1, imm);
4520 switch (op) {
4521 case 0: /* VSHR */
4522 case 1: /* VSRA */
4523 if (u)
4524 gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1);
4525 else
4526 gen_helper_neon_shl_s64(cpu_V0, cpu_V0, cpu_V1);
4527 break;
4528 case 2: /* VRSHR */
4529 case 3: /* VRSRA */
4530 if (u)
4531 gen_helper_neon_rshl_u64(cpu_V0, cpu_V0, cpu_V1);
4532 else
4533 gen_helper_neon_rshl_s64(cpu_V0, cpu_V0, cpu_V1);
4534 break;
4535 case 4: /* VSRI */
4536 if (!u)
4537 return 1;
4538 gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1);
4539 break;
4540 case 5: /* VSHL, VSLI */
4541 gen_helper_neon_shl_u64(cpu_V0, cpu_V0, cpu_V1);
4542 break;
4543 case 6: /* VQSHL */
4544 if (u)
4545 gen_helper_neon_qshl_u64(cpu_V0, cpu_env, cpu_V0, cpu_V1);
4546 else
4547 gen_helper_neon_qshl_s64(cpu_V0, cpu_env, cpu_V0, cpu_V1);
4548 break;
4549 case 7: /* VQSHLU */
4550 gen_helper_neon_qshl_u64(cpu_V0, cpu_env, cpu_V0, cpu_V1);
4551 break;
4552 }
4553 if (op == 1 || op == 3) {
4554 /* Accumulate. */
4555 neon_load_reg64(cpu_V0, rd + pass);
4556 tcg_gen_add_i64(cpu_V0, cpu_V0, cpu_V1);
4557 } else if (op == 4 || (op == 5 && u)) {
4558 /* Insert */
4559 cpu_abort(env, "VS[LR]I.64 not implemented");
4560 }
4561 neon_store_reg64(cpu_V0, rd + pass);
4562 } else { /* size < 3 */
pbrook9ee6e8b2007-11-11 00:04:49 +00004563 /* Operands in T0 and T1. */
4564 gen_op_movl_T1_im(imm);
4565 NEON_GET_REG(T0, rm, pass);
pbrookad694712008-03-31 03:48:30 +00004566 switch (op) {
4567 case 0: /* VSHR */
4568 case 1: /* VSRA */
4569 GEN_NEON_INTEGER_OP(shl);
4570 break;
4571 case 2: /* VRSHR */
4572 case 3: /* VRSRA */
4573 GEN_NEON_INTEGER_OP(rshl);
4574 break;
4575 case 4: /* VSRI */
4576 if (!u)
4577 return 1;
4578 GEN_NEON_INTEGER_OP(shl);
4579 break;
4580 case 5: /* VSHL, VSLI */
4581 switch (size) {
4582 case 0: gen_helper_neon_shl_u8(CPU_T001); break;
4583 case 1: gen_helper_neon_shl_u16(CPU_T001); break;
4584 case 2: gen_helper_neon_shl_u32(CPU_T001); break;
4585 default: return 1;
4586 }
4587 break;
4588 case 6: /* VQSHL */
4589 GEN_NEON_INTEGER_OP_ENV(qshl);
4590 break;
4591 case 7: /* VQSHLU */
4592 switch (size) {
4593 case 0: gen_helper_neon_qshl_u8(CPU_T0E01); break;
4594 case 1: gen_helper_neon_qshl_u16(CPU_T0E01); break;
4595 case 2: gen_helper_neon_qshl_u32(CPU_T0E01); break;
4596 default: return 1;
4597 }
4598 break;
4599 }
pbrook9ee6e8b2007-11-11 00:04:49 +00004600
pbrookad694712008-03-31 03:48:30 +00004601 if (op == 1 || op == 3) {
4602 /* Accumulate. */
pbrook9ee6e8b2007-11-11 00:04:49 +00004603 NEON_GET_REG(T1, rd, pass);
4604 gen_neon_add(size);
pbrookad694712008-03-31 03:48:30 +00004605 } else if (op == 4 || (op == 5 && u)) {
4606 /* Insert */
4607 switch (size) {
4608 case 0:
4609 if (op == 4)
4610 imm = 0xff >> -shift;
4611 else
4612 imm = (uint8_t)(0xff << shift);
4613 imm |= imm << 8;
4614 imm |= imm << 16;
4615 break;
4616 case 1:
4617 if (op == 4)
4618 imm = 0xffff >> -shift;
4619 else
4620 imm = (uint16_t)(0xffff << shift);
4621 imm |= imm << 16;
4622 break;
4623 case 2:
4624 if (op == 4)
4625 imm = 0xffffffffu >> -shift;
4626 else
4627 imm = 0xffffffffu << shift;
4628 break;
4629 default:
4630 abort();
4631 }
4632 tmp = neon_load_reg(rd, pass);
4633 tcg_gen_andi_i32(cpu_T[0], cpu_T[0], imm);
4634 tcg_gen_andi_i32(tmp, tmp, ~imm);
4635 tcg_gen_or_i32(cpu_T[0], cpu_T[0], tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00004636 }
pbrook9ee6e8b2007-11-11 00:04:49 +00004637 NEON_SET_REG(T0, rd, pass);
4638 }
4639 } /* for pass */
4640 } else if (op < 10) {
pbrookad694712008-03-31 03:48:30 +00004641 /* Shift by immediate and narrow:
pbrook9ee6e8b2007-11-11 00:04:49 +00004642 VSHRN, VRSHRN, VQSHRN, VQRSHRN. */
4643 shift = shift - (1 << (size + 3));
4644 size++;
pbrook9ee6e8b2007-11-11 00:04:49 +00004645 switch (size) {
4646 case 1:
pbrookad694712008-03-31 03:48:30 +00004647 imm = (uint16_t)shift;
pbrook9ee6e8b2007-11-11 00:04:49 +00004648 imm |= imm << 16;
pbrookad694712008-03-31 03:48:30 +00004649 tmp2 = tcg_const_i32(imm);
pbrook9ee6e8b2007-11-11 00:04:49 +00004650 break;
4651 case 2:
pbrookad694712008-03-31 03:48:30 +00004652 imm = (uint32_t)shift;
4653 tmp2 = tcg_const_i32(imm);
pbrook9ee6e8b2007-11-11 00:04:49 +00004654 case 3:
pbrookad694712008-03-31 03:48:30 +00004655 tmp2 = tcg_const_i64(shift);
pbrook9ee6e8b2007-11-11 00:04:49 +00004656 break;
4657 default:
4658 abort();
4659 }
4660
pbrookad694712008-03-31 03:48:30 +00004661 for (pass = 0; pass < 2; pass++) {
4662 if (size == 3) {
4663 neon_load_reg64(cpu_V0, rm + pass);
4664 if (q) {
4665 if (u)
4666 gen_helper_neon_rshl_u64(cpu_V0, cpu_V0, tmp2);
4667 else
4668 gen_helper_neon_rshl_s64(cpu_V0, cpu_V0, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00004669 } else {
pbrookad694712008-03-31 03:48:30 +00004670 if (u)
4671 gen_helper_neon_shl_u64(cpu_V0, cpu_V0, tmp2);
4672 else
4673 gen_helper_neon_shl_s64(cpu_V0, cpu_V0, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00004674 }
pbrookad694712008-03-31 03:48:30 +00004675 } else {
4676 tmp = neon_load_reg(rm + pass, 0);
4677 gen_neon_shift_narrow(size, tmp, tmp2, q, u);
4678 tcg_gen_extu_i32_i64(cpu_V0, tmp);
4679 dead_tmp(tmp);
4680 tmp = neon_load_reg(rm + pass, 1);
4681 gen_neon_shift_narrow(size, tmp, tmp2, q, u);
4682 tcg_gen_extu_i32_i64(cpu_V1, tmp);
4683 dead_tmp(tmp);
4684 tcg_gen_shli_i64(cpu_V1, cpu_V1, 32);
4685 tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1);
4686 }
4687 tmp = new_tmp();
4688 if (op == 8 && !u) {
4689 gen_neon_narrow(size - 1, tmp, cpu_V0);
4690 } else {
4691 if (op == 8)
4692 gen_neon_narrow_sats(size - 1, tmp, cpu_V0);
pbrook9ee6e8b2007-11-11 00:04:49 +00004693 else
pbrookad694712008-03-31 03:48:30 +00004694 gen_neon_narrow_satu(size - 1, tmp, cpu_V0);
4695 }
4696 if (pass == 0) {
4697 tmp2 = tmp;
4698 } else {
4699 neon_store_reg(rd, 0, tmp2);
4700 neon_store_reg(rd, 1, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00004701 }
4702 } /* for pass */
4703 } else if (op == 10) {
4704 /* VSHLL */
pbrookad694712008-03-31 03:48:30 +00004705 if (q || size == 3)
pbrook9ee6e8b2007-11-11 00:04:49 +00004706 return 1;
pbrookad694712008-03-31 03:48:30 +00004707 tmp = neon_load_reg(rm, 0);
4708 tmp2 = neon_load_reg(rm, 1);
pbrook9ee6e8b2007-11-11 00:04:49 +00004709 for (pass = 0; pass < 2; pass++) {
pbrookad694712008-03-31 03:48:30 +00004710 if (pass == 1)
4711 tmp = tmp2;
pbrook9ee6e8b2007-11-11 00:04:49 +00004712
pbrookad694712008-03-31 03:48:30 +00004713 gen_neon_widen(cpu_V0, tmp, size, u);
4714
pbrook9ee6e8b2007-11-11 00:04:49 +00004715 if (shift != 0) {
4716 /* The shift is less than the width of the source
pbrookad694712008-03-31 03:48:30 +00004717 type, so we can just shift the whole register. */
4718 tcg_gen_shli_i64(cpu_V0, cpu_V0, shift);
4719 if (size < 2 || !u) {
4720 uint64_t imm64;
4721 if (size == 0) {
4722 imm = (0xffu >> (8 - shift));
4723 imm |= imm << 16;
4724 } else {
4725 imm = 0xffff >> (16 - shift);
pbrook9ee6e8b2007-11-11 00:04:49 +00004726 }
pbrookad694712008-03-31 03:48:30 +00004727 imm64 = imm | (((uint64_t)imm) << 32);
4728 tcg_gen_andi_i64(cpu_V0, cpu_V0, imm64);
pbrook9ee6e8b2007-11-11 00:04:49 +00004729 }
4730 }
pbrookad694712008-03-31 03:48:30 +00004731 neon_store_reg64(cpu_V0, rd + pass);
pbrook9ee6e8b2007-11-11 00:04:49 +00004732 }
4733 } else if (op == 15 || op == 16) {
4734 /* VCVT fixed-point. */
4735 for (pass = 0; pass < (q ? 4 : 2); pass++) {
pbrook4373f3c2008-03-31 03:47:19 +00004736 tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, pass));
pbrook9ee6e8b2007-11-11 00:04:49 +00004737 if (op & 1) {
4738 if (u)
pbrook4373f3c2008-03-31 03:47:19 +00004739 gen_vfp_ulto(0, shift);
pbrook9ee6e8b2007-11-11 00:04:49 +00004740 else
pbrook4373f3c2008-03-31 03:47:19 +00004741 gen_vfp_slto(0, shift);
pbrook9ee6e8b2007-11-11 00:04:49 +00004742 } else {
4743 if (u)
pbrook4373f3c2008-03-31 03:47:19 +00004744 gen_vfp_toul(0, shift);
pbrook9ee6e8b2007-11-11 00:04:49 +00004745 else
pbrook4373f3c2008-03-31 03:47:19 +00004746 gen_vfp_tosl(0, shift);
pbrook9ee6e8b2007-11-11 00:04:49 +00004747 }
pbrook4373f3c2008-03-31 03:47:19 +00004748 tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, pass));
pbrook9ee6e8b2007-11-11 00:04:49 +00004749 }
4750 } else {
4751 return 1;
4752 }
4753 } else { /* (insn & 0x00380080) == 0 */
4754 int invert;
4755
4756 op = (insn >> 8) & 0xf;
4757 /* One register and immediate. */
4758 imm = (u << 7) | ((insn >> 12) & 0x70) | (insn & 0xf);
4759 invert = (insn & (1 << 5)) != 0;
4760 switch (op) {
4761 case 0: case 1:
4762 /* no-op */
4763 break;
4764 case 2: case 3:
4765 imm <<= 8;
4766 break;
4767 case 4: case 5:
4768 imm <<= 16;
4769 break;
4770 case 6: case 7:
4771 imm <<= 24;
4772 break;
4773 case 8: case 9:
4774 imm |= imm << 16;
4775 break;
4776 case 10: case 11:
4777 imm = (imm << 8) | (imm << 24);
4778 break;
4779 case 12:
4780 imm = (imm < 8) | 0xff;
4781 break;
4782 case 13:
4783 imm = (imm << 16) | 0xffff;
4784 break;
4785 case 14:
4786 imm |= (imm << 8) | (imm << 16) | (imm << 24);
4787 if (invert)
4788 imm = ~imm;
4789 break;
4790 case 15:
4791 imm = ((imm & 0x80) << 24) | ((imm & 0x3f) << 19)
4792 | ((imm & 0x40) ? (0x1f << 25) : (1 << 30));
4793 break;
4794 }
4795 if (invert)
4796 imm = ~imm;
4797
4798 if (op != 14 || !invert)
4799 gen_op_movl_T1_im(imm);
4800
4801 for (pass = 0; pass < (q ? 4 : 2); pass++) {
4802 if (op & 1 && op < 12) {
pbrookad694712008-03-31 03:48:30 +00004803 tmp = neon_load_reg(rd, pass);
pbrook9ee6e8b2007-11-11 00:04:49 +00004804 if (invert) {
4805 /* The immediate value has already been inverted, so
4806 BIC becomes AND. */
pbrookad694712008-03-31 03:48:30 +00004807 tcg_gen_andi_i32(tmp, tmp, imm);
pbrook9ee6e8b2007-11-11 00:04:49 +00004808 } else {
pbrookad694712008-03-31 03:48:30 +00004809 tcg_gen_ori_i32(tmp, tmp, imm);
pbrook9ee6e8b2007-11-11 00:04:49 +00004810 }
pbrook9ee6e8b2007-11-11 00:04:49 +00004811 } else {
pbrookad694712008-03-31 03:48:30 +00004812 /* VMOV, VMVN. */
4813 tmp = new_tmp();
pbrook9ee6e8b2007-11-11 00:04:49 +00004814 if (op == 14 && invert) {
pbrookad694712008-03-31 03:48:30 +00004815 uint32_t val;
4816 val = 0;
pbrook9ee6e8b2007-11-11 00:04:49 +00004817 for (n = 0; n < 4; n++) {
4818 if (imm & (1 << (n + (pass & 1) * 4)))
pbrookad694712008-03-31 03:48:30 +00004819 val |= 0xff << (n * 8);
pbrook9ee6e8b2007-11-11 00:04:49 +00004820 }
pbrookad694712008-03-31 03:48:30 +00004821 tcg_gen_movi_i32(tmp, val);
4822 } else {
4823 tcg_gen_movi_i32(tmp, imm);
pbrook9ee6e8b2007-11-11 00:04:49 +00004824 }
pbrook9ee6e8b2007-11-11 00:04:49 +00004825 }
pbrookad694712008-03-31 03:48:30 +00004826 neon_store_reg(rd, pass, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00004827 }
4828 }
4829 } else { /* (insn & 0x00800010 == 0x00800010) */
4830 if (size != 3) {
4831 op = (insn >> 8) & 0xf;
4832 if ((insn & (1 << 6)) == 0) {
4833 /* Three registers of different lengths. */
4834 int src1_wide;
4835 int src2_wide;
4836 int prewiden;
4837 /* prewiden, src1_wide, src2_wide */
4838 static const int neon_3reg_wide[16][3] = {
4839 {1, 0, 0}, /* VADDL */
4840 {1, 1, 0}, /* VADDW */
4841 {1, 0, 0}, /* VSUBL */
4842 {1, 1, 0}, /* VSUBW */
4843 {0, 1, 1}, /* VADDHN */
4844 {0, 0, 0}, /* VABAL */
4845 {0, 1, 1}, /* VSUBHN */
4846 {0, 0, 0}, /* VABDL */
4847 {0, 0, 0}, /* VMLAL */
4848 {0, 0, 0}, /* VQDMLAL */
4849 {0, 0, 0}, /* VMLSL */
4850 {0, 0, 0}, /* VQDMLSL */
4851 {0, 0, 0}, /* Integer VMULL */
4852 {0, 0, 0}, /* VQDMULL */
4853 {0, 0, 0} /* Polynomial VMULL */
4854 };
4855
4856 prewiden = neon_3reg_wide[op][0];
4857 src1_wide = neon_3reg_wide[op][1];
4858 src2_wide = neon_3reg_wide[op][2];
4859
pbrookad694712008-03-31 03:48:30 +00004860 if (size == 0 && (op == 9 || op == 11 || op == 13))
4861 return 1;
4862
pbrook9ee6e8b2007-11-11 00:04:49 +00004863 /* Avoid overlapping operands. Wide source operands are
4864 always aligned so will never overlap with wide
4865 destinations in problematic ways. */
pbrook8f8e3aa2008-03-31 03:48:01 +00004866 if (rd == rm && !src2_wide) {
4867 NEON_GET_REG(T0, rm, 1);
4868 gen_neon_movl_scratch_T0(2);
4869 } else if (rd == rn && !src1_wide) {
4870 NEON_GET_REG(T0, rn, 1);
4871 gen_neon_movl_scratch_T0(2);
pbrook9ee6e8b2007-11-11 00:04:49 +00004872 }
4873 for (pass = 0; pass < 2; pass++) {
pbrook8f8e3aa2008-03-31 03:48:01 +00004874 if (src1_wide) {
pbrookad694712008-03-31 03:48:30 +00004875 neon_load_reg64(cpu_V0, rn + pass);
pbrook9ee6e8b2007-11-11 00:04:49 +00004876 } else {
pbrook8f8e3aa2008-03-31 03:48:01 +00004877 if (pass == 1 && rd == rn) {
4878 gen_neon_movl_T0_scratch(2);
pbrookad694712008-03-31 03:48:30 +00004879 tmp = new_tmp();
4880 tcg_gen_mov_i32(tmp, cpu_T[0]);
pbrook9ee6e8b2007-11-11 00:04:49 +00004881 } else {
pbrookad694712008-03-31 03:48:30 +00004882 tmp = neon_load_reg(rn, pass);
4883 }
4884 if (prewiden) {
4885 gen_neon_widen(cpu_V0, tmp, size, u);
pbrook9ee6e8b2007-11-11 00:04:49 +00004886 }
4887 }
pbrookad694712008-03-31 03:48:30 +00004888 if (src2_wide) {
4889 neon_load_reg64(cpu_V1, rm + pass);
4890 } else {
4891 if (pass == 1 && rd == rm) {
4892 gen_neon_movl_T0_scratch(2);
4893 tmp2 = new_tmp();
4894 tcg_gen_mov_i32(tmp2, cpu_T[0]);
4895 } else {
4896 tmp2 = neon_load_reg(rm, pass);
4897 }
4898 if (prewiden) {
4899 gen_neon_widen(cpu_V1, tmp2, size, u);
4900 }
pbrook9ee6e8b2007-11-11 00:04:49 +00004901 }
4902 switch (op) {
4903 case 0: case 1: case 4: /* VADDL, VADDW, VADDHN, VRADDHN */
pbrookad694712008-03-31 03:48:30 +00004904 gen_neon_addl(size);
pbrook9ee6e8b2007-11-11 00:04:49 +00004905 break;
4906 case 2: case 3: case 6: /* VSUBL, VSUBW, VSUBHL, VRSUBHL */
pbrookad694712008-03-31 03:48:30 +00004907 gen_neon_subl(size);
pbrook9ee6e8b2007-11-11 00:04:49 +00004908 break;
4909 case 5: case 7: /* VABAL, VABDL */
4910 switch ((size << 1) | u) {
pbrookad694712008-03-31 03:48:30 +00004911 case 0:
4912 gen_helper_neon_abdl_s16(cpu_V0, tmp, tmp2);
4913 break;
4914 case 1:
4915 gen_helper_neon_abdl_u16(cpu_V0, tmp, tmp2);
4916 break;
4917 case 2:
4918 gen_helper_neon_abdl_s32(cpu_V0, tmp, tmp2);
4919 break;
4920 case 3:
4921 gen_helper_neon_abdl_u32(cpu_V0, tmp, tmp2);
4922 break;
4923 case 4:
4924 gen_helper_neon_abdl_s64(cpu_V0, tmp, tmp2);
4925 break;
4926 case 5:
4927 gen_helper_neon_abdl_u64(cpu_V0, tmp, tmp2);
4928 break;
pbrook9ee6e8b2007-11-11 00:04:49 +00004929 default: abort();
4930 }
pbrookad694712008-03-31 03:48:30 +00004931 dead_tmp(tmp2);
4932 dead_tmp(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00004933 break;
4934 case 8: case 9: case 10: case 11: case 12: case 13:
4935 /* VMLAL, VQDMLAL, VMLSL, VQDMLSL, VMULL, VQDMULL */
pbrookad694712008-03-31 03:48:30 +00004936 gen_neon_mull(cpu_V0, tmp, tmp2, size, u);
pbrook9ee6e8b2007-11-11 00:04:49 +00004937 break;
4938 case 14: /* Polynomial VMULL */
4939 cpu_abort(env, "Polynomial VMULL not implemented");
4940
4941 default: /* 15 is RESERVED. */
4942 return 1;
4943 }
4944 if (op == 5 || op == 13 || (op >= 8 && op <= 11)) {
4945 /* Accumulate. */
4946 if (op == 10 || op == 11) {
pbrookad694712008-03-31 03:48:30 +00004947 gen_neon_negl(cpu_V0, size);
pbrook9ee6e8b2007-11-11 00:04:49 +00004948 }
4949
pbrook9ee6e8b2007-11-11 00:04:49 +00004950 if (op != 13) {
pbrookad694712008-03-31 03:48:30 +00004951 neon_load_reg64(cpu_V1, rd + pass);
pbrook9ee6e8b2007-11-11 00:04:49 +00004952 }
4953
4954 switch (op) {
4955 case 5: case 8: case 10: /* VABAL, VMLAL, VMLSL */
pbrookad694712008-03-31 03:48:30 +00004956 gen_neon_addl(size);
pbrook9ee6e8b2007-11-11 00:04:49 +00004957 break;
4958 case 9: case 11: /* VQDMLAL, VQDMLSL */
pbrookad694712008-03-31 03:48:30 +00004959 gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
4960 gen_neon_addl_saturate(cpu_V0, cpu_V1, size);
4961 break;
pbrook9ee6e8b2007-11-11 00:04:49 +00004962 /* Fall through. */
4963 case 13: /* VQDMULL */
pbrookad694712008-03-31 03:48:30 +00004964 gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
pbrook9ee6e8b2007-11-11 00:04:49 +00004965 break;
4966 default:
4967 abort();
4968 }
pbrookad694712008-03-31 03:48:30 +00004969 neon_store_reg64(cpu_V0, rd + pass);
pbrook9ee6e8b2007-11-11 00:04:49 +00004970 } else if (op == 4 || op == 6) {
4971 /* Narrowing operation. */
pbrookad694712008-03-31 03:48:30 +00004972 tmp = new_tmp();
pbrook9ee6e8b2007-11-11 00:04:49 +00004973 if (u) {
4974 switch (size) {
pbrookad694712008-03-31 03:48:30 +00004975 case 0:
4976 gen_helper_neon_narrow_high_u8(tmp, cpu_V0);
4977 break;
4978 case 1:
4979 gen_helper_neon_narrow_high_u16(tmp, cpu_V0);
4980 break;
4981 case 2:
4982 tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
4983 tcg_gen_trunc_i64_i32(tmp, cpu_V0);
4984 break;
pbrook9ee6e8b2007-11-11 00:04:49 +00004985 default: abort();
4986 }
4987 } else {
4988 switch (size) {
pbrookad694712008-03-31 03:48:30 +00004989 case 0:
4990 gen_helper_neon_narrow_round_high_u8(tmp, cpu_V0);
4991 break;
4992 case 1:
4993 gen_helper_neon_narrow_round_high_u16(tmp, cpu_V0);
4994 break;
4995 case 2:
4996 tcg_gen_addi_i64(cpu_V0, cpu_V0, 1u << 31);
4997 tcg_gen_shri_i64(cpu_V0, cpu_V0, 32);
4998 tcg_gen_trunc_i64_i32(tmp, cpu_V0);
4999 break;
pbrook9ee6e8b2007-11-11 00:04:49 +00005000 default: abort();
5001 }
5002 }
pbrookad694712008-03-31 03:48:30 +00005003 if (pass == 0) {
5004 tmp3 = tmp;
5005 } else {
5006 neon_store_reg(rd, 0, tmp3);
5007 neon_store_reg(rd, 1, tmp);
5008 }
pbrook9ee6e8b2007-11-11 00:04:49 +00005009 } else {
5010 /* Write back the result. */
pbrookad694712008-03-31 03:48:30 +00005011 neon_store_reg64(cpu_V0, rd + pass);
pbrook9ee6e8b2007-11-11 00:04:49 +00005012 }
5013 }
5014 } else {
5015 /* Two registers and a scalar. */
5016 switch (op) {
5017 case 0: /* Integer VMLA scalar */
5018 case 1: /* Float VMLA scalar */
5019 case 4: /* Integer VMLS scalar */
5020 case 5: /* Floating point VMLS scalar */
5021 case 8: /* Integer VMUL scalar */
5022 case 9: /* Floating point VMUL scalar */
5023 case 12: /* VQDMULH scalar */
5024 case 13: /* VQRDMULH scalar */
5025 gen_neon_get_scalar(size, rm);
pbrook8f8e3aa2008-03-31 03:48:01 +00005026 gen_neon_movl_scratch_T0(0);
pbrook9ee6e8b2007-11-11 00:04:49 +00005027 for (pass = 0; pass < (u ? 4 : 2); pass++) {
5028 if (pass != 0)
pbrook8f8e3aa2008-03-31 03:48:01 +00005029 gen_neon_movl_T0_scratch(0);
pbrook9ee6e8b2007-11-11 00:04:49 +00005030 NEON_GET_REG(T1, rn, pass);
5031 if (op == 12) {
5032 if (size == 1) {
pbrookad694712008-03-31 03:48:30 +00005033 gen_helper_neon_qdmulh_s16(CPU_T0E01);
pbrook9ee6e8b2007-11-11 00:04:49 +00005034 } else {
pbrookad694712008-03-31 03:48:30 +00005035 gen_helper_neon_qdmulh_s32(CPU_T0E01);
pbrook9ee6e8b2007-11-11 00:04:49 +00005036 }
5037 } else if (op == 13) {
5038 if (size == 1) {
pbrookad694712008-03-31 03:48:30 +00005039 gen_helper_neon_qrdmulh_s16(CPU_T0E01);
pbrook9ee6e8b2007-11-11 00:04:49 +00005040 } else {
pbrookad694712008-03-31 03:48:30 +00005041 gen_helper_neon_qrdmulh_s32(CPU_T0E01);
pbrook9ee6e8b2007-11-11 00:04:49 +00005042 }
5043 } else if (op & 1) {
pbrookad694712008-03-31 03:48:30 +00005044 gen_helper_neon_mul_f32(CPU_T001);
pbrook9ee6e8b2007-11-11 00:04:49 +00005045 } else {
5046 switch (size) {
pbrookad694712008-03-31 03:48:30 +00005047 case 0: gen_helper_neon_mul_u8(CPU_T001); break;
5048 case 1: gen_helper_neon_mul_u16(CPU_T001); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00005049 case 2: gen_op_mul_T0_T1(); break;
5050 default: return 1;
5051 }
5052 }
5053 if (op < 8) {
5054 /* Accumulate. */
5055 NEON_GET_REG(T1, rd, pass);
5056 switch (op) {
5057 case 0:
5058 gen_neon_add(size);
5059 break;
5060 case 1:
pbrookad694712008-03-31 03:48:30 +00005061 gen_helper_neon_add_f32(CPU_T001);
pbrook9ee6e8b2007-11-11 00:04:49 +00005062 break;
5063 case 4:
pbrookad694712008-03-31 03:48:30 +00005064 gen_neon_rsb(size);
pbrook9ee6e8b2007-11-11 00:04:49 +00005065 break;
5066 case 5:
pbrookad694712008-03-31 03:48:30 +00005067 gen_helper_neon_sub_f32(cpu_T[0], cpu_T[1], cpu_T[0]);
pbrook9ee6e8b2007-11-11 00:04:49 +00005068 break;
5069 default:
5070 abort();
5071 }
5072 }
5073 NEON_SET_REG(T0, rd, pass);
5074 }
5075 break;
5076 case 2: /* VMLAL sclar */
5077 case 3: /* VQDMLAL scalar */
5078 case 6: /* VMLSL scalar */
5079 case 7: /* VQDMLSL scalar */
5080 case 10: /* VMULL scalar */
5081 case 11: /* VQDMULL scalar */
pbrookad694712008-03-31 03:48:30 +00005082 if (size == 0 && (op == 3 || op == 7 || op == 11))
5083 return 1;
5084
pbrook9ee6e8b2007-11-11 00:04:49 +00005085 gen_neon_get_scalar(size, rm);
pbrookad694712008-03-31 03:48:30 +00005086 NEON_GET_REG(T1, rn, 1);
5087
pbrook9ee6e8b2007-11-11 00:04:49 +00005088 for (pass = 0; pass < 2; pass++) {
pbrookad694712008-03-31 03:48:30 +00005089 if (pass == 0) {
5090 tmp = neon_load_reg(rn, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00005091 } else {
pbrookad694712008-03-31 03:48:30 +00005092 tmp = new_tmp();
5093 tcg_gen_mov_i32(tmp, cpu_T[1]);
pbrook9ee6e8b2007-11-11 00:04:49 +00005094 }
pbrookad694712008-03-31 03:48:30 +00005095 tmp2 = new_tmp();
5096 tcg_gen_mov_i32(tmp2, cpu_T[0]);
5097 gen_neon_mull(cpu_V0, tmp, tmp2, size, u);
pbrook9ee6e8b2007-11-11 00:04:49 +00005098 if (op == 6 || op == 7) {
pbrookad694712008-03-31 03:48:30 +00005099 gen_neon_negl(cpu_V0, size);
pbrook9ee6e8b2007-11-11 00:04:49 +00005100 }
pbrookad694712008-03-31 03:48:30 +00005101 if (op != 11) {
5102 neon_load_reg64(cpu_V1, rd + pass);
5103 }
pbrook9ee6e8b2007-11-11 00:04:49 +00005104 switch (op) {
5105 case 2: case 6:
pbrookad694712008-03-31 03:48:30 +00005106 gen_neon_addl(size);
pbrook9ee6e8b2007-11-11 00:04:49 +00005107 break;
5108 case 3: case 7:
pbrookad694712008-03-31 03:48:30 +00005109 gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
5110 gen_neon_addl_saturate(cpu_V0, cpu_V1, size);
pbrook9ee6e8b2007-11-11 00:04:49 +00005111 break;
5112 case 10:
5113 /* no-op */
5114 break;
5115 case 11:
pbrookad694712008-03-31 03:48:30 +00005116 gen_neon_addl_saturate(cpu_V0, cpu_V0, size);
pbrook9ee6e8b2007-11-11 00:04:49 +00005117 break;
5118 default:
5119 abort();
5120 }
pbrookad694712008-03-31 03:48:30 +00005121 neon_store_reg64(cpu_V0, rd + pass);
pbrook9ee6e8b2007-11-11 00:04:49 +00005122 }
5123 break;
5124 default: /* 14 and 15 are RESERVED */
5125 return 1;
5126 }
5127 }
5128 } else { /* size == 3 */
5129 if (!u) {
5130 /* Extract. */
pbrook9ee6e8b2007-11-11 00:04:49 +00005131 imm = (insn >> 8) & 0xf;
pbrookad694712008-03-31 03:48:30 +00005132 count = q + 1;
5133
5134 if (imm > 7 && !q)
5135 return 1;
5136
5137 if (imm == 0) {
5138 neon_load_reg64(cpu_V0, rn);
5139 if (q) {
5140 neon_load_reg64(cpu_V1, rn + 1);
pbrook9ee6e8b2007-11-11 00:04:49 +00005141 }
pbrookad694712008-03-31 03:48:30 +00005142 } else if (imm == 8) {
5143 neon_load_reg64(cpu_V0, rn + 1);
5144 if (q) {
5145 neon_load_reg64(cpu_V1, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00005146 }
pbrookad694712008-03-31 03:48:30 +00005147 } else if (q) {
5148 tmp = tcg_temp_new(TCG_TYPE_I64);
5149 if (imm < 8) {
5150 neon_load_reg64(cpu_V0, rn);
5151 neon_load_reg64(tmp, rn + 1);
pbrook9ee6e8b2007-11-11 00:04:49 +00005152 } else {
pbrookad694712008-03-31 03:48:30 +00005153 neon_load_reg64(cpu_V0, rn + 1);
5154 neon_load_reg64(tmp, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00005155 }
pbrookad694712008-03-31 03:48:30 +00005156 tcg_gen_shri_i64(cpu_V0, cpu_V0, (imm & 7) * 8);
5157 tcg_gen_shli_i64(cpu_V1, tmp, 64 - ((imm & 7) * 8));
5158 tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1);
5159 if (imm < 8) {
5160 neon_load_reg64(cpu_V1, rm);
5161 } else {
5162 neon_load_reg64(cpu_V1, rm + 1);
5163 imm -= 8;
5164 }
5165 tcg_gen_shli_i64(cpu_V1, cpu_V1, 64 - (imm * 8));
5166 tcg_gen_shri_i64(tmp, tmp, imm * 8);
5167 tcg_gen_or_i64(cpu_V1, cpu_V1, tmp);
5168 } else {
5169 neon_load_reg64(cpu_V0, rn);
5170 tcg_gen_shri_i32(cpu_V0, cpu_V0, imm * 8);
5171 neon_load_reg64(cpu_V1, rm);
5172 tcg_gen_shli_i32(cpu_V1, cpu_V1, 64 - (imm * 8));
5173 tcg_gen_or_i64(cpu_V0, cpu_V0, cpu_V1);
5174 }
5175 neon_store_reg64(cpu_V0, rd);
5176 if (q) {
5177 neon_store_reg64(cpu_V1, rd + 1);
pbrook9ee6e8b2007-11-11 00:04:49 +00005178 }
5179 } else if ((insn & (1 << 11)) == 0) {
5180 /* Two register misc. */
5181 op = ((insn >> 12) & 0x30) | ((insn >> 7) & 0xf);
5182 size = (insn >> 18) & 3;
5183 switch (op) {
5184 case 0: /* VREV64 */
5185 if (size == 3)
5186 return 1;
5187 for (pass = 0; pass < (q ? 2 : 1); pass++) {
5188 NEON_GET_REG(T0, rm, pass * 2);
5189 NEON_GET_REG(T1, rm, pass * 2 + 1);
5190 switch (size) {
pbrookb0109802008-03-31 03:47:03 +00005191 case 0: tcg_gen_bswap_i32(cpu_T[0], cpu_T[0]); break;
pbrook8f012452008-03-31 03:46:03 +00005192 case 1: gen_swap_half(cpu_T[0]); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00005193 case 2: /* no-op */ break;
5194 default: abort();
5195 }
5196 NEON_SET_REG(T0, rd, pass * 2 + 1);
5197 if (size == 2) {
5198 NEON_SET_REG(T1, rd, pass * 2);
5199 } else {
5200 gen_op_movl_T0_T1();
5201 switch (size) {
pbrookb0109802008-03-31 03:47:03 +00005202 case 0: tcg_gen_bswap_i32(cpu_T[0], cpu_T[0]); break;
pbrook8f012452008-03-31 03:46:03 +00005203 case 1: gen_swap_half(cpu_T[0]); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00005204 default: abort();
5205 }
5206 NEON_SET_REG(T0, rd, pass * 2);
5207 }
5208 }
5209 break;
5210 case 4: case 5: /* VPADDL */
5211 case 12: case 13: /* VPADAL */
pbrook9ee6e8b2007-11-11 00:04:49 +00005212 if (size == 3)
5213 return 1;
pbrookad694712008-03-31 03:48:30 +00005214 for (pass = 0; pass < q + 1; pass++) {
5215 tmp = neon_load_reg(rm, pass * 2);
5216 gen_neon_widen(cpu_V0, tmp, size, op & 1);
5217 tmp = neon_load_reg(rm, pass * 2 + 1);
5218 gen_neon_widen(cpu_V1, tmp, size, op & 1);
5219 switch (size) {
5220 case 0: gen_helper_neon_paddl_u16(CPU_V001); break;
5221 case 1: gen_helper_neon_paddl_u32(CPU_V001); break;
5222 case 2: tcg_gen_add_i64(CPU_V001); break;
5223 default: abort();
5224 }
pbrook9ee6e8b2007-11-11 00:04:49 +00005225 if (op >= 12) {
5226 /* Accumulate. */
pbrookad694712008-03-31 03:48:30 +00005227 neon_load_reg64(cpu_V1, rd + pass);
5228 gen_neon_addl(size);
pbrook9ee6e8b2007-11-11 00:04:49 +00005229 }
pbrookad694712008-03-31 03:48:30 +00005230 neon_store_reg64(cpu_V0, rd + pass);
pbrook9ee6e8b2007-11-11 00:04:49 +00005231 }
5232 break;
5233 case 33: /* VTRN */
5234 if (size == 2) {
5235 for (n = 0; n < (q ? 4 : 2); n += 2) {
5236 NEON_GET_REG(T0, rm, n);
5237 NEON_GET_REG(T1, rd, n + 1);
5238 NEON_SET_REG(T1, rm, n);
5239 NEON_SET_REG(T0, rd, n + 1);
5240 }
5241 } else {
5242 goto elementwise;
5243 }
5244 break;
5245 case 34: /* VUZP */
5246 /* Reg Before After
5247 Rd A3 A2 A1 A0 B2 B0 A2 A0
5248 Rm B3 B2 B1 B0 B3 B1 A3 A1
5249 */
5250 if (size == 3)
5251 return 1;
5252 gen_neon_unzip(rd, q, 0, size);
5253 gen_neon_unzip(rm, q, 4, size);
5254 if (q) {
5255 static int unzip_order_q[8] =
5256 {0, 2, 4, 6, 1, 3, 5, 7};
5257 for (n = 0; n < 8; n++) {
5258 int reg = (n < 4) ? rd : rm;
5259 gen_neon_movl_T0_scratch(unzip_order_q[n]);
5260 NEON_SET_REG(T0, reg, n % 4);
5261 }
5262 } else {
5263 static int unzip_order[4] =
5264 {0, 4, 1, 5};
5265 for (n = 0; n < 4; n++) {
5266 int reg = (n < 2) ? rd : rm;
5267 gen_neon_movl_T0_scratch(unzip_order[n]);
5268 NEON_SET_REG(T0, reg, n % 2);
5269 }
5270 }
5271 break;
5272 case 35: /* VZIP */
5273 /* Reg Before After
5274 Rd A3 A2 A1 A0 B1 A1 B0 A0
5275 Rm B3 B2 B1 B0 B3 A3 B2 A2
5276 */
5277 if (size == 3)
5278 return 1;
5279 count = (q ? 4 : 2);
5280 for (n = 0; n < count; n++) {
5281 NEON_GET_REG(T0, rd, n);
5282 NEON_GET_REG(T1, rd, n);
5283 switch (size) {
pbrookad694712008-03-31 03:48:30 +00005284 case 0: gen_helper_neon_zip_u8(); break;
5285 case 1: gen_helper_neon_zip_u16(); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00005286 case 2: /* no-op */; break;
5287 default: abort();
5288 }
5289 gen_neon_movl_scratch_T0(n * 2);
5290 gen_neon_movl_scratch_T1(n * 2 + 1);
5291 }
5292 for (n = 0; n < count * 2; n++) {
5293 int reg = (n < count) ? rd : rm;
5294 gen_neon_movl_T0_scratch(n);
5295 NEON_SET_REG(T0, reg, n % count);
5296 }
5297 break;
5298 case 36: case 37: /* VMOVN, VQMOVUN, VQMOVN */
pbrookad694712008-03-31 03:48:30 +00005299 if (size == 3)
5300 return 1;
pbrook9ee6e8b2007-11-11 00:04:49 +00005301 for (pass = 0; pass < 2; pass++) {
pbrookad694712008-03-31 03:48:30 +00005302 neon_load_reg64(cpu_V0, rm + pass);
5303 tmp = new_tmp();
pbrook9ee6e8b2007-11-11 00:04:49 +00005304 if (op == 36 && q == 0) {
pbrookad694712008-03-31 03:48:30 +00005305 gen_neon_narrow(size, tmp, cpu_V0);
pbrook9ee6e8b2007-11-11 00:04:49 +00005306 } else if (q) {
pbrookad694712008-03-31 03:48:30 +00005307 gen_neon_narrow_satu(size, tmp, cpu_V0);
pbrook9ee6e8b2007-11-11 00:04:49 +00005308 } else {
pbrookad694712008-03-31 03:48:30 +00005309 gen_neon_narrow_sats(size, tmp, cpu_V0);
pbrook9ee6e8b2007-11-11 00:04:49 +00005310 }
pbrookad694712008-03-31 03:48:30 +00005311 if (pass == 0) {
5312 tmp2 = tmp;
5313 } else {
5314 neon_store_reg(rd, 0, tmp2);
5315 neon_store_reg(rd, 1, tmp);
5316 }
pbrook9ee6e8b2007-11-11 00:04:49 +00005317 }
5318 break;
5319 case 38: /* VSHLL */
pbrookad694712008-03-31 03:48:30 +00005320 if (q || size == 3)
pbrook9ee6e8b2007-11-11 00:04:49 +00005321 return 1;
pbrookad694712008-03-31 03:48:30 +00005322 tmp = neon_load_reg(rm, 0);
5323 tmp2 = neon_load_reg(rm, 1);
pbrook9ee6e8b2007-11-11 00:04:49 +00005324 for (pass = 0; pass < 2; pass++) {
pbrookad694712008-03-31 03:48:30 +00005325 if (pass == 1)
5326 tmp = tmp2;
5327 gen_neon_widen(cpu_V0, tmp, size, 1);
5328 neon_store_reg64(cpu_V0, rd + pass);
pbrook9ee6e8b2007-11-11 00:04:49 +00005329 }
5330 break;
5331 default:
5332 elementwise:
5333 for (pass = 0; pass < (q ? 4 : 2); pass++) {
5334 if (op == 30 || op == 31 || op >= 58) {
pbrook4373f3c2008-03-31 03:47:19 +00005335 tcg_gen_ld_f32(cpu_F0s, cpu_env,
5336 neon_reg_offset(rm, pass));
pbrook9ee6e8b2007-11-11 00:04:49 +00005337 } else {
5338 NEON_GET_REG(T0, rm, pass);
5339 }
5340 switch (op) {
5341 case 1: /* VREV32 */
5342 switch (size) {
pbrookb0109802008-03-31 03:47:03 +00005343 case 0: tcg_gen_bswap_i32(cpu_T[0], cpu_T[0]); break;
pbrook8f012452008-03-31 03:46:03 +00005344 case 1: gen_swap_half(cpu_T[0]); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00005345 default: return 1;
5346 }
5347 break;
5348 case 2: /* VREV16 */
5349 if (size != 0)
5350 return 1;
pbrook36706692008-03-31 03:46:19 +00005351 gen_rev16(cpu_T[0]);
pbrook9ee6e8b2007-11-11 00:04:49 +00005352 break;
pbrook9ee6e8b2007-11-11 00:04:49 +00005353 case 8: /* CLS */
5354 switch (size) {
pbrookad694712008-03-31 03:48:30 +00005355 case 0: gen_helper_neon_cls_s8(cpu_T[0], cpu_T[0]); break;
5356 case 1: gen_helper_neon_cls_s16(cpu_T[0], cpu_T[0]); break;
5357 case 2: gen_helper_neon_cls_s32(cpu_T[0], cpu_T[0]); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00005358 default: return 1;
5359 }
5360 break;
5361 case 9: /* CLZ */
5362 switch (size) {
pbrookad694712008-03-31 03:48:30 +00005363 case 0: gen_helper_neon_clz_u8(cpu_T[0], cpu_T[0]); break;
5364 case 1: gen_helper_neon_clz_u16(cpu_T[0], cpu_T[0]); break;
pbrook1497c962008-03-31 03:45:50 +00005365 case 2: gen_helper_clz(cpu_T[0], cpu_T[0]); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00005366 default: return 1;
5367 }
5368 break;
5369 case 10: /* CNT */
5370 if (size != 0)
5371 return 1;
pbrookad694712008-03-31 03:48:30 +00005372 gen_helper_neon_cnt_u8(cpu_T[0], cpu_T[0]);
pbrook9ee6e8b2007-11-11 00:04:49 +00005373 break;
5374 case 11: /* VNOT */
5375 if (size != 0)
5376 return 1;
5377 gen_op_notl_T0();
5378 break;
5379 case 14: /* VQABS */
5380 switch (size) {
pbrookad694712008-03-31 03:48:30 +00005381 case 0: gen_helper_neon_qabs_s8(cpu_T[0], cpu_env, cpu_T[0]); break;
5382 case 1: gen_helper_neon_qabs_s16(cpu_T[0], cpu_env, cpu_T[0]); break;
5383 case 2: gen_helper_neon_qabs_s32(cpu_T[0], cpu_env, cpu_T[0]); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00005384 default: return 1;
5385 }
5386 break;
5387 case 15: /* VQNEG */
5388 switch (size) {
pbrookad694712008-03-31 03:48:30 +00005389 case 0: gen_helper_neon_qneg_s8(cpu_T[0], cpu_env, cpu_T[0]); break;
5390 case 1: gen_helper_neon_qneg_s16(cpu_T[0], cpu_env, cpu_T[0]); break;
5391 case 2: gen_helper_neon_qneg_s32(cpu_T[0], cpu_env, cpu_T[0]); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00005392 default: return 1;
5393 }
5394 break;
5395 case 16: case 19: /* VCGT #0, VCLE #0 */
5396 gen_op_movl_T1_im(0);
5397 switch(size) {
pbrookad694712008-03-31 03:48:30 +00005398 case 0: gen_helper_neon_cgt_s8(CPU_T001); break;
5399 case 1: gen_helper_neon_cgt_s16(CPU_T001); break;
5400 case 2: gen_helper_neon_cgt_s32(CPU_T001); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00005401 default: return 1;
5402 }
5403 if (op == 19)
5404 gen_op_notl_T0();
5405 break;
5406 case 17: case 20: /* VCGE #0, VCLT #0 */
5407 gen_op_movl_T1_im(0);
5408 switch(size) {
pbrookad694712008-03-31 03:48:30 +00005409 case 0: gen_helper_neon_cge_s8(CPU_T001); break;
5410 case 1: gen_helper_neon_cge_s16(CPU_T001); break;
5411 case 2: gen_helper_neon_cge_s32(CPU_T001); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00005412 default: return 1;
5413 }
5414 if (op == 20)
5415 gen_op_notl_T0();
5416 break;
5417 case 18: /* VCEQ #0 */
5418 gen_op_movl_T1_im(0);
5419 switch(size) {
pbrookad694712008-03-31 03:48:30 +00005420 case 0: gen_helper_neon_ceq_u8(CPU_T001); break;
5421 case 1: gen_helper_neon_ceq_u16(CPU_T001); break;
5422 case 2: gen_helper_neon_ceq_u32(CPU_T001); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00005423 default: return 1;
5424 }
5425 break;
5426 case 22: /* VABS */
5427 switch(size) {
pbrookad694712008-03-31 03:48:30 +00005428 case 0: gen_helper_neon_abs_s8(cpu_T[0], cpu_T[0]); break;
5429 case 1: gen_helper_neon_abs_s16(cpu_T[0], cpu_T[0]); break;
5430 case 2: tcg_gen_abs_i32(cpu_T[0], cpu_T[0]); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00005431 default: return 1;
5432 }
5433 break;
5434 case 23: /* VNEG */
5435 gen_op_movl_T1_im(0);
pbrookad694712008-03-31 03:48:30 +00005436 if (size == 3)
5437 return 1;
5438 gen_neon_rsb(size);
pbrook9ee6e8b2007-11-11 00:04:49 +00005439 break;
5440 case 24: case 27: /* Float VCGT #0, Float VCLE #0 */
5441 gen_op_movl_T1_im(0);
pbrookad694712008-03-31 03:48:30 +00005442 gen_helper_neon_cgt_f32(CPU_T001);
pbrook9ee6e8b2007-11-11 00:04:49 +00005443 if (op == 27)
5444 gen_op_notl_T0();
5445 break;
5446 case 25: case 28: /* Float VCGE #0, Float VCLT #0 */
5447 gen_op_movl_T1_im(0);
pbrookad694712008-03-31 03:48:30 +00005448 gen_helper_neon_cge_f32(CPU_T001);
pbrook9ee6e8b2007-11-11 00:04:49 +00005449 if (op == 28)
5450 gen_op_notl_T0();
5451 break;
5452 case 26: /* Float VCEQ #0 */
5453 gen_op_movl_T1_im(0);
pbrookad694712008-03-31 03:48:30 +00005454 gen_helper_neon_ceq_f32(CPU_T001);
pbrook9ee6e8b2007-11-11 00:04:49 +00005455 break;
5456 case 30: /* Float VABS */
pbrook4373f3c2008-03-31 03:47:19 +00005457 gen_vfp_abs(0);
pbrook9ee6e8b2007-11-11 00:04:49 +00005458 break;
5459 case 31: /* Float VNEG */
pbrook4373f3c2008-03-31 03:47:19 +00005460 gen_vfp_neg(0);
pbrook9ee6e8b2007-11-11 00:04:49 +00005461 break;
5462 case 32: /* VSWP */
5463 NEON_GET_REG(T1, rd, pass);
5464 NEON_SET_REG(T1, rm, pass);
5465 break;
5466 case 33: /* VTRN */
5467 NEON_GET_REG(T1, rd, pass);
5468 switch (size) {
pbrookad694712008-03-31 03:48:30 +00005469 case 0: gen_helper_neon_trn_u8(); break;
5470 case 1: gen_helper_neon_trn_u16(); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00005471 case 2: abort();
5472 default: return 1;
5473 }
5474 NEON_SET_REG(T1, rm, pass);
5475 break;
5476 case 56: /* Integer VRECPE */
pbrook4373f3c2008-03-31 03:47:19 +00005477 gen_helper_recpe_u32(cpu_T[0], cpu_T[0], cpu_env);
pbrook9ee6e8b2007-11-11 00:04:49 +00005478 break;
5479 case 57: /* Integer VRSQRTE */
pbrook4373f3c2008-03-31 03:47:19 +00005480 gen_helper_rsqrte_u32(cpu_T[0], cpu_T[0], cpu_env);
pbrook9ee6e8b2007-11-11 00:04:49 +00005481 break;
5482 case 58: /* Float VRECPE */
pbrook4373f3c2008-03-31 03:47:19 +00005483 gen_helper_recpe_f32(cpu_F0s, cpu_F0s, cpu_env);
pbrook9ee6e8b2007-11-11 00:04:49 +00005484 break;
5485 case 59: /* Float VRSQRTE */
pbrook4373f3c2008-03-31 03:47:19 +00005486 gen_helper_rsqrte_f32(cpu_F0s, cpu_F0s, cpu_env);
pbrook9ee6e8b2007-11-11 00:04:49 +00005487 break;
5488 case 60: /* VCVT.F32.S32 */
pbrook4373f3c2008-03-31 03:47:19 +00005489 gen_vfp_tosiz(0);
pbrook9ee6e8b2007-11-11 00:04:49 +00005490 break;
5491 case 61: /* VCVT.F32.U32 */
pbrook4373f3c2008-03-31 03:47:19 +00005492 gen_vfp_touiz(0);
pbrook9ee6e8b2007-11-11 00:04:49 +00005493 break;
5494 case 62: /* VCVT.S32.F32 */
pbrook4373f3c2008-03-31 03:47:19 +00005495 gen_vfp_sito(0);
pbrook9ee6e8b2007-11-11 00:04:49 +00005496 break;
5497 case 63: /* VCVT.U32.F32 */
pbrook4373f3c2008-03-31 03:47:19 +00005498 gen_vfp_uito(0);
pbrook9ee6e8b2007-11-11 00:04:49 +00005499 break;
5500 default:
5501 /* Reserved: 21, 29, 39-56 */
5502 return 1;
5503 }
5504 if (op == 30 || op == 31 || op >= 58) {
pbrook4373f3c2008-03-31 03:47:19 +00005505 tcg_gen_st_f32(cpu_F0s, cpu_env,
5506 neon_reg_offset(rd, pass));
pbrook9ee6e8b2007-11-11 00:04:49 +00005507 } else {
5508 NEON_SET_REG(T0, rd, pass);
5509 }
5510 }
5511 break;
5512 }
5513 } else if ((insn & (1 << 10)) == 0) {
5514 /* VTBL, VTBX. */
5515 n = (insn >> 5) & 0x18;
pbrook9ee6e8b2007-11-11 00:04:49 +00005516 if (insn & (1 << 6)) {
pbrook8f8e3aa2008-03-31 03:48:01 +00005517 tmp = neon_load_reg(rd, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00005518 } else {
pbrook8f8e3aa2008-03-31 03:48:01 +00005519 tmp = new_tmp();
5520 tcg_gen_movi_i32(tmp, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00005521 }
pbrook8f8e3aa2008-03-31 03:48:01 +00005522 tmp2 = neon_load_reg(rm, 0);
5523 gen_helper_neon_tbl(tmp2, tmp2, tmp, tcg_const_i32(rn),
5524 tcg_const_i32(n));
pbrook9ee6e8b2007-11-11 00:04:49 +00005525 if (insn & (1 << 6)) {
pbrook8f8e3aa2008-03-31 03:48:01 +00005526 tmp = neon_load_reg(rd, 1);
pbrook9ee6e8b2007-11-11 00:04:49 +00005527 } else {
pbrook8f8e3aa2008-03-31 03:48:01 +00005528 tmp = new_tmp();
5529 tcg_gen_movi_i32(tmp, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00005530 }
pbrook8f8e3aa2008-03-31 03:48:01 +00005531 tmp3 = neon_load_reg(rm, 1);
5532 gen_helper_neon_tbl(tmp3, tmp3, tmp, tcg_const_i32(rn),
5533 tcg_const_i32(n));
5534 neon_store_reg(rd, 0, tmp2);
5535 neon_store_reg(rd, 1, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00005536 } else if ((insn & 0x380) == 0) {
5537 /* VDUP */
5538 if (insn & (1 << 19)) {
5539 NEON_SET_REG(T0, rm, 1);
5540 } else {
5541 NEON_SET_REG(T0, rm, 0);
5542 }
5543 if (insn & (1 << 16)) {
pbrookad694712008-03-31 03:48:30 +00005544 gen_neon_dup_u8(cpu_T[0], ((insn >> 17) & 3) * 8);
pbrook9ee6e8b2007-11-11 00:04:49 +00005545 } else if (insn & (1 << 17)) {
5546 if ((insn >> 18) & 1)
pbrookad694712008-03-31 03:48:30 +00005547 gen_neon_dup_high16(cpu_T[0]);
pbrook9ee6e8b2007-11-11 00:04:49 +00005548 else
pbrookad694712008-03-31 03:48:30 +00005549 gen_neon_dup_low16(cpu_T[0]);
pbrook9ee6e8b2007-11-11 00:04:49 +00005550 }
5551 for (pass = 0; pass < (q ? 4 : 2); pass++) {
5552 NEON_SET_REG(T0, rd, pass);
5553 }
5554 } else {
5555 return 1;
5556 }
5557 }
5558 }
5559 return 0;
5560}
5561
5562static int disas_coproc_insn(CPUState * env, DisasContext *s, uint32_t insn)
5563{
5564 int cpnum;
5565
5566 cpnum = (insn >> 8) & 0xf;
5567 if (arm_feature(env, ARM_FEATURE_XSCALE)
5568 && ((env->cp15.c15_cpar ^ 0x3fff) & (1 << cpnum)))
5569 return 1;
5570
5571 switch (cpnum) {
5572 case 0:
5573 case 1:
5574 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
5575 return disas_iwmmxt_insn(env, s, insn);
5576 } else if (arm_feature(env, ARM_FEATURE_XSCALE)) {
5577 return disas_dsp_insn(env, s, insn);
5578 }
5579 return 1;
5580 case 10:
5581 case 11:
5582 return disas_vfp_insn (env, s, insn);
5583 case 15:
5584 return disas_cp15_insn (env, s, insn);
5585 default:
5586 /* Unknown coprocessor. See if the board has hooked it. */
5587 return disas_cp_insn (env, s, insn);
5588 }
5589}
5590
pbrook5e3f8782008-03-31 03:47:34 +00005591
5592/* Store a 64-bit value to a register pair. Clobbers val. */
5593static void gen_storeq_reg(DisasContext *s, int rlow, int rhigh, TCGv val)
5594{
5595 TCGv tmp;
5596 tmp = new_tmp();
5597 tcg_gen_trunc_i64_i32(tmp, val);
5598 store_reg(s, rlow, tmp);
5599 tmp = new_tmp();
5600 tcg_gen_shri_i64(val, val, 32);
5601 tcg_gen_trunc_i64_i32(tmp, val);
5602 store_reg(s, rhigh, tmp);
5603}
5604
5605/* load a 32-bit value from a register and perform a 64-bit accumulate. */
5606static void gen_addq_lo(DisasContext *s, TCGv val, int rlow)
5607{
5608 TCGv tmp;
5609 TCGv tmp2;
5610
5611 /* Load 64-bit value rd:rn. */
5612 tmp = tcg_temp_new(TCG_TYPE_I64);
5613 tmp2 = load_reg(s, rlow);
5614 tcg_gen_extu_i32_i64(tmp, tmp2);
5615 dead_tmp(tmp2);
5616 tcg_gen_add_i64(val, val, tmp);
5617}
5618
5619/* load and add a 64-bit value from a register pair. */
5620static void gen_addq(DisasContext *s, TCGv val, int rlow, int rhigh)
5621{
5622 TCGv tmp;
5623 TCGv tmp2;
5624
5625 /* Load 64-bit value rd:rn. */
5626 tmp = tcg_temp_new(TCG_TYPE_I64);
5627 tmp2 = load_reg(s, rhigh);
5628 tcg_gen_extu_i32_i64(tmp, tmp2);
5629 dead_tmp(tmp2);
5630 tcg_gen_shli_i64(tmp, tmp, 32);
5631 tcg_gen_add_i64(val, val, tmp);
5632
5633 tmp2 = load_reg(s, rlow);
5634 tcg_gen_extu_i32_i64(tmp, tmp2);
5635 dead_tmp(tmp2);
5636 tcg_gen_add_i64(val, val, tmp);
5637}
5638
5639/* Set N and Z flags from a 64-bit value. */
5640static void gen_logicq_cc(TCGv val)
5641{
5642 TCGv tmp = new_tmp();
5643 gen_helper_logicq_cc(tmp, val);
5644 store_cpu_field(tmp, NZF);
5645}
5646
bellardb7bcbe92005-02-22 19:27:29 +00005647static void disas_arm_insn(CPUState * env, DisasContext *s)
bellard2c0262a2003-09-30 20:34:21 +00005648{
5649 unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;
pbrookb26eefb2008-03-31 03:44:26 +00005650 TCGv tmp;
pbrook36706692008-03-31 03:46:19 +00005651 TCGv tmp2;
pbrook6ddbc6e2008-03-31 03:46:33 +00005652 TCGv tmp3;
pbrookb0109802008-03-31 03:47:03 +00005653 TCGv addr;
ths3b46e622007-09-17 08:09:54 +00005654
bellardb5ff1b32005-11-26 10:38:39 +00005655 insn = ldl_code(s->pc);
bellard2c0262a2003-09-30 20:34:21 +00005656 s->pc += 4;
ths3b46e622007-09-17 08:09:54 +00005657
pbrook9ee6e8b2007-11-11 00:04:49 +00005658 /* M variants do not implement ARM mode. */
5659 if (IS_M(env))
5660 goto illegal_op;
bellard2c0262a2003-09-30 20:34:21 +00005661 cond = insn >> 28;
bellard99c475a2005-01-31 20:45:13 +00005662 if (cond == 0xf){
bellardb7bcbe92005-02-22 19:27:29 +00005663 /* Unconditional instructions. */
pbrook9ee6e8b2007-11-11 00:04:49 +00005664 if (((insn >> 25) & 7) == 1) {
5665 /* NEON Data processing. */
5666 if (!arm_feature(env, ARM_FEATURE_NEON))
5667 goto illegal_op;
5668
5669 if (disas_neon_data_insn(env, s, insn))
5670 goto illegal_op;
5671 return;
5672 }
5673 if ((insn & 0x0f100000) == 0x04000000) {
5674 /* NEON load/store. */
5675 if (!arm_feature(env, ARM_FEATURE_NEON))
5676 goto illegal_op;
5677
5678 if (disas_neon_ls_insn(env, s, insn))
5679 goto illegal_op;
5680 return;
5681 }
bellard99c475a2005-01-31 20:45:13 +00005682 if ((insn & 0x0d70f000) == 0x0550f000)
5683 return; /* PLD */
pbrook9ee6e8b2007-11-11 00:04:49 +00005684 else if ((insn & 0x0ffffdff) == 0x01010000) {
5685 ARCH(6);
5686 /* setend */
5687 if (insn & (1 << 9)) {
5688 /* BE8 mode not implemented. */
5689 goto illegal_op;
5690 }
5691 return;
5692 } else if ((insn & 0x0fffff00) == 0x057ff000) {
5693 switch ((insn >> 4) & 0xf) {
5694 case 1: /* clrex */
5695 ARCH(6K);
pbrook8f8e3aa2008-03-31 03:48:01 +00005696 gen_helper_clrex(cpu_env);
pbrook9ee6e8b2007-11-11 00:04:49 +00005697 return;
5698 case 4: /* dsb */
5699 case 5: /* dmb */
5700 case 6: /* isb */
5701 ARCH(7);
5702 /* We don't emulate caches so these are a no-op. */
5703 return;
5704 default:
5705 goto illegal_op;
5706 }
5707 } else if ((insn & 0x0e5fffe0) == 0x084d0500) {
5708 /* srs */
5709 uint32_t offset;
5710 if (IS_USER(s))
5711 goto illegal_op;
5712 ARCH(6);
5713 op1 = (insn & 0x1f);
5714 if (op1 == (env->uncached_cpsr & CPSR_M)) {
pbrookb0109802008-03-31 03:47:03 +00005715 addr = load_reg(s, 13);
pbrook9ee6e8b2007-11-11 00:04:49 +00005716 } else {
pbrookb0109802008-03-31 03:47:03 +00005717 addr = new_tmp();
5718 gen_helper_get_r13_banked(addr, cpu_env, tcg_const_i32(op1));
pbrook9ee6e8b2007-11-11 00:04:49 +00005719 }
5720 i = (insn >> 23) & 3;
5721 switch (i) {
5722 case 0: offset = -4; break; /* DA */
5723 case 1: offset = -8; break; /* DB */
5724 case 2: offset = 0; break; /* IA */
5725 case 3: offset = 4; break; /* IB */
5726 default: abort();
5727 }
5728 if (offset)
pbrookb0109802008-03-31 03:47:03 +00005729 tcg_gen_addi_i32(addr, addr, offset);
5730 tmp = load_reg(s, 14);
5731 gen_st32(tmp, addr, 0);
5732 tmp = new_tmp();
5733 gen_helper_cpsr_read(tmp);
5734 tcg_gen_addi_i32(addr, addr, 4);
5735 gen_st32(tmp, addr, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00005736 if (insn & (1 << 21)) {
5737 /* Base writeback. */
5738 switch (i) {
5739 case 0: offset = -8; break;
5740 case 1: offset = -4; break;
5741 case 2: offset = 4; break;
5742 case 3: offset = 0; break;
5743 default: abort();
5744 }
5745 if (offset)
pbrookb0109802008-03-31 03:47:03 +00005746 tcg_gen_addi_i32(addr, tmp, offset);
pbrook9ee6e8b2007-11-11 00:04:49 +00005747 if (op1 == (env->uncached_cpsr & CPSR_M)) {
5748 gen_movl_reg_T1(s, 13);
5749 } else {
pbrookb0109802008-03-31 03:47:03 +00005750 gen_helper_set_r13_banked(cpu_env, tcg_const_i32(op1), cpu_T[1]);
pbrook9ee6e8b2007-11-11 00:04:49 +00005751 }
pbrookb0109802008-03-31 03:47:03 +00005752 } else {
5753 dead_tmp(addr);
pbrook9ee6e8b2007-11-11 00:04:49 +00005754 }
5755 } else if ((insn & 0x0e5fffe0) == 0x081d0a00) {
5756 /* rfe */
5757 uint32_t offset;
5758 if (IS_USER(s))
5759 goto illegal_op;
5760 ARCH(6);
5761 rn = (insn >> 16) & 0xf;
pbrookb0109802008-03-31 03:47:03 +00005762 addr = load_reg(s, rn);
pbrook9ee6e8b2007-11-11 00:04:49 +00005763 i = (insn >> 23) & 3;
5764 switch (i) {
pbrookb0109802008-03-31 03:47:03 +00005765 case 0: offset = -4; break; /* DA */
5766 case 1: offset = -8; break; /* DB */
5767 case 2: offset = 0; break; /* IA */
5768 case 3: offset = 4; break; /* IB */
pbrook9ee6e8b2007-11-11 00:04:49 +00005769 default: abort();
5770 }
5771 if (offset)
pbrookb0109802008-03-31 03:47:03 +00005772 tcg_gen_addi_i32(addr, addr, offset);
5773 /* Load PC into tmp and CPSR into tmp2. */
5774 tmp = gen_ld32(addr, 0);
5775 tcg_gen_addi_i32(addr, addr, 4);
5776 tmp2 = gen_ld32(addr, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00005777 if (insn & (1 << 21)) {
5778 /* Base writeback. */
5779 switch (i) {
pbrookb0109802008-03-31 03:47:03 +00005780 case 0: offset = -8; break;
5781 case 1: offset = -4; break;
5782 case 2: offset = 4; break;
5783 case 3: offset = 0; break;
pbrook9ee6e8b2007-11-11 00:04:49 +00005784 default: abort();
5785 }
5786 if (offset)
pbrookb0109802008-03-31 03:47:03 +00005787 tcg_gen_addi_i32(addr, addr, offset);
5788 store_reg(s, rn, addr);
5789 } else {
5790 dead_tmp(addr);
pbrook9ee6e8b2007-11-11 00:04:49 +00005791 }
pbrookb0109802008-03-31 03:47:03 +00005792 gen_rfe(s, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00005793 } else if ((insn & 0x0e000000) == 0x0a000000) {
bellard99c475a2005-01-31 20:45:13 +00005794 /* branch link and change to thumb (blx <offset>) */
5795 int32_t offset;
5796
5797 val = (uint32_t)s->pc;
pbrookd9ba4832008-03-31 03:46:50 +00005798 tmp = new_tmp();
5799 tcg_gen_movi_i32(tmp, val);
5800 store_reg(s, 14, tmp);
bellard99c475a2005-01-31 20:45:13 +00005801 /* Sign-extend the 24-bit offset */
5802 offset = (((int32_t)insn) << 8) >> 8;
5803 /* offset * 4 + bit24 * 2 + (thumb bit) */
5804 val += (offset << 2) | ((insn >> 23) & 2) | 1;
5805 /* pipeline offset */
5806 val += 4;
pbrookd9ba4832008-03-31 03:46:50 +00005807 gen_bx_im(s, val);
bellard99c475a2005-01-31 20:45:13 +00005808 return;
balrog2e232132007-08-01 02:31:54 +00005809 } else if ((insn & 0x0e000f00) == 0x0c000100) {
5810 if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
5811 /* iWMMXt register transfer. */
5812 if (env->cp15.c15_cpar & (1 << 1))
5813 if (!disas_iwmmxt_insn(env, s, insn))
5814 return;
5815 }
bellardb7bcbe92005-02-22 19:27:29 +00005816 } else if ((insn & 0x0fe00000) == 0x0c400000) {
5817 /* Coprocessor double register transfer. */
5818 } else if ((insn & 0x0f000010) == 0x0e000010) {
5819 /* Additional coprocessor register transfer. */
bellardb5ff1b32005-11-26 10:38:39 +00005820 } else if ((insn & 0x0ff10010) == 0x01000000) {
pbrook9ee6e8b2007-11-11 00:04:49 +00005821 uint32_t mask;
5822 uint32_t val;
bellardb5ff1b32005-11-26 10:38:39 +00005823 /* cps (privileged) */
pbrook9ee6e8b2007-11-11 00:04:49 +00005824 if (IS_USER(s))
5825 return;
5826 mask = val = 0;
5827 if (insn & (1 << 19)) {
5828 if (insn & (1 << 8))
5829 mask |= CPSR_A;
5830 if (insn & (1 << 7))
5831 mask |= CPSR_I;
5832 if (insn & (1 << 6))
5833 mask |= CPSR_F;
5834 if (insn & (1 << 18))
5835 val |= mask;
5836 }
5837 if (insn & (1 << 14)) {
5838 mask |= CPSR_M;
5839 val |= (insn & 0x1f);
5840 }
5841 if (mask) {
5842 gen_op_movl_T0_im(val);
5843 gen_set_psr_T0(s, mask, 0);
bellardb5ff1b32005-11-26 10:38:39 +00005844 }
5845 return;
bellard99c475a2005-01-31 20:45:13 +00005846 }
bellard2c0262a2003-09-30 20:34:21 +00005847 goto illegal_op;
bellard99c475a2005-01-31 20:45:13 +00005848 }
bellard2c0262a2003-09-30 20:34:21 +00005849 if (cond != 0xe) {
5850 /* if not always execute, we generate a conditional jump to
5851 next instruction */
bellarde50e6a22005-04-26 20:36:11 +00005852 s->condlabel = gen_new_label();
pbrookd9ba4832008-03-31 03:46:50 +00005853 gen_test_cc(cond ^ 1, s->condlabel);
bellarde50e6a22005-04-26 20:36:11 +00005854 s->condjmp = 1;
bellard2c0262a2003-09-30 20:34:21 +00005855 }
bellard99c475a2005-01-31 20:45:13 +00005856 if ((insn & 0x0f900000) == 0x03000000) {
pbrook9ee6e8b2007-11-11 00:04:49 +00005857 if ((insn & (1 << 21)) == 0) {
5858 ARCH(6T2);
5859 rd = (insn >> 12) & 0xf;
5860 val = ((insn >> 4) & 0xf000) | (insn & 0xfff);
5861 if ((insn & (1 << 22)) == 0) {
5862 /* MOVW */
pbrook5e3f8782008-03-31 03:47:34 +00005863 tmp = new_tmp();
5864 tcg_gen_movi_i32(tmp, val);
pbrook9ee6e8b2007-11-11 00:04:49 +00005865 } else {
5866 /* MOVT */
pbrook5e3f8782008-03-31 03:47:34 +00005867 tmp = load_reg(s, rd);
5868 tcg_gen_andi_i32(tmp, tmp, 0xffff);
5869 tcg_gen_ori_i32(tmp, tmp, val << 16);
pbrook9ee6e8b2007-11-11 00:04:49 +00005870 }
pbrook5e3f8782008-03-31 03:47:34 +00005871 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00005872 } else {
5873 if (((insn >> 12) & 0xf) != 0xf)
5874 goto illegal_op;
5875 if (((insn >> 16) & 0xf) == 0) {
5876 gen_nop_hint(s, insn & 0xff);
5877 } else {
5878 /* CPSR = immediate */
5879 val = insn & 0xff;
5880 shift = ((insn >> 8) & 0xf) * 2;
5881 if (shift)
5882 val = (val >> shift) | (val << (32 - shift));
5883 gen_op_movl_T0_im(val);
5884 i = ((insn & (1 << 22)) != 0);
5885 if (gen_set_psr_T0(s, msr_mask(env, s, (insn >> 16) & 0xf, i), i))
5886 goto illegal_op;
5887 }
5888 }
bellard99c475a2005-01-31 20:45:13 +00005889 } else if ((insn & 0x0f900000) == 0x01000000
5890 && (insn & 0x00000090) != 0x00000090) {
5891 /* miscellaneous instructions */
5892 op1 = (insn >> 21) & 3;
5893 sh = (insn >> 4) & 0xf;
5894 rm = insn & 0xf;
5895 switch (sh) {
5896 case 0x0: /* move program status register */
bellard99c475a2005-01-31 20:45:13 +00005897 if (op1 & 1) {
bellardb5ff1b32005-11-26 10:38:39 +00005898 /* PSR = reg */
bellard99c475a2005-01-31 20:45:13 +00005899 gen_movl_T0_reg(s, rm);
pbrook2ae23e72006-02-11 16:20:39 +00005900 i = ((op1 & 2) != 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00005901 if (gen_set_psr_T0(s, msr_mask(env, s, (insn >> 16) & 0xf, i), i))
bellardb5ff1b32005-11-26 10:38:39 +00005902 goto illegal_op;
bellard99c475a2005-01-31 20:45:13 +00005903 } else {
pbrook2ae23e72006-02-11 16:20:39 +00005904 /* reg = PSR */
bellard99c475a2005-01-31 20:45:13 +00005905 rd = (insn >> 12) & 0xf;
bellardb5ff1b32005-11-26 10:38:39 +00005906 if (op1 & 2) {
5907 if (IS_USER(s))
5908 goto illegal_op;
pbrookd9ba4832008-03-31 03:46:50 +00005909 tmp = load_cpu_field(spsr);
bellardb5ff1b32005-11-26 10:38:39 +00005910 } else {
pbrookd9ba4832008-03-31 03:46:50 +00005911 tmp = new_tmp();
5912 gen_helper_cpsr_read(tmp);
bellardb5ff1b32005-11-26 10:38:39 +00005913 }
pbrookd9ba4832008-03-31 03:46:50 +00005914 store_reg(s, rd, tmp);
bellard99c475a2005-01-31 20:45:13 +00005915 }
bellardb8a9e8f2005-02-07 23:10:07 +00005916 break;
bellard99c475a2005-01-31 20:45:13 +00005917 case 0x1:
5918 if (op1 == 1) {
5919 /* branch/exchange thumb (bx). */
pbrookd9ba4832008-03-31 03:46:50 +00005920 tmp = load_reg(s, rm);
5921 gen_bx(s, tmp);
bellard99c475a2005-01-31 20:45:13 +00005922 } else if (op1 == 3) {
5923 /* clz */
5924 rd = (insn >> 12) & 0xf;
pbrook1497c962008-03-31 03:45:50 +00005925 tmp = load_reg(s, rm);
5926 gen_helper_clz(tmp, tmp);
5927 store_reg(s, rd, tmp);
bellard99c475a2005-01-31 20:45:13 +00005928 } else {
5929 goto illegal_op;
5930 }
5931 break;
bellardb5ff1b32005-11-26 10:38:39 +00005932 case 0x2:
5933 if (op1 == 1) {
5934 ARCH(5J); /* bxj */
5935 /* Trivial implementation equivalent to bx. */
pbrookd9ba4832008-03-31 03:46:50 +00005936 tmp = load_reg(s, rm);
5937 gen_bx(s, tmp);
bellardb5ff1b32005-11-26 10:38:39 +00005938 } else {
5939 goto illegal_op;
5940 }
5941 break;
bellard99c475a2005-01-31 20:45:13 +00005942 case 0x3:
5943 if (op1 != 1)
5944 goto illegal_op;
5945
5946 /* branch link/exchange thumb (blx) */
pbrookd9ba4832008-03-31 03:46:50 +00005947 tmp = load_reg(s, rm);
5948 tmp2 = new_tmp();
5949 tcg_gen_movi_i32(tmp2, s->pc);
5950 store_reg(s, 14, tmp2);
5951 gen_bx(s, tmp);
bellard99c475a2005-01-31 20:45:13 +00005952 break;
5953 case 0x5: /* saturating add/subtract */
5954 rd = (insn >> 12) & 0xf;
5955 rn = (insn >> 16) & 0xf;
pbrook5e3f8782008-03-31 03:47:34 +00005956 tmp = load_reg(s, rn);
5957 tmp2 = load_reg(s, rn);
bellardff8263a2005-05-13 22:45:23 +00005958 if (op1 & 2)
pbrook5e3f8782008-03-31 03:47:34 +00005959 gen_helper_double_saturate(tmp2, tmp2);
bellard99c475a2005-01-31 20:45:13 +00005960 if (op1 & 1)
pbrook5e3f8782008-03-31 03:47:34 +00005961 gen_helper_sub_saturate(tmp, tmp, tmp2);
bellard99c475a2005-01-31 20:45:13 +00005962 else
pbrook5e3f8782008-03-31 03:47:34 +00005963 gen_helper_add_saturate(tmp, tmp, tmp2);
5964 dead_tmp(tmp2);
5965 store_reg(s, rd, tmp);
bellard99c475a2005-01-31 20:45:13 +00005966 break;
pbrook06c949e2006-02-04 19:35:26 +00005967 case 7: /* bkpt */
pbrook9ee6e8b2007-11-11 00:04:49 +00005968 gen_set_condexec(s);
pbrook5e3f8782008-03-31 03:47:34 +00005969 gen_set_pc_im(s->pc - 4);
pbrookd9ba4832008-03-31 03:46:50 +00005970 gen_exception(EXCP_BKPT);
pbrook06c949e2006-02-04 19:35:26 +00005971 s->is_jmp = DISAS_JUMP;
5972 break;
bellard99c475a2005-01-31 20:45:13 +00005973 case 0x8: /* signed multiply */
5974 case 0xa:
5975 case 0xc:
5976 case 0xe:
5977 rs = (insn >> 8) & 0xf;
5978 rn = (insn >> 12) & 0xf;
5979 rd = (insn >> 16) & 0xf;
5980 if (op1 == 1) {
5981 /* (32 * 16) >> 16 */
pbrook5e3f8782008-03-31 03:47:34 +00005982 tmp = load_reg(s, rm);
5983 tmp2 = load_reg(s, rs);
bellard99c475a2005-01-31 20:45:13 +00005984 if (sh & 4)
pbrook5e3f8782008-03-31 03:47:34 +00005985 tcg_gen_sari_i32(tmp2, tmp2, 16);
bellard99c475a2005-01-31 20:45:13 +00005986 else
pbrook5e3f8782008-03-31 03:47:34 +00005987 gen_sxth(tmp2);
5988 tmp2 = gen_muls_i64_i32(tmp, tmp2);
5989 tcg_gen_shri_i64(tmp2, tmp2, 16);
5990 tmp = new_tmp();
5991 tcg_gen_trunc_i64_i32(tmp, tmp2);
bellard99c475a2005-01-31 20:45:13 +00005992 if ((sh & 2) == 0) {
pbrook5e3f8782008-03-31 03:47:34 +00005993 tmp2 = load_reg(s, rn);
5994 gen_helper_add_setq(tmp, tmp, tmp2);
5995 dead_tmp(tmp2);
bellard99c475a2005-01-31 20:45:13 +00005996 }
pbrook5e3f8782008-03-31 03:47:34 +00005997 store_reg(s, rd, tmp);
bellard99c475a2005-01-31 20:45:13 +00005998 } else {
5999 /* 16 * 16 */
pbrook5e3f8782008-03-31 03:47:34 +00006000 tmp = load_reg(s, rm);
6001 tmp2 = load_reg(s, rs);
6002 gen_mulxy(tmp, tmp2, sh & 2, sh & 4);
6003 dead_tmp(tmp2);
bellard99c475a2005-01-31 20:45:13 +00006004 if (op1 == 2) {
pbrook5e3f8782008-03-31 03:47:34 +00006005 tmp = tcg_temp_new(TCG_TYPE_I64);
6006 tcg_gen_ext_i32_i64(tmp, cpu_T[0]);
6007 gen_addq(s, tmp, rn, rd);
6008 gen_storeq_reg(s, rn, rd, tmp);
bellard99c475a2005-01-31 20:45:13 +00006009 } else {
bellard99c475a2005-01-31 20:45:13 +00006010 if (op1 == 0) {
pbrook5e3f8782008-03-31 03:47:34 +00006011 tmp2 = load_reg(s, rn);
6012 gen_helper_add_setq(tmp, tmp, tmp2);
6013 dead_tmp(tmp2);
bellard99c475a2005-01-31 20:45:13 +00006014 }
pbrook5e3f8782008-03-31 03:47:34 +00006015 store_reg(s, rd, tmp);
bellard99c475a2005-01-31 20:45:13 +00006016 }
6017 }
6018 break;
6019 default:
6020 goto illegal_op;
6021 }
6022 } else if (((insn & 0x0e000000) == 0 &&
6023 (insn & 0x00000090) != 0x90) ||
6024 ((insn & 0x0e000000) == (1 << 25))) {
bellard2c0262a2003-09-30 20:34:21 +00006025 int set_cc, logic_cc, shiftop;
ths3b46e622007-09-17 08:09:54 +00006026
bellard2c0262a2003-09-30 20:34:21 +00006027 op1 = (insn >> 21) & 0xf;
6028 set_cc = (insn >> 20) & 1;
6029 logic_cc = table_logic_cc[op1] & set_cc;
6030
6031 /* data processing instruction */
6032 if (insn & (1 << 25)) {
6033 /* immediate operand */
6034 val = insn & 0xff;
6035 shift = ((insn >> 8) & 0xf) * 2;
6036 if (shift)
6037 val = (val >> shift) | (val << (32 - shift));
6038 gen_op_movl_T1_im(val);
bellard7ff4d212005-02-07 12:42:35 +00006039 if (logic_cc && shift)
pbrookb26eefb2008-03-31 03:44:26 +00006040 gen_set_CF_bit31(cpu_T[1]);
bellard2c0262a2003-09-30 20:34:21 +00006041 } else {
6042 /* register */
6043 rm = (insn) & 0xf;
6044 gen_movl_T1_reg(s, rm);
6045 shiftop = (insn >> 5) & 3;
6046 if (!(insn & (1 << 4))) {
6047 shift = (insn >> 7) & 0x1f;
pbrook9a119ff2008-03-31 03:45:35 +00006048 gen_arm_shift_im(cpu_T[1], shiftop, shift, logic_cc);
bellard2c0262a2003-09-30 20:34:21 +00006049 } else {
6050 rs = (insn >> 8) & 0xf;
pbrook8984bd22008-03-31 03:47:48 +00006051 tmp = load_reg(s, rs);
6052 gen_arm_shift_reg(cpu_T[1], shiftop, tmp, logic_cc);
bellard2c0262a2003-09-30 20:34:21 +00006053 }
6054 }
6055 if (op1 != 0x0f && op1 != 0x0d) {
6056 rn = (insn >> 16) & 0xf;
6057 gen_movl_T0_reg(s, rn);
6058 }
6059 rd = (insn >> 12) & 0xf;
6060 switch(op1) {
6061 case 0x00:
6062 gen_op_andl_T0_T1();
6063 gen_movl_reg_T0(s, rd);
6064 if (logic_cc)
6065 gen_op_logic_T0_cc();
6066 break;
6067 case 0x01:
6068 gen_op_xorl_T0_T1();
6069 gen_movl_reg_T0(s, rd);
6070 if (logic_cc)
6071 gen_op_logic_T0_cc();
6072 break;
6073 case 0x02:
bellardb5ff1b32005-11-26 10:38:39 +00006074 if (set_cc && rd == 15) {
6075 /* SUBS r15, ... is used for exception return. */
6076 if (IS_USER(s))
6077 goto illegal_op;
bellard2c0262a2003-09-30 20:34:21 +00006078 gen_op_subl_T0_T1_cc();
bellardb5ff1b32005-11-26 10:38:39 +00006079 gen_exception_return(s);
6080 } else {
6081 if (set_cc)
6082 gen_op_subl_T0_T1_cc();
6083 else
6084 gen_op_subl_T0_T1();
6085 gen_movl_reg_T0(s, rd);
6086 }
bellard2c0262a2003-09-30 20:34:21 +00006087 break;
6088 case 0x03:
6089 if (set_cc)
6090 gen_op_rsbl_T0_T1_cc();
6091 else
6092 gen_op_rsbl_T0_T1();
6093 gen_movl_reg_T0(s, rd);
6094 break;
6095 case 0x04:
6096 if (set_cc)
6097 gen_op_addl_T0_T1_cc();
6098 else
6099 gen_op_addl_T0_T1();
6100 gen_movl_reg_T0(s, rd);
6101 break;
6102 case 0x05:
6103 if (set_cc)
6104 gen_op_adcl_T0_T1_cc();
6105 else
pbrookb26eefb2008-03-31 03:44:26 +00006106 gen_adc_T0_T1();
bellard2c0262a2003-09-30 20:34:21 +00006107 gen_movl_reg_T0(s, rd);
6108 break;
6109 case 0x06:
6110 if (set_cc)
6111 gen_op_sbcl_T0_T1_cc();
6112 else
pbrook36706692008-03-31 03:46:19 +00006113 gen_sbc_T0_T1();
bellard2c0262a2003-09-30 20:34:21 +00006114 gen_movl_reg_T0(s, rd);
6115 break;
6116 case 0x07:
6117 if (set_cc)
6118 gen_op_rscl_T0_T1_cc();
6119 else
pbrook36706692008-03-31 03:46:19 +00006120 gen_rsc_T0_T1();
bellard2c0262a2003-09-30 20:34:21 +00006121 gen_movl_reg_T0(s, rd);
6122 break;
6123 case 0x08:
6124 if (set_cc) {
6125 gen_op_andl_T0_T1();
6126 gen_op_logic_T0_cc();
6127 }
6128 break;
6129 case 0x09:
6130 if (set_cc) {
6131 gen_op_xorl_T0_T1();
6132 gen_op_logic_T0_cc();
6133 }
6134 break;
6135 case 0x0a:
6136 if (set_cc) {
6137 gen_op_subl_T0_T1_cc();
6138 }
6139 break;
6140 case 0x0b:
6141 if (set_cc) {
6142 gen_op_addl_T0_T1_cc();
6143 }
6144 break;
6145 case 0x0c:
6146 gen_op_orl_T0_T1();
6147 gen_movl_reg_T0(s, rd);
6148 if (logic_cc)
6149 gen_op_logic_T0_cc();
6150 break;
6151 case 0x0d:
bellardb5ff1b32005-11-26 10:38:39 +00006152 if (logic_cc && rd == 15) {
6153 /* MOVS r15, ... is used for exception return. */
6154 if (IS_USER(s))
6155 goto illegal_op;
6156 gen_op_movl_T0_T1();
6157 gen_exception_return(s);
6158 } else {
6159 gen_movl_reg_T1(s, rd);
6160 if (logic_cc)
6161 gen_op_logic_T1_cc();
6162 }
bellard2c0262a2003-09-30 20:34:21 +00006163 break;
6164 case 0x0e:
6165 gen_op_bicl_T0_T1();
6166 gen_movl_reg_T0(s, rd);
6167 if (logic_cc)
6168 gen_op_logic_T0_cc();
6169 break;
6170 default:
6171 case 0x0f:
6172 gen_op_notl_T1();
6173 gen_movl_reg_T1(s, rd);
6174 if (logic_cc)
6175 gen_op_logic_T1_cc();
6176 break;
6177 }
6178 } else {
6179 /* other instructions */
6180 op1 = (insn >> 24) & 0xf;
6181 switch(op1) {
6182 case 0x0:
6183 case 0x1:
bellard99c475a2005-01-31 20:45:13 +00006184 /* multiplies, extra load/stores */
bellard2c0262a2003-09-30 20:34:21 +00006185 sh = (insn >> 5) & 3;
6186 if (sh == 0) {
6187 if (op1 == 0x0) {
6188 rd = (insn >> 16) & 0xf;
6189 rn = (insn >> 12) & 0xf;
6190 rs = (insn >> 8) & 0xf;
6191 rm = (insn) & 0xf;
pbrook9ee6e8b2007-11-11 00:04:49 +00006192 op1 = (insn >> 20) & 0xf;
6193 switch (op1) {
6194 case 0: case 1: case 2: case 3: case 6:
bellard2c0262a2003-09-30 20:34:21 +00006195 /* 32 bit mul */
pbrook5e3f8782008-03-31 03:47:34 +00006196 tmp = load_reg(s, rs);
6197 tmp2 = load_reg(s, rm);
6198 tcg_gen_mul_i32(tmp, tmp, tmp2);
6199 dead_tmp(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00006200 if (insn & (1 << 22)) {
6201 /* Subtract (mls) */
6202 ARCH(6T2);
pbrook5e3f8782008-03-31 03:47:34 +00006203 tmp2 = load_reg(s, rn);
6204 tcg_gen_sub_i32(tmp, tmp2, tmp);
6205 dead_tmp(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00006206 } else if (insn & (1 << 21)) {
6207 /* Add */
pbrook5e3f8782008-03-31 03:47:34 +00006208 tmp2 = load_reg(s, rn);
6209 tcg_gen_add_i32(tmp, tmp, tmp2);
6210 dead_tmp(tmp2);
bellard2c0262a2003-09-30 20:34:21 +00006211 }
ths5fafdf22007-09-16 21:08:06 +00006212 if (insn & (1 << 20))
pbrook5e3f8782008-03-31 03:47:34 +00006213 gen_logic_CC(tmp);
6214 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006215 break;
6216 default:
bellard2c0262a2003-09-30 20:34:21 +00006217 /* 64 bit mul */
pbrook5e3f8782008-03-31 03:47:34 +00006218 tmp = load_reg(s, rs);
6219 tmp2 = load_reg(s, rm);
ths5fafdf22007-09-16 21:08:06 +00006220 if (insn & (1 << 22))
pbrook5e3f8782008-03-31 03:47:34 +00006221 tmp = gen_muls_i64_i32(tmp, tmp2);
bellard2e134c92003-11-11 13:55:33 +00006222 else
pbrook5e3f8782008-03-31 03:47:34 +00006223 tmp = gen_mulu_i64_i32(tmp, tmp2);
bellard99c475a2005-01-31 20:45:13 +00006224 if (insn & (1 << 21)) /* mult accumulate */
pbrook5e3f8782008-03-31 03:47:34 +00006225 gen_addq(s, tmp, rn, rd);
bellard99c475a2005-01-31 20:45:13 +00006226 if (!(insn & (1 << 23))) { /* double accumulate */
bellardb5ff1b32005-11-26 10:38:39 +00006227 ARCH(6);
pbrook5e3f8782008-03-31 03:47:34 +00006228 gen_addq_lo(s, tmp, rn);
6229 gen_addq_lo(s, tmp, rd);
bellard99c475a2005-01-31 20:45:13 +00006230 }
ths5fafdf22007-09-16 21:08:06 +00006231 if (insn & (1 << 20))
pbrook5e3f8782008-03-31 03:47:34 +00006232 gen_logicq_cc(tmp);
6233 gen_storeq_reg(s, rn, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006234 break;
bellard2c0262a2003-09-30 20:34:21 +00006235 }
6236 } else {
bellard2c0262a2003-09-30 20:34:21 +00006237 rn = (insn >> 16) & 0xf;
6238 rd = (insn >> 12) & 0xf;
bellard99c475a2005-01-31 20:45:13 +00006239 if (insn & (1 << 23)) {
6240 /* load/store exclusive */
pbrook9ee6e8b2007-11-11 00:04:49 +00006241 gen_movl_T1_reg(s, rn);
6242 if (insn & (1 << 20)) {
pbrook8f8e3aa2008-03-31 03:48:01 +00006243 gen_helper_mark_exclusive(cpu_env, cpu_T[1]);
6244 tmp = gen_ld32(addr, IS_USER(s));
6245 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006246 } else {
pbrook8f8e3aa2008-03-31 03:48:01 +00006247 int label = gen_new_label();
pbrook9ee6e8b2007-11-11 00:04:49 +00006248 rm = insn & 0xf;
pbrook8f8e3aa2008-03-31 03:48:01 +00006249 gen_helper_test_exclusive(cpu_T[0], cpu_env, addr);
6250 tcg_gen_brcond_i32(TCG_COND_NE, cpu_T[0],
6251 tcg_const_i32(0), label);
6252 tmp = load_reg(s,rm);
6253 gen_st32(tmp, cpu_T[1], IS_USER(s));
6254 gen_movl_reg_T0(s, rd);
pbrook9ee6e8b2007-11-11 00:04:49 +00006255 }
bellard2c0262a2003-09-30 20:34:21 +00006256 } else {
bellard99c475a2005-01-31 20:45:13 +00006257 /* SWP instruction */
6258 rm = (insn) & 0xf;
ths3b46e622007-09-17 08:09:54 +00006259
pbrook8984bd22008-03-31 03:47:48 +00006260 /* ??? This is not really atomic. However we know
6261 we never have multiple CPUs running in parallel,
6262 so it is good enough. */
6263 addr = load_reg(s, rn);
6264 tmp = load_reg(s, rm);
bellard99c475a2005-01-31 20:45:13 +00006265 if (insn & (1 << 22)) {
pbrook8984bd22008-03-31 03:47:48 +00006266 tmp2 = gen_ld8u(addr, IS_USER(s));
6267 gen_st8(tmp, addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00006268 } else {
pbrook8984bd22008-03-31 03:47:48 +00006269 tmp2 = gen_ld32(addr, IS_USER(s));
6270 gen_st32(tmp, addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00006271 }
pbrook8984bd22008-03-31 03:47:48 +00006272 dead_tmp(addr);
6273 store_reg(s, rd, tmp2);
bellard2c0262a2003-09-30 20:34:21 +00006274 }
bellard2c0262a2003-09-30 20:34:21 +00006275 }
6276 } else {
pbrook191f9a92006-06-14 14:36:07 +00006277 int address_offset;
pbrook5fd46862007-03-17 01:43:01 +00006278 int load;
bellard99c475a2005-01-31 20:45:13 +00006279 /* Misc load/store */
bellard2c0262a2003-09-30 20:34:21 +00006280 rn = (insn >> 16) & 0xf;
6281 rd = (insn >> 12) & 0xf;
pbrookb0109802008-03-31 03:47:03 +00006282 addr = load_reg(s, rn);
bellardbeddab72004-05-05 18:36:10 +00006283 if (insn & (1 << 24))
pbrookb0109802008-03-31 03:47:03 +00006284 gen_add_datah_offset(s, insn, 0, addr);
pbrook191f9a92006-06-14 14:36:07 +00006285 address_offset = 0;
bellard2c0262a2003-09-30 20:34:21 +00006286 if (insn & (1 << 20)) {
6287 /* load */
6288 switch(sh) {
6289 case 1:
pbrookb0109802008-03-31 03:47:03 +00006290 tmp = gen_ld16u(addr, IS_USER(s));
bellard2c0262a2003-09-30 20:34:21 +00006291 break;
6292 case 2:
pbrookb0109802008-03-31 03:47:03 +00006293 tmp = gen_ld8s(addr, IS_USER(s));
bellard2c0262a2003-09-30 20:34:21 +00006294 break;
6295 default:
6296 case 3:
pbrookb0109802008-03-31 03:47:03 +00006297 tmp = gen_ld16s(addr, IS_USER(s));
bellard2c0262a2003-09-30 20:34:21 +00006298 break;
6299 }
pbrook5fd46862007-03-17 01:43:01 +00006300 load = 1;
bellard99c475a2005-01-31 20:45:13 +00006301 } else if (sh & 2) {
6302 /* doubleword */
6303 if (sh & 1) {
6304 /* store */
pbrookb0109802008-03-31 03:47:03 +00006305 tmp = load_reg(s, rd);
6306 gen_st32(tmp, addr, IS_USER(s));
6307 tcg_gen_addi_i32(addr, addr, 4);
6308 tmp = load_reg(s, rd + 1);
6309 gen_st32(tmp, addr, IS_USER(s));
pbrook5fd46862007-03-17 01:43:01 +00006310 load = 0;
bellard99c475a2005-01-31 20:45:13 +00006311 } else {
6312 /* load */
pbrookb0109802008-03-31 03:47:03 +00006313 tmp = gen_ld32(addr, IS_USER(s));
6314 store_reg(s, rd, tmp);
6315 tcg_gen_addi_i32(addr, addr, 4);
6316 tmp = gen_ld32(addr, IS_USER(s));
pbrook5fd46862007-03-17 01:43:01 +00006317 rd++;
6318 load = 1;
bellard99c475a2005-01-31 20:45:13 +00006319 }
pbrook191f9a92006-06-14 14:36:07 +00006320 address_offset = -4;
bellard2c0262a2003-09-30 20:34:21 +00006321 } else {
6322 /* store */
pbrookb0109802008-03-31 03:47:03 +00006323 tmp = load_reg(s, rd);
6324 gen_st16(tmp, addr, IS_USER(s));
pbrook5fd46862007-03-17 01:43:01 +00006325 load = 0;
bellard2c0262a2003-09-30 20:34:21 +00006326 }
pbrook5fd46862007-03-17 01:43:01 +00006327 /* Perform base writeback before the loaded value to
6328 ensure correct behavior with overlapping index registers.
6329 ldrd with base writeback is is undefined if the
6330 destination and index registers overlap. */
bellard2c0262a2003-09-30 20:34:21 +00006331 if (!(insn & (1 << 24))) {
pbrookb0109802008-03-31 03:47:03 +00006332 gen_add_datah_offset(s, insn, address_offset, addr);
6333 store_reg(s, rn, addr);
bellard2c0262a2003-09-30 20:34:21 +00006334 } else if (insn & (1 << 21)) {
pbrook191f9a92006-06-14 14:36:07 +00006335 if (address_offset)
pbrookb0109802008-03-31 03:47:03 +00006336 tcg_gen_addi_i32(addr, addr, address_offset);
6337 store_reg(s, rn, addr);
6338 } else {
6339 dead_tmp(addr);
bellard2c0262a2003-09-30 20:34:21 +00006340 }
pbrook5fd46862007-03-17 01:43:01 +00006341 if (load) {
6342 /* Complete the load. */
pbrookb0109802008-03-31 03:47:03 +00006343 store_reg(s, rd, tmp);
pbrook5fd46862007-03-17 01:43:01 +00006344 }
bellard2c0262a2003-09-30 20:34:21 +00006345 }
6346 break;
6347 case 0x4:
6348 case 0x5:
pbrook9ee6e8b2007-11-11 00:04:49 +00006349 goto do_ldst;
bellard2c0262a2003-09-30 20:34:21 +00006350 case 0x6:
6351 case 0x7:
pbrook9ee6e8b2007-11-11 00:04:49 +00006352 if (insn & (1 << 4)) {
6353 ARCH(6);
6354 /* Armv6 Media instructions. */
6355 rm = insn & 0xf;
6356 rn = (insn >> 16) & 0xf;
6357 rd = (insn >> 12) & 0xf;
6358 rs = (insn >> 8) & 0xf;
6359 switch ((insn >> 23) & 3) {
6360 case 0: /* Parallel add/subtract. */
6361 op1 = (insn >> 20) & 7;
pbrook6ddbc6e2008-03-31 03:46:33 +00006362 tmp = load_reg(s, rn);
6363 tmp2 = load_reg(s, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00006364 sh = (insn >> 5) & 7;
6365 if ((op1 & 3) == 0 || sh == 5 || sh == 6)
6366 goto illegal_op;
pbrook6ddbc6e2008-03-31 03:46:33 +00006367 gen_arm_parallel_addsub(op1, sh, tmp, tmp2);
6368 dead_tmp(tmp2);
6369 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006370 break;
6371 case 1:
6372 if ((insn & 0x00700020) == 0) {
6373 /* Hafword pack. */
pbrook36706692008-03-31 03:46:19 +00006374 tmp = load_reg(s, rn);
6375 tmp2 = load_reg(s, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00006376 shift = (insn >> 7) & 0x1f;
6377 if (shift)
pbrook36706692008-03-31 03:46:19 +00006378 tcg_gen_shli_i32(tmp2, tmp2, shift);
6379 if (insn & (1 << 6)) {
6380 /* pkhtb */
6381 tcg_gen_andi_i32(tmp, tmp, 0xffff0000);
6382 tcg_gen_andi_i32(tmp2, tmp2, 0xffff);
6383 } else {
6384 /* pkhbt */
6385 tcg_gen_andi_i32(tmp, tmp, 0xffff);
6386 tcg_gen_andi_i32(tmp2, tmp2, 0xffff0000);
6387 }
6388 tcg_gen_or_i32(tmp, tmp, tmp2);
6389 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006390 } else if ((insn & 0x00200020) == 0x00200000) {
6391 /* [us]sat */
pbrook6ddbc6e2008-03-31 03:46:33 +00006392 tmp = load_reg(s, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00006393 shift = (insn >> 7) & 0x1f;
6394 if (insn & (1 << 6)) {
6395 if (shift == 0)
6396 shift = 31;
pbrook6ddbc6e2008-03-31 03:46:33 +00006397 tcg_gen_sari_i32(tmp, tmp, shift);
pbrook9ee6e8b2007-11-11 00:04:49 +00006398 } else {
pbrook6ddbc6e2008-03-31 03:46:33 +00006399 tcg_gen_shli_i32(tmp, tmp, shift);
pbrook9ee6e8b2007-11-11 00:04:49 +00006400 }
6401 sh = (insn >> 16) & 0x1f;
6402 if (sh != 0) {
6403 if (insn & (1 << 22))
pbrook6ddbc6e2008-03-31 03:46:33 +00006404 gen_helper_usat(tmp, tmp, tcg_const_i32(sh));
pbrook9ee6e8b2007-11-11 00:04:49 +00006405 else
pbrook6ddbc6e2008-03-31 03:46:33 +00006406 gen_helper_ssat(tmp, tmp, tcg_const_i32(sh));
pbrook9ee6e8b2007-11-11 00:04:49 +00006407 }
pbrook6ddbc6e2008-03-31 03:46:33 +00006408 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006409 } else if ((insn & 0x00300fe0) == 0x00200f20) {
6410 /* [us]sat16 */
pbrook6ddbc6e2008-03-31 03:46:33 +00006411 tmp = load_reg(s, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00006412 sh = (insn >> 16) & 0x1f;
6413 if (sh != 0) {
6414 if (insn & (1 << 22))
pbrook6ddbc6e2008-03-31 03:46:33 +00006415 gen_helper_usat16(tmp, tmp, tcg_const_i32(sh));
pbrook9ee6e8b2007-11-11 00:04:49 +00006416 else
pbrook6ddbc6e2008-03-31 03:46:33 +00006417 gen_helper_ssat16(tmp, tmp, tcg_const_i32(sh));
pbrook9ee6e8b2007-11-11 00:04:49 +00006418 }
pbrook6ddbc6e2008-03-31 03:46:33 +00006419 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006420 } else if ((insn & 0x00700fe0) == 0x00000fa0) {
6421 /* Select bytes. */
pbrook6ddbc6e2008-03-31 03:46:33 +00006422 tmp = load_reg(s, rn);
6423 tmp2 = load_reg(s, rm);
6424 tmp3 = new_tmp();
6425 tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUState, GE));
6426 gen_helper_sel_flags(tmp, tmp3, tmp, tmp2);
6427 dead_tmp(tmp3);
6428 dead_tmp(tmp2);
6429 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006430 } else if ((insn & 0x000003e0) == 0x00000060) {
pbrook5e3f8782008-03-31 03:47:34 +00006431 tmp = load_reg(s, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00006432 shift = (insn >> 10) & 3;
6433 /* ??? In many cases it's not neccessary to do a
6434 rotate, a shift is sufficient. */
6435 if (shift != 0)
pbrook5e3f8782008-03-31 03:47:34 +00006436 tcg_gen_rori_i32(tmp, tmp, shift * 8);
pbrook9ee6e8b2007-11-11 00:04:49 +00006437 op1 = (insn >> 20) & 7;
6438 switch (op1) {
pbrook5e3f8782008-03-31 03:47:34 +00006439 case 0: gen_sxtb16(tmp); break;
6440 case 2: gen_sxtb(tmp); break;
6441 case 3: gen_sxth(tmp); break;
6442 case 4: gen_uxtb16(tmp); break;
6443 case 6: gen_uxtb(tmp); break;
6444 case 7: gen_uxth(tmp); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00006445 default: goto illegal_op;
6446 }
6447 if (rn != 15) {
pbrook5e3f8782008-03-31 03:47:34 +00006448 tmp2 = load_reg(s, rn);
pbrook9ee6e8b2007-11-11 00:04:49 +00006449 if ((op1 & 3) == 0) {
pbrook5e3f8782008-03-31 03:47:34 +00006450 gen_add16(tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00006451 } else {
pbrook5e3f8782008-03-31 03:47:34 +00006452 tcg_gen_add_i32(tmp, tmp, tmp2);
6453 dead_tmp(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00006454 }
6455 }
pbrook5e3f8782008-03-31 03:47:34 +00006456 store_reg(s, rd, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00006457 } else if ((insn & 0x003f0f60) == 0x003f0f20) {
6458 /* rev */
pbrookb0109802008-03-31 03:47:03 +00006459 tmp = load_reg(s, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00006460 if (insn & (1 << 22)) {
6461 if (insn & (1 << 7)) {
pbrookb0109802008-03-31 03:47:03 +00006462 gen_revsh(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006463 } else {
6464 ARCH(6T2);
pbrookb0109802008-03-31 03:47:03 +00006465 gen_helper_rbit(tmp, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006466 }
6467 } else {
6468 if (insn & (1 << 7))
pbrookb0109802008-03-31 03:47:03 +00006469 gen_rev16(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006470 else
pbrookb0109802008-03-31 03:47:03 +00006471 tcg_gen_bswap_i32(tmp, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006472 }
pbrookb0109802008-03-31 03:47:03 +00006473 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006474 } else {
6475 goto illegal_op;
6476 }
6477 break;
6478 case 2: /* Multiplies (Type 3). */
pbrook5e3f8782008-03-31 03:47:34 +00006479 tmp = load_reg(s, rm);
6480 tmp2 = load_reg(s, rs);
pbrook9ee6e8b2007-11-11 00:04:49 +00006481 if (insn & (1 << 20)) {
6482 /* Signed multiply most significant [accumulate]. */
pbrook5e3f8782008-03-31 03:47:34 +00006483 tmp2 = gen_muls_i64_i32(tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00006484 if (insn & (1 << 5))
pbrook5e3f8782008-03-31 03:47:34 +00006485 tcg_gen_addi_i64(tmp2, tmp2, 0x80000000u);
6486 tcg_gen_shri_i64(tmp2, tmp2, 32);
6487 tmp = new_tmp();
6488 tcg_gen_trunc_i64_i32(tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00006489 if (rn != 15) {
pbrook5e3f8782008-03-31 03:47:34 +00006490 tmp2 = load_reg(s, rn);
pbrook9ee6e8b2007-11-11 00:04:49 +00006491 if (insn & (1 << 6)) {
pbrook5e3f8782008-03-31 03:47:34 +00006492 tcg_gen_sub_i32(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00006493 } else {
pbrook5e3f8782008-03-31 03:47:34 +00006494 tcg_gen_add_i32(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00006495 }
pbrook5e3f8782008-03-31 03:47:34 +00006496 dead_tmp(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00006497 }
pbrook5e3f8782008-03-31 03:47:34 +00006498 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006499 } else {
6500 if (insn & (1 << 5))
pbrook5e3f8782008-03-31 03:47:34 +00006501 gen_swap_half(tmp2);
6502 gen_smul_dual(tmp, tmp2);
6503 /* This addition cannot overflow. */
6504 if (insn & (1 << 6)) {
6505 tcg_gen_sub_i32(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00006506 } else {
pbrook5e3f8782008-03-31 03:47:34 +00006507 tcg_gen_add_i32(tmp, tmp, tmp2);
6508 }
6509 dead_tmp(tmp2);
6510 if (insn & (1 << 22)) {
6511 /* smlald, smlsld */
6512 tmp2 = tcg_temp_new(TCG_TYPE_I64);
6513 tcg_gen_ext_i32_i64(tmp2, tmp);
6514 dead_tmp(tmp);
6515 gen_addq(s, tmp2, rn, rd);
6516 gen_storeq_reg(s, rn, rd, tmp2);
6517 } else {
6518 /* smuad, smusd, smlad, smlsd */
pbrook9ee6e8b2007-11-11 00:04:49 +00006519 if (rn != 15)
6520 {
pbrook5e3f8782008-03-31 03:47:34 +00006521 tmp2 = load_reg(s, rn);
6522 gen_helper_add_setq(tmp, tmp, tmp2);
6523 dead_tmp(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00006524 }
pbrook5e3f8782008-03-31 03:47:34 +00006525 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006526 }
6527 }
6528 break;
6529 case 3:
6530 op1 = ((insn >> 17) & 0x38) | ((insn >> 5) & 7);
6531 switch (op1) {
6532 case 0: /* Unsigned sum of absolute differences. */
pbrook6ddbc6e2008-03-31 03:46:33 +00006533 ARCH(6);
6534 tmp = load_reg(s, rm);
6535 tmp2 = load_reg(s, rs);
6536 gen_helper_usad8(tmp, tmp, tmp2);
6537 dead_tmp(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00006538 if (rn != 15) {
pbrook6ddbc6e2008-03-31 03:46:33 +00006539 tmp2 = load_reg(s, rn);
6540 tcg_gen_add_i32(tmp, tmp, tmp2);
6541 dead_tmp(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00006542 }
pbrook6ddbc6e2008-03-31 03:46:33 +00006543 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006544 break;
6545 case 0x20: case 0x24: case 0x28: case 0x2c:
6546 /* Bitfield insert/clear. */
6547 ARCH(6T2);
6548 shift = (insn >> 7) & 0x1f;
6549 i = (insn >> 16) & 0x1f;
6550 i = i + 1 - shift;
6551 if (rm == 15) {
pbrook5e3f8782008-03-31 03:47:34 +00006552 tmp = new_tmp();
6553 tcg_gen_movi_i32(tmp, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00006554 } else {
pbrook5e3f8782008-03-31 03:47:34 +00006555 tmp = load_reg(s, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00006556 }
6557 if (i != 32) {
pbrook5e3f8782008-03-31 03:47:34 +00006558 tmp2 = load_reg(s, rd);
pbrook8f8e3aa2008-03-31 03:48:01 +00006559 gen_bfi(tmp, tmp2, tmp, shift, (1u << i) - 1);
pbrook5e3f8782008-03-31 03:47:34 +00006560 dead_tmp(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00006561 }
pbrook5e3f8782008-03-31 03:47:34 +00006562 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006563 break;
6564 case 0x12: case 0x16: case 0x1a: case 0x1e: /* sbfx */
6565 case 0x32: case 0x36: case 0x3a: case 0x3e: /* ubfx */
pbrook5e3f8782008-03-31 03:47:34 +00006566 tmp = load_reg(s, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00006567 shift = (insn >> 7) & 0x1f;
6568 i = ((insn >> 16) & 0x1f) + 1;
6569 if (shift + i > 32)
6570 goto illegal_op;
6571 if (i < 32) {
6572 if (op1 & 0x20) {
pbrook5e3f8782008-03-31 03:47:34 +00006573 gen_ubfx(tmp, shift, (1u << i) - 1);
pbrook9ee6e8b2007-11-11 00:04:49 +00006574 } else {
pbrook5e3f8782008-03-31 03:47:34 +00006575 gen_sbfx(tmp, shift, i);
pbrook9ee6e8b2007-11-11 00:04:49 +00006576 }
6577 }
pbrook5e3f8782008-03-31 03:47:34 +00006578 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006579 break;
6580 default:
6581 goto illegal_op;
6582 }
6583 break;
6584 }
6585 break;
6586 }
6587 do_ldst:
bellard159f3662006-05-22 23:06:04 +00006588 /* Check for undefined extension instructions
6589 * per the ARM Bible IE:
6590 * xxxx 0111 1111 xxxx xxxx xxxx 1111 xxxx
6591 */
6592 sh = (0xf << 20) | (0xf << 4);
6593 if (op1 == 0x7 && ((insn & sh) == sh))
6594 {
6595 goto illegal_op;
6596 }
bellard2c0262a2003-09-30 20:34:21 +00006597 /* load/store byte/word */
6598 rn = (insn >> 16) & 0xf;
6599 rd = (insn >> 12) & 0xf;
pbrookb0109802008-03-31 03:47:03 +00006600 tmp2 = load_reg(s, rn);
bellardb5ff1b32005-11-26 10:38:39 +00006601 i = (IS_USER(s) || (insn & 0x01200000) == 0x00200000);
bellard2c0262a2003-09-30 20:34:21 +00006602 if (insn & (1 << 24))
pbrookb0109802008-03-31 03:47:03 +00006603 gen_add_data_offset(s, insn, tmp2);
bellard2c0262a2003-09-30 20:34:21 +00006604 if (insn & (1 << 20)) {
6605 /* load */
pbrook6658ffb2007-03-16 23:58:11 +00006606 s->is_mem = 1;
bellardb5ff1b32005-11-26 10:38:39 +00006607 if (insn & (1 << 22)) {
pbrookb0109802008-03-31 03:47:03 +00006608 tmp = gen_ld8u(tmp2, i);
bellardb5ff1b32005-11-26 10:38:39 +00006609 } else {
pbrookb0109802008-03-31 03:47:03 +00006610 tmp = gen_ld32(tmp2, i);
bellardb5ff1b32005-11-26 10:38:39 +00006611 }
bellard2c0262a2003-09-30 20:34:21 +00006612 } else {
6613 /* store */
pbrookb0109802008-03-31 03:47:03 +00006614 tmp = load_reg(s, rd);
bellard2c0262a2003-09-30 20:34:21 +00006615 if (insn & (1 << 22))
pbrookb0109802008-03-31 03:47:03 +00006616 gen_st8(tmp, tmp2, i);
bellard2c0262a2003-09-30 20:34:21 +00006617 else
pbrookb0109802008-03-31 03:47:03 +00006618 gen_st32(tmp, tmp2, i);
bellard2c0262a2003-09-30 20:34:21 +00006619 }
6620 if (!(insn & (1 << 24))) {
pbrookb0109802008-03-31 03:47:03 +00006621 gen_add_data_offset(s, insn, tmp2);
6622 store_reg(s, rn, tmp2);
6623 } else if (insn & (1 << 21)) {
6624 store_reg(s, rn, tmp2);
6625 } else {
6626 dead_tmp(tmp2);
bellard2c0262a2003-09-30 20:34:21 +00006627 }
pbrook5fd46862007-03-17 01:43:01 +00006628 if (insn & (1 << 20)) {
6629 /* Complete the load. */
6630 if (rd == 15)
pbrookb0109802008-03-31 03:47:03 +00006631 gen_bx(s, tmp);
pbrook5fd46862007-03-17 01:43:01 +00006632 else
pbrookb0109802008-03-31 03:47:03 +00006633 store_reg(s, rd, tmp);
pbrook5fd46862007-03-17 01:43:01 +00006634 }
bellard2c0262a2003-09-30 20:34:21 +00006635 break;
6636 case 0x08:
6637 case 0x09:
6638 {
pbrook191abaa2006-02-04 21:50:36 +00006639 int j, n, user, loaded_base;
pbrookb0109802008-03-31 03:47:03 +00006640 TCGv loaded_var;
bellard2c0262a2003-09-30 20:34:21 +00006641 /* load/store multiple words */
6642 /* XXX: store correct base if write back */
bellardb5ff1b32005-11-26 10:38:39 +00006643 user = 0;
6644 if (insn & (1 << 22)) {
6645 if (IS_USER(s))
6646 goto illegal_op; /* only usable in supervisor mode */
6647
6648 if ((insn & (1 << 15)) == 0)
6649 user = 1;
6650 }
bellard2c0262a2003-09-30 20:34:21 +00006651 rn = (insn >> 16) & 0xf;
pbrookb0109802008-03-31 03:47:03 +00006652 addr = load_reg(s, rn);
ths3b46e622007-09-17 08:09:54 +00006653
bellard2c0262a2003-09-30 20:34:21 +00006654 /* compute total size */
pbrook191abaa2006-02-04 21:50:36 +00006655 loaded_base = 0;
bellard2c0262a2003-09-30 20:34:21 +00006656 n = 0;
6657 for(i=0;i<16;i++) {
6658 if (insn & (1 << i))
6659 n++;
6660 }
6661 /* XXX: test invalid n == 0 case ? */
6662 if (insn & (1 << 23)) {
6663 if (insn & (1 << 24)) {
6664 /* pre increment */
pbrookb0109802008-03-31 03:47:03 +00006665 tcg_gen_addi_i32(addr, addr, 4);
bellard2c0262a2003-09-30 20:34:21 +00006666 } else {
6667 /* post increment */
6668 }
6669 } else {
6670 if (insn & (1 << 24)) {
6671 /* pre decrement */
pbrookb0109802008-03-31 03:47:03 +00006672 tcg_gen_addi_i32(addr, addr, -(n * 4));
bellard2c0262a2003-09-30 20:34:21 +00006673 } else {
6674 /* post decrement */
6675 if (n != 1)
pbrookb0109802008-03-31 03:47:03 +00006676 tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
bellard2c0262a2003-09-30 20:34:21 +00006677 }
6678 }
6679 j = 0;
6680 for(i=0;i<16;i++) {
6681 if (insn & (1 << i)) {
6682 if (insn & (1 << 20)) {
6683 /* load */
pbrookb0109802008-03-31 03:47:03 +00006684 tmp = gen_ld32(addr, IS_USER(s));
bellardb5ff1b32005-11-26 10:38:39 +00006685 if (i == 15) {
pbrookb0109802008-03-31 03:47:03 +00006686 gen_bx(s, tmp);
bellardb5ff1b32005-11-26 10:38:39 +00006687 } else if (user) {
pbrookb0109802008-03-31 03:47:03 +00006688 gen_helper_set_user_reg(tcg_const_i32(i), tmp);
6689 dead_tmp(tmp);
pbrook191abaa2006-02-04 21:50:36 +00006690 } else if (i == rn) {
pbrookb0109802008-03-31 03:47:03 +00006691 loaded_var = tmp;
pbrook191abaa2006-02-04 21:50:36 +00006692 loaded_base = 1;
bellardb5ff1b32005-11-26 10:38:39 +00006693 } else {
pbrookb0109802008-03-31 03:47:03 +00006694 store_reg(s, i, tmp);
bellardb5ff1b32005-11-26 10:38:39 +00006695 }
bellard2c0262a2003-09-30 20:34:21 +00006696 } else {
6697 /* store */
6698 if (i == 15) {
balrog7a774c82007-06-10 13:53:18 +00006699 /* special case: r15 = PC + 8 */
6700 val = (long)s->pc + 4;
pbrookb0109802008-03-31 03:47:03 +00006701 tmp = new_tmp();
6702 tcg_gen_movi_i32(tmp, val);
bellardb5ff1b32005-11-26 10:38:39 +00006703 } else if (user) {
pbrookb0109802008-03-31 03:47:03 +00006704 tmp = new_tmp();
6705 gen_helper_get_user_reg(tmp, tcg_const_i32(i));
bellard2c0262a2003-09-30 20:34:21 +00006706 } else {
pbrookb0109802008-03-31 03:47:03 +00006707 tmp = load_reg(s, i);
bellard2c0262a2003-09-30 20:34:21 +00006708 }
pbrookb0109802008-03-31 03:47:03 +00006709 gen_st32(tmp, addr, IS_USER(s));
bellard2c0262a2003-09-30 20:34:21 +00006710 }
6711 j++;
6712 /* no need to add after the last transfer */
6713 if (j != n)
pbrookb0109802008-03-31 03:47:03 +00006714 tcg_gen_addi_i32(addr, addr, 4);
bellard2c0262a2003-09-30 20:34:21 +00006715 }
6716 }
6717 if (insn & (1 << 21)) {
6718 /* write back */
6719 if (insn & (1 << 23)) {
6720 if (insn & (1 << 24)) {
6721 /* pre increment */
6722 } else {
6723 /* post increment */
pbrookb0109802008-03-31 03:47:03 +00006724 tcg_gen_addi_i32(addr, addr, 4);
bellard2c0262a2003-09-30 20:34:21 +00006725 }
6726 } else {
6727 if (insn & (1 << 24)) {
6728 /* pre decrement */
6729 if (n != 1)
pbrookb0109802008-03-31 03:47:03 +00006730 tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
bellard2c0262a2003-09-30 20:34:21 +00006731 } else {
6732 /* post decrement */
pbrookb0109802008-03-31 03:47:03 +00006733 tcg_gen_addi_i32(addr, addr, -(n * 4));
bellard2c0262a2003-09-30 20:34:21 +00006734 }
6735 }
pbrookb0109802008-03-31 03:47:03 +00006736 store_reg(s, rn, addr);
6737 } else {
6738 dead_tmp(addr);
bellard2c0262a2003-09-30 20:34:21 +00006739 }
pbrook191abaa2006-02-04 21:50:36 +00006740 if (loaded_base) {
pbrookb0109802008-03-31 03:47:03 +00006741 store_reg(s, rn, loaded_var);
pbrook191abaa2006-02-04 21:50:36 +00006742 }
bellardb5ff1b32005-11-26 10:38:39 +00006743 if ((insn & (1 << 22)) && !user) {
6744 /* Restore CPSR from SPSR. */
pbrookd9ba4832008-03-31 03:46:50 +00006745 tmp = load_cpu_field(spsr);
6746 gen_set_cpsr(tmp, 0xffffffff);
6747 dead_tmp(tmp);
bellardb5ff1b32005-11-26 10:38:39 +00006748 s->is_jmp = DISAS_UPDATE;
6749 }
bellard2c0262a2003-09-30 20:34:21 +00006750 }
6751 break;
6752 case 0xa:
6753 case 0xb:
6754 {
bellard99c475a2005-01-31 20:45:13 +00006755 int32_t offset;
ths3b46e622007-09-17 08:09:54 +00006756
bellard2c0262a2003-09-30 20:34:21 +00006757 /* branch (and link) */
bellard99c475a2005-01-31 20:45:13 +00006758 val = (int32_t)s->pc;
bellard2c0262a2003-09-30 20:34:21 +00006759 if (insn & (1 << 24)) {
pbrook5e3f8782008-03-31 03:47:34 +00006760 tmp = new_tmp();
6761 tcg_gen_movi_i32(tmp, val);
6762 store_reg(s, 14, tmp);
bellard2c0262a2003-09-30 20:34:21 +00006763 }
bellard99c475a2005-01-31 20:45:13 +00006764 offset = (((int32_t)insn << 8) >> 8);
bellard2c0262a2003-09-30 20:34:21 +00006765 val += (offset << 2) + 4;
bellard8aaca4c2005-04-23 18:27:52 +00006766 gen_jmp(s, val);
bellard2c0262a2003-09-30 20:34:21 +00006767 }
6768 break;
bellardb7bcbe92005-02-22 19:27:29 +00006769 case 0xc:
6770 case 0xd:
6771 case 0xe:
6772 /* Coprocessor. */
pbrook9ee6e8b2007-11-11 00:04:49 +00006773 if (disas_coproc_insn(env, s, insn))
balrogc1713132007-04-30 01:26:42 +00006774 goto illegal_op;
bellardb7bcbe92005-02-22 19:27:29 +00006775 break;
bellard2c0262a2003-09-30 20:34:21 +00006776 case 0xf:
6777 /* swi */
pbrook5e3f8782008-03-31 03:47:34 +00006778 gen_set_pc_im(s->pc);
pbrook9ee6e8b2007-11-11 00:04:49 +00006779 s->is_jmp = DISAS_SWI;
bellard2c0262a2003-09-30 20:34:21 +00006780 break;
bellard2c0262a2003-09-30 20:34:21 +00006781 default:
6782 illegal_op:
pbrook9ee6e8b2007-11-11 00:04:49 +00006783 gen_set_condexec(s);
pbrook5e3f8782008-03-31 03:47:34 +00006784 gen_set_pc_im(s->pc - 4);
pbrookd9ba4832008-03-31 03:46:50 +00006785 gen_exception(EXCP_UDEF);
bellard2c0262a2003-09-30 20:34:21 +00006786 s->is_jmp = DISAS_JUMP;
6787 break;
6788 }
6789 }
6790}
6791
pbrook9ee6e8b2007-11-11 00:04:49 +00006792/* Return true if this is a Thumb-2 logical op. */
6793static int
6794thumb2_logic_op(int op)
6795{
6796 return (op < 8);
6797}
6798
6799/* Generate code for a Thumb-2 data processing operation. If CONDS is nonzero
6800 then set condition code flags based on the result of the operation.
6801 If SHIFTER_OUT is nonzero then set the carry flag for logical operations
6802 to the high bit of T1.
6803 Returns zero if the opcode is valid. */
6804
6805static int
6806gen_thumb2_data_op(DisasContext *s, int op, int conds, uint32_t shifter_out)
6807{
6808 int logic_cc;
6809
6810 logic_cc = 0;
6811 switch (op) {
6812 case 0: /* and */
6813 gen_op_andl_T0_T1();
6814 logic_cc = conds;
6815 break;
6816 case 1: /* bic */
6817 gen_op_bicl_T0_T1();
6818 logic_cc = conds;
6819 break;
6820 case 2: /* orr */
6821 gen_op_orl_T0_T1();
6822 logic_cc = conds;
6823 break;
6824 case 3: /* orn */
6825 gen_op_notl_T1();
6826 gen_op_orl_T0_T1();
6827 logic_cc = conds;
6828 break;
6829 case 4: /* eor */
6830 gen_op_xorl_T0_T1();
6831 logic_cc = conds;
6832 break;
6833 case 8: /* add */
6834 if (conds)
6835 gen_op_addl_T0_T1_cc();
6836 else
6837 gen_op_addl_T0_T1();
6838 break;
6839 case 10: /* adc */
6840 if (conds)
6841 gen_op_adcl_T0_T1_cc();
6842 else
pbrookb26eefb2008-03-31 03:44:26 +00006843 gen_adc_T0_T1();
pbrook9ee6e8b2007-11-11 00:04:49 +00006844 break;
6845 case 11: /* sbc */
6846 if (conds)
6847 gen_op_sbcl_T0_T1_cc();
6848 else
pbrook36706692008-03-31 03:46:19 +00006849 gen_sbc_T0_T1();
pbrook9ee6e8b2007-11-11 00:04:49 +00006850 break;
6851 case 13: /* sub */
6852 if (conds)
6853 gen_op_subl_T0_T1_cc();
6854 else
6855 gen_op_subl_T0_T1();
6856 break;
6857 case 14: /* rsb */
6858 if (conds)
6859 gen_op_rsbl_T0_T1_cc();
6860 else
6861 gen_op_rsbl_T0_T1();
6862 break;
6863 default: /* 5, 6, 7, 9, 12, 15. */
6864 return 1;
6865 }
6866 if (logic_cc) {
6867 gen_op_logic_T0_cc();
6868 if (shifter_out)
pbrookb26eefb2008-03-31 03:44:26 +00006869 gen_set_CF_bit31(cpu_T[1]);
pbrook9ee6e8b2007-11-11 00:04:49 +00006870 }
6871 return 0;
6872}
6873
6874/* Translate a 32-bit thumb instruction. Returns nonzero if the instruction
6875 is not legal. */
6876static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
6877{
pbrookb0109802008-03-31 03:47:03 +00006878 uint32_t insn, imm, shift, offset;
pbrook9ee6e8b2007-11-11 00:04:49 +00006879 uint32_t rd, rn, rm, rs;
pbrookb26eefb2008-03-31 03:44:26 +00006880 TCGv tmp;
pbrook6ddbc6e2008-03-31 03:46:33 +00006881 TCGv tmp2;
6882 TCGv tmp3;
pbrookb0109802008-03-31 03:47:03 +00006883 TCGv addr;
pbrook9ee6e8b2007-11-11 00:04:49 +00006884 int op;
6885 int shiftop;
6886 int conds;
6887 int logic_cc;
6888
6889 if (!(arm_feature(env, ARM_FEATURE_THUMB2)
6890 || arm_feature (env, ARM_FEATURE_M))) {
6891 /* Thumb-1 cores may need to tread bl and blx as a pair of
6892 16-bit instructions to get correct prefetch abort behavior. */
6893 insn = insn_hw1;
6894 if ((insn & (1 << 12)) == 0) {
6895 /* Second half of blx. */
6896 offset = ((insn & 0x7ff) << 1);
pbrookd9ba4832008-03-31 03:46:50 +00006897 tmp = load_reg(s, 14);
6898 tcg_gen_addi_i32(tmp, tmp, offset);
6899 tcg_gen_andi_i32(tmp, tmp, 0xfffffffc);
pbrook9ee6e8b2007-11-11 00:04:49 +00006900
pbrookd9ba4832008-03-31 03:46:50 +00006901 tmp2 = new_tmp();
pbrookb0109802008-03-31 03:47:03 +00006902 tcg_gen_movi_i32(tmp2, s->pc | 1);
pbrookd9ba4832008-03-31 03:46:50 +00006903 store_reg(s, 14, tmp2);
6904 gen_bx(s, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006905 return 0;
6906 }
6907 if (insn & (1 << 11)) {
6908 /* Second half of bl. */
6909 offset = ((insn & 0x7ff) << 1) | 1;
pbrookd9ba4832008-03-31 03:46:50 +00006910 tmp = load_reg(s, 14);
6911 tcg_gen_addi_i32(tmp, tmp, 14);
pbrook9ee6e8b2007-11-11 00:04:49 +00006912
pbrookd9ba4832008-03-31 03:46:50 +00006913 tmp2 = new_tmp();
pbrookb0109802008-03-31 03:47:03 +00006914 tcg_gen_movi_i32(tmp2, s->pc | 1);
pbrookd9ba4832008-03-31 03:46:50 +00006915 store_reg(s, 14, tmp2);
6916 gen_bx(s, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006917 return 0;
6918 }
6919 if ((s->pc & ~TARGET_PAGE_MASK) == 0) {
6920 /* Instruction spans a page boundary. Implement it as two
6921 16-bit instructions in case the second half causes an
6922 prefetch abort. */
6923 offset = ((int32_t)insn << 21) >> 9;
pbrookb0109802008-03-31 03:47:03 +00006924 gen_op_movl_T0_im(s->pc + 2 + offset);
pbrook9ee6e8b2007-11-11 00:04:49 +00006925 gen_movl_reg_T0(s, 14);
6926 return 0;
6927 }
6928 /* Fall through to 32-bit decode. */
6929 }
6930
6931 insn = lduw_code(s->pc);
6932 s->pc += 2;
6933 insn |= (uint32_t)insn_hw1 << 16;
6934
6935 if ((insn & 0xf800e800) != 0xf000e800) {
6936 ARCH(6T2);
6937 }
6938
6939 rn = (insn >> 16) & 0xf;
6940 rs = (insn >> 12) & 0xf;
6941 rd = (insn >> 8) & 0xf;
6942 rm = insn & 0xf;
6943 switch ((insn >> 25) & 0xf) {
6944 case 0: case 1: case 2: case 3:
6945 /* 16-bit instructions. Should never happen. */
6946 abort();
6947 case 4:
6948 if (insn & (1 << 22)) {
6949 /* Other load/store, table branch. */
6950 if (insn & 0x01200000) {
6951 /* Load/store doubleword. */
6952 if (rn == 15) {
pbrookb0109802008-03-31 03:47:03 +00006953 addr = new_tmp();
6954 tcg_gen_movi_i32(addr, s->pc & ~3);
pbrook9ee6e8b2007-11-11 00:04:49 +00006955 } else {
pbrookb0109802008-03-31 03:47:03 +00006956 addr = load_reg(s, rn);
pbrook9ee6e8b2007-11-11 00:04:49 +00006957 }
6958 offset = (insn & 0xff) * 4;
6959 if ((insn & (1 << 23)) == 0)
6960 offset = -offset;
6961 if (insn & (1 << 24)) {
pbrookb0109802008-03-31 03:47:03 +00006962 tcg_gen_addi_i32(addr, addr, offset);
pbrook9ee6e8b2007-11-11 00:04:49 +00006963 offset = 0;
6964 }
6965 if (insn & (1 << 20)) {
6966 /* ldrd */
pbrookb0109802008-03-31 03:47:03 +00006967 tmp = gen_ld32(addr, IS_USER(s));
6968 store_reg(s, rs, tmp);
6969 tcg_gen_addi_i32(addr, addr, 4);
6970 tmp = gen_ld32(addr, IS_USER(s));
6971 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006972 } else {
6973 /* strd */
pbrookb0109802008-03-31 03:47:03 +00006974 tmp = load_reg(s, rs);
6975 gen_st32(tmp, addr, IS_USER(s));
6976 tcg_gen_addi_i32(addr, addr, 4);
6977 tmp = load_reg(s, rd);
6978 gen_st32(tmp, addr, IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00006979 }
6980 if (insn & (1 << 21)) {
6981 /* Base writeback. */
6982 if (rn == 15)
6983 goto illegal_op;
pbrookb0109802008-03-31 03:47:03 +00006984 tcg_gen_addi_i32(addr, addr, offset - 4);
6985 store_reg(s, rn, addr);
6986 } else {
6987 dead_tmp(addr);
pbrook9ee6e8b2007-11-11 00:04:49 +00006988 }
6989 } else if ((insn & (1 << 23)) == 0) {
6990 /* Load/store exclusive word. */
pbrook9ee6e8b2007-11-11 00:04:49 +00006991 gen_movl_T1_reg(s, rn);
6992 if (insn & (1 << 20)) {
pbrook8f8e3aa2008-03-31 03:48:01 +00006993 gen_helper_mark_exclusive(cpu_env, cpu_T[1]);
6994 tmp = gen_ld32(addr, IS_USER(s));
6995 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00006996 } else {
pbrook8f8e3aa2008-03-31 03:48:01 +00006997 int label = gen_new_label();
6998 gen_helper_test_exclusive(cpu_T[0], cpu_env, addr);
6999 tcg_gen_brcond_i32(TCG_COND_NE, cpu_T[0],
7000 tcg_const_i32(0), label);
7001 tmp = load_reg(s, rs);
7002 gen_st32(tmp, cpu_T[1], IS_USER(s));
7003 gen_set_label(label);
7004 gen_movl_reg_T0(s, rd);
pbrook9ee6e8b2007-11-11 00:04:49 +00007005 }
pbrook9ee6e8b2007-11-11 00:04:49 +00007006 } else if ((insn & (1 << 6)) == 0) {
7007 /* Table Branch. */
7008 if (rn == 15) {
pbrookb0109802008-03-31 03:47:03 +00007009 addr = new_tmp();
7010 tcg_gen_movi_i32(addr, s->pc);
pbrook9ee6e8b2007-11-11 00:04:49 +00007011 } else {
pbrookb0109802008-03-31 03:47:03 +00007012 addr = load_reg(s, rn);
pbrook9ee6e8b2007-11-11 00:04:49 +00007013 }
pbrookb26eefb2008-03-31 03:44:26 +00007014 tmp = load_reg(s, rm);
pbrookb0109802008-03-31 03:47:03 +00007015 tcg_gen_add_i32(addr, addr, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007016 if (insn & (1 << 4)) {
7017 /* tbh */
pbrookb0109802008-03-31 03:47:03 +00007018 tcg_gen_add_i32(addr, addr, tmp);
pbrookb26eefb2008-03-31 03:44:26 +00007019 dead_tmp(tmp);
pbrookb0109802008-03-31 03:47:03 +00007020 tmp = gen_ld16u(addr, IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00007021 } else { /* tbb */
pbrookb26eefb2008-03-31 03:44:26 +00007022 dead_tmp(tmp);
pbrookb0109802008-03-31 03:47:03 +00007023 tmp = gen_ld8u(addr, IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00007024 }
pbrookb0109802008-03-31 03:47:03 +00007025 dead_tmp(addr);
7026 tcg_gen_shli_i32(tmp, tmp, 1);
7027 tcg_gen_addi_i32(tmp, tmp, s->pc);
7028 store_reg(s, 15, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007029 } else {
7030 /* Load/store exclusive byte/halfword/doubleword. */
pbrook8f8e3aa2008-03-31 03:48:01 +00007031 /* ??? These are not really atomic. However we know
7032 we never have multiple CPUs running in parallel,
7033 so it is good enough. */
pbrook9ee6e8b2007-11-11 00:04:49 +00007034 op = (insn >> 4) & 0x3;
pbrook8f8e3aa2008-03-31 03:48:01 +00007035 /* Must use a global reg for the address because we have
7036 a conditional branch in the store instruction. */
pbrook9ee6e8b2007-11-11 00:04:49 +00007037 gen_movl_T1_reg(s, rn);
pbrook8f8e3aa2008-03-31 03:48:01 +00007038 addr = cpu_T[1];
pbrook9ee6e8b2007-11-11 00:04:49 +00007039 if (insn & (1 << 20)) {
pbrook8f8e3aa2008-03-31 03:48:01 +00007040 gen_helper_mark_exclusive(cpu_env, addr);
pbrook9ee6e8b2007-11-11 00:04:49 +00007041 switch (op) {
7042 case 0:
pbrook8f8e3aa2008-03-31 03:48:01 +00007043 tmp = gen_ld8u(addr, IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00007044 break;
7045 case 1:
pbrook8f8e3aa2008-03-31 03:48:01 +00007046 tmp = gen_ld16u(addr, IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00007047 break;
7048 case 3:
pbrook8f8e3aa2008-03-31 03:48:01 +00007049 tmp = gen_ld32(addr, IS_USER(s));
7050 tcg_gen_addi_i32(addr, addr, 4);
7051 tmp2 = gen_ld32(addr, IS_USER(s));
7052 store_reg(s, rd, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007053 break;
7054 default:
7055 goto illegal_op;
7056 }
pbrook8f8e3aa2008-03-31 03:48:01 +00007057 store_reg(s, rs, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007058 } else {
pbrook8f8e3aa2008-03-31 03:48:01 +00007059 int label = gen_new_label();
7060 /* Must use a global that is not killed by the branch. */
7061 gen_helper_test_exclusive(cpu_T[0], cpu_env, addr);
7062 tcg_gen_brcond_i32(TCG_COND_NE, cpu_T[0], tcg_const_i32(0),
7063 label);
7064 tmp = load_reg(s, rs);
pbrook9ee6e8b2007-11-11 00:04:49 +00007065 switch (op) {
7066 case 0:
pbrook8f8e3aa2008-03-31 03:48:01 +00007067 gen_st8(tmp, addr, IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00007068 break;
7069 case 1:
pbrook8f8e3aa2008-03-31 03:48:01 +00007070 gen_st16(tmp, addr, IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00007071 break;
7072 case 3:
pbrook8f8e3aa2008-03-31 03:48:01 +00007073 gen_st32(tmp, addr, IS_USER(s));
7074 tcg_gen_addi_i32(addr, addr, 4);
7075 tmp = load_reg(s, rd);
7076 gen_st32(tmp, addr, IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00007077 break;
7078 default:
7079 goto illegal_op;
7080 }
pbrook8f8e3aa2008-03-31 03:48:01 +00007081 gen_set_label(label);
pbrook9ee6e8b2007-11-11 00:04:49 +00007082 gen_movl_reg_T0(s, rm);
7083 }
7084 }
7085 } else {
7086 /* Load/store multiple, RFE, SRS. */
7087 if (((insn >> 23) & 1) == ((insn >> 24) & 1)) {
7088 /* Not available in user mode. */
pbrookb0109802008-03-31 03:47:03 +00007089 if (IS_USER(s))
pbrook9ee6e8b2007-11-11 00:04:49 +00007090 goto illegal_op;
7091 if (insn & (1 << 20)) {
7092 /* rfe */
pbrookb0109802008-03-31 03:47:03 +00007093 addr = load_reg(s, rn);
7094 if ((insn & (1 << 24)) == 0)
7095 tcg_gen_addi_i32(addr, addr, -8);
7096 /* Load PC into tmp and CPSR into tmp2. */
7097 tmp = gen_ld32(addr, 0);
7098 tcg_gen_addi_i32(addr, addr, 4);
7099 tmp2 = gen_ld32(addr, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00007100 if (insn & (1 << 21)) {
7101 /* Base writeback. */
pbrookb0109802008-03-31 03:47:03 +00007102 if (insn & (1 << 24)) {
7103 tcg_gen_addi_i32(addr, addr, 4);
7104 } else {
7105 tcg_gen_addi_i32(addr, addr, -4);
7106 }
7107 store_reg(s, rn, addr);
7108 } else {
7109 dead_tmp(addr);
pbrook9ee6e8b2007-11-11 00:04:49 +00007110 }
pbrookb0109802008-03-31 03:47:03 +00007111 gen_rfe(s, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007112 } else {
7113 /* srs */
7114 op = (insn & 0x1f);
7115 if (op == (env->uncached_cpsr & CPSR_M)) {
pbrookb0109802008-03-31 03:47:03 +00007116 addr = load_reg(s, 13);
pbrook9ee6e8b2007-11-11 00:04:49 +00007117 } else {
pbrookb0109802008-03-31 03:47:03 +00007118 addr = new_tmp();
7119 gen_helper_get_r13_banked(addr, cpu_env, tcg_const_i32(op));
pbrook9ee6e8b2007-11-11 00:04:49 +00007120 }
7121 if ((insn & (1 << 24)) == 0) {
pbrookb0109802008-03-31 03:47:03 +00007122 tcg_gen_addi_i32(addr, addr, -8);
pbrook9ee6e8b2007-11-11 00:04:49 +00007123 }
pbrookb0109802008-03-31 03:47:03 +00007124 tmp = load_reg(s, 14);
7125 gen_st32(tmp, addr, 0);
7126 tcg_gen_addi_i32(addr, addr, 4);
7127 tmp = new_tmp();
7128 gen_helper_cpsr_read(tmp);
7129 gen_st32(tmp, addr, 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00007130 if (insn & (1 << 21)) {
7131 if ((insn & (1 << 24)) == 0) {
pbrookb0109802008-03-31 03:47:03 +00007132 tcg_gen_addi_i32(addr, addr, -4);
pbrook9ee6e8b2007-11-11 00:04:49 +00007133 } else {
pbrookb0109802008-03-31 03:47:03 +00007134 tcg_gen_addi_i32(addr, addr, 4);
pbrook9ee6e8b2007-11-11 00:04:49 +00007135 }
7136 if (op == (env->uncached_cpsr & CPSR_M)) {
pbrookb0109802008-03-31 03:47:03 +00007137 store_reg(s, 13, addr);
pbrook9ee6e8b2007-11-11 00:04:49 +00007138 } else {
pbrookb0109802008-03-31 03:47:03 +00007139 gen_helper_set_r13_banked(cpu_env,
7140 tcg_const_i32(op), addr);
pbrook9ee6e8b2007-11-11 00:04:49 +00007141 }
pbrookb0109802008-03-31 03:47:03 +00007142 } else {
7143 dead_tmp(addr);
pbrook9ee6e8b2007-11-11 00:04:49 +00007144 }
7145 }
7146 } else {
7147 int i;
7148 /* Load/store multiple. */
pbrookb0109802008-03-31 03:47:03 +00007149 addr = load_reg(s, rn);
pbrook9ee6e8b2007-11-11 00:04:49 +00007150 offset = 0;
7151 for (i = 0; i < 16; i++) {
7152 if (insn & (1 << i))
7153 offset += 4;
7154 }
7155 if (insn & (1 << 24)) {
pbrookb0109802008-03-31 03:47:03 +00007156 tcg_gen_addi_i32(addr, addr, -offset);
pbrook9ee6e8b2007-11-11 00:04:49 +00007157 }
7158
7159 for (i = 0; i < 16; i++) {
7160 if ((insn & (1 << i)) == 0)
7161 continue;
7162 if (insn & (1 << 20)) {
7163 /* Load. */
pbrookb0109802008-03-31 03:47:03 +00007164 tmp = gen_ld32(addr, IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00007165 if (i == 15) {
pbrookb0109802008-03-31 03:47:03 +00007166 gen_bx(s, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007167 } else {
pbrookb0109802008-03-31 03:47:03 +00007168 store_reg(s, i, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007169 }
7170 } else {
7171 /* Store. */
pbrookb0109802008-03-31 03:47:03 +00007172 tmp = load_reg(s, i);
7173 gen_st32(tmp, addr, IS_USER(s));
pbrook9ee6e8b2007-11-11 00:04:49 +00007174 }
pbrookb0109802008-03-31 03:47:03 +00007175 tcg_gen_addi_i32(addr, addr, 4);
pbrook9ee6e8b2007-11-11 00:04:49 +00007176 }
7177 if (insn & (1 << 21)) {
7178 /* Base register writeback. */
7179 if (insn & (1 << 24)) {
pbrookb0109802008-03-31 03:47:03 +00007180 tcg_gen_addi_i32(addr, addr, -offset);
pbrook9ee6e8b2007-11-11 00:04:49 +00007181 }
7182 /* Fault if writeback register is in register list. */
7183 if (insn & (1 << rn))
7184 goto illegal_op;
pbrookb0109802008-03-31 03:47:03 +00007185 store_reg(s, rn, addr);
7186 } else {
7187 dead_tmp(addr);
pbrook9ee6e8b2007-11-11 00:04:49 +00007188 }
7189 }
7190 }
7191 break;
7192 case 5: /* Data processing register constant shift. */
7193 if (rn == 15)
7194 gen_op_movl_T0_im(0);
7195 else
7196 gen_movl_T0_reg(s, rn);
7197 gen_movl_T1_reg(s, rm);
7198 op = (insn >> 21) & 0xf;
7199 shiftop = (insn >> 4) & 3;
7200 shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c);
7201 conds = (insn & (1 << 20)) != 0;
7202 logic_cc = (conds && thumb2_logic_op(op));
pbrook9a119ff2008-03-31 03:45:35 +00007203 gen_arm_shift_im(cpu_T[1], shiftop, shift, logic_cc);
pbrook9ee6e8b2007-11-11 00:04:49 +00007204 if (gen_thumb2_data_op(s, op, conds, 0))
7205 goto illegal_op;
7206 if (rd != 15)
7207 gen_movl_reg_T0(s, rd);
7208 break;
7209 case 13: /* Misc data processing. */
7210 op = ((insn >> 22) & 6) | ((insn >> 7) & 1);
7211 if (op < 4 && (insn & 0xf000) != 0xf000)
7212 goto illegal_op;
7213 switch (op) {
7214 case 0: /* Register controlled shift. */
pbrook8984bd22008-03-31 03:47:48 +00007215 tmp = load_reg(s, rn);
7216 tmp2 = load_reg(s, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00007217 if ((insn & 0x70) != 0)
7218 goto illegal_op;
7219 op = (insn >> 21) & 3;
pbrook8984bd22008-03-31 03:47:48 +00007220 logic_cc = (insn & (1 << 20)) != 0;
7221 gen_arm_shift_reg(tmp, op, tmp2, logic_cc);
7222 if (logic_cc)
7223 gen_logic_CC(tmp);
7224 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007225 break;
7226 case 1: /* Sign/zero extend. */
pbrook5e3f8782008-03-31 03:47:34 +00007227 tmp = load_reg(s, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00007228 shift = (insn >> 4) & 3;
7229 /* ??? In many cases it's not neccessary to do a
7230 rotate, a shift is sufficient. */
7231 if (shift != 0)
pbrook5e3f8782008-03-31 03:47:34 +00007232 tcg_gen_rori_i32(tmp, tmp, shift * 8);
pbrook9ee6e8b2007-11-11 00:04:49 +00007233 op = (insn >> 20) & 7;
7234 switch (op) {
pbrook5e3f8782008-03-31 03:47:34 +00007235 case 0: gen_sxth(tmp); break;
7236 case 1: gen_uxth(tmp); break;
7237 case 2: gen_sxtb16(tmp); break;
7238 case 3: gen_uxtb16(tmp); break;
7239 case 4: gen_sxtb(tmp); break;
7240 case 5: gen_uxtb(tmp); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00007241 default: goto illegal_op;
7242 }
7243 if (rn != 15) {
pbrook5e3f8782008-03-31 03:47:34 +00007244 tmp2 = load_reg(s, rn);
pbrook9ee6e8b2007-11-11 00:04:49 +00007245 if ((op >> 1) == 1) {
pbrook5e3f8782008-03-31 03:47:34 +00007246 gen_add16(tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007247 } else {
pbrook5e3f8782008-03-31 03:47:34 +00007248 tcg_gen_add_i32(tmp, tmp, tmp2);
7249 dead_tmp(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007250 }
7251 }
pbrook5e3f8782008-03-31 03:47:34 +00007252 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007253 break;
7254 case 2: /* SIMD add/subtract. */
7255 op = (insn >> 20) & 7;
7256 shift = (insn >> 4) & 7;
7257 if ((op & 3) == 3 || (shift & 3) == 3)
7258 goto illegal_op;
pbrook6ddbc6e2008-03-31 03:46:33 +00007259 tmp = load_reg(s, rn);
7260 tmp2 = load_reg(s, rm);
7261 gen_thumb2_parallel_addsub(op, shift, tmp, tmp2);
7262 dead_tmp(tmp2);
7263 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007264 break;
7265 case 3: /* Other data processing. */
7266 op = ((insn >> 17) & 0x38) | ((insn >> 4) & 7);
7267 if (op < 4) {
7268 /* Saturating add/subtract. */
pbrookd9ba4832008-03-31 03:46:50 +00007269 tmp = load_reg(s, rn);
7270 tmp2 = load_reg(s, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00007271 if (op & 2)
pbrookd9ba4832008-03-31 03:46:50 +00007272 gen_helper_double_saturate(tmp, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007273 if (op & 1)
pbrookd9ba4832008-03-31 03:46:50 +00007274 gen_helper_sub_saturate(tmp, tmp2, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007275 else
pbrookd9ba4832008-03-31 03:46:50 +00007276 gen_helper_add_saturate(tmp, tmp, tmp2);
7277 dead_tmp(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007278 } else {
pbrookd9ba4832008-03-31 03:46:50 +00007279 tmp = load_reg(s, rn);
pbrook9ee6e8b2007-11-11 00:04:49 +00007280 switch (op) {
7281 case 0x0a: /* rbit */
pbrookd9ba4832008-03-31 03:46:50 +00007282 gen_helper_rbit(tmp, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007283 break;
7284 case 0x08: /* rev */
pbrookd9ba4832008-03-31 03:46:50 +00007285 tcg_gen_bswap_i32(tmp, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007286 break;
7287 case 0x09: /* rev16 */
pbrookd9ba4832008-03-31 03:46:50 +00007288 gen_rev16(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007289 break;
7290 case 0x0b: /* revsh */
pbrookd9ba4832008-03-31 03:46:50 +00007291 gen_revsh(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007292 break;
7293 case 0x10: /* sel */
pbrookd9ba4832008-03-31 03:46:50 +00007294 tmp2 = load_reg(s, rm);
pbrook6ddbc6e2008-03-31 03:46:33 +00007295 tmp3 = new_tmp();
7296 tcg_gen_ld_i32(tmp3, cpu_env, offsetof(CPUState, GE));
pbrookd9ba4832008-03-31 03:46:50 +00007297 gen_helper_sel_flags(tmp, tmp3, tmp, tmp2);
pbrook6ddbc6e2008-03-31 03:46:33 +00007298 dead_tmp(tmp3);
pbrookd9ba4832008-03-31 03:46:50 +00007299 dead_tmp(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007300 break;
7301 case 0x18: /* clz */
pbrookd9ba4832008-03-31 03:46:50 +00007302 gen_helper_clz(tmp, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007303 break;
7304 default:
7305 goto illegal_op;
7306 }
7307 }
pbrookd9ba4832008-03-31 03:46:50 +00007308 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007309 break;
7310 case 4: case 5: /* 32-bit multiply. Sum of absolute differences. */
7311 op = (insn >> 4) & 0xf;
pbrookd9ba4832008-03-31 03:46:50 +00007312 tmp = load_reg(s, rn);
7313 tmp2 = load_reg(s, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00007314 switch ((insn >> 20) & 7) {
7315 case 0: /* 32 x 32 -> 32 */
pbrookd9ba4832008-03-31 03:46:50 +00007316 tcg_gen_mul_i32(tmp, tmp, tmp2);
7317 dead_tmp(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007318 if (rs != 15) {
pbrookd9ba4832008-03-31 03:46:50 +00007319 tmp2 = load_reg(s, rs);
pbrook9ee6e8b2007-11-11 00:04:49 +00007320 if (op)
pbrookd9ba4832008-03-31 03:46:50 +00007321 tcg_gen_sub_i32(tmp, tmp2, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007322 else
pbrookd9ba4832008-03-31 03:46:50 +00007323 tcg_gen_add_i32(tmp, tmp, tmp2);
7324 dead_tmp(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007325 }
pbrook9ee6e8b2007-11-11 00:04:49 +00007326 break;
7327 case 1: /* 16 x 16 -> 32 */
pbrookd9ba4832008-03-31 03:46:50 +00007328 gen_mulxy(tmp, tmp2, op & 2, op & 1);
7329 dead_tmp(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007330 if (rs != 15) {
pbrookd9ba4832008-03-31 03:46:50 +00007331 tmp2 = load_reg(s, rs);
7332 gen_helper_add_setq(tmp, tmp, tmp2);
7333 dead_tmp(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007334 }
pbrook9ee6e8b2007-11-11 00:04:49 +00007335 break;
7336 case 2: /* Dual multiply add. */
7337 case 4: /* Dual multiply subtract. */
7338 if (op)
pbrookd9ba4832008-03-31 03:46:50 +00007339 gen_swap_half(tmp2);
7340 gen_smul_dual(tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007341 /* This addition cannot overflow. */
7342 if (insn & (1 << 22)) {
pbrookd9ba4832008-03-31 03:46:50 +00007343 tcg_gen_sub_i32(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007344 } else {
pbrookd9ba4832008-03-31 03:46:50 +00007345 tcg_gen_add_i32(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007346 }
pbrookd9ba4832008-03-31 03:46:50 +00007347 dead_tmp(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007348 if (rs != 15)
7349 {
pbrookd9ba4832008-03-31 03:46:50 +00007350 tmp2 = load_reg(s, rs);
7351 gen_helper_add_setq(tmp, tmp, tmp2);
7352 dead_tmp(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007353 }
pbrook9ee6e8b2007-11-11 00:04:49 +00007354 break;
7355 case 3: /* 32 * 16 -> 32msb */
7356 if (op)
pbrookd9ba4832008-03-31 03:46:50 +00007357 tcg_gen_sari_i32(tmp2, tmp2, 16);
pbrook9ee6e8b2007-11-11 00:04:49 +00007358 else
pbrookd9ba4832008-03-31 03:46:50 +00007359 gen_sxth(tmp2);
pbrook5e3f8782008-03-31 03:47:34 +00007360 tmp2 = gen_muls_i64_i32(tmp, tmp2);
7361 tcg_gen_shri_i64(tmp2, tmp2, 16);
7362 tmp = new_tmp();
7363 tcg_gen_trunc_i64_i32(tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007364 if (rs != 15)
7365 {
pbrookd9ba4832008-03-31 03:46:50 +00007366 tmp2 = load_reg(s, rs);
7367 gen_helper_add_setq(tmp, tmp, tmp2);
7368 dead_tmp(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007369 }
pbrook9ee6e8b2007-11-11 00:04:49 +00007370 break;
7371 case 5: case 6: /* 32 * 32 -> 32msb */
pbrookd9ba4832008-03-31 03:46:50 +00007372 gen_imull(tmp, tmp2);
7373 if (insn & (1 << 5)) {
7374 gen_roundqd(tmp, tmp2);
7375 dead_tmp(tmp2);
7376 } else {
7377 dead_tmp(tmp);
7378 tmp = tmp2;
pbrook9ee6e8b2007-11-11 00:04:49 +00007379 }
pbrookd9ba4832008-03-31 03:46:50 +00007380 if (rs != 15) {
7381 tmp2 = load_reg(s, rs);
7382 if (insn & (1 << 21)) {
7383 tcg_gen_add_i32(tmp, tmp, tmp2);
7384 } else {
7385 tcg_gen_sub_i32(tmp, tmp2, tmp);
7386 }
7387 dead_tmp(tmp2);
7388 }
pbrook9ee6e8b2007-11-11 00:04:49 +00007389 break;
7390 case 7: /* Unsigned sum of absolute differences. */
pbrookd9ba4832008-03-31 03:46:50 +00007391 gen_helper_usad8(tmp, tmp, tmp2);
7392 dead_tmp(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007393 if (rs != 15) {
pbrookd9ba4832008-03-31 03:46:50 +00007394 tmp2 = load_reg(s, rs);
7395 tcg_gen_add_i32(tmp, tmp, tmp2);
7396 dead_tmp(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007397 }
pbrook9ee6e8b2007-11-11 00:04:49 +00007398 break;
7399 }
pbrookd9ba4832008-03-31 03:46:50 +00007400 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007401 break;
7402 case 6: case 7: /* 64-bit multiply, Divide. */
7403 op = ((insn >> 4) & 0xf) | ((insn >> 16) & 0x70);
pbrook5e3f8782008-03-31 03:47:34 +00007404 tmp = load_reg(s, rn);
7405 tmp2 = load_reg(s, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00007406 if ((op & 0x50) == 0x10) {
7407 /* sdiv, udiv */
7408 if (!arm_feature(env, ARM_FEATURE_DIV))
7409 goto illegal_op;
7410 if (op & 0x20)
pbrook5e3f8782008-03-31 03:47:34 +00007411 gen_helper_udiv(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007412 else
pbrook5e3f8782008-03-31 03:47:34 +00007413 gen_helper_sdiv(tmp, tmp, tmp2);
7414 dead_tmp(tmp2);
7415 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007416 } else if ((op & 0xe) == 0xc) {
7417 /* Dual multiply accumulate long. */
7418 if (op & 1)
pbrook5e3f8782008-03-31 03:47:34 +00007419 gen_swap_half(tmp2);
7420 gen_smul_dual(tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007421 if (op & 0x10) {
pbrook5e3f8782008-03-31 03:47:34 +00007422 tcg_gen_sub_i32(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007423 } else {
pbrook5e3f8782008-03-31 03:47:34 +00007424 tcg_gen_add_i32(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007425 }
pbrook5e3f8782008-03-31 03:47:34 +00007426 dead_tmp(tmp2);
7427 tmp2 = tcg_temp_new(TCG_TYPE_I64);
7428 gen_addq(s, tmp, rs, rd);
7429 gen_storeq_reg(s, rs, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007430 } else {
7431 if (op & 0x20) {
7432 /* Unsigned 64-bit multiply */
pbrook5e3f8782008-03-31 03:47:34 +00007433 tmp = gen_mulu_i64_i32(tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007434 } else {
7435 if (op & 8) {
7436 /* smlalxy */
pbrook5e3f8782008-03-31 03:47:34 +00007437 gen_mulxy(tmp, tmp2, op & 2, op & 1);
7438 dead_tmp(tmp2);
7439 tmp2 = tcg_temp_new(TCG_TYPE_I64);
7440 tcg_gen_ext_i32_i64(tmp2, tmp);
7441 dead_tmp(tmp);
7442 tmp = tmp2;
pbrook9ee6e8b2007-11-11 00:04:49 +00007443 } else {
7444 /* Signed 64-bit multiply */
pbrook5e3f8782008-03-31 03:47:34 +00007445 tmp = gen_muls_i64_i32(tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007446 }
7447 }
7448 if (op & 4) {
7449 /* umaal */
pbrook5e3f8782008-03-31 03:47:34 +00007450 gen_addq_lo(s, tmp, rs);
7451 gen_addq_lo(s, tmp, rd);
pbrook9ee6e8b2007-11-11 00:04:49 +00007452 } else if (op & 0x40) {
7453 /* 64-bit accumulate. */
pbrook5e3f8782008-03-31 03:47:34 +00007454 gen_addq(s, tmp, rs, rd);
pbrook9ee6e8b2007-11-11 00:04:49 +00007455 }
pbrook5e3f8782008-03-31 03:47:34 +00007456 gen_storeq_reg(s, rs, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007457 }
7458 break;
7459 }
7460 break;
7461 case 6: case 7: case 14: case 15:
7462 /* Coprocessor. */
7463 if (((insn >> 24) & 3) == 3) {
7464 /* Translate into the equivalent ARM encoding. */
7465 insn = (insn & 0xe2ffffff) | ((insn & (1 << 28)) >> 4);
7466 if (disas_neon_data_insn(env, s, insn))
7467 goto illegal_op;
7468 } else {
7469 if (insn & (1 << 28))
7470 goto illegal_op;
7471 if (disas_coproc_insn (env, s, insn))
7472 goto illegal_op;
7473 }
7474 break;
7475 case 8: case 9: case 10: case 11:
7476 if (insn & (1 << 15)) {
7477 /* Branches, misc control. */
7478 if (insn & 0x5000) {
7479 /* Unconditional branch. */
7480 /* signextend(hw1[10:0]) -> offset[:12]. */
7481 offset = ((int32_t)insn << 5) >> 9 & ~(int32_t)0xfff;
7482 /* hw1[10:0] -> offset[11:1]. */
7483 offset |= (insn & 0x7ff) << 1;
7484 /* (~hw2[13, 11] ^ offset[24]) -> offset[23,22]
7485 offset[24:22] already have the same value because of the
7486 sign extension above. */
7487 offset ^= ((~insn) & (1 << 13)) << 10;
7488 offset ^= ((~insn) & (1 << 11)) << 11;
7489
pbrook9ee6e8b2007-11-11 00:04:49 +00007490 if (insn & (1 << 14)) {
7491 /* Branch and link. */
pbrookb0109802008-03-31 03:47:03 +00007492 gen_op_movl_T1_im(s->pc | 1);
pbrook9ee6e8b2007-11-11 00:04:49 +00007493 gen_movl_reg_T1(s, 14);
7494 }
7495
pbrookb0109802008-03-31 03:47:03 +00007496 offset += s->pc;
pbrook9ee6e8b2007-11-11 00:04:49 +00007497 if (insn & (1 << 12)) {
7498 /* b/bl */
pbrookb0109802008-03-31 03:47:03 +00007499 gen_jmp(s, offset);
pbrook9ee6e8b2007-11-11 00:04:49 +00007500 } else {
7501 /* blx */
pbrookb0109802008-03-31 03:47:03 +00007502 offset &= ~(uint32_t)2;
7503 gen_bx_im(s, offset);
pbrook9ee6e8b2007-11-11 00:04:49 +00007504 }
7505 } else if (((insn >> 23) & 7) == 7) {
7506 /* Misc control */
7507 if (insn & (1 << 13))
7508 goto illegal_op;
7509
7510 if (insn & (1 << 26)) {
7511 /* Secure monitor call (v6Z) */
7512 goto illegal_op; /* not implemented. */
7513 } else {
7514 op = (insn >> 20) & 7;
7515 switch (op) {
7516 case 0: /* msr cpsr. */
7517 if (IS_M(env)) {
pbrook8984bd22008-03-31 03:47:48 +00007518 tmp = load_reg(s, rn);
7519 addr = tcg_const_i32(insn & 0xff);
7520 gen_helper_v7m_msr(cpu_env, addr, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007521 gen_lookup_tb(s);
7522 break;
7523 }
7524 /* fall through */
7525 case 1: /* msr spsr. */
7526 if (IS_M(env))
7527 goto illegal_op;
7528 gen_movl_T0_reg(s, rn);
7529 if (gen_set_psr_T0(s,
7530 msr_mask(env, s, (insn >> 8) & 0xf, op == 1),
7531 op == 1))
7532 goto illegal_op;
7533 break;
7534 case 2: /* cps, nop-hint. */
7535 if (((insn >> 8) & 7) == 0) {
7536 gen_nop_hint(s, insn & 0xff);
7537 }
7538 /* Implemented as NOP in user mode. */
7539 if (IS_USER(s))
7540 break;
7541 offset = 0;
7542 imm = 0;
7543 if (insn & (1 << 10)) {
7544 if (insn & (1 << 7))
7545 offset |= CPSR_A;
7546 if (insn & (1 << 6))
7547 offset |= CPSR_I;
7548 if (insn & (1 << 5))
7549 offset |= CPSR_F;
7550 if (insn & (1 << 9))
7551 imm = CPSR_A | CPSR_I | CPSR_F;
7552 }
7553 if (insn & (1 << 8)) {
7554 offset |= 0x1f;
7555 imm |= (insn & 0x1f);
7556 }
7557 if (offset) {
7558 gen_op_movl_T0_im(imm);
7559 gen_set_psr_T0(s, offset, 0);
7560 }
7561 break;
7562 case 3: /* Special control operations. */
7563 op = (insn >> 4) & 0xf;
7564 switch (op) {
7565 case 2: /* clrex */
pbrook8f8e3aa2008-03-31 03:48:01 +00007566 gen_helper_clrex(cpu_env);
pbrook9ee6e8b2007-11-11 00:04:49 +00007567 break;
7568 case 4: /* dsb */
7569 case 5: /* dmb */
7570 case 6: /* isb */
7571 /* These execute as NOPs. */
7572 ARCH(7);
7573 break;
7574 default:
7575 goto illegal_op;
7576 }
7577 break;
7578 case 4: /* bxj */
7579 /* Trivial implementation equivalent to bx. */
pbrookd9ba4832008-03-31 03:46:50 +00007580 tmp = load_reg(s, rn);
7581 gen_bx(s, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007582 break;
7583 case 5: /* Exception return. */
7584 /* Unpredictable in user mode. */
7585 goto illegal_op;
7586 case 6: /* mrs cpsr. */
pbrook8984bd22008-03-31 03:47:48 +00007587 tmp = new_tmp();
pbrook9ee6e8b2007-11-11 00:04:49 +00007588 if (IS_M(env)) {
pbrook8984bd22008-03-31 03:47:48 +00007589 addr = tcg_const_i32(insn & 0xff);
7590 gen_helper_v7m_mrs(tmp, cpu_env, addr);
pbrook9ee6e8b2007-11-11 00:04:49 +00007591 } else {
pbrook8984bd22008-03-31 03:47:48 +00007592 gen_helper_cpsr_read(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007593 }
pbrook8984bd22008-03-31 03:47:48 +00007594 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007595 break;
7596 case 7: /* mrs spsr. */
7597 /* Not accessible in user mode. */
7598 if (IS_USER(s) || IS_M(env))
7599 goto illegal_op;
pbrookd9ba4832008-03-31 03:46:50 +00007600 tmp = load_cpu_field(spsr);
7601 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007602 break;
7603 }
7604 }
7605 } else {
7606 /* Conditional branch. */
7607 op = (insn >> 22) & 0xf;
7608 /* Generate a conditional jump to next instruction. */
7609 s->condlabel = gen_new_label();
pbrookd9ba4832008-03-31 03:46:50 +00007610 gen_test_cc(op ^ 1, s->condlabel);
pbrook9ee6e8b2007-11-11 00:04:49 +00007611 s->condjmp = 1;
7612
7613 /* offset[11:1] = insn[10:0] */
7614 offset = (insn & 0x7ff) << 1;
7615 /* offset[17:12] = insn[21:16]. */
7616 offset |= (insn & 0x003f0000) >> 4;
7617 /* offset[31:20] = insn[26]. */
7618 offset |= ((int32_t)((insn << 5) & 0x80000000)) >> 11;
7619 /* offset[18] = insn[13]. */
7620 offset |= (insn & (1 << 13)) << 5;
7621 /* offset[19] = insn[11]. */
7622 offset |= (insn & (1 << 11)) << 8;
7623
7624 /* jump to the offset */
pbrookb0109802008-03-31 03:47:03 +00007625 gen_jmp(s, s->pc + offset);
pbrook9ee6e8b2007-11-11 00:04:49 +00007626 }
7627 } else {
7628 /* Data processing immediate. */
7629 if (insn & (1 << 25)) {
7630 if (insn & (1 << 24)) {
7631 if (insn & (1 << 20))
7632 goto illegal_op;
7633 /* Bitfield/Saturate. */
7634 op = (insn >> 21) & 7;
7635 imm = insn & 0x1f;
7636 shift = ((insn >> 6) & 3) | ((insn >> 10) & 0x1c);
pbrook6ddbc6e2008-03-31 03:46:33 +00007637 if (rn == 15) {
7638 tmp = new_tmp();
7639 tcg_gen_movi_i32(tmp, 0);
7640 } else {
7641 tmp = load_reg(s, rn);
7642 }
pbrook9ee6e8b2007-11-11 00:04:49 +00007643 switch (op) {
7644 case 2: /* Signed bitfield extract. */
7645 imm++;
7646 if (shift + imm > 32)
7647 goto illegal_op;
7648 if (imm < 32)
pbrook6ddbc6e2008-03-31 03:46:33 +00007649 gen_sbfx(tmp, shift, imm);
pbrook9ee6e8b2007-11-11 00:04:49 +00007650 break;
7651 case 6: /* Unsigned bitfield extract. */
7652 imm++;
7653 if (shift + imm > 32)
7654 goto illegal_op;
7655 if (imm < 32)
pbrook6ddbc6e2008-03-31 03:46:33 +00007656 gen_ubfx(tmp, shift, (1u << imm) - 1);
pbrook9ee6e8b2007-11-11 00:04:49 +00007657 break;
7658 case 3: /* Bitfield insert/clear. */
7659 if (imm < shift)
7660 goto illegal_op;
7661 imm = imm + 1 - shift;
7662 if (imm != 32) {
pbrook6ddbc6e2008-03-31 03:46:33 +00007663 tmp2 = load_reg(s, rd);
pbrook8f8e3aa2008-03-31 03:48:01 +00007664 gen_bfi(tmp, tmp2, tmp, shift, (1u << imm) - 1);
pbrook6ddbc6e2008-03-31 03:46:33 +00007665 dead_tmp(tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007666 }
7667 break;
7668 case 7:
7669 goto illegal_op;
7670 default: /* Saturate. */
pbrook9ee6e8b2007-11-11 00:04:49 +00007671 if (shift) {
7672 if (op & 1)
pbrook6ddbc6e2008-03-31 03:46:33 +00007673 tcg_gen_sari_i32(tmp, tmp, shift);
pbrook9ee6e8b2007-11-11 00:04:49 +00007674 else
pbrook6ddbc6e2008-03-31 03:46:33 +00007675 tcg_gen_shli_i32(tmp, tmp, shift);
pbrook9ee6e8b2007-11-11 00:04:49 +00007676 }
pbrook6ddbc6e2008-03-31 03:46:33 +00007677 tmp2 = tcg_const_i32(imm);
pbrook9ee6e8b2007-11-11 00:04:49 +00007678 if (op & 4) {
7679 /* Unsigned. */
pbrook9ee6e8b2007-11-11 00:04:49 +00007680 if ((op & 1) && shift == 0)
pbrook6ddbc6e2008-03-31 03:46:33 +00007681 gen_helper_usat16(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007682 else
pbrook6ddbc6e2008-03-31 03:46:33 +00007683 gen_helper_usat(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007684 } else {
7685 /* Signed. */
pbrook9ee6e8b2007-11-11 00:04:49 +00007686 if ((op & 1) && shift == 0)
pbrook6ddbc6e2008-03-31 03:46:33 +00007687 gen_helper_ssat16(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007688 else
pbrook6ddbc6e2008-03-31 03:46:33 +00007689 gen_helper_ssat(tmp, tmp, tmp2);
pbrook9ee6e8b2007-11-11 00:04:49 +00007690 }
7691 break;
7692 }
pbrook6ddbc6e2008-03-31 03:46:33 +00007693 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007694 } else {
7695 imm = ((insn & 0x04000000) >> 15)
7696 | ((insn & 0x7000) >> 4) | (insn & 0xff);
7697 if (insn & (1 << 22)) {
7698 /* 16-bit immediate. */
7699 imm |= (insn >> 4) & 0xf000;
7700 if (insn & (1 << 23)) {
7701 /* movt */
pbrook5e3f8782008-03-31 03:47:34 +00007702 tmp = load_reg(s, rd);
7703 tcg_gen_andi_i32(tmp, tmp, 0xffff);
7704 tcg_gen_ori_i32(tmp, tmp, imm << 16);
pbrook9ee6e8b2007-11-11 00:04:49 +00007705 } else {
7706 /* movw */
pbrook5e3f8782008-03-31 03:47:34 +00007707 tmp = new_tmp();
7708 tcg_gen_movi_i32(tmp, imm);
pbrook9ee6e8b2007-11-11 00:04:49 +00007709 }
7710 } else {
7711 /* Add/sub 12-bit immediate. */
7712 if (rn == 15) {
pbrookb0109802008-03-31 03:47:03 +00007713 offset = s->pc & ~(uint32_t)3;
pbrook9ee6e8b2007-11-11 00:04:49 +00007714 if (insn & (1 << 23))
pbrookb0109802008-03-31 03:47:03 +00007715 offset -= imm;
pbrook9ee6e8b2007-11-11 00:04:49 +00007716 else
pbrookb0109802008-03-31 03:47:03 +00007717 offset += imm;
pbrook5e3f8782008-03-31 03:47:34 +00007718 tmp = new_tmp();
7719 tcg_gen_movi_i32(tmp, offset);
pbrook9ee6e8b2007-11-11 00:04:49 +00007720 } else {
pbrook5e3f8782008-03-31 03:47:34 +00007721 tmp = load_reg(s, rn);
pbrook9ee6e8b2007-11-11 00:04:49 +00007722 if (insn & (1 << 23))
pbrook5e3f8782008-03-31 03:47:34 +00007723 tcg_gen_subi_i32(tmp, tmp, imm);
pbrook9ee6e8b2007-11-11 00:04:49 +00007724 else
pbrook5e3f8782008-03-31 03:47:34 +00007725 tcg_gen_addi_i32(tmp, tmp, imm);
pbrook9ee6e8b2007-11-11 00:04:49 +00007726 }
7727 }
pbrook5e3f8782008-03-31 03:47:34 +00007728 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007729 }
7730 } else {
7731 int shifter_out = 0;
7732 /* modified 12-bit immediate. */
7733 shift = ((insn & 0x04000000) >> 23) | ((insn & 0x7000) >> 12);
7734 imm = (insn & 0xff);
7735 switch (shift) {
7736 case 0: /* XY */
7737 /* Nothing to do. */
7738 break;
7739 case 1: /* 00XY00XY */
7740 imm |= imm << 16;
7741 break;
7742 case 2: /* XY00XY00 */
7743 imm |= imm << 16;
7744 imm <<= 8;
7745 break;
7746 case 3: /* XYXYXYXY */
7747 imm |= imm << 16;
7748 imm |= imm << 8;
7749 break;
7750 default: /* Rotated constant. */
7751 shift = (shift << 1) | (imm >> 7);
7752 imm |= 0x80;
7753 imm = imm << (32 - shift);
7754 shifter_out = 1;
7755 break;
7756 }
7757 gen_op_movl_T1_im(imm);
7758 rn = (insn >> 16) & 0xf;
7759 if (rn == 15)
7760 gen_op_movl_T0_im(0);
7761 else
7762 gen_movl_T0_reg(s, rn);
7763 op = (insn >> 21) & 0xf;
7764 if (gen_thumb2_data_op(s, op, (insn & (1 << 20)) != 0,
7765 shifter_out))
7766 goto illegal_op;
7767 rd = (insn >> 8) & 0xf;
7768 if (rd != 15) {
7769 gen_movl_reg_T0(s, rd);
7770 }
7771 }
7772 }
7773 break;
7774 case 12: /* Load/store single data item. */
7775 {
7776 int postinc = 0;
7777 int writeback = 0;
pbrookb0109802008-03-31 03:47:03 +00007778 int user;
pbrook9ee6e8b2007-11-11 00:04:49 +00007779 if ((insn & 0x01100000) == 0x01000000) {
7780 if (disas_neon_ls_insn(env, s, insn))
7781 goto illegal_op;
7782 break;
7783 }
pbrookb0109802008-03-31 03:47:03 +00007784 user = IS_USER(s);
pbrook9ee6e8b2007-11-11 00:04:49 +00007785 if (rn == 15) {
pbrookb0109802008-03-31 03:47:03 +00007786 addr = new_tmp();
pbrook9ee6e8b2007-11-11 00:04:49 +00007787 /* PC relative. */
7788 /* s->pc has already been incremented by 4. */
7789 imm = s->pc & 0xfffffffc;
7790 if (insn & (1 << 23))
7791 imm += insn & 0xfff;
7792 else
7793 imm -= insn & 0xfff;
pbrookb0109802008-03-31 03:47:03 +00007794 tcg_gen_movi_i32(addr, imm);
pbrook9ee6e8b2007-11-11 00:04:49 +00007795 } else {
pbrookb0109802008-03-31 03:47:03 +00007796 addr = load_reg(s, rn);
pbrook9ee6e8b2007-11-11 00:04:49 +00007797 if (insn & (1 << 23)) {
7798 /* Positive offset. */
7799 imm = insn & 0xfff;
pbrookb0109802008-03-31 03:47:03 +00007800 tcg_gen_addi_i32(addr, addr, imm);
pbrook9ee6e8b2007-11-11 00:04:49 +00007801 } else {
7802 op = (insn >> 8) & 7;
7803 imm = insn & 0xff;
7804 switch (op) {
7805 case 0: case 8: /* Shifted Register. */
7806 shift = (insn >> 4) & 0xf;
7807 if (shift > 3)
7808 goto illegal_op;
pbrookb26eefb2008-03-31 03:44:26 +00007809 tmp = load_reg(s, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00007810 if (shift)
pbrookb26eefb2008-03-31 03:44:26 +00007811 tcg_gen_shli_i32(tmp, tmp, shift);
pbrookb0109802008-03-31 03:47:03 +00007812 tcg_gen_add_i32(addr, addr, tmp);
pbrookb26eefb2008-03-31 03:44:26 +00007813 dead_tmp(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007814 break;
7815 case 4: /* Negative offset. */
pbrookb0109802008-03-31 03:47:03 +00007816 tcg_gen_addi_i32(addr, addr, -imm);
pbrook9ee6e8b2007-11-11 00:04:49 +00007817 break;
7818 case 6: /* User privilege. */
pbrookb0109802008-03-31 03:47:03 +00007819 tcg_gen_addi_i32(addr, addr, imm);
7820 user = 1;
pbrook9ee6e8b2007-11-11 00:04:49 +00007821 break;
7822 case 1: /* Post-decrement. */
7823 imm = -imm;
7824 /* Fall through. */
7825 case 3: /* Post-increment. */
pbrook9ee6e8b2007-11-11 00:04:49 +00007826 postinc = 1;
7827 writeback = 1;
7828 break;
7829 case 5: /* Pre-decrement. */
7830 imm = -imm;
7831 /* Fall through. */
7832 case 7: /* Pre-increment. */
pbrookb0109802008-03-31 03:47:03 +00007833 tcg_gen_addi_i32(addr, addr, imm);
pbrook9ee6e8b2007-11-11 00:04:49 +00007834 writeback = 1;
7835 break;
7836 default:
7837 goto illegal_op;
7838 }
7839 }
7840 }
7841 op = ((insn >> 21) & 3) | ((insn >> 22) & 4);
7842 if (insn & (1 << 20)) {
7843 /* Load. */
7844 if (rs == 15 && op != 2) {
7845 if (op & 2)
7846 goto illegal_op;
7847 /* Memory hint. Implemented as NOP. */
7848 } else {
7849 switch (op) {
pbrookb0109802008-03-31 03:47:03 +00007850 case 0: tmp = gen_ld8u(addr, user); break;
7851 case 4: tmp = gen_ld8s(addr, user); break;
7852 case 1: tmp = gen_ld16u(addr, user); break;
7853 case 5: tmp = gen_ld16s(addr, user); break;
7854 case 2: tmp = gen_ld32(addr, user); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00007855 default: goto illegal_op;
7856 }
7857 if (rs == 15) {
pbrookb0109802008-03-31 03:47:03 +00007858 gen_bx(s, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007859 } else {
pbrookb0109802008-03-31 03:47:03 +00007860 store_reg(s, rs, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00007861 }
7862 }
7863 } else {
7864 /* Store. */
7865 if (rs == 15)
7866 goto illegal_op;
pbrookb0109802008-03-31 03:47:03 +00007867 tmp = load_reg(s, rs);
pbrook9ee6e8b2007-11-11 00:04:49 +00007868 switch (op) {
pbrookb0109802008-03-31 03:47:03 +00007869 case 0: gen_st8(tmp, addr, user); break;
7870 case 1: gen_st16(tmp, addr, user); break;
7871 case 2: gen_st32(tmp, addr, user); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00007872 default: goto illegal_op;
7873 }
7874 }
7875 if (postinc)
pbrookb0109802008-03-31 03:47:03 +00007876 tcg_gen_addi_i32(addr, addr, imm);
7877 if (writeback) {
7878 store_reg(s, rn, addr);
7879 } else {
7880 dead_tmp(addr);
7881 }
pbrook9ee6e8b2007-11-11 00:04:49 +00007882 }
7883 break;
7884 default:
7885 goto illegal_op;
7886 }
7887 return 0;
7888illegal_op:
7889 return 1;
7890}
7891
7892static void disas_thumb_insn(CPUState *env, DisasContext *s)
bellard99c475a2005-01-31 20:45:13 +00007893{
7894 uint32_t val, insn, op, rm, rn, rd, shift, cond;
7895 int32_t offset;
7896 int i;
pbrookb26eefb2008-03-31 03:44:26 +00007897 TCGv tmp;
pbrookd9ba4832008-03-31 03:46:50 +00007898 TCGv tmp2;
pbrookb0109802008-03-31 03:47:03 +00007899 TCGv addr;
bellard99c475a2005-01-31 20:45:13 +00007900
pbrook9ee6e8b2007-11-11 00:04:49 +00007901 if (s->condexec_mask) {
7902 cond = s->condexec_cond;
7903 s->condlabel = gen_new_label();
pbrookd9ba4832008-03-31 03:46:50 +00007904 gen_test_cc(cond ^ 1, s->condlabel);
pbrook9ee6e8b2007-11-11 00:04:49 +00007905 s->condjmp = 1;
7906 }
7907
bellardb5ff1b32005-11-26 10:38:39 +00007908 insn = lduw_code(s->pc);
bellard99c475a2005-01-31 20:45:13 +00007909 s->pc += 2;
bellardb5ff1b32005-11-26 10:38:39 +00007910
bellard99c475a2005-01-31 20:45:13 +00007911 switch (insn >> 12) {
7912 case 0: case 1:
7913 rd = insn & 7;
7914 op = (insn >> 11) & 3;
7915 if (op == 3) {
7916 /* add/subtract */
7917 rn = (insn >> 3) & 7;
7918 gen_movl_T0_reg(s, rn);
7919 if (insn & (1 << 10)) {
7920 /* immediate */
7921 gen_op_movl_T1_im((insn >> 6) & 7);
7922 } else {
7923 /* reg */
7924 rm = (insn >> 6) & 7;
7925 gen_movl_T1_reg(s, rm);
7926 }
pbrook9ee6e8b2007-11-11 00:04:49 +00007927 if (insn & (1 << 9)) {
7928 if (s->condexec_mask)
7929 gen_op_subl_T0_T1();
7930 else
7931 gen_op_subl_T0_T1_cc();
7932 } else {
7933 if (s->condexec_mask)
7934 gen_op_addl_T0_T1();
7935 else
7936 gen_op_addl_T0_T1_cc();
7937 }
bellard99c475a2005-01-31 20:45:13 +00007938 gen_movl_reg_T0(s, rd);
7939 } else {
7940 /* shift immediate */
7941 rm = (insn >> 3) & 7;
7942 shift = (insn >> 6) & 0x1f;
pbrook9a119ff2008-03-31 03:45:35 +00007943 tmp = load_reg(s, rm);
7944 gen_arm_shift_im(tmp, op, shift, s->condexec_mask == 0);
7945 if (!s->condexec_mask)
7946 gen_logic_CC(tmp);
7947 store_reg(s, rd, tmp);
bellard99c475a2005-01-31 20:45:13 +00007948 }
7949 break;
7950 case 2: case 3:
7951 /* arithmetic large immediate */
7952 op = (insn >> 11) & 3;
7953 rd = (insn >> 8) & 0x7;
7954 if (op == 0) {
7955 gen_op_movl_T0_im(insn & 0xff);
7956 } else {
7957 gen_movl_T0_reg(s, rd);
7958 gen_op_movl_T1_im(insn & 0xff);
7959 }
7960 switch (op) {
7961 case 0: /* mov */
pbrook9ee6e8b2007-11-11 00:04:49 +00007962 if (!s->condexec_mask)
7963 gen_op_logic_T0_cc();
bellard99c475a2005-01-31 20:45:13 +00007964 break;
7965 case 1: /* cmp */
7966 gen_op_subl_T0_T1_cc();
7967 break;
7968 case 2: /* add */
pbrook9ee6e8b2007-11-11 00:04:49 +00007969 if (s->condexec_mask)
7970 gen_op_addl_T0_T1();
7971 else
7972 gen_op_addl_T0_T1_cc();
bellard99c475a2005-01-31 20:45:13 +00007973 break;
7974 case 3: /* sub */
pbrook9ee6e8b2007-11-11 00:04:49 +00007975 if (s->condexec_mask)
7976 gen_op_subl_T0_T1();
7977 else
7978 gen_op_subl_T0_T1_cc();
bellard99c475a2005-01-31 20:45:13 +00007979 break;
7980 }
7981 if (op != 1)
7982 gen_movl_reg_T0(s, rd);
7983 break;
7984 case 4:
7985 if (insn & (1 << 11)) {
7986 rd = (insn >> 8) & 7;
bellard5899f382005-04-27 20:25:20 +00007987 /* load pc-relative. Bit 1 of PC is ignored. */
7988 val = s->pc + 2 + ((insn & 0xff) * 4);
7989 val &= ~(uint32_t)2;
pbrookb0109802008-03-31 03:47:03 +00007990 addr = new_tmp();
7991 tcg_gen_movi_i32(addr, val);
7992 tmp = gen_ld32(addr, IS_USER(s));
7993 dead_tmp(addr);
7994 store_reg(s, rd, tmp);
bellard99c475a2005-01-31 20:45:13 +00007995 break;
7996 }
7997 if (insn & (1 << 10)) {
7998 /* data processing extended or blx */
7999 rd = (insn & 7) | ((insn >> 4) & 8);
8000 rm = (insn >> 3) & 0xf;
8001 op = (insn >> 8) & 3;
8002 switch (op) {
8003 case 0: /* add */
8004 gen_movl_T0_reg(s, rd);
8005 gen_movl_T1_reg(s, rm);
8006 gen_op_addl_T0_T1();
8007 gen_movl_reg_T0(s, rd);
8008 break;
8009 case 1: /* cmp */
8010 gen_movl_T0_reg(s, rd);
8011 gen_movl_T1_reg(s, rm);
8012 gen_op_subl_T0_T1_cc();
8013 break;
8014 case 2: /* mov/cpy */
8015 gen_movl_T0_reg(s, rm);
8016 gen_movl_reg_T0(s, rd);
8017 break;
8018 case 3:/* branch [and link] exchange thumb register */
pbrookb0109802008-03-31 03:47:03 +00008019 tmp = load_reg(s, rm);
bellard99c475a2005-01-31 20:45:13 +00008020 if (insn & (1 << 7)) {
8021 val = (uint32_t)s->pc | 1;
pbrookb0109802008-03-31 03:47:03 +00008022 tmp2 = new_tmp();
8023 tcg_gen_movi_i32(tmp2, val);
8024 store_reg(s, 14, tmp2);
bellard99c475a2005-01-31 20:45:13 +00008025 }
pbrookd9ba4832008-03-31 03:46:50 +00008026 gen_bx(s, tmp);
bellard99c475a2005-01-31 20:45:13 +00008027 break;
8028 }
8029 break;
8030 }
8031
8032 /* data processing register */
8033 rd = insn & 7;
8034 rm = (insn >> 3) & 7;
8035 op = (insn >> 6) & 0xf;
8036 if (op == 2 || op == 3 || op == 4 || op == 7) {
8037 /* the shift/rotate ops want the operands backwards */
8038 val = rm;
8039 rm = rd;
8040 rd = val;
8041 val = 1;
8042 } else {
8043 val = 0;
8044 }
8045
8046 if (op == 9) /* neg */
8047 gen_op_movl_T0_im(0);
8048 else if (op != 0xf) /* mvn doesn't read its first operand */
8049 gen_movl_T0_reg(s, rd);
8050
8051 gen_movl_T1_reg(s, rm);
bellard5899f382005-04-27 20:25:20 +00008052 switch (op) {
bellard99c475a2005-01-31 20:45:13 +00008053 case 0x0: /* and */
8054 gen_op_andl_T0_T1();
pbrook9ee6e8b2007-11-11 00:04:49 +00008055 if (!s->condexec_mask)
8056 gen_op_logic_T0_cc();
bellard99c475a2005-01-31 20:45:13 +00008057 break;
8058 case 0x1: /* eor */
8059 gen_op_xorl_T0_T1();
pbrook9ee6e8b2007-11-11 00:04:49 +00008060 if (!s->condexec_mask)
8061 gen_op_logic_T0_cc();
bellard99c475a2005-01-31 20:45:13 +00008062 break;
8063 case 0x2: /* lsl */
pbrook9ee6e8b2007-11-11 00:04:49 +00008064 if (s->condexec_mask) {
pbrook8984bd22008-03-31 03:47:48 +00008065 gen_helper_shl(cpu_T[1], cpu_T[1], cpu_T[0]);
pbrook9ee6e8b2007-11-11 00:04:49 +00008066 } else {
pbrook8984bd22008-03-31 03:47:48 +00008067 gen_helper_shl_cc(cpu_T[1], cpu_T[1], cpu_T[0]);
pbrook9ee6e8b2007-11-11 00:04:49 +00008068 gen_op_logic_T1_cc();
8069 }
bellard99c475a2005-01-31 20:45:13 +00008070 break;
8071 case 0x3: /* lsr */
pbrook9ee6e8b2007-11-11 00:04:49 +00008072 if (s->condexec_mask) {
pbrook8984bd22008-03-31 03:47:48 +00008073 gen_helper_shr(cpu_T[1], cpu_T[1], cpu_T[0]);
pbrook9ee6e8b2007-11-11 00:04:49 +00008074 } else {
pbrook8984bd22008-03-31 03:47:48 +00008075 gen_helper_shr_cc(cpu_T[1], cpu_T[1], cpu_T[0]);
pbrook9ee6e8b2007-11-11 00:04:49 +00008076 gen_op_logic_T1_cc();
8077 }
bellard99c475a2005-01-31 20:45:13 +00008078 break;
8079 case 0x4: /* asr */
pbrook9ee6e8b2007-11-11 00:04:49 +00008080 if (s->condexec_mask) {
pbrook8984bd22008-03-31 03:47:48 +00008081 gen_helper_sar(cpu_T[1], cpu_T[1], cpu_T[0]);
pbrook9ee6e8b2007-11-11 00:04:49 +00008082 } else {
pbrook8984bd22008-03-31 03:47:48 +00008083 gen_helper_sar_cc(cpu_T[1], cpu_T[1], cpu_T[0]);
pbrook9ee6e8b2007-11-11 00:04:49 +00008084 gen_op_logic_T1_cc();
8085 }
bellard99c475a2005-01-31 20:45:13 +00008086 break;
8087 case 0x5: /* adc */
pbrook9ee6e8b2007-11-11 00:04:49 +00008088 if (s->condexec_mask)
pbrookb26eefb2008-03-31 03:44:26 +00008089 gen_adc_T0_T1();
pbrook9ee6e8b2007-11-11 00:04:49 +00008090 else
8091 gen_op_adcl_T0_T1_cc();
bellard99c475a2005-01-31 20:45:13 +00008092 break;
8093 case 0x6: /* sbc */
pbrook9ee6e8b2007-11-11 00:04:49 +00008094 if (s->condexec_mask)
pbrook36706692008-03-31 03:46:19 +00008095 gen_sbc_T0_T1();
pbrook9ee6e8b2007-11-11 00:04:49 +00008096 else
8097 gen_op_sbcl_T0_T1_cc();
bellard99c475a2005-01-31 20:45:13 +00008098 break;
8099 case 0x7: /* ror */
pbrook9ee6e8b2007-11-11 00:04:49 +00008100 if (s->condexec_mask) {
pbrook8984bd22008-03-31 03:47:48 +00008101 gen_helper_ror(cpu_T[1], cpu_T[1], cpu_T[0]);
pbrook9ee6e8b2007-11-11 00:04:49 +00008102 } else {
pbrook8984bd22008-03-31 03:47:48 +00008103 gen_helper_ror_cc(cpu_T[1], cpu_T[1], cpu_T[0]);
pbrook9ee6e8b2007-11-11 00:04:49 +00008104 gen_op_logic_T1_cc();
8105 }
bellard99c475a2005-01-31 20:45:13 +00008106 break;
8107 case 0x8: /* tst */
8108 gen_op_andl_T0_T1();
8109 gen_op_logic_T0_cc();
8110 rd = 16;
bellard5899f382005-04-27 20:25:20 +00008111 break;
bellard99c475a2005-01-31 20:45:13 +00008112 case 0x9: /* neg */
pbrook9ee6e8b2007-11-11 00:04:49 +00008113 if (s->condexec_mask)
8114 gen_op_subl_T0_T1();
8115 else
8116 gen_op_subl_T0_T1_cc();
bellard99c475a2005-01-31 20:45:13 +00008117 break;
8118 case 0xa: /* cmp */
8119 gen_op_subl_T0_T1_cc();
8120 rd = 16;
8121 break;
8122 case 0xb: /* cmn */
8123 gen_op_addl_T0_T1_cc();
8124 rd = 16;
8125 break;
8126 case 0xc: /* orr */
8127 gen_op_orl_T0_T1();
pbrook9ee6e8b2007-11-11 00:04:49 +00008128 if (!s->condexec_mask)
8129 gen_op_logic_T0_cc();
bellard99c475a2005-01-31 20:45:13 +00008130 break;
8131 case 0xd: /* mul */
8132 gen_op_mull_T0_T1();
pbrook9ee6e8b2007-11-11 00:04:49 +00008133 if (!s->condexec_mask)
8134 gen_op_logic_T0_cc();
bellard99c475a2005-01-31 20:45:13 +00008135 break;
8136 case 0xe: /* bic */
8137 gen_op_bicl_T0_T1();
pbrook9ee6e8b2007-11-11 00:04:49 +00008138 if (!s->condexec_mask)
8139 gen_op_logic_T0_cc();
bellard99c475a2005-01-31 20:45:13 +00008140 break;
8141 case 0xf: /* mvn */
8142 gen_op_notl_T1();
pbrook9ee6e8b2007-11-11 00:04:49 +00008143 if (!s->condexec_mask)
8144 gen_op_logic_T1_cc();
bellard99c475a2005-01-31 20:45:13 +00008145 val = 1;
bellard5899f382005-04-27 20:25:20 +00008146 rm = rd;
bellard99c475a2005-01-31 20:45:13 +00008147 break;
8148 }
8149 if (rd != 16) {
8150 if (val)
bellard5899f382005-04-27 20:25:20 +00008151 gen_movl_reg_T1(s, rm);
bellard99c475a2005-01-31 20:45:13 +00008152 else
8153 gen_movl_reg_T0(s, rd);
8154 }
8155 break;
8156
8157 case 5:
8158 /* load/store register offset. */
8159 rd = insn & 7;
8160 rn = (insn >> 3) & 7;
8161 rm = (insn >> 6) & 7;
8162 op = (insn >> 9) & 7;
pbrookb0109802008-03-31 03:47:03 +00008163 addr = load_reg(s, rn);
pbrookb26eefb2008-03-31 03:44:26 +00008164 tmp = load_reg(s, rm);
pbrookb0109802008-03-31 03:47:03 +00008165 tcg_gen_add_i32(addr, addr, tmp);
pbrookb26eefb2008-03-31 03:44:26 +00008166 dead_tmp(tmp);
bellard99c475a2005-01-31 20:45:13 +00008167
8168 if (op < 3) /* store */
pbrookb0109802008-03-31 03:47:03 +00008169 tmp = load_reg(s, rd);
bellard99c475a2005-01-31 20:45:13 +00008170
8171 switch (op) {
8172 case 0: /* str */
pbrookb0109802008-03-31 03:47:03 +00008173 gen_st32(tmp, addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00008174 break;
8175 case 1: /* strh */
pbrookb0109802008-03-31 03:47:03 +00008176 gen_st16(tmp, addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00008177 break;
8178 case 2: /* strb */
pbrookb0109802008-03-31 03:47:03 +00008179 gen_st8(tmp, addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00008180 break;
8181 case 3: /* ldrsb */
pbrookb0109802008-03-31 03:47:03 +00008182 tmp = gen_ld8s(addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00008183 break;
8184 case 4: /* ldr */
pbrookb0109802008-03-31 03:47:03 +00008185 tmp = gen_ld32(addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00008186 break;
8187 case 5: /* ldrh */
pbrookb0109802008-03-31 03:47:03 +00008188 tmp = gen_ld16u(addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00008189 break;
8190 case 6: /* ldrb */
pbrookb0109802008-03-31 03:47:03 +00008191 tmp = gen_ld8u(addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00008192 break;
8193 case 7: /* ldrsh */
pbrookb0109802008-03-31 03:47:03 +00008194 tmp = gen_ld16s(addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00008195 break;
8196 }
8197 if (op >= 3) /* load */
pbrookb0109802008-03-31 03:47:03 +00008198 store_reg(s, rd, tmp);
8199 dead_tmp(addr);
bellard99c475a2005-01-31 20:45:13 +00008200 break;
8201
8202 case 6:
8203 /* load/store word immediate offset */
8204 rd = insn & 7;
8205 rn = (insn >> 3) & 7;
pbrookb0109802008-03-31 03:47:03 +00008206 addr = load_reg(s, rn);
bellard99c475a2005-01-31 20:45:13 +00008207 val = (insn >> 4) & 0x7c;
pbrookb0109802008-03-31 03:47:03 +00008208 tcg_gen_addi_i32(addr, addr, val);
bellard99c475a2005-01-31 20:45:13 +00008209
8210 if (insn & (1 << 11)) {
8211 /* load */
pbrookb0109802008-03-31 03:47:03 +00008212 tmp = gen_ld32(addr, IS_USER(s));
8213 store_reg(s, rd, tmp);
bellard99c475a2005-01-31 20:45:13 +00008214 } else {
8215 /* store */
pbrookb0109802008-03-31 03:47:03 +00008216 tmp = load_reg(s, rd);
8217 gen_st32(tmp, addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00008218 }
pbrookb0109802008-03-31 03:47:03 +00008219 dead_tmp(addr);
bellard99c475a2005-01-31 20:45:13 +00008220 break;
8221
8222 case 7:
8223 /* load/store byte immediate offset */
8224 rd = insn & 7;
8225 rn = (insn >> 3) & 7;
pbrookb0109802008-03-31 03:47:03 +00008226 addr = load_reg(s, rn);
bellard99c475a2005-01-31 20:45:13 +00008227 val = (insn >> 6) & 0x1f;
pbrookb0109802008-03-31 03:47:03 +00008228 tcg_gen_addi_i32(addr, addr, val);
bellard99c475a2005-01-31 20:45:13 +00008229
8230 if (insn & (1 << 11)) {
8231 /* load */
pbrookb0109802008-03-31 03:47:03 +00008232 tmp = gen_ld8u(addr, IS_USER(s));
8233 store_reg(s, rd, tmp);
bellard99c475a2005-01-31 20:45:13 +00008234 } else {
8235 /* store */
pbrookb0109802008-03-31 03:47:03 +00008236 tmp = load_reg(s, rd);
8237 gen_st8(tmp, addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00008238 }
pbrookb0109802008-03-31 03:47:03 +00008239 dead_tmp(addr);
bellard99c475a2005-01-31 20:45:13 +00008240 break;
8241
8242 case 8:
8243 /* load/store halfword immediate offset */
8244 rd = insn & 7;
8245 rn = (insn >> 3) & 7;
pbrookb0109802008-03-31 03:47:03 +00008246 addr = load_reg(s, rn);
bellard99c475a2005-01-31 20:45:13 +00008247 val = (insn >> 5) & 0x3e;
pbrookb0109802008-03-31 03:47:03 +00008248 tcg_gen_addi_i32(addr, addr, val);
bellard99c475a2005-01-31 20:45:13 +00008249
8250 if (insn & (1 << 11)) {
8251 /* load */
pbrookb0109802008-03-31 03:47:03 +00008252 tmp = gen_ld16u(addr, IS_USER(s));
8253 store_reg(s, rd, tmp);
bellard99c475a2005-01-31 20:45:13 +00008254 } else {
8255 /* store */
pbrookb0109802008-03-31 03:47:03 +00008256 tmp = load_reg(s, rd);
8257 gen_st16(tmp, addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00008258 }
pbrookb0109802008-03-31 03:47:03 +00008259 dead_tmp(addr);
bellard99c475a2005-01-31 20:45:13 +00008260 break;
8261
8262 case 9:
8263 /* load/store from stack */
8264 rd = (insn >> 8) & 7;
pbrookb0109802008-03-31 03:47:03 +00008265 addr = load_reg(s, 13);
bellard99c475a2005-01-31 20:45:13 +00008266 val = (insn & 0xff) * 4;
pbrookb0109802008-03-31 03:47:03 +00008267 tcg_gen_addi_i32(addr, addr, val);
bellard99c475a2005-01-31 20:45:13 +00008268
8269 if (insn & (1 << 11)) {
8270 /* load */
pbrookb0109802008-03-31 03:47:03 +00008271 tmp = gen_ld32(addr, IS_USER(s));
8272 store_reg(s, rd, tmp);
bellard99c475a2005-01-31 20:45:13 +00008273 } else {
8274 /* store */
pbrookb0109802008-03-31 03:47:03 +00008275 tmp = load_reg(s, rd);
8276 gen_st32(tmp, addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00008277 }
pbrookb0109802008-03-31 03:47:03 +00008278 dead_tmp(addr);
bellard99c475a2005-01-31 20:45:13 +00008279 break;
8280
8281 case 10:
8282 /* add to high reg */
8283 rd = (insn >> 8) & 7;
bellard5899f382005-04-27 20:25:20 +00008284 if (insn & (1 << 11)) {
8285 /* SP */
pbrook5e3f8782008-03-31 03:47:34 +00008286 tmp = load_reg(s, 13);
bellard5899f382005-04-27 20:25:20 +00008287 } else {
8288 /* PC. bit 1 is ignored. */
pbrook5e3f8782008-03-31 03:47:34 +00008289 tmp = new_tmp();
8290 tcg_gen_movi_i32(tmp, (s->pc + 2) & ~(uint32_t)2);
bellard5899f382005-04-27 20:25:20 +00008291 }
bellard99c475a2005-01-31 20:45:13 +00008292 val = (insn & 0xff) * 4;
pbrook5e3f8782008-03-31 03:47:34 +00008293 tcg_gen_addi_i32(tmp, tmp, val);
8294 store_reg(s, rd, tmp);
bellard99c475a2005-01-31 20:45:13 +00008295 break;
8296
8297 case 11:
8298 /* misc */
8299 op = (insn >> 8) & 0xf;
8300 switch (op) {
8301 case 0:
8302 /* adjust stack pointer */
pbrookb26eefb2008-03-31 03:44:26 +00008303 tmp = load_reg(s, 13);
bellard99c475a2005-01-31 20:45:13 +00008304 val = (insn & 0x7f) * 4;
8305 if (insn & (1 << 7))
8306 val = -(int32_t)val;
pbrookb26eefb2008-03-31 03:44:26 +00008307 tcg_gen_addi_i32(tmp, tmp, val);
8308 store_reg(s, 13, tmp);
bellard99c475a2005-01-31 20:45:13 +00008309 break;
8310
pbrook9ee6e8b2007-11-11 00:04:49 +00008311 case 2: /* sign/zero extend. */
8312 ARCH(6);
8313 rd = insn & 7;
8314 rm = (insn >> 3) & 7;
pbrookb0109802008-03-31 03:47:03 +00008315 tmp = load_reg(s, rm);
pbrook9ee6e8b2007-11-11 00:04:49 +00008316 switch ((insn >> 6) & 3) {
pbrookb0109802008-03-31 03:47:03 +00008317 case 0: gen_sxth(tmp); break;
8318 case 1: gen_sxtb(tmp); break;
8319 case 2: gen_uxth(tmp); break;
8320 case 3: gen_uxtb(tmp); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00008321 }
pbrookb0109802008-03-31 03:47:03 +00008322 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00008323 break;
bellard99c475a2005-01-31 20:45:13 +00008324 case 4: case 5: case 0xc: case 0xd:
8325 /* push/pop */
pbrookb0109802008-03-31 03:47:03 +00008326 addr = load_reg(s, 13);
bellard5899f382005-04-27 20:25:20 +00008327 if (insn & (1 << 8))
8328 offset = 4;
bellard99c475a2005-01-31 20:45:13 +00008329 else
bellard5899f382005-04-27 20:25:20 +00008330 offset = 0;
8331 for (i = 0; i < 8; i++) {
8332 if (insn & (1 << i))
8333 offset += 4;
8334 }
8335 if ((insn & (1 << 11)) == 0) {
pbrookb0109802008-03-31 03:47:03 +00008336 tcg_gen_addi_i32(addr, addr, -offset);
bellard5899f382005-04-27 20:25:20 +00008337 }
bellard99c475a2005-01-31 20:45:13 +00008338 for (i = 0; i < 8; i++) {
8339 if (insn & (1 << i)) {
8340 if (insn & (1 << 11)) {
8341 /* pop */
pbrookb0109802008-03-31 03:47:03 +00008342 tmp = gen_ld32(addr, IS_USER(s));
8343 store_reg(s, i, tmp);
bellard99c475a2005-01-31 20:45:13 +00008344 } else {
8345 /* push */
pbrookb0109802008-03-31 03:47:03 +00008346 tmp = load_reg(s, i);
8347 gen_st32(tmp, addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00008348 }
bellard5899f382005-04-27 20:25:20 +00008349 /* advance to the next address. */
pbrookb0109802008-03-31 03:47:03 +00008350 tcg_gen_addi_i32(addr, addr, 4);
bellard99c475a2005-01-31 20:45:13 +00008351 }
8352 }
8353 if (insn & (1 << 8)) {
8354 if (insn & (1 << 11)) {
8355 /* pop pc */
pbrookb0109802008-03-31 03:47:03 +00008356 tmp = gen_ld32(addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00008357 /* don't set the pc until the rest of the instruction
8358 has completed */
8359 } else {
8360 /* push lr */
pbrookb0109802008-03-31 03:47:03 +00008361 tmp = load_reg(s, 14);
8362 gen_st32(tmp, addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00008363 }
pbrookb0109802008-03-31 03:47:03 +00008364 tcg_gen_addi_i32(addr, addr, 4);
bellard99c475a2005-01-31 20:45:13 +00008365 }
bellard5899f382005-04-27 20:25:20 +00008366 if ((insn & (1 << 11)) == 0) {
pbrookb0109802008-03-31 03:47:03 +00008367 tcg_gen_addi_i32(addr, addr, -offset);
bellard5899f382005-04-27 20:25:20 +00008368 }
bellard99c475a2005-01-31 20:45:13 +00008369 /* write back the new stack pointer */
pbrookb0109802008-03-31 03:47:03 +00008370 store_reg(s, 13, addr);
bellard99c475a2005-01-31 20:45:13 +00008371 /* set the new PC value */
8372 if ((insn & 0x0900) == 0x0900)
pbrookb0109802008-03-31 03:47:03 +00008373 gen_bx(s, tmp);
bellard99c475a2005-01-31 20:45:13 +00008374 break;
8375
pbrook9ee6e8b2007-11-11 00:04:49 +00008376 case 1: case 3: case 9: case 11: /* czb */
8377 rm = insn & 7;
pbrookd9ba4832008-03-31 03:46:50 +00008378 tmp = load_reg(s, rm);
8379 tmp2 = tcg_const_i32(0);
pbrook9ee6e8b2007-11-11 00:04:49 +00008380 s->condlabel = gen_new_label();
8381 s->condjmp = 1;
8382 if (insn & (1 << 11))
pbrookd9ba4832008-03-31 03:46:50 +00008383 tcg_gen_brcond_i32(TCG_COND_EQ, tmp, tmp2, s->condlabel);
pbrook9ee6e8b2007-11-11 00:04:49 +00008384 else
pbrookd9ba4832008-03-31 03:46:50 +00008385 tcg_gen_brcond_i32(TCG_COND_NE, tmp, tmp2, s->condlabel);
8386 dead_tmp(tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00008387 offset = ((insn & 0xf8) >> 2) | (insn & 0x200) >> 3;
8388 val = (uint32_t)s->pc + 2;
8389 val += offset;
8390 gen_jmp(s, val);
8391 break;
8392
8393 case 15: /* IT, nop-hint. */
8394 if ((insn & 0xf) == 0) {
8395 gen_nop_hint(s, (insn >> 4) & 0xf);
8396 break;
8397 }
8398 /* If Then. */
8399 s->condexec_cond = (insn >> 4) & 0xe;
8400 s->condexec_mask = insn & 0x1f;
8401 /* No actual code generated for this insn, just setup state. */
8402 break;
8403
pbrook06c949e2006-02-04 19:35:26 +00008404 case 0xe: /* bkpt */
pbrook9ee6e8b2007-11-11 00:04:49 +00008405 gen_set_condexec(s);
pbrook5e3f8782008-03-31 03:47:34 +00008406 gen_set_pc_im(s->pc - 2);
pbrookd9ba4832008-03-31 03:46:50 +00008407 gen_exception(EXCP_BKPT);
pbrook06c949e2006-02-04 19:35:26 +00008408 s->is_jmp = DISAS_JUMP;
8409 break;
8410
pbrook9ee6e8b2007-11-11 00:04:49 +00008411 case 0xa: /* rev */
8412 ARCH(6);
8413 rn = (insn >> 3) & 0x7;
8414 rd = insn & 0x7;
pbrookb0109802008-03-31 03:47:03 +00008415 tmp = load_reg(s, rn);
pbrook9ee6e8b2007-11-11 00:04:49 +00008416 switch ((insn >> 6) & 3) {
pbrookb0109802008-03-31 03:47:03 +00008417 case 0: tcg_gen_bswap_i32(tmp, tmp); break;
8418 case 1: gen_rev16(tmp); break;
8419 case 3: gen_revsh(tmp); break;
pbrook9ee6e8b2007-11-11 00:04:49 +00008420 default: goto illegal_op;
8421 }
pbrookb0109802008-03-31 03:47:03 +00008422 store_reg(s, rd, tmp);
pbrook9ee6e8b2007-11-11 00:04:49 +00008423 break;
8424
8425 case 6: /* cps */
8426 ARCH(6);
8427 if (IS_USER(s))
8428 break;
8429 if (IS_M(env)) {
pbrook8984bd22008-03-31 03:47:48 +00008430 tmp = tcg_const_i32((insn & (1 << 4)) != 0);
pbrook9ee6e8b2007-11-11 00:04:49 +00008431 /* PRIMASK */
pbrook8984bd22008-03-31 03:47:48 +00008432 if (insn & 1) {
8433 addr = tcg_const_i32(16);
8434 gen_helper_v7m_msr(cpu_env, addr, tmp);
8435 }
pbrook9ee6e8b2007-11-11 00:04:49 +00008436 /* FAULTMASK */
pbrook8984bd22008-03-31 03:47:48 +00008437 if (insn & 2) {
8438 addr = tcg_const_i32(17);
8439 gen_helper_v7m_msr(cpu_env, addr, tmp);
8440 }
pbrook9ee6e8b2007-11-11 00:04:49 +00008441 gen_lookup_tb(s);
8442 } else {
8443 if (insn & (1 << 4))
8444 shift = CPSR_A | CPSR_I | CPSR_F;
8445 else
8446 shift = 0;
8447
8448 val = ((insn & 7) << 6) & shift;
8449 gen_op_movl_T0_im(val);
8450 gen_set_psr_T0(s, shift, 0);
8451 }
8452 break;
8453
bellard99c475a2005-01-31 20:45:13 +00008454 default:
8455 goto undef;
8456 }
8457 break;
8458
8459 case 12:
8460 /* load/store multiple */
8461 rn = (insn >> 8) & 0x7;
pbrookb0109802008-03-31 03:47:03 +00008462 addr = load_reg(s, rn);
bellard99c475a2005-01-31 20:45:13 +00008463 for (i = 0; i < 8; i++) {
8464 if (insn & (1 << i)) {
bellard99c475a2005-01-31 20:45:13 +00008465 if (insn & (1 << 11)) {
8466 /* load */
pbrookb0109802008-03-31 03:47:03 +00008467 tmp = gen_ld32(addr, IS_USER(s));
8468 store_reg(s, i, tmp);
bellard99c475a2005-01-31 20:45:13 +00008469 } else {
8470 /* store */
pbrookb0109802008-03-31 03:47:03 +00008471 tmp = load_reg(s, i);
8472 gen_st32(tmp, addr, IS_USER(s));
bellard99c475a2005-01-31 20:45:13 +00008473 }
bellard5899f382005-04-27 20:25:20 +00008474 /* advance to the next address */
pbrookb0109802008-03-31 03:47:03 +00008475 tcg_gen_addi_i32(addr, addr, 4);
bellard99c475a2005-01-31 20:45:13 +00008476 }
8477 }
bellard5899f382005-04-27 20:25:20 +00008478 /* Base register writeback. */
pbrookb0109802008-03-31 03:47:03 +00008479 if ((insn & (1 << rn)) == 0) {
8480 store_reg(s, rn, addr);
8481 } else {
8482 dead_tmp(addr);
8483 }
bellard99c475a2005-01-31 20:45:13 +00008484 break;
8485
8486 case 13:
8487 /* conditional branch or swi */
8488 cond = (insn >> 8) & 0xf;
8489 if (cond == 0xe)
8490 goto undef;
8491
8492 if (cond == 0xf) {
8493 /* swi */
pbrook9ee6e8b2007-11-11 00:04:49 +00008494 gen_set_condexec(s);
pbrook5e3f8782008-03-31 03:47:34 +00008495 gen_set_pc_im(s->pc | 1);
pbrook9ee6e8b2007-11-11 00:04:49 +00008496 s->is_jmp = DISAS_SWI;
bellard99c475a2005-01-31 20:45:13 +00008497 break;
8498 }
8499 /* generate a conditional jump to next instruction */
bellarde50e6a22005-04-26 20:36:11 +00008500 s->condlabel = gen_new_label();
pbrookd9ba4832008-03-31 03:46:50 +00008501 gen_test_cc(cond ^ 1, s->condlabel);
bellarde50e6a22005-04-26 20:36:11 +00008502 s->condjmp = 1;
bellard99c475a2005-01-31 20:45:13 +00008503 gen_movl_T1_reg(s, 15);
8504
8505 /* jump to the offset */
bellard5899f382005-04-27 20:25:20 +00008506 val = (uint32_t)s->pc + 2;
bellard99c475a2005-01-31 20:45:13 +00008507 offset = ((int32_t)insn << 24) >> 24;
bellard5899f382005-04-27 20:25:20 +00008508 val += offset << 1;
bellard8aaca4c2005-04-23 18:27:52 +00008509 gen_jmp(s, val);
bellard99c475a2005-01-31 20:45:13 +00008510 break;
8511
8512 case 14:
pbrook358bf292006-04-09 14:38:57 +00008513 if (insn & (1 << 11)) {
pbrook9ee6e8b2007-11-11 00:04:49 +00008514 if (disas_thumb2_insn(env, s, insn))
8515 goto undef32;
pbrook358bf292006-04-09 14:38:57 +00008516 break;
8517 }
pbrook9ee6e8b2007-11-11 00:04:49 +00008518 /* unconditional branch */
bellard99c475a2005-01-31 20:45:13 +00008519 val = (uint32_t)s->pc;
8520 offset = ((int32_t)insn << 21) >> 21;
8521 val += (offset << 1) + 2;
bellard8aaca4c2005-04-23 18:27:52 +00008522 gen_jmp(s, val);
bellard99c475a2005-01-31 20:45:13 +00008523 break;
8524
8525 case 15:
pbrook9ee6e8b2007-11-11 00:04:49 +00008526 if (disas_thumb2_insn(env, s, insn))
8527 goto undef32;
8528 break;
bellard99c475a2005-01-31 20:45:13 +00008529 }
8530 return;
pbrook9ee6e8b2007-11-11 00:04:49 +00008531undef32:
8532 gen_set_condexec(s);
pbrook5e3f8782008-03-31 03:47:34 +00008533 gen_set_pc_im(s->pc - 4);
pbrookd9ba4832008-03-31 03:46:50 +00008534 gen_exception(EXCP_UDEF);
pbrook9ee6e8b2007-11-11 00:04:49 +00008535 s->is_jmp = DISAS_JUMP;
8536 return;
8537illegal_op:
bellard99c475a2005-01-31 20:45:13 +00008538undef:
pbrook9ee6e8b2007-11-11 00:04:49 +00008539 gen_set_condexec(s);
pbrook5e3f8782008-03-31 03:47:34 +00008540 gen_set_pc_im(s->pc - 2);
pbrookd9ba4832008-03-31 03:46:50 +00008541 gen_exception(EXCP_UDEF);
bellard99c475a2005-01-31 20:45:13 +00008542 s->is_jmp = DISAS_JUMP;
8543}
8544
bellard2c0262a2003-09-30 20:34:21 +00008545/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
8546 basic block 'tb'. If search_pc is TRUE, also generate PC
8547 information for each intermediate instruction. */
ths5fafdf22007-09-16 21:08:06 +00008548static inline int gen_intermediate_code_internal(CPUState *env,
8549 TranslationBlock *tb,
bellard2c0262a2003-09-30 20:34:21 +00008550 int search_pc)
8551{
8552 DisasContext dc1, *dc = &dc1;
8553 uint16_t *gen_opc_end;
8554 int j, lj;
bellard0fa85d42005-01-03 23:43:32 +00008555 target_ulong pc_start;
bellardb5ff1b32005-11-26 10:38:39 +00008556 uint32_t next_page_start;
ths3b46e622007-09-17 08:09:54 +00008557
bellard2c0262a2003-09-30 20:34:21 +00008558 /* generate intermediate code */
pbrookb26eefb2008-03-31 03:44:26 +00008559 num_temps = 0;
8560 memset(temps, 0, sizeof(temps));
8561
bellard0fa85d42005-01-03 23:43:32 +00008562 pc_start = tb->pc;
ths3b46e622007-09-17 08:09:54 +00008563
bellard2c0262a2003-09-30 20:34:21 +00008564 dc->tb = tb;
8565
bellard2c0262a2003-09-30 20:34:21 +00008566 gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
bellard2c0262a2003-09-30 20:34:21 +00008567
8568 dc->is_jmp = DISAS_NEXT;
8569 dc->pc = pc_start;
bellard8aaca4c2005-04-23 18:27:52 +00008570 dc->singlestep_enabled = env->singlestep_enabled;
bellarde50e6a22005-04-26 20:36:11 +00008571 dc->condjmp = 0;
bellard5899f382005-04-27 20:25:20 +00008572 dc->thumb = env->thumb;
pbrook9ee6e8b2007-11-11 00:04:49 +00008573 dc->condexec_mask = (env->condexec_bits & 0xf) << 1;
8574 dc->condexec_cond = env->condexec_bits >> 4;
pbrook6658ffb2007-03-16 23:58:11 +00008575 dc->is_mem = 0;
bellardb5ff1b32005-11-26 10:38:39 +00008576#if !defined(CONFIG_USER_ONLY)
pbrook9ee6e8b2007-11-11 00:04:49 +00008577 if (IS_M(env)) {
8578 dc->user = ((env->v7m.exception == 0) && (env->v7m.control & 1));
8579 } else {
8580 dc->user = (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_USR;
8581 }
bellardb5ff1b32005-11-26 10:38:39 +00008582#endif
pbrook4373f3c2008-03-31 03:47:19 +00008583 cpu_F0s = tcg_temp_new(TCG_TYPE_I32);
8584 cpu_F1s = tcg_temp_new(TCG_TYPE_I32);
8585 cpu_F0d = tcg_temp_new(TCG_TYPE_I64);
8586 cpu_F1d = tcg_temp_new(TCG_TYPE_I64);
pbrookad694712008-03-31 03:48:30 +00008587 cpu_V0 = cpu_F0d;
8588 cpu_V1 = cpu_F1d;
pbrooke6771372008-03-31 03:49:05 +00008589 /* FIXME: cpu_M0 can probably be the same as cpu_V0. */
8590 cpu_M0 = tcg_temp_new(TCG_TYPE_I64);
bellardb5ff1b32005-11-26 10:38:39 +00008591 next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
bellard2c0262a2003-09-30 20:34:21 +00008592 lj = -1;
pbrook9ee6e8b2007-11-11 00:04:49 +00008593 /* Reset the conditional execution bits immediately. This avoids
8594 complications trying to do it at the end of the block. */
8595 if (env->condexec_bits)
pbrook8f012452008-03-31 03:46:03 +00008596 {
8597 TCGv tmp = new_tmp();
8598 tcg_gen_movi_i32(tmp, 0);
pbrookd9ba4832008-03-31 03:46:50 +00008599 store_cpu_field(tmp, condexec_bits);
pbrook8f012452008-03-31 03:46:03 +00008600 }
bellard2c0262a2003-09-30 20:34:21 +00008601 do {
pbrook9ee6e8b2007-11-11 00:04:49 +00008602#ifndef CONFIG_USER_ONLY
8603 if (dc->pc >= 0xfffffff0 && IS_M(env)) {
8604 /* We always get here via a jump, so know we are not in a
8605 conditional execution block. */
pbrookd9ba4832008-03-31 03:46:50 +00008606 gen_exception(EXCP_EXCEPTION_EXIT);
pbrook9ee6e8b2007-11-11 00:04:49 +00008607 }
8608#endif
8609
bellard1fddef42005-04-17 19:16:13 +00008610 if (env->nb_breakpoints > 0) {
8611 for(j = 0; j < env->nb_breakpoints; j++) {
8612 if (env->breakpoints[j] == dc->pc) {
pbrook9ee6e8b2007-11-11 00:04:49 +00008613 gen_set_condexec(dc);
pbrook5e3f8782008-03-31 03:47:34 +00008614 gen_set_pc_im(dc->pc);
pbrookd9ba4832008-03-31 03:46:50 +00008615 gen_exception(EXCP_DEBUG);
bellard1fddef42005-04-17 19:16:13 +00008616 dc->is_jmp = DISAS_JUMP;
pbrook9ee6e8b2007-11-11 00:04:49 +00008617 /* Advance PC so that clearing the breakpoint will
8618 invalidate this TB. */
8619 dc->pc += 2;
8620 goto done_generating;
bellard1fddef42005-04-17 19:16:13 +00008621 break;
8622 }
8623 }
8624 }
bellard2c0262a2003-09-30 20:34:21 +00008625 if (search_pc) {
8626 j = gen_opc_ptr - gen_opc_buf;
8627 if (lj < j) {
8628 lj++;
8629 while (lj < j)
8630 gen_opc_instr_start[lj++] = 0;
8631 }
bellard0fa85d42005-01-03 23:43:32 +00008632 gen_opc_pc[lj] = dc->pc;
bellard2c0262a2003-09-30 20:34:21 +00008633 gen_opc_instr_start[lj] = 1;
8634 }
bellarde50e6a22005-04-26 20:36:11 +00008635
pbrook9ee6e8b2007-11-11 00:04:49 +00008636 if (env->thumb) {
8637 disas_thumb_insn(env, dc);
8638 if (dc->condexec_mask) {
8639 dc->condexec_cond = (dc->condexec_cond & 0xe)
8640 | ((dc->condexec_mask >> 4) & 1);
8641 dc->condexec_mask = (dc->condexec_mask << 1) & 0x1f;
8642 if (dc->condexec_mask == 0) {
8643 dc->condexec_cond = 0;
8644 }
8645 }
8646 } else {
8647 disas_arm_insn(env, dc);
8648 }
pbrookb26eefb2008-03-31 03:44:26 +00008649 if (num_temps) {
8650 fprintf(stderr, "Internal resource leak before %08x\n", dc->pc);
8651 num_temps = 0;
8652 }
bellarde50e6a22005-04-26 20:36:11 +00008653
8654 if (dc->condjmp && !dc->is_jmp) {
8655 gen_set_label(dc->condlabel);
8656 dc->condjmp = 0;
8657 }
pbrook6658ffb2007-03-16 23:58:11 +00008658 /* Terminate the TB on memory ops if watchpoints are present. */
8659 /* FIXME: This should be replacd by the deterministic execution
8660 * IRQ raising bits. */
8661 if (dc->is_mem && env->nb_watchpoints)
8662 break;
8663
bellarde50e6a22005-04-26 20:36:11 +00008664 /* Translation stops when a conditional branch is enoutered.
8665 * Otherwise the subsequent code could get translated several times.
bellardb5ff1b32005-11-26 10:38:39 +00008666 * Also stop translation when a page boundary is reached. This
8667 * ensures prefech aborts occur at the right place. */
bellard1fddef42005-04-17 19:16:13 +00008668 } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
8669 !env->singlestep_enabled &&
bellardb5ff1b32005-11-26 10:38:39 +00008670 dc->pc < next_page_start);
pbrook9ee6e8b2007-11-11 00:04:49 +00008671
bellardb5ff1b32005-11-26 10:38:39 +00008672 /* At this stage dc->condjmp will only be set when the skipped
pbrook9ee6e8b2007-11-11 00:04:49 +00008673 instruction was a conditional branch or trap, and the PC has
8674 already been written. */
bellard8aaca4c2005-04-23 18:27:52 +00008675 if (__builtin_expect(env->singlestep_enabled, 0)) {
8676 /* Make sure the pc is updated, and raise a debug exception. */
bellarde50e6a22005-04-26 20:36:11 +00008677 if (dc->condjmp) {
pbrook9ee6e8b2007-11-11 00:04:49 +00008678 gen_set_condexec(dc);
8679 if (dc->is_jmp == DISAS_SWI) {
pbrookd9ba4832008-03-31 03:46:50 +00008680 gen_exception(EXCP_SWI);
pbrook9ee6e8b2007-11-11 00:04:49 +00008681 } else {
pbrookd9ba4832008-03-31 03:46:50 +00008682 gen_exception(EXCP_DEBUG);
pbrook9ee6e8b2007-11-11 00:04:49 +00008683 }
bellarde50e6a22005-04-26 20:36:11 +00008684 gen_set_label(dc->condlabel);
8685 }
8686 if (dc->condjmp || !dc->is_jmp) {
pbrook5e3f8782008-03-31 03:47:34 +00008687 gen_set_pc_im(dc->pc);
bellarde50e6a22005-04-26 20:36:11 +00008688 dc->condjmp = 0;
bellard8aaca4c2005-04-23 18:27:52 +00008689 }
pbrook9ee6e8b2007-11-11 00:04:49 +00008690 gen_set_condexec(dc);
8691 if (dc->is_jmp == DISAS_SWI && !dc->condjmp) {
pbrookd9ba4832008-03-31 03:46:50 +00008692 gen_exception(EXCP_SWI);
pbrook9ee6e8b2007-11-11 00:04:49 +00008693 } else {
8694 /* FIXME: Single stepping a WFI insn will not halt
8695 the CPU. */
pbrookd9ba4832008-03-31 03:46:50 +00008696 gen_exception(EXCP_DEBUG);
pbrook9ee6e8b2007-11-11 00:04:49 +00008697 }
bellard8aaca4c2005-04-23 18:27:52 +00008698 } else {
pbrook9ee6e8b2007-11-11 00:04:49 +00008699 /* While branches must always occur at the end of an IT block,
8700 there are a few other things that can cause us to terminate
8701 the TB in the middel of an IT block:
8702 - Exception generating instructions (bkpt, swi, undefined).
8703 - Page boundaries.
8704 - Hardware watchpoints.
8705 Hardware breakpoints have already been handled and skip this code.
8706 */
8707 gen_set_condexec(dc);
bellard8aaca4c2005-04-23 18:27:52 +00008708 switch(dc->is_jmp) {
bellard8aaca4c2005-04-23 18:27:52 +00008709 case DISAS_NEXT:
bellard6e256c92005-11-20 10:32:05 +00008710 gen_goto_tb(dc, 1, dc->pc);
bellard8aaca4c2005-04-23 18:27:52 +00008711 break;
8712 default:
8713 case DISAS_JUMP:
8714 case DISAS_UPDATE:
8715 /* indicate that the hash table must be used to find the next TB */
bellard57fec1f2008-02-01 10:50:11 +00008716 tcg_gen_exit_tb(0);
bellard8aaca4c2005-04-23 18:27:52 +00008717 break;
8718 case DISAS_TB_JUMP:
8719 /* nothing more to generate */
8720 break;
pbrook9ee6e8b2007-11-11 00:04:49 +00008721 case DISAS_WFI:
pbrookd9ba4832008-03-31 03:46:50 +00008722 gen_helper_wfi();
pbrook9ee6e8b2007-11-11 00:04:49 +00008723 break;
8724 case DISAS_SWI:
pbrookd9ba4832008-03-31 03:46:50 +00008725 gen_exception(EXCP_SWI);
pbrook9ee6e8b2007-11-11 00:04:49 +00008726 break;
bellard8aaca4c2005-04-23 18:27:52 +00008727 }
bellarde50e6a22005-04-26 20:36:11 +00008728 if (dc->condjmp) {
8729 gen_set_label(dc->condlabel);
pbrook9ee6e8b2007-11-11 00:04:49 +00008730 gen_set_condexec(dc);
bellard6e256c92005-11-20 10:32:05 +00008731 gen_goto_tb(dc, 1, dc->pc);
bellarde50e6a22005-04-26 20:36:11 +00008732 dc->condjmp = 0;
8733 }
bellard2c0262a2003-09-30 20:34:21 +00008734 }
pbrook9ee6e8b2007-11-11 00:04:49 +00008735done_generating:
bellard2c0262a2003-09-30 20:34:21 +00008736 *gen_opc_ptr = INDEX_op_end;
8737
8738#ifdef DEBUG_DISAS
bellarde19e89a2004-03-21 17:08:23 +00008739 if (loglevel & CPU_LOG_TB_IN_ASM) {
bellard2c0262a2003-09-30 20:34:21 +00008740 fprintf(logfile, "----------------\n");
8741 fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
bellard5899f382005-04-27 20:25:20 +00008742 target_disas(logfile, pc_start, dc->pc - pc_start, env->thumb);
bellard2c0262a2003-09-30 20:34:21 +00008743 fprintf(logfile, "\n");
bellard2c0262a2003-09-30 20:34:21 +00008744 }
8745#endif
bellardb5ff1b32005-11-26 10:38:39 +00008746 if (search_pc) {
8747 j = gen_opc_ptr - gen_opc_buf;
8748 lj++;
8749 while (lj <= j)
8750 gen_opc_instr_start[lj++] = 0;
bellardb5ff1b32005-11-26 10:38:39 +00008751 } else {
bellard2c0262a2003-09-30 20:34:21 +00008752 tb->size = dc->pc - pc_start;
bellardb5ff1b32005-11-26 10:38:39 +00008753 }
bellard2c0262a2003-09-30 20:34:21 +00008754 return 0;
8755}
8756
8757int gen_intermediate_code(CPUState *env, TranslationBlock *tb)
8758{
8759 return gen_intermediate_code_internal(env, tb, 0);
8760}
8761
8762int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
8763{
8764 return gen_intermediate_code_internal(env, tb, 1);
8765}
8766
bellardb5ff1b32005-11-26 10:38:39 +00008767static const char *cpu_mode_names[16] = {
8768 "usr", "fiq", "irq", "svc", "???", "???", "???", "abt",
8769 "???", "???", "???", "und", "???", "???", "???", "sys"
8770};
pbrook9ee6e8b2007-11-11 00:04:49 +00008771
ths5fafdf22007-09-16 21:08:06 +00008772void cpu_dump_state(CPUState *env, FILE *f,
bellard7fe48482004-10-09 18:08:01 +00008773 int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
8774 int flags)
bellard2c0262a2003-09-30 20:34:21 +00008775{
8776 int i;
bellardbc380d12005-05-13 22:50:47 +00008777 union {
bellardb7bcbe92005-02-22 19:27:29 +00008778 uint32_t i;
8779 float s;
8780 } s0, s1;
8781 CPU_DoubleU d;
pbrooka94a6ab2006-10-25 17:43:33 +00008782 /* ??? This assumes float64 and double have the same layout.
8783 Oh well, it's only debug dumps. */
8784 union {
8785 float64 f64;
8786 double d;
8787 } d0;
bellardb5ff1b32005-11-26 10:38:39 +00008788 uint32_t psr;
bellard2c0262a2003-09-30 20:34:21 +00008789
8790 for(i=0;i<16;i++) {
bellard7fe48482004-10-09 18:08:01 +00008791 cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
bellard2c0262a2003-09-30 20:34:21 +00008792 if ((i % 4) == 3)
bellard7fe48482004-10-09 18:08:01 +00008793 cpu_fprintf(f, "\n");
bellard2c0262a2003-09-30 20:34:21 +00008794 else
bellard7fe48482004-10-09 18:08:01 +00008795 cpu_fprintf(f, " ");
bellard2c0262a2003-09-30 20:34:21 +00008796 }
bellardb5ff1b32005-11-26 10:38:39 +00008797 psr = cpsr_read(env);
ths687fa642007-04-02 08:18:36 +00008798 cpu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%d\n",
8799 psr,
bellardb5ff1b32005-11-26 10:38:39 +00008800 psr & (1 << 31) ? 'N' : '-',
8801 psr & (1 << 30) ? 'Z' : '-',
8802 psr & (1 << 29) ? 'C' : '-',
8803 psr & (1 << 28) ? 'V' : '-',
ths5fafdf22007-09-16 21:08:06 +00008804 psr & CPSR_T ? 'T' : 'A',
bellardb5ff1b32005-11-26 10:38:39 +00008805 cpu_mode_names[psr & 0xf], (psr & 0x10) ? 32 : 26);
bellardb7bcbe92005-02-22 19:27:29 +00008806
pbrook5e3f8782008-03-31 03:47:34 +00008807#if 0
bellardb7bcbe92005-02-22 19:27:29 +00008808 for (i = 0; i < 16; i++) {
bellard8e960052005-04-07 19:42:46 +00008809 d.d = env->vfp.regs[i];
8810 s0.i = d.l.lower;
8811 s1.i = d.l.upper;
pbrooka94a6ab2006-10-25 17:43:33 +00008812 d0.f64 = d.d;
8813 cpu_fprintf(f, "s%02d=%08x(%8g) s%02d=%08x(%8g) d%02d=%08x%08x(%8g)\n",
bellardb7bcbe92005-02-22 19:27:29 +00008814 i * 2, (int)s0.i, s0.s,
pbrooka94a6ab2006-10-25 17:43:33 +00008815 i * 2 + 1, (int)s1.i, s1.s,
bellardb7bcbe92005-02-22 19:27:29 +00008816 i, (int)(uint32_t)d.l.upper, (int)(uint32_t)d.l.lower,
pbrooka94a6ab2006-10-25 17:43:33 +00008817 d0.d);
bellardb7bcbe92005-02-22 19:27:29 +00008818 }
pbrook40f137e2006-02-20 00:33:36 +00008819 cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.xregs[ARM_VFP_FPSCR]);
pbrook5e3f8782008-03-31 03:47:34 +00008820#endif
bellard2c0262a2003-09-30 20:34:21 +00008821}
bellarda6b025d2004-01-24 15:18:16 +00008822